audio-lnx: Rename folders to new flat structure.

Kernel audio drivers can be categorised into below folders.
asoc - ALSA based drivers,
asoc/codecs - codec drivers,
ipc - APR IPC communication drivers,
dsp - DSP low level drivers/Audio ION/ADSP Loader,
dsp/codecs - Native encoders and decoders,
soc - SoC based drivers(pinctrl/regmap/soundwire)

Restructure drivers to above folder format.
Include directories also follow above format.

Change-Id: I8fa0857baaacd47db126fb5c1f1f5ed7e886dbc0
Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
diff --git a/asoc/codecs/Makefile b/asoc/codecs/Makefile
new file mode 100644
index 0000000..04218e8
--- /dev/null
+++ b/asoc/codecs/Makefile
@@ -0,0 +1,32 @@
+snd-soc-wcd9xxx-v2-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o wcdcal-hwdep.o wcd9xxx-soc-init.o
+snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o
+snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o
+snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o wcd-mbhc-adc.o
+snd-soc-wcd-dsp-utils-objs := wcd-dsp-utils.o
+snd-soc-wcd-dsp-mgr-objs := wcd-dsp-mgr.o
+snd-soc-wcd-spi-objs := wcd-spi.o
+
+obj-$(CONFIG_SND_SOC_WCD934X)	+= wcd934x/
+ifeq ($(CONFIG_COMMON_CLK_MSM), y)
+	obj-$(CONFIG_AUDIO_EXT_CLK)	+= audio-ext-clk.o
+endif
+ifeq ($(CONFIG_COMMON_CLK_QCOM), y)
+	obj-$(CONFIG_AUDIO_EXT_CLK)     += audio-ext-clk-up.o
+endif
+
+obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += snd-soc-wcd9xxx-v2.o
+obj-$(CONFIG_SND_SOC_WCD_CPE)   += snd-soc-wcd-cpe.o
+obj-$(CONFIG_SND_SOC_WCD_MBHC)  += snd-soc-wcd-mbhc.o
+obj-$(CONFIG_SND_SOC_WSA881X)	+= snd-soc-wsa881x.o
+obj-$(CONFIG_SND_SOC_WCD_DSP_MGR)	+= snd-soc-wcd-dsp-mgr.o snd-soc-wcd-dsp-utils.o
+obj-$(CONFIG_SND_SOC_WCD_SPI)  += snd-soc-wcd-spi.o
+
+snd-soc-msm-stub-objs := msm_stub.o
+obj-$(CONFIG_SND_SOC_MSM_STUB)  += snd-soc-msm-stub.o
+
+wcd-core-objs                  := wcd9xxx-rst.o wcd9xxx-core-init.o \
+				wcd9xxx-core.o wcd9xxx-irq.o \
+				wcd9xxx-slimslave.o wcd9xxx-utils.o \
+				wcd9335-regmap.o wcd9335-tables.o \
+				msm-cdc-pinctrl.o msm-cdc-supply.o
+obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd-core.o
diff --git a/asoc/codecs/audio-ext-clk-up.c b/asoc/codecs/audio-ext-clk-up.c
new file mode 100644
index 0000000..50a8ed6
--- /dev/null
+++ b/asoc/codecs/audio-ext-clk-up.c
@@ -0,0 +1,626 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include "../../../drivers/clk/qcom/common.h"
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <dt-bindings/clock/qcom,audio-ext-clk.h>
+#include <dsp/q6afe-v2.h>
+#include "audio-ext-clk-up.h"
+
+enum audio_clk_mux {
+	AP_CLK2,
+	LPASS_MCLK,
+	LPASS_MCLK2,
+};
+
+struct pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *sleep;
+	struct pinctrl_state *active;
+	char __iomem *base;
+};
+
+struct audio_ext_ap_clk {
+	bool enabled;
+	int gpio;
+	struct clk_fixed_factor fact;
+};
+
+struct audio_ext_pmi_clk {
+	int gpio;
+	struct clk_fixed_factor fact;
+};
+
+struct audio_ext_ap_clk2 {
+	bool enabled;
+	struct pinctrl_info pnctrl_info;
+	struct clk_fixed_factor fact;
+};
+
+struct audio_ext_lpass_mclk {
+	struct pinctrl_info pnctrl_info;
+	struct clk_fixed_factor fact;
+};
+
+static struct afe_clk_set clk2_config = {
+	Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
+	Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
+	Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
+	Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+	0,
+};
+
+static struct afe_clk_set lpass_default = {
+	Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
+	Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
+	Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
+	Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+	0,
+};
+
+static struct afe_clk_set lpass_mclk = {
+	Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
+	Q6AFE_LPASS_CLK_ID_MCLK_1,
+	Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ,
+	Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+	0,
+};
+
+static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk_hw *hw)
+{
+	return container_of(hw, struct audio_ext_ap_clk, fact.hw);
+}
+
+static int audio_ext_clk_prepare(struct clk_hw *hw)
+{
+	struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw);
+
+	pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
+	if (gpio_is_valid(audio_clk->gpio))
+		return gpio_direction_output(audio_clk->gpio, 1);
+	return 0;
+}
+
+static void audio_ext_clk_unprepare(struct clk_hw *hw)
+{
+	struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw);
+
+	pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
+	if (gpio_is_valid(audio_clk->gpio))
+		gpio_direction_output(audio_clk->gpio, 0);
+}
+
+static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk_hw *hw)
+{
+	return container_of(hw, struct audio_ext_ap_clk2, fact.hw);
+}
+
+static int audio_ext_clk2_prepare(struct clk_hw *hw)
+{
+	struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw);
+	struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
+	int ret;
+
+
+	if (!pnctrl_info->pinctrl || !pnctrl_info->active)
+		return 0;
+
+	ret = pinctrl_select_state(pnctrl_info->pinctrl,
+				   pnctrl_info->active);
+	if (ret) {
+		pr_err("%s: active state select failed with %d\n",
+			__func__, ret);
+		return -EIO;
+	}
+
+	clk2_config.enable = 1;
+	ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
+	if (ret < 0) {
+		pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void audio_ext_clk2_unprepare(struct clk_hw *hw)
+{
+	struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw);
+	struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
+	int ret;
+
+	if (!pnctrl_info->pinctrl || !pnctrl_info->sleep)
+		return;
+
+	ret = pinctrl_select_state(pnctrl_info->pinctrl,
+				   pnctrl_info->sleep);
+	if (ret)
+		pr_err("%s: sleep state select failed with %d\n",
+			__func__, ret);
+
+	clk2_config.enable = 0;
+	ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
+	if (ret < 0)
+		pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
+}
+
+static inline struct audio_ext_lpass_mclk *to_audio_lpass_mclk(
+						struct clk_hw *hw)
+{
+	return container_of(hw, struct audio_ext_lpass_mclk, fact.hw);
+}
+
+static int audio_ext_lpass_mclk_prepare(struct clk_hw *hw)
+{
+	struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw);
+	struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info;
+	int ret;
+
+	lpass_mclk.enable = 1;
+	ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
+				&lpass_mclk);
+	if (ret < 0) {
+		pr_err("%s afe_set_digital_codec_core_clock failed\n",
+			__func__);
+		return ret;
+	}
+
+	if (pnctrl_info->pinctrl) {
+		ret = pinctrl_select_state(pnctrl_info->pinctrl,
+				pnctrl_info->active);
+		if (ret) {
+			pr_err("%s: active state select failed with %d\n",
+				__func__, ret);
+			return -EIO;
+		}
+	}
+
+	if (pnctrl_info->base)
+		iowrite32(1, pnctrl_info->base);
+	return 0;
+}
+
+static void audio_ext_lpass_mclk_unprepare(struct clk_hw *hw)
+{
+	struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw);
+	struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info;
+	int ret;
+
+	if (pnctrl_info->pinctrl) {
+		ret = pinctrl_select_state(pnctrl_info->pinctrl,
+					   pnctrl_info->sleep);
+		if (ret) {
+			pr_err("%s: active state select failed with %d\n",
+				__func__, ret);
+			return;
+		}
+	}
+
+	lpass_mclk.enable = 0;
+	ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
+			&lpass_mclk);
+	if (ret < 0)
+		pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n",
+			__func__, ret);
+	if (pnctrl_info->base)
+		iowrite32(0, pnctrl_info->base);
+}
+
+static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw)
+{
+	struct audio_ext_lpass_mclk *audio_lpass_mclk2 =
+					to_audio_lpass_mclk(hw);
+	struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info;
+	int ret;
+
+	if (pnctrl_info->pinctrl) {
+		ret = pinctrl_select_state(pnctrl_info->pinctrl,
+					   pnctrl_info->active);
+		if (ret) {
+			pr_err("%s: active state select failed with %d\n",
+				__func__, ret);
+			return -EIO;
+		}
+	}
+
+	lpass_default.enable = 1;
+	ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default);
+	if (ret < 0) {
+		pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void audio_ext_lpass_mclk2_unprepare(struct clk_hw *hw)
+{
+	struct audio_ext_lpass_mclk *audio_lpass_mclk2 =
+					to_audio_lpass_mclk(hw);
+	struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info;
+	int ret;
+
+	if (pnctrl_info->pinctrl) {
+		ret = pinctrl_select_state(pnctrl_info->pinctrl,
+					   pnctrl_info->sleep);
+		if (ret)
+			pr_err("%s: sleep state select failed with %d\n",
+				__func__, ret);
+	}
+
+	lpass_default.enable = 0;
+	ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default);
+	if (ret < 0)
+		pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
+}
+
+static const struct clk_ops audio_ext_ap_clk_ops = {
+	.prepare = audio_ext_clk_prepare,
+	.unprepare = audio_ext_clk_unprepare,
+};
+
+static const struct clk_ops audio_ext_ap_clk2_ops = {
+	.prepare = audio_ext_clk2_prepare,
+	.unprepare = audio_ext_clk2_unprepare,
+};
+
+static const struct clk_ops audio_ext_lpass_mclk_ops = {
+	.prepare = audio_ext_lpass_mclk_prepare,
+	.unprepare = audio_ext_lpass_mclk_unprepare,
+};
+
+static const struct clk_ops audio_ext_lpass_mclk2_ops = {
+	.prepare = audio_ext_lpass_mclk2_prepare,
+	.unprepare = audio_ext_lpass_mclk2_unprepare,
+};
+
+static struct audio_ext_pmi_clk audio_pmi_clk = {
+	.gpio = -EINVAL,
+	.fact = {
+		.mult = 1,
+		.div = 1,
+		.hw.init = &(struct clk_init_data){
+			.name = "audio_ext_pmi_clk",
+			.parent_names = (const char *[]){ "div_clk1" },
+			.num_parents = 1,
+			.ops = &clk_dummy_ops,
+		},
+	},
+};
+
+static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = {
+	.gpio = -EINVAL,
+	.fact = {
+		.mult = 1,
+		.div = 1,
+		.hw.init = &(struct clk_init_data){
+			.name = "audio_ext_pmi_lnbb_clk",
+			.parent_names = (const char *[]){ "ln_bb_clk2" },
+			.num_parents = 1,
+			.ops = &clk_dummy_ops,
+		},
+	},
+};
+
+static struct audio_ext_ap_clk audio_ap_clk = {
+	.gpio = -EINVAL,
+	.fact = {
+		.mult = 1,
+		.div = 1,
+		.hw.init = &(struct clk_init_data){
+			.name = "audio_ap_clk",
+			.ops = &audio_ext_ap_clk_ops,
+		},
+	},
+};
+
+static struct audio_ext_ap_clk2 audio_ap_clk2 = {
+	.enabled = false,
+	.pnctrl_info = {NULL},
+	.fact = {
+		.mult = 1,
+		.div = 1,
+		.hw.init = &(struct clk_init_data){
+			.name = "audio_ap_clk2",
+			.ops = &audio_ext_ap_clk2_ops,
+		},
+	},
+};
+
+static struct audio_ext_lpass_mclk audio_lpass_mclk = {
+	.pnctrl_info = {NULL},
+	.fact = {
+		.mult = 1,
+		.div = 1,
+		.hw.init = &(struct clk_init_data){
+			.name = "audio_lpass_mclk",
+			.ops = &audio_ext_lpass_mclk_ops,
+		},
+	},
+};
+
+static struct audio_ext_lpass_mclk audio_lpass_mclk2 = {
+	.pnctrl_info = {NULL},
+	.fact = {
+		.mult = 1,
+		.div = 1,
+		.hw.init = &(struct clk_init_data){
+			.name = "audio_lpass_mclk2",
+			.ops = &audio_ext_lpass_mclk2_ops,
+		},
+	},
+};
+
+static struct clk_hw *audio_msm_hws[] = {
+	&audio_pmi_clk.fact.hw,
+	&audio_ap_clk.fact.hw,
+	&audio_ap_clk2.fact.hw,
+	&audio_lpass_mclk.fact.hw,
+	&audio_lpass_mclk2.fact.hw,
+};
+
+static struct clk_hw *audio_msm_hws1[] = {
+	&audio_pmi_lnbb_clk.fact.hw,
+};
+
+static int audio_get_pinctrl(struct platform_device *pdev,
+			     enum audio_clk_mux mux)
+{
+	struct device *dev =  &pdev->dev;
+	struct pinctrl_info *pnctrl_info;
+	struct pinctrl *pinctrl;
+	int ret;
+	u32 reg;
+
+	switch (mux) {
+	case AP_CLK2:
+		pnctrl_info = &audio_ap_clk2.pnctrl_info;
+		break;
+	case LPASS_MCLK:
+		pnctrl_info = &audio_lpass_mclk.pnctrl_info;
+		break;
+	case LPASS_MCLK2:
+		pnctrl_info = &audio_lpass_mclk2.pnctrl_info;
+		break;
+	default:
+		dev_err(dev, "%s Not a valid MUX ID: %d\n",
+			__func__, mux);
+		return -EINVAL;
+	}
+
+	if (pnctrl_info->pinctrl) {
+		dev_dbg(dev, "%s: already requested before\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR_OR_NULL(pinctrl)) {
+		dev_dbg(dev, "%s: Unable to get pinctrl handle\n",
+			__func__);
+		return -EINVAL;
+	}
+	pnctrl_info->pinctrl = pinctrl;
+	/* get all state handles from Device Tree */
+	pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
+	if (IS_ERR(pnctrl_info->sleep)) {
+		dev_err(dev, "%s: could not get sleep pinstate\n",
+			__func__);
+		goto err;
+	}
+	pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
+	if (IS_ERR(pnctrl_info->active)) {
+		dev_err(dev, "%s: could not get active pinstate\n",
+			__func__);
+		goto err;
+	}
+	/* Reset the TLMM pins to a default state */
+	ret = pinctrl_select_state(pnctrl_info->pinctrl,
+				   pnctrl_info->sleep);
+	if (ret) {
+		dev_err(dev, "%s: Disable TLMM pins failed with %d\n",
+			__func__, ret);
+		goto err;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,mclk-clk-reg", &reg);
+	if (ret < 0) {
+		dev_dbg(dev, "%s: miss mclk reg\n", __func__);
+	} else {
+		pnctrl_info->base = ioremap(reg, sizeof(u32));
+		if (pnctrl_info->base ==  NULL) {
+			dev_err(dev, "%s ioremap failed\n", __func__);
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	devm_pinctrl_put(pnctrl_info->pinctrl);
+	return -EINVAL;
+}
+
+static int audio_ref_clk_probe(struct platform_device *pdev)
+{
+	int clk_gpio;
+	int ret;
+	u32 mclk_freq;
+	struct clk *audio_clk;
+	struct device *dev = &pdev->dev;
+	int i;
+	struct clk_onecell_data *clk_data;
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+			"qcom,codec-mclk-clk-freq",
+			&mclk_freq);
+	if (!ret) {
+		lpass_mclk.clk_freq_in_hz = mclk_freq;
+
+		ret = audio_get_pinctrl(pdev, LPASS_MCLK);
+		if (ret)
+			dev_err(&pdev->dev, "%s: Parsing pinctrl %s failed\n",
+				__func__, "LPASS_MCLK");
+		ret = audio_get_pinctrl(pdev, LPASS_MCLK2);
+		if (ret)
+			dev_dbg(&pdev->dev, "%s: Parsing pinctrl %s failed\n",
+				__func__, "LPASS_MCLK2");
+	}
+
+	clk_gpio = of_get_named_gpio(pdev->dev.of_node,
+				     "qcom,audio-ref-clk-gpio", 0);
+	if (clk_gpio > 0) {
+		ret = gpio_request(clk_gpio, "EXT_CLK");
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Request ext clk gpio failed %d, err:%d\n",
+				clk_gpio, ret);
+			goto err;
+		}
+		if (of_property_read_bool(pdev->dev.of_node,
+					"qcom,node_has_rpm_clock")) {
+			audio_pmi_clk.gpio = clk_gpio;
+		} else
+			audio_ap_clk.gpio = clk_gpio;
+
+	}
+
+	ret = audio_get_pinctrl(pdev, AP_CLK2);
+	if (ret)
+		dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n",
+			__func__);
+
+	clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		goto err_gpio;
+
+
+	clk_gpio = of_get_named_gpio(pdev->dev.of_node,
+				     "qcom,audio-ref-clk-gpio", 0);
+	if (clk_gpio > 0) {
+		clk_data->clk_num = ARRAY_SIZE(audio_msm_hws);
+		clk_data->clks = devm_kzalloc(&pdev->dev,
+					clk_data->clk_num *
+					sizeof(struct clk *),
+					GFP_KERNEL);
+		if (!clk_data->clks)
+			goto err_clk;
+
+		for (i = 0; i < ARRAY_SIZE(audio_msm_hws); i++) {
+			audio_clk = devm_clk_register(dev, audio_msm_hws[i]);
+			if (IS_ERR(audio_clk)) {
+				dev_err(&pdev->dev,
+					"%s: ref clock: %d register failed\n",
+					__func__, i);
+				return PTR_ERR(audio_clk);
+			}
+			clk_data->clks[i] = audio_clk;
+		}
+	} else {
+		clk_data->clk_num = ARRAY_SIZE(audio_msm_hws1);
+		clk_data->clks = devm_kzalloc(&pdev->dev,
+					clk_data->clk_num *
+					sizeof(struct clk *),
+					GFP_KERNEL);
+		if (!clk_data->clks)
+			goto err_clk;
+
+		for (i = 0; i < ARRAY_SIZE(audio_msm_hws1); i++) {
+			audio_clk = devm_clk_register(dev, audio_msm_hws1[i]);
+			if (IS_ERR(audio_clk)) {
+				dev_err(&pdev->dev,
+					"%s: ref clock: %d register failed\n",
+					__func__, i);
+				return PTR_ERR(audio_clk);
+			}
+			clk_data->clks[i] = audio_clk;
+		}
+	}
+
+	ret = of_clk_add_provider(pdev->dev.of_node,
+				of_clk_src_onecell_get, clk_data);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: audio ref clock register failed\n",
+			__func__);
+		goto err_gpio;
+	}
+
+	return 0;
+
+err_clk:
+	if (clk_data)
+		devm_kfree(&pdev->dev, clk_data->clks);
+	devm_kfree(&pdev->dev, clk_data);
+err_gpio:
+	gpio_free(clk_gpio);
+
+err:
+	return ret;
+}
+
+static int audio_ref_clk_remove(struct platform_device *pdev)
+{
+	struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info;
+
+	if (audio_pmi_clk.gpio > 0)
+		gpio_free(audio_pmi_clk.gpio);
+	else if (audio_ap_clk.gpio > 0)
+		gpio_free(audio_ap_clk.gpio);
+
+	if (pnctrl_info->pinctrl) {
+		devm_pinctrl_put(pnctrl_info->pinctrl);
+		pnctrl_info->pinctrl = NULL;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id audio_ref_clk_match[] = {
+	{.compatible = "qcom,audio-ref-clk"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, audio_ref_clk_match);
+
+static struct platform_driver audio_ref_clk_driver = {
+	.driver = {
+		.name = "audio-ref-clk",
+		.owner = THIS_MODULE,
+		.of_match_table = audio_ref_clk_match,
+	},
+	.probe = audio_ref_clk_probe,
+	.remove = audio_ref_clk_remove,
+};
+
+int audio_ref_clk_platform_init(void)
+{
+	return platform_driver_register(&audio_ref_clk_driver);
+}
+
+void audio_ref_clk_platform_exit(void)
+{
+	platform_driver_unregister(&audio_ref_clk_driver);
+}
+
+MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/audio-ext-clk-up.h b/asoc/codecs/audio-ext-clk-up.h
new file mode 100644
index 0000000..8a0232e
--- /dev/null
+++ b/asoc/codecs/audio-ext-clk-up.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __AUDIO_EXT_CLK_UP_H_
+#define __AUDIO_EXT_CLK_UP_H_
+
+int audio_ref_clk_platform_init(void);
+void audio_ref_clk_platform_exit(void);
+
+#endif
diff --git a/asoc/codecs/audio-ext-clk.c b/asoc/codecs/audio-ext-clk.c
new file mode 100644
index 0000000..72f16f5
--- /dev/null
+++ b/asoc/codecs/audio-ext-clk.c
@@ -0,0 +1,348 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <dt-bindings/clock/audio-ext-clk.h>
+#include <sound/q6afe-v2.h>
+#include "audio-ext-clk-up.h"
+
+struct pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *sleep;
+	struct pinctrl_state *active;
+};
+
+struct audio_ext_ap_clk {
+	bool enabled;
+	int gpio;
+	struct clk c;
+};
+
+struct audio_ext_pmi_clk {
+	int gpio;
+	struct clk c;
+};
+
+struct audio_ext_ap_clk2 {
+	bool enabled;
+	struct pinctrl_info pnctrl_info;
+	struct clk c;
+};
+
+static struct afe_clk_set clk2_config = {
+	Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
+	Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
+	Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
+	Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+	0,
+};
+
+static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk *clk)
+{
+	return container_of(clk, struct audio_ext_ap_clk, c);
+}
+
+static int audio_ext_clk_prepare(struct clk *clk)
+{
+	struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(clk);
+
+	pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
+	if (gpio_is_valid(audio_clk->gpio))
+		return gpio_direction_output(audio_clk->gpio, 1);
+	return 0;
+}
+
+static void audio_ext_clk_unprepare(struct clk *clk)
+{
+	struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(clk);
+
+	pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
+	if (gpio_is_valid(audio_clk->gpio))
+		gpio_direction_output(audio_clk->gpio, 0);
+}
+
+static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk *clk)
+{
+	return container_of(clk, struct audio_ext_ap_clk2, c);
+}
+
+static int audio_ext_clk2_prepare(struct clk *clk)
+{
+	struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(clk);
+	struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
+	int ret;
+
+
+	if (!pnctrl_info->pinctrl || !pnctrl_info->active)
+		return 0;
+
+	ret = pinctrl_select_state(pnctrl_info->pinctrl,
+				   pnctrl_info->active);
+	if (ret) {
+		pr_err("%s: active state select failed with %d\n",
+			__func__, ret);
+		return -EIO;
+	}
+
+	clk2_config.enable = 1;
+	ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
+	if (ret < 0) {
+		pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void audio_ext_clk2_unprepare(struct clk *clk)
+{
+	struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(clk);
+	struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
+	int ret;
+
+	if (!pnctrl_info->pinctrl || !pnctrl_info->sleep)
+		return;
+
+	ret = pinctrl_select_state(pnctrl_info->pinctrl,
+				   pnctrl_info->sleep);
+	if (ret)
+		pr_err("%s: sleep state select failed with %d\n",
+			__func__, ret);
+
+	clk2_config.enable = 0;
+	ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
+	if (ret < 0)
+		pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
+}
+
+static const struct clk_ops audio_ext_ap_clk_ops = {
+	.prepare = audio_ext_clk_prepare,
+	.unprepare = audio_ext_clk_unprepare,
+};
+
+static const struct clk_ops audio_ext_ap_clk2_ops = {
+	.prepare = audio_ext_clk2_prepare,
+	.unprepare = audio_ext_clk2_unprepare,
+};
+
+static struct audio_ext_pmi_clk audio_pmi_clk = {
+	.gpio = -EINVAL,
+	.c = {
+		.dbg_name = "audio_ext_pmi_clk",
+		.ops = &clk_ops_dummy,
+		CLK_INIT(audio_pmi_clk.c),
+	},
+};
+
+static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = {
+	.gpio = -EINVAL,
+	.c = {
+		.dbg_name = "audio_ext_pmi_lnbb_clk",
+		.ops = &clk_ops_dummy,
+		CLK_INIT(audio_pmi_lnbb_clk.c),
+	},
+};
+
+static struct audio_ext_ap_clk audio_ap_clk = {
+	.gpio = -EINVAL,
+	.c = {
+		.dbg_name = "audio_ext_ap_clk",
+		.ops = &audio_ext_ap_clk_ops,
+		CLK_INIT(audio_ap_clk.c),
+	},
+};
+
+static struct audio_ext_ap_clk2 audio_ap_clk2 = {
+	.c = {
+		.dbg_name = "audio_ext_ap_clk2",
+		.ops = &audio_ext_ap_clk2_ops,
+		CLK_INIT(audio_ap_clk2.c),
+	},
+};
+
+static struct clk_lookup audio_ref_clock[] = {
+	CLK_LIST(audio_ap_clk),
+	CLK_LIST(audio_pmi_clk),
+	CLK_LIST(audio_pmi_lnbb_clk),
+	CLK_LIST(audio_ap_clk2),
+};
+
+static int audio_get_pinctrl(struct platform_device *pdev)
+{
+	struct pinctrl_info *pnctrl_info;
+	struct pinctrl *pinctrl;
+	int ret;
+
+	pnctrl_info = &audio_ap_clk2.pnctrl_info;
+
+	if (pnctrl_info->pinctrl) {
+		dev_dbg(&pdev->dev, "%s: already requested before\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR_OR_NULL(pinctrl)) {
+		dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n",
+			__func__);
+		return -EINVAL;
+	}
+	pnctrl_info->pinctrl = pinctrl;
+	/* get all state handles from Device Tree */
+	pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
+	if (IS_ERR(pnctrl_info->sleep)) {
+		dev_err(&pdev->dev, "%s: could not get sleep pinstate\n",
+			__func__);
+		goto err;
+	}
+	pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
+	if (IS_ERR(pnctrl_info->active)) {
+		dev_err(&pdev->dev, "%s: could not get active pinstate\n",
+			__func__);
+		goto err;
+	}
+	/* Reset the TLMM pins to a default state */
+	ret = pinctrl_select_state(pnctrl_info->pinctrl,
+				   pnctrl_info->sleep);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n",
+			__func__, ret);
+		goto err;
+	}
+	return 0;
+
+err:
+	devm_pinctrl_put(pnctrl_info->pinctrl);
+	return -EINVAL;
+}
+
+static int audio_ref_clk_probe(struct platform_device *pdev)
+{
+	int clk_gpio;
+	int ret;
+	struct clk *audio_clk;
+
+	clk_gpio = of_get_named_gpio(pdev->dev.of_node,
+				     "qcom,audio-ref-clk-gpio", 0);
+	if (clk_gpio > 0) {
+		ret = gpio_request(clk_gpio, "EXT_CLK");
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Request ext clk gpio failed %d, err:%d\n",
+				clk_gpio, ret);
+			goto err;
+		}
+		if (of_property_read_bool(pdev->dev.of_node,
+					"qcom,node_has_rpm_clock")) {
+			audio_clk = clk_get(&pdev->dev, NULL);
+			if (IS_ERR(audio_clk)) {
+				dev_err(&pdev->dev, "Failed to get RPM div clk\n");
+				ret = PTR_ERR(audio_clk);
+				goto err_gpio;
+			}
+			audio_pmi_clk.c.parent = audio_clk;
+			audio_pmi_clk.gpio = clk_gpio;
+		} else
+			audio_ap_clk.gpio = clk_gpio;
+
+	} else {
+		if (of_property_read_bool(pdev->dev.of_node,
+					"qcom,node_has_rpm_clock")) {
+			audio_clk = clk_get(&pdev->dev, NULL);
+			if (IS_ERR(audio_clk)) {
+				dev_err(&pdev->dev, "Failed to get lnbbclk2\n");
+				ret = PTR_ERR(audio_clk);
+				goto err;
+			}
+			audio_pmi_lnbb_clk.c.parent = audio_clk;
+			audio_pmi_lnbb_clk.gpio = -EINVAL;
+		}
+	}
+
+	ret = audio_get_pinctrl(pdev);
+	if (ret)
+		dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n",
+			__func__);
+
+	ret = of_msm_clock_register(pdev->dev.of_node, audio_ref_clock,
+			      ARRAY_SIZE(audio_ref_clock));
+	if (ret) {
+		dev_err(&pdev->dev, "%s: audio ref clock register failed\n",
+			__func__);
+		goto err_gpio;
+	}
+
+	return 0;
+
+err_gpio:
+	gpio_free(clk_gpio);
+
+err:
+	return ret;
+}
+
+static int audio_ref_clk_remove(struct platform_device *pdev)
+{
+	struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info;
+
+	if (audio_pmi_clk.gpio > 0)
+		gpio_free(audio_pmi_clk.gpio);
+	else if (audio_ap_clk.gpio > 0)
+		gpio_free(audio_ap_clk.gpio);
+
+	if (pnctrl_info->pinctrl) {
+		devm_pinctrl_put(pnctrl_info->pinctrl);
+		pnctrl_info->pinctrl = NULL;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id audio_ref_clk_match[] = {
+	{.compatible = "qcom,audio-ref-clk"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, audio_ref_clk_match);
+
+static struct platform_driver audio_ref_clk_driver = {
+	.driver = {
+		.name = "audio-ref-clk",
+		.owner = THIS_MODULE,
+		.of_match_table = audio_ref_clk_match,
+	},
+	.probe = audio_ref_clk_probe,
+	.remove = audio_ref_clk_remove,
+};
+
+int audio_ref_clk_platform_init(void)
+{
+	return platform_driver_register(&audio_ref_clk_driver);
+}
+
+void audio_ref_clk_platform_exit(void)
+{
+	platform_driver_unregister(&audio_ref_clk_driver);
+}
+
+MODULE_DESCRIPTION("Audio Ref Clock module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/core.h b/asoc/codecs/core.h
new file mode 100644
index 0000000..b994010
--- /dev/null
+++ b/asoc/codecs/core.h
@@ -0,0 +1,440 @@
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MFD_TABLA_CORE_H__
+#define __MFD_TABLA_CORE_H__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/pm_qos.h>
+
+#define WCD9XXX_MAX_IRQ_REGS 4
+#define WCD9XXX_MAX_NUM_IRQS (WCD9XXX_MAX_IRQ_REGS * 8)
+#define WCD9XXX_SLIM_NUM_PORT_REG 3
+#define TABLA_VERSION_1_0	0
+#define TABLA_VERSION_1_1	1
+#define TABLA_VERSION_2_0	2
+#define TABLA_IS_1_X(ver) \
+	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
+#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
+
+#define WCD9XXX_SUPPLY_BUCK_NAME "cdc-vdd-buck"
+
+#define SITAR_VERSION_1P0 0
+#define SITAR_VERSION_1P1 1
+#define SITAR_IS_1P0(ver) \
+	((ver == SITAR_VERSION_1P0) ? 1 : 0)
+#define SITAR_IS_1P1(ver) \
+	((ver == SITAR_VERSION_1P1) ? 1 : 0)
+
+#define TAIKO_VERSION_1_0	1
+#define TAIKO_IS_1_0(ver) \
+	((ver == TAIKO_VERSION_1_0) ? 1 : 0)
+
+#define TAPAN_VERSION_1_0	0
+#define TAPAN_IS_1_0(ver) \
+	((ver == TAPAN_VERSION_1_0) ? 1 : 0)
+
+#define TOMTOM_VERSION_1_0	1
+#define TOMTOM_IS_1_0(ver) \
+	((ver == TOMTOM_VERSION_1_0) ? 1 : 0)
+
+#define TASHA_VERSION_1_0     0
+#define TASHA_VERSION_1_1     1
+#define TASHA_VERSION_2_0     2
+
+#define TASHA_IS_1_0(wcd) \
+	((wcd->type == WCD9335 || wcd->type == WCD9326) ? \
+	((wcd->version == TASHA_VERSION_1_0) ? 1 : 0) : 0)
+
+#define TASHA_IS_1_1(wcd) \
+	((wcd->type == WCD9335 || wcd->type == WCD9326) ? \
+	((wcd->version == TASHA_VERSION_1_1) ? 1 : 0) : 0)
+
+#define TASHA_IS_2_0(wcd) \
+	((wcd->type == WCD9335 || wcd->type == WCD9326) ? \
+	((wcd->version == TASHA_VERSION_2_0) ? 1 : 0) : 0)
+
+/*
+ * As fine version info cannot be retrieved before tavil probe.
+ * Define three coarse versions for possible future use before tavil probe.
+ */
+#define TAVIL_VERSION_1_0             0
+#define TAVIL_VERSION_1_1             1
+#define TAVIL_VERSION_WCD9340_1_0     2
+#define TAVIL_VERSION_WCD9341_1_0     3
+#define TAVIL_VERSION_WCD9340_1_1     4
+#define TAVIL_VERSION_WCD9341_1_1     5
+
+#define TAVIL_IS_1_0(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == TAVIL_VERSION_1_0 || \
+	   wcd->version == TAVIL_VERSION_WCD9340_1_0 || \
+	   wcd->version == TAVIL_VERSION_WCD9341_1_0) ? 1 : 0) : 0)
+#define TAVIL_IS_1_1(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == TAVIL_VERSION_1_1 || \
+	   wcd->version == TAVIL_VERSION_WCD9340_1_1 || \
+	   wcd->version == TAVIL_VERSION_WCD9341_1_1) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9340_1_0(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == TAVIL_VERSION_WCD9340_1_0) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9341_1_0(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == TAVIL_VERSION_WCD9341_1_0) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9340_1_1(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == TAVIL_VERSION_WCD9340_1_1) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9341_1_1(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == TAVIL_VERSION_WCD9341_1_1) ? 1 : 0) : 0)
+
+#define IS_CODEC_TYPE(wcd, wcdtype) \
+	((wcd->type == wcdtype) ? true : false)
+#define IS_CODEC_VERSION(wcd, wcdversion) \
+	((wcd->version == wcdversion) ? true : false)
+
+enum {
+	CDC_V_1_0,
+	CDC_V_1_1,
+	CDC_V_2_0,
+};
+
+enum codec_variant {
+	WCD9XXX,
+	WCD9330,
+	WCD9335,
+	WCD9326,
+	WCD934X,
+};
+
+enum wcd9xxx_slim_slave_addr_type {
+	WCD9XXX_SLIM_SLAVE_ADDR_TYPE_0,
+	WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1,
+};
+
+enum wcd9xxx_pm_state {
+	WCD9XXX_PM_SLEEPABLE,
+	WCD9XXX_PM_AWAKE,
+	WCD9XXX_PM_ASLEEP,
+};
+
+enum {
+	WCD9XXX_INTR_STATUS_BASE = 0,
+	WCD9XXX_INTR_CLEAR_BASE,
+	WCD9XXX_INTR_MASK_BASE,
+	WCD9XXX_INTR_LEVEL_BASE,
+	WCD9XXX_INTR_CLR_COMMIT,
+	WCD9XXX_INTR_REG_MAX,
+};
+
+enum wcd9xxx_intf_status {
+	WCD9XXX_INTERFACE_TYPE_PROBING,
+	WCD9XXX_INTERFACE_TYPE_SLIMBUS,
+	WCD9XXX_INTERFACE_TYPE_I2C,
+};
+
+enum {
+	/* INTR_REG 0 */
+	WCD9XXX_IRQ_SLIMBUS = 0,
+	WCD9XXX_IRQ_MBHC_REMOVAL,
+	WCD9XXX_IRQ_MBHC_SHORT_TERM,
+	WCD9XXX_IRQ_MBHC_PRESS,
+	WCD9XXX_IRQ_MBHC_RELEASE,
+	WCD9XXX_IRQ_MBHC_POTENTIAL,
+	WCD9XXX_IRQ_MBHC_INSERTION,
+	WCD9XXX_IRQ_BG_PRECHARGE,
+	/* INTR_REG 1 */
+	WCD9XXX_IRQ_PA1_STARTUP,
+	WCD9XXX_IRQ_PA2_STARTUP,
+	WCD9XXX_IRQ_PA3_STARTUP,
+	WCD9XXX_IRQ_PA4_STARTUP,
+	WCD9306_IRQ_HPH_PA_OCPR_FAULT = WCD9XXX_IRQ_PA4_STARTUP,
+	WCD9XXX_IRQ_PA5_STARTUP,
+	WCD9XXX_IRQ_MICBIAS1_PRECHARGE,
+	WCD9306_IRQ_HPH_PA_OCPL_FAULT = WCD9XXX_IRQ_MICBIAS1_PRECHARGE,
+	WCD9XXX_IRQ_MICBIAS2_PRECHARGE,
+	WCD9XXX_IRQ_MICBIAS3_PRECHARGE,
+	/* INTR_REG 2 */
+	WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+	WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+	WCD9XXX_IRQ_EAR_PA_OCPL_FAULT,
+	WCD9XXX_IRQ_HPH_L_PA_STARTUP,
+	WCD9XXX_IRQ_HPH_R_PA_STARTUP,
+	WCD9320_IRQ_EAR_PA_STARTUP,
+	WCD9306_IRQ_MBHC_JACK_SWITCH = WCD9320_IRQ_EAR_PA_STARTUP,
+	WCD9310_NUM_IRQS,
+	WCD9XXX_IRQ_RESERVED_0 = WCD9310_NUM_IRQS,
+	WCD9XXX_IRQ_RESERVED_1,
+	WCD9330_IRQ_SVASS_ERR_EXCEPTION = WCD9310_NUM_IRQS,
+	WCD9330_IRQ_MBHC_JACK_SWITCH,
+	/* INTR_REG 3 */
+	WCD9XXX_IRQ_MAD_AUDIO,
+	WCD9XXX_IRQ_MAD_ULTRASOUND,
+	WCD9XXX_IRQ_MAD_BEACON,
+	WCD9XXX_IRQ_SPEAKER_CLIPPING,
+	WCD9320_IRQ_MBHC_JACK_SWITCH,
+	WCD9306_NUM_IRQS,
+	WCD9XXX_IRQ_VBAT_MONITOR_ATTACK = WCD9306_NUM_IRQS,
+	WCD9XXX_IRQ_VBAT_MONITOR_RELEASE,
+	WCD9XXX_NUM_IRQS,
+	/* WCD9330 INTR1_REG 3*/
+	WCD9330_IRQ_SVASS_ENGINE = WCD9XXX_IRQ_MAD_AUDIO,
+	WCD9330_IRQ_MAD_AUDIO,
+	WCD9330_IRQ_MAD_ULTRASOUND,
+	WCD9330_IRQ_MAD_BEACON,
+	WCD9330_IRQ_SPEAKER1_CLIPPING,
+	WCD9330_IRQ_SPEAKER2_CLIPPING,
+	WCD9330_IRQ_VBAT_MONITOR_ATTACK,
+	WCD9330_IRQ_VBAT_MONITOR_RELEASE,
+	WCD9330_NUM_IRQS,
+	WCD9XXX_IRQ_RESERVED_2 = WCD9330_NUM_IRQS,
+};
+
+enum {
+	TABLA_NUM_IRQS = WCD9310_NUM_IRQS,
+	SITAR_NUM_IRQS = WCD9310_NUM_IRQS,
+	TAIKO_NUM_IRQS = WCD9XXX_NUM_IRQS,
+	TAPAN_NUM_IRQS = WCD9306_NUM_IRQS,
+	TOMTOM_NUM_IRQS = WCD9330_NUM_IRQS,
+};
+
+struct intr_data {
+	int intr_num;
+	bool clear_first;
+};
+
+struct wcd9xxx_core_resource {
+	struct mutex irq_lock;
+	struct mutex nested_irq_lock;
+
+	enum wcd9xxx_pm_state pm_state;
+	struct mutex pm_lock;
+	/* pm_wq notifies change of pm_state */
+	wait_queue_head_t pm_wq;
+	struct pm_qos_request pm_qos_req;
+	int wlock_holders;
+
+
+	/* holds the table of interrupts per codec */
+	const struct intr_data *intr_table;
+	int intr_table_size;
+	unsigned int irq_base;
+	unsigned int irq;
+	u8 irq_masks_cur[WCD9XXX_MAX_IRQ_REGS];
+	u8 irq_masks_cache[WCD9XXX_MAX_IRQ_REGS];
+	bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
+	int num_irqs;
+	int num_irq_regs;
+	u16 intr_reg[WCD9XXX_INTR_REG_MAX];
+	struct regmap *wcd_core_regmap;
+
+	/* Pointer to parent container data structure */
+	void *parent;
+
+	struct device *dev;
+	struct irq_domain *domain;
+};
+
+/*
+ * data structure for Slimbus and I2S channel.
+ * Some of fields are only used in smilbus mode
+ */
+struct wcd9xxx_ch {
+	u32 sph;		/* share channel handle - slimbus only	*/
+	u32 ch_num;		/*
+				 * vitrual channel number, such as 128 -144.
+				 * apply for slimbus only
+				 */
+	u16 ch_h;		/* chanel handle - slimbus only */
+	u16 port;		/*
+				 * tabla port for RX and TX
+				 * such as 0-9 for TX and 10 -16 for RX
+				 * apply for both i2s and slimbus
+				 */
+	u16 shift;		/*
+				 * shift bit for RX and TX
+				 * apply for both i2s and slimbus
+				 */
+	struct list_head list;	/*
+				 * channel link list
+				 * apply for both i2s and slimbus
+				 */
+};
+
+struct wcd9xxx_codec_dai_data {
+	u32 rate;				/* sample rate          */
+	u32 bit_width;				/* sit width 16,24,32   */
+	struct list_head wcd9xxx_ch_list;	/* channel list         */
+	u16 grph;				/* slimbus group handle */
+	unsigned long ch_mask;
+	wait_queue_head_t dai_wait;
+	bool bus_down_in_recovery;
+};
+
+#define WCD9XXX_CH(xport, xshift) \
+	{.port = xport, .shift = xshift}
+
+enum wcd9xxx_chipid_major {
+	TABLA_MAJOR = cpu_to_le16(0x100),
+	SITAR_MAJOR = cpu_to_le16(0x101),
+	TAIKO_MAJOR = cpu_to_le16(0x102),
+	TAPAN_MAJOR = cpu_to_le16(0x103),
+	TOMTOM_MAJOR = cpu_to_le16(0x105),
+	TASHA_MAJOR = cpu_to_le16(0x0),
+	TASHA2P0_MAJOR = cpu_to_le16(0x107),
+	TAVIL_MAJOR = cpu_to_le16(0x108),
+};
+
+enum codec_power_states {
+	WCD_REGION_POWER_COLLAPSE_REMOVE,
+	WCD_REGION_POWER_COLLAPSE_BEGIN,
+	WCD_REGION_POWER_DOWN,
+};
+
+enum wcd_power_regions {
+	WCD9XXX_DIG_CORE_REGION_1,
+	WCD9XXX_MAX_PWR_REGIONS,
+};
+
+struct wcd9xxx_codec_type {
+	u16 id_major;
+	u16 id_minor;
+	struct mfd_cell *dev;
+	int size;
+	int num_irqs;
+	int version; /* -1 to retrieve version from chip version register */
+	enum wcd9xxx_slim_slave_addr_type slim_slave_type;
+	u16 i2c_chip_status;
+	const struct intr_data *intr_tbl;
+	int intr_tbl_size;
+	u16 intr_reg[WCD9XXX_INTR_REG_MAX];
+};
+
+struct wcd9xxx_power_region {
+	enum codec_power_states power_state;
+	u16 pwr_collapse_reg_min;
+	u16 pwr_collapse_reg_max;
+};
+
+struct wcd9xxx {
+	struct device *dev;
+	struct slim_device *slim;
+	struct slim_device *slim_slave;
+	struct mutex io_lock;
+	struct mutex xfer_lock;
+	struct mutex reset_lock;
+	u8 version;
+
+	int reset_gpio;
+	struct device_node *wcd_rst_np;
+
+	int (*read_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *dest, bool interface_reg);
+	int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *src, bool interface_reg);
+	int (*multi_reg_write)(struct wcd9xxx *wcd9xxx, const void *data,
+			       size_t count);
+	int (*dev_down)(struct wcd9xxx *wcd9xxx);
+	int (*post_reset)(struct wcd9xxx *wcd9xxx);
+
+	void *ssr_priv;
+	unsigned long dev_up;
+
+	u32 num_of_supplies;
+	struct regulator_bulk_data *supplies;
+
+	struct wcd9xxx_core_resource core_res;
+
+	u16 id_minor;
+	u16 id_major;
+
+	/* Slimbus or I2S port */
+	u32 num_rx_port;
+	u32 num_tx_port;
+	struct wcd9xxx_ch *rx_chs;
+	struct wcd9xxx_ch *tx_chs;
+	u32 mclk_rate;
+	enum codec_variant type;
+	struct regmap *regmap;
+
+	struct wcd9xxx_codec_type *codec_type;
+	bool prev_pg_valid;
+	u8 prev_pg;
+	u8 avoid_cdc_rstlow;
+	struct wcd9xxx_power_region *wcd9xxx_pwr[WCD9XXX_MAX_PWR_REGIONS];
+};
+
+struct wcd9xxx_reg_val {
+	unsigned short reg; /* register address */
+	u8 *buf;            /* buffer to be written to reg. addr */
+	int bytes;          /* number of bytes to be written */
+};
+
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		u8 val);
+int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
+int wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			     int bytes, void *src);
+int wcd9xxx_slim_reserve_bw(struct wcd9xxx *wcd9xxx,
+			    u32 bw_ops, bool commit);
+int wcd9xxx_set_power_state(struct wcd9xxx *wcd9xxx, enum codec_power_states,
+			    enum wcd_power_regions);
+int wcd9xxx_get_current_power_state(struct wcd9xxx *wcd9xxx,
+				    enum wcd_power_regions);
+
+int wcd9xxx_page_write(struct wcd9xxx *wcd9xxx, unsigned short *reg);
+
+int wcd9xxx_slim_bulk_write(struct wcd9xxx *wcd9xxx,
+			    struct wcd9xxx_reg_val *bulk_reg,
+			    unsigned int size, bool interface);
+
+extern int wcd9xxx_core_res_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	int num_irqs, int num_irq_regs, struct regmap *wcd_regmap);
+
+extern void wcd9xxx_core_res_deinit(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res);
+
+extern int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	pm_message_t pmesg);
+
+extern int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res);
+
+extern int wcd9xxx_core_irq_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res);
+
+extern int wcd9xxx_assign_irq(struct wcd9xxx_core_resource *wcd9xxx_core_res,
+			      unsigned int irq,
+			      unsigned int irq_base);
+
+extern enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
+extern void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status);
+
+extern enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+			struct wcd9xxx_core_resource *wcd9xxx_core_res,
+			enum wcd9xxx_pm_state o,
+			enum wcd9xxx_pm_state n);
+static inline int __init wcd9xxx_irq_of_init(struct device_node *node,
+			       struct device_node *parent)
+{
+	return 0;
+}
+
+int wcd9xxx_init(void);
+void wcd9xxx_exit(void);
+#endif
diff --git a/asoc/codecs/cpe_cmi.h b/asoc/codecs/cpe_cmi.h
new file mode 100644
index 0000000..c145a8a
--- /dev/null
+++ b/asoc/codecs/cpe_cmi.h
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CPE_CMI_H__
+#define __CPE_CMI_H__
+
+#include <linux/types.h>
+
+#define CPE_AFE_PORT_1_TX 1
+#define CPE_AFE_PORT_3_TX 3
+#define CPE_AFE_PORT_ID_2_OUT 0x02
+#define CMI_INBAND_MESSAGE_SIZE 127
+
+/*
+ * Multiple mad types can be supported at once.
+ * these values can be OR'ed to form the set of
+ * supported mad types
+ */
+#define MAD_TYPE_AUDIO (1 << 0)
+#define MAD_TYPE_BEACON (1 << 1)
+#define MAD_TYPE_ULTRASND (1 << 2)
+
+/* Core service command opcodes */
+#define CPE_CORE_SVC_CMD_SHARED_MEM_ALLOC	(0x3001)
+#define CPE_CORE_SVC_CMDRSP_SHARED_MEM_ALLOC	(0x3002)
+#define CPE_CORE_SVC_CMD_SHARED_MEM_DEALLOC	(0x3003)
+#define CPE_CORE_SVC_CMD_DRAM_ACCESS_REQ	(0x3004)
+#define CPE_CORE_SVC_EVENT_SYSTEM_BOOT		(0x3005)
+/* core service command opcodes for WCD9335 */
+#define CPE_CORE_SVC_CMD_CFG_CLK_PLAN		(0x3006)
+#define CPE_CORE_SVC_CMD_CLK_FREQ_REQUEST	(0x3007)
+
+#define CPE_BOOT_SUCCESS 0x00
+#define CPE_BOOT_FAILED 0x01
+
+#define CPE_CORE_VERSION_SYSTEM_BOOT_EVENT 0x01
+
+/* LSM Service command opcodes */
+#define CPE_LSM_SESSION_CMD_OPEN_TX		(0x2000)
+#define CPE_LSM_SESSION_CMD_SET_PARAMS		(0x2001)
+#define CPE_LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x2002)
+#define CPE_LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x2003)
+#define CPE_LSM_SESSION_CMD_START		(0x2004)
+#define CPE_LSM_SESSION_CMD_STOP		(0x2005)
+#define CPE_LSM_SESSION_EVENT_DETECTION_STATUS_V2 (0x2006)
+#define CPE_LSM_SESSION_CMD_CLOSE_TX		(0x2007)
+#define CPE_LSM_SESSION_CMD_SHARED_MEM_ALLOC	(0x2008)
+#define CPE_LSM_SESSION_CMDRSP_SHARED_MEM_ALLOC (0x2009)
+#define CPE_LSM_SESSION_CMD_SHARED_MEM_DEALLOC	(0x200A)
+#define CPE_LSM_SESSION_CMD_TX_BUFF_OUTPUT_CONFIG (0x200f)
+#define CPE_LSM_SESSION_CMD_OPEN_TX_V2		(0x200D)
+#define CPE_LSM_SESSION_CMD_SET_PARAMS_V2	(0x200E)
+
+/* LSM Service module and param IDs */
+#define CPE_LSM_MODULE_ID_VOICE_WAKEUP		(0x00012C00)
+#define CPE_LSM_MODULE_ID_VOICE_WAKEUP_V2	(0x00012C0D)
+#define CPE_LSM_MODULE_FRAMEWORK		(0x00012C0E)
+
+#define CPE_LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01)
+#define CPE_LSM_PARAM_ID_OPERATION_MODE		(0x00012C02)
+#define CPE_LSM_PARAM_ID_GAIN			(0x00012C03)
+#define CPE_LSM_PARAM_ID_CONNECT_TO_PORT	(0x00012C04)
+#define CPE_LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS	(0x00012C07)
+
+/* LSM LAB command opcodes */
+#define CPE_LSM_SESSION_CMD_EOB		0x0000200B
+#define CPE_LSM_MODULE_ID_LAB		0x00012C08
+/* used for enable/disable lab*/
+#define CPE_LSM_PARAM_ID_LAB_ENABLE	0x00012C09
+/* used for T in LAB config DSP internal buffer*/
+#define CPE_LSM_PARAM_ID_LAB_CONFIG	0x00012C0A
+#define CPE_LSM_PARAM_ID_REGISTER_SOUND_MODEL	(0x00012C14)
+#define CPE_LSM_PARAM_ID_DEREGISTER_SOUND_MODEL	(0x00012C15)
+#define CPE_LSM_PARAM_ID_MEDIA_FMT		(0x00012C1E)
+
+/* AFE Service command opcodes */
+#define CPE_AFE_PORT_CMD_START			(0x1001)
+#define CPE_AFE_PORT_CMD_STOP			(0x1002)
+#define CPE_AFE_PORT_CMD_SUSPEND		(0x1003)
+#define CPE_AFE_PORT_CMD_RESUME			(0x1004)
+#define CPE_AFE_PORT_CMD_SHARED_MEM_ALLOC	(0x1005)
+#define CPE_AFE_PORT_CMDRSP_SHARED_MEM_ALLOC	(0x1006)
+#define CPE_AFE_PORT_CMD_SHARED_MEM_DEALLOC	(0x1007)
+#define CPE_AFE_PORT_CMD_GENERIC_CONFIG		(0x1008)
+#define CPE_AFE_SVC_CMD_LAB_MODE		(0x1009)
+
+/* AFE Service module and param IDs */
+#define CPE_AFE_CMD_SET_PARAM			(0x1000)
+#define CPE_AFE_MODULE_ID_SW_MAD		(0x0001022D)
+#define CPE_AFE_PARAM_ID_SW_MAD_CFG		(0x0001022E)
+#define CPE_AFE_PARAM_ID_SVM_MODEL		(0x0001022F)
+
+#define CPE_AFE_MODULE_HW_MAD			(0x00010230)
+#define CPE_AFE_PARAM_ID_HW_MAD_CTL		(0x00010232)
+#define CPE_AFE_PARAM_ID_HW_MAD_CFG		(0x00010231)
+
+#define CPE_AFE_MODULE_AUDIO_DEV_INTERFACE	(0x0001020C)
+#define CPE_AFE_PARAM_ID_GENERIC_PORT_CONFIG	(0x00010253)
+
+#define CPE_CMI_BASIC_RSP_OPCODE	(0x0001)
+#define CPE_HDR_MAX_PLD_SIZE	(0x7F)
+
+#define CMI_OBM_FLAG_IN_BAND	0
+#define CMI_OBM_FLAG_OUT_BAND	1
+
+#define CMI_SHMEM_ALLOC_FAILED 0xff
+
+/*
+ * Future Service ID's can be added one line
+ * before the CMI_CPE_SERVICE_ID_MAX
+ */
+enum {
+	CMI_CPE_SERVICE_ID_MIN = 0,
+	CMI_CPE_CORE_SERVICE_ID,
+	CMI_CPE_AFE_SERVICE_ID,
+	CMI_CPE_LSM_SERVICE_ID,
+	CMI_CPE_SERVICE_ID_MAX,
+};
+
+#define CPE_LSM_SESSION_ID_MAX 2
+
+#define IS_VALID_SESSION_ID(s_id) \
+	(s_id <= CPE_LSM_SESSION_ID_MAX)
+
+#define IS_VALID_SERVICE_ID(s_id) \
+	(s_id > CMI_CPE_SERVICE_ID_MIN && \
+	 s_id < CMI_CPE_SERVICE_ID_MAX)
+
+#define IS_VALID_PLD_SIZE(p_size) \
+	(p_size <= CPE_HDR_MAX_PLD_SIZE)
+
+#define CMI_HDR_SET_OPCODE(hdr, cmd) (hdr->opcode = cmd)
+
+
+#define CMI_HDR_SET(hdr_info, mask, shift, value) \
+		(hdr_info = (((hdr_info) & ~(mask)) | \
+			((value << shift) & mask)))
+
+#define SVC_ID_SHIFT 4
+#define SVC_ID_MASK (0x07 << SVC_ID_SHIFT)
+
+#define SESSION_ID_SHIFT 0
+#define SESSION_ID_MASK (0x0F << SESSION_ID_SHIFT)
+
+#define PAYLD_SIZE_SHIFT 0
+#define PAYLD_SIZE_MASK (0x7F << PAYLD_SIZE_SHIFT)
+
+#define OBM_FLAG_SHIFT 7
+#define OBM_FLAG_MASK (1 << OBM_FLAG_SHIFT)
+
+#define VERSION_SHIFT 7
+#define VERSION_MASK (1 << VERSION_SHIFT)
+
+#define CMI_HDR_SET_SERVICE(hdr, s_id) \
+		CMI_HDR_SET(hdr->hdr_info, SVC_ID_MASK,\
+			    SVC_ID_SHIFT, s_id)
+#define CMI_HDR_GET_SERVICE(hdr) \
+		((hdr->hdr_info >> SVC_ID_SHIFT) & \
+			(SVC_ID_MASK >> SVC_ID_SHIFT))
+
+
+#define CMI_HDR_SET_SESSION(hdr, s_id) \
+		CMI_HDR_SET(hdr->hdr_info, SESSION_ID_MASK,\
+			    SESSION_ID_SHIFT, s_id)
+
+#define CMI_HDR_GET_SESSION_ID(hdr) \
+		((hdr->hdr_info >> SESSION_ID_SHIFT) & \
+			 (SESSION_ID_MASK >> SESSION_ID_SHIFT))
+
+#define CMI_GET_HEADER(msg)	((struct cmi_hdr *)(msg))
+#define CMI_GET_PAYLOAD(msg)	((void *)(CMI_GET_HEADER(msg) + 1))
+#define CMI_GET_OPCODE(msg)	(CMI_GET_HEADER(msg)->opcode)
+
+#define CMI_HDR_SET_VERSION(hdr, ver) \
+		CMI_HDR_SET(hdr->hdr_info, VERSION_MASK, \
+				VERSION_SHIFT, ver)
+
+#define CMI_HDR_SET_PAYLOAD_SIZE(hdr, p_size) \
+		CMI_HDR_SET(hdr->pld_info, PAYLD_SIZE_MASK, \
+			    PAYLD_SIZE_SHIFT, p_size)
+
+#define CMI_HDR_GET_PAYLOAD_SIZE(hdr) \
+		((hdr->pld_info >> PAYLD_SIZE_SHIFT) & \
+			(PAYLD_SIZE_MASK >> PAYLD_SIZE_SHIFT))
+
+#define CMI_HDR_SET_OBM(hdr, obm_flag) \
+		CMI_HDR_SET(hdr->pld_info, OBM_FLAG_MASK, \
+			    OBM_FLAG_SHIFT, obm_flag)
+
+#define CMI_HDR_GET_OBM_FLAG(hdr) \
+	((hdr->pld_info >> OBM_FLAG_SHIFT) & \
+		(OBM_FLAG_MASK >> OBM_FLAG_SHIFT))
+
+struct cmi_hdr {
+	/*
+	 * bits 0:3 is session id
+	 * bits 4:6 is service id
+	 * bit 7 is the version flag
+	 */
+	u8 hdr_info;
+
+	/*
+	 * bits 0:6 is payload size in case of in-band message
+	 * bits 0:6 is size (OBM message size)
+	 * bit 7 is the OBM flag
+	 */
+	u8 pld_info;
+
+	/* 16 bit command opcode */
+	u16 opcode;
+} __packed;
+
+union cpe_addr {
+	u64 msw_lsw;
+	void *kvaddr;
+} __packed;
+
+struct cmi_obm {
+	u32 version;
+	u32 size;
+	union cpe_addr data_ptr;
+	u32 mem_handle;
+} __packed;
+
+struct cmi_obm_msg {
+	struct cmi_hdr hdr;
+	struct cmi_obm pld;
+} __packed;
+
+struct cmi_core_svc_event_system_boot {
+	u8 status;
+	u8 version;
+	u16 sfr_buff_size;
+	u32 sfr_buff_address;
+} __packed;
+
+struct cmi_core_svc_cmd_shared_mem_alloc {
+	u32 size;
+} __packed;
+
+struct cmi_core_svc_cmdrsp_shared_mem_alloc {
+	u32 addr;
+} __packed;
+
+struct cmi_core_svc_cmd_clk_freq_request {
+	u32 clk_freq;
+} __packed;
+
+struct cmi_msg_transport {
+	u32 size;
+	u32 addr;
+} __packed;
+
+struct cmi_basic_rsp_result {
+	u8 status;
+} __packed;
+
+struct cpe_lsm_cmd_open_tx {
+	struct cmi_hdr	hdr;
+	u16 app_id;
+	u16 reserved;
+	u32 sampling_rate;
+} __packed;
+
+struct cpe_lsm_cmd_open_tx_v2 {
+	struct cmi_hdr hdr;
+	u32 topology_id;
+} __packed;
+
+struct cpe_cmd_shmem_alloc {
+	struct cmi_hdr hdr;
+	u32 size;
+} __packed;
+
+struct cpe_cmdrsp_shmem_alloc {
+	struct cmi_hdr hdr;
+	u32 addr;
+} __packed;
+
+struct cpe_cmd_shmem_dealloc {
+	struct cmi_hdr	hdr;
+	u32 addr;
+} __packed;
+
+struct cpe_lsm_event_detect_v2 {
+	struct cmi_hdr	hdr;
+	u8 detection_status;
+	u8 size;
+	u8 payload[0];
+} __packed;
+
+struct cpe_lsm_psize_res {
+	u16 param_size;
+	u16 reserved;
+} __packed;
+
+union cpe_lsm_param_size {
+	u32 param_size;
+	struct cpe_lsm_psize_res sr;
+} __packed;
+
+struct cpe_param_data {
+	u32 module_id;
+	u32 param_id;
+	union cpe_lsm_param_size p_size;
+} __packed;
+
+struct cpe_lsm_param_epd_thres {
+	struct cmi_hdr hdr;
+	struct cpe_param_data param;
+	u32 minor_version;
+	u32 epd_begin;
+	u32 epd_end;
+} __packed;
+
+struct cpe_lsm_param_gain {
+	struct cmi_hdr hdr;
+	struct cpe_param_data param;
+	u32 minor_version;
+	u16 gain;
+	u16 reserved;
+} __packed;
+
+struct cpe_afe_hw_mad_ctrl {
+	struct cpe_param_data param;
+	u32 minor_version;
+	u16 mad_type;
+	u16 mad_enable;
+} __packed;
+
+struct cpe_afe_port_cfg {
+	struct cpe_param_data param;
+	u32 minor_version;
+	u16 bit_width;
+	u16 num_channels;
+	u32 sample_rate;
+} __packed;
+
+struct cpe_afe_cmd_port_cfg {
+	struct cmi_hdr hdr;
+	u8 bit_width;
+	u8 num_channels;
+	u16 buffer_size;
+	u32 sample_rate;
+} __packed;
+
+struct cpe_afe_params {
+	struct cmi_hdr hdr;
+	struct cpe_afe_hw_mad_ctrl hw_mad_ctrl;
+	struct cpe_afe_port_cfg port_cfg;
+} __packed;
+
+struct cpe_afe_svc_cmd_mode {
+	struct cmi_hdr hdr;
+	u8 mode;
+} __packed;
+
+struct cpe_lsm_param_opmode {
+	struct cmi_hdr hdr;
+	struct cpe_param_data param;
+	u32 minor_version;
+	u16 mode;
+	u16 reserved;
+} __packed;
+
+struct cpe_lsm_param_connectport {
+	struct cmi_hdr hdr;
+	struct cpe_param_data param;
+	u32 minor_version;
+	u16 afe_port_id;
+	u16 reserved;
+} __packed;
+
+/*
+ * This cannot be sent to CPE as is,
+ * need to append the conf_levels dynamically
+ */
+struct cpe_lsm_conf_level {
+	struct cmi_hdr hdr;
+	struct cpe_param_data param;
+	u8 num_active_models;
+} __packed;
+
+struct cpe_lsm_output_format_cfg {
+	struct cmi_hdr hdr;
+	u8 format;
+	u8 packing;
+	u8 data_path_events;
+} __packed;
+
+struct cpe_lsm_lab_enable {
+	struct cpe_param_data param;
+	u16 enable;
+	u16 reserved;
+} __packed;
+
+struct cpe_lsm_control_lab {
+	struct cmi_hdr hdr;
+	struct cpe_lsm_lab_enable lab_enable;
+} __packed;
+
+struct cpe_lsm_lab_config {
+	struct cpe_param_data param;
+	u32 minor_ver;
+	u32 latency;
+} __packed;
+
+struct cpe_lsm_lab_latency_config {
+	struct cmi_hdr hdr;
+	struct cpe_lsm_lab_config latency_cfg;
+} __packed;
+
+struct cpe_lsm_media_fmt_param {
+	struct cmi_hdr hdr;
+	struct cpe_param_data param;
+	u32 minor_version;
+	u32 sample_rate;
+	u16 num_channels;
+	u16 bit_width;
+} __packed;
+
+
+#define CPE_PARAM_LSM_LAB_LATENCY_SIZE (\
+				sizeof(struct cpe_lsm_lab_latency_config) - \
+				sizeof(struct cmi_hdr))
+#define PARAM_SIZE_LSM_LATENCY_SIZE (\
+					sizeof(struct cpe_lsm_lab_config) - \
+					sizeof(struct cpe_param_data))
+#define CPE_PARAM_SIZE_LSM_LAB_CONTROL (\
+				sizeof(struct cpe_lsm_control_lab) - \
+				sizeof(struct cmi_hdr))
+#define PARAM_SIZE_LSM_CONTROL_SIZE (sizeof(struct cpe_lsm_lab_enable) - \
+					sizeof(struct cpe_param_data))
+#define PARAM_SIZE_AFE_HW_MAD_CTRL (sizeof(struct cpe_afe_hw_mad_ctrl) - \
+				sizeof(struct cpe_param_data))
+#define PARAM_SIZE_AFE_PORT_CFG (sizeof(struct cpe_afe_port_cfg) - \
+				 sizeof(struct cpe_param_data))
+#define CPE_AFE_PARAM_PAYLOAD_SIZE (sizeof(struct cpe_afe_params) - \
+				sizeof(struct cmi_hdr))
+
+#define OPEN_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx) - \
+			       sizeof(struct cmi_hdr))
+#define OPEN_V2_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx_v2) - \
+			       sizeof(struct cmi_hdr))
+#define SHMEM_ALLOC_CMD_PLD_SIZE (sizeof(struct cpe_cmd_shmem_alloc) - \
+				      sizeof(struct cmi_hdr))
+
+#define SHMEM_DEALLOC_CMD_PLD_SIZE (sizeof(struct cpe_cmd_shmem_dealloc) - \
+				      sizeof(struct cmi_hdr))
+#define OUT_FMT_CFG_CMD_PAYLOAD_SIZE ( \
+		sizeof(struct cpe_lsm_output_format_cfg) - \
+		sizeof(struct cmi_hdr))
+
+#define CPE_AFE_CMD_PORT_CFG_PAYLOAD_SIZE \
+		(sizeof(struct cpe_afe_cmd_port_cfg) - \
+		 sizeof(struct cmi_hdr))
+
+#define CPE_AFE_CMD_MODE_PAYLOAD_SIZE \
+		(sizeof(struct cpe_afe_svc_cmd_mode) - \
+		 sizeof(struct cmi_hdr))
+#define CPE_CMD_EPD_THRES_PLD_SIZE (sizeof(struct cpe_lsm_param_epd_thres) - \
+				    sizeof(struct cmi_hdr))
+#define CPE_EPD_THRES_PARAM_SIZE ((CPE_CMD_EPD_THRES_PLD_SIZE) - \
+				  sizeof(struct cpe_param_data))
+#define CPE_CMD_OPMODE_PLD_SIZE (sizeof(struct cpe_lsm_param_opmode) - \
+				 sizeof(struct cmi_hdr))
+#define CPE_OPMODE_PARAM_SIZE ((CPE_CMD_OPMODE_PLD_SIZE) -\
+			       sizeof(struct cpe_param_data))
+#define CPE_CMD_CONNECTPORT_PLD_SIZE \
+	(sizeof(struct cpe_lsm_param_connectport) - \
+	 sizeof(struct cmi_hdr))
+#define CPE_CONNECTPORT_PARAM_SIZE ((CPE_CMD_CONNECTPORT_PLD_SIZE) - \
+				    sizeof(struct cpe_param_data))
+#define CPE_CMD_GAIN_PLD_SIZE (sizeof(struct cpe_lsm_param_gain) - \
+			       sizeof(struct cmi_hdr))
+#define CPE_GAIN_PARAM_SIZE ((CPE_CMD_GAIN_PLD_SIZE) - \
+			     sizeof(struct cpe_param_data))
+#define CPE_MEDIA_FMT_PLD_SIZE (sizeof(struct cpe_lsm_media_fmt_param) - \
+				sizeof(struct cmi_hdr))
+#define CPE_MEDIA_FMT_PARAM_SIZE ((CPE_MEDIA_FMT_PLD_SIZE) - \
+				  sizeof(struct cpe_param_data))
+#endif /* __CPE_CMI_H__ */
diff --git a/asoc/codecs/cpe_core.h b/asoc/codecs/cpe_core.h
new file mode 100644
index 0000000..9f7c2f3
--- /dev/null
+++ b/asoc/codecs/cpe_core.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CPE_CORE_H__
+#define __CPE_CORE_H__
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <sound/lsm_params.h>
+
+enum {
+	CMD_INIT_STATE = 0,
+	CMD_SENT,
+	CMD_RESP_RCVD,
+};
+
+enum wcd_cpe_event {
+	WCD_CPE_PRE_ENABLE = 1,
+	WCD_CPE_POST_ENABLE,
+	WCD_CPE_PRE_DISABLE,
+	WCD_CPE_POST_DISABLE,
+};
+
+struct wcd_cpe_afe_port_cfg {
+	u8 port_id;
+	u16 bit_width;
+	u16 num_channels;
+	u32 sample_rate;
+};
+
+struct lsm_out_fmt_cfg {
+	u8 format;
+	u8 pack_mode;
+	u8 data_path_events;
+	u8 transfer_mode;
+};
+
+struct lsm_hw_params {
+	u32 sample_rate;
+	u16 num_chs;
+	u16 bit_width;
+};
+
+struct cpe_lsm_session {
+	/* sound model related */
+	void *snd_model_data;
+	u8 *conf_levels;
+	void *cmi_reg_handle;
+
+	/* Clients private data */
+	void *priv_d;
+
+	void (*event_cb)(void *priv_data,
+			  u8 detect_status,
+			  u8 size, u8 *payload);
+
+	struct completion cmd_comp;
+	struct wcd_cpe_afe_port_cfg afe_port_cfg;
+	struct wcd_cpe_afe_port_cfg afe_out_port_cfg;
+	struct mutex lsm_lock;
+
+	u32 snd_model_size;
+	u32 lsm_mem_handle;
+	u16 cmd_err_code;
+	u8 id;
+	u8 num_confidence_levels;
+	u16 afe_out_port_id;
+	struct task_struct *lsm_lab_thread;
+	bool started;
+
+	u32 lab_enable;
+	struct lsm_out_fmt_cfg out_fmt_cfg;
+
+	bool is_topology_used;
+};
+
+struct wcd_cpe_afe_ops {
+	int (*afe_set_params)(void *core_handle,
+			       struct wcd_cpe_afe_port_cfg *cfg,
+			       bool afe_mad_ctl);
+
+	int (*afe_port_start)(void *core_handle,
+			       struct wcd_cpe_afe_port_cfg *cfg);
+
+	int (*afe_port_stop)(void *core_handle,
+			       struct wcd_cpe_afe_port_cfg *cfg);
+
+	int (*afe_port_suspend)(void *core_handle,
+			       struct wcd_cpe_afe_port_cfg *cfg);
+
+	int (*afe_port_resume)(void *core_handle,
+			       struct wcd_cpe_afe_port_cfg *cfg);
+
+	int (*afe_port_cmd_cfg)(void *core_handle,
+				struct wcd_cpe_afe_port_cfg *cfg);
+};
+
+struct wcd_cpe_lsm_ops {
+
+	struct cpe_lsm_session *(*lsm_alloc_session)
+			(void *core_handle, void *lsm_priv_d,
+			 void (*event_cb)(void *priv_data,
+					   u8 detect_status,
+					   u8 size, u8 *payload));
+
+	int (*lsm_dealloc_session)
+		(void *core_handle, struct cpe_lsm_session *);
+
+	int (*lsm_open_tx)(void *core_handle,
+			    struct cpe_lsm_session *, u16, u16);
+
+	int (*lsm_close_tx)(void *core_handle,
+			     struct cpe_lsm_session *);
+
+	int (*lsm_shmem_alloc)(void *core_handle,
+				struct cpe_lsm_session *, u32 size);
+
+	int (*lsm_shmem_dealloc)(void *core_handle,
+				  struct cpe_lsm_session *);
+
+	int (*lsm_register_snd_model)(void *core_handle,
+				       struct cpe_lsm_session *,
+				       enum lsm_detection_mode, bool);
+
+	int (*lsm_deregister_snd_model)(void *core_handle,
+					 struct cpe_lsm_session *);
+
+	int (*lsm_get_afe_out_port_id)(void *core_handle,
+			       struct cpe_lsm_session *session);
+
+	int (*lsm_start)(void *core_handle,
+			  struct cpe_lsm_session *);
+
+	int (*lsm_stop)(void *core_handle,
+			 struct cpe_lsm_session *);
+
+	int (*lsm_lab_control)(void *core_handle,
+			       struct cpe_lsm_session *session,
+			       bool enable);
+
+	int (*lab_ch_setup)(void *core_handle,
+				   struct cpe_lsm_session *session,
+				   enum wcd_cpe_event event);
+
+	int (*lsm_set_data)(void *core_handle,
+			struct cpe_lsm_session *session,
+			enum lsm_detection_mode detect_mode,
+			bool detect_failure);
+	int (*lsm_set_fmt_cfg)(void *core_handle,
+			struct cpe_lsm_session *session);
+	int (*lsm_set_one_param)(void *core_handle,
+			struct cpe_lsm_session *session,
+			struct lsm_params_info *p_info,
+			void *data, uint32_t param_type);
+	void (*lsm_get_snd_model_offset)
+		(void *core_handle, struct cpe_lsm_session *,
+		 size_t *offset);
+	int (*lsm_set_media_fmt_params)(void *core_handle,
+				       struct cpe_lsm_session *session,
+				       struct lsm_hw_params *param);
+	int (*lsm_set_port)(void *core_handle,
+			    struct cpe_lsm_session *session, void *data);
+};
+
+int wcd_cpe_get_lsm_ops(struct wcd_cpe_lsm_ops *lsm_ops);
+int wcd_cpe_get_afe_ops(struct wcd_cpe_afe_ops *afe_ops);
+void *wcd_cpe_get_core_handle(struct snd_soc_codec *codec);
+#endif
diff --git a/asoc/codecs/cpe_err.h b/asoc/codecs/cpe_err.h
new file mode 100644
index 0000000..b70dc49
--- /dev/null
+++ b/asoc/codecs/cpe_err.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CPE_ERR__
+#define __CPE_ERR__
+
+#include <linux/errno.h>
+
+/* ERROR CODES */
+/* Success. The operation completed with no errors. */
+#define CPE_EOK          0x00000000
+/* General failure. */
+#define CPE_EFAILED      0x00000001
+/* Bad operation parameter. */
+#define CPE_EBADPARAM    0x00000002
+/* Unsupported routine or operation. */
+#define CPE_EUNSUPPORTED 0x00000003
+/* Unsupported version. */
+#define CPE_EVERSION     0x00000004
+/* Unexpected problem encountered. */
+#define CPE_EUNEXPECTED  0x00000005
+/* Unhandled problem occurred. */
+#define CPE_EPANIC       0x00000006
+/* Unable to allocate resource. */
+#define CPE_ENORESOURCE  0x00000007
+/* Invalid handle. */
+#define CPE_EHANDLE      0x00000008
+/* Operation is already processed. */
+#define CPE_EALREADY     0x00000009
+/* Operation is not ready to be processed. */
+#define CPE_ENOTREADY    0x0000000A
+/* Operation is pending completion. */
+#define CPE_EPENDING     0x0000000B
+/* Operation could not be accepted or processed. */
+#define CPE_EBUSY        0x0000000C
+/* Operation aborted due to an error. */
+#define CPE_EABORTED     0x0000000D
+/* Operation preempted by a higher priority. */
+#define CPE_EPREEMPTED   0x0000000E
+/* Operation requests intervention to complete. */
+#define CPE_ECONTINUE    0x0000000F
+/* Operation requests immediate intervention to complete. */
+#define CPE_EIMMEDIATE   0x00000010
+/* Operation is not implemented. */
+#define CPE_ENOTIMPL     0x00000011
+/* Operation needs more data or resources. */
+#define CPE_ENEEDMORE    0x00000012
+/* Operation does not have memory. */
+#define CPE_ENOMEMORY    0x00000014
+/* Item does not exist. */
+#define CPE_ENOTEXIST    0x00000015
+/* Operation is finished. */
+#define CPE_ETERMINATED  0x00000016
+/* Max count for adsp error code sent to HLOS*/
+#define CPE_ERR_MAX      (CPE_ETERMINATED + 1)
+
+
+/* ERROR STRING */
+/* Success. The operation completed with no errors. */
+#define CPE_EOK_STR          "CPE_EOK"
+/* General failure. */
+#define CPE_EFAILED_STR      "CPE_EFAILED"
+/* Bad operation parameter. */
+#define CPE_EBADPARAM_STR    "CPE_EBADPARAM"
+/* Unsupported routine or operation. */
+#define CPE_EUNSUPPORTED_STR "CPE_EUNSUPPORTED"
+/* Unsupported version. */
+#define CPE_EVERSION_STR     "CPE_EVERSION"
+/* Unexpected problem encountered. */
+#define CPE_EUNEXPECTED_STR  "CPE_EUNEXPECTED"
+/* Unhandled problem occurred. */
+#define CPE_EPANIC_STR       "CPE_EPANIC"
+/* Unable to allocate resource. */
+#define CPE_ENORESOURCE_STR  "CPE_ENORESOURCE"
+/* Invalid handle. */
+#define CPE_EHANDLE_STR      "CPE_EHANDLE"
+/* Operation is already processed. */
+#define CPE_EALREADY_STR     "CPE_EALREADY"
+/* Operation is not ready to be processed. */
+#define CPE_ENOTREADY_STR    "CPE_ENOTREADY"
+/* Operation is pending completion. */
+#define CPE_EPENDING_STR     "CPE_EPENDING"
+/* Operation could not be accepted or processed. */
+#define CPE_EBUSY_STR        "CPE_EBUSY"
+/* Operation aborted due to an error. */
+#define CPE_EABORTED_STR     "CPE_EABORTED"
+/* Operation preempted by a higher priority. */
+#define CPE_EPREEMPTED_STR   "CPE_EPREEMPTED"
+/* Operation requests intervention to complete. */
+#define CPE_ECONTINUE_STR    "CPE_ECONTINUE"
+/* Operation requests immediate intervention to complete. */
+#define CPE_EIMMEDIATE_STR   "CPE_EIMMEDIATE"
+/* Operation is not implemented. */
+#define CPE_ENOTIMPL_STR     "CPE_ENOTIMPL"
+/* Operation needs more data or resources. */
+#define CPE_ENEEDMORE_STR    "CPE_ENEEDMORE"
+/* Operation does not have memory. */
+#define CPE_ENOMEMORY_STR    "CPE_ENOMEMORY"
+/* Item does not exist. */
+#define CPE_ENOTEXIST_STR    "CPE_ENOTEXIST"
+/* Operation is finished. */
+#define CPE_ETERMINATED_STR  "CPE_ETERMINATED"
+/* Unexpected error code. */
+#define CPE_ERR_MAX_STR      "CPE_ERR_MAX"
+
+
+struct cpe_err_code {
+	int     lnx_err_code;
+	char    *cpe_err_str;
+};
+
+
+static struct cpe_err_code cpe_err_code_info[CPE_ERR_MAX+1] = {
+	{ 0, CPE_EOK_STR},
+	{ -ENOTRECOVERABLE, CPE_EFAILED_STR},
+	{ -EINVAL, CPE_EBADPARAM_STR},
+	{ -EOPNOTSUPP, CPE_EUNSUPPORTED_STR},
+	{ -ENOPROTOOPT, CPE_EVERSION_STR},
+	{ -ENOTRECOVERABLE, CPE_EUNEXPECTED_STR},
+	{ -ENOTRECOVERABLE, CPE_EPANIC_STR},
+	{ -ENOSPC, CPE_ENORESOURCE_STR},
+	{ -EBADR, CPE_EHANDLE_STR},
+	{ -EALREADY, CPE_EALREADY_STR},
+	{ -EPERM, CPE_ENOTREADY_STR},
+	{ -EINPROGRESS, CPE_EPENDING_STR},
+	{ -EBUSY, CPE_EBUSY_STR},
+	{ -ECANCELED, CPE_EABORTED_STR},
+	{ -EAGAIN, CPE_EPREEMPTED_STR},
+	{ -EAGAIN, CPE_ECONTINUE_STR},
+	{ -EAGAIN, CPE_EIMMEDIATE_STR},
+	{ -EAGAIN, CPE_ENOTIMPL_STR},
+	{ -ENODATA, CPE_ENEEDMORE_STR},
+	{ -EADV, CPE_ERR_MAX_STR},
+	{ -ENOMEM, CPE_ENOMEMORY_STR},
+	{ -ENODEV, CPE_ENOTEXIST_STR},
+	{ -EADV, CPE_ETERMINATED_STR},
+	{ -EADV, CPE_ERR_MAX_STR},
+};
+
+static inline int cpe_err_get_lnx_err_code(u32 cpe_error)
+{
+	if (cpe_error > CPE_ERR_MAX)
+		return cpe_err_code_info[CPE_ERR_MAX].lnx_err_code;
+	else
+		return cpe_err_code_info[cpe_error].lnx_err_code;
+}
+
+static inline char *cpe_err_get_err_str(u32 cpe_error)
+{
+	if (cpe_error > CPE_ERR_MAX)
+		return cpe_err_code_info[CPE_ERR_MAX].cpe_err_str;
+	else
+		return cpe_err_code_info[cpe_error].cpe_err_str;
+}
+
+#endif
diff --git a/asoc/codecs/msm-cdc-pinctrl.c b/asoc/codecs/msm-cdc-pinctrl.c
new file mode 100644
index 0000000..c4d0ec1
--- /dev/null
+++ b/asoc/codecs/msm-cdc-pinctrl.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include "msm-cdc-pinctrl.h"
+
+struct msm_cdc_pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pinctrl_active;
+	struct pinctrl_state *pinctrl_sleep;
+	int gpio;
+	bool state;
+};
+
+static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata(
+						struct device_node *np)
+{
+	struct platform_device *pdev;
+	struct msm_cdc_pinctrl_info *gpio_data;
+
+	if (!np) {
+		pr_err("%s: device node is null\n", __func__);
+		return NULL;
+	}
+
+	pdev = of_find_device_by_node(np);
+	if (!pdev) {
+		pr_err("%s: platform device not found!\n", __func__);
+		return NULL;
+	}
+
+	gpio_data = dev_get_drvdata(&pdev->dev);
+	if (!gpio_data)
+		dev_err(&pdev->dev, "%s: cannot find cdc gpio info\n",
+			__func__);
+
+	return gpio_data;
+}
+
+/*
+ * msm_cdc_get_gpio_state: select pinctrl sleep state
+ * @np: pointer to struct device_node
+ *
+ * Returns error code for failure and GPIO value on success
+ */
+int msm_cdc_get_gpio_state(struct device_node *np)
+{
+	struct msm_cdc_pinctrl_info *gpio_data;
+	int value = -EINVAL;
+
+	gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
+	if (!gpio_data)
+		return value;
+
+	if (gpio_is_valid(gpio_data->gpio))
+		value = gpio_get_value_cansleep(gpio_data->gpio);
+
+	return value;
+}
+EXPORT_SYMBOL(msm_cdc_get_gpio_state);
+
+/*
+ * msm_cdc_pinctrl_select_sleep_state: select pinctrl sleep state
+ * @np: pointer to struct device_node
+ *
+ * Returns error code for failure
+ */
+int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
+{
+	struct msm_cdc_pinctrl_info *gpio_data;
+
+	gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
+	if (!gpio_data)
+		return -EINVAL;
+
+	if (!gpio_data->pinctrl_sleep) {
+		pr_err("%s: pinctrl sleep state is null\n", __func__);
+		return -EINVAL;
+	}
+	gpio_data->state = false;
+
+	return pinctrl_select_state(gpio_data->pinctrl,
+				    gpio_data->pinctrl_sleep);
+}
+EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state);
+
+/*
+ * msm_cdc_pinctrl_select_active_state: select pinctrl active state
+ * @np: pointer to struct device_node
+ *
+ * Returns error code for failure
+ */
+int msm_cdc_pinctrl_select_active_state(struct device_node *np)
+{
+	struct msm_cdc_pinctrl_info *gpio_data;
+
+	gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
+	if (!gpio_data)
+		return -EINVAL;
+
+	if (!gpio_data->pinctrl_active) {
+		pr_err("%s: pinctrl active state is null\n", __func__);
+		return -EINVAL;
+	}
+	gpio_data->state = true;
+
+	return pinctrl_select_state(gpio_data->pinctrl,
+				    gpio_data->pinctrl_active);
+}
+EXPORT_SYMBOL(msm_cdc_pinctrl_select_active_state);
+
+/*
+ * msm_cdc_pinctrl_get_state: get curren pinctrl state
+ * @np: pointer to struct device_node
+ *
+ * Returns 0 for sleep state, 1 for active state
+ */
+bool msm_cdc_pinctrl_get_state(struct device_node *np)
+{
+	struct msm_cdc_pinctrl_info *gpio_data;
+
+	gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
+	if (!gpio_data)
+		return -EINVAL;
+
+	return gpio_data->state;
+}
+EXPORT_SYMBOL(msm_cdc_pinctrl_get_state);
+
+static int msm_cdc_pinctrl_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_cdc_pinctrl_info *gpio_data;
+
+	gpio_data = devm_kzalloc(&pdev->dev,
+				 sizeof(struct msm_cdc_pinctrl_info),
+				 GFP_KERNEL);
+	if (!gpio_data)
+		return -ENOMEM;
+
+	gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR_OR_NULL(gpio_data->pinctrl)) {
+		dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n",
+			__func__, PTR_ERR(gpio_data->pinctrl));
+		ret = PTR_ERR(gpio_data->pinctrl);
+		goto err_pctrl_get;
+	}
+
+	gpio_data->pinctrl_active = pinctrl_lookup_state(
+					gpio_data->pinctrl, "aud_active");
+	if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) {
+		dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n",
+			__func__, PTR_ERR(gpio_data->pinctrl_active));
+		ret = PTR_ERR(gpio_data->pinctrl_active);
+		goto err_lookup_state;
+	}
+
+	gpio_data->pinctrl_sleep = pinctrl_lookup_state(
+					gpio_data->pinctrl, "aud_sleep");
+	if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) {
+		dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n",
+			__func__, PTR_ERR(gpio_data->pinctrl_sleep));
+		ret = PTR_ERR(gpio_data->pinctrl_sleep);
+		goto err_lookup_state;
+	}
+	/* skip setting to sleep state for LPI_TLMM GPIOs */
+	if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
+		/* Set pinctrl state to aud_sleep by default */
+		ret = pinctrl_select_state(gpio_data->pinctrl,
+					   gpio_data->pinctrl_sleep);
+		if (ret)
+			dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
+				__func__, ret);
+	}
+
+	gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
+					    "qcom,cdc-rst-n-gpio", 0);
+	if (gpio_is_valid(gpio_data->gpio)) {
+		ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET");
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to request gpio %d\n",
+				__func__, gpio_data->gpio);
+			goto err_lookup_state;
+		}
+	}
+
+	dev_set_drvdata(&pdev->dev, gpio_data);
+	return 0;
+
+err_lookup_state:
+	devm_pinctrl_put(gpio_data->pinctrl);
+err_pctrl_get:
+	devm_kfree(&pdev->dev, gpio_data);
+	return ret;
+}
+
+static int msm_cdc_pinctrl_remove(struct platform_device *pdev)
+{
+	struct msm_cdc_pinctrl_info *gpio_data;
+
+	gpio_data = dev_get_drvdata(&pdev->dev);
+
+	if (gpio_data && gpio_data->pinctrl)
+		devm_pinctrl_put(gpio_data->pinctrl);
+
+	devm_kfree(&pdev->dev, gpio_data);
+
+	return 0;
+}
+
+static const struct of_device_id msm_cdc_pinctrl_match[] = {
+	{.compatible = "qcom,msm-cdc-pinctrl"},
+	{}
+};
+
+static struct platform_driver msm_cdc_pinctrl_driver = {
+	.driver = {
+		.name = "msm-cdc-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cdc_pinctrl_match,
+	},
+	.probe = msm_cdc_pinctrl_probe,
+	.remove = msm_cdc_pinctrl_remove,
+};
+
+int msm_cdc_pinctrl_drv_init(void)
+{
+	return platform_driver_register(&msm_cdc_pinctrl_driver);
+}
+
+void msm_cdc_pinctrl_drv_exit(void)
+{
+	platform_driver_unregister(&msm_cdc_pinctrl_driver);
+}
+MODULE_DESCRIPTION("MSM CODEC pin control platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/msm-cdc-pinctrl.h b/asoc/codecs/msm-cdc-pinctrl.h
new file mode 100644
index 0000000..7eabefb
--- /dev/null
+++ b/asoc/codecs/msm-cdc-pinctrl.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MFD_CDC_PINCTRL_H_
+#define __MFD_CDC_PINCTRL_H_
+
+#include <linux/types.h>
+#include <linux/of.h>
+
+#if IS_ENABLED(CONFIG_MSM_CDC_PINCTRL)
+extern int msm_cdc_pinctrl_select_sleep_state(struct device_node *np);
+extern int msm_cdc_pinctrl_select_active_state(struct device_node *np);
+extern bool msm_cdc_pinctrl_get_state(struct device_node *np);
+extern int msm_cdc_get_gpio_state(struct device_node *np);
+int msm_cdc_pinctrl_drv_init(void);
+void msm_cdc_pinctrl_drv_exit(void);
+
+#else
+int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
+{
+	return 0;
+}
+int msm_cdc_pinctrl_select_active_state(struct device_node *np)
+{
+	return 0;
+}
+int msm_cdc_get_gpio_state(struct device_node *np)
+{
+	return 0;
+}
+int msm_cdc_pinctrl_drv_init(void)
+{
+	return 0;
+}
+void msm_cdc_pinctrl_drv_exit(void)
+{
+}
+#endif
+
+#endif
diff --git a/asoc/codecs/msm-cdc-supply.c b/asoc/codecs/msm-cdc-supply.c
new file mode 100644
index 0000000..e36baa8
--- /dev/null
+++ b/asoc/codecs/msm-cdc-supply.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include "msm-cdc-supply.h"
+#include <linux/regulator/consumer.h>
+
+#define CODEC_DT_MAX_PROP_SIZE 40
+
+static int msm_cdc_dt_parse_vreg_info(struct device *dev,
+				      struct cdc_regulator *cdc_vreg,
+				      const char *name, bool is_ond)
+{
+	char prop_name[CODEC_DT_MAX_PROP_SIZE];
+	struct device_node *regulator_node = NULL;
+	const __be32 *prop;
+	int len, rc;
+	u32 prop_val;
+
+	/* Parse supply name */
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply", name);
+
+	regulator_node = of_parse_phandle(dev->of_node, prop_name, 0);
+	if (!regulator_node) {
+		dev_err(dev, "%s: Looking up %s property in node %s failed",
+			__func__, prop_name, dev->of_node->full_name);
+		rc = -EINVAL;
+		goto done;
+	}
+	cdc_vreg->name = name;
+	cdc_vreg->ondemand = is_ond;
+
+	/* Parse supply - voltage */
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-voltage", name);
+	prop = of_get_property(dev->of_node, prop_name, &len);
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_err(dev, "%s: %s %s property\n", __func__,
+			prop ? "invalid format" : "no", prop_name);
+		rc = -EINVAL;
+		goto done;
+	} else {
+		cdc_vreg->min_uV = be32_to_cpup(&prop[0]);
+		cdc_vreg->max_uV = be32_to_cpup(&prop[1]);
+	}
+
+	/* Parse supply - current */
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-current", name);
+	rc = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (rc) {
+		dev_err(dev, "%s: Looking up %s property in node %s failed",
+			__func__, prop_name, dev->of_node->full_name);
+		goto done;
+	}
+	cdc_vreg->optimum_uA = prop_val;
+
+	dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n",
+		 __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV,
+		 cdc_vreg->optimum_uA, cdc_vreg->ondemand);
+
+done:
+	return rc;
+}
+
+static int msm_cdc_parse_supplies(struct device *dev,
+				  struct cdc_regulator *cdc_reg,
+				  const char *sup_list, int sup_cnt,
+				  bool is_ond)
+{
+	int idx, rc = 0;
+	const char *name = NULL;
+
+	for (idx = 0; idx < sup_cnt; idx++) {
+		rc = of_property_read_string_index(dev->of_node, sup_list, idx,
+						   &name);
+		if (rc) {
+			dev_err(dev, "%s: read string %s[%d] error (%d)\n",
+				__func__, sup_list, idx, rc);
+			goto done;
+		}
+
+		dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n",
+			__func__, name, sup_list);
+
+		rc = msm_cdc_dt_parse_vreg_info(dev, &cdc_reg[idx], name,
+						is_ond);
+		if (rc) {
+			dev_err(dev, "%s: parse %s vreg info failed (%d)\n",
+				__func__, name, rc);
+			goto done;
+		}
+	}
+
+done:
+	return rc;
+}
+
+static int msm_cdc_check_supply_param(struct device *dev,
+				      struct cdc_regulator *cdc_vreg,
+				      int num_supplies)
+{
+	if (!dev) {
+		pr_err("%s: device is NULL\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!cdc_vreg || (num_supplies <= 0)) {
+		dev_err(dev, "%s: supply check failed: vreg: %pK, num_supplies: %d\n",
+			__func__, cdc_vreg, num_supplies);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * msm_cdc_disable_static_supplies:
+ *	Disable codec static supplies
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply disable is failed
+ */
+int msm_cdc_disable_static_supplies(struct device *dev,
+				    struct regulator_bulk_data *supplies,
+				    struct cdc_regulator *cdc_vreg,
+				    int num_supplies)
+{
+	int rc, i;
+
+	if ((!dev) || (!supplies) || (!cdc_vreg)) {
+		pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
+				__func__);
+		return -EINVAL;
+	}
+	/* input parameter validation */
+	rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < num_supplies; i++) {
+		if (cdc_vreg[i].ondemand)
+			continue;
+
+		rc = regulator_disable(supplies[i].consumer);
+		if (rc)
+			dev_err(dev, "%s: failed to disable supply %s, err:%d\n",
+				__func__, supplies[i].supply, rc);
+		else
+			dev_dbg(dev, "%s: disabled regulator %s\n",
+				__func__, supplies[i].supply);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_cdc_disable_static_supplies);
+
+/*
+ * msm_cdc_release_supplies:
+ *	Release codec power supplies
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply disable is failed
+ */
+int msm_cdc_release_supplies(struct device *dev,
+			     struct regulator_bulk_data *supplies,
+			     struct cdc_regulator *cdc_vreg,
+			     int num_supplies)
+{
+	int rc = 0;
+	int i;
+
+	if ((!dev) || (!supplies) || (!cdc_vreg)) {
+		pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
+				__func__);
+		return -EINVAL;
+	}
+	/* input parameter validation */
+	rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+	if (rc)
+		return rc;
+
+	msm_cdc_disable_static_supplies(dev, supplies, cdc_vreg,
+					num_supplies);
+	for (i = 0; i < num_supplies; i++) {
+		if (regulator_count_voltages(supplies[i].consumer) < 0)
+			continue;
+
+		regulator_set_voltage(supplies[i].consumer, 0,
+				      cdc_vreg[i].max_uV);
+		regulator_set_load(supplies[i].consumer, 0);
+		devm_regulator_put(supplies[i].consumer);
+		supplies[i].consumer = NULL;
+	}
+	devm_kfree(dev, supplies);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_cdc_release_supplies);
+
+/*
+ * msm_cdc_enable_static_supplies:
+ *	Enable codec static supplies
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply enable is failed
+ */
+int msm_cdc_enable_static_supplies(struct device *dev,
+				   struct regulator_bulk_data *supplies,
+				   struct cdc_regulator *cdc_vreg,
+				   int num_supplies)
+{
+	int rc, i;
+
+	if ((!dev) || (!supplies) || (!cdc_vreg)) {
+		pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
+				__func__);
+		return -EINVAL;
+	}
+	/* input parameter validation */
+	rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < num_supplies; i++) {
+		if (cdc_vreg[i].ondemand)
+			continue;
+
+		rc = regulator_enable(supplies[i].consumer);
+		if (rc) {
+			dev_err(dev, "%s: failed to enable supply %s, rc: %d\n",
+				__func__, supplies[i].supply, rc);
+			break;
+		}
+	}
+
+	while (rc && i--)
+		if (!cdc_vreg[i].ondemand)
+			regulator_disable(supplies[i].consumer);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_cdc_enable_static_supplies);
+
+/*
+ * msm_cdc_init_supplies:
+ *	Initialize codec static supplies with regulator get
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply init is failed
+ */
+int msm_cdc_init_supplies(struct device *dev,
+			  struct regulator_bulk_data **supplies,
+			  struct cdc_regulator *cdc_vreg,
+			  int num_supplies)
+{
+	struct regulator_bulk_data *vsup;
+	int rc;
+	int i;
+
+	if (!dev || !cdc_vreg) {
+		pr_err("%s: device pointer or dce_vreg is NULL\n",
+				__func__);
+		return -EINVAL;
+	}
+	/* input parameter validation */
+	rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+	if (rc)
+		return rc;
+
+	vsup = devm_kcalloc(dev, num_supplies,
+			    sizeof(struct regulator_bulk_data),
+			    GFP_KERNEL);
+	if (!vsup)
+		return -ENOMEM;
+
+	for (i = 0; i < num_supplies; i++) {
+		if (!cdc_vreg[i].name) {
+			dev_err(dev, "%s: supply name not defined\n",
+				__func__);
+			rc = -EINVAL;
+			goto err_supply;
+		}
+		vsup[i].supply = cdc_vreg[i].name;
+	}
+
+	rc = devm_regulator_bulk_get(dev, num_supplies, vsup);
+	if (rc) {
+		dev_err(dev, "%s: failed to get supplies (%d)\n",
+			__func__, rc);
+		goto err_supply;
+	}
+
+	/* Set voltage and current on regulators */
+	for (i = 0; i < num_supplies; i++) {
+		if (regulator_count_voltages(vsup[i].consumer) < 0)
+			continue;
+
+		rc = regulator_set_voltage(vsup[i].consumer,
+					   cdc_vreg[i].min_uV,
+					   cdc_vreg[i].max_uV);
+		if (rc) {
+			dev_err(dev, "%s: set regulator voltage failed for %s, err:%d\n",
+				__func__, vsup[i].supply, rc);
+			goto err_set_supply;
+		}
+		rc = regulator_set_load(vsup[i].consumer,
+					cdc_vreg[i].optimum_uA);
+		if (rc < 0) {
+			dev_err(dev, "%s: set regulator optimum mode failed for %s, err:%d\n",
+				__func__, vsup[i].supply, rc);
+			goto err_set_supply;
+		}
+	}
+
+	*supplies = vsup;
+
+	return 0;
+
+err_set_supply:
+	for (i = 0; i < num_supplies; i++)
+		devm_regulator_put(vsup[i].consumer);
+err_supply:
+	devm_kfree(dev, vsup);
+	return rc;
+}
+EXPORT_SYMBOL(msm_cdc_init_supplies);
+
+/*
+ * msm_cdc_get_power_supplies:
+ *	Get codec power supplies from device tree.
+ *	Allocate memory to hold regulator data for
+ *	all power supplies.
+ *
+ * @dev: pointer to codec device
+ * @cdc_vreg: pointer to codec regulator
+ * @total_num_supplies: total number of supplies read from DT
+ *
+ * Return error code if supply disable is failed
+ */
+int msm_cdc_get_power_supplies(struct device *dev,
+			       struct cdc_regulator **cdc_vreg,
+			       int *total_num_supplies)
+{
+	const char *static_prop_name = "qcom,cdc-static-supplies";
+	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+	const char *cp_prop_name = "qcom,cdc-cp-supplies";
+	int static_sup_cnt = 0;
+	int ond_sup_cnt = 0;
+	int cp_sup_cnt = 0;
+	int num_supplies = 0;
+	struct cdc_regulator *cdc_reg;
+	int rc;
+
+	if (!dev) {
+		pr_err("%s: device pointer is NULL\n", __func__);
+		return -EINVAL;
+	}
+	static_sup_cnt = of_property_count_strings(dev->of_node,
+						   static_prop_name);
+	if (static_sup_cnt < 0) {
+		dev_err(dev, "%s: Failed to get static supplies(%d)\n",
+			__func__, static_sup_cnt);
+		rc = static_sup_cnt;
+		goto err_supply_cnt;
+	}
+	ond_sup_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+	if (ond_sup_cnt < 0)
+		ond_sup_cnt = 0;
+
+	cp_sup_cnt = of_property_count_strings(dev->of_node,
+					       cp_prop_name);
+	if (cp_sup_cnt < 0)
+		cp_sup_cnt = 0;
+
+	num_supplies = static_sup_cnt + ond_sup_cnt + cp_sup_cnt;
+	if (num_supplies <= 0) {
+		dev_err(dev, "%s: supply count is 0 or negative\n", __func__);
+		rc = -EINVAL;
+		goto err_supply_cnt;
+	}
+
+	cdc_reg = devm_kcalloc(dev, num_supplies,
+			       sizeof(struct cdc_regulator),
+			       GFP_KERNEL);
+	if (!cdc_reg) {
+		rc = -ENOMEM;
+		goto err_mem_alloc;
+	}
+
+	rc = msm_cdc_parse_supplies(dev, cdc_reg, static_prop_name,
+				    static_sup_cnt, false);
+	if (rc) {
+		dev_err(dev, "%s: failed to parse static supplies(%d)\n",
+				__func__, rc);
+		goto err_sup;
+	}
+
+	rc = msm_cdc_parse_supplies(dev, &cdc_reg[static_sup_cnt],
+				    ond_prop_name, ond_sup_cnt,
+				    true);
+	if (rc) {
+		dev_err(dev, "%s: failed to parse demand supplies(%d)\n",
+				__func__, rc);
+		goto err_sup;
+	}
+
+	rc = msm_cdc_parse_supplies(dev,
+				    &cdc_reg[static_sup_cnt + ond_sup_cnt],
+				    cp_prop_name, cp_sup_cnt, true);
+	if (rc) {
+		dev_err(dev, "%s: failed to parse cp supplies(%d)\n",
+				__func__, rc);
+		goto err_sup;
+	}
+
+	*cdc_vreg = cdc_reg;
+	*total_num_supplies = num_supplies;
+
+	return 0;
+
+err_sup:
+	devm_kfree(dev, cdc_reg);
+err_supply_cnt:
+err_mem_alloc:
+	return rc;
+}
+EXPORT_SYMBOL(msm_cdc_get_power_supplies);
diff --git a/asoc/codecs/msm-cdc-supply.h b/asoc/codecs/msm-cdc-supply.h
new file mode 100644
index 0000000..b40f44b
--- /dev/null
+++ b/asoc/codecs/msm-cdc-supply.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CODEC_POWER_SUPPLY_H__
+#define __CODEC_POWER_SUPPLY_H__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+struct cdc_regulator {
+	const char *name;
+	int min_uV;
+	int max_uV;
+	int optimum_uA;
+	bool ondemand;
+	struct regulator *regulator;
+};
+
+extern int msm_cdc_get_power_supplies(struct device *dev,
+				      struct cdc_regulator **cdc_vreg,
+				      int *total_num_supplies);
+extern int msm_cdc_disable_static_supplies(struct device *dev,
+					struct regulator_bulk_data *supplies,
+					struct cdc_regulator *cdc_vreg,
+					int num_supplies);
+extern int msm_cdc_release_supplies(struct device *dev,
+				    struct regulator_bulk_data *supplies,
+				    struct cdc_regulator *cdc_vreg,
+				    int num_supplies);
+extern int msm_cdc_enable_static_supplies(struct device *dev,
+					  struct regulator_bulk_data *supplies,
+					  struct cdc_regulator *cdc_vreg,
+					  int num_supplies);
+extern int msm_cdc_init_supplies(struct device *dev,
+				 struct regulator_bulk_data **supplies,
+				 struct cdc_regulator *cdc_vreg,
+				 int num_supplies);
+#endif
diff --git a/asoc/codecs/msm_hdmi_codec_rx.c b/asoc/codecs/msm_hdmi_codec_rx.c
new file mode 100644
index 0000000..46cfe7d
--- /dev/null
+++ b/asoc/codecs/msm_hdmi_codec_rx.c
@@ -0,0 +1,562 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/err.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <linux/msm_ext_display.h>
+
+#define MSM_EXT_DISP_PCM_RATES	SNDRV_PCM_RATE_48000
+#define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT)
+#define AUD_EXT_DISP_ACK_CONNECT    (AUDIO_ACK_CONNECT)
+#define AUD_EXT_DISP_ACK_ENABLE     (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE)
+
+static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"};
+static const char *const ext_disp_audio_ack_text[] = {"Disconnect",  "Connect",
+						      "Ack_Enable"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_type, ext_disp_audio_type_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_ack_state,
+				ext_disp_audio_ack_text);
+
+struct msm_ext_disp_audio_codec_rx_data {
+	struct platform_device *ext_disp_core_pdev;
+	struct msm_ext_disp_audio_codec_ops ext_disp_ops;
+	int cable_status;
+};
+
+static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_ext_disp_audio_codec_rx_data *codec_data;
+	struct msm_ext_disp_audio_edid_blk edid_blk;
+	int rc;
+
+	codec_data = snd_soc_codec_get_drvdata(codec);
+
+	if (!codec_data) {
+		dev_err(codec->dev, "%s: codec_data is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!codec_data->ext_disp_ops.get_audio_edid_blk) {
+		dev_dbg(codec->dev, "%s: get_audio_edid_blk() is NULL\n",
+			__func__);
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+		uinfo->count = 0;
+		return 0;
+	}
+
+	rc = codec_data->ext_disp_ops.get_audio_edid_blk(
+				codec_data->ext_disp_core_pdev, &edid_blk);
+	if (rc >= 0) {
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+		uinfo->count = edid_blk.audio_data_blk_size +
+			edid_blk.spk_alloc_data_blk_size;
+	}
+
+	dev_dbg(codec->dev, "%s: count: %d\n", __func__, uinfo->count);
+
+	return rc;
+}
+
+static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol) {
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_ext_disp_audio_codec_rx_data *codec_data;
+	struct msm_ext_disp_audio_edid_blk edid_blk;
+	int rc;
+
+	codec_data = snd_soc_codec_get_drvdata(codec);
+	if (!codec_data || !codec_data->ext_disp_ops.get_audio_edid_blk) {
+		dev_err(codec->dev, "%s: codec_data or get_audio_edid_blk() is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = codec_data->ext_disp_ops.get_audio_edid_blk(
+			codec_data->ext_disp_core_pdev, &edid_blk);
+	if (rc >= 0) {
+		if (sizeof(ucontrol->value.bytes.data) <
+			  (edid_blk.audio_data_blk_size +
+			   edid_blk.spk_alloc_data_blk_size)) {
+			dev_err(codec->dev,
+				"%s: Not enough memory to copy EDID data\n",
+				__func__);
+			return -ENOMEM;
+		}
+
+		memcpy(ucontrol->value.bytes.data,
+		       edid_blk.audio_data_blk,
+		       edid_blk.audio_data_blk_size);
+		memcpy((ucontrol->value.bytes.data +
+		       edid_blk.audio_data_blk_size),
+		       edid_blk.spk_alloc_data_blk,
+		       edid_blk.spk_alloc_data_blk_size);
+
+		dev_dbg(codec->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n",
+			__func__, edid_blk.audio_data_blk_size,
+			edid_blk.spk_alloc_data_blk_size);
+	}
+
+	return rc;
+}
+
+static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_ext_disp_audio_codec_rx_data *codec_data;
+	enum msm_ext_disp_cable_state cable_state;
+	enum msm_ext_disp_type disp_type;
+	int rc;
+
+	codec_data = snd_soc_codec_get_drvdata(codec);
+	if (!codec_data ||
+	    !codec_data->ext_disp_ops.get_audio_edid_blk ||
+	    !codec_data->ext_disp_ops.get_intf_id) {
+		dev_err(codec->dev, "%s: codec_data, get_audio_edid_blk() or get_intf_id is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	cable_state = codec_data->ext_disp_ops.cable_status(
+				   codec_data->ext_disp_core_pdev, 1);
+	if (cable_state < 0) {
+		dev_err(codec->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n",
+			__func__, cable_state);
+		rc = cable_state;
+		goto done;
+	}
+
+	codec_data->cable_status = cable_state;
+	if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) {
+		dev_err(codec->dev, "%s: Display cable disconnected\n",
+			__func__);
+		ucontrol->value.integer.value[0] = 0;
+		rc = 0;
+		goto done;
+	}
+
+	disp_type = codec_data->ext_disp_ops.get_intf_id(
+						codec_data->ext_disp_core_pdev);
+	if (disp_type >= 0) {
+		switch (disp_type) {
+		case EXT_DISPLAY_TYPE_DP:
+			ucontrol->value.integer.value[0] = 2;
+			rc = 0;
+			break;
+		case EXT_DISPLAY_TYPE_HDMI:
+			ucontrol->value.integer.value[0] = 1;
+			rc = 0;
+			break;
+		default:
+			rc = -EINVAL;
+			dev_err(codec->dev, "%s: Invalid disp_type:%d\n",
+			       __func__, disp_type);
+			goto done;
+		}
+		dev_dbg(codec->dev, "%s: Display type: %d\n",
+			__func__, disp_type);
+	} else {
+		dev_err(codec->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n",
+			__func__, disp_type);
+		rc = disp_type;
+	}
+
+done:
+	return rc;
+}
+
+static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_ext_disp_audio_codec_rx_data *codec_data;
+	u32 ack_state = 0;
+	int rc;
+
+	codec_data = snd_soc_codec_get_drvdata(codec);
+	if (!codec_data ||
+	    !codec_data->ext_disp_ops.acknowledge) {
+		dev_err(codec->dev,
+			"%s: codec_data or ops acknowledge() is NULL\n",
+			__func__);
+		rc = -EINVAL;
+		goto done;
+	}
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		ack_state = AUD_EXT_DISP_ACK_DISCONNECT;
+		break;
+	case 1:
+		ack_state = AUD_EXT_DISP_ACK_CONNECT;
+		break;
+	case 2:
+		ack_state = AUD_EXT_DISP_ACK_ENABLE;
+		break;
+	default:
+		rc = -EINVAL;
+		dev_err(codec->dev,
+			"%s: invalid value %d for mixer ctl\n",
+			__func__, ucontrol->value.enumerated.item[0]);
+		goto done;
+	}
+	dev_dbg(codec->dev, "%s: control %d, ack set value 0x%x\n",
+		__func__, ucontrol->value.enumerated.item[0], ack_state);
+
+	rc = codec_data->ext_disp_ops.acknowledge(
+			 codec_data->ext_disp_core_pdev, ack_state);
+	if (rc < 0) {
+		dev_err(codec->dev, "%s: error from acknowledge(), err:%d\n",
+			__func__, rc);
+	}
+
+done:
+	return rc;
+}
+
+static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.iface  = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name   = "HDMI EDID",
+		.info   = msm_ext_disp_edid_ctl_info,
+		.get    = msm_ext_disp_edid_get,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.iface  = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name   = "Display Port EDID",
+		.info   = msm_ext_disp_edid_ctl_info,
+		.get    = msm_ext_disp_edid_get,
+	},
+	SOC_ENUM_EXT("External Display Type", ext_disp_audio_type,
+		     msm_ext_disp_audio_type_get, NULL),
+	SOC_ENUM_EXT("External Display Audio Ack", ext_disp_audio_ack_state,
+		     NULL, msm_ext_disp_audio_ack_set),
+};
+
+static int msm_ext_disp_audio_codec_rx_dai_startup(
+		struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	int ret = 0;
+	struct msm_ext_disp_audio_codec_rx_data *codec_data =
+			dev_get_drvdata(dai->codec->dev);
+
+	if (!codec_data || !codec_data->ext_disp_ops.cable_status) {
+		dev_err(dai->dev, "%s() codec_data or cable_status is null\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	codec_data->cable_status =
+		codec_data->ext_disp_ops.cable_status(
+		codec_data->ext_disp_core_pdev, 1);
+	if (codec_data->cable_status < 0) {
+		dev_err(dai->dev,
+			"%s() ext disp core is not ready (ret val = %d)\n",
+			__func__, codec_data->cable_status);
+		ret = codec_data->cable_status;
+	} else if (!codec_data->cable_status) {
+		dev_err(dai->dev,
+			"%s() ext disp cable is not connected (ret val = %d)\n",
+			__func__, codec_data->cable_status);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int msm_ext_disp_audio_codec_rx_dai_hw_params(
+		struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	u32 channel_allocation = 0;
+	u32 level_shift  = 0; /* 0dB */
+	bool down_mix = 0;
+	u32 num_channels = params_channels(params);
+	int rc = 0;
+	struct msm_ext_disp_audio_setup_params audio_setup_params = {0};
+
+	struct msm_ext_disp_audio_codec_rx_data *codec_data =
+			dev_get_drvdata(dai->codec->dev);
+
+	if (!codec_data || !codec_data->ext_disp_ops.audio_info_setup) {
+		dev_err(dai->dev, "%s: codec_data or audio_info_setup is null\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (codec_data->cable_status < 0) {
+		dev_err_ratelimited(dai->dev,
+			"%s() ext disp core is not ready (ret val = %d)\n",
+			__func__, codec_data->cable_status);
+		return codec_data->cable_status;
+	} else if (!codec_data->cable_status) {
+		dev_err_ratelimited(dai->dev,
+			"%s() ext disp cable is not connected (ret val = %d)\n",
+			__func__, codec_data->cable_status);
+		return -ENODEV;
+	}
+
+	/*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
+	switch (num_channels) {
+	case 2:
+		channel_allocation  = 0;
+		break;
+	case 3:
+		channel_allocation  = 0x02;/*default to FL/FR/FC*/
+		audio_setup_params.sample_present = 0x3;
+		break;
+	case 4:
+		channel_allocation  = 0x06;/*default to FL/FR/FC/RC*/
+		audio_setup_params.sample_present = 0x7;
+		break;
+	case 5:
+		channel_allocation  = 0x0A;/*default to FL/FR/FC/RR/RL*/
+		audio_setup_params.sample_present = 0x7;
+		break;
+	case 6:
+		channel_allocation  = 0x0B;
+		audio_setup_params.sample_present = 0x7;
+		break;
+	case 7:
+		channel_allocation  = 0x12;/*default to FL/FR/FC/RL/RR/RRC/RLC*/
+		audio_setup_params.sample_present = 0xf;
+		break;
+	case 8:
+		channel_allocation  = 0x13;
+		audio_setup_params.sample_present = 0xf;
+		break;
+	default:
+		dev_err(dai->dev, "invalid Channels = %u\n", num_channels);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev,
+		"%s() num_ch %u  samplerate %u channel_allocation = %u\n",
+		__func__, num_channels, params_rate(params),
+		channel_allocation);
+
+	audio_setup_params.sample_rate_hz = params_rate(params);
+	audio_setup_params.num_of_channels = num_channels;
+	audio_setup_params.channel_allocation = channel_allocation;
+	audio_setup_params.level_shift = level_shift;
+	audio_setup_params.down_mix = down_mix;
+
+	rc = codec_data->ext_disp_ops.audio_info_setup(
+			codec_data->ext_disp_core_pdev, &audio_setup_params);
+	if (rc < 0) {
+		dev_err_ratelimited(dai->dev,
+			"%s() ext disp core is not ready, rc: %d\n",
+			__func__, rc);
+	}
+
+	return rc;
+}
+
+static void msm_ext_disp_audio_codec_rx_dai_shutdown(
+		struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	int rc;
+
+	struct msm_ext_disp_audio_codec_rx_data *codec_data =
+			dev_get_drvdata(dai->codec->dev);
+
+	if (!codec_data || !codec_data->ext_disp_ops.teardown_done ||
+	    !codec_data->ext_disp_ops.cable_status) {
+		dev_err(dai->dev, "%s: codec data or teardown_done or cable_status is null\n",
+			__func__);
+		return;
+	}
+
+	rc = codec_data->ext_disp_ops.cable_status(
+			codec_data->ext_disp_core_pdev, 0);
+	if (rc < 0) {
+		dev_err(dai->dev,
+			"%s: ext disp core had problems releasing audio flag\n",
+			__func__);
+	}
+
+	codec_data->ext_disp_ops.teardown_done(
+		codec_data->ext_disp_core_pdev);
+}
+
+static int msm_ext_disp_audio_codec_rx_probe(struct snd_soc_codec *codec)
+{
+	struct msm_ext_disp_audio_codec_rx_data *codec_data;
+	struct device_node *of_node_parent = NULL;
+
+	codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data),
+		GFP_KERNEL);
+
+	if (!codec_data) {
+		dev_err(codec->dev, "%s(): fail to allocate dai data\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	of_node_parent = of_get_parent(codec->dev->of_node);
+	if (!of_node_parent) {
+		dev_err(codec->dev, "%s(): Parent device tree node not found\n",
+				__func__);
+		kfree(codec_data);
+		return -ENODEV;
+	}
+
+	codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent);
+	if (!codec_data->ext_disp_core_pdev) {
+		dev_err(codec->dev, "%s(): can't get parent pdev\n", __func__);
+		kfree(codec_data);
+		return -ENODEV;
+	}
+
+	if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev,
+				&codec_data->ext_disp_ops)) {
+		dev_err(codec->dev, "%s(): can't register with ext disp core",
+				__func__);
+		kfree(codec_data);
+		return -ENODEV;
+	}
+
+	dev_set_drvdata(codec->dev, codec_data);
+
+	dev_dbg(codec->dev, "%s(): registered %s with ext disp core\n",
+		__func__, codec->component.name);
+
+	return 0;
+}
+
+static int msm_ext_disp_audio_codec_rx_remove(struct snd_soc_codec *codec)
+{
+	struct msm_ext_disp_audio_codec_rx_data *codec_data;
+
+	codec_data = dev_get_drvdata(codec->dev);
+	kfree(codec_data);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = {
+	.startup   = msm_ext_disp_audio_codec_rx_dai_startup,
+	.hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params,
+	.shutdown  = msm_ext_disp_audio_codec_rx_dai_shutdown
+};
+
+static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = {
+	{
+		.name = "msm_hdmi_audio_codec_rx_dai",
+		.playback = {
+			.stream_name = "HDMI Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min = 48000,
+			.rate_max = 48000,
+			.rates = MSM_EXT_DISP_PCM_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &msm_ext_disp_audio_codec_rx_dai_ops,
+	},
+	{
+		.name = "msm_dp_audio_codec_rx_dai",
+		.playback = {
+			.stream_name = "Display Port Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min = 48000,
+			.rate_max = 192000,
+			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE,
+		},
+		.ops = &msm_ext_disp_audio_codec_rx_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver msm_ext_disp_audio_codec_rx_soc_driver = {
+	.probe = msm_ext_disp_audio_codec_rx_probe,
+	.remove =  msm_ext_disp_audio_codec_rx_remove,
+	.component_driver = {
+		.controls = msm_ext_disp_codec_rx_controls,
+		.num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls),
+	},
+};
+
+static int msm_ext_disp_audio_codec_rx_plat_probe(
+		struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__,
+		dev_name(&pdev->dev));
+
+	return snd_soc_register_codec(&pdev->dev,
+		&msm_ext_disp_audio_codec_rx_soc_driver,
+		msm_ext_disp_audio_codec_rx_dais,
+		ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais));
+}
+
+static int msm_ext_disp_audio_codec_rx_plat_remove(
+		struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = {
+	{ .compatible = "qcom,msm-ext-disp-audio-codec-rx", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match);
+
+static struct platform_driver msm_ext_disp_audio_codec_rx_driver = {
+	.driver = {
+		.name = "msm-ext-disp-audio-codec-rx",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ext_disp_audio_codec_rx_dt_match,
+	},
+	.probe = msm_ext_disp_audio_codec_rx_plat_probe,
+	.remove = msm_ext_disp_audio_codec_rx_plat_remove,
+};
+
+static int __init msm_ext_disp_audio_codec_rx_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver);
+	if (rc) {
+		pr_err("%s: failed to register ext disp codec driver err:%d\n",
+		       __func__, rc);
+	}
+
+	return rc;
+}
+module_init(msm_ext_disp_audio_codec_rx_init);
+
+static void __exit msm_ext_disp_audio_codec_rx_exit(void)
+{
+	platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver);
+}
+module_exit(msm_ext_disp_audio_codec_rx_exit);
+
+MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/msm_sdw/Makefile b/asoc/codecs/msm_sdw/Makefile
new file mode 100644
index 0000000..64e932b
--- /dev/null
+++ b/asoc/codecs/msm_sdw/Makefile
@@ -0,0 +1,3 @@
+snd-soc-msm-sdw-objs := msm_sdw_cdc.o msm_sdw_regmap.o msm-sdw-tables.o msm_sdw_cdc_utils.o
+obj-$(CONFIG_SND_SOC_MSM_SDW)	+= snd-soc-msm-sdw.o
+ccflags-y += -I$(srctree)/sound/soc/msm
diff --git a/asoc/codecs/msm_sdw/msm-sdw-tables.c b/asoc/codecs/msm_sdw/msm-sdw-tables.c
new file mode 100644
index 0000000..1b51805
--- /dev/null
+++ b/asoc/codecs/msm_sdw/msm-sdw-tables.c
@@ -0,0 +1,319 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include "msm_sdw.h"
+
+const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER] = {
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 0xa,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 0xa,
+	[MSM_SDW_COMPANDER7_CTL0] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL1] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL2] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL3] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL4] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL5] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL6] = 0xb,
+	[MSM_SDW_COMPANDER7_CTL7] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL0] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL1] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL2] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL3] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL4] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL5] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL6] = 0xb,
+	[MSM_SDW_COMPANDER8_CTL7] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CFG0] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CFG1] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_CFG2] = 0xb,
+	[MSM_SDW_RX7_RX_VOL_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_CFG] = 0xb,
+	[MSM_SDW_RX7_RX_VOL_MIX_CTL] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC0] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC1] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC2] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC3] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC5] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC6] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_SEC7] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 0xb,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CFG0] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CFG1] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_CFG2] = 0xb,
+	[MSM_SDW_RX8_RX_VOL_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_CFG] = 0xb,
+	[MSM_SDW_RX8_RX_VOL_MIX_CTL] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC0] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC1] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC2] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC3] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC5] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC6] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_SEC7] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 0xb,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 0xb,
+	[MSM_SDW_BOOST0_BOOST_PATH_CTL] = 0xc,
+	[MSM_SDW_BOOST0_BOOST_CTL] = 0xc,
+	[MSM_SDW_BOOST0_BOOST_CFG1] = 0xc,
+	[MSM_SDW_BOOST0_BOOST_CFG2] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_PATH_CTL] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_CTL] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_CFG1] = 0xc,
+	[MSM_SDW_BOOST1_BOOST_CFG2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_0] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_1] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_2] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_3] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 0xc,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_STATUS] = 0xc,
+	[MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 0xd,
+	[MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 0xd,
+	[MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 0xd,
+	[MSM_SDW_TOP_TOP_CFG0] = 0xd,
+	[MSM_SDW_TOP_TOP_CFG1] = 0xd,
+	[MSM_SDW_TOP_RX_I2S_CTL] = 0xd,
+	[MSM_SDW_TOP_TX_I2S_CTL] = 0xd,
+	[MSM_SDW_TOP_I2S_CLK] = 0xd,
+	[MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 0xd,
+	[MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 0xd,
+	[MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 0xd,
+	[MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 0xd,
+	[MSM_SDW_TOP_FREQ_MCLK] = 0xd,
+	[MSM_SDW_TOP_DEBUG_BUS_SEL] = 0xd,
+	[MSM_SDW_TOP_DEBUG_EN] = 0xd,
+	[MSM_SDW_TOP_I2S_RESET] = 0xd,
+	[MSM_SDW_TOP_BLOCKS_RESET] = 0xd,
+};
+
+const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER] = {
+	[MSM_SDW_PAGE_REGISTER] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_COMPANDER7_CTL0] = 1,
+	[MSM_SDW_COMPANDER7_CTL1] = 1,
+	[MSM_SDW_COMPANDER7_CTL2] = 1,
+	[MSM_SDW_COMPANDER7_CTL3] = 1,
+	[MSM_SDW_COMPANDER7_CTL4] = 1,
+	[MSM_SDW_COMPANDER7_CTL5] = 1,
+	[MSM_SDW_COMPANDER7_CTL6] = 1,
+	[MSM_SDW_COMPANDER7_CTL7] = 1,
+	[MSM_SDW_COMPANDER8_CTL0] = 1,
+	[MSM_SDW_COMPANDER8_CTL1] = 1,
+	[MSM_SDW_COMPANDER8_CTL2] = 1,
+	[MSM_SDW_COMPANDER8_CTL3] = 1,
+	[MSM_SDW_COMPANDER8_CTL4] = 1,
+	[MSM_SDW_COMPANDER8_CTL5] = 1,
+	[MSM_SDW_COMPANDER8_CTL6] = 1,
+	[MSM_SDW_COMPANDER8_CTL7] = 1,
+	[MSM_SDW_RX7_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX7_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX7_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX8_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX8_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_BOOST0_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG2] = 1,
+	[MSM_SDW_BOOST1_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_DATA_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 1,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_STATUS] = 1,
+	[MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 1,
+	[MSM_SDW_TOP_TOP_CFG0] = 1,
+	[MSM_SDW_TOP_TOP_CFG1] = 1,
+	[MSM_SDW_TOP_RX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_TX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_FREQ_MCLK] = 1,
+	[MSM_SDW_TOP_DEBUG_BUS_SEL] = 1,
+	[MSM_SDW_TOP_DEBUG_EN] = 1,
+	[MSM_SDW_TOP_I2S_RESET] = 1,
+	[MSM_SDW_TOP_BLOCKS_RESET] = 1,
+};
+
+const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER] = {
+	[MSM_SDW_PAGE_REGISTER] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_COMPANDER7_CTL0] = 1,
+	[MSM_SDW_COMPANDER7_CTL1] = 1,
+	[MSM_SDW_COMPANDER7_CTL2] = 1,
+	[MSM_SDW_COMPANDER7_CTL3] = 1,
+	[MSM_SDW_COMPANDER7_CTL4] = 1,
+	[MSM_SDW_COMPANDER7_CTL5] = 1,
+	[MSM_SDW_COMPANDER7_CTL7] = 1,
+	[MSM_SDW_COMPANDER8_CTL0] = 1,
+	[MSM_SDW_COMPANDER8_CTL1] = 1,
+	[MSM_SDW_COMPANDER8_CTL2] = 1,
+	[MSM_SDW_COMPANDER8_CTL3] = 1,
+	[MSM_SDW_COMPANDER8_CTL4] = 1,
+	[MSM_SDW_COMPANDER8_CTL5] = 1,
+	[MSM_SDW_COMPANDER8_CTL7] = 1,
+	[MSM_SDW_RX7_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX7_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX7_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX8_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX8_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_BOOST0_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG2] = 1,
+	[MSM_SDW_BOOST1_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 1,
+	[MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 1,
+	[MSM_SDW_TOP_TOP_CFG0] = 1,
+	[MSM_SDW_TOP_TOP_CFG1] = 1,
+	[MSM_SDW_TOP_RX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_TX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_FREQ_MCLK] = 1,
+	[MSM_SDW_TOP_DEBUG_BUS_SEL] = 1,
+	[MSM_SDW_TOP_DEBUG_EN] = 1,
+	[MSM_SDW_TOP_I2S_RESET] = 1,
+	[MSM_SDW_TOP_BLOCKS_RESET] = 1,
+};
diff --git a/asoc/codecs/msm_sdw/msm_sdw.h b/asoc/codecs/msm_sdw/msm_sdw.h
new file mode 100644
index 0000000..376ebc6
--- /dev/null
+++ b/asoc/codecs/msm_sdw/msm_sdw.h
@@ -0,0 +1,170 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_SDW_H
+#define MSM_SDW_H
+
+#include <sound/soc.h>
+#include <sound/q6afe-v2.h>
+#include "msm_sdw_registers.h"
+
+#define MSM_SDW_MAX_REGISTER 0x400
+
+extern const struct regmap_config msm_sdw_regmap_config;
+extern const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER];
+extern const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER];
+extern const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER];
+
+enum {
+	MSM_SDW_RX4 = 0,
+	MSM_SDW_RX5,
+	MSM_SDW_RX_MAX,
+};
+
+enum {
+	MSM_SDW_TX0 = 0,
+	MSM_SDW_TX1,
+	MSM_SDW_TX_MAX,
+};
+
+enum {
+	COMP1, /* SPK_L */
+	COMP2, /* SPK_R */
+	COMP_MAX
+};
+
+/*
+ * Structure used to update codec
+ * register defaults after reset
+ */
+struct msm_sdw_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+/*
+ * Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+	SPKR_MODE_DEFAULT,
+	SPKR_MODE_1,          /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+/* Rx path gain offsets */
+enum {
+	RX_GAIN_OFFSET_M1P5_DB,
+	RX_GAIN_OFFSET_0_DB,
+};
+
+struct msm_sdw_reg_val {
+	unsigned short reg; /* register address */
+	u8 *buf;            /* buffer to be written to reg. addr */
+	int bytes;          /* number of bytes to be written */
+};
+
+/* Hold instance to soundwire platform device */
+struct msm_sdw_ctrl_data {
+	struct platform_device *sdw_pdev;
+};
+
+struct wcd_sdw_ctrl_platform_data {
+	void *handle; /* holds codec private data */
+	int (*read)(void *handle, int reg);
+	int (*write)(void *handle, int reg, int val);
+	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
+	int (*clk)(void *handle, bool enable);
+	int (*handle_irq)(void *handle,
+			  irqreturn_t (*swrm_irq_handler)(int irq,
+							  void *data),
+			  void *swrm_handle,
+			  int action);
+};
+
+struct msm_sdw_priv {
+	struct device *dev;
+	struct mutex io_lock;
+
+	int (*read_dev)(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			int bytes, void *dest);
+	int (*write_dev)(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			 int bytes, void *src);
+	int (*multi_reg_write)(struct msm_sdw_priv *msm_sdw, const void *data,
+			       size_t count);
+	struct snd_soc_codec *codec;
+	struct device_node *sdw_gpio_p; /* used by pinctrl API */
+	/* SoundWire data structure */
+	struct msm_sdw_ctrl_data *sdw_ctrl_data;
+	int nr;
+
+	/* compander */
+	int comp_enabled[COMP_MAX];
+	int ear_spkr_gain;
+
+	/* to track the status */
+	unsigned long status_mask;
+
+	struct work_struct msm_sdw_add_child_devices_work;
+	struct wcd_sdw_ctrl_platform_data sdw_plat_data;
+
+	unsigned int vi_feed_value;
+
+	struct mutex sdw_read_lock;
+	struct mutex sdw_write_lock;
+	struct mutex sdw_clk_lock;
+	int sdw_clk_users;
+	int sdw_mclk_users;
+
+	int sdw_irq;
+	int int_mclk1_rsc_ref;
+	bool int_mclk1_enabled;
+	bool sdw_npl_clk_enabled;
+	struct mutex cdc_int_mclk1_mutex;
+	struct mutex sdw_npl_clk_mutex;
+	struct delayed_work disable_int_mclk1_work;
+	struct afe_clk_set sdw_cdc_core_clk;
+	struct afe_clk_set sdw_npl_clk;
+	struct notifier_block service_nb;
+	int (*sdw_cdc_gpio_fn)(bool enable, struct snd_soc_codec *codec);
+	bool dev_up;
+
+	int spkr_gain_offset;
+	int spkr_mode;
+	struct mutex codec_mutex;
+	int rx_4_count;
+	int rx_5_count;
+	u32 mclk_rate;
+	struct regmap *regmap;
+
+	bool prev_pg_valid;
+	u8 prev_pg;
+	u32 sdw_base_addr;
+	char __iomem *sdw_base;
+	u32 version;
+
+	/* Entry for version info */
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+};
+
+extern int msm_sdw_set_spkr_mode(struct snd_soc_codec *codec, int mode);
+extern int msm_sdw_set_spkr_gain_offset(struct snd_soc_codec *codec,
+					int offset);
+extern void msm_sdw_gpio_cb(
+	int (*sdw_cdc_gpio_fn)(bool enable, struct snd_soc_codec *codec),
+	struct snd_soc_codec *codec);
+extern struct regmap *msm_sdw_regmap_init(struct device *dev,
+					  const struct regmap_config *config);
+extern int msm_sdw_codec_info_create_codec_entry(
+	struct snd_info_entry *codec_root,
+	struct snd_soc_codec *codec);
+#endif
diff --git a/asoc/codecs/msm_sdw/msm_sdw_cdc.c b/asoc/codecs/msm_sdw/msm_sdw_cdc.c
new file mode 100644
index 0000000..cfe42e0
--- /dev/null
+++ b/asoc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -0,0 +1,2007 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/qdsp6v2/apr.h>
+#include <linux/soundwire/swr-wcd.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/q6core.h>
+#include <sound/tlv.h>
+#include "msm_sdw.h"
+#include "msm_sdw_registers.h"
+
+#define MSM_SDW_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define MSM_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE |\
+		SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define MSM_SDW_STRING_LEN 80
+
+#define INT_MCLK1_FREQ 9600000
+#define SDW_NPL_FREQ 153600000
+
+#define MSM_SDW_VERSION_1_0 0x0001
+#define MSM_SDW_VERSION_ENTRY_SIZE 32
+
+/*
+ * 200 Milliseconds sufficient for DSP bring up in the modem
+ * after Sub System Restart
+ */
+#define ADSP_STATE_READY_TIMEOUT_MS 200
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static struct snd_soc_dai_driver msm_sdw_dai[];
+static bool skip_irq = true;
+
+static int msm_sdw_config_ear_spkr_gain(struct snd_soc_codec *codec,
+					int event, int gain_reg);
+static int msm_sdw_config_compander(struct snd_soc_codec *, int, int);
+static int msm_sdw_mclk_enable(struct msm_sdw_priv *msm_sdw,
+			       int mclk_enable, bool dapm);
+static int msm_int_enable_sdw_cdc_clk(struct msm_sdw_priv *msm_sdw,
+				      int enable, bool dapm);
+
+enum {
+	VI_SENSE_1,
+	VI_SENSE_2,
+};
+
+enum {
+	AIF1_SDW_PB = 0,
+	AIF1_SDW_VIFEED,
+	NUM_CODEC_DAIS,
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_spkr_default[] = {
+	{MSM_SDW_COMPANDER7_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER8_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER7_CTL7, 0x01, 0x01},
+	{MSM_SDW_COMPANDER8_CTL7, 0x01, 0x01},
+	{MSM_SDW_BOOST0_BOOST_CTL, 0x7C, 0x50},
+	{MSM_SDW_BOOST1_BOOST_CTL, 0x7C, 0x50},
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_spkr_mode1[] = {
+	{MSM_SDW_COMPANDER7_CTL3, 0x80, 0x00},
+	{MSM_SDW_COMPANDER8_CTL3, 0x80, 0x00},
+	{MSM_SDW_COMPANDER7_CTL7, 0x01, 0x00},
+	{MSM_SDW_COMPANDER8_CTL7, 0x01, 0x00},
+	{MSM_SDW_BOOST0_BOOST_CTL, 0x7C, 0x44},
+	{MSM_SDW_BOOST1_BOOST_CTL, 0x7C, 0x44},
+};
+
+/**
+ * msm_sdw_set_spkr_gain_offset - offset the speaker path
+ * gain with the given offset value.
+ *
+ * @codec: codec instance
+ * @offset: Indicates speaker path gain offset value.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_sdw_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset)
+{
+	struct msm_sdw_priv *priv;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer!\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = snd_soc_codec_get_drvdata(codec);
+	if (!priv)
+		return -EINVAL;
+
+	priv->spkr_gain_offset = offset;
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_set_spkr_gain_offset);
+
+/**
+ * msm_sdw_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @codec: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_sdw_set_spkr_mode(struct snd_soc_codec *codec, int mode)
+{
+	struct msm_sdw_priv *priv;
+	int i;
+	const struct msm_sdw_reg_mask_val *regs;
+	int size;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer!\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = snd_soc_codec_get_drvdata(codec);
+	if (!priv)
+		return -EINVAL;
+
+	switch (mode) {
+	case SPKR_MODE_1:
+		regs = msm_sdw_spkr_mode1;
+		size = ARRAY_SIZE(msm_sdw_spkr_mode1);
+		break;
+	default:
+		regs = msm_sdw_spkr_default;
+		size = ARRAY_SIZE(msm_sdw_spkr_default);
+		break;
+	}
+
+	priv->spkr_mode = mode;
+	for (i = 0; i < size; i++)
+		snd_soc_update_bits(codec, regs[i].reg,
+				    regs[i].mask, regs[i].val);
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_set_spkr_mode);
+
+static int msm_enable_sdw_npl_clk(struct msm_sdw_priv *msm_sdw, int enable)
+{
+	int ret = 0;
+
+	dev_dbg(msm_sdw->dev, "%s: enable %d\n", __func__, enable);
+
+	mutex_lock(&msm_sdw->sdw_npl_clk_mutex);
+	if (enable) {
+		if (msm_sdw->sdw_npl_clk_enabled == false) {
+			msm_sdw->sdw_npl_clk.enable = 1;
+			ret = afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT4_MI2S_RX,
+				&msm_sdw->sdw_npl_clk);
+			if (ret < 0) {
+				dev_err(msm_sdw->dev,
+					"%s: failed to enable SDW NPL CLK\n",
+					__func__);
+				mutex_unlock(&msm_sdw->sdw_npl_clk_mutex);
+				return ret;
+			}
+			dev_dbg(msm_sdw->dev, "enabled sdw npl clk\n");
+			msm_sdw->sdw_npl_clk_enabled = true;
+		}
+	} else {
+		if (msm_sdw->sdw_npl_clk_enabled == true) {
+			msm_sdw->sdw_npl_clk.enable = 0;
+			ret = afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT4_MI2S_RX,
+				&msm_sdw->sdw_npl_clk);
+			if (ret < 0)
+				dev_err(msm_sdw->dev,
+					"%s: failed to disable SDW NPL CLK\n",
+					__func__);
+			msm_sdw->sdw_npl_clk_enabled = false;
+		}
+	}
+	mutex_unlock(&msm_sdw->sdw_npl_clk_mutex);
+	return ret;
+}
+
+static int msm_int_enable_sdw_cdc_clk(struct msm_sdw_priv *msm_sdw,
+				      int enable, bool dapm)
+{
+	int ret = 0;
+
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	dev_dbg(msm_sdw->dev, "%s: enable %d mclk1 ref counter %d\n",
+		__func__, enable, msm_sdw->int_mclk1_rsc_ref);
+	if (enable) {
+		if (msm_sdw->int_mclk1_rsc_ref == 0) {
+			cancel_delayed_work_sync(
+					&msm_sdw->disable_int_mclk1_work);
+			if (msm_sdw->int_mclk1_enabled == false) {
+				msm_sdw->sdw_cdc_core_clk.enable = 1;
+				ret = afe_set_lpass_clock_v2(
+					AFE_PORT_ID_INT4_MI2S_RX,
+					&msm_sdw->sdw_cdc_core_clk);
+				if (ret < 0) {
+					dev_err(msm_sdw->dev,
+						"%s: failed to enable SDW MCLK\n",
+						__func__);
+					goto rtn;
+				}
+				dev_dbg(msm_sdw->dev,
+					"enabled sdw codec core mclk\n");
+				msm_sdw->int_mclk1_enabled = true;
+			}
+		}
+		msm_sdw->int_mclk1_rsc_ref++;
+	} else {
+		cancel_delayed_work_sync(&msm_sdw->disable_int_mclk1_work);
+		if (msm_sdw->int_mclk1_rsc_ref > 0) {
+			msm_sdw->int_mclk1_rsc_ref--;
+			dev_dbg(msm_sdw->dev,
+				"%s: decrementing mclk_res_ref %d\n",
+				 __func__, msm_sdw->int_mclk1_rsc_ref);
+		}
+		if (msm_sdw->int_mclk1_enabled == true &&
+			msm_sdw->int_mclk1_rsc_ref == 0) {
+			msm_sdw->sdw_cdc_core_clk.enable = 0;
+			ret = afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT4_MI2S_RX,
+				&msm_sdw->sdw_cdc_core_clk);
+			if (ret < 0)
+				dev_err(msm_sdw->dev,
+					"%s: failed to disable SDW MCLK\n",
+					__func__);
+			msm_sdw->int_mclk1_enabled = false;
+		}
+	}
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+rtn:
+	return ret;
+}
+EXPORT_SYMBOL(msm_int_enable_sdw_cdc_clk);
+
+static void msm_disable_int_mclk1(struct work_struct *work)
+{
+	struct msm_sdw_priv *msm_sdw = NULL;
+	struct delayed_work *dwork;
+	int ret = 0;
+
+	dwork = to_delayed_work(work);
+	msm_sdw = container_of(dwork, struct msm_sdw_priv,
+			disable_int_mclk1_work);
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	dev_dbg(msm_sdw->dev, "%s: mclk1_enabled %d mclk1_rsc_ref %d\n",
+		__func__, msm_sdw->int_mclk1_enabled,
+		msm_sdw->int_mclk1_rsc_ref);
+	if (msm_sdw->int_mclk1_enabled == true
+			&& msm_sdw->int_mclk1_rsc_ref == 0) {
+		dev_dbg(msm_sdw->dev, "Disable the mclk1\n");
+		msm_sdw->sdw_cdc_core_clk.enable = 0;
+		ret = afe_set_lpass_clock_v2(
+			AFE_PORT_ID_INT4_MI2S_RX,
+			&msm_sdw->sdw_cdc_core_clk);
+		if (ret < 0)
+			dev_err(msm_sdw->dev,
+				"%s failed to disable the MCLK1\n",
+				__func__);
+		msm_sdw->int_mclk1_enabled = false;
+	}
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+}
+
+static int msm_int_mclk1_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(msm_sdw->dev, "%s: event = %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* enable the codec mclk config */
+		msm_int_enable_sdw_cdc_clk(msm_sdw, 1, true);
+		msm_sdw_mclk_enable(msm_sdw, 1, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* disable the codec mclk config */
+		msm_sdw_mclk_enable(msm_sdw, 0, true);
+		msm_int_enable_sdw_cdc_clk(msm_sdw, 0, true);
+		break;
+	default:
+		dev_err(msm_sdw->dev,
+			"%s: invalid DAPM event %d\n", __func__, event);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int msm_sdw_ahb_write_device(struct msm_sdw_priv *msm_sdw,
+					u16 reg, u8 *value)
+{
+	u32 temp = (u32)(*value) & 0x000000FF;
+
+	if (!msm_sdw->dev_up) {
+		dev_err_ratelimited(msm_sdw->dev, "%s: q6 not ready\n",
+				    __func__);
+		return 0;
+	}
+
+	iowrite32(temp, msm_sdw->sdw_base + reg);
+	return 0;
+}
+
+static int msm_sdw_ahb_read_device(struct msm_sdw_priv *msm_sdw,
+					u16 reg, u8 *value)
+{
+	u32 temp;
+
+	if (!msm_sdw->dev_up) {
+		dev_err_ratelimited(msm_sdw->dev, "%s: q6 not ready\n",
+				    __func__);
+		return 0;
+	}
+
+	temp = ioread32(msm_sdw->sdw_base + reg);
+	*value = (u8)temp;
+	return 0;
+}
+
+static int __msm_sdw_reg_read(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			int bytes, void *dest)
+{
+	int ret = -EINVAL, i;
+	u8 temp = 0;
+
+	dev_dbg(msm_sdw->dev, "%s reg = %x\n", __func__, reg);
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	if (msm_sdw->int_mclk1_enabled == false) {
+		msm_sdw->sdw_cdc_core_clk.enable = 1;
+		ret = afe_set_lpass_clock_v2(
+					AFE_PORT_ID_INT4_MI2S_RX,
+					&msm_sdw->sdw_cdc_core_clk);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"%s:failed to enable the INT_MCLK1\n",
+				__func__);
+			goto unlock_exit;
+		}
+		dev_dbg(msm_sdw->dev, "%s:enabled sdw codec core clk\n",
+			__func__);
+		for (i = 0; i < bytes; i++)  {
+			ret = msm_sdw_ahb_read_device(
+				msm_sdw, reg + (4 * i), &temp);
+			((u8 *)dest)[i] = temp;
+		}
+		msm_sdw->int_mclk1_enabled = true;
+		schedule_delayed_work(&msm_sdw->disable_int_mclk1_work, 50);
+		goto unlock_exit;
+	}
+	for (i = 0; i < bytes; i++)  {
+		ret = msm_sdw_ahb_read_device(
+			msm_sdw, reg + (4 * i), &temp);
+		((u8 *)dest)[i] = temp;
+	}
+unlock_exit:
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+	if (ret < 0) {
+		dev_err_ratelimited(msm_sdw->dev,
+				    "%s: codec read failed for reg 0x%x\n",
+				    __func__, reg);
+		return ret;
+	}
+	dev_dbg(msm_sdw->dev, "Read 0x%02x from 0x%x\n", temp, reg);
+
+	return 0;
+}
+
+static int __msm_sdw_reg_write(struct msm_sdw_priv *msm_sdw, unsigned short reg,
+			       int bytes, void *src)
+{
+	int ret = -EINVAL, i;
+
+	mutex_lock(&msm_sdw->cdc_int_mclk1_mutex);
+	if (msm_sdw->int_mclk1_enabled == false) {
+		msm_sdw->sdw_cdc_core_clk.enable = 1;
+		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_INT4_MI2S_RX,
+					     &msm_sdw->sdw_cdc_core_clk);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"%s: failed to enable the INT_MCLK1\n",
+				__func__);
+			ret = 0;
+			goto unlock_exit;
+		}
+		dev_dbg(msm_sdw->dev, "%s: enabled INT_MCLK1\n", __func__);
+		for (i = 0; i < bytes; i++)
+			ret = msm_sdw_ahb_write_device(msm_sdw, reg + (4 * i),
+						       &((u8 *)src)[i]);
+		msm_sdw->int_mclk1_enabled = true;
+		schedule_delayed_work(&msm_sdw->disable_int_mclk1_work, 50);
+		goto unlock_exit;
+	}
+	for (i = 0; i < bytes; i++)
+		ret = msm_sdw_ahb_write_device(msm_sdw, reg + (4 * i),
+					       &((u8 *)src)[i]);
+unlock_exit:
+	mutex_unlock(&msm_sdw->cdc_int_mclk1_mutex);
+	dev_dbg(msm_sdw->dev, "Write 0x%x val 0x%02x\n",
+				reg, (u32)(*(u32 *)src));
+
+	return ret;
+}
+
+static int msm_sdw_codec_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	struct snd_soc_codec *codec = NULL;
+	struct msm_sdw_priv *msm_sdw_p = NULL;
+	int ret = 0;
+
+	if (!w) {
+		pr_err("%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	codec = snd_soc_dapm_to_codec(w->dapm);
+	msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
+		__func__, codec->component.num_dai, w->sname);
+
+	dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
+		__func__, w->name, event, w->shift);
+	if (w->shift != AIF1_SDW_VIFEED) {
+		dev_err(codec->dev,
+			"%s:Error in enabling the vi feedback path\n",
+			__func__);
+		ret = -EINVAL;
+		goto out_vi;
+	}
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (test_bit(VI_SENSE_1, &msm_sdw_p->status_mask)) {
+			dev_dbg(codec->dev, "%s: spkr1 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x0F, 0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &msm_sdw_p->status_mask)) {
+			dev_dbg(codec->dev, "%s: spkr2 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x0F,
+				0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x0F,
+				0x04);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (test_bit(VI_SENSE_1, &msm_sdw_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr1 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &msm_sdw_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr2 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+			snd_soc_update_bits(codec,
+				MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		break;
+	}
+out_vi:
+	return ret;
+}
+
+static int msm_sdwm_handle_irq(void *handle,
+			       irqreturn_t (*swrm_irq_handler)(int irq,
+							       void *data),
+			       void *swrm_handle,
+			       int action)
+{
+	struct msm_sdw_priv *msm_sdw;
+	int ret = 0;
+
+	if (!handle) {
+		pr_err("%s: null handle received\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw = (struct msm_sdw_priv *) handle;
+
+	if (skip_irq)
+		return ret;
+
+	if (action) {
+		ret = request_threaded_irq(msm_sdw->sdw_irq, NULL,
+					   swrm_irq_handler,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "swr_master_irq", swrm_handle);
+		if (ret)
+			dev_err(msm_sdw->dev, "%s: Failed to request irq %d\n",
+				__func__, ret);
+	} else
+		free_irq(msm_sdw->sdw_irq, swrm_handle);
+
+	return ret;
+}
+
+static void msm_sdw_codec_hd2_control(struct snd_soc_codec *codec,
+				      u16 reg, int event)
+{
+	u16 hd2_scale_reg;
+	u16 hd2_enable_reg = 0;
+
+	if (reg == MSM_SDW_RX7_RX_PATH_CTL) {
+		hd2_scale_reg = MSM_SDW_RX7_RX_PATH_SEC3;
+		hd2_enable_reg = MSM_SDW_RX7_RX_PATH_CFG0;
+	}
+	if (reg == MSM_SDW_RX8_RX_PATH_CTL) {
+		hd2_scale_reg = MSM_SDW_RX8_RX_PATH_SEC3;
+		hd2_enable_reg = MSM_SDW_RX8_RX_PATH_CFG0;
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01);
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04);
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00);
+	}
+}
+
+static int msm_sdw_enable_swr(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_sdw_priv *msm_sdw;
+	int i, ch_cnt;
+
+	msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	if (!msm_sdw->nr)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (!(strnstr(w->name, "RX4", sizeof("RX4 MIX"))) &&
+		    !msm_sdw->rx_4_count)
+			msm_sdw->rx_4_count++;
+		if (!(strnstr(w->name, "RX5", sizeof("RX5 MIX"))) &&
+		    !msm_sdw->rx_5_count)
+			msm_sdw->rx_5_count++;
+		ch_cnt = msm_sdw->rx_4_count + msm_sdw->rx_5_count;
+
+		for (i = 0; i < msm_sdw->nr; i++) {
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_DEVICE_UP, NULL);
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_SET_NUM_RX_CH, &ch_cnt);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (!(strnstr(w->name, "RX4", sizeof("RX4 MIX"))) &&
+		    msm_sdw->rx_4_count)
+			msm_sdw->rx_4_count--;
+		if (!(strnstr(w->name, "RX5", sizeof("RX5 MIX"))) &&
+		    msm_sdw->rx_5_count)
+			msm_sdw->rx_5_count--;
+		ch_cnt = msm_sdw->rx_4_count + msm_sdw->rx_5_count;
+
+		for (i = 0; i < msm_sdw->nr; i++)
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_SET_NUM_RX_CH, &ch_cnt);
+		break;
+	}
+	dev_dbg(msm_sdw->dev, "%s: current swr ch cnt: %d\n",
+		__func__, msm_sdw->rx_4_count + msm_sdw->rx_5_count);
+
+	return 0;
+}
+
+static int msm_sdw_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	u16 gain_reg;
+	u16 reg;
+	int val;
+	int offset_val = 0;
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+	if (!(strcmp(w->name, "RX INT4 INTERP"))) {
+		reg = MSM_SDW_RX7_RX_PATH_CTL;
+		gain_reg = MSM_SDW_RX7_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT5 INTERP"))) {
+		reg = MSM_SDW_RX8_RX_PATH_CTL;
+		gain_reg = MSM_SDW_RX8_RX_VOL_CTL;
+	} else {
+		dev_err(codec->dev, "%s: Interpolator reg not found\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, reg, 0x10, 0x10);
+		msm_sdw_codec_hd2_control(codec, reg, event);
+		snd_soc_update_bits(codec, reg, 1 << 0x5, 1 << 0x5);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		msm_sdw_config_compander(codec, w->shift, event);
+		/* apply gain after int clk is enabled */
+		if ((msm_sdw->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (msm_sdw->comp_enabled[COMP1] ||
+		     msm_sdw->comp_enabled[COMP2]) &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL ||
+		     gain_reg == MSM_SDW_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, MSM_SDW_RX7_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec, MSM_SDW_RX8_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			offset_val = -2;
+		}
+		val = snd_soc_read(codec, gain_reg);
+		val += offset_val;
+		snd_soc_write(codec, gain_reg, val);
+		msm_sdw_config_ear_spkr_gain(codec, event, gain_reg);
+		snd_soc_update_bits(codec, reg, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, reg, 1 << 0x5, 0 << 0x5);
+		snd_soc_update_bits(codec, reg,	0x40, 0x40);
+		snd_soc_update_bits(codec, reg,	0x40, 0x00);
+		msm_sdw_codec_hd2_control(codec, reg, event);
+		msm_sdw_config_compander(codec, w->shift, event);
+		if ((msm_sdw->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (msm_sdw->comp_enabled[COMP1] ||
+		     msm_sdw->comp_enabled[COMP2]) &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL ||
+		     gain_reg == MSM_SDW_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, MSM_SDW_RX7_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec, MSM_SDW_RX8_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    MSM_SDW_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			offset_val = 2;
+			val = snd_soc_read(codec, gain_reg);
+			val += offset_val;
+			snd_soc_write(codec, gain_reg, val);
+		}
+		msm_sdw_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	};
+
+	return 0;
+}
+
+static int msm_sdw_config_ear_spkr_gain(struct snd_soc_codec *codec,
+					int event, int gain_reg)
+{
+	int comp_gain_offset, val;
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	switch (msm_sdw->spkr_mode) {
+	/* Compander gain in SPKR_MODE1 case is 12 dB */
+	case SPKR_MODE_1:
+		comp_gain_offset = -12;
+		break;
+	/* Default case compander gain is 15 dB */
+	default:
+		comp_gain_offset = -15;
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Apply ear spkr gain only if compander is enabled */
+		if (msm_sdw->comp_enabled[COMP1] &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL) &&
+		    (msm_sdw->ear_spkr_gain != 0)) {
+			/* For example, val is -8(-12+5-1) for 4dB of gain */
+			val = comp_gain_offset + msm_sdw->ear_spkr_gain - 1;
+			snd_soc_write(codec, gain_reg, val);
+
+			dev_dbg(codec->dev, "%s: RX4 Volume %d dB\n",
+				__func__, val);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * Reset RX4 volume to 0 dB if compander is enabled and
+		 * ear_spkr_gain is non-zero.
+		 */
+		if (msm_sdw->comp_enabled[COMP1] &&
+		    (gain_reg == MSM_SDW_RX7_RX_VOL_CTL) &&
+		    (msm_sdw->ear_spkr_gain != 0)) {
+			snd_soc_write(codec, gain_reg, 0x0);
+
+			dev_dbg(codec->dev, "%s: Reset RX4 Volume to 0 dB\n",
+				__func__);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_sdw_codec_spk_boost_event(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 boost_path_ctl, boost_path_cfg1;
+	u16 reg;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	if (!strcmp(w->name, "RX INT4 CHAIN")) {
+		boost_path_ctl = MSM_SDW_BOOST0_BOOST_PATH_CTL;
+		boost_path_cfg1 = MSM_SDW_RX7_RX_PATH_CFG1;
+		reg = MSM_SDW_RX7_RX_PATH_CTL;
+	} else if (!strcmp(w->name, "RX INT5 CHAIN")) {
+		boost_path_ctl = MSM_SDW_BOOST1_BOOST_PATH_CTL;
+		boost_path_cfg1 = MSM_SDW_RX8_RX_PATH_CFG1;
+		reg = MSM_SDW_RX8_RX_PATH_CTL;
+	} else {
+		dev_err(codec->dev, "%s: boost reg not found\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x10);
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x01);
+		snd_soc_update_bits(codec, reg, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x00);
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x00);
+		break;
+	};
+
+	return 0;
+}
+
+static int msm_sdw_config_compander(struct snd_soc_codec *codec, int comp,
+				    int event)
+{
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+	if (comp < COMP1 || comp >= COMP_MAX)
+		return 0;
+
+	dev_dbg(codec->dev, "%s: event %d compander %d, enabled %d\n",
+		__func__, event, comp + 1, msm_sdw->comp_enabled[comp]);
+
+	if (!msm_sdw->comp_enabled[comp])
+		return 0;
+
+	comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 0x20);
+	rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 0x1E0);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Compander Clock */
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x01);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x02);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04);
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00);
+	}
+
+	return 0;
+}
+
+static int msm_sdw_get_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = msm_sdw->comp_enabled[comp];
+	return 0;
+}
+
+static int msm_sdw_set_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
+		__func__, comp + 1, msm_sdw->comp_enabled[comp], value);
+	msm_sdw->comp_enabled[comp] = value;
+
+	return 0;
+}
+
+static int msm_sdw_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = msm_sdw->ear_spkr_gain;
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_sdw_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_sdw_priv *msm_sdw = snd_soc_codec_get_drvdata(codec);
+
+	msm_sdw->ear_spkr_gain =  ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: gain = %d\n", __func__,
+		msm_sdw->ear_spkr_gain);
+
+	return 0;
+}
+
+static int msm_sdw_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = msm_sdw_p->vi_feed_value;
+
+	return 0;
+}
+
+static int msm_sdw_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct msm_sdw_priv *msm_sdw_p = snd_soc_codec_get_drvdata(codec);
+	struct soc_multi_mixer_control *mixer =
+		((struct soc_multi_mixer_control *)kcontrol->private_value);
+	u32 dai_id = widget->shift;
+	u32 port_id = mixer->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n",
+		__func__, enable, port_id, dai_id);
+
+	msm_sdw_p->vi_feed_value = ucontrol->value.integer.value[0];
+
+	mutex_lock(&msm_sdw_p->codec_mutex);
+	if (enable) {
+		if (port_id == MSM_SDW_TX0 && !test_bit(VI_SENSE_1,
+						&msm_sdw_p->status_mask))
+			set_bit(VI_SENSE_1, &msm_sdw_p->status_mask);
+		if (port_id == MSM_SDW_TX1 && !test_bit(VI_SENSE_2,
+						&msm_sdw_p->status_mask))
+			set_bit(VI_SENSE_2, &msm_sdw_p->status_mask);
+	} else {
+		if (port_id == MSM_SDW_TX0 && test_bit(VI_SENSE_1,
+					&msm_sdw_p->status_mask))
+			clear_bit(VI_SENSE_1, &msm_sdw_p->status_mask);
+		if (port_id == MSM_SDW_TX1 && test_bit(VI_SENSE_2,
+					&msm_sdw_p->status_mask))
+			clear_bit(VI_SENSE_2, &msm_sdw_p->status_mask);
+	}
+	mutex_unlock(&msm_sdw_p->codec_mutex);
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+	return 0;
+}
+
+static int msm_sdw_mclk_enable(struct msm_sdw_priv *msm_sdw,
+			       int mclk_enable, bool dapm)
+{
+	dev_dbg(msm_sdw->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n",
+		__func__, mclk_enable, dapm, msm_sdw->sdw_mclk_users);
+	if (mclk_enable) {
+		msm_sdw->sdw_mclk_users++;
+		if (msm_sdw->sdw_mclk_users == 1) {
+			regmap_update_bits(msm_sdw->regmap,
+					MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x01, 0x01);
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL,
+				0x01, 0x01);
+			/* 9.6MHz MCLK, set value 0x00 if other frequency */
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_TOP_FREQ_MCLK, 0x01, 0x01);
+		}
+	} else {
+		msm_sdw->sdw_mclk_users--;
+		if (msm_sdw->sdw_mclk_users == 0) {
+			regmap_update_bits(msm_sdw->regmap,
+					MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x01, 0x00);
+			regmap_update_bits(msm_sdw->regmap,
+					MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL,
+					0x01, 0x00);
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_mclk_enable);
+
+static int msm_sdw_swrm_read(void *handle, int reg)
+{
+	struct msm_sdw_priv *msm_sdw;
+	unsigned short sdw_rd_addr_base;
+	unsigned short sdw_rd_data_base;
+	int val, ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw = (struct msm_sdw_priv *)handle;
+
+	dev_dbg(msm_sdw->dev, "%s: Reading soundwire register, 0x%x\n",
+		__func__, reg);
+	sdw_rd_addr_base = MSM_SDW_AHB_BRIDGE_RD_ADDR_0;
+	sdw_rd_data_base = MSM_SDW_AHB_BRIDGE_RD_DATA_0;
+	/*
+	 * Add sleep as SWR slave access read takes time.
+	 * Allow for RD_DONE to complete for previous register if any.
+	 */
+	usleep_range(100, 105);
+
+	/* read_lock */
+	mutex_lock(&msm_sdw->sdw_read_lock);
+	ret = regmap_bulk_write(msm_sdw->regmap, sdw_rd_addr_base,
+				(u8 *)&reg, 4);
+	if (ret < 0) {
+		dev_err(msm_sdw->dev, "%s: RD Addr Failure\n", __func__);
+		goto err;
+	}
+	/* Add sleep for SWR register read value to get updated. */
+	usleep_range(100, 105);
+	/* Check for RD value */
+	ret = regmap_bulk_read(msm_sdw->regmap, sdw_rd_data_base,
+			       (u8 *)&val, 4);
+	if (ret < 0) {
+		dev_err(msm_sdw->dev, "%s: RD Data Failure\n", __func__);
+		goto err;
+	}
+	ret = val;
+err:
+	/* read_unlock */
+	mutex_unlock(&msm_sdw->sdw_read_lock);
+	return ret;
+}
+
+static int msm_sdw_bulk_write(struct msm_sdw_priv *msm_sdw,
+				struct msm_sdw_reg_val *bulk_reg,
+				size_t len)
+{
+	int i, ret = 0;
+	unsigned short sdw_wr_addr_base;
+	unsigned short sdw_wr_data_base;
+
+	sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+	sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+	for (i = 0; i < len; i += 2) {
+		/*
+		 * Add sleep as SWR slave write takes time.
+		 * Allow for any previous pending write to complete.
+		 */
+		usleep_range(100, 105);
+		/* First Write the Data to register */
+		ret = regmap_bulk_write(msm_sdw->regmap,
+			sdw_wr_data_base, bulk_reg[i].buf, 4);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev, "%s: WR Data Failure\n",
+				__func__);
+			break;
+		}
+		/* Next Write Address */
+		ret = regmap_bulk_write(msm_sdw->regmap,
+			sdw_wr_addr_base, bulk_reg[i+1].buf, 4);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"%s: WR Addr Failure: 0x%x\n",
+				__func__, (u32)(bulk_reg[i+1].buf[0]));
+			break;
+		}
+	}
+	return ret;
+}
+
+static int msm_sdw_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len)
+{
+	struct msm_sdw_priv *msm_sdw;
+	struct msm_sdw_reg_val *bulk_reg;
+	unsigned short sdw_wr_addr_base;
+	unsigned short sdw_wr_data_base;
+	int i, j, ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+
+	msm_sdw = (struct msm_sdw_priv *)handle;
+	if (len <= 0) {
+		dev_err(msm_sdw->dev,
+			"%s: Invalid size: %zu\n", __func__, len);
+		return -EINVAL;
+	}
+
+	sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+	sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+	bulk_reg = kzalloc((2 * len * sizeof(struct msm_sdw_reg_val)),
+			   GFP_KERNEL);
+	if (!bulk_reg)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < (len * 2); i += 2, j++) {
+		bulk_reg[i].reg = sdw_wr_data_base;
+		bulk_reg[i].buf = (u8 *)(&val[j]);
+		bulk_reg[i].bytes = 4;
+		bulk_reg[i+1].reg = sdw_wr_addr_base;
+		bulk_reg[i+1].buf = (u8 *)(&reg[j]);
+		bulk_reg[i+1].bytes = 4;
+	}
+	mutex_lock(&msm_sdw->sdw_write_lock);
+
+	ret = msm_sdw_bulk_write(msm_sdw, bulk_reg, (len * 2));
+	if (ret)
+		dev_err(msm_sdw->dev, "%s: swrm bulk write failed, ret: %d\n",
+			__func__, ret);
+
+	mutex_unlock(&msm_sdw->sdw_write_lock);
+	kfree(bulk_reg);
+
+	return ret;
+}
+
+static int msm_sdw_swrm_write(void *handle, int reg, int val)
+{
+	struct msm_sdw_priv *msm_sdw;
+	unsigned short sdw_wr_addr_base;
+	unsigned short sdw_wr_data_base;
+	struct msm_sdw_reg_val bulk_reg[2];
+	int ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw = (struct msm_sdw_priv *)handle;
+
+	sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
+	sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+
+	/* First Write the Data to register */
+	bulk_reg[0].reg = sdw_wr_data_base;
+	bulk_reg[0].buf = (u8 *)(&val);
+	bulk_reg[0].bytes = 4;
+	bulk_reg[1].reg = sdw_wr_addr_base;
+	bulk_reg[1].buf = (u8 *)(&reg);
+	bulk_reg[1].bytes = 4;
+
+	mutex_lock(&msm_sdw->sdw_write_lock);
+
+	ret = msm_sdw_bulk_write(msm_sdw, bulk_reg, 2);
+	if (ret < 0)
+		dev_err(msm_sdw->dev, "%s: WR Data Failure\n", __func__);
+
+	mutex_unlock(&msm_sdw->sdw_write_lock);
+	return ret;
+}
+
+static int msm_sdw_swrm_clock(void *handle, bool enable)
+{
+	struct msm_sdw_priv *msm_sdw = (struct msm_sdw_priv *) handle;
+
+	mutex_lock(&msm_sdw->sdw_clk_lock);
+
+	dev_dbg(msm_sdw->dev, "%s: swrm clock %s\n",
+		__func__, (enable ? "enable" : "disable"));
+	if (enable) {
+		msm_sdw->sdw_clk_users++;
+		if (msm_sdw->sdw_clk_users == 1) {
+			msm_int_enable_sdw_cdc_clk(msm_sdw, 1, true);
+			msm_sdw_mclk_enable(msm_sdw, 1, true);
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_CLK_RST_CTRL_SWR_CONTROL, 0x01, 0x01);
+			msm_enable_sdw_npl_clk(msm_sdw, true);
+			msm_cdc_pinctrl_select_active_state(
+							msm_sdw->sdw_gpio_p);
+		}
+	} else {
+		msm_sdw->sdw_clk_users--;
+		if (msm_sdw->sdw_clk_users == 0) {
+			regmap_update_bits(msm_sdw->regmap,
+				MSM_SDW_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x00);
+			msm_sdw_mclk_enable(msm_sdw, 0, true);
+			msm_int_enable_sdw_cdc_clk(msm_sdw, 0, true);
+			msm_enable_sdw_npl_clk(msm_sdw, false);
+			msm_cdc_pinctrl_select_sleep_state(msm_sdw->sdw_gpio_p);
+		}
+	}
+	dev_dbg(msm_sdw->dev, "%s: swrm clock users %d\n",
+		__func__, msm_sdw->sdw_clk_users);
+	mutex_unlock(&msm_sdw->sdw_clk_lock);
+	return 0;
+}
+
+static int msm_sdw_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
+		__func__,
+		substream->name, substream->stream);
+	return 0;
+}
+
+static int msm_sdw_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	u8 clk_fs_rate, fs_rate;
+
+	dev_dbg(dai->codec->dev,
+		"%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
+		__func__, dai->name, dai->id, params_rate(params),
+		params_channels(params), params_format(params));
+
+	switch (params_rate(params)) {
+	case 8000:
+		clk_fs_rate = 0x00;
+		fs_rate = 0x00;
+		break;
+	case 16000:
+		clk_fs_rate = 0x01;
+		fs_rate = 0x01;
+		break;
+	case 32000:
+		clk_fs_rate = 0x02;
+		fs_rate = 0x03;
+		break;
+	case 48000:
+		clk_fs_rate = 0x03;
+		fs_rate = 0x04;
+		break;
+	case 96000:
+		clk_fs_rate = 0x04;
+		fs_rate = 0x05;
+		break;
+	case 192000:
+		clk_fs_rate = 0x05;
+		fs_rate = 0x06;
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Invalid sampling rate %d\n", __func__,
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_TOP_TX_I2S_CTL, 0x1C,
+				(clk_fs_rate << 2));
+	} else {
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_TOP_RX_I2S_CTL, 0x1C,
+				(clk_fs_rate << 2));
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_RX7_RX_PATH_CTL, 0x0F,
+				fs_rate);
+		snd_soc_update_bits(dai->codec,
+				MSM_SDW_RX8_RX_PATH_CTL, 0x0F,
+				fs_rate);
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_TX_I2S_CTL, 0x20, 0x20);
+		else
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_RX_I2S_CTL, 0x20, 0x20);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_TX_I2S_CTL, 0x20, 0x00);
+		else
+			snd_soc_update_bits(dai->codec,
+					MSM_SDW_TOP_RX_I2S_CTL, 0x20, 0x00);
+		break;
+	default:
+		dev_err(dai->codec->dev, "%s: wrong format selected\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void msm_sdw_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->codec->dev,
+		"%s(): substream = %s  stream = %d\n", __func__,
+		substream->name, substream->stream);
+}
+
+static ssize_t msm_sdw_codec_version_read(struct snd_info_entry *entry,
+					  void *file_private_data,
+					  struct file *file,
+					  char __user *buf, size_t count,
+					  loff_t pos)
+{
+	struct msm_sdw_priv *msm_sdw;
+	char buffer[MSM_SDW_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	msm_sdw = (struct msm_sdw_priv *) entry->private_data;
+	if (!msm_sdw) {
+		pr_err("%s: msm_sdw priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (msm_sdw->version) {
+	case MSM_SDW_VERSION_1_0:
+		len = snprintf(buffer, sizeof(buffer), "SDW-CDC_1_0\n");
+		break;
+	default:
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	}
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_sdw_codec_info_ops = {
+	.read = msm_sdw_codec_version_read,
+};
+
+/*
+ * msm_sdw_codec_info_create_codec_entry - creates msm_sdw module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates msm_sdw module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_sdw_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct msm_sdw_priv *msm_sdw;
+	struct snd_soc_card *card;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	msm_sdw = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	msm_sdw->entry = snd_info_create_subdir(codec_root->module,
+						  "152c1000.msm-sdw-codec",
+						  codec_root);
+	if (!msm_sdw->entry) {
+		dev_err(codec->dev, "%s: failed to create msm_sdw entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   msm_sdw->entry);
+	if (!version_entry) {
+		dev_err(codec->dev, "%s: failed to create msm_sdw version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = msm_sdw;
+	version_entry->size = MSM_SDW_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &msm_sdw_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	msm_sdw->version_entry = version_entry;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_sdw_codec_info_create_codec_entry);
+
+static struct snd_soc_dai_ops msm_sdw_dai_ops = {
+	.startup = msm_sdw_startup,
+	.shutdown = msm_sdw_shutdown,
+	.hw_params = msm_sdw_hw_params,
+};
+
+static struct snd_soc_dai_driver msm_sdw_dai[] = {
+	{
+		.name = "msm_sdw_i2s_rx1",
+		.id = AIF1_SDW_PB,
+		.playback = {
+			.stream_name = "AIF1_SDW Playback",
+			.rates = MSM_SDW_RATES,
+			.formats = MSM_SDW_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &msm_sdw_dai_ops,
+	},
+	{
+		.name = "msm_sdw_vifeedback",
+		.id = AIF1_SDW_VIFEED,
+		.capture = {
+			.stream_name = "VIfeed_SDW",
+			.rates = MSM_SDW_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 2,
+			.channels_max = 4,
+		},
+		.ops = &msm_sdw_dai_ops,
+	},
+};
+
+static const char * const rx_mix1_text[] = {
+	"ZERO", "RX4", "RX5"
+};
+
+static const char * const msm_sdw_ear_spkr_pa_gain_text[] = {
+	"G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB",
+	"G_4_DB", "G_5_DB", "G_6_DB"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(msm_sdw_ear_spkr_pa_gain_enum,
+				msm_sdw_ear_spkr_pa_gain_text);
+/* RX4 MIX1 */
+static const struct soc_enum rx4_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX7_PATH_INPUT0_MUX,
+		0, 3, rx_mix1_text);
+
+static const struct soc_enum rx4_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX7_PATH_INPUT1_MUX,
+		0, 3, rx_mix1_text);
+
+/* RX5 MIX1 */
+static const struct soc_enum rx5_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX8_PATH_INPUT0_MUX,
+		0, 3, rx_mix1_text);
+
+static const struct soc_enum rx5_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM_SDW_TOP_RX8_PATH_INPUT1_MUX,
+		0, 3, rx_mix1_text);
+
+static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new aif1_vi_mixer[] = {
+	SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, MSM_SDW_TX0, 1, 0,
+			msm_sdw_vi_feed_mixer_get, msm_sdw_vi_feed_mixer_put),
+	SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, MSM_SDW_TX1, 1, 0,
+			msm_sdw_vi_feed_mixer_get, msm_sdw_vi_feed_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget msm_sdw_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("I2S RX4", "AIF1_SDW Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_IN("I2S RX5", "AIF1_SDW Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF1_SDW VI", "VIfeed_SDW", 0, SND_SOC_NOPM,
+		AIF1_SDW_VIFEED, 0, msm_sdw_codec_enable_vi_feedback,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("AIF1_VI_SDW Mixer", SND_SOC_NOPM, AIF1_SDW_VIFEED,
+		0, aif1_vi_mixer, ARRAY_SIZE(aif1_vi_mixer)),
+
+	SND_SOC_DAPM_MUX_E("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp1_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx5_mix1_inp1_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx5_mix1_inp2_mux, msm_sdw_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX5 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX INT4 INTERP", SND_SOC_NOPM,
+		COMP1, 0, NULL, 0, msm_sdw_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT5 INTERP", SND_SOC_NOPM,
+		COMP2, 0, NULL, 0, msm_sdw_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("RX INT4 CHAIN", SND_SOC_NOPM, 0, 0,
+		NULL, 0, msm_sdw_codec_spk_boost_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT5 CHAIN", SND_SOC_NOPM, 0, 0,
+		NULL, 0, msm_sdw_codec_spk_boost_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("VIINPUT_SDW"),
+
+	SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
+	SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
+
+	SND_SOC_DAPM_SUPPLY_S("SDW_CONN", -1, MSM_SDW_TOP_I2S_CLK,
+		0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("INT_MCLK1", -2, SND_SOC_NOPM, 0, 0,
+	msm_int_mclk1_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("SDW_RX_I2S_CLK",
+		MSM_SDW_TOP_RX_I2S_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SDW_TX_I2S_CLK",
+		MSM_SDW_TOP_TX_I2S_CTL, 0, 0, NULL, 0),
+};
+
+static const struct snd_kcontrol_new msm_sdw_snd_controls[] = {
+	SOC_ENUM_EXT("EAR SPKR PA Gain", msm_sdw_ear_spkr_pa_gain_enum,
+		     msm_sdw_ear_spkr_pa_gain_get,
+		     msm_sdw_ear_spkr_pa_gain_put),
+	SOC_SINGLE_SX_TLV("RX4 Digital Volume", MSM_SDW_RX7_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX5 Digital Volume", MSM_SDW_RX8_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMP1, 1, 0,
+		msm_sdw_get_compander, msm_sdw_set_compander),
+	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMP2, 1, 0,
+		msm_sdw_get_compander, msm_sdw_set_compander),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	{"AIF1_SDW VI", NULL, "SDW_TX_I2S_CLK"},
+	{"SDW_TX_I2S_CLK", NULL, "INT_MCLK1"},
+	{"SDW_TX_I2S_CLK", NULL, "SDW_CONN"},
+
+	/* VI Feedback */
+	{"AIF1_VI_SDW Mixer", "SPKR_VI_1", "VIINPUT_SDW"},
+	{"AIF1_VI_SDW Mixer", "SPKR_VI_2", "VIINPUT_SDW"},
+	{"AIF1_SDW VI", NULL, "AIF1_VI_SDW Mixer"},
+
+	{"SDW_RX_I2S_CLK", NULL, "INT_MCLK1"},
+	{"SDW_RX_I2S_CLK", NULL, "SDW_CONN"},
+	{"I2S RX4", NULL, "SDW_RX_I2S_CLK"},
+	{"I2S RX5", NULL, "SDW_RX_I2S_CLK"},
+
+	{"RX4 MIX1 INP1", "RX4", "I2S RX4"},
+	{"RX4 MIX1 INP1", "RX5", "I2S RX5"},
+	{"RX4 MIX1 INP2", "RX4", "I2S RX4"},
+	{"RX4 MIX1 INP2", "RX5", "I2S RX5"},
+	{"RX5 MIX1 INP1", "RX4", "I2S RX4"},
+	{"RX5 MIX1 INP1", "RX5", "I2S RX5"},
+	{"RX5 MIX1 INP2", "RX4", "I2S RX4"},
+	{"RX5 MIX1 INP2", "RX5", "I2S RX5"},
+
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
+	{"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
+	{"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
+
+	{"RX INT4 INTERP", NULL, "RX4 MIX1"},
+	{"RX INT4 CHAIN", NULL, "RX INT4 INTERP"},
+	{"SPK1 OUT", NULL, "RX INT4 CHAIN"},
+
+	{"RX INT5 INTERP", NULL, "RX5 MIX1"},
+	{"RX INT5 CHAIN", NULL, "RX INT5 INTERP"},
+	{"SPK2 OUT", NULL, "RX INT5 CHAIN"},
+};
+
+static const struct msm_sdw_reg_mask_val msm_sdw_reg_init[] = {
+	{MSM_SDW_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+	{MSM_SDW_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+	{MSM_SDW_COMPANDER7_CTL7, 0x1E, 0x18},
+	{MSM_SDW_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+	{MSM_SDW_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+	{MSM_SDW_COMPANDER8_CTL7, 0x1E, 0x18},
+	{MSM_SDW_BOOST0_BOOST_CTL, 0x70, 0x50},
+	{MSM_SDW_BOOST1_BOOST_CTL, 0x70, 0x50},
+	{MSM_SDW_RX7_RX_PATH_CFG1, 0x08, 0x08},
+	{MSM_SDW_RX8_RX_PATH_CFG1, 0x08, 0x08},
+	{MSM_SDW_TOP_TOP_CFG1, 0x02, 0x02},
+	{MSM_SDW_TOP_TOP_CFG1, 0x01, 0x01},
+	{MSM_SDW_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_COMPANDER7_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER8_CTL3, 0x80, 0x80},
+	{MSM_SDW_COMPANDER7_CTL7, 0x01, 0x01},
+	{MSM_SDW_COMPANDER8_CTL7, 0x01, 0x01},
+	{MSM_SDW_RX7_RX_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_RX8_RX_PATH_CFG0, 0x01, 0x01},
+	{MSM_SDW_RX7_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{MSM_SDW_RX8_RX_PATH_MIX_CFG, 0x01, 0x01},
+};
+
+static void msm_sdw_init_reg(struct snd_soc_codec *codec)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_sdw_reg_init); i++)
+		snd_soc_update_bits(codec,
+				msm_sdw_reg_init[i].reg,
+				msm_sdw_reg_init[i].mask,
+				msm_sdw_reg_init[i].val);
+}
+
+static int msm_sdw_notifier_service_cb(struct notifier_block *nb,
+				       unsigned long opcode, void *ptr)
+{
+	int i;
+	struct msm_sdw_priv *msm_sdw = container_of(nb,
+						    struct msm_sdw_priv,
+						    service_nb);
+	bool adsp_ready = false;
+	unsigned long timeout;
+	static bool initial_boot = true;
+
+	pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+	mutex_lock(&msm_sdw->codec_mutex);
+	switch (opcode) {
+	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		if (initial_boot) {
+			initial_boot = false;
+			break;
+		}
+		msm_sdw->int_mclk1_enabled = false;
+		msm_sdw->dev_up = false;
+		for (i = 0; i < msm_sdw->nr; i++)
+			swrm_wcd_notify(msm_sdw->sdw_ctrl_data[i].sdw_pdev,
+					SWR_DEVICE_DOWN, NULL);
+		break;
+	case AUDIO_NOTIFIER_SERVICE_UP:
+		if (initial_boot)
+			initial_boot = false;
+		if (!q6core_is_adsp_ready()) {
+			dev_dbg(msm_sdw->dev, "ADSP isn't ready\n");
+			timeout = jiffies +
+				  msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+			while (!time_after(jiffies, timeout)) {
+				if (!q6core_is_adsp_ready()) {
+					dev_dbg(msm_sdw->dev,
+						"ADSP isn't ready\n");
+				} else {
+					dev_dbg(msm_sdw->dev,
+						"ADSP is ready\n");
+					adsp_ready = true;
+					goto powerup;
+				}
+			}
+		} else {
+			adsp_ready = true;
+			dev_dbg(msm_sdw->dev, "%s: DSP is ready\n", __func__);
+		}
+powerup:
+		if (adsp_ready) {
+			msm_sdw->dev_up = true;
+			msm_sdw_init_reg(msm_sdw->codec);
+			regcache_mark_dirty(msm_sdw->regmap);
+			regcache_sync(msm_sdw->regmap);
+			msm_sdw_set_spkr_mode(msm_sdw->codec,
+					      msm_sdw->spkr_mode);
+		}
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(&msm_sdw->codec_mutex);
+	return NOTIFY_OK;
+}
+
+static int msm_sdw_codec_probe(struct snd_soc_codec *codec)
+{
+	struct msm_sdw_priv *msm_sdw;
+	int i, ret;
+
+	msm_sdw = snd_soc_codec_get_drvdata(codec);
+	if (!msm_sdw) {
+		pr_err("%s:SDW priv data null\n", __func__);
+		return -EINVAL;
+	}
+	msm_sdw->codec = codec;
+	for (i = 0; i < COMP_MAX; i++)
+		msm_sdw->comp_enabled[i] = 0;
+
+	msm_sdw->spkr_gain_offset = RX_GAIN_OFFSET_0_DB;
+	msm_sdw_init_reg(codec);
+	msm_sdw->version = MSM_SDW_VERSION_1_0;
+
+	msm_sdw->service_nb.notifier_call = msm_sdw_notifier_service_cb;
+	ret = audio_notifier_register("msm_sdw",
+				AUDIO_NOTIFIER_ADSP_DOMAIN,
+				&msm_sdw->service_nb);
+	if (ret < 0)
+		dev_err(msm_sdw->dev,
+			"%s: Audio notifier register failed ret = %d\n",
+			__func__, ret);
+	return 0;
+}
+
+static int msm_sdw_codec_remove(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct regmap *msm_sdw_get_regmap(struct device *dev)
+{
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+
+	return msm_sdw->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_msm_sdw = {
+	.probe = msm_sdw_codec_probe,
+	.remove = msm_sdw_codec_remove,
+	.get_regmap = msm_sdw_get_regmap,
+	.component_driver = {
+		.controls = msm_sdw_snd_controls,
+		.num_controls = ARRAY_SIZE(msm_sdw_snd_controls),
+		.dapm_widgets = msm_sdw_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(msm_sdw_dapm_widgets),
+		.dapm_routes = audio_map,
+		.num_dapm_routes = ARRAY_SIZE(audio_map),
+	},
+};
+
+static void msm_sdw_add_child_devices(struct work_struct *work)
+{
+	struct msm_sdw_priv *msm_sdw;
+	struct platform_device *pdev;
+	struct device_node *node;
+	struct msm_sdw_ctrl_data *sdw_ctrl_data = NULL, *temp;
+	int ret, ctrl_num = 0;
+	struct wcd_sdw_ctrl_platform_data *platdata;
+	char plat_dev_name[MSM_SDW_STRING_LEN];
+
+	msm_sdw = container_of(work, struct msm_sdw_priv,
+			     msm_sdw_add_child_devices_work);
+	if (!msm_sdw) {
+		pr_err("%s: Memory for msm_sdw does not exist\n",
+			__func__);
+		return;
+	}
+	if (!msm_sdw->dev->of_node) {
+		dev_err(msm_sdw->dev,
+			"%s: DT node for msm_sdw does not exist\n", __func__);
+		return;
+	}
+
+	platdata = &msm_sdw->sdw_plat_data;
+
+	for_each_available_child_of_node(msm_sdw->dev->of_node, node) {
+		if (!strcmp(node->name, "swr_master"))
+			strlcpy(plat_dev_name, "msm_sdw_swr_ctrl",
+				(MSM_SDW_STRING_LEN - 1));
+		else if (strnstr(node->name, "msm_cdc_pinctrl",
+				 strlen("msm_cdc_pinctrl")) != NULL)
+			strlcpy(plat_dev_name, node->name,
+				(MSM_SDW_STRING_LEN - 1));
+		else
+			continue;
+
+		pdev = platform_device_alloc(plat_dev_name, -1);
+		if (!pdev) {
+			dev_err(msm_sdw->dev, "%s: pdev memory alloc failed\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err;
+		}
+		pdev->dev.parent = msm_sdw->dev;
+		pdev->dev.of_node = node;
+
+		if (!strcmp(node->name, "swr_master")) {
+			ret = platform_device_add_data(pdev, platdata,
+						       sizeof(*platdata));
+			if (ret) {
+				dev_err(&pdev->dev,
+					"%s: cannot add plat data ctrl:%d\n",
+					__func__, ctrl_num);
+				goto fail_pdev_add;
+			}
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s: Cannot add platform device\n",
+				__func__);
+			goto fail_pdev_add;
+		}
+
+		if (!strcmp(node->name, "swr_master")) {
+			temp = krealloc(sdw_ctrl_data,
+					(ctrl_num + 1) * sizeof(
+					struct msm_sdw_ctrl_data),
+					GFP_KERNEL);
+			if (!temp) {
+				dev_err(&pdev->dev, "out of memory\n");
+				ret = -ENOMEM;
+				goto err;
+			}
+			sdw_ctrl_data = temp;
+			sdw_ctrl_data[ctrl_num].sdw_pdev = pdev;
+			ctrl_num++;
+			dev_dbg(&pdev->dev,
+				"%s: Added soundwire ctrl device(s)\n",
+				__func__);
+			msm_sdw->nr = ctrl_num;
+			msm_sdw->sdw_ctrl_data = sdw_ctrl_data;
+		}
+	}
+
+	return;
+fail_pdev_add:
+	platform_device_put(pdev);
+err:
+	return;
+}
+
+static int msm_sdw_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_sdw_priv *msm_sdw;
+	int adsp_state;
+
+	adsp_state = apr_get_subsys_state();
+	if (adsp_state != APR_SUBSYS_LOADED) {
+		dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
+				adsp_state);
+		return -EPROBE_DEFER;
+	}
+
+	msm_sdw = devm_kzalloc(&pdev->dev, sizeof(struct msm_sdw_priv),
+			    GFP_KERNEL);
+	if (!msm_sdw)
+		return -ENOMEM;
+	dev_set_drvdata(&pdev->dev, msm_sdw);
+	msm_sdw->dev_up = true;
+
+	msm_sdw->dev = &pdev->dev;
+	INIT_WORK(&msm_sdw->msm_sdw_add_child_devices_work,
+		  msm_sdw_add_child_devices);
+	msm_sdw->sdw_plat_data.handle = (void *) msm_sdw;
+	msm_sdw->sdw_plat_data.read = msm_sdw_swrm_read;
+	msm_sdw->sdw_plat_data.write = msm_sdw_swrm_write;
+	msm_sdw->sdw_plat_data.bulk_write = msm_sdw_swrm_bulk_write;
+	msm_sdw->sdw_plat_data.clk = msm_sdw_swrm_clock;
+	msm_sdw->sdw_plat_data.handle_irq = msm_sdwm_handle_irq;
+	ret = of_property_read_u32(pdev->dev.of_node, "reg",
+				   &msm_sdw->sdw_base_addr);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+			__func__, "reg");
+		goto err_sdw_cdc;
+	}
+
+	msm_sdw->sdw_gpio_p = of_parse_phandle(pdev->dev.of_node,
+					"qcom,cdc-sdw-gpios", 0);
+	msm_sdw->sdw_base = ioremap(msm_sdw->sdw_base_addr,
+				    MSM_SDW_MAX_REGISTER);
+	msm_sdw->read_dev = __msm_sdw_reg_read;
+	msm_sdw->write_dev = __msm_sdw_reg_write;
+
+	msm_sdw->regmap = msm_sdw_regmap_init(msm_sdw->dev,
+					      &msm_sdw_regmap_config);
+	msm_sdw->sdw_irq = platform_get_irq_byname(pdev, "swr_master_irq");
+	if (msm_sdw->sdw_irq < 0) {
+		dev_err(msm_sdw->dev, "%s() error getting irq handle: %d\n",
+				__func__, msm_sdw->sdw_irq);
+		ret = -ENODEV;
+		goto err_sdw_cdc;
+	}
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_msm_sdw,
+				     msm_sdw_dai, ARRAY_SIZE(msm_sdw_dai));
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Codec registration failed, ret = %d\n",
+			__func__, ret);
+		goto err_sdw_cdc;
+	}
+	/* initialize the int_mclk1 */
+	msm_sdw->sdw_cdc_core_clk.clk_set_minor_version =
+			AFE_API_VERSION_I2S_CONFIG;
+	msm_sdw->sdw_cdc_core_clk.clk_id =
+			Q6AFE_LPASS_CLK_ID_INT_MCLK_1;
+	msm_sdw->sdw_cdc_core_clk.clk_freq_in_hz =
+			INT_MCLK1_FREQ;
+	msm_sdw->sdw_cdc_core_clk.clk_attri =
+			Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+	msm_sdw->sdw_cdc_core_clk.clk_root =
+			Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+	msm_sdw->sdw_cdc_core_clk.enable = 0;
+
+	/* initialize the sdw_npl_clk */
+	msm_sdw->sdw_npl_clk.clk_set_minor_version =
+			AFE_API_VERSION_I2S_CONFIG;
+	msm_sdw->sdw_npl_clk.clk_id =
+			AFE_CLOCK_SET_CLOCK_ID_SWR_NPL_CLK;
+	msm_sdw->sdw_npl_clk.clk_freq_in_hz = SDW_NPL_FREQ;
+	msm_sdw->sdw_npl_clk.clk_attri =
+			Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+	msm_sdw->sdw_npl_clk.clk_root =
+			Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+	msm_sdw->sdw_npl_clk.enable = 0;
+
+	INIT_DELAYED_WORK(&msm_sdw->disable_int_mclk1_work,
+			  msm_disable_int_mclk1);
+	mutex_init(&msm_sdw->cdc_int_mclk1_mutex);
+	mutex_init(&msm_sdw->sdw_npl_clk_mutex);
+	mutex_init(&msm_sdw->io_lock);
+	mutex_init(&msm_sdw->sdw_read_lock);
+	mutex_init(&msm_sdw->sdw_write_lock);
+	mutex_init(&msm_sdw->sdw_clk_lock);
+	mutex_init(&msm_sdw->codec_mutex);
+	schedule_work(&msm_sdw->msm_sdw_add_child_devices_work);
+
+	dev_dbg(&pdev->dev, "%s: msm_sdw driver probe done\n", __func__);
+	return ret;
+
+err_sdw_cdc:
+	devm_kfree(&pdev->dev, msm_sdw);
+	return ret;
+}
+
+static int msm_sdw_remove(struct platform_device *pdev)
+{
+	struct msm_sdw_priv *msm_sdw;
+
+	msm_sdw = dev_get_drvdata(&pdev->dev);
+
+	mutex_destroy(&msm_sdw->io_lock);
+	mutex_destroy(&msm_sdw->sdw_read_lock);
+	mutex_destroy(&msm_sdw->sdw_write_lock);
+	mutex_destroy(&msm_sdw->sdw_clk_lock);
+	mutex_destroy(&msm_sdw->codec_mutex);
+	mutex_destroy(&msm_sdw->cdc_int_mclk1_mutex);
+	devm_kfree(&pdev->dev, msm_sdw);
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id msm_sdw_codec_dt_match[] = {
+	{ .compatible = "qcom,msm-sdw-codec", },
+	{}
+};
+
+static struct platform_driver msm_sdw_codec_driver = {
+	.probe = msm_sdw_probe,
+	.remove = msm_sdw_remove,
+	.driver = {
+		.name = "msm_sdw_codec",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_sdw_codec_dt_match,
+	},
+};
+module_platform_driver(msm_sdw_codec_driver);
+
+MODULE_DESCRIPTION("MSM Soundwire Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/msm_sdw/msm_sdw_cdc_utils.c b/asoc/codecs/msm_sdw/msm_sdw_cdc_utils.c
new file mode 100644
index 0000000..9a5c85b
--- /dev/null
+++ b/asoc/codecs/msm_sdw/msm_sdw_cdc_utils.c
@@ -0,0 +1,211 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include "msm_sdw.h"
+
+#define REG_BYTES 2
+#define VAL_BYTES 1
+/*
+ * Page Register Address that APP Proc uses to
+ * access WCD9335 Codec registers is identified
+ * as 0x00
+ */
+#define PAGE_REG_ADDR 0x00
+
+/*
+ * msm_sdw_page_write:
+ * Retrieve page number from register and
+ * write that page number to the page address.
+ * Called under io_lock acquisition.
+ *
+ * @msm_sdw: pointer to msm_sdw
+ * @reg: Register address from which page number is retrieved
+ *
+ * Returns 0 for success and negative error code for failure.
+ */
+int msm_sdw_page_write(struct msm_sdw_priv *msm_sdw, unsigned short reg)
+{
+	int ret = 0;
+	u8 pg_num, prev_pg_num;
+
+	pg_num = msm_sdw_page_map[reg];
+	if (msm_sdw->prev_pg_valid) {
+		prev_pg_num = msm_sdw->prev_pg;
+		if (prev_pg_num != pg_num) {
+			ret = msm_sdw->write_dev(msm_sdw, PAGE_REG_ADDR, 1,
+						 (void *) &pg_num);
+			if (ret < 0) {
+				dev_err(msm_sdw->dev,
+					"page write error, pg_num: 0x%x\n",
+					pg_num);
+			} else {
+				msm_sdw->prev_pg = pg_num;
+				dev_dbg(msm_sdw->dev,
+					"%s: Page 0x%x Write to 0x00\n",
+					__func__, pg_num);
+			}
+		}
+	} else {
+		ret = msm_sdw->write_dev(msm_sdw, PAGE_REG_ADDR, 1,
+					 (void *) &pg_num);
+		if (ret < 0) {
+			dev_err(msm_sdw->dev,
+				"page write error, pg_num: 0x%x\n", pg_num);
+		} else {
+			msm_sdw->prev_pg = pg_num;
+			msm_sdw->prev_pg_valid = true;
+			dev_dbg(msm_sdw->dev, "%s: Page 0x%x Write to 0x00\n",
+				__func__, pg_num);
+		}
+	}
+	return ret;
+}
+EXPORT_SYMBOL(msm_sdw_page_write);
+
+static int regmap_bus_read(void *context, const void *reg, size_t reg_size,
+			   void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+	unsigned short c_reg;
+	int ret, i;
+
+	if (!msm_sdw) {
+		dev_err(dev, "%s: msm_sdw is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (!reg || !val) {
+		dev_err(dev, "%s: reg or val is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (reg_size != REG_BYTES) {
+		dev_err(dev, "%s: register size %zd bytes, not supported\n",
+			__func__, reg_size);
+		return -EINVAL;
+	}
+	if (!msm_sdw->dev_up) {
+		dev_dbg_ratelimited(dev, "%s: No read allowed. dev_up = %d\n",
+				    __func__, msm_sdw->dev_up);
+		return 0;
+	}
+
+	mutex_lock(&msm_sdw->io_lock);
+	c_reg = *(u16 *)reg;
+	ret = msm_sdw_page_write(msm_sdw, c_reg);
+	if (ret)
+		goto err;
+	ret = msm_sdw->read_dev(msm_sdw, c_reg, val_size, val);
+	if (ret < 0)
+		dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n",
+			__func__, ret, c_reg, val_size);
+	else {
+		for (i = 0; i < val_size; i++)
+			dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n",
+				__func__, ((u8 *)val)[i], c_reg + i);
+	}
+err:
+	mutex_unlock(&msm_sdw->io_lock);
+
+	return ret;
+}
+
+static int regmap_bus_gather_write(void *context,
+				   const void *reg, size_t reg_size,
+				   const void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+	unsigned short c_reg;
+	int ret, i;
+
+	if (!msm_sdw) {
+		dev_err(dev, "%s: msm_sdw is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (!reg || !val) {
+		dev_err(dev, "%s: reg or val is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (reg_size != REG_BYTES) {
+		dev_err(dev, "%s: register size %zd bytes, not supported\n",
+			__func__, reg_size);
+		return -EINVAL;
+	}
+	if (!msm_sdw->dev_up) {
+		dev_dbg_ratelimited(dev, "%s: No write allowed. dev_up = %d\n",
+				    __func__, msm_sdw->dev_up);
+		return 0;
+	}
+
+	mutex_lock(&msm_sdw->io_lock);
+	c_reg = *(u16 *)reg;
+	ret = msm_sdw_page_write(msm_sdw, c_reg);
+	if (ret)
+		goto err;
+
+	for (i = 0; i < val_size; i++)
+		dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i],
+			c_reg + i*4);
+
+	ret = msm_sdw->write_dev(msm_sdw, c_reg, val_size, (void *) val);
+	if (ret < 0)
+		dev_err(dev,
+			"%s: Codec write failed (%d), reg:0x%x, size:%zd\n",
+			__func__, ret, c_reg, val_size);
+
+err:
+	mutex_unlock(&msm_sdw->io_lock);
+	return ret;
+}
+
+static int regmap_bus_write(void *context, const void *data, size_t count)
+{
+	struct device *dev = context;
+	struct msm_sdw_priv *msm_sdw = dev_get_drvdata(dev);
+
+	if (!msm_sdw)
+		return -EINVAL;
+
+	WARN_ON(count < REG_BYTES);
+
+	return regmap_bus_gather_write(context, data, REG_BYTES,
+				       data + REG_BYTES,
+				       count - REG_BYTES);
+
+}
+
+static struct regmap_bus regmap_bus_config = {
+	.write = regmap_bus_write,
+	.gather_write = regmap_bus_gather_write,
+	.read = regmap_bus_read,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/*
+ * msm_sdw_regmap_init:
+ * Initialize msm_sdw register map
+ *
+ * @dev: pointer to wcd device
+ * @config: pointer to register map config
+ *
+ * Returns pointer to regmap structure for success
+ * or NULL in case of failure.
+ */
+struct regmap *msm_sdw_regmap_init(struct device *dev,
+				   const struct regmap_config *config)
+{
+	return devm_regmap_init(dev, &regmap_bus_config, dev, config);
+}
+EXPORT_SYMBOL(msm_sdw_regmap_init);
diff --git a/asoc/codecs/msm_sdw/msm_sdw_registers.h b/asoc/codecs/msm_sdw/msm_sdw_registers.h
new file mode 100644
index 0000000..1b7b0b0
--- /dev/null
+++ b/asoc/codecs/msm_sdw/msm_sdw_registers.h
@@ -0,0 +1,126 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_SDW_REGISTERS_H
+#define MSM_SDW_REGISTERS_H
+
+#define MSM_SDW_PAGE_REGISTER                     0x0000
+
+/* Page-A Registers */
+#define MSM_SDW_TX9_SPKR_PROT_PATH_CTL               0x0308
+#define MSM_SDW_TX9_SPKR_PROT_PATH_CFG0              0x030c
+#define MSM_SDW_TX10_SPKR_PROT_PATH_CTL              0x0318
+#define MSM_SDW_TX10_SPKR_PROT_PATH_CFG0             0x031c
+#define MSM_SDW_TX11_SPKR_PROT_PATH_CTL              0x0328
+#define MSM_SDW_TX11_SPKR_PROT_PATH_CFG0             0x032c
+#define MSM_SDW_TX12_SPKR_PROT_PATH_CTL              0x0338
+#define MSM_SDW_TX12_SPKR_PROT_PATH_CFG0             0x033c
+
+/* Page-B Registers */
+#define MSM_SDW_COMPANDER7_CTL0                      0x0024
+#define MSM_SDW_COMPANDER7_CTL1                      0x0028
+#define MSM_SDW_COMPANDER7_CTL2                      0x002c
+#define MSM_SDW_COMPANDER7_CTL3                      0x0030
+#define MSM_SDW_COMPANDER7_CTL4                      0x0034
+#define MSM_SDW_COMPANDER7_CTL5                      0x0038
+#define MSM_SDW_COMPANDER7_CTL6                      0x003c
+#define MSM_SDW_COMPANDER7_CTL7                      0x0040
+#define MSM_SDW_COMPANDER8_CTL0                      0x0044
+#define MSM_SDW_COMPANDER8_CTL1                      0x0048
+#define MSM_SDW_COMPANDER8_CTL2                      0x004c
+#define MSM_SDW_COMPANDER8_CTL3                      0x0050
+#define MSM_SDW_COMPANDER8_CTL4                      0x0054
+#define MSM_SDW_COMPANDER8_CTL5                      0x0058
+#define MSM_SDW_COMPANDER8_CTL6                      0x005c
+#define MSM_SDW_COMPANDER8_CTL7                      0x0060
+#define MSM_SDW_RX7_RX_PATH_CTL                      0x01a4
+#define MSM_SDW_RX7_RX_PATH_CFG0                     0x01a8
+#define MSM_SDW_RX7_RX_PATH_CFG1                     0x01ac
+#define MSM_SDW_RX7_RX_PATH_CFG2                     0x01b0
+#define MSM_SDW_RX7_RX_VOL_CTL                       0x01b4
+#define MSM_SDW_RX7_RX_PATH_MIX_CTL                  0x01b8
+#define MSM_SDW_RX7_RX_PATH_MIX_CFG                  0x01bc
+#define MSM_SDW_RX7_RX_VOL_MIX_CTL                   0x01c0
+#define MSM_SDW_RX7_RX_PATH_SEC0                     0x01c4
+#define MSM_SDW_RX7_RX_PATH_SEC1                     0x01c8
+#define MSM_SDW_RX7_RX_PATH_SEC2                     0x01cc
+#define MSM_SDW_RX7_RX_PATH_SEC3                     0x01d0
+#define MSM_SDW_RX7_RX_PATH_SEC5                     0x01d8
+#define MSM_SDW_RX7_RX_PATH_SEC6                     0x01dc
+#define MSM_SDW_RX7_RX_PATH_SEC7                     0x01e0
+#define MSM_SDW_RX7_RX_PATH_MIX_SEC0                 0x01e4
+#define MSM_SDW_RX7_RX_PATH_MIX_SEC1                 0x01e8
+#define MSM_SDW_RX8_RX_PATH_CTL                      0x0384
+#define MSM_SDW_RX8_RX_PATH_CFG0                     0x0388
+#define MSM_SDW_RX8_RX_PATH_CFG1                     0x038c
+#define MSM_SDW_RX8_RX_PATH_CFG2                     0x0390
+#define MSM_SDW_RX8_RX_VOL_CTL                       0x0394
+#define MSM_SDW_RX8_RX_PATH_MIX_CTL                  0x0398
+#define MSM_SDW_RX8_RX_PATH_MIX_CFG                  0x039c
+#define MSM_SDW_RX8_RX_VOL_MIX_CTL                   0x03a0
+#define MSM_SDW_RX8_RX_PATH_SEC0                     0x03a4
+#define MSM_SDW_RX8_RX_PATH_SEC1                     0x03a8
+#define MSM_SDW_RX8_RX_PATH_SEC2                     0x03ac
+#define MSM_SDW_RX8_RX_PATH_SEC3                     0x03b0
+#define MSM_SDW_RX8_RX_PATH_SEC5                     0x03b8
+#define MSM_SDW_RX8_RX_PATH_SEC6                     0x03bc
+#define MSM_SDW_RX8_RX_PATH_SEC7                     0x03c0
+#define MSM_SDW_RX8_RX_PATH_MIX_SEC0                 0x03c4
+#define MSM_SDW_RX8_RX_PATH_MIX_SEC1                 0x03c8
+
+/* Page-C Registers */
+#define MSM_SDW_BOOST0_BOOST_PATH_CTL                0x0064
+#define MSM_SDW_BOOST0_BOOST_CTL                     0x0068
+#define MSM_SDW_BOOST0_BOOST_CFG1                    0x006c
+#define MSM_SDW_BOOST0_BOOST_CFG2                    0x0070
+#define MSM_SDW_BOOST1_BOOST_PATH_CTL                0x0084
+#define MSM_SDW_BOOST1_BOOST_CTL                     0x0088
+#define MSM_SDW_BOOST1_BOOST_CFG1                    0x008c
+#define MSM_SDW_BOOST1_BOOST_CFG2                    0x0090
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_0                 0x00a4
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_1                 0x00a8
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_2                 0x00ac
+#define MSM_SDW_AHB_BRIDGE_WR_DATA_3                 0x00b0
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_0                 0x00b4
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_1                 0x00b8
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_2                 0x00bc
+#define MSM_SDW_AHB_BRIDGE_WR_ADDR_3                 0x00c0
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_0                 0x00c4
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_1                 0x00c8
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_2                 0x00cc
+#define MSM_SDW_AHB_BRIDGE_RD_ADDR_3                 0x00d0
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_0                 0x00d4
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_1                 0x00d8
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_2                 0x00dc
+#define MSM_SDW_AHB_BRIDGE_RD_DATA_3                 0x00e0
+#define MSM_SDW_AHB_BRIDGE_ACCESS_CFG                0x00e4
+#define MSM_SDW_AHB_BRIDGE_ACCESS_STATUS             0x00e8
+
+/* Page-D Registers */
+#define MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL            0x0104
+#define MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL          0x0108
+#define MSM_SDW_CLK_RST_CTRL_SWR_CONTROL             0x010c
+#define MSM_SDW_TOP_TOP_CFG0                         0x0204
+#define MSM_SDW_TOP_TOP_CFG1                         0x0208
+#define MSM_SDW_TOP_RX_I2S_CTL                       0x020c
+#define MSM_SDW_TOP_TX_I2S_CTL                       0x0210
+#define MSM_SDW_TOP_I2S_CLK                          0x0214
+#define MSM_SDW_TOP_RX7_PATH_INPUT0_MUX              0x0218
+#define MSM_SDW_TOP_RX7_PATH_INPUT1_MUX              0x021c
+#define MSM_SDW_TOP_RX8_PATH_INPUT0_MUX              0x0220
+#define MSM_SDW_TOP_RX8_PATH_INPUT1_MUX              0x0224
+#define MSM_SDW_TOP_FREQ_MCLK                        0x0228
+#define MSM_SDW_TOP_DEBUG_BUS_SEL                    0x022c
+#define MSM_SDW_TOP_DEBUG_EN                         0x0230
+#define MSM_SDW_TOP_I2S_RESET                        0x0234
+#define MSM_SDW_TOP_BLOCKS_RESET                     0x0238
+
+#endif
diff --git a/asoc/codecs/msm_sdw/msm_sdw_regmap.c b/asoc/codecs/msm_sdw/msm_sdw_regmap.c
new file mode 100644
index 0000000..2266338
--- /dev/null
+++ b/asoc/codecs/msm_sdw/msm_sdw_regmap.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include "msm_sdw.h"
+
+static const struct reg_default msm_sdw_defaults[] = {
+	/* Page #10 registers */
+	{ MSM_SDW_PAGE_REGISTER, 0x00 },
+	{ MSM_SDW_TX9_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX9_SPKR_PROT_PATH_CFG0, 0x00 },
+	{ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX10_SPKR_PROT_PATH_CFG0, 0x00 },
+	{ MSM_SDW_TX11_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX11_SPKR_PROT_PATH_CFG0, 0x00 },
+	{ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x02 },
+	{ MSM_SDW_TX12_SPKR_PROT_PATH_CFG0, 0x00 },
+	/* Page #11 registers */
+	{ MSM_SDW_COMPANDER7_CTL0, 0x60 },
+	{ MSM_SDW_COMPANDER7_CTL1, 0xdb },
+	{ MSM_SDW_COMPANDER7_CTL2, 0xff },
+	{ MSM_SDW_COMPANDER7_CTL3, 0x35 },
+	{ MSM_SDW_COMPANDER7_CTL4, 0xff },
+	{ MSM_SDW_COMPANDER7_CTL5, 0x00 },
+	{ MSM_SDW_COMPANDER7_CTL6, 0x01 },
+	{ MSM_SDW_COMPANDER8_CTL0, 0x60 },
+	{ MSM_SDW_COMPANDER8_CTL1, 0xdb },
+	{ MSM_SDW_COMPANDER8_CTL2, 0xff },
+	{ MSM_SDW_COMPANDER8_CTL3, 0x35 },
+	{ MSM_SDW_COMPANDER8_CTL4, 0xff },
+	{ MSM_SDW_COMPANDER8_CTL5, 0x00 },
+	{ MSM_SDW_COMPANDER8_CTL6, 0x01 },
+	{ MSM_SDW_RX7_RX_PATH_CTL, 0x04 },
+	{ MSM_SDW_RX7_RX_PATH_CFG0, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_CFG2, 0x8f },
+	{ MSM_SDW_RX7_RX_VOL_CTL, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_MIX_CTL, 0x04 },
+	{ MSM_SDW_RX7_RX_VOL_MIX_CTL, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC2, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC3, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC5, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC6, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_SEC7, 0x00 },
+	{ MSM_SDW_RX7_RX_PATH_MIX_SEC1, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_CTL, 0x04 },
+	{ MSM_SDW_RX8_RX_PATH_CFG0, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_CFG2, 0x8f },
+	{ MSM_SDW_RX8_RX_VOL_CTL, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_MIX_CTL, 0x04 },
+	{ MSM_SDW_RX8_RX_VOL_MIX_CTL, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC2, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC3, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC5, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC6, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_SEC7, 0x00 },
+	{ MSM_SDW_RX8_RX_PATH_MIX_SEC1, 0x00 },
+	/* Page #12 registers */
+	{ MSM_SDW_BOOST0_BOOST_PATH_CTL, 0x00 },
+	{ MSM_SDW_BOOST0_BOOST_CTL, 0xb2 },
+	{ MSM_SDW_BOOST0_BOOST_CFG1, 0x00 },
+	{ MSM_SDW_BOOST0_BOOST_CFG2, 0x00 },
+	{ MSM_SDW_BOOST1_BOOST_PATH_CTL, 0x00 },
+	{ MSM_SDW_BOOST1_BOOST_CTL, 0xb2 },
+	{ MSM_SDW_BOOST1_BOOST_CFG1, 0x00 },
+	{ MSM_SDW_BOOST1_BOOST_CFG2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_DATA_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_WR_ADDR_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_ADDR_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_0, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_1, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_2, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_RD_DATA_3, 0x00 },
+	{ MSM_SDW_AHB_BRIDGE_ACCESS_CFG, 0x0f },
+	{ MSM_SDW_AHB_BRIDGE_ACCESS_STATUS, 0x03 },
+	/* Page #13 registers */
+	{ MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL, 0x00 },
+	{ MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 },
+	{ MSM_SDW_CLK_RST_CTRL_SWR_CONTROL, 0x00 },
+	{ MSM_SDW_TOP_TOP_CFG0, 0x00 },
+	{ MSM_SDW_TOP_TOP_CFG1, 0x00 },
+	{ MSM_SDW_TOP_RX_I2S_CTL, 0x0C },
+	{ MSM_SDW_TOP_TX_I2S_CTL, 0x00 },
+	{ MSM_SDW_TOP_I2S_CLK, 0x00 },
+	{ MSM_SDW_TOP_RX7_PATH_INPUT0_MUX, 0x00 },
+	{ MSM_SDW_TOP_RX7_PATH_INPUT1_MUX, 0x00 },
+	{ MSM_SDW_TOP_RX8_PATH_INPUT0_MUX, 0x00 },
+	{ MSM_SDW_TOP_RX8_PATH_INPUT1_MUX, 0x00 },
+	{ MSM_SDW_TOP_FREQ_MCLK, 0x00 },
+	{ MSM_SDW_TOP_DEBUG_BUS_SEL, 0x00 },
+	{ MSM_SDW_TOP_DEBUG_EN, 0x00 },
+	{ MSM_SDW_TOP_I2S_RESET, 0x00 },
+	{ MSM_SDW_TOP_BLOCKS_RESET, 0x00 },
+};
+
+static bool msm_sdw_is_readable_register(struct device *dev, unsigned int reg)
+{
+	return msm_sdw_reg_readable[reg];
+}
+
+static bool msm_sdw_is_writeable_register(struct device *dev, unsigned int reg)
+{
+	return msm_sdw_reg_writeable[reg];
+}
+
+static bool msm_sdw_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_0:
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_1:
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_2:
+	case MSM_SDW_AHB_BRIDGE_WR_DATA_3:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_0:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_1:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_2:
+	case MSM_SDW_AHB_BRIDGE_WR_ADDR_3:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_0:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_1:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_2:
+	case MSM_SDW_AHB_BRIDGE_RD_DATA_3:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_0:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_1:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_2:
+	case MSM_SDW_AHB_BRIDGE_RD_ADDR_3:
+	case MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL:
+	case MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+const struct regmap_config msm_sdw_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.reg_stride = 4,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = msm_sdw_defaults,
+	.num_reg_defaults = ARRAY_SIZE(msm_sdw_defaults),
+	.max_register = MSM_SDW_MAX_REGISTER,
+	.writeable_reg = msm_sdw_is_writeable_register,
+	.volatile_reg = msm_sdw_is_volatile_register,
+	.readable_reg = msm_sdw_is_readable_register,
+};
diff --git a/asoc/codecs/msm_stub.c b/asoc/codecs/msm_stub.c
new file mode 100644
index 0000000..68e55ae
--- /dev/null
+++ b/asoc/codecs/msm_stub.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+/* A dummy driver useful only to advertise hardware parameters */
+static struct snd_soc_dai_driver msm_stub_dais[] = {
+	{
+		.name = "msm-stub-rx",
+		.playback = { /* Support maximum range */
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	},
+	{
+		.name = "msm-stub-tx",
+		.capture = { /* Support maximum range */
+			.stream_name = "Record",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE),
+		},
+	},
+};
+
+static struct snd_soc_codec_driver soc_msm_stub = {};
+
+static int msm_stub_dev_probe(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+
+	return snd_soc_register_codec(&pdev->dev,
+	&soc_msm_stub, msm_stub_dais, ARRAY_SIZE(msm_stub_dais));
+}
+
+static int msm_stub_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+static const struct of_device_id msm_stub_codec_dt_match[] = {
+	{ .compatible = "qcom,msm-stub-codec", },
+	{}
+};
+
+static struct platform_driver msm_stub_driver = {
+	.driver = {
+		.name = "msm-stub-codec",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_stub_codec_dt_match,
+	},
+	.probe = msm_stub_dev_probe,
+	.remove = msm_stub_dev_remove,
+};
+
+static int __init msm_stub_init(void)
+{
+	return platform_driver_register(&msm_stub_driver);
+}
+module_init(msm_stub_init);
+
+static void __exit msm_stub_exit(void)
+{
+	platform_driver_unregister(&msm_stub_driver);
+}
+module_exit(msm_stub_exit);
+
+MODULE_DESCRIPTION("Generic MSM CODEC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/pdata.h b/asoc/codecs/pdata.h
new file mode 100644
index 0000000..fa16b3d
--- /dev/null
+++ b/asoc/codecs/pdata.h
@@ -0,0 +1,197 @@
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MFD_WCD9XXX_PDATA_H__
+
+#define __MFD_WCD9XXX_PDATA_H__
+
+#include <linux/slimbus/slimbus.h>
+#include "msm-cdc-supply.h"
+
+#define MICBIAS_EXT_BYP_CAP 0x00
+#define MICBIAS_NO_EXT_BYP_CAP 0x01
+
+#define SITAR_LDOH_1P95_V 0x0
+#define SITAR_LDOH_2P35_V 0x1
+#define SITAR_LDOH_2P75_V 0x2
+#define SITAR_LDOH_2P85_V 0x3
+
+#define SITAR_CFILT1_SEL 0x0
+#define SITAR_CFILT2_SEL 0x1
+#define SITAR_CFILT3_SEL 0x2
+
+#define WCD9XXX_LDOH_1P95_V 0x0
+#define WCD9XXX_LDOH_2P35_V 0x1
+#define WCD9XXX_LDOH_2P75_V 0x2
+#define WCD9XXX_LDOH_2P85_V 0x3
+#define WCD9XXX_LDOH_3P0_V 0x3
+
+#define TABLA_LDOH_1P95_V 0x0
+#define TABLA_LDOH_2P35_V 0x1
+#define TABLA_LDOH_2P75_V 0x2
+#define TABLA_LDOH_2P85_V 0x3
+
+#define TABLA_CFILT1_SEL 0x0
+#define TABLA_CFILT2_SEL 0x1
+#define TABLA_CFILT3_SEL 0x2
+
+#define MAX_AMIC_CHANNEL 7
+
+#define TABLA_OCP_300_MA 0x0
+#define TABLA_OCP_350_MA 0x2
+#define TABLA_OCP_365_MA 0x3
+#define TABLA_OCP_150_MA 0x4
+#define TABLA_OCP_190_MA 0x6
+#define TABLA_OCP_220_MA 0x7
+
+#define TABLA_DCYCLE_255  0x0
+#define TABLA_DCYCLE_511  0x1
+#define TABLA_DCYCLE_767  0x2
+#define TABLA_DCYCLE_1023 0x3
+#define TABLA_DCYCLE_1279 0x4
+#define TABLA_DCYCLE_1535 0x5
+#define TABLA_DCYCLE_1791 0x6
+#define TABLA_DCYCLE_2047 0x7
+#define TABLA_DCYCLE_2303 0x8
+#define TABLA_DCYCLE_2559 0x9
+#define TABLA_DCYCLE_2815 0xA
+#define TABLA_DCYCLE_3071 0xB
+#define TABLA_DCYCLE_3327 0xC
+#define TABLA_DCYCLE_3583 0xD
+#define TABLA_DCYCLE_3839 0xE
+#define TABLA_DCYCLE_4095 0xF
+
+#define WCD9XXX_MCLK_CLK_12P288MHZ 12288000
+#define WCD9XXX_MCLK_CLK_9P6HZ 9600000
+
+/* Only valid for 9.6 MHz mclk */
+#define WCD9XXX_DMIC_SAMPLE_RATE_600KHZ 600000
+#define WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ 2400000
+#define WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ 3200000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ 4800000
+
+/* Only valid for 12.288 MHz mclk */
+#define WCD9XXX_DMIC_SAMPLE_RATE_768KHZ 768000
+#define WCD9XXX_DMIC_SAMPLE_RATE_2P048MHZ 2048000
+#define WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ 3072000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ 4096000
+#define WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ 6144000
+
+#define WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED 0
+
+#define WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED 0
+
+struct wcd9xxx_amic {
+	/*legacy mode, txfe_enable and txfe_buff take 7 input
+	 * each bit represent the channel / TXFE number
+	 * and numbered as below
+	 * bit 0 = channel 1 / TXFE1_ENABLE / TXFE1_BUFF
+	 * bit 1 = channel 2 / TXFE2_ENABLE / TXFE2_BUFF
+	 * ...
+	 * bit 7 = channel 7 / TXFE7_ENABLE / TXFE7_BUFF
+	 */
+	u8 legacy_mode:MAX_AMIC_CHANNEL;
+	u8 txfe_enable:MAX_AMIC_CHANNEL;
+	u8 txfe_buff:MAX_AMIC_CHANNEL;
+	u8 use_pdata:MAX_AMIC_CHANNEL;
+};
+
+/* Each micbias can be assigned to one of three cfilters
+ * Vbatt_min >= .15V + ldoh_v
+ * ldoh_v >= .15v + cfiltx_mv
+ * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
+ * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
+ * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
+ * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
+ */
+
+struct wcd9xxx_micbias_setting {
+	u8 ldoh_v;
+	u32 cfilt1_mv; /* in mv */
+	u32 cfilt2_mv; /* in mv */
+	u32 cfilt3_mv; /* in mv */
+	u32 micb1_mv;
+	u32 micb2_mv;
+	u32 micb3_mv;
+	u32 micb4_mv;
+	/* Different WCD9xxx series codecs may not
+	 * have 4 mic biases. If a codec has fewer
+	 * mic biases, some of these properties will
+	 * not be used.
+	 */
+	u8 bias1_cfilt_sel;
+	u8 bias2_cfilt_sel;
+	u8 bias3_cfilt_sel;
+	u8 bias4_cfilt_sel;
+	u8 bias1_cap_mode;
+	u8 bias2_cap_mode;
+	u8 bias3_cap_mode;
+	u8 bias4_cap_mode;
+	bool bias2_is_headset_only;
+};
+
+struct wcd9xxx_ocp_setting {
+	unsigned int	use_pdata:1; /* 0 - use sys default as recommended */
+	unsigned int	num_attempts:4; /* up to 15 attempts */
+	unsigned int	run_time:4; /* in duty cycle */
+	unsigned int	wait_time:4; /* in duty cycle */
+	unsigned int	hph_ocp_limit:3; /* Headphone OCP current limit */
+};
+
+#define WCD9XXX_MAX_REGULATOR	9
+/*
+ *      format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
+ *
+ *      <POWER_SUPPLY_PIN_NAME> from Tabla objective spec
+ */
+
+#define  WCD9XXX_CDC_VDDA_CP_CUR_MAX      500000
+#define  WCD9XXX_CDC_VDDA_RX_CUR_MAX      20000
+#define  WCD9XXX_CDC_VDDA_TX_CUR_MAX      20000
+#define  WCD9XXX_VDDIO_CDC_CUR_MAX        5000
+
+#define  WCD9XXX_VDDD_CDC_D_CUR_MAX       5000
+#define  WCD9XXX_VDDD_CDC_A_CUR_MAX       5000
+
+#define WCD9XXX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv"
+#define WCD9XXX_VDD_SPKDRV2_NAME "cdc-vdd-spkdrv-2"
+
+struct wcd9xxx_regulator {
+	const char *name;
+	int min_uV;
+	int max_uV;
+	int optimum_uA;
+	bool ondemand;
+	struct regulator *regulator;
+};
+
+struct wcd9xxx_pdata {
+	int irq;
+	int irq_base;
+	int num_irqs;
+	int reset_gpio;
+	struct device_node *wcd_rst_np;
+	struct wcd9xxx_amic amic_settings;
+	struct slim_device slimbus_slave_device;
+	struct wcd9xxx_micbias_setting micbias;
+	struct wcd9xxx_ocp_setting ocp;
+	struct cdc_regulator *regulator;
+	int num_supplies;
+	u32 mclk_rate;
+	u32 dmic_sample_rate;
+	u32 mad_dmic_sample_rate;
+	u32 ecpp_dmic_sample_rate;
+	u32 dmic_clk_drv;
+	u16 use_pinctrl;
+};
+
+#endif
diff --git a/asoc/codecs/sdm660_cdc/Makefile b/asoc/codecs/sdm660_cdc/Makefile
new file mode 100644
index 0000000..d846fae
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/Makefile
@@ -0,0 +1,2 @@
+snd-soc-sdm660-cdc-objs := msm-analog-cdc.o msm-digital-cdc.o sdm660-regmap.o
+obj-$(CONFIG_SND_SOC_SDM660_CDC) += snd-soc-sdm660-cdc.o sdm660-cdc-irq.o
diff --git a/asoc/codecs/sdm660_cdc/msm-analog-cdc.c b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
new file mode 100644
index 0000000..ddef508
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -0,0 +1,4691 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <dsp/audio_notifier.h>
+#include <dsp/q6afe-v2.h>
+#include <dsp/q6core.h>
+#include <ipc/apr.h>
+#include "msm-analog-cdc.h"
+#include "msm-cdc-common.h"
+#include "sdm660-cdc-irq.h"
+#include "sdm660-cdc-registers.h"
+#include "../../sdm660-common.h"
+#include "../wcd-mbhc-v2-api.h"
+
+#define DRV_NAME "pmic_analog_codec"
+#define SDM660_CDC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
+			SNDRV_PCM_RATE_192000)
+#define SDM660_CDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE)
+#define MSM_DIG_CDC_STRING_LEN 80
+#define MSM_ANLG_CDC_VERSION_ENTRY_SIZE 32
+
+#define CODEC_DT_MAX_PROP_SIZE			40
+#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH	64
+#define BUS_DOWN 1
+
+/*
+ * 50 Milliseconds sufficient for DSP bring up in the lpass
+ * after Sub System Restart
+ */
+#define ADSP_STATE_READY_TIMEOUT_MS 50
+
+#define EAR_PMD 0
+#define EAR_PMU 1
+#define SPK_PMD 2
+#define SPK_PMU 3
+
+#define MICBIAS_DEFAULT_VAL 1800000
+#define MICBIAS_MIN_VAL 1600000
+#define MICBIAS_STEP_SIZE 50000
+
+#define DEFAULT_BOOST_VOLTAGE 5000
+#define MIN_BOOST_VOLTAGE 4000
+#define MAX_BOOST_VOLTAGE 5550
+#define BOOST_VOLTAGE_STEP 50
+
+#define SDM660_CDC_MBHC_BTN_COARSE_ADJ  100 /* in mV */
+#define SDM660_CDC_MBHC_BTN_FINE_ADJ 12 /* in mV */
+
+#define VOLTAGE_CONVERTER(value, min_value, step_size)\
+	((value - min_value)/step_size)
+
+enum {
+	BOOST_SWITCH = 0,
+	BOOST_ALWAYS,
+	BYPASS_ALWAYS,
+	BOOST_ON_FOREVER,
+};
+
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[];
+/* By default enable the internal speaker boost */
+static bool spkr_boost_en = true;
+
+static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
+	"cdc-vdd-mic-bias",
+};
+
+static struct wcd_mbhc_register
+	wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
+	WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x18, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+			  MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x06, 1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+			  MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+			  MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0xF0, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+			  MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x0C, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+			  MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x01,
+			  0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x02,
+			  1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x08,
+			  3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x04,
+			  2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+			  MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+			  MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x70, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0xFF,
+			  0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+			  MSM89XX_PMIC_ANALOG_MICB_2_EN, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFC, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+			  MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x30, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+			  MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT,
+			  0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
+			  MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", 0, 0, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", 0, 0, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", 0, 0, 0, 0),
+};
+
+/* Multiply gain_adj and offset by 1000 and 100 to avoid float arithmetic */
+static const struct wcd_imped_i_ref imped_i_ref[] = {
+	{I_h4_UA, 8, 800, 9000, 10000},
+	{I_pt5_UA, 10, 100, 990, 4600},
+	{I_14_UA, 17, 14, 1050, 700},
+	{I_l4_UA, 10, 4, 1165, 110},
+	{I_1_UA, 0, 1, 1200, 65},
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+	.mbhc_sw_intr =  MSM89XX_IRQ_MBHC_HS_DET,
+	.mbhc_btn_press_intr = MSM89XX_IRQ_MBHC_PRESS,
+	.mbhc_btn_release_intr = MSM89XX_IRQ_MBHC_RELEASE,
+	.mbhc_hs_ins_intr = MSM89XX_IRQ_MBHC_INSREM_DET1,
+	.mbhc_hs_rem_intr = MSM89XX_IRQ_MBHC_INSREM_DET,
+	.hph_left_ocp = MSM89XX_IRQ_HPHL_OCP,
+	.hph_right_ocp = MSM89XX_IRQ_HPHR_OCP,
+};
+
+static int msm_anlg_cdc_dt_parse_vreg_info(struct device *dev,
+					   struct sdm660_cdc_regulator *vreg,
+					   const char *vreg_name,
+					   bool ondemand);
+static struct sdm660_cdc_pdata *msm_anlg_cdc_populate_dt_pdata(
+						struct device *dev);
+static int msm_anlg_cdc_enable_ext_mb_source(struct wcd_mbhc *wcd_mbhc,
+					     bool turn_on);
+static void msm_anlg_cdc_trim_btn_reg(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_micb_v(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_boost_v(struct snd_soc_codec *codec);
+static void msm_anlg_cdc_set_auto_zeroing(struct snd_soc_codec *codec,
+					  bool enable);
+static void msm_anlg_cdc_configure_cap(struct snd_soc_codec *codec,
+				       bool micbias1, bool micbias2);
+static bool msm_anlg_cdc_use_mb(struct snd_soc_codec *codec);
+
+static int get_codec_version(struct sdm660_cdc_priv *sdm660_cdc)
+{
+	if (sdm660_cdc->codec_version == DRAX_CDC)
+		return DRAX_CDC;
+	else if (sdm660_cdc->codec_version == DIANGU)
+		return DIANGU;
+	else if (sdm660_cdc->codec_version == CAJON_2_0)
+		return CAJON_2_0;
+	else if (sdm660_cdc->codec_version == CAJON)
+		return CAJON;
+	else if (sdm660_cdc->codec_version == CONGA)
+		return CONGA;
+	else if (sdm660_cdc->pmic_rev == TOMBAK_2_0)
+		return TOMBAK_2_0;
+	else if (sdm660_cdc->pmic_rev == TOMBAK_1_0)
+		return TOMBAK_1_0;
+
+	pr_err("%s: unsupported codec version\n", __func__);
+	return UNSUPPORTED;
+}
+
+static void wcd_mbhc_meas_imped(struct snd_soc_codec *codec,
+				s16 *impedance_l, s16 *impedance_r)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if ((sdm660_cdc->imped_det_pin == WCD_MBHC_DET_BOTH) ||
+	    (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL)) {
+		/* Enable ZDET_L_MEAS_EN */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x08, 0x08);
+		/* Wait for 2ms for measurement to complete */
+		usleep_range(2000, 2100);
+		/* Read Left impedance value from Result1 */
+		*impedance_l = snd_soc_read(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+		/* Enable ZDET_R_MEAS_EN */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x08, 0x00);
+	}
+	if ((sdm660_cdc->imped_det_pin == WCD_MBHC_DET_BOTH) ||
+	    (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)) {
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x04, 0x04);
+		/* Wait for 2ms for measurement to complete */
+		usleep_range(2000, 2100);
+		/* Read Right impedance value from Result1 */
+		*impedance_r = snd_soc_read(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x04, 0x00);
+	}
+}
+
+static void msm_anlg_cdc_set_ref_current(struct snd_soc_codec *codec,
+					 enum wcd_curr_ref curr_ref)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: curr_ref: %d\n", __func__, curr_ref);
+
+	if (get_codec_version(sdm660_cdc) < CAJON)
+		dev_dbg(codec->dev, "%s: Setting ref current not required\n",
+			__func__);
+
+	sdm660_cdc->imped_i_ref = imped_i_ref[curr_ref];
+
+	switch (curr_ref) {
+	case I_h4_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x01);
+		break;
+	case I_pt5_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x04);
+		break;
+	case I_14_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x03);
+		break;
+	case I_l4_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x01);
+		break;
+	case I_1_UA:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0x07, 0x00);
+		break;
+	default:
+		pr_debug("%s: No ref current set\n", __func__);
+		break;
+	}
+}
+
+static bool msm_anlg_cdc_adj_ref_current(struct snd_soc_codec *codec,
+					 s16 *impedance_l, s16 *impedance_r)
+{
+	int i = 2;
+	s16 compare_imp = 0;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)
+		compare_imp = *impedance_r;
+	else
+		compare_imp = *impedance_l;
+
+	if (get_codec_version(sdm660_cdc) < CAJON) {
+		dev_dbg(codec->dev,
+			"%s: Reference current adjustment not required\n",
+			 __func__);
+		return false;
+	}
+
+	while (compare_imp < imped_i_ref[i].min_val) {
+		msm_anlg_cdc_set_ref_current(codec, imped_i_ref[++i].curr_ref);
+		wcd_mbhc_meas_imped(codec, impedance_l, impedance_r);
+		compare_imp = (sdm660_cdc->imped_det_pin ==
+			       WCD_MBHC_DET_HPHR) ? *impedance_r : *impedance_l;
+		if (i >= I_1_UA)
+			break;
+	}
+	return true;
+}
+
+void msm_anlg_cdc_spk_ext_pa_cb(
+		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
+			int enable), struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer!\n", __func__);
+		return;
+	}
+
+	sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: Enter\n", __func__);
+	sdm660_cdc->codec_spk_ext_pa_cb = codec_spk_ext_pa;
+}
+
+static void msm_anlg_cdc_compute_impedance(struct snd_soc_codec *codec, s16 l,
+					   s16 r, uint32_t *zl, uint32_t *zr,
+					   bool high)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	uint32_t rl = 0, rr = 0;
+	struct wcd_imped_i_ref R = sdm660_cdc->imped_i_ref;
+	int codec_ver = get_codec_version(sdm660_cdc);
+
+	switch (codec_ver) {
+	case TOMBAK_1_0:
+	case TOMBAK_2_0:
+	case CONGA:
+		if (high) {
+			dev_dbg(codec->dev,
+				"%s: This plug has high range impedance\n",
+				 __func__);
+			rl = (uint32_t)(((100 * (l * 400 - 200))/96) - 230);
+			rr = (uint32_t)(((100 * (r * 400 - 200))/96) - 230);
+		} else {
+			dev_dbg(codec->dev,
+				"%s: This plug has low range impedance\n",
+				 __func__);
+			rl = (uint32_t)(((1000 * (l * 2 - 1))/1165) - (13/10));
+			rr = (uint32_t)(((1000 * (r * 2 - 1))/1165) - (13/10));
+		}
+		break;
+	case CAJON:
+	case CAJON_2_0:
+	case DIANGU:
+	case DRAX_CDC:
+		if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL) {
+			rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+			rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+		} else if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR) {
+			rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+			rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+		} else if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_NONE) {
+			rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) -
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+			rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))-
+			   (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN);
+		} else {
+			rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+			rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5)))
+			      - R.offset * R.gain_adj)/(R.gain_adj * 100));
+		}
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: No codec mentioned\n", __func__);
+		break;
+	}
+	*zl = rl;
+	*zr = rr;
+}
+
+static struct firmware_cal *msm_anlg_cdc_get_hwdep_fw_cal(
+		struct wcd_mbhc *wcd_mbhc,
+		enum wcd_cal_type type)
+{
+	struct sdm660_cdc_priv *sdm660_cdc;
+	struct firmware_cal *hwdep_cal;
+	struct snd_soc_codec *codec = wcd_mbhc->codec;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer\n", __func__);
+		return NULL;
+	}
+	sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	hwdep_cal = wcdcal_get_fw_cal(sdm660_cdc->fw_data, type);
+	if (!hwdep_cal) {
+		dev_err(codec->dev, "%s: cal not sent by %d\n",
+				__func__, type);
+		return NULL;
+	}
+	return hwdep_cal;
+}
+
+static void wcd9xxx_spmi_irq_control(struct snd_soc_codec *codec,
+				     int irq, bool enable)
+{
+	if (enable)
+		wcd9xxx_spmi_enable_irq(irq);
+	else
+		wcd9xxx_spmi_disable_irq(irq);
+}
+
+static void msm_anlg_cdc_mbhc_clk_setup(struct snd_soc_codec *codec,
+					bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				0x08, 0x08);
+	else
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				0x08, 0x00);
+}
+
+static int msm_anlg_cdc_mbhc_map_btn_code_to_num(struct snd_soc_codec *codec)
+{
+	int btn_code;
+	int btn;
+
+	btn_code = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+
+	switch (btn_code) {
+	case 0:
+		btn = 0;
+		break;
+	case 1:
+		btn = 1;
+		break;
+	case 3:
+		btn = 2;
+		break;
+	case 7:
+		btn = 3;
+		break;
+	case 15:
+		btn = 4;
+		break;
+	default:
+		btn = -EINVAL;
+		break;
+	};
+
+	return btn;
+}
+
+static bool msm_anlg_cdc_spmi_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+	if (lock)
+		return wcd9xxx_spmi_lock_sleep();
+	wcd9xxx_spmi_unlock_sleep();
+	return 0;
+}
+
+static bool msm_anlg_cdc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+	if (micb_num == MIC_BIAS_1)
+		return (snd_soc_read(mbhc->codec,
+				     MSM89XX_PMIC_ANALOG_MICB_1_EN) &
+			0x80);
+	if (micb_num == MIC_BIAS_2)
+		return (snd_soc_read(mbhc->codec,
+				     MSM89XX_PMIC_ANALOG_MICB_2_EN) &
+			0x80);
+	return false;
+}
+
+static void msm_anlg_cdc_enable_master_bias(struct snd_soc_codec *codec,
+					    bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
+				    0x30, 0x30);
+	else
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL,
+				    0x30, 0x00);
+}
+
+static void msm_anlg_cdc_mbhc_common_micb_ctrl(struct snd_soc_codec *codec,
+					       int event, bool enable)
+{
+	u16 reg;
+	u8 mask;
+	u8 val;
+
+	switch (event) {
+	case MBHC_COMMON_MICB_PRECHARGE:
+		reg = MSM89XX_PMIC_ANALOG_MICB_1_CTL;
+		mask = 0x60;
+		val = (enable ? 0x60 : 0x00);
+		break;
+	case MBHC_COMMON_MICB_SET_VAL:
+		reg = MSM89XX_PMIC_ANALOG_MICB_1_VAL;
+		mask = 0xFF;
+		val = (enable ? 0xC0 : 0x00);
+		break;
+	case MBHC_COMMON_MICB_TAIL_CURR:
+		reg = MSM89XX_PMIC_ANALOG_MICB_1_EN;
+		mask = 0x04;
+		val = (enable ? 0x04 : 0x00);
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: Invalid event received\n", __func__);
+		return;
+	};
+	snd_soc_update_bits(codec, reg, mask, val);
+}
+
+static void msm_anlg_cdc_mbhc_internal_micbias_ctrl(struct snd_soc_codec *codec,
+						    int micbias_num,
+						    bool enable)
+{
+	if (micbias_num == 1) {
+		if (enable)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
+				0x10, 0x10);
+		else
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS,
+				0x10, 0x00);
+	}
+}
+
+static bool msm_anlg_cdc_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
+{
+	return (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN) &
+		0x30) ? true : false;
+}
+
+static void msm_anlg_cdc_mbhc_program_btn_thr(struct snd_soc_codec *codec,
+					      s16 *btn_low, s16 *btn_high,
+					      int num_btn, bool is_micbias)
+{
+	int i;
+	u32 course, fine, reg_val;
+	u16 reg_addr = MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL;
+	s16 *btn_voltage;
+
+	btn_voltage = ((is_micbias) ? btn_high : btn_low);
+
+	for (i = 0; i <  num_btn; i++) {
+		course = (btn_voltage[i] / SDM660_CDC_MBHC_BTN_COARSE_ADJ);
+		fine = ((btn_voltage[i] % SDM660_CDC_MBHC_BTN_COARSE_ADJ) /
+				SDM660_CDC_MBHC_BTN_FINE_ADJ);
+
+		reg_val = (course << 5) | (fine << 2);
+		snd_soc_update_bits(codec, reg_addr, 0xFC, reg_val);
+		dev_dbg(codec->dev,
+			"%s: course: %d fine: %d reg_addr: %x reg_val: %x\n",
+			  __func__, course, fine, reg_addr, reg_val);
+		reg_addr++;
+	}
+}
+
+static void msm_anlg_cdc_mbhc_calc_impedance(struct wcd_mbhc *mbhc,
+					     uint32_t *zl, uint32_t *zr)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	s16 impedance_l, impedance_r;
+	s16 impedance_l_fixed;
+	s16 reg0, reg1, reg2, reg3, reg4;
+	bool high = false;
+	bool min_range_used =  false;
+
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+	reg0 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER);
+	reg1 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL);
+	reg2 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2);
+	reg3 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN);
+	reg4 = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL);
+
+	sdm660_cdc->imped_det_pin = WCD_MBHC_DET_BOTH;
+	mbhc->hph_type = WCD_MBHC_HPH_NONE;
+
+	/* disable FSM and micbias and enable pullup*/
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x80, 0x00);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_2_EN,
+			0xA5, 0x25);
+	/*
+	 * Enable legacy electrical detection current sources
+	 * and disable fast ramp and enable manual switching
+	 * of extra capacitance
+	 */
+	dev_dbg(codec->dev, "%s: Setup for impedance det\n", __func__);
+
+	msm_anlg_cdc_set_ref_current(codec, I_h4_UA);
+
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
+			0x06, 0x02);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER,
+			0x02, 0x02);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL,
+			0x02, 0x00);
+
+	dev_dbg(codec->dev, "%s: Start performing impedance detection\n",
+		 __func__);
+
+	wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
+
+	if (impedance_l > 2 || impedance_r > 2) {
+		high = true;
+		if (!mbhc->mbhc_cfg->mono_stero_detection) {
+			/* Set ZDET_CHG to 0  to discharge ramp */
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+					0x02, 0x00);
+			/* wait 40ms for the discharge ramp to complete */
+			usleep_range(40000, 40100);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+				0x03, 0x00);
+			sdm660_cdc->imped_det_pin = (impedance_l > 2 &&
+						      impedance_r > 2) ?
+						      WCD_MBHC_DET_NONE :
+						      ((impedance_l > 2) ?
+						      WCD_MBHC_DET_HPHR :
+						      WCD_MBHC_DET_HPHL);
+			if (sdm660_cdc->imped_det_pin == WCD_MBHC_DET_NONE)
+				goto exit;
+		} else {
+			if (get_codec_version(sdm660_cdc) >= CAJON) {
+				if (impedance_l == 63 && impedance_r == 63) {
+					dev_dbg(codec->dev,
+						"%s: HPHL and HPHR are floating\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_NONE;
+					mbhc->hph_type = WCD_MBHC_HPH_NONE;
+				} else if (impedance_l == 63
+					   && impedance_r < 63) {
+					dev_dbg(codec->dev,
+						"%s: Mono HS with HPHL floating\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_HPHR;
+					mbhc->hph_type = WCD_MBHC_HPH_MONO;
+				} else if (impedance_r == 63 &&
+					   impedance_l < 63) {
+					dev_dbg(codec->dev,
+						"%s: Mono HS with HPHR floating\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_HPHL;
+					mbhc->hph_type = WCD_MBHC_HPH_MONO;
+				} else if (impedance_l > 3 && impedance_r > 3 &&
+					(impedance_l == impedance_r)) {
+					snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2,
+					0x06, 0x06);
+					wcd_mbhc_meas_imped(codec, &impedance_l,
+							    &impedance_r);
+					if (impedance_r == impedance_l)
+						dev_dbg(codec->dev,
+							"%s: Mono Headset\n",
+							__func__);
+						sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_NONE;
+						mbhc->hph_type =
+							WCD_MBHC_HPH_MONO;
+				} else {
+					dev_dbg(codec->dev,
+						"%s: STEREO headset is found\n",
+						 __func__);
+					sdm660_cdc->imped_det_pin =
+							WCD_MBHC_DET_BOTH;
+					mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+				}
+			}
+		}
+	}
+
+	msm_anlg_cdc_set_ref_current(codec, I_pt5_UA);
+	msm_anlg_cdc_set_ref_current(codec, I_14_UA);
+
+	/* Enable RAMP_L , RAMP_R & ZDET_CHG*/
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x03, 0x03);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x02);
+	/* wait for 50msec for the HW to apply ramp on HPHL and HPHR */
+	usleep_range(50000, 50100);
+	/* Enable ZDET_DISCHG_CAP_CTL  to add extra capacitance */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x01, 0x01);
+	/* wait for 5msec for the voltage to get stable */
+	usleep_range(5000, 5100);
+
+	wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r);
+
+	min_range_used = msm_anlg_cdc_adj_ref_current(codec,
+						&impedance_l, &impedance_r);
+	if (!mbhc->mbhc_cfg->mono_stero_detection) {
+		/* Set ZDET_CHG to 0  to discharge ramp */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+				0x02, 0x00);
+		/* wait for 40msec for the capacitor to discharge */
+		usleep_range(40000, 40100);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+				0x03, 0x00);
+		goto exit;
+	}
+
+	/* we are setting ref current to the minimun range or the measured
+	 * value larger than the minimum value, so min_range_used is true.
+	 * If the headset is mono headset with either HPHL or HPHR floating
+	 * then we have already done the mono stereo detection and do not
+	 * need to continue further.
+	 */
+
+	if (!min_range_used ||
+	    sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHL ||
+	    sdm660_cdc->imped_det_pin == WCD_MBHC_DET_HPHR)
+		goto exit;
+
+
+	/* Disable Set ZDET_CONN_RAMP_L and enable ZDET_CONN_FIXED_L */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x02, 0x00);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
+			0x02, 0x02);
+	/* Set ZDET_CHG to 0  */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x00);
+	/* wait for 40msec for the capacitor to discharge */
+	usleep_range(40000, 40100);
+
+	/* Set ZDET_CONN_RAMP_R to 0  */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x01, 0x00);
+	/* Enable ZDET_L_MEAS_EN */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x08, 0x08);
+	/* wait for 2msec for the HW to compute left inpedance value */
+	usleep_range(2000, 2100);
+	/* Read Left impedance value from Result1 */
+	impedance_l_fixed = snd_soc_read(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT);
+	/* Disable ZDET_L_MEAS_EN */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x08, 0x00);
+	/*
+	 * Assume impedance_l is L1, impedance_l_fixed is L2.
+	 * If the following condition is met, we can take this
+	 * headset as mono one with impedance of L2.
+	 * Otherwise, take it as stereo with impedance of L1.
+	 * Condition:
+	 * abs[(L2-0.5L1)/(L2+0.5L1)] < abs [(L2-L1)/(L2+L1)]
+	 */
+	if ((abs(impedance_l_fixed - impedance_l/2) *
+		(impedance_l_fixed + impedance_l)) >=
+		(abs(impedance_l_fixed - impedance_l) *
+		(impedance_l_fixed + impedance_l/2))) {
+		dev_dbg(codec->dev,
+			"%s: STEREO plug type detected\n",
+			 __func__);
+		mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+	} else {
+		dev_dbg(codec->dev,
+			"%s: MONO plug type detected\n",
+			__func__);
+		mbhc->hph_type = WCD_MBHC_HPH_MONO;
+		impedance_l = impedance_l_fixed;
+	}
+	/* Enable ZDET_CHG  */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x02);
+	/* wait for 10msec for the capacitor to charge */
+	usleep_range(10000, 10100);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x02, 0x02);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL,
+			0x02, 0x00);
+	/* Set ZDET_CHG to 0  to discharge HPHL */
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL,
+			0x02, 0x00);
+	/* wait for 40msec for the capacitor to discharge */
+	usleep_range(40000, 40100);
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL,
+			0x02, 0x00);
+
+exit:
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, reg4);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN, reg3);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, reg1);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, reg0);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, reg2);
+	msm_anlg_cdc_compute_impedance(codec, impedance_l, impedance_r,
+				      zl, zr, high);
+
+	dev_dbg(codec->dev, "%s: RL %d ohm, RR %d ohm\n", __func__, *zl, *zr);
+	dev_dbg(codec->dev, "%s: Impedance detection completed\n", __func__);
+}
+
+static int msm_anlg_cdc_dig_register_notifier(void *handle,
+					      struct notifier_block *nblock,
+					      bool enable)
+{
+	struct sdm660_cdc_priv *handle_cdc = handle;
+
+	if (enable)
+		return blocking_notifier_chain_register(&handle_cdc->notifier,
+							nblock);
+
+	return blocking_notifier_chain_unregister(&handle_cdc->notifier,
+						  nblock);
+}
+
+static int msm_anlg_cdc_mbhc_register_notifier(struct wcd_mbhc *wcd_mbhc,
+					       struct notifier_block *nblock,
+					       bool enable)
+{
+	struct snd_soc_codec *codec = wcd_mbhc->codec;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (enable)
+		return blocking_notifier_chain_register(
+						&sdm660_cdc->notifier_mbhc,
+						nblock);
+
+	return blocking_notifier_chain_unregister(&sdm660_cdc->notifier_mbhc,
+						  nblock);
+}
+
+static int msm_anlg_cdc_request_irq(struct snd_soc_codec *codec,
+				    int irq, irq_handler_t handler,
+				    const char *name, void *data)
+{
+	return wcd9xxx_spmi_request_irq(irq, handler, name, data);
+}
+
+static int msm_anlg_cdc_free_irq(struct snd_soc_codec *codec,
+				 int irq, void *data)
+{
+	return wcd9xxx_spmi_free_irq(irq, data);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+	.enable_mb_source = msm_anlg_cdc_enable_ext_mb_source,
+	.trim_btn_reg = msm_anlg_cdc_trim_btn_reg,
+	.compute_impedance = msm_anlg_cdc_mbhc_calc_impedance,
+	.set_micbias_value = msm_anlg_cdc_set_micb_v,
+	.set_auto_zeroing = msm_anlg_cdc_set_auto_zeroing,
+	.get_hwdep_fw_cal = msm_anlg_cdc_get_hwdep_fw_cal,
+	.set_cap_mode = msm_anlg_cdc_configure_cap,
+	.register_notifier = msm_anlg_cdc_mbhc_register_notifier,
+	.request_irq = msm_anlg_cdc_request_irq,
+	.irq_control = wcd9xxx_spmi_irq_control,
+	.free_irq = msm_anlg_cdc_free_irq,
+	.clk_setup = msm_anlg_cdc_mbhc_clk_setup,
+	.map_btn_code_to_num = msm_anlg_cdc_mbhc_map_btn_code_to_num,
+	.lock_sleep = msm_anlg_cdc_spmi_lock_sleep,
+	.micbias_enable_status = msm_anlg_cdc_micb_en_status,
+	.mbhc_bias = msm_anlg_cdc_enable_master_bias,
+	.mbhc_common_micb_ctrl = msm_anlg_cdc_mbhc_common_micb_ctrl,
+	.micb_internal = msm_anlg_cdc_mbhc_internal_micbias_ctrl,
+	.hph_pa_on_status = msm_anlg_cdc_mbhc_hph_pa_on_status,
+	.set_btn_thr = msm_anlg_cdc_mbhc_program_btn_thr,
+	.extn_use_mb = msm_anlg_cdc_use_mb,
+};
+
+static const uint32_t wcd_imped_val[] = {4, 8, 12, 13, 16,
+					20, 24, 28, 32,
+					36, 40, 44, 48};
+
+static void msm_anlg_cdc_dig_notifier_call(struct snd_soc_codec *codec,
+					const enum dig_cdc_notify_event event)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: notifier call event %d\n", __func__, event);
+	blocking_notifier_call_chain(&sdm660_cdc->notifier,
+				     event, NULL);
+}
+
+static void msm_anlg_cdc_notifier_call(struct snd_soc_codec *codec,
+				       const enum wcd_notify_event event)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: notifier call event %d\n", __func__, event);
+	blocking_notifier_call_chain(&sdm660_cdc->notifier_mbhc, event,
+				     &sdm660_cdc->mbhc);
+}
+
+static void msm_anlg_cdc_boost_on(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F, 0x0F);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0)
+		snd_soc_write(codec, MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82);
+	else
+		snd_soc_write(codec, MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+			    0x69, 0x69);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG,
+			    0x01, 0x01);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO,
+			    0x88, 0x88);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+			    0x03, 0x03);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL,
+			    0xE1, 0xE1);
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x20, 0x20);
+		/* Wait for 1ms after clock ctl enable */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0xDF, 0xDF);
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+	} else {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x20, 0x20);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0x80, 0x80);
+		/* Wait for 500us after BOOST_EN to happen */
+		usleep_range(500, 510);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+				    0x40, 0x40);
+		/* Wait for 500us after BOOST pulse_skip */
+		usleep_range(500, 510);
+	}
+}
+
+static void msm_anlg_cdc_boost_off(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+			    0xDF, 0x5F);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    0x20, 0x00);
+}
+
+static void msm_anlg_cdc_bypass_on(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+		snd_soc_write(codec,
+			MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+			0xA5);
+		snd_soc_write(codec,
+			MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3,
+			0x07);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x40, 0x40);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+			0xDF, 0xDF);
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			0x20, 0x20);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x20, 0x20);
+	}
+}
+
+static void msm_anlg_cdc_bypass_off(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CAJON_2_0) {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BOOST_EN_CTL,
+			0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x02, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x40, 0x00);
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_BYPASS_MODE,
+			0x20, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			0x20, 0x00);
+	}
+}
+
+static void msm_anlg_cdc_boost_mode_sequence(struct snd_soc_codec *codec,
+					     int flag)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (flag == EAR_PMU) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->ear_pa_boost_set) {
+				msm_anlg_cdc_boost_off(codec);
+				msm_anlg_cdc_bypass_on(codec);
+			}
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		case BYPASS_ALWAYS:
+			msm_anlg_cdc_bypass_on(codec);
+			break;
+		case BOOST_ON_FOREVER:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	} else if (flag == EAR_PMD) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->ear_pa_boost_set)
+				msm_anlg_cdc_bypass_off(codec);
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_off(codec);
+			/* 80ms for EAR boost to settle down */
+			msleep(80);
+			break;
+		case BYPASS_ALWAYS:
+			/* nothing to do as bypass on always */
+			break;
+		case BOOST_ON_FOREVER:
+			/* nothing to do as boost on forever */
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	} else if (flag == SPK_PMU) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set) {
+				msm_anlg_cdc_bypass_off(codec);
+				msm_anlg_cdc_boost_on(codec);
+			}
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		case BYPASS_ALWAYS:
+			msm_anlg_cdc_bypass_on(codec);
+			break;
+		case BOOST_ON_FOREVER:
+			msm_anlg_cdc_boost_on(codec);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	} else if (flag == SPK_PMD) {
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set) {
+				msm_anlg_cdc_boost_off(codec);
+				/*
+				 * Add 40 ms sleep for the spk
+				 * boost to settle down
+				 */
+				msleep(40);
+			}
+			break;
+		case BOOST_ALWAYS:
+			msm_anlg_cdc_boost_off(codec);
+			/*
+			 * Add 40 ms sleep for the spk
+			 * boost to settle down
+			 */
+			msleep(40);
+			break;
+		case BYPASS_ALWAYS:
+			/* nothing to do as bypass on always */
+			break;
+		case BOOST_ON_FOREVER:
+			/* nothing to do as boost on forever */
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+	}
+}
+
+static int msm_anlg_cdc_dt_parse_vreg_info(struct device *dev,
+	struct sdm660_cdc_regulator *vreg, const char *vreg_name,
+	bool ondemand)
+{
+	int len, ret = 0;
+	const __be32 *prop;
+	char prop_name[CODEC_DT_MAX_PROP_SIZE];
+	struct device_node *regnode = NULL;
+	u32 prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
+		vreg_name);
+	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+	if (!regnode) {
+		dev_err(dev, "Looking up %s property in node %s failed\n",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+
+	dev_dbg(dev, "Looking up %s property in node %s\n",
+		prop_name, dev->of_node->full_name);
+
+	vreg->name = vreg_name;
+	vreg->ondemand = ondemand;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+		"qcom,%s-voltage", vreg_name);
+	prop = of_get_property(dev->of_node, prop_name, &len);
+
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_err(dev, "%s %s property\n",
+			prop ? "invalid format" : "no", prop_name);
+		return -EINVAL;
+	}
+	vreg->min_uv = be32_to_cpup(&prop[0]);
+	vreg->max_uv = be32_to_cpup(&prop[1]);
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+		"qcom,%s-current", vreg_name);
+
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -EFAULT;
+	}
+	vreg->optimum_ua = prop_val;
+
+	dev_dbg(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
+		 vreg->min_uv, vreg->max_uv, vreg->optimum_ua, vreg->ondemand);
+	return 0;
+}
+
+static void msm_anlg_cdc_dt_parse_boost_info(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+	const char *prop_name = "qcom,cdc-boost-voltage";
+	int boost_voltage, ret;
+
+	ret = of_property_read_u32(codec->dev->of_node, prop_name,
+			&boost_voltage);
+	if (ret) {
+		dev_dbg(codec->dev, "Looking up %s property in node %s failed\n",
+			prop_name, codec->dev->of_node->full_name);
+		boost_voltage = DEFAULT_BOOST_VOLTAGE;
+	}
+	if (boost_voltage < MIN_BOOST_VOLTAGE ||
+			boost_voltage > MAX_BOOST_VOLTAGE) {
+		dev_err(codec->dev,
+				"Incorrect boost voltage. Reverting to default\n");
+		boost_voltage = DEFAULT_BOOST_VOLTAGE;
+	}
+
+	sdm660_cdc_priv->boost_voltage =
+		VOLTAGE_CONVERTER(boost_voltage, MIN_BOOST_VOLTAGE,
+				BOOST_VOLTAGE_STEP);
+	dev_dbg(codec->dev, "Boost voltage value is: %d\n",
+			boost_voltage);
+}
+
+static void msm_anlg_cdc_dt_parse_micbias_info(struct device *dev,
+				struct wcd_micbias_setting *micbias)
+{
+	const char *prop_name = "qcom,cdc-micbias-cfilt-mv";
+	int ret;
+
+	ret = of_property_read_u32(dev->of_node, prop_name,
+			&micbias->cfilt1_mv);
+	if (ret) {
+		dev_dbg(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		micbias->cfilt1_mv = MICBIAS_DEFAULT_VAL;
+	}
+}
+
+static struct sdm660_cdc_pdata *msm_anlg_cdc_populate_dt_pdata(
+						struct device *dev)
+{
+	struct sdm660_cdc_pdata *pdata;
+	int ret, static_cnt, ond_cnt, idx, i;
+	const char *name = NULL;
+	const char *static_prop_name = "qcom,cdc-static-supplies";
+	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
+	if (static_cnt < 0) {
+		dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
+			static_cnt);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* On-demand supply list is an optional property */
+	ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+	if (ond_cnt < 0)
+		ond_cnt = 0;
+
+	WARN_ON(static_cnt <= 0 || ond_cnt < 0);
+	if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
+		dev_err(dev, "%s: Num of supplies %u > max supported %zd\n",
+				__func__, (static_cnt + ond_cnt),
+					ARRAY_SIZE(pdata->regulator));
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (idx = 0; idx < static_cnt; idx++) {
+		ret = of_property_read_string_index(dev->of_node,
+						    static_prop_name, idx,
+						    &name);
+		if (ret) {
+			dev_err(dev, "%s: of read string %s idx %d error %d\n",
+				__func__, static_prop_name, idx, ret);
+			goto err;
+		}
+
+		dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
+			name);
+		ret = msm_anlg_cdc_dt_parse_vreg_info(dev,
+						&pdata->regulator[idx],
+						name, false);
+		if (ret) {
+			dev_err(dev, "%s:err parsing vreg for %s idx %d\n",
+				__func__, name, idx);
+			goto err;
+		}
+	}
+
+	for (i = 0; i < ond_cnt; i++, idx++) {
+		ret = of_property_read_string_index(dev->of_node, ond_prop_name,
+						    i, &name);
+		if (ret) {
+			dev_err(dev, "%s: err parsing on_demand for %s idx %d\n",
+				__func__, ond_prop_name, i);
+			goto err;
+		}
+
+		dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
+			name);
+		ret = msm_anlg_cdc_dt_parse_vreg_info(dev,
+						&pdata->regulator[idx],
+						name, true);
+		if (ret) {
+			dev_err(dev, "%s: err parsing vreg on_demand for %s idx %d\n",
+				__func__, name, idx);
+			goto err;
+		}
+	}
+	msm_anlg_cdc_dt_parse_micbias_info(dev, &pdata->micbias);
+
+	return pdata;
+err:
+	devm_kfree(dev, pdata);
+	dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
+		__func__, ret);
+	return NULL;
+}
+
+static int msm_anlg_cdc_codec_enable_on_demand_supply(
+		struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	struct on_demand_supply *supply;
+
+	if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
+		dev_err(codec->dev, "%s: error index > MAX Demand supplies",
+			__func__);
+		ret = -EINVAL;
+		goto out;
+	}
+	dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
+		__func__, on_demand_supply_name[w->shift], event,
+		atomic_read(&sdm660_cdc->on_demand_list[w->shift].ref));
+
+	supply = &sdm660_cdc->on_demand_list[w->shift];
+	WARN_ONCE(!supply->supply, "%s isn't defined\n",
+		  on_demand_supply_name[w->shift]);
+	if (!supply->supply) {
+		dev_err(codec->dev, "%s: err supply not present ond for %d",
+			__func__, w->shift);
+		goto out;
+	}
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (atomic_inc_return(&supply->ref) == 1) {
+			ret = regulator_set_voltage(supply->supply,
+						    supply->min_uv,
+						    supply->max_uv);
+			if (ret) {
+				dev_err(codec->dev,
+					"Setting regulator voltage(en) for micbias with err = %d\n",
+					ret);
+				goto out;
+			}
+			ret = regulator_set_load(supply->supply,
+						 supply->optimum_ua);
+			if (ret < 0) {
+				dev_err(codec->dev,
+					"Setting regulator optimum mode(en) failed for micbias with err = %d\n",
+					ret);
+				goto out;
+			}
+			ret = regulator_enable(supply->supply);
+		}
+		if (ret)
+			dev_err(codec->dev, "%s: Failed to enable %s\n",
+				__func__,
+				on_demand_supply_name[w->shift]);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (atomic_read(&supply->ref) == 0) {
+			dev_dbg(codec->dev, "%s: %s supply has been disabled.\n",
+				 __func__, on_demand_supply_name[w->shift]);
+			goto out;
+		}
+		if (atomic_dec_return(&supply->ref) == 0) {
+			ret = regulator_disable(supply->supply);
+			if (ret)
+				dev_err(codec->dev, "%s: Failed to disable %s\n",
+					__func__,
+					on_demand_supply_name[w->shift]);
+			ret = regulator_set_voltage(supply->supply,
+						    0,
+						    supply->max_uv);
+			if (ret) {
+				dev_err(codec->dev,
+					"Setting regulator voltage(dis) failed for micbias with err = %d\n",
+					ret);
+				goto out;
+			}
+			ret = regulator_set_load(supply->supply, 0);
+			if (ret < 0)
+				dev_err(codec->dev,
+					"Setting regulator optimum mode(dis) failed for micbias with err = %d\n",
+					ret);
+		}
+		break;
+	default:
+		break;
+	}
+out:
+	return ret;
+}
+
+static int msm_anlg_cdc_codec_enable_clock_block(struct snd_soc_codec *codec,
+						 int enable)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	if (enable) {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
+		msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+						 struct snd_kcontrol *kcontrol,
+						 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+		if (!(strcmp(w->name, "EAR CP"))) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x80);
+			msm_anlg_cdc_boost_mode_sequence(codec, EAR_PMU);
+		} else if (get_codec_version(sdm660_cdc) >= DIANGU) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x80);
+		} else {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0xC0, 0xC0);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Wait for 1ms post powerup of chargepump */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Wait for 1ms post powerdown of chargepump */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		if (!(strcmp(w->name, "EAR CP"))) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x00);
+			if (sdm660_cdc->boost_option != BOOST_ALWAYS) {
+				dev_dbg(codec->dev,
+					"%s: boost_option:%d, tear down ear\n",
+					__func__, sdm660_cdc->boost_option);
+				msm_anlg_cdc_boost_mode_sequence(codec,
+								 EAR_PMD);
+			}
+			/*
+			 * Reset pa select bit from ear to hph after ear pa
+			 * is disabled and HPH DAC disable to reduce ear
+			 * turn off pop and avoid HPH pop in concurrency
+			 */
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x00);
+		} else {
+			if (get_codec_version(sdm660_cdc) < DIANGU)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x40, 0x00);
+			if (sdm660_cdc->rx_bias_count == 0)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x00);
+			dev_dbg(codec->dev, "%s: rx_bias_count = %d\n",
+					__func__, sdm660_cdc->rx_bias_count);
+		}
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_ear_pa_boost_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] =
+		(sdm660_cdc->ear_pa_boost_set ? 1 : 0);
+	dev_dbg(codec->dev, "%s: sdm660_cdc->ear_pa_boost_set = %d\n",
+			__func__, sdm660_cdc->ear_pa_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_ear_pa_boost_set(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+	sdm660_cdc->ear_pa_boost_set =
+		(ucontrol->value.integer.value[0] ? true : false);
+	return 0;
+}
+
+static int msm_anlg_cdc_loopback_mode_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	return pdata->lb_mode;
+}
+
+static int msm_anlg_cdc_loopback_mode_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		pdata->lb_mode = false;
+		break;
+	case 1:
+		pdata->lb_mode = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_anlg_cdc_pa_gain_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) >= DIANGU) {
+		ear_pa_gain = snd_soc_read(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC);
+		ear_pa_gain = (ear_pa_gain >> 1) & 0x3;
+
+		if (ear_pa_gain == 0x00) {
+			ucontrol->value.integer.value[0] = 3;
+		} else if (ear_pa_gain == 0x01) {
+			ucontrol->value.integer.value[1] = 2;
+		} else if (ear_pa_gain == 0x02) {
+			ucontrol->value.integer.value[2] = 1;
+		} else if (ear_pa_gain == 0x03) {
+			ucontrol->value.integer.value[3] = 0;
+		} else {
+			dev_err(codec->dev,
+				"%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+				__func__, ear_pa_gain);
+			return -EINVAL;
+		}
+	} else {
+		ear_pa_gain = snd_soc_read(codec,
+					   MSM89XX_PMIC_ANALOG_RX_EAR_CTL);
+		ear_pa_gain = (ear_pa_gain >> 5) & 0x1;
+		if (ear_pa_gain == 0x00) {
+			ucontrol->value.integer.value[0] = 0;
+		} else if (ear_pa_gain == 0x01) {
+			ucontrol->value.integer.value[0] = 3;
+		} else  {
+			dev_err(codec->dev,
+				"%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+				__func__, ear_pa_gain);
+			return -EINVAL;
+		}
+	}
+	ucontrol->value.integer.value[0] = ear_pa_gain;
+	dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+	return 0;
+}
+
+static int msm_anlg_cdc_pa_gain_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	if (get_codec_version(sdm660_cdc) >= DIANGU) {
+		switch (ucontrol->value.integer.value[0]) {
+		case 0:
+			ear_pa_gain = 0x06;
+			break;
+		case 1:
+			ear_pa_gain = 0x04;
+			break;
+		case 2:
+			ear_pa_gain = 0x02;
+			break;
+		case 3:
+			ear_pa_gain = 0x00;
+			break;
+		default:
+			return -EINVAL;
+		}
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+			    0x06, ear_pa_gain);
+	} else {
+		switch (ucontrol->value.integer.value[0]) {
+		case 0:
+			ear_pa_gain = 0x00;
+			break;
+		case 3:
+			ear_pa_gain = 0x20;
+			break;
+		case 1:
+		case 2:
+		default:
+			return -EINVAL;
+		}
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x20, ear_pa_gain);
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_hph_mode_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->hph_mode == NORMAL_MODE) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (sdm660_cdc->hph_mode == HD2_MODE) {
+		ucontrol->value.integer.value[0] = 1;
+	} else  {
+		dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n",
+			__func__, sdm660_cdc->hph_mode);
+	}
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->hph_mode = %d\n", __func__,
+			sdm660_cdc->hph_mode);
+	return 0;
+}
+
+static int msm_anlg_cdc_hph_mode_set(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->hph_mode = NORMAL_MODE;
+		break;
+	case 1:
+		if (get_codec_version(sdm660_cdc) >= DIANGU)
+			sdm660_cdc->hph_mode = HD2_MODE;
+		break;
+	default:
+		sdm660_cdc->hph_mode = NORMAL_MODE;
+		break;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->hph_mode_set = %d\n",
+		__func__, sdm660_cdc->hph_mode);
+	return 0;
+}
+
+static int msm_anlg_cdc_boost_option_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->boost_option == BOOST_SWITCH) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (sdm660_cdc->boost_option == BOOST_ALWAYS) {
+		ucontrol->value.integer.value[0] = 1;
+	} else if (sdm660_cdc->boost_option == BYPASS_ALWAYS) {
+		ucontrol->value.integer.value[0] = 2;
+	} else if (sdm660_cdc->boost_option == BOOST_ON_FOREVER) {
+		ucontrol->value.integer.value[0] = 3;
+	} else  {
+		dev_err(codec->dev, "%s: ERROR: Unsupported Boost option= %d\n",
+			__func__, sdm660_cdc->boost_option);
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->boost_option = %d\n", __func__,
+			sdm660_cdc->boost_option);
+	return 0;
+}
+
+static int msm_anlg_cdc_boost_option_set(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->boost_option = BOOST_SWITCH;
+		break;
+	case 1:
+		sdm660_cdc->boost_option = BOOST_ALWAYS;
+		break;
+	case 2:
+		sdm660_cdc->boost_option = BYPASS_ALWAYS;
+		msm_anlg_cdc_bypass_on(codec);
+		break;
+	case 3:
+		sdm660_cdc->boost_option = BOOST_ON_FOREVER;
+		msm_anlg_cdc_boost_on(codec);
+		break;
+	default:
+		pr_err("%s: invalid boost option: %d\n", __func__,
+					sdm660_cdc->boost_option);
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->boost_option_set = %d\n",
+		__func__, sdm660_cdc->boost_option);
+	return 0;
+}
+
+static int msm_anlg_cdc_spk_boost_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->spk_boost_set == false) {
+		ucontrol->value.integer.value[0] = 0;
+	} else if (sdm660_cdc->spk_boost_set == true) {
+		ucontrol->value.integer.value[0] = 1;
+	} else  {
+		dev_err(codec->dev, "%s: ERROR: Unsupported Speaker Boost = %d\n",
+				__func__, sdm660_cdc->spk_boost_set);
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n", __func__,
+			sdm660_cdc->spk_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_spk_boost_set(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+			__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->spk_boost_set = false;
+		break;
+	case 1:
+		sdm660_cdc->spk_boost_set = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n",
+		__func__, sdm660_cdc->spk_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_ext_spk_boost_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (sdm660_cdc->ext_spk_boost_set == false)
+		ucontrol->value.integer.value[0] = 0;
+	else
+		ucontrol->value.integer.value[0] = 1;
+
+	dev_dbg(codec->dev, "%s: sdm660_cdc->ext_spk_boost_set = %d\n",
+				__func__, sdm660_cdc->ext_spk_boost_set);
+	return 0;
+}
+
+static int msm_anlg_cdc_ext_spk_boost_set(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		sdm660_cdc->ext_spk_boost_set = false;
+		break;
+	case 1:
+		sdm660_cdc->ext_spk_boost_set = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: sdm660_cdc->spk_boost_set = %d\n",
+		__func__, sdm660_cdc->spk_boost_set);
+	return 0;
+}
+
+
+static const char * const msm_anlg_cdc_loopback_mode_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_loopback_mode_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_loopback_mode_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ear_pa_boost_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_ear_pa_boost_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_ear_pa_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ear_pa_gain_text[] = {
+		"POS_1P5_DB", "POS_3_DB", "POS_4P5_DB", "POS_6_DB"};
+static const struct soc_enum msm_anlg_cdc_ear_pa_gain_enum[] = {
+		SOC_ENUM_SINGLE_EXT(4, msm_anlg_cdc_ear_pa_gain_text),
+};
+
+static const char * const msm_anlg_cdc_boost_option_ctrl_text[] = {
+		"BOOST_SWITCH", "BOOST_ALWAYS", "BYPASS_ALWAYS",
+		"BOOST_ON_FOREVER"};
+static const struct soc_enum msm_anlg_cdc_boost_option_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(4, msm_anlg_cdc_boost_option_ctrl_text),
+};
+static const char * const msm_anlg_cdc_spk_boost_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_spk_boost_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_spk_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_ext_spk_boost_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum msm_anlg_cdc_ext_spk_boost_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, msm_anlg_cdc_ext_spk_boost_ctrl_text),
+};
+
+static const char * const msm_anlg_cdc_hph_mode_ctrl_text[] = {
+		"NORMAL", "HD2"};
+static const struct soc_enum msm_anlg_cdc_hph_mode_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_anlg_cdc_hph_mode_ctrl_text),
+			msm_anlg_cdc_hph_mode_ctrl_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+
+static const struct snd_kcontrol_new msm_anlg_cdc_snd_controls[] = {
+
+	SOC_ENUM_EXT("RX HPH Mode", msm_anlg_cdc_hph_mode_ctl_enum[0],
+		msm_anlg_cdc_hph_mode_get, msm_anlg_cdc_hph_mode_set),
+
+	SOC_ENUM_EXT("Boost Option", msm_anlg_cdc_boost_option_ctl_enum[0],
+		msm_anlg_cdc_boost_option_get, msm_anlg_cdc_boost_option_set),
+
+	SOC_ENUM_EXT("EAR PA Boost", msm_anlg_cdc_ear_pa_boost_ctl_enum[0],
+		msm_anlg_cdc_ear_pa_boost_get, msm_anlg_cdc_ear_pa_boost_set),
+
+	SOC_ENUM_EXT("EAR PA Gain", msm_anlg_cdc_ear_pa_gain_enum[0],
+		msm_anlg_cdc_pa_gain_get, msm_anlg_cdc_pa_gain_put),
+
+	SOC_ENUM_EXT("Speaker Boost", msm_anlg_cdc_spk_boost_ctl_enum[0],
+		msm_anlg_cdc_spk_boost_get, msm_anlg_cdc_spk_boost_set),
+
+	SOC_ENUM_EXT("Ext Spk Boost", msm_anlg_cdc_ext_spk_boost_ctl_enum[0],
+		msm_anlg_cdc_ext_spk_boost_get, msm_anlg_cdc_ext_spk_boost_set),
+
+	SOC_ENUM_EXT("LOOPBACK Mode", msm_anlg_cdc_loopback_mode_ctl_enum[0],
+		msm_anlg_cdc_loopback_mode_get, msm_anlg_cdc_loopback_mode_put),
+	SOC_SINGLE_TLV("ADC1 Volume", MSM89XX_PMIC_ANALOG_TX_1_EN, 3,
+					8, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", MSM89XX_PMIC_ANALOG_TX_2_EN, 3,
+					8, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", MSM89XX_PMIC_ANALOG_TX_3_EN, 3,
+					8, 0, analog_gain),
+
+
+};
+
+static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	uint32_t zl, zr;
+	bool hphr;
+	struct soc_multi_mixer_control *mc;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+
+	hphr = mc->shift;
+	ret = wcd_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
+	if (ret)
+		dev_dbg(codec->dev, "%s: Failed to get mbhc imped", __func__);
+	dev_dbg(codec->dev, "%s: zl %u, zr %u\n", __func__, zl, zr);
+	ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+			tombak_hph_impedance_get, NULL),
+	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+			tombak_hph_impedance_get, NULL),
+};
+
+static int tombak_get_hph_type(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct sdm660_cdc_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wcd_mbhc *mbhc;
+
+	if (!priv) {
+		dev_err(codec->dev,
+			"%s: sdm660_cdc-wcd private data is NULL\n",
+			 __func__);
+		return -EINVAL;
+	}
+
+	mbhc = &priv->mbhc;
+	if (!mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
+	dev_dbg(codec->dev, "%s: hph_type = %u\n", __func__, mbhc->hph_type);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+	SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+	tombak_get_hph_type, NULL),
+};
+
+static const char * const rdac2_mux_text[] = {
+	"ZERO", "RX2", "RX1"
+};
+
+static const struct snd_kcontrol_new adc1_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct soc_enum rdac2_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL,
+		0, 3, rdac2_mux_text);
+
+static const char * const adc2_mux_text[] = {
+	"ZERO", "INP2", "INP3"
+};
+
+static const char * const ext_spk_text[] = {
+	"Off", "On"
+};
+
+static const char * const wsa_spk_text[] = {
+	"ZERO", "WSA"
+};
+
+static const struct soc_enum adc2_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+		ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct soc_enum ext_spk_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+		ARRAY_SIZE(ext_spk_text), ext_spk_text);
+
+static const struct soc_enum wsa_spk_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+		ARRAY_SIZE(wsa_spk_text), wsa_spk_text);
+
+
+
+static const struct snd_kcontrol_new ext_spk_mux =
+	SOC_DAPM_ENUM("Ext Spk Switch Mux", ext_spk_enum);
+
+
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+	SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+
+static const struct snd_kcontrol_new rdac2_mux =
+	SOC_DAPM_ENUM("RDAC2 MUX Mux", rdac2_mux_enum);
+
+static const char * const ear_text[] = {
+	"ZERO", "Switch",
+};
+
+static const struct soc_enum ear_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ear_text), ear_text);
+
+static const struct snd_kcontrol_new ear_pa_mux[] = {
+	SOC_DAPM_ENUM("EAR_S", ear_enum)
+};
+
+static const struct snd_kcontrol_new wsa_spk_mux[] = {
+	SOC_DAPM_ENUM("WSA Spk Switch", wsa_spk_enum)
+};
+
+
+
+static const char * const hph_text[] = {
+	"ZERO", "Switch",
+};
+
+static const struct soc_enum hph_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new hphl_mux[] = {
+	SOC_DAPM_ENUM("HPHL", hph_enum)
+};
+
+static const struct snd_kcontrol_new hphr_mux[] = {
+	SOC_DAPM_ENUM("HPHR", hph_enum)
+};
+
+static const struct snd_kcontrol_new spkr_mux[] = {
+	SOC_DAPM_ENUM("SPK", hph_enum)
+};
+
+static const char * const lo_text[] = {
+	"ZERO", "Switch",
+};
+
+static const struct soc_enum lo_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new lo_mux[] = {
+	SOC_DAPM_ENUM("LINE_OUT", lo_enum)
+};
+
+static void msm_anlg_cdc_codec_enable_adc_block(struct snd_soc_codec *codec,
+					 int enable)
+{
+	struct sdm660_cdc_priv *wcd8x16 = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, enable);
+
+	if (enable) {
+		wcd8x16->adc_count++;
+		snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x20, 0x20);
+		snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x10, 0x10);
+	} else {
+		wcd8x16->adc_count--;
+		if (!wcd8x16->adc_count) {
+			snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x10, 0x00);
+			snd_soc_update_bits(codec,
+				    MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+					    0x20, 0x0);
+		}
+	}
+}
+
+static int msm_anlg_cdc_codec_enable_adc(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 adc_reg;
+	u8 init_bit_shift;
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	adc_reg = MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2;
+
+	if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+		init_bit_shift = 5;
+	else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+		 (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+		init_bit_shift = 4;
+	else {
+		dev_err(codec->dev, "%s: Error, invalid adc register\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		msm_anlg_cdc_codec_enable_adc_block(codec, 1);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x02);
+		/*
+		 * Add delay of 10 ms to give sufficient time for the voltage
+		 * to shoot up and settle so that the txfe init does not
+		 * happen when the input voltage is changing too much.
+		 */
+		usleep_range(10000, 10010);
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+				1 << init_bit_shift);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
+				0x03, 0x00);
+		else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+			(w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
+				0x03, 0x00);
+		/* Wait for 1ms to allow txfe settling time */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * Add delay of 12 ms before deasserting the init
+		 * to reduce the tx pop
+		 */
+		usleep_range(12000, 12010);
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+		/* Wait for 1ms to allow txfe settling time post powerup */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		msm_anlg_cdc_codec_enable_adc_block(codec, 0);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x00);
+		if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL,
+				0x03, 0x02);
+		else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) ||
+			(w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL,
+				0x03, 0x02);
+
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x01);
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (!sdm660_cdc->spk_boost_set)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+					0x10, 0x10);
+			break;
+		case BOOST_ALWAYS:
+		case BOOST_ON_FOREVER:
+			break;
+		case BYPASS_ALWAYS:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+				0x10, 0x10);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+		/* Wait for 1ms after SPK_DAC CTL setting */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0xE0);
+		if (get_codec_version(sdm660_cdc) != TOMBAK_1_0)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x01);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Wait for 1ms after SPK_VBAT_LDO Enable */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+					0xEF, 0xEF);
+			else
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+					0x10, 0x00);
+			break;
+		case BOOST_ALWAYS:
+		case BOOST_ON_FOREVER:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+				0xEF, 0xEF);
+			break;
+		case BYPASS_ALWAYS:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+		msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX3_MUTE_OFF);
+		snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX3_MUTE_ON);
+		/*
+		 * Add 1 ms sleep for the mute to take effect
+		 */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x10);
+		if (get_codec_version(sdm660_cdc) < CAJON_2_0)
+			msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMD);
+		snd_soc_update_bits(codec, w->reg, 0x80, 0x00);
+		switch (sdm660_cdc->boost_option) {
+		case BOOST_SWITCH:
+			if (sdm660_cdc->spk_boost_set)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+					0xEF, 0x69);
+			break;
+		case BOOST_ALWAYS:
+		case BOOST_ON_FOREVER:
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+				0xEF, 0x69);
+			break;
+		case BYPASS_ALWAYS:
+			break;
+		default:
+			dev_err(codec->dev,
+				"%s: invalid boost option: %d\n", __func__,
+				sdm660_cdc->boost_option);
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0x00);
+		/* Wait for 1ms to allow setting time for spkr path disable */
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
+		if (get_codec_version(sdm660_cdc) != TOMBAK_1_0)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+		if (get_codec_version(sdm660_cdc) >= CAJON_2_0)
+			msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMD);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+	dev_dbg(codec->dev, "%s event %d w->name %s\n", __func__,
+			event, w->name);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+		snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
+		msm_anlg_cdc_boost_mode_sequence(codec, SPK_PMU);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (sdm660_cdc->rx_bias_count == 0)
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+					0x80, 0x00);
+	}
+	return 0;
+}
+
+
+
+static bool msm_anlg_cdc_use_mb(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CAJON)
+		return true;
+	else
+		return false;
+}
+
+static void msm_anlg_cdc_set_auto_zeroing(struct snd_soc_codec *codec,
+					  bool enable)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) < CONGA) {
+		if (enable)
+			/*
+			 * Set autozeroing for special headset detection and
+			 * buttons to work.
+			 */
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_2_EN,
+				0x18, 0x10);
+		else
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_2_EN,
+				0x18, 0x00);
+
+	} else {
+		dev_dbg(codec->dev,
+			"%s: Auto Zeroing is not required from CONGA\n",
+			__func__);
+	}
+}
+
+static void msm_anlg_cdc_trim_btn_reg(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	if (get_codec_version(sdm660_cdc) == TOMBAK_1_0) {
+		pr_debug("%s: This device needs to be trimmed\n", __func__);
+		/*
+		 * Calculate the trim value for each device used
+		 * till is comes in production by hardware team
+		 */
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+				0xA5, 0xA5);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_TRIM_CTRL2,
+				0xFF, 0x30);
+	} else {
+		dev_dbg(codec->dev, "%s: This device is trimmed at ATE\n",
+			__func__);
+	}
+}
+
+static int msm_anlg_cdc_enable_ext_mb_source(struct wcd_mbhc *wcd_mbhc,
+					     bool turn_on)
+{
+	int ret = 0;
+	static int count;
+	struct snd_soc_codec *codec = wcd_mbhc->codec;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	dev_dbg(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
+			count);
+	if (turn_on) {
+		if (!count) {
+			ret = snd_soc_dapm_force_enable_pin(dapm,
+				"MICBIAS_REGULATOR");
+			snd_soc_dapm_sync(dapm);
+		}
+		count++;
+	} else {
+		if (count > 0)
+			count--;
+		if (!count) {
+			ret = snd_soc_dapm_disable_pin(dapm,
+				"MICBIAS_REGULATOR");
+			snd_soc_dapm_sync(dapm);
+		}
+	}
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			 __func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static int msm_anlg_cdc_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+				snd_soc_codec_get_drvdata(codec);
+	u16 micb_int_reg;
+	char *internal1_text = "Internal1";
+	char *internal2_text = "Internal2";
+	char *internal3_text = "Internal3";
+	char *external2_text = "External2";
+	char *external_text = "External";
+	bool micbias2;
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+	switch (w->reg) {
+	case MSM89XX_PMIC_ANALOG_MICB_1_EN:
+	case MSM89XX_PMIC_ANALOG_MICB_2_EN:
+		micb_int_reg = MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS;
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: Error, invalid micbias register 0x%x\n",
+			__func__, w->reg);
+		return -EINVAL;
+	}
+
+	micbias2 = (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_MICB_2_EN) & 0x80);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (strnstr(w->name, internal1_text, strlen(w->name))) {
+			if (get_codec_version(sdm660_cdc) >= CAJON)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
+					0x02, 0x02);
+			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
+		} else if (strnstr(w->name, internal2_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
+			snd_soc_update_bits(codec, w->reg, 0x60, 0x00);
+		} else if (strnstr(w->name, internal3_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+		/*
+		 * update MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2
+		 * for external bias only, not for external2.
+		*/
+		} else if (!strnstr(w->name, external2_text, strlen(w->name)) &&
+					strnstr(w->name, external_text,
+						strlen(w->name))) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2,
+					0x02, 0x02);
+		}
+		if (!strnstr(w->name, external_text, strlen(w->name)))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x05, 0x04);
+		if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
+			msm_anlg_cdc_configure_cap(codec, true, micbias2);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (get_codec_version(sdm660_cdc) <= TOMBAK_2_0)
+			/*
+			 * Wait for 20ms post micbias enable
+			 * for version < tombak 2.0.
+			 */
+			usleep_range(20000, 20100);
+		if (strnstr(w->name, internal1_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x40, 0x40);
+		} else if (strnstr(w->name, internal2_text,  strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x08, 0x08);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_ON);
+		} else if (strnstr(w->name, internal3_text, 30)) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x01, 0x01);
+		} else if (strnstr(w->name, external2_text, strlen(w->name))) {
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_ON);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (strnstr(w->name, internal1_text, strlen(w->name))) {
+			snd_soc_update_bits(codec, micb_int_reg, 0xC0, 0x40);
+		} else if (strnstr(w->name, internal2_text, strlen(w->name))) {
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_OFF);
+		} else if (strnstr(w->name, internal3_text, 30)) {
+			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
+		} else if (strnstr(w->name, external2_text, strlen(w->name))) {
+			/*
+			 * send micbias turn off event to mbhc driver and then
+			 * break, as no need to set MICB_1_EN register.
+			 */
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_MICBIAS_2_OFF);
+			break;
+		}
+		if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN)
+			msm_anlg_cdc_configure_cap(codec, false, micbias2);
+		break;
+	}
+	return 0;
+}
+
+static void update_clkdiv(void *handle, int val)
+{
+	struct sdm660_cdc_priv *handle_cdc = handle;
+	struct snd_soc_codec *codec = handle_cdc->codec;
+
+	snd_soc_update_bits(codec,
+			    MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV,
+			    0xFF, val);
+}
+
+static int get_cdc_version(void *handle)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = handle;
+
+	return get_codec_version(sdm660_cdc);
+}
+
+static int sdm660_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
+					       struct snd_kcontrol *kcontrol,
+					       int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	if (!sdm660_cdc->ext_spk_boost_set) {
+		dev_dbg(codec->dev, "%s: ext_boost not supported/disabled\n",
+								__func__);
+		return 0;
+	}
+	dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (sdm660_cdc->spkdrv_reg) {
+			ret = regulator_enable(sdm660_cdc->spkdrv_reg);
+			if (ret)
+				dev_err(codec->dev,
+					"%s Failed to enable spkdrv reg %s\n",
+					__func__, MSM89XX_VDD_SPKDRV_NAME);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (sdm660_cdc->spkdrv_reg) {
+			ret = regulator_disable(sdm660_cdc->spkdrv_reg);
+			if (ret)
+				dev_err(codec->dev,
+					"%s: Failed to disable spkdrv_reg %s\n",
+					__func__, MSM89XX_VDD_SPKDRV_NAME);
+		}
+		break;
+	}
+	return 0;
+}
+
+
+/* The register address is the same as other codec so it can use resmgr */
+static int msm_anlg_cdc_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		sdm660_cdc->rx_bias_count++;
+		if (sdm660_cdc->rx_bias_count == 1) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x80, 0x80);
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x01, 0x01);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		sdm660_cdc->rx_bias_count--;
+		if (sdm660_cdc->rx_bias_count == 0) {
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x01, 0x00);
+			snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+					0x80, 0x00);
+		}
+		break;
+	}
+	dev_dbg(codec->dev, "%s rx_bias_count = %d\n",
+			__func__, sdm660_cdc->rx_bias_count);
+	return 0;
+}
+
+static uint32_t wcd_get_impedance_value(uint32_t imped)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wcd_imped_val) - 1; i++) {
+		if (imped >= wcd_imped_val[i] &&
+			imped < wcd_imped_val[i + 1])
+			break;
+	}
+
+	pr_debug("%s: selected impedance value = %d\n",
+		 __func__, wcd_imped_val[i]);
+	return wcd_imped_val[i];
+}
+
+static void wcd_imped_config(struct snd_soc_codec *codec,
+			     uint32_t imped, bool set_gain)
+{
+	uint32_t value;
+	int codec_version;
+	struct sdm660_cdc_priv *sdm660_cdc =
+				snd_soc_codec_get_drvdata(codec);
+
+	value = wcd_get_impedance_value(imped);
+
+	if (value < wcd_imped_val[0]) {
+		dev_dbg(codec->dev,
+			"%s, detected impedance is less than 4 Ohm\n",
+			 __func__);
+		return;
+	}
+
+	codec_version = get_codec_version(sdm660_cdc);
+
+	if (set_gain) {
+		switch (codec_version) {
+		case TOMBAK_1_0:
+		case TOMBAK_2_0:
+		case CONGA:
+			/*
+			 * For 32Ohm load and higher loads, Set 0x19E
+			 * bit 5 to 1 (POS_0_DB_DI). For loads lower
+			 * than 32Ohm (such as 16Ohm load), Set 0x19E
+			 * bit 5 to 0 (POS_M4P5_DB_DI)
+			 */
+			if (value >= 32)
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x20);
+			else
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x00);
+			break;
+		case CAJON:
+		case CAJON_2_0:
+		case DIANGU:
+		case DRAX_CDC:
+			if (value >= 13) {
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x20);
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+					0x07, 0x07);
+			} else {
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+					0x20, 0x00);
+				snd_soc_update_bits(codec,
+					MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+					0x07, 0x04);
+			}
+			break;
+		}
+	} else {
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			0x20, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_NCP_VCTRL,
+			0x07, 0x04);
+	}
+
+	dev_dbg(codec->dev, "%s: Exit\n", __func__);
+}
+
+static int msm_anlg_cdc_hphl_dac_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol,
+				       int event)
+{
+	uint32_t impedl, impedr;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+	ret = wcd_mbhc_get_impedance(&sdm660_cdc->mbhc,
+			&impedl, &impedr);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (get_codec_version(sdm660_cdc) > CAJON)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+				0x08, 0x08);
+		if (get_codec_version(sdm660_cdc) == CAJON ||
+			get_codec_version(sdm660_cdc) == CAJON_2_0) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST,
+				0x80, 0x80);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST,
+				0x80, 0x80);
+		}
+		if (get_codec_version(sdm660_cdc) > CAJON)
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+				0x08, 0x00);
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_PRE_RX1_INT_ON);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02);
+		if (!ret)
+			wcd_imped_config(codec, impedl, true);
+		else
+			dev_dbg(codec->dev, "Failed to get mbhc impedance %d\n",
+				ret);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_imped_config(codec, impedl, false);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_POST_RX1_INT_OFF);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_lo_dac_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x20);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x80);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x40);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Wait for 20ms before powerdown of lineout_dac */
+		usleep_range(20000, 20100);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_hphr_dac_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol,
+				       int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_PRE_RX2_INT_ON);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00);
+		if (sdm660_cdc->hph_mode == HD2_MODE)
+			msm_anlg_cdc_dig_notifier_call(codec,
+					DIG_CDC_EVENT_POST_RX2_INT_OFF);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_hph_pa_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (w->shift == 5)
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHL_PA_ON);
+		else if (w->shift == 4)
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHR_PA_ON);
+		snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x20, 0x20);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		/* Wait for 7ms to allow setting time for HPH_PA Enable */
+		usleep_range(7000, 7100);
+		if (w->shift == 5) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX1_MUTE_OFF);
+		} else if (w->shift == 4) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX2_MUTE_OFF);
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		if (w->shift == 5) {
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX1_MUTE_ON);
+			/* Wait for 20ms after HPHL RX digital mute */
+			msleep(20);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x00);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHL_PA_OFF);
+		} else if (w->shift == 4) {
+			msm_anlg_cdc_dig_notifier_call(codec,
+					       DIG_CDC_EVENT_RX2_MUTE_ON);
+			/* Wait for 20ms after HPHR RX digital mute */
+			msleep(20);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x00);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_PRE_HPHR_PA_OFF);
+		}
+		if (get_codec_version(sdm660_cdc) >= CAJON) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP,
+				0xF0, 0x30);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (w->shift == 5) {
+			clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK,
+				&sdm660_cdc->mbhc.hph_pa_dac_state);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_HPHL_PA_OFF);
+		} else if (w->shift == 4) {
+			clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK,
+				&sdm660_cdc->mbhc.hph_pa_dac_state);
+			msm_anlg_cdc_notifier_call(codec,
+					WCD_EVENT_POST_HPHR_PA_OFF);
+		}
+		/* Wait for 15ms after HPH RX teardown */
+		usleep_range(15000, 15100);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* RDAC Connections */
+	{"HPHR DAC", NULL, "RDAC2 MUX"},
+	{"RDAC2 MUX", "RX1", "PDM_IN_RX1"},
+	{"RDAC2 MUX", "RX2", "PDM_IN_RX2"},
+
+	/* WSA */
+	{"WSA_SPK OUT", NULL, "WSA Spk Switch"},
+	{"WSA Spk Switch", "WSA", "EAR PA"},
+
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR_S"},
+	{"EAR_S", "Switch", "EAR PA"},
+	{"EAR PA", NULL, "RX_BIAS"},
+	{"EAR PA", NULL, "HPHL DAC"},
+	{"EAR PA", NULL, "HPHR DAC"},
+	{"EAR PA", NULL, "EAR CP"},
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL PA"},
+	{"HEADPHONE", NULL, "HPHR PA"},
+
+	{"Ext Spk", NULL, "Ext Spk Switch"},
+	{"Ext Spk Switch", "On", "HPHL PA"},
+	{"Ext Spk Switch", "On", "HPHR PA"},
+
+	{"HPHL PA", NULL, "HPHL"},
+	{"HPHR PA", NULL, "HPHR"},
+	{"HPHL", "Switch", "HPHL DAC"},
+	{"HPHR", "Switch", "HPHR DAC"},
+	{"HPHL PA", NULL, "CP"},
+	{"HPHL PA", NULL, "RX_BIAS"},
+	{"HPHR PA", NULL, "CP"},
+	{"HPHR PA", NULL, "RX_BIAS"},
+	{"HPHL DAC", NULL, "PDM_IN_RX1"},
+
+	{"SPK_OUT", NULL, "SPK PA"},
+	{"SPK PA", NULL, "SPK_RX_BIAS"},
+	{"SPK PA", NULL, "SPK"},
+	{"SPK", "Switch", "SPK DAC"},
+	{"SPK DAC", NULL, "PDM_IN_RX3"},
+	{"SPK DAC", NULL, "VDD_SPKDRV"},
+
+	/* lineout */
+	{"LINEOUT", NULL, "LINEOUT PA"},
+	{"LINEOUT PA", NULL, "SPK_RX_BIAS"},
+	{"LINEOUT PA", NULL, "LINE_OUT"},
+	{"LINE_OUT", "Switch", "LINEOUT DAC"},
+	{"LINEOUT DAC", NULL, "PDM_IN_RX3"},
+
+	/* lineout to WSA */
+	{"WSA_SPK OUT", NULL, "LINEOUT PA"},
+
+	{"PDM_IN_RX1", NULL, "RX1 CLK"},
+	{"PDM_IN_RX2", NULL, "RX2 CLK"},
+	{"PDM_IN_RX3", NULL, "RX3 CLK"},
+
+	{"ADC1_OUT", NULL, "ADC1"},
+	{"ADC2_OUT", NULL, "ADC2"},
+	{"ADC3_OUT", NULL, "ADC3"},
+
+	/* ADC Connections */
+	{"ADC2", NULL, "ADC2 MUX"},
+	{"ADC3", NULL, "ADC2 MUX"},
+	{"ADC2 MUX", "INP2", "ADC2_INP2"},
+	{"ADC2 MUX", "INP3", "ADC2_INP3"},
+
+	{"ADC1", NULL, "ADC1_INP1"},
+	{"ADC1_INP1", "Switch", "AMIC1"},
+	{"ADC2_INP2", NULL, "AMIC2"},
+	{"ADC2_INP3", NULL, "AMIC3"},
+
+	{"MIC BIAS Internal1", NULL, "INT_LDO_H"},
+	{"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+	{"MIC BIAS External", NULL, "INT_LDO_H"},
+	{"MIC BIAS External2", NULL, "INT_LDO_H"},
+	{"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
+	{"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
+	{"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
+	{"MIC BIAS External2", NULL, "MICBIAS_REGULATOR"},
+};
+
+static int msm_anlg_cdc_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+		snd_soc_codec_get_drvdata(dai->codec);
+
+	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
+		__func__,
+		substream->name, substream->stream);
+	/*
+	 * If status_mask is BUS_DOWN it means SSR is not complete.
+	 * So return error.
+	 */
+	if (test_bit(BUS_DOWN, &sdm660_cdc->status_mask)) {
+		dev_err(dai->codec->dev, "Error, Device is not up post SSR\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void msm_anlg_cdc_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->codec->dev,
+		"%s(): substream = %s  stream = %d\n", __func__,
+		substream->name, substream->stream);
+}
+
+int msm_anlg_cdc_mclk_enable(struct snd_soc_codec *codec,
+			     int mclk_enable, bool dapm)
+{
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
+		__func__, mclk_enable, dapm);
+	if (mclk_enable) {
+		sdm660_cdc->int_mclk0_enabled = true;
+		msm_anlg_cdc_codec_enable_clock_block(codec, 1);
+	} else {
+		if (!sdm660_cdc->int_mclk0_enabled) {
+			dev_err(codec->dev, "Error, MCLK already diabled\n");
+			return -EINVAL;
+		}
+		sdm660_cdc->int_mclk0_enabled = false;
+		msm_anlg_cdc_codec_enable_clock_block(codec, 0);
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int msm_anlg_cdc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int msm_anlg_cdc_set_channel_map(struct snd_soc_dai *dai,
+				unsigned int tx_num, unsigned int *tx_slot,
+				unsigned int rx_num, unsigned int *rx_slot)
+
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static int msm_anlg_cdc_get_channel_map(struct snd_soc_dai *dai,
+				 unsigned int *tx_num, unsigned int *tx_slot,
+				 unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+	dev_dbg(dai->codec->dev, "%s\n", __func__);
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm_anlg_cdc_dai_ops = {
+	.startup = msm_anlg_cdc_startup,
+	.shutdown = msm_anlg_cdc_shutdown,
+	.set_sysclk = msm_anlg_cdc_set_dai_sysclk,
+	.set_fmt = msm_anlg_cdc_set_dai_fmt,
+	.set_channel_map = msm_anlg_cdc_set_channel_map,
+	.get_channel_map = msm_anlg_cdc_get_channel_map,
+};
+
+static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[] = {
+	{
+		.name = "msm_anlg_cdc_i2s_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "PDM Playback",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 3,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+	{
+		.name = "msm_anlg_cdc_i2s_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "PDM Capture",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+	{
+		.name = "msm_anlg_cdc_i2s_tx2",
+		.id = AIF3_SVA,
+		.capture = {
+			.stream_name = "RecordSVA",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+	{
+		.name = "msm_anlg_vifeedback",
+		.id = AIF2_VIFEED,
+		.capture = {
+			.stream_name = "VIfeed",
+			.rates = SDM660_CDC_RATES,
+			.formats = SDM660_CDC_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &msm_anlg_cdc_dai_ops,
+	},
+};
+
+
+static int msm_anlg_cdc_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
+					   struct snd_kcontrol *kcontrol,
+					   int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s: %d %s\n", __func__, event, w->name);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX3_MUTE_OFF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX3_MUTE_ON);
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_spk_ext_pa(struct snd_soc_dapm_widget *w,
+						struct snd_kcontrol *kcontrol,
+						int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		dev_dbg(codec->dev,
+			"%s: enable external speaker PA\n", __func__);
+		if (sdm660_cdc->codec_spk_ext_pa_cb)
+			sdm660_cdc->codec_spk_ext_pa_cb(codec, 1);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		dev_dbg(codec->dev,
+			"%s: enable external speaker PA\n", __func__);
+		if (sdm660_cdc->codec_spk_ext_pa_cb)
+			sdm660_cdc->codec_spk_ext_pa_cb(codec, 0);
+		break;
+	}
+	return 0;
+}
+
+static int msm_anlg_cdc_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		dev_dbg(codec->dev,
+			"%s: Sleeping 20ms after select EAR PA\n",
+			__func__);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x80, 0x80);
+		if (get_codec_version(sdm660_cdc) < CONGA)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A);
+		if (get_codec_version(sdm660_cdc) >= DIANGU) {
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x08, 0x00);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		dev_dbg(codec->dev,
+			"%s: Sleeping 20ms after enabling EAR PA\n",
+			__func__);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x40, 0x40);
+		/* Wait for 7ms after EAR PA enable */
+		usleep_range(7000, 7100);
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX1_MUTE_OFF);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		msm_anlg_cdc_dig_notifier_call(codec,
+				       DIG_CDC_EVENT_RX1_MUTE_ON);
+		/* Wait for 20ms for RX digital mute to take effect */
+		msleep(20);
+		if (sdm660_cdc->boost_option == BOOST_ALWAYS) {
+			dev_dbg(codec->dev,
+				"%s: boost_option:%d, tear down ear\n",
+				__func__, sdm660_cdc->boost_option);
+			msm_anlg_cdc_boost_mode_sequence(codec, EAR_PMD);
+		}
+		if (get_codec_version(sdm660_cdc) >= DIANGU) {
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x0);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x0);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		dev_dbg(codec->dev,
+			"%s: Sleeping 7ms after disabling EAR PA\n",
+			__func__);
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+			    0x40, 0x00);
+		/* Wait for 7ms after EAR PA teardown */
+		usleep_range(7000, 7100);
+		if (get_codec_version(sdm660_cdc) < CONGA)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x16);
+		if (get_codec_version(sdm660_cdc) >= DIANGU)
+			snd_soc_update_bits(codec,
+			MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x08, 0x08);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm_anlg_cdc_dapm_widgets[] = {
+	SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM,
+			0, 0, NULL, 0, msm_anlg_cdc_codec_enable_ear_pa,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHL PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+		5, 0, NULL, 0,
+		msm_anlg_cdc_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHR PA", MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+		4, 0, NULL, 0,
+		msm_anlg_cdc_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM,
+			0, 0, NULL, 0, msm_anlg_cdc_codec_enable_spk_pa,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL,
+			5, 0, NULL, 0, msm_anlg_cdc_codec_enable_lo_pa,
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, ear_pa_mux),
+	SND_SOC_DAPM_MUX("SPK", SND_SOC_NOPM, 0, 0, spkr_mux),
+	SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, hphl_mux),
+	SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, hphr_mux),
+	SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
+	SND_SOC_DAPM_MUX("WSA Spk Switch", SND_SOC_NOPM, 0, 0, wsa_spk_mux),
+	SND_SOC_DAPM_MUX("Ext Spk Switch", SND_SOC_NOPM, 0, 0, &ext_spk_mux),
+	SND_SOC_DAPM_MUX("LINE_OUT", SND_SOC_NOPM, 0, 0, lo_mux),
+	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+
+	SND_SOC_DAPM_MIXER_E("HPHL DAC",
+		MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
+		0, msm_anlg_cdc_hphl_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("HPHR DAC",
+		MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
+		0, msm_anlg_cdc_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("SPK DAC", NULL, MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL,
+			 7, 0),
+	SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
+		SND_SOC_NOPM, 0, 0, msm_anlg_cdc_lo_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Ext Spk", msm_anlg_cdc_codec_enable_spk_ext_pa),
+
+	SND_SOC_DAPM_SWITCH("ADC1_INP1", SND_SOC_NOPM, 0, 0,
+			    &adc1_switch),
+	SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+			    2, 0, msm_anlg_cdc_codec_enable_dig_clk,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("CP", MSM89XX_PMIC_ANALOG_NCP_EN, 0, 0,
+			    msm_anlg_cdc_codec_enable_charge_pump,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("EAR CP", MSM89XX_PMIC_ANALOG_NCP_EN, 4, 0,
+			    msm_anlg_cdc_codec_enable_charge_pump,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("RX_BIAS", 1, SND_SOC_NOPM,
+		0, 0, msm_anlg_cdc_codec_enable_rx_bias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("SPK_RX_BIAS", 1, SND_SOC_NOPM, 0, 0,
+		msm_anlg_cdc_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
+			    sdm660_wcd_codec_enable_vdd_spkr,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
+		ON_DEMAND_MICBIAS, 0,
+		msm_anlg_cdc_codec_enable_on_demand_supply,
+		SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
+		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
+		MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
+		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM89XX_PMIC_ANALOG_TX_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP2",
+		NULL, MSM89XX_PMIC_ANALOG_TX_2_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP3",
+		NULL, MSM89XX_PMIC_ANALOG_TX_3_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
+		MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS External2",
+		MSM89XX_PMIC_ANALOG_MICB_2_EN, 7, 0,
+		msm_anlg_cdc_codec_enable_micbias, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_AIF_IN("PDM_IN_RX1", "PDM Playback",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PDM_IN_RX2", "PDM Playback",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PDM_IN_RX3", "PDM Playback",
+		0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("WSA_SPK OUT"),
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT"),
+	SND_SOC_DAPM_AIF_OUT("ADC1_OUT", "PDM Capture",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("ADC2_OUT", "PDM Capture",
+		0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("ADC3_OUT", "PDM Capture",
+		0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct sdm660_cdc_reg_mask_val msm_anlg_cdc_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+};
+
+static const struct sdm660_cdc_reg_mask_val
+					msm_anlg_cdc_reg_defaults_2_0[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x5F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x88),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val conga_wcd_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x0A),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val cajon_wcd_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static const struct sdm660_cdc_reg_mask_val cajon2p0_wcd_reg_defaults[] = {
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x10),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x18),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA),
+	MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80),
+};
+
+static void msm_anlg_cdc_update_reg_defaults(struct snd_soc_codec *codec)
+{
+	u32 i, version;
+	struct sdm660_cdc_priv *sdm660_cdc =
+					snd_soc_codec_get_drvdata(codec);
+
+	version = get_codec_version(sdm660_cdc);
+	if (version == TOMBAK_1_0) {
+		for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_reg_defaults); i++)
+			snd_soc_write(codec, msm_anlg_cdc_reg_defaults[i].reg,
+					msm_anlg_cdc_reg_defaults[i].val);
+	} else if (version == TOMBAK_2_0) {
+		for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_reg_defaults_2_0); i++)
+			snd_soc_write(codec,
+				msm_anlg_cdc_reg_defaults_2_0[i].reg,
+				msm_anlg_cdc_reg_defaults_2_0[i].val);
+	} else if (version == CONGA) {
+		for (i = 0; i < ARRAY_SIZE(conga_wcd_reg_defaults); i++)
+			snd_soc_write(codec,
+				conga_wcd_reg_defaults[i].reg,
+				conga_wcd_reg_defaults[i].val);
+	} else if (version == CAJON) {
+		for (i = 0; i < ARRAY_SIZE(cajon_wcd_reg_defaults); i++)
+			snd_soc_write(codec,
+				cajon_wcd_reg_defaults[i].reg,
+				cajon_wcd_reg_defaults[i].val);
+	} else if (version == CAJON_2_0 || version == DIANGU
+				|| version == DRAX_CDC) {
+		for (i = 0; i < ARRAY_SIZE(cajon2p0_wcd_reg_defaults); i++)
+			snd_soc_write(codec,
+				cajon2p0_wcd_reg_defaults[i].reg,
+				cajon2p0_wcd_reg_defaults[i].val);
+	}
+}
+
+static const struct sdm660_cdc_reg_mask_val
+	msm_anlg_cdc_codec_reg_init_val[] = {
+
+	/* Initialize current threshold to 350MA
+	 * number of wait and run cycles to 4096
+	 */
+	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xFF, 0x12},
+	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+};
+
+static void msm_anlg_cdc_codec_init_cache(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	regcache_cache_only(codec->component.regmap, true);
+	/* update cache with POR values */
+	for (i = 0; i < ARRAY_SIZE(msm89xx_pmic_cdc_defaults); i++)
+		snd_soc_write(codec, msm89xx_pmic_cdc_defaults[i].reg,
+			      msm89xx_pmic_cdc_defaults[i].def);
+	regcache_cache_only(codec->component.regmap, false);
+}
+
+static void msm_anlg_cdc_codec_init_reg(struct snd_soc_codec *codec)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_anlg_cdc_codec_reg_init_val); i++)
+		snd_soc_update_bits(codec,
+				    msm_anlg_cdc_codec_reg_init_val[i].reg,
+				    msm_anlg_cdc_codec_reg_init_val[i].mask,
+				    msm_anlg_cdc_codec_reg_init_val[i].val);
+}
+
+static int msm_anlg_cdc_bringup(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec,
+		MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x01);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x01);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_DIGITAL_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_SEC_ACCESS,
+		0xA5);
+	snd_soc_write(codec, MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00);
+
+	return 0;
+}
+
+static struct regulator *msm_anlg_cdc_find_regulator(
+				const struct sdm660_cdc_priv *sdm660_cdc,
+				const char *name)
+{
+	int i;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (sdm660_cdc->supplies[i].supply &&
+		    !strcmp(sdm660_cdc->supplies[i].supply, name))
+			return sdm660_cdc->supplies[i].consumer;
+	}
+
+	dev_err(sdm660_cdc->dev, "Error: regulator not found:%s\n"
+				, name);
+	return NULL;
+}
+
+static void msm_anlg_cdc_update_micbias_regulator(
+				const struct sdm660_cdc_priv *sdm660_cdc,
+				const char *name,
+				struct on_demand_supply *micbias_supply)
+{
+	int i;
+	struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (sdm660_cdc->supplies[i].supply &&
+		    !strcmp(sdm660_cdc->supplies[i].supply, name)) {
+			micbias_supply->supply =
+				sdm660_cdc->supplies[i].consumer;
+			micbias_supply->min_uv = pdata->regulator[i].min_uv;
+			micbias_supply->max_uv = pdata->regulator[i].max_uv;
+			micbias_supply->optimum_ua =
+					pdata->regulator[i].optimum_ua;
+			return;
+		}
+	}
+
+	dev_err(sdm660_cdc->dev, "Error: regulator not found:%s\n", name);
+}
+
+static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+	unsigned int tx_1_en;
+	unsigned int tx_2_en;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s: device down!\n", __func__);
+
+	tx_1_en = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_TX_1_EN);
+	tx_2_en = snd_soc_read(codec, MSM89XX_PMIC_ANALOG_TX_2_EN);
+	tx_1_en = tx_1_en & 0x7f;
+	tx_2_en = tx_2_en & 0x7f;
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_TX_1_EN, tx_1_en);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_TX_2_EN, tx_2_en);
+	if (sdm660_cdc_priv->boost_option == BOOST_ON_FOREVER) {
+		if ((snd_soc_read(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL)
+			& 0x80) == 0) {
+			msm_anlg_cdc_dig_notifier_call(codec,
+						       DIG_CDC_EVENT_CLK_ON);
+			snd_soc_write(codec,
+				MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL,
+				0x0C, 0x0C);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL,
+				0x84, 0x84);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL,
+				0x10, 0x10);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
+				0x1F, 0x1F);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC,
+				0x90, 0x90);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_RX_EAR_CTL,
+				0xFF, 0xFF);
+			/* Wait for 20us for boost settings to take effect */
+			usleep_range(20, 21);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL,
+				0xFF, 0xFF);
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+				0xE9, 0xE9);
+		}
+	}
+	msm_anlg_cdc_boost_off(codec);
+	sdm660_cdc_priv->hph_mode = NORMAL_MODE;
+
+	/* 40ms to allow boost to discharge */
+	msleep(40);
+	/* Disable PA to avoid pop during codec bring up */
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
+			0x30, 0x00);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
+			0x80, 0x00);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12);
+	snd_soc_write(codec,
+		MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
+
+	msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN);
+	atomic_set(&pdata->int_mclk0_enabled, false);
+	set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
+	snd_soc_card_change_online_state(codec->component.card, 0);
+
+	return 0;
+}
+
+static int msm_anlg_cdc_device_up(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: device up!\n", __func__);
+
+	msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_UP);
+	clear_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
+	snd_soc_card_change_online_state(codec->component.card, 1);
+	/* delay is required to make sure sound card state updated */
+	usleep_range(5000, 5100);
+
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_INT_EN_SET,
+				MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR);
+	snd_soc_write(codec, MSM89XX_PMIC_DIGITAL_INT_EN_CLR,
+				MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR);
+
+	msm_anlg_cdc_set_boost_v(codec);
+	msm_anlg_cdc_set_micb_v(codec);
+	if (sdm660_cdc_priv->boost_option == BOOST_ON_FOREVER)
+		msm_anlg_cdc_boost_on(codec);
+	else if (sdm660_cdc_priv->boost_option == BYPASS_ALWAYS)
+		msm_anlg_cdc_bypass_on(codec);
+
+	return 0;
+}
+
+static int sdm660_cdc_notifier_service_cb(struct notifier_block *nb,
+					     unsigned long opcode, void *ptr)
+{
+	struct snd_soc_codec *codec;
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+				container_of(nb, struct sdm660_cdc_priv,
+					     audio_ssr_nb);
+	bool adsp_ready = false;
+	bool timedout;
+	unsigned long timeout;
+	static bool initial_boot = true;
+
+	codec = sdm660_cdc_priv->codec;
+	dev_dbg(codec->dev, "%s: Service opcode 0x%lx\n", __func__, opcode);
+
+	switch (opcode) {
+	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		if (initial_boot) {
+			initial_boot = false;
+			break;
+		}
+		dev_dbg(codec->dev,
+			"ADSP is about to power down. teardown/reset codec\n");
+		msm_anlg_cdc_device_down(codec);
+		break;
+	case AUDIO_NOTIFIER_SERVICE_UP:
+		if (initial_boot)
+			initial_boot = false;
+		dev_dbg(codec->dev,
+			"ADSP is about to power up. bring up codec\n");
+
+		if (!q6core_is_adsp_ready()) {
+			dev_dbg(codec->dev,
+				"ADSP isn't ready\n");
+			timeout = jiffies +
+				  msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+			while (!(timedout = time_after(jiffies, timeout))) {
+				if (!q6core_is_adsp_ready()) {
+					dev_dbg(codec->dev,
+						"ADSP isn't ready\n");
+				} else {
+					dev_dbg(codec->dev,
+						"ADSP is ready\n");
+					adsp_ready = true;
+					goto powerup;
+				}
+			}
+		} else {
+			adsp_ready = true;
+			dev_dbg(codec->dev, "%s: DSP is ready\n", __func__);
+		}
+powerup:
+		if (adsp_ready)
+			msm_anlg_cdc_device_up(codec);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+int msm_anlg_cdc_hs_detect(struct snd_soc_codec *codec,
+			   struct wcd_mbhc_config *mbhc_cfg)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+
+	return wcd_mbhc_start(&sdm660_cdc_priv->mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(msm_anlg_cdc_hs_detect);
+
+void msm_anlg_cdc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+		snd_soc_codec_get_drvdata(codec);
+
+	wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
+}
+EXPORT_SYMBOL(msm_anlg_cdc_hs_detect_exit);
+
+void msm_anlg_cdc_update_int_spk_boost(bool enable)
+{
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	spkr_boost_en = enable;
+}
+EXPORT_SYMBOL(msm_anlg_cdc_update_int_spk_boost);
+
+static void msm_anlg_cdc_set_micb_v(struct snd_soc_codec *codec)
+{
+
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+	u8 reg_val;
+
+	reg_val = VOLTAGE_CONVERTER(pdata->micbias.cfilt1_mv, MICBIAS_MIN_VAL,
+			MICBIAS_STEP_SIZE);
+	dev_dbg(codec->dev, "cfilt1_mv %d reg_val %x\n",
+			(u32)pdata->micbias.cfilt1_mv, reg_val);
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_VAL,
+			0xF8, (reg_val << 3));
+}
+
+static void msm_anlg_cdc_set_boost_v(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+				snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE,
+			0x1F, sdm660_cdc_priv->boost_voltage);
+}
+
+static void msm_anlg_cdc_configure_cap(struct snd_soc_codec *codec,
+				       bool micbias1, bool micbias2)
+{
+
+	struct msm_asoc_mach_data *pdata = NULL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+	pr_debug("\n %s: micbias1 %x micbias2 = %d\n", __func__, micbias1,
+			micbias2);
+	if (micbias1 && micbias2) {
+		if ((pdata->micbias1_cap_mode
+		     == MICBIAS_EXT_BYP_CAP) ||
+		    (pdata->micbias2_cap_mode
+		     == MICBIAS_EXT_BYP_CAP))
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (MICBIAS_EXT_BYP_CAP << 6));
+		else
+			snd_soc_update_bits(codec,
+				MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (MICBIAS_NO_EXT_BYP_CAP << 6));
+	} else if (micbias2) {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (pdata->micbias2_cap_mode << 6));
+	} else if (micbias1) {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, (pdata->micbias1_cap_mode << 6));
+	} else {
+		snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MICB_1_EN,
+				0x40, 0x00);
+	}
+}
+
+static ssize_t msm_anlg_codec_version_read(struct snd_info_entry *entry,
+					   void *file_private_data,
+					   struct file *file,
+					   char __user *buf, size_t count,
+					   loff_t pos)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv;
+	char buffer[MSM_ANLG_CDC_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	sdm660_cdc_priv = (struct sdm660_cdc_priv *) entry->private_data;
+	if (!sdm660_cdc_priv) {
+		pr_err("%s: sdm660_cdc_priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (get_codec_version(sdm660_cdc_priv)) {
+	case DRAX_CDC:
+		len = snprintf(buffer, sizeof(buffer), "DRAX-CDC_1_0\n");
+		break;
+	default:
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	}
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_anlg_codec_info_ops = {
+	.read = msm_anlg_codec_version_read,
+};
+
+/*
+ * msm_anlg_codec_info_create_codec_entry - creates pmic_analog module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates pmic_analog module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_anlg_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					   struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct sdm660_cdc_priv *sdm660_cdc_priv;
+	struct snd_soc_card *card;
+	int ret;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	sdm660_cdc_priv = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	sdm660_cdc_priv->entry = snd_info_create_subdir(codec_root->module,
+							     "spmi0-03",
+							     codec_root);
+	if (!sdm660_cdc_priv->entry) {
+		dev_dbg(codec->dev, "%s: failed to create pmic_analog entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   sdm660_cdc_priv->entry);
+	if (!version_entry) {
+		dev_dbg(codec->dev, "%s: failed to create pmic_analog version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = sdm660_cdc_priv;
+	version_entry->size = MSM_ANLG_CDC_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &msm_anlg_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	sdm660_cdc_priv->version_entry = version_entry;
+
+	sdm660_cdc_priv->audio_ssr_nb.notifier_call =
+				sdm660_cdc_notifier_service_cb;
+	ret = audio_notifier_register("pmic_analog_cdc",
+				      AUDIO_NOTIFIER_ADSP_DOMAIN,
+				      &sdm660_cdc_priv->audio_ssr_nb);
+	if (ret < 0) {
+		pr_err("%s: Audio notifier register failed ret = %d\n",
+			__func__, ret);
+		return ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_anlg_codec_info_create_codec_entry);
+
+static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int ret;
+
+	sdm660_cdc = dev_get_drvdata(codec->dev);
+	sdm660_cdc->codec = codec;
+
+	/* codec resmgr module init */
+	sdm660_cdc->spkdrv_reg =
+				msm_anlg_cdc_find_regulator(sdm660_cdc,
+						MSM89XX_VDD_SPKDRV_NAME);
+	sdm660_cdc->pmic_rev =
+				snd_soc_read(codec,
+					     MSM89XX_PMIC_DIGITAL_REVISION1);
+	sdm660_cdc->codec_version =
+				snd_soc_read(codec,
+					MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE);
+	sdm660_cdc->analog_major_rev =
+				snd_soc_read(codec,
+					     MSM89XX_PMIC_ANALOG_REVISION4);
+
+	if (sdm660_cdc->codec_version == CONGA) {
+		dev_dbg(codec->dev, "%s :Conga REV: %d\n", __func__,
+					sdm660_cdc->codec_version);
+		sdm660_cdc->ext_spk_boost_set = true;
+	} else {
+		dev_dbg(codec->dev, "%s :PMIC REV: %d\n", __func__,
+					sdm660_cdc->pmic_rev);
+		if (sdm660_cdc->pmic_rev == TOMBAK_1_0 &&
+			sdm660_cdc->codec_version == CAJON_2_0) {
+			if (sdm660_cdc->analog_major_rev == 0x02) {
+				sdm660_cdc->codec_version = DRAX_CDC;
+				dev_dbg(codec->dev,
+					"%s : Drax codec detected\n", __func__);
+			} else {
+				sdm660_cdc->codec_version = DIANGU;
+				dev_dbg(codec->dev, "%s : Diangu detected\n",
+					__func__);
+			}
+		} else if (sdm660_cdc->pmic_rev == TOMBAK_1_0 &&
+			(snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+			 & 0x80)) {
+			sdm660_cdc->codec_version = CAJON;
+			dev_dbg(codec->dev, "%s : Cajon detected\n", __func__);
+		} else if (sdm660_cdc->pmic_rev == TOMBAK_2_0 &&
+			(snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+			 & 0x80)) {
+			sdm660_cdc->codec_version = CAJON_2_0;
+			dev_dbg(codec->dev, "%s : Cajon 2.0 detected\n",
+						__func__);
+		}
+	}
+	/*
+	 * set to default boost option BOOST_SWITCH, user mixer path can change
+	 * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
+	 */
+	sdm660_cdc->boost_option = BOOST_SWITCH;
+	sdm660_cdc->hph_mode = NORMAL_MODE;
+
+	msm_anlg_cdc_dt_parse_boost_info(codec);
+	msm_anlg_cdc_set_boost_v(codec);
+
+	snd_soc_add_codec_controls(codec, impedance_detect_controls,
+				   ARRAY_SIZE(impedance_detect_controls));
+	snd_soc_add_codec_controls(codec, hph_type_detect_controls,
+				  ARRAY_SIZE(hph_type_detect_controls));
+
+	msm_anlg_cdc_bringup(codec);
+	msm_anlg_cdc_codec_init_cache(codec);
+	msm_anlg_cdc_codec_init_reg(codec);
+	msm_anlg_cdc_update_reg_defaults(codec);
+
+	wcd9xxx_spmi_set_codec(codec);
+
+	msm_anlg_cdc_update_micbias_regulator(
+				sdm660_cdc,
+				on_demand_supply_name[ON_DEMAND_MICBIAS],
+				&sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS]);
+	atomic_set(&sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].ref,
+		   0);
+
+	sdm660_cdc->fw_data = devm_kzalloc(codec->dev,
+					sizeof(*(sdm660_cdc->fw_data)),
+					GFP_KERNEL);
+	if (!sdm660_cdc->fw_data)
+		return -ENOMEM;
+
+	set_bit(WCD9XXX_MBHC_CAL, sdm660_cdc->fw_data->cal_bit);
+	ret = wcd_cal_create_hwdep(sdm660_cdc->fw_data,
+			WCD9XXX_CODEC_HWDEP_NODE, codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	wcd_mbhc_init(&sdm660_cdc->mbhc, codec, &mbhc_cb, &intr_ids,
+		      wcd_mbhc_registers, true);
+
+	sdm660_cdc->int_mclk0_enabled = false;
+	/*Update speaker boost configuration*/
+	sdm660_cdc->spk_boost_set = spkr_boost_en;
+	pr_debug("%s: speaker boost configured = %d\n",
+			__func__, sdm660_cdc->spk_boost_set);
+
+	/* Set initial MICBIAS voltage level */
+	msm_anlg_cdc_set_micb_v(codec);
+
+	/* Set initial cap mode */
+	msm_anlg_cdc_configure_cap(codec, false, false);
+
+	snd_soc_dapm_ignore_suspend(dapm, "PDM Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM Capture");
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int msm_anlg_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc_priv =
+					dev_get_drvdata(codec->dev);
+
+	sdm660_cdc_priv->spkdrv_reg = NULL;
+	sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
+	atomic_set(&sdm660_cdc_priv->on_demand_list[ON_DEMAND_MICBIAS].ref,
+		   0);
+	wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
+
+	return 0;
+}
+
+static int msm_anlg_cdc_enable_static_supplies_to_optimum(
+				struct sdm660_cdc_priv *sdm660_cdc,
+				struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		if (regulator_count_voltages(
+				sdm660_cdc->supplies[i].consumer) <= 0)
+			continue;
+
+		ret = regulator_set_voltage(
+				sdm660_cdc->supplies[i].consumer,
+				pdata->regulator[i].min_uv,
+				pdata->regulator[i].max_uv);
+		if (ret) {
+			dev_err(sdm660_cdc->dev,
+				"Setting volt failed for regulator %s err %d\n",
+				sdm660_cdc->supplies[i].supply, ret);
+		}
+
+		ret = regulator_set_load(sdm660_cdc->supplies[i].consumer,
+			pdata->regulator[i].optimum_ua);
+		dev_dbg(sdm660_cdc->dev, "Regulator %s set optimum mode\n",
+			 sdm660_cdc->supplies[i].supply);
+	}
+
+	return ret;
+}
+
+static int msm_anlg_cdc_disable_static_supplies_to_optimum(
+			struct sdm660_cdc_priv *sdm660_cdc,
+			struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		if (regulator_count_voltages(
+				sdm660_cdc->supplies[i].consumer) <= 0)
+			continue;
+		regulator_set_voltage(sdm660_cdc->supplies[i].consumer, 0,
+				pdata->regulator[i].max_uv);
+		regulator_set_load(sdm660_cdc->supplies[i].consumer, 0);
+		dev_dbg(sdm660_cdc->dev, "Regulator %s set optimum mode\n",
+				 sdm660_cdc->supplies[i].supply);
+	}
+
+	return ret;
+}
+
+static int msm_anlg_cdc_suspend(struct snd_soc_codec *codec)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	struct sdm660_cdc_pdata *sdm660_cdc_pdata =
+					sdm660_cdc->dev->platform_data;
+
+	msm_anlg_cdc_disable_static_supplies_to_optimum(sdm660_cdc,
+							sdm660_cdc_pdata);
+	return 0;
+}
+
+static int msm_anlg_cdc_resume(struct snd_soc_codec *codec)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+	struct sdm660_cdc_pdata *sdm660_cdc_pdata =
+					sdm660_cdc->dev->platform_data;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	msm_anlg_cdc_enable_static_supplies_to_optimum(sdm660_cdc,
+						       sdm660_cdc_pdata);
+	return 0;
+}
+
+static struct regmap *msm_anlg_get_regmap(struct device *dev)
+{
+	return dev_get_regmap(dev->parent, NULL);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sdm660_cdc = {
+	.probe	= msm_anlg_cdc_soc_probe,
+	.remove	= msm_anlg_cdc_soc_remove,
+	.suspend = msm_anlg_cdc_suspend,
+	.resume = msm_anlg_cdc_resume,
+	.reg_word_size = 1,
+	.get_regmap = msm_anlg_get_regmap,
+	.component_driver = {
+		.controls = msm_anlg_cdc_snd_controls,
+		.num_controls = ARRAY_SIZE(msm_anlg_cdc_snd_controls),
+		.dapm_widgets = msm_anlg_cdc_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(msm_anlg_cdc_dapm_widgets),
+		.dapm_routes = audio_map,
+		.num_dapm_routes = ARRAY_SIZE(audio_map),
+	},
+};
+
+static int msm_anlg_cdc_init_supplies(struct sdm660_cdc_priv *sdm660_cdc,
+				struct sdm660_cdc_pdata *pdata)
+{
+	int ret;
+	int i;
+
+	sdm660_cdc->supplies = devm_kzalloc(sdm660_cdc->dev,
+					sizeof(struct regulator_bulk_data) *
+					ARRAY_SIZE(pdata->regulator),
+					GFP_KERNEL);
+	if (!sdm660_cdc->supplies) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	sdm660_cdc->num_of_supplies = 0;
+	if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+		dev_err(sdm660_cdc->dev, "%s: Array Size out of bound\n",
+			__func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (pdata->regulator[i].name) {
+			sdm660_cdc->supplies[i].supply =
+						pdata->regulator[i].name;
+			sdm660_cdc->num_of_supplies++;
+		}
+	}
+
+	ret = devm_regulator_bulk_get(sdm660_cdc->dev,
+				      sdm660_cdc->num_of_supplies,
+				      sdm660_cdc->supplies);
+	if (ret != 0) {
+		dev_err(sdm660_cdc->dev,
+			"Failed to get supplies: err = %d\n",
+			ret);
+		goto err_supplies;
+	}
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (regulator_count_voltages(
+			sdm660_cdc->supplies[i].consumer) <= 0)
+			continue;
+		if (pdata->regulator[i].ondemand) {
+			ret = regulator_set_voltage(
+					sdm660_cdc->supplies[i].consumer,
+					0, pdata->regulator[i].max_uv);
+			if (ret) {
+				dev_err(sdm660_cdc->dev,
+					"Setting regulator voltage failed for regulator %s err = %d\n",
+					sdm660_cdc->supplies[i].supply, ret);
+				goto err_supplies;
+			}
+			ret = regulator_set_load(
+				sdm660_cdc->supplies[i].consumer, 0);
+			if (ret < 0) {
+				dev_err(sdm660_cdc->dev,
+					"Setting regulator optimum mode failed for regulator %s err = %d\n",
+					sdm660_cdc->supplies[i].supply, ret);
+				goto err_supplies;
+			} else {
+				ret = 0;
+				continue;
+			}
+		}
+		ret = regulator_set_voltage(sdm660_cdc->supplies[i].consumer,
+					    pdata->regulator[i].min_uv,
+					    pdata->regulator[i].max_uv);
+		if (ret) {
+			dev_err(sdm660_cdc->dev,
+				"Setting regulator voltage failed for regulator %s err = %d\n",
+				sdm660_cdc->supplies[i].supply, ret);
+			goto err_supplies;
+		}
+		ret = regulator_set_load(sdm660_cdc->supplies[i].consumer,
+					 pdata->regulator[i].optimum_ua);
+		if (ret < 0) {
+			dev_err(sdm660_cdc->dev,
+				"Setting regulator optimum mode failed for regulator %s err = %d\n",
+				sdm660_cdc->supplies[i].supply, ret);
+			goto err_supplies;
+		} else {
+			ret = 0;
+		}
+	}
+
+	return ret;
+
+err_supplies:
+	kfree(sdm660_cdc->supplies);
+err:
+	return ret;
+}
+
+static int msm_anlg_cdc_enable_static_supplies(
+					struct sdm660_cdc_priv *sdm660_cdc,
+					struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		ret = regulator_enable(sdm660_cdc->supplies[i].consumer);
+		if (ret) {
+			dev_err(sdm660_cdc->dev, "Failed to enable %s\n",
+			       sdm660_cdc->supplies[i].supply);
+			break;
+		}
+		dev_dbg(sdm660_cdc->dev, "Enabled regulator %s\n",
+				 sdm660_cdc->supplies[i].supply);
+	}
+
+	while (ret && --i)
+		if (!pdata->regulator[i].ondemand)
+			regulator_disable(sdm660_cdc->supplies[i].consumer);
+	return ret;
+}
+
+static void msm_anlg_cdc_disable_supplies(struct sdm660_cdc_priv *sdm660_cdc,
+				     struct sdm660_cdc_pdata *pdata)
+{
+	int i;
+
+	regulator_bulk_disable(sdm660_cdc->num_of_supplies,
+			       sdm660_cdc->supplies);
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (regulator_count_voltages(
+				sdm660_cdc->supplies[i].consumer) <= 0)
+			continue;
+		regulator_set_voltage(sdm660_cdc->supplies[i].consumer, 0,
+				pdata->regulator[i].max_uv);
+		regulator_set_load(sdm660_cdc->supplies[i].consumer, 0);
+	}
+	regulator_bulk_free(sdm660_cdc->num_of_supplies,
+			    sdm660_cdc->supplies);
+	kfree(sdm660_cdc->supplies);
+}
+
+static const struct of_device_id sdm660_codec_of_match[] = {
+	{ .compatible = "qcom,pmic-analog-codec", },
+	{},
+};
+
+static void msm_anlg_add_child_devices(struct work_struct *work)
+{
+	struct sdm660_cdc_priv *pdata;
+	struct platform_device *pdev;
+	struct device_node *node;
+	struct msm_dig_ctrl_data *dig_ctrl_data = NULL, *temp;
+	int ret, ctrl_num = 0;
+	struct msm_dig_ctrl_platform_data *platdata;
+	char plat_dev_name[MSM_DIG_CDC_STRING_LEN];
+
+	pdata = container_of(work, struct sdm660_cdc_priv,
+			     msm_anlg_add_child_devices_work);
+	if (!pdata) {
+		pr_err("%s: Memory for pdata does not exist\n",
+			__func__);
+		return;
+	}
+	if (!pdata->dev->of_node) {
+		dev_err(pdata->dev,
+			"%s: DT node for pdata does not exist\n", __func__);
+		return;
+	}
+
+	platdata = &pdata->dig_plat_data;
+
+	for_each_child_of_node(pdata->dev->of_node, node) {
+		if (!strcmp(node->name, "msm-dig-codec"))
+			strlcpy(plat_dev_name, "msm_digital_codec",
+				(MSM_DIG_CDC_STRING_LEN - 1));
+		else
+			continue;
+
+		pdev = platform_device_alloc(plat_dev_name, -1);
+		if (!pdev) {
+			dev_err(pdata->dev, "%s: pdev memory alloc failed\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err;
+		}
+		pdev->dev.parent = pdata->dev;
+		pdev->dev.of_node = node;
+
+		if (!strcmp(node->name, "msm-dig-codec")) {
+			ret = platform_device_add_data(pdev, platdata,
+						       sizeof(*platdata));
+			if (ret) {
+				dev_err(&pdev->dev,
+					"%s: cannot add plat data ctrl:%d\n",
+					__func__, ctrl_num);
+				goto fail_pdev_add;
+			}
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s: Cannot add platform device\n",
+				__func__);
+			goto fail_pdev_add;
+		}
+
+		if (!strcmp(node->name, "msm-dig-codec")) {
+			temp = krealloc(dig_ctrl_data,
+					(ctrl_num + 1) * sizeof(
+					struct msm_dig_ctrl_data),
+					GFP_KERNEL);
+			if (!temp) {
+				dev_err(&pdev->dev, "out of memory\n");
+				ret = -ENOMEM;
+				goto err;
+			}
+			dig_ctrl_data = temp;
+			dig_ctrl_data[ctrl_num].dig_pdev = pdev;
+			ctrl_num++;
+			dev_dbg(&pdev->dev,
+				"%s: Added digital codec device(s)\n",
+				__func__);
+			pdata->dig_ctrl_data = dig_ctrl_data;
+		}
+	}
+
+	return;
+fail_pdev_add:
+	platform_device_put(pdev);
+err:
+	return;
+}
+
+static int msm_anlg_cdc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct sdm660_cdc_priv *sdm660_cdc = NULL;
+	struct sdm660_cdc_pdata *pdata;
+	int adsp_state;
+
+	adsp_state = apr_get_subsys_state();
+	if (adsp_state != APR_SUBSYS_LOADED) {
+		dev_err(&pdev->dev, "Adsp is not loaded yet %d\n",
+			adsp_state);
+		return -EPROBE_DEFER;
+	}
+	device_init_wakeup(&pdev->dev, true);
+
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "%s:Platform data from device tree\n",
+			__func__);
+		pdata = msm_anlg_cdc_populate_dt_pdata(&pdev->dev);
+		pdev->dev.platform_data = pdata;
+	} else {
+		dev_dbg(&pdev->dev, "%s:Platform data from board file\n",
+			__func__);
+		pdata = pdev->dev.platform_data;
+	}
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "%s:Platform data failed to populate\n",
+			__func__);
+		goto rtn;
+	}
+	sdm660_cdc = devm_kzalloc(&pdev->dev, sizeof(struct sdm660_cdc_priv),
+				     GFP_KERNEL);
+	if (sdm660_cdc == NULL) {
+		ret = -ENOMEM;
+		goto rtn;
+	}
+
+	sdm660_cdc->dev = &pdev->dev;
+	ret = msm_anlg_cdc_init_supplies(sdm660_cdc, pdata);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Fail to enable Codec supplies\n",
+			__func__);
+		goto rtn;
+	}
+	ret = msm_anlg_cdc_enable_static_supplies(sdm660_cdc, pdata);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s: Fail to enable Codec pre-reset supplies\n",
+			__func__);
+		goto rtn;
+	}
+	/* Allow supplies to be ready */
+	usleep_range(5, 6);
+
+	wcd9xxx_spmi_set_dev(pdev, 0);
+	wcd9xxx_spmi_set_dev(pdev, 1);
+	if (wcd9xxx_spmi_irq_init()) {
+		dev_err(&pdev->dev,
+			"%s: irq initialization failed\n", __func__);
+	} else {
+		dev_dbg(&pdev->dev,
+			"%s: irq initialization passed\n", __func__);
+	}
+	dev_set_drvdata(&pdev->dev, sdm660_cdc);
+
+	ret = snd_soc_register_codec(&pdev->dev,
+				     &soc_codec_dev_sdm660_cdc,
+				     msm_anlg_cdc_i2s_dai,
+				     ARRAY_SIZE(msm_anlg_cdc_i2s_dai));
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s:snd_soc_register_codec failed with error %d\n",
+			__func__, ret);
+		goto err_supplies;
+	}
+	BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier);
+	BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier_mbhc);
+
+	sdm660_cdc->dig_plat_data.handle = (void *) sdm660_cdc;
+	sdm660_cdc->dig_plat_data.update_clkdiv = update_clkdiv;
+	sdm660_cdc->dig_plat_data.get_cdc_version = get_cdc_version;
+	sdm660_cdc->dig_plat_data.register_notifier =
+					msm_anlg_cdc_dig_register_notifier;
+	INIT_WORK(&sdm660_cdc->msm_anlg_add_child_devices_work,
+		  msm_anlg_add_child_devices);
+	schedule_work(&sdm660_cdc->msm_anlg_add_child_devices_work);
+
+	return ret;
+err_supplies:
+	msm_anlg_cdc_disable_supplies(sdm660_cdc, pdata);
+rtn:
+	return ret;
+}
+
+static int msm_anlg_cdc_remove(struct platform_device *pdev)
+{
+	struct sdm660_cdc_priv *sdm660_cdc = dev_get_drvdata(&pdev->dev);
+	struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+
+	snd_soc_unregister_codec(&pdev->dev);
+	msm_anlg_cdc_disable_supplies(sdm660_cdc, pdata);
+	return 0;
+}
+
+static struct platform_driver msm_anlg_codec_driver = {
+	.driver		= {
+		.owner          = THIS_MODULE,
+		.name           = DRV_NAME,
+		.of_match_table = of_match_ptr(sdm660_codec_of_match)
+	},
+	.probe          = msm_anlg_cdc_probe,
+	.remove         = msm_anlg_cdc_remove,
+};
+module_platform_driver(msm_anlg_codec_driver);
+
+MODULE_DESCRIPTION("MSM Audio Analog codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/sdm660_cdc/msm-analog-cdc.h b/asoc/codecs/sdm660_cdc/msm-analog-cdc.h
new file mode 100644
index 0000000..fffdf31
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/msm-analog-cdc.h
@@ -0,0 +1,240 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_ANALOG_CDC_H
+#define MSM_ANALOG_CDC_H
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <dsp/q6afe-v2.h>
+#include "../wcd-mbhc-v2.h"
+#include "../wcdcal-hwdep.h"
+#include "sdm660-cdc-registers.h"
+
+#define MICBIAS_EXT_BYP_CAP 0x00
+#define MICBIAS_NO_EXT_BYP_CAP 0x01
+
+#define MSM89XX_NUM_IRQ_REGS	2
+#define MAX_REGULATOR		7
+#define MSM89XX_REG_VAL(reg, val)	{reg, 0, val}
+
+#define MSM89XX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv"
+
+#define DEFAULT_MULTIPLIER 800
+#define DEFAULT_GAIN 9
+#define DEFAULT_OFFSET 100
+
+extern const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE];
+extern const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE];
+extern struct regmap_config msm89xx_cdc_core_regmap_config;
+extern struct regmap_config msm89xx_pmic_cdc_regmap_config;
+
+enum wcd_curr_ref {
+	I_h4_UA = 0,
+	I_pt5_UA,
+	I_14_UA,
+	I_l4_UA,
+	I_1_UA,
+};
+
+enum wcd_mbhc_imp_det_pin {
+	WCD_MBHC_DET_NONE = 0,
+	WCD_MBHC_DET_HPHL,
+	WCD_MBHC_DET_HPHR,
+	WCD_MBHC_DET_BOTH,
+};
+
+
+/* Each micbias can be assigned to one of three cfilters
+ * Vbatt_min >= .15V + ldoh_v
+ * ldoh_v >= .15v + cfiltx_mv
+ * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
+ * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
+ * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
+ * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
+ */
+
+struct wcd_micbias_setting {
+	u8 ldoh_v;
+	u32 cfilt1_mv; /* in mv */
+	u32 cfilt2_mv; /* in mv */
+	u32 cfilt3_mv; /* in mv */
+	/* Different WCD9xxx series codecs may not
+	 * have 4 mic biases. If a codec has fewer
+	 * mic biases, some of these properties will
+	 * not be used.
+	 */
+	u8 bias1_cfilt_sel;
+	u8 bias2_cfilt_sel;
+	u8 bias3_cfilt_sel;
+	u8 bias4_cfilt_sel;
+	u8 bias1_cap_mode;
+	u8 bias2_cap_mode;
+	u8 bias3_cap_mode;
+	u8 bias4_cap_mode;
+	bool bias2_is_headset_only;
+};
+
+enum sdm660_cdc_pid_current {
+	MSM89XX_PID_MIC_2P5_UA,
+	MSM89XX_PID_MIC_5_UA,
+	MSM89XX_PID_MIC_10_UA,
+	MSM89XX_PID_MIC_20_UA,
+};
+
+struct sdm660_cdc_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+enum {
+	/* INTR_REG 0 - Digital Periph */
+	MSM89XX_IRQ_SPKR_CNP = 0,
+	MSM89XX_IRQ_SPKR_CLIP,
+	MSM89XX_IRQ_SPKR_OCP,
+	MSM89XX_IRQ_MBHC_INSREM_DET1,
+	MSM89XX_IRQ_MBHC_RELEASE,
+	MSM89XX_IRQ_MBHC_PRESS,
+	MSM89XX_IRQ_MBHC_INSREM_DET,
+	MSM89XX_IRQ_MBHC_HS_DET,
+	/* INTR_REG 1 - Analog Periph */
+	MSM89XX_IRQ_EAR_OCP,
+	MSM89XX_IRQ_HPHR_OCP,
+	MSM89XX_IRQ_HPHL_OCP,
+	MSM89XX_IRQ_EAR_CNP,
+	MSM89XX_IRQ_HPHR_CNP,
+	MSM89XX_IRQ_HPHL_CNP,
+	MSM89XX_NUM_IRQS,
+};
+
+enum {
+	ON_DEMAND_MICBIAS = 0,
+	ON_DEMAND_SPKDRV,
+	ON_DEMAND_SUPPLIES_MAX,
+};
+
+/*
+ * The delay list is per codec HW specification.
+ * Please add delay in the list in the future instead
+ * of magic number
+ */
+enum {
+	CODEC_DELAY_1_MS = 1000,
+	CODEC_DELAY_1_1_MS  = 1100,
+};
+
+struct sdm660_cdc_regulator {
+	const char *name;
+	int min_uv;
+	int max_uv;
+	int optimum_ua;
+	bool ondemand;
+	struct regulator *regulator;
+};
+
+struct on_demand_supply {
+	struct regulator *supply;
+	atomic_t ref;
+	int min_uv;
+	int max_uv;
+	int optimum_ua;
+};
+
+struct wcd_imped_i_ref {
+	enum wcd_curr_ref curr_ref;
+	int min_val;
+	int multiplier;
+	int gain_adj;
+	int offset;
+};
+
+enum sdm660_cdc_micbias_num {
+	MSM89XX_MICBIAS1 = 0,
+};
+
+/* Hold instance to digital codec platform device */
+struct msm_dig_ctrl_data {
+	struct platform_device *dig_pdev;
+};
+
+struct msm_dig_ctrl_platform_data {
+	void *handle;
+	void (*update_clkdiv)(void *handle, int val);
+	int (*get_cdc_version)(void *handle);
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
+};
+
+struct sdm660_cdc_priv {
+	struct device *dev;
+	u32 num_of_supplies;
+	struct regulator_bulk_data *supplies;
+	struct snd_soc_codec *codec;
+	struct work_struct msm_anlg_add_child_devices_work;
+	struct msm_dig_ctrl_platform_data dig_plat_data;
+	/* digital codec data structure */
+	struct msm_dig_ctrl_data *dig_ctrl_data;
+	struct blocking_notifier_head notifier;
+	u16 pmic_rev;
+	u16 codec_version;
+	u16 analog_major_rev;
+	u32 boost_voltage;
+	u32 adc_count;
+	u32 rx_bias_count;
+	bool int_mclk0_enabled;
+	u16 boost_option;
+	/* mode to select hd2 */
+	u32 hph_mode;
+	/* compander used for each rx chain */
+	bool spk_boost_set;
+	bool ear_pa_boost_set;
+	bool ext_spk_boost_set;
+	struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
+	struct regulator *spkdrv_reg;
+	struct blocking_notifier_head notifier_mbhc;
+	/* mbhc module */
+	struct wcd_mbhc mbhc;
+	/* cal info for codec */
+	struct fw_info *fw_data;
+	struct notifier_block audio_ssr_nb;
+	int (*codec_spk_ext_pa_cb)(struct snd_soc_codec *codec, int enable);
+	unsigned long status_mask;
+	struct wcd_imped_i_ref imped_i_ref;
+	enum wcd_mbhc_imp_det_pin imped_det_pin;
+	/* Entry for version info */
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+};
+
+struct sdm660_cdc_pdata {
+	struct wcd_micbias_setting micbias;
+	struct sdm660_cdc_regulator regulator[MAX_REGULATOR];
+};
+
+
+extern int msm_anlg_cdc_mclk_enable(struct snd_soc_codec *codec,
+				    int mclk_enable, bool dapm);
+
+extern int msm_anlg_cdc_hs_detect(struct snd_soc_codec *codec,
+		    struct wcd_mbhc_config *mbhc_cfg);
+
+extern void msm_anlg_cdc_hs_detect_exit(struct snd_soc_codec *codec);
+
+extern void sdm660_cdc_update_int_spk_boost(bool enable);
+
+extern void msm_anlg_cdc_spk_ext_pa_cb(
+		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
+		int enable), struct snd_soc_codec *codec);
+int msm_anlg_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					   struct snd_soc_codec *codec);
+#endif
diff --git a/asoc/codecs/sdm660_cdc/msm-cdc-common.h b/asoc/codecs/sdm660_cdc/msm-cdc-common.h
new file mode 100644
index 0000000..1a490a4
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/msm-cdc-common.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include "sdm660-cdc-registers.h"
+
+extern struct reg_default
+		msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE];
+extern struct reg_default
+		msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE];
+
+bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg);
+bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg);
+bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg);
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	AIF2_VIFEED,
+	AIF3_SVA,
+	NUM_CODEC_DAIS,
+};
+
+enum codec_versions {
+	TOMBAK_1_0,
+	TOMBAK_2_0,
+	CONGA,
+	CAJON,
+	CAJON_2_0,
+	DIANGU,
+	DRAX_CDC,
+	UNSUPPORTED,
+};
+
+/* Support different hph modes */
+enum {
+	NORMAL_MODE = 0,
+	HD2_MODE,
+};
+
+enum dig_cdc_notify_event {
+	DIG_CDC_EVENT_INVALID,
+	DIG_CDC_EVENT_CLK_ON,
+	DIG_CDC_EVENT_CLK_OFF,
+	DIG_CDC_EVENT_RX1_MUTE_ON,
+	DIG_CDC_EVENT_RX1_MUTE_OFF,
+	DIG_CDC_EVENT_RX2_MUTE_ON,
+	DIG_CDC_EVENT_RX2_MUTE_OFF,
+	DIG_CDC_EVENT_RX3_MUTE_ON,
+	DIG_CDC_EVENT_RX3_MUTE_OFF,
+	DIG_CDC_EVENT_PRE_RX1_INT_ON,
+	DIG_CDC_EVENT_PRE_RX2_INT_ON,
+	DIG_CDC_EVENT_POST_RX1_INT_OFF,
+	DIG_CDC_EVENT_POST_RX2_INT_OFF,
+	DIG_CDC_EVENT_SSR_DOWN,
+	DIG_CDC_EVENT_SSR_UP,
+	DIG_CDC_EVENT_LAST,
+};
diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc.c b/asoc/codecs/sdm660_cdc/msm-digital-cdc.c
new file mode 100644
index 0000000..f59b653
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -0,0 +1,2191 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <dsp/q6afe-v2.h>
+#include <ipc/apr.h>
+#include <soc/internal.h>
+#include "sdm660-cdc-registers.h"
+#include "msm-digital-cdc.h"
+#include "msm-cdc-common.h"
+#include "../../sdm660-common.h"
+
+#define DRV_NAME "msm_digital_codec"
+#define MCLK_RATE_9P6MHZ        9600000
+#define MCLK_RATE_12P288MHZ     12288000
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK	0x30
+#define CF_MIN_3DB_4HZ			0x0
+#define CF_MIN_3DB_75HZ			0x1
+#define CF_MIN_3DB_150HZ		0x2
+
+#define MSM_DIG_CDC_VERSION_ENTRY_SIZE 32
+
+static unsigned long rx_digital_gain_reg[] = {
+	MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
+	MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
+	MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
+};
+
+static unsigned long tx_digital_gain_reg[] = {
+	MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN,
+	MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+
+struct snd_soc_codec *registered_digcodec;
+struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR1 = 0,
+	IIR2,
+	IIR_MAX,
+};
+
+static int msm_digcdc_clock_control(bool flag)
+{
+	int ret = -EINVAL;
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct msm_dig_priv *msm_dig_cdc =
+				snd_soc_codec_get_drvdata(registered_digcodec);
+
+	pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card);
+
+	if (flag) {
+		mutex_lock(&pdata->cdc_int_mclk0_mutex);
+		if (atomic_read(&pdata->int_mclk0_enabled) == false) {
+			pdata->digital_cdc_core_clk.enable = 1;
+			ret = afe_set_lpass_clock_v2(
+						AFE_PORT_ID_INT0_MI2S_RX,
+						&pdata->digital_cdc_core_clk);
+			if (ret < 0) {
+				pr_err("%s:failed to enable the MCLK\n",
+				       __func__);
+				/*
+				 * Avoid access to lpass register
+				 * as clock enable failed during SSR.
+				 */
+				if (ret == -ENODEV)
+					msm_dig_cdc->regmap->cache_only = true;
+				return ret;
+			}
+			pr_debug("enabled digital codec core clk\n");
+			atomic_set(&pdata->int_mclk0_enabled, true);
+			schedule_delayed_work(&pdata->disable_int_mclk0_work,
+					      50);
+		}
+	} else {
+		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+		dev_dbg(registered_digcodec->dev,
+			"disable MCLK, workq to disable set already\n");
+	}
+	return 0;
+}
+
+static void enable_digital_callback(void *flag)
+{
+	msm_digcdc_clock_control(true);
+}
+
+static void disable_digital_callback(void *flag)
+{
+	msm_digcdc_clock_control(false);
+	pr_debug("disable mclk happens in workq\n");
+}
+
+static int msm_dig_cdc_put_dec_enum(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+			dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int dec_mux, decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	u16 tx_mux_ctl_reg;
+	u8 adc_dmic_sel = 0x0;
+	int ret = 0;
+	char *dec_num;
+
+	if (ucontrol->value.enumerated.item[0] > e->items) {
+		dev_err(codec->dev, "%s: Invalid enum value: %d\n",
+			__func__, ucontrol->value.enumerated.item[0]);
+		return -EINVAL;
+	}
+	dec_mux = ucontrol->value.enumerated.item[0];
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name) {
+		dev_err(codec->dev, "%s: failed to copy string\n",
+			__func__);
+		return -ENOMEM;
+	}
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, w->name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	dec_num = strpbrk(dec_name, "12345");
+	if (dec_num == NULL) {
+		dev_err(codec->dev, "%s: Invalid DEC selected\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(dec_num, 10, &decimator);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, dec_name);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
+		, __func__, w->name, decimator, dec_mux);
+
+	switch (decimator) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		if ((dec_mux == 4) || (dec_mux == 5) ||
+		    (dec_mux == 6) || (dec_mux == 7))
+			adc_dmic_sel = 0x1;
+		else
+			adc_dmic_sel = 0x0;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
+			__func__, decimator);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_mux_ctl_reg =
+		MSM89XX_CDC_CORE_TX1_MUX_CTL + 32 * (decimator - 1);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+
+static int msm_dig_cdc_codec_config_compander(struct snd_soc_codec *codec,
+					      int interp_n, int event)
+{
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n",
+		__func__, event, interp_n,
+		dig_cdc->comp_enabled[interp_n]);
+
+	/* compander is not enabled */
+	if (!dig_cdc->comp_enabled[interp_n])
+		return 0;
+
+	switch (dig_cdc->comp_enabled[interp_n]) {
+	case COMPANDER_1:
+		if (SND_SOC_DAPM_EVENT_ON(event)) {
+			/* Enable Compander Clock */
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B1_CTL,
+				1 << interp_n, 1 << interp_n);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50);
+			/* add sleep for compander to settle */
+			usleep_range(1000, 1100);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0);
+
+			/* Enable Compander GPIO */
+			if (dig_cdc->codec_hph_comp_gpio)
+				dig_cdc->codec_hph_comp_gpio(1, codec);
+		} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+			/* Disable Compander GPIO */
+			if (dig_cdc->codec_hph_comp_gpio)
+				dig_cdc->codec_hph_comp_gpio(0, codec);
+
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_COMP0_B1_CTL,
+				1 << interp_n, 0);
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00);
+		}
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__,
+				dig_cdc->comp_enabled[interp_n]);
+		break;
+	};
+
+	return 0;
+}
+
+/**
+ * msm_dig_cdc_hph_comp_cb - registers callback to codec by machine driver.
+ *
+ * @codec_hph_comp_gpio: function pointer to set comp gpio at machine driver
+ * @codec: codec pointer
+ *
+ */
+void msm_dig_cdc_hph_comp_cb(
+	int (*codec_hph_comp_gpio)(bool enable, struct snd_soc_codec *codec),
+	struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: Enter\n", __func__);
+	dig_cdc->codec_hph_comp_gpio = codec_hph_comp_gpio;
+}
+EXPORT_SYMBOL(msm_dig_cdc_hph_comp_cb);
+
+static int msm_dig_cdc_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+						 struct snd_kcontrol *kcontrol,
+						 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+	if (w->shift >= MSM89XX_RX_MAX || w->shift < 0) {
+		dev_err(codec->dev, "%s: wrong RX index: %d\n",
+			__func__, w->shift);
+		return -EINVAL;
+	}
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msm_dig_cdc_codec_config_compander(codec, w->shift, event);
+		/* apply the digital gain after the interpolator is enabled*/
+		if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+			snd_soc_write(codec,
+				  rx_digital_gain_reg[w->shift],
+				  snd_soc_read(codec,
+				  rx_digital_gain_reg[w->shift])
+				  );
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		msm_dig_cdc_codec_config_compander(codec, w->shift, event);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
+			1 << w->shift, 1 << w->shift);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_RX_RESET_CTL,
+			1 << w->shift, 0x0);
+		/*
+		 * disable the mute enabled during the PMD of this device
+		 */
+		if ((w->shift == 0) &&
+			(msm_dig_cdc->mute_mask & HPHL_PA_DISABLE)) {
+			pr_debug("disabling HPHL mute\n");
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
+			msm_dig_cdc->mute_mask &= ~(HPHL_PA_DISABLE);
+		} else if ((w->shift == 1) &&
+				(msm_dig_cdc->mute_mask & HPHR_PA_DISABLE)) {
+			pr_debug("disabling HPHR mute\n");
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
+			msm_dig_cdc->mute_mask &= ~(HPHR_PA_DISABLE);
+		} else if ((w->shift == 2) &&
+				(msm_dig_cdc->mute_mask & SPKR_PA_DISABLE)) {
+			pr_debug("disabling SPKR mute\n");
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
+			msm_dig_cdc->mute_mask &= ~(SPKR_PA_DISABLE);
+		}
+	}
+	return 0;
+}
+
+static int msm_dig_cdc_get_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec,
+			    (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
+		(1 << band_idx)) != 0;
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_dig_cdc_put_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	/* Mask first 5 bits, 6-8 are reserved */
+	snd_soc_update_bits(codec,
+		(MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx),
+			    (1 << band_idx), (value << band_idx));
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+	  iir_idx, band_idx,
+		((snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) &
+	  (1 << band_idx)) != 0));
+
+	return 0;
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+				   int iir_idx, int band_idx,
+				   int coeff_idx)
+{
+	uint32_t value = 0;
+
+	/* Address does not automatically update if reading */
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t)) & 0x7F);
+
+	value |= snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx));
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 1) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 2) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 3) & 0x7F);
+
+	/* Mask bits top 2 bits since they are reserved */
+	value |= ((snd_soc_read(codec, (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL
+		+ 64 * iir_idx)) & 0x3f) << 24);
+
+	return value;
+
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+			       int iir_idx, int band_idx,
+			       uint32_t value)
+{
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value & 0xFF));
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value >> 8) & 0xFF);
+
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value >> 16) & 0xFF);
+
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx),
+		(value >> 24) & 0x3F);
+
+}
+
+static int msm_dig_cdc_get_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+	ucontrol->value.integer.value[1] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+	ucontrol->value.integer.value[2] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+	ucontrol->value.integer.value[3] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+	ucontrol->value.integer.value[4] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[1],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[2],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[3],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[4]);
+	return 0;
+}
+
+static int msm_dig_cdc_put_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	/* Mask top bit it is reserved */
+	/* Updates addr automatically for each B2 write */
+	snd_soc_write(codec,
+		(MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx),
+		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[0]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[1]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[2]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[3]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+			   ucontrol->value.integer.value[4]);
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+	return 0;
+}
+
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct snd_soc_codec *codec;
+	struct msm_dig_priv *msm_dig_cdc;
+	u16 tx_mux_ctl_reg;
+	u8 hpf_cut_of_freq;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	codec = hpf_work->dig_cdc->codec;
+	msm_dig_cdc = hpf_work->dig_cdc;
+	hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+	tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
+			(hpf_work->decimator - 1) * 32;
+
+	dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
+		 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+	msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x51);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+static int msm_dig_cdc_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int value = 0, reg;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->shift == 0)
+			reg = MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL;
+		else if (w->shift == 1)
+			reg = MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL;
+		else
+			goto ret;
+		value = snd_soc_read(codec, reg);
+		snd_soc_write(codec, reg, value);
+		break;
+	default:
+		pr_err("%s: event = %d not expected\n", __func__, event);
+	}
+ret:
+	return 0;
+}
+
+static int msm_dig_cdc_compander_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+	int comp_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int rx_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	dev_dbg(codec->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n",
+			__func__, comp_idx, rx_idx,
+			dig_cdc->comp_enabled[rx_idx]);
+
+	ucontrol->value.integer.value[0] = dig_cdc->comp_enabled[rx_idx];
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_dig_cdc_compander_set(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+	int comp_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int rx_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	if (dig_cdc->version >= DIANGU) {
+		if (!value)
+			dig_cdc->comp_enabled[rx_idx] = 0;
+		else
+			dig_cdc->comp_enabled[rx_idx] = comp_idx;
+	}
+
+	dev_dbg(codec->dev, "%s: msm_dig_cdc->comp[%d]_enabled[%d] = %d\n",
+		__func__, comp_idx, rx_idx,
+		dig_cdc->comp_enabled[rx_idx]);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new compander_kcontrols[] = {
+	SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM89XX_RX1, 1, 0,
+	msm_dig_cdc_compander_get, msm_dig_cdc_compander_set),
+
+	SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM89XX_RX2, 1, 0,
+	msm_dig_cdc_compander_get, msm_dig_cdc_compander_set),
+
+};
+
+static int msm_dig_cdc_set_interpolator_rate(struct snd_soc_dai *dai,
+					     u8 rx_fs_rate_reg_val,
+					     u32 sample_rate)
+{
+	snd_soc_update_bits(dai->codec,
+			MSM89XX_CDC_CORE_RX1_B5_CTL, 0xF0, rx_fs_rate_reg_val);
+	snd_soc_update_bits(dai->codec,
+			MSM89XX_CDC_CORE_RX2_B5_CTL, 0xF0, rx_fs_rate_reg_val);
+	return 0;
+}
+
+static int msm_dig_cdc_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	u8 tx_fs_rate, rx_fs_rate, rx_clk_fs_rate;
+	int ret;
+
+	dev_dbg(dai->codec->dev,
+		"%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
+		__func__, dai->name, dai->id, params_rate(params),
+		params_channels(params), params_format(params));
+
+	switch (params_rate(params)) {
+	case 8000:
+		tx_fs_rate = 0x00;
+		rx_fs_rate = 0x00;
+		rx_clk_fs_rate = 0x00;
+		break;
+	case 16000:
+		tx_fs_rate = 0x20;
+		rx_fs_rate = 0x20;
+		rx_clk_fs_rate = 0x01;
+		break;
+	case 32000:
+		tx_fs_rate = 0x40;
+		rx_fs_rate = 0x40;
+		rx_clk_fs_rate = 0x02;
+		break;
+	case 44100:
+	case 48000:
+		tx_fs_rate = 0x60;
+		rx_fs_rate = 0x60;
+		rx_clk_fs_rate = 0x03;
+		break;
+	case 96000:
+		tx_fs_rate = 0x80;
+		rx_fs_rate = 0x80;
+		rx_clk_fs_rate = 0x04;
+		break;
+	case 192000:
+		tx_fs_rate = 0xA0;
+		rx_fs_rate = 0xA0;
+		rx_clk_fs_rate = 0x05;
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Invalid sampling rate %d\n", __func__,
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(dai->codec,
+			MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x0F, rx_clk_fs_rate);
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_CAPTURE:
+		break;
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = msm_dig_cdc_set_interpolator_rate(dai, rx_fs_rate,
+						  params_rate(params));
+		if (ret < 0) {
+			dev_err(dai->codec->dev,
+				"%s: set decimator rate failed %d\n", __func__,
+				ret);
+			return ret;
+		}
+		break;
+	default:
+		dev_err(dai->codec->dev,
+			"%s: Invalid stream type %d\n", __func__,
+			substream->stream);
+		return -EINVAL;
+	}
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(dai->codec,
+				MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x20);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		snd_soc_update_bits(dai->codec,
+				MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x00);
+		break;
+	default:
+		dev_err(dai->codec->dev, "%s: wrong format selected\n",
+				__func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_dig_cdc_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec);
+	u8  dmic_clk_en;
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	unsigned int dmic;
+	int ret;
+	char *dmic_num = strpbrk(w->name, "1234");
+
+	if (dmic_num == NULL) {
+		dev_err(codec->dev, "%s: Invalid DMIC\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(dmic_num, 10, &dmic);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Invalid DMIC line on the codec\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 1:
+	case 2:
+		dmic_clk_en = 0x01;
+		dmic_clk_cnt = &(dig_cdc->dmic_1_2_clk_cnt);
+		dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL;
+		dev_dbg(codec->dev,
+			"%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+		break;
+	case 3:
+	case 4:
+		dmic_clk_en = 0x01;
+		dmic_clk_cnt = &(dig_cdc->dmic_3_4_clk_cnt);
+		dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL;
+		dev_dbg(codec->dev,
+			"%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1) {
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					0x0E, 0x04);
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, dmic_clk_en);
+		}
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_TX1_DMIC_CTL + (dmic - 1) * 0x20,
+			0x07, 0x02);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0)
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, 0);
+		break;
+	}
+	return 0;
+}
+
+static int msm_dig_cdc_codec_enable_dec(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct msm_asoc_mach_data *pdata = NULL;
+	unsigned int decimator;
+	struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	int ret = 0, i;
+	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+	u8 dec_hpf_cut_of_freq;
+	int offset;
+	char *dec_num;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		dev_err(codec->dev,
+			"%s: Invalid decimator = %s\n", __func__, w->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dec_num = strpbrk(dec_name, "12345");
+	if (dec_num == NULL) {
+		dev_err(codec->dev, "%s: Invalid Decimator\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(dec_num, 10, &decimator);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(codec->dev,
+		"%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+		w->name, dec_name, decimator);
+
+	if (w->reg == MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL) {
+		dec_reset_reg = MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL;
+		offset = 0;
+	} else {
+		dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
+			 32 * (decimator - 1);
+	tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL +
+			  32 * (decimator - 1);
+	if (decimator == 5) {
+		tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG;
+		tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX5_MUX_CTL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enableable TX digital mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+		for (i = 0; i < NUM_DECIMATORS; i++) {
+			if (decimator == i + 1)
+				msm_dig_cdc->dec_active[i] = true;
+		}
+
+		dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+
+		dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
+
+		tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+			dec_hpf_cut_of_freq;
+
+		if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) {
+
+			/* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
+			snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+					    CF_MIN_3DB_150HZ << 4);
+		}
+		msm_dig_cdc->update_clkdiv(msm_dig_cdc->handle, 0x42);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* enable HPF */
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
+
+		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+				CF_MIN_3DB_150HZ) {
+
+			schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+					msecs_to_jiffies(300));
+		}
+		/* apply the digital gain after the decimator is enabled*/
+		if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
+			snd_soc_write(codec,
+				  tx_digital_gain_reg[w->shift + offset],
+				  snd_soc_read(codec,
+				  tx_digital_gain_reg[w->shift + offset])
+				  );
+		if (pdata->lb_mode) {
+			pr_debug("%s: loopback mode unmute the DEC\n",
+							__func__);
+			snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+		}
+				snd_soc_update_bits(codec, tx_vol_ctl_reg,
+						0x01, 0x00);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+		msleep(20);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+			1 << w->shift);
+		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+		for (i = 0; i < NUM_DECIMATORS; i++) {
+			if (decimator == i + 1)
+				msm_dig_cdc->dec_active[i] = false;
+		}
+		break;
+	}
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+static int msm_dig_cdc_event_notify(struct notifier_block *block,
+				    unsigned long val,
+				    void *data)
+{
+	enum dig_cdc_notify_event event = (enum dig_cdc_notify_event)val;
+	struct snd_soc_codec *codec = registered_digcodec;
+	struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+	struct msm_asoc_mach_data *pdata = NULL;
+	int ret = -EINVAL;
+
+	pdata = snd_soc_card_get_drvdata(codec->component.card);
+
+	switch (event) {
+	case DIG_CDC_EVENT_CLK_ON:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03);
+		if (pdata->mclk_freq == MCLK_RATE_12P288MHZ ||
+		    pdata->native_clk_set)
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x00);
+		else if (pdata->mclk_freq == MCLK_RATE_9P6MHZ)
+			snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01);
+		break;
+	case DIG_CDC_EVENT_CLK_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x00);
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x00);
+		break;
+	case DIG_CDC_EVENT_RX1_MUTE_ON:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01);
+		msm_dig_cdc->mute_mask |= HPHL_PA_DISABLE;
+		break;
+	case DIG_CDC_EVENT_RX1_MUTE_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00);
+		msm_dig_cdc->mute_mask &= (~HPHL_PA_DISABLE);
+		break;
+	case DIG_CDC_EVENT_RX2_MUTE_ON:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x01);
+		msm_dig_cdc->mute_mask |= HPHR_PA_DISABLE;
+		break;
+	case DIG_CDC_EVENT_RX2_MUTE_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00);
+		msm_dig_cdc->mute_mask &= (~HPHR_PA_DISABLE);
+		break;
+	case DIG_CDC_EVENT_RX3_MUTE_ON:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x01);
+		msm_dig_cdc->mute_mask |= SPKR_PA_DISABLE;
+		break;
+	case DIG_CDC_EVENT_RX3_MUTE_OFF:
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00);
+		msm_dig_cdc->mute_mask &= (~SPKR_PA_DISABLE);
+		break;
+	case DIG_CDC_EVENT_PRE_RX1_INT_ON:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x28);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x80);
+		break;
+	case DIG_CDC_EVENT_PRE_RX2_INT_ON:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x28);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x80);
+		break;
+	case DIG_CDC_EVENT_POST_RX1_INT_OFF:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x00);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x00);
+		break;
+	case DIG_CDC_EVENT_POST_RX2_INT_OFF:
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x00);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
+		snd_soc_update_bits(codec,
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x00);
+		break;
+	case DIG_CDC_EVENT_SSR_DOWN:
+		regcache_cache_only(msm_dig_cdc->regmap, true);
+		break;
+	case DIG_CDC_EVENT_SSR_UP:
+		regcache_cache_only(msm_dig_cdc->regmap, false);
+		regcache_mark_dirty(msm_dig_cdc->regmap);
+
+		mutex_lock(&pdata->cdc_int_mclk0_mutex);
+		pdata->digital_cdc_core_clk.enable = 1;
+		ret = afe_set_lpass_clock_v2(
+					AFE_PORT_ID_INT0_MI2S_RX,
+					&pdata->digital_cdc_core_clk);
+		if (ret < 0) {
+			pr_err("%s:failed to enable the MCLK\n",
+			       __func__);
+			mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+			break;
+		}
+		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+
+		regcache_sync(msm_dig_cdc->regmap);
+
+		mutex_lock(&pdata->cdc_int_mclk0_mutex);
+		pdata->digital_cdc_core_clk.enable = 0;
+		afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT0_MI2S_RX,
+				&pdata->digital_cdc_core_clk);
+		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+		break;
+	case DIG_CDC_EVENT_INVALID:
+	default:
+		break;
+	}
+	return 0;
+}
+
+static ssize_t msm_dig_codec_version_read(struct snd_info_entry *entry,
+					  void *file_private_data,
+					  struct file *file,
+					  char __user *buf, size_t count,
+					  loff_t pos)
+{
+	struct msm_dig_priv *msm_dig;
+	char buffer[MSM_DIG_CDC_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	msm_dig = (struct msm_dig_priv *) entry->private_data;
+	if (!msm_dig) {
+		pr_err("%s: msm_dig priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (msm_dig->version) {
+	case DRAX_CDC:
+		len = snprintf(buffer, sizeof(buffer), "SDM660-CDC_1_0\n");
+		break;
+	default:
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	}
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops msm_dig_codec_info_ops = {
+	.read = msm_dig_codec_version_read,
+};
+
+/*
+ * msm_dig_codec_info_create_codec_entry - creates msm_dig module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates msm_dig module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct msm_dig_priv *msm_dig;
+	struct snd_soc_card *card;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	msm_dig = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	msm_dig->entry = snd_info_create_subdir(codec_root->module,
+						  "msm_digital_codec",
+						  codec_root);
+	if (!msm_dig->entry) {
+		dev_dbg(codec->dev, "%s: failed to create msm_digital entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   msm_dig->entry);
+	if (!version_entry) {
+		dev_dbg(codec->dev, "%s: failed to create msm_digital version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = msm_dig;
+	version_entry->size = MSM_DIG_CDC_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &msm_dig_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	msm_dig->version_entry = version_entry;
+	if (msm_dig->get_cdc_version)
+		msm_dig->version = msm_dig->get_cdc_version(msm_dig->handle);
+	else
+		msm_dig->version = DRAX_CDC;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_dig_codec_info_create_codec_entry);
+
+static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int i, ret;
+
+	msm_dig_cdc->codec = codec;
+
+	snd_soc_add_codec_controls(codec, compander_kcontrols,
+			ARRAY_SIZE(compander_kcontrols));
+
+	for (i = 0; i < NUM_DECIMATORS; i++) {
+		tx_hpf_work[i].dig_cdc = msm_dig_cdc;
+		tx_hpf_work[i].decimator = i + 1;
+		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+			tx_hpf_corner_freq_callback);
+	}
+
+	for (i = 0; i < MSM89XX_RX_MAX; i++)
+		msm_dig_cdc->comp_enabled[i] = COMPANDER_NONE;
+
+	/* Register event notifier */
+	msm_dig_cdc->nblock.notifier_call = msm_dig_cdc_event_notify;
+	if (msm_dig_cdc->register_notifier) {
+		ret = msm_dig_cdc->register_notifier(msm_dig_cdc->handle,
+						     &msm_dig_cdc->nblock,
+						     true);
+		if (ret) {
+			pr_err("%s: Failed to register notifier %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	registered_digcodec = codec;
+
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture");
+	snd_soc_dapm_ignore_suspend(dapm, "ADC1_IN");
+	snd_soc_dapm_ignore_suspend(dapm, "ADC2_IN");
+	snd_soc_dapm_ignore_suspend(dapm, "ADC3_IN");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX1");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2");
+	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3");
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int msm_dig_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+	if (msm_dig_cdc->register_notifier)
+		msm_dig_cdc->register_notifier(msm_dig_cdc->handle,
+					       &msm_dig_cdc->nblock,
+					       false);
+	iounmap(msm_dig_cdc->dig_base);
+	return 0;
+}
+
+static const struct snd_soc_dapm_route audio_dig_map[] = {
+	{"RX_I2S_CLK", NULL, "CDC_CONN"},
+	{"I2S RX1", NULL, "RX_I2S_CLK"},
+	{"I2S RX2", NULL, "RX_I2S_CLK"},
+	{"I2S RX3", NULL, "RX_I2S_CLK"},
+
+	{"I2S TX1", NULL, "TX_I2S_CLK"},
+	{"I2S TX2", NULL, "TX_I2S_CLK"},
+	{"I2S TX3", NULL, "TX_I2S_CLK"},
+	{"I2S TX4", NULL, "TX_I2S_CLK"},
+	{"I2S TX5", NULL, "TX_I2S_CLK"},
+	{"I2S TX6", NULL, "TX_I2S_CLK"},
+
+	{"I2S TX1", NULL, "DEC1 MUX"},
+	{"I2S TX2", NULL, "DEC2 MUX"},
+	{"I2S TX3", NULL, "I2S TX2 INP1"},
+	{"I2S TX4", NULL, "I2S TX2 INP2"},
+	{"I2S TX5", NULL, "DEC3 MUX"},
+	{"I2S TX6", NULL, "I2S TX3 INP2"},
+
+	{"I2S TX2 INP1", "RX_MIX1", "RX1 MIX2"},
+	{"I2S TX2 INP1", "DEC3", "DEC3 MUX"},
+	{"I2S TX2 INP2", "RX_MIX2", "RX2 MIX2"},
+	{"I2S TX2 INP2", "RX_MIX3", "RX3 MIX1"},
+	{"I2S TX2 INP2", "DEC4", "DEC4 MUX"},
+	{"I2S TX3 INP2", "DEC4", "DEC4 MUX"},
+	{"I2S TX3 INP2", "DEC5", "DEC5 MUX"},
+
+	{"PDM_OUT_RX1", NULL, "RX1 CHAIN"},
+	{"PDM_OUT_RX2", NULL, "RX2 CHAIN"},
+	{"PDM_OUT_RX3", NULL, "RX3 CHAIN"},
+
+	{"RX1 CHAIN", NULL, "RX1 MIX2"},
+	{"RX2 CHAIN", NULL, "RX2 MIX2"},
+	{"RX3 CHAIN", NULL, "RX3 MIX1"},
+
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+	{"RX1 MIX2", NULL, "RX1 MIX1"},
+	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
+	{"RX2 MIX2", NULL, "RX2 MIX1"},
+	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
+
+	{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP1", "IIR2", "IIR2"},
+	{"RX1 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX1 MIX1 INP2", "IIR2", "IIR2"},
+	{"RX1 MIX1 INP3", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP3", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP3", "RX3", "I2S RX3"},
+
+	{"RX2 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP1", "IIR2", "IIR2"},
+	{"RX2 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX2 MIX1 INP2", "IIR2", "IIR2"},
+
+	{"RX3 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP1", "RX3", "I2S RX3"},
+	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP1", "IIR2", "IIR2"},
+	{"RX3 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP2", "RX3", "I2S RX3"},
+	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX3 MIX1 INP2", "IIR2", "IIR2"},
+
+	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
+	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
+	{"RX1 MIX2 INP1", "IIR2", "IIR2"},
+	{"RX2 MIX2 INP1", "IIR2", "IIR2"},
+
+		/* Decimator Inputs */
+	{"DEC1 MUX", "DMIC1", "DMIC1"},
+	{"DEC1 MUX", "DMIC2", "DMIC2"},
+	{"DEC1 MUX", "DMIC3", "DMIC3"},
+	{"DEC1 MUX", "DMIC4", "DMIC4"},
+	{"DEC1 MUX", "ADC1", "ADC1_IN"},
+	{"DEC1 MUX", "ADC2", "ADC2_IN"},
+	{"DEC1 MUX", "ADC3", "ADC3_IN"},
+	{"DEC1 MUX", NULL, "CDC_CONN"},
+
+	{"DEC2 MUX", "DMIC1", "DMIC1"},
+	{"DEC2 MUX", "DMIC2", "DMIC2"},
+	{"DEC2 MUX", "DMIC3", "DMIC3"},
+	{"DEC2 MUX", "DMIC4", "DMIC4"},
+	{"DEC2 MUX", "ADC1", "ADC1_IN"},
+	{"DEC2 MUX", "ADC2", "ADC2_IN"},
+	{"DEC2 MUX", "ADC3", "ADC3_IN"},
+	{"DEC2 MUX", NULL, "CDC_CONN"},
+
+	{"DEC3 MUX", "DMIC1", "DMIC1"},
+	{"DEC3 MUX", "DMIC2", "DMIC2"},
+	{"DEC3 MUX", "DMIC3", "DMIC3"},
+	{"DEC3 MUX", "DMIC4", "DMIC4"},
+	{"DEC3 MUX", "ADC1", "ADC1_IN"},
+	{"DEC3 MUX", "ADC2", "ADC2_IN"},
+	{"DEC3 MUX", "ADC3", "ADC3_IN"},
+	{"DEC3 MUX", NULL, "CDC_CONN"},
+
+	{"DEC4 MUX", "DMIC1", "DMIC1"},
+	{"DEC4 MUX", "DMIC2", "DMIC2"},
+	{"DEC4 MUX", "DMIC3", "DMIC3"},
+	{"DEC4 MUX", "DMIC4", "DMIC4"},
+	{"DEC4 MUX", "ADC1", "ADC1_IN"},
+	{"DEC4 MUX", "ADC2", "ADC2_IN"},
+	{"DEC4 MUX", "ADC3", "ADC3_IN"},
+	{"DEC4 MUX", NULL, "CDC_CONN"},
+
+	{"DEC5 MUX", "DMIC1", "DMIC1"},
+	{"DEC5 MUX", "DMIC2", "DMIC2"},
+	{"DEC5 MUX", "DMIC3", "DMIC3"},
+	{"DEC5 MUX", "DMIC4", "DMIC4"},
+	{"DEC5 MUX", "ADC1", "ADC1_IN"},
+	{"DEC5 MUX", "ADC2", "ADC2_IN"},
+	{"DEC5 MUX", "ADC3", "ADC3_IN"},
+	{"DEC5 MUX", NULL, "CDC_CONN"},
+
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR2", NULL, "IIR2 INP1 MUX"},
+	{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+};
+
+
+static const char * const i2s_tx2_inp1_text[] = {
+	"ZERO", "RX_MIX1", "DEC3"
+};
+
+static const char * const i2s_tx2_inp2_text[] = {
+	"ZERO", "RX_MIX2", "RX_MIX3", "DEC4"
+};
+
+static const char * const i2s_tx3_inp2_text[] = {
+	"DEC4", "DEC5"
+};
+
+static const char * const rx_mix1_text[] = {
+	"ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
+};
+
+static const char * const rx_mix2_text[] = {
+	"ZERO", "IIR1", "IIR2"
+};
+
+static const char * const dec_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
+};
+
+static const char * const iir_inp1_text[] = {
+	"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3", "DEC3", "DEC4"
+};
+
+/* I2S TX MUXes */
+static const struct soc_enum i2s_tx2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+		2, 3, i2s_tx2_inp1_text);
+
+static const struct soc_enum i2s_tx2_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+		0, 4, i2s_tx2_inp2_text);
+
+static const struct soc_enum i2s_tx3_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL,
+		4, 2, i2s_tx3_inp2_text);
+
+/* RX1 MIX1 */
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
+		0, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL,
+		3, 6, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B2_CTL,
+		0, 6, rx_mix1_text);
+
+/* RX1 MIX2 */
+static const struct soc_enum rx_mix2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B3_CTL,
+		0, 3, rx_mix2_text);
+
+/* RX2 MIX1 */
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+		0, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+		3, 6, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL,
+		0, 6, rx_mix1_text);
+
+/* RX2 MIX2 */
+static const struct soc_enum rx2_mix2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B3_CTL,
+		0, 3, rx_mix2_text);
+
+/* RX3 MIX1 */
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+		0, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+		3, 6, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL,
+		0, 6, rx_mix1_text);
+
+/* DEC */
+static const struct soc_enum dec1_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
+		0, 8, dec_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL,
+		3, 8, dec_mux_text);
+
+static const struct soc_enum dec3_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B2_CTL,
+		0, 8, dec_mux_text);
+
+static const struct soc_enum dec4_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B2_CTL,
+		3, 8, dec_mux_text);
+
+static const struct soc_enum decsva_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B3_CTL,
+		0, 8, dec_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL,
+		0, 8, iir_inp1_text);
+
+static const struct soc_enum iir2_inp1_mux_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL,
+		0, 8, iir_inp1_text);
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_rxmix1_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX1_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix2_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX2_B4_CTL, 0, 3, cf_text);
+
+static const struct soc_enum cf_rxmix3_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX3_B4_CTL, 0, 3, cf_text);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+#define MSM89XX_DEC_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_dapm_get_enum_double, \
+	.put = msm_dig_cdc_put_dec_enum, \
+	.private_value = (unsigned long)&xenum }
+
+static const struct snd_kcontrol_new dec1_mux =
+	MSM89XX_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+	MSM89XX_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new dec3_mux =
+	MSM89XX_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+
+static const struct snd_kcontrol_new dec4_mux =
+	MSM89XX_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+
+static const struct snd_kcontrol_new decsva_mux =
+	MSM89XX_DEC_ENUM("DEC5 MUX Mux", decsva_mux_enum);
+
+static const struct snd_kcontrol_new i2s_tx2_inp1_mux =
+	SOC_DAPM_ENUM("I2S TX2 INP1 Mux", i2s_tx2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new i2s_tx2_inp2_mux =
+	SOC_DAPM_ENUM("I2S TX2 INP2 Mux", i2s_tx2_inp2_chain_enum);
+
+static const struct snd_kcontrol_new i2s_tx3_inp2_mux =
+	SOC_DAPM_ENUM("I2S TX3 INP2 Mux", i2s_tx3_inp2_chain_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp1_mux =
+	SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
+	SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
+	SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
+
+static const struct snd_soc_dapm_widget msm_dig_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX1 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+			     MSM89XX_RX1, 0, NULL, 0,
+			     msm_dig_cdc_codec_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX2 MIX2", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+			     MSM89XX_RX2, 0, NULL, 0,
+			     msm_dig_cdc_codec_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX3 MIX1", MSM89XX_CDC_CORE_CLK_RX_B1_CTL,
+			     MSM89XX_RX3, 0, NULL, 0,
+			     msm_dig_cdc_codec_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX3 CHAIN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp3_mux),
+
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp3_mux),
+
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp3_mux),
+
+	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx1_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix2_inp1_mux),
+
+	SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, MSM89XX_CDC_CORE_CLK_OTHR_CTL,
+		2, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX_E("DEC1 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+		&dec1_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC2 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+		&dec2_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC3 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+		&dec3_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC4 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+		&dec4_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC5 MUX",
+		MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 4, 0,
+		&decsva_mux, msm_dig_cdc_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	/* Sidetone */
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_PGA_E("IIR1", MSM89XX_CDC_CORE_CLK_SD_CTL, 0, 0, NULL, 0,
+		msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
+	SND_SOC_DAPM_PGA_E("IIR2", MSM89XX_CDC_CORE_CLK_SD_CTL, 1, 0, NULL, 0,
+		msm_dig_cdc_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK",
+		MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK",
+		MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 4, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_MUX("I2S TX2 INP1", SND_SOC_NOPM, 0, 0,
+			&i2s_tx2_inp1_mux),
+	SND_SOC_DAPM_MUX("I2S TX2 INP2", SND_SOC_NOPM, 0, 0,
+			&i2s_tx2_inp2_mux),
+	SND_SOC_DAPM_MUX("I2S TX3 INP2", SND_SOC_NOPM, 0, 0,
+			&i2s_tx3_inp2_mux),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		msm_dig_cdc_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("ADC1_IN"),
+	SND_SOC_DAPM_INPUT("ADC2_IN"),
+	SND_SOC_DAPM_INPUT("ADC3_IN"),
+	SND_SOC_DAPM_OUTPUT("PDM_OUT_RX1"),
+	SND_SOC_DAPM_OUTPUT("PDM_OUT_RX2"),
+	SND_SOC_DAPM_OUTPUT("PDM_OUT_RX3"),
+};
+
+static const struct soc_enum cf_dec1_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX2_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec3_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec4_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_decsva_enum =
+	SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX5_MUX_CTL, 4, 3, cf_text);
+
+static const struct snd_kcontrol_new msm_dig_snd_controls[] = {
+	SOC_SINGLE_SX_TLV("DEC1 Volume",
+		MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC2 Volume",
+		  MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC3 Volume",
+		  MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC4 Volume",
+		  MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC5 Volume",
+		  MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN,
+		0, -84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL,
+			0,  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL,
+			0,  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL,
+			0,  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP4 Volume",
+			  MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL,
+			0,  -84,	40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR2 INP1 Volume",
+			  MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL,
+			0,  -84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("RX1 Digital Volume",
+		MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Digital Volume",
+		MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Digital Volume",
+		MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL,
+		0, -84, 40, digital_gain),
+
+	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+		msm_dig_cdc_get_iir_enable_audio_mixer,
+		msm_dig_cdc_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+		msm_dig_cdc_get_iir_band_audio_mixer,
+		msm_dig_cdc_put_iir_band_audio_mixer),
+
+	SOC_SINGLE("RX1 HPF Switch",
+		MSM89XX_CDC_CORE_RX1_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX2 HPF Switch",
+		MSM89XX_CDC_CORE_RX2_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX3 HPF Switch",
+		MSM89XX_CDC_CORE_RX3_B5_CTL, 2, 1, 0),
+
+	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+	SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
+	SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
+
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+	SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+	SOC_ENUM("TX5 HPF cut off", cf_decsva_enum),
+	SOC_SINGLE("TX1 HPF Switch",
+		MSM89XX_CDC_CORE_TX1_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX2 HPF Switch",
+		MSM89XX_CDC_CORE_TX2_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX3 HPF Switch",
+		MSM89XX_CDC_CORE_TX3_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX4 HPF Switch",
+		MSM89XX_CDC_CORE_TX4_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX5 HPF Switch",
+		MSM89XX_CDC_CORE_TX5_MUX_CTL, 3, 1, 0),
+};
+
+static int msm_dig_cdc_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = NULL;
+	u16 tx_vol_ctl_reg = 0;
+	u8 decimator = 0, i;
+	struct msm_dig_priv *dig_cdc;
+
+	pr_debug("%s: Digital Mute val = %d\n", __func__, mute);
+
+	if (!dai || !dai->codec) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	codec = dai->codec;
+	dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+	if (dai->id == AIF1_PB) {
+		dev_dbg(codec->dev, "%s: Not capture use case skip\n",
+			__func__);
+		return 0;
+	}
+
+	mute = (mute) ? 1 : 0;
+	if (!mute) {
+		/*
+		 * 15 ms is an emperical value for the mute time
+		 * that was arrived by checking the pop level
+		 * to be inaudible
+		 */
+		usleep_range(15000, 15010);
+	}
+
+	if (dai->id == AIF3_SVA) {
+		snd_soc_update_bits(codec,
+			MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG, 0x01, mute);
+		goto ret;
+	}
+	for (i = 0; i < (NUM_DECIMATORS - 1); i++) {
+		if (dig_cdc->dec_active[i])
+			decimator = i + 1;
+		if (decimator && decimator < NUM_DECIMATORS) {
+			/* mute/unmute decimators corresponding to Tx DAI's */
+			tx_vol_ctl_reg =
+			MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG +
+					32 * (decimator - 1);
+			snd_soc_update_bits(codec, tx_vol_ctl_reg,
+					    0x01, mute);
+		}
+		decimator = 0;
+	}
+ret:
+	return 0;
+}
+
+static struct snd_soc_dai_ops msm_dig_dai_ops = {
+	.hw_params = msm_dig_cdc_hw_params,
+	.digital_mute = msm_dig_cdc_digital_mute,
+};
+
+
+static struct snd_soc_dai_driver msm_codec_dais[] = {
+	{
+		.name = "msm_dig_cdc_dai_rx1",
+		.id = AIF1_PB,
+		.playback = { /* Support maximum range */
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE |
+				SNDRV_PCM_FMTBIT_S24_3LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+	{
+		.name = "msm_dig_cdc_dai_tx1",
+		.id = AIF1_CAP,
+		.capture = { /* Support maximum range */
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+	{
+		.name = "msm_dig_cdc_dai_tx2",
+		.id = AIF3_SVA,
+		.capture = { /* Support maximum range */
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+	{
+		.name = "msm_dig_cdc_dai_vifeed",
+		.id = AIF2_VIFEED,
+		.capture = { /* Support maximum range */
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		 .ops = &msm_dig_dai_ops,
+	},
+};
+
+static struct regmap *msm_digital_get_regmap(struct device *dev)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev);
+
+	return msm_dig_cdc->regmap;
+}
+
+static int msm_dig_cdc_suspend(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+	msm_dig_cdc->dapm_bias_off = 1;
+	return 0;
+}
+
+static int msm_dig_cdc_resume(struct snd_soc_codec *codec)
+{
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+	msm_dig_cdc->dapm_bias_off = 0;
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_msm_dig_codec = {
+	.probe  = msm_dig_cdc_soc_probe,
+	.remove = msm_dig_cdc_soc_remove,
+	.suspend = msm_dig_cdc_suspend,
+	.resume = msm_dig_cdc_resume,
+	.get_regmap = msm_digital_get_regmap,
+	.component_driver = {
+		.controls = msm_dig_snd_controls,
+		.num_controls = ARRAY_SIZE(msm_dig_snd_controls),
+		.dapm_widgets = msm_dig_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(msm_dig_dapm_widgets),
+		.dapm_routes = audio_dig_map,
+		.num_dapm_routes = ARRAY_SIZE(audio_dig_map),
+	},
+};
+
+const struct regmap_config msm_digital_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 8,
+	.lock = enable_digital_callback,
+	.unlock = disable_digital_callback,
+	.cache_type = REGCACHE_FLAT,
+	.reg_defaults = msm89xx_cdc_core_defaults,
+	.num_reg_defaults = MSM89XX_CDC_CORE_MAX_REGISTER,
+	.writeable_reg = msm89xx_cdc_core_writeable_reg,
+	.readable_reg = msm89xx_cdc_core_readable_reg,
+	.volatile_reg = msm89xx_cdc_core_volatile_reg,
+	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian = REGMAP_ENDIAN_NATIVE,
+	.max_register = MSM89XX_CDC_CORE_MAX_REGISTER,
+};
+
+static int msm_dig_cdc_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 dig_cdc_addr;
+	struct msm_dig_priv *msm_dig_cdc;
+	struct dig_ctrl_platform_data *pdata;
+
+	msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig_priv),
+			      GFP_KERNEL);
+	if (!msm_dig_cdc)
+		return -ENOMEM;
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: pdata from parent is NULL\n",
+			__func__);
+		ret = -EINVAL;
+		goto rtn;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "reg",
+					&dig_cdc_addr);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+			__func__, "reg");
+		return ret;
+	}
+
+	msm_dig_cdc->dig_base = ioremap(dig_cdc_addr,
+					MSM89XX_CDC_CORE_MAX_REGISTER);
+	if (msm_dig_cdc->dig_base == NULL) {
+		dev_err(&pdev->dev, "%s ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+	msm_dig_cdc->regmap =
+		devm_regmap_init_mmio_clk(&pdev->dev, NULL,
+			msm_dig_cdc->dig_base, &msm_digital_regmap_config);
+
+	msm_dig_cdc->update_clkdiv = pdata->update_clkdiv;
+	msm_dig_cdc->get_cdc_version = pdata->get_cdc_version;
+	msm_dig_cdc->handle = pdata->handle;
+	msm_dig_cdc->register_notifier = pdata->register_notifier;
+
+	dev_set_drvdata(&pdev->dev, msm_dig_cdc);
+	snd_soc_register_codec(&pdev->dev, &soc_msm_dig_codec,
+				msm_codec_dais, ARRAY_SIZE(msm_codec_dais));
+	dev_dbg(&pdev->dev, "%s: registered DIG CODEC 0x%x\n",
+			__func__, dig_cdc_addr);
+rtn:
+	return ret;
+}
+
+static int msm_dig_cdc_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int msm_dig_suspend(struct device *dev)
+{
+	struct msm_asoc_mach_data *pdata;
+	struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev);
+
+	if (!registered_digcodec || !msm_dig_cdc) {
+		pr_debug("%s:digcodec not initialized, return\n", __func__);
+		return 0;
+	}
+	pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card);
+	if (!pdata) {
+		pr_debug("%s:card not initialized, return\n", __func__);
+		return 0;
+	}
+	if (msm_dig_cdc->dapm_bias_off) {
+		pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n",
+			__func__, atomic_read(&pdata->int_mclk0_rsc_ref),
+			atomic_read(&pdata->int_mclk0_enabled));
+
+		if (atomic_read(&pdata->int_mclk0_enabled) == true) {
+			cancel_delayed_work_sync(
+				&pdata->disable_int_mclk0_work);
+			mutex_lock(&pdata->cdc_int_mclk0_mutex);
+			pdata->digital_cdc_core_clk.enable = 0;
+			afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX,
+						&pdata->digital_cdc_core_clk);
+			atomic_set(&pdata->int_mclk0_enabled, false);
+			mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+		}
+	}
+
+	return 0;
+}
+
+static int msm_dig_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops msm_dig_pm_ops = {
+	.suspend_late = msm_dig_suspend,
+	.resume_early = msm_dig_resume,
+};
+#endif
+
+static const struct of_device_id msm_dig_cdc_of_match[] = {
+	{.compatible = "qcom,msm-digital-codec"},
+	{},
+};
+
+static struct platform_driver msm_digcodec_driver = {
+	.driver                 = {
+		.owner          = THIS_MODULE,
+		.name           = DRV_NAME,
+		.of_match_table = msm_dig_cdc_of_match,
+#ifdef CONFIG_PM
+	.pm = &msm_dig_pm_ops,
+#endif
+	},
+	.probe                  = msm_dig_cdc_probe,
+	.remove                 = msm_dig_cdc_remove,
+};
+module_platform_driver(msm_digcodec_driver);
+
+MODULE_DESCRIPTION("MSM Audio Digital codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/sdm660_cdc/msm-digital-cdc.h b/asoc/codecs/sdm660_cdc/msm-digital-cdc.h
new file mode 100644
index 0000000..f0e7a9c
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/msm-digital-cdc.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_DIGITAL_CDC_H
+#define MSM_DIGITAL_CDC_H
+
+#define HPHL_PA_DISABLE (0x01 << 1)
+#define HPHR_PA_DISABLE (0x01 << 2)
+#define SPKR_PA_DISABLE (0x01 << 3)
+
+#define NUM_DECIMATORS	5
+/* Codec supports 1 compander */
+enum {
+	COMPANDER_NONE = 0,
+	COMPANDER_1, /* HPHL/R */
+	COMPANDER_MAX,
+};
+
+/* Number of output I2S port */
+enum {
+	MSM89XX_RX1 = 0,
+	MSM89XX_RX2,
+	MSM89XX_RX3,
+	MSM89XX_RX_MAX,
+};
+
+struct msm_dig_priv {
+	struct snd_soc_codec *codec;
+	u32 comp_enabled[MSM89XX_RX_MAX];
+	int (*codec_hph_comp_gpio)(bool enable, struct snd_soc_codec *codec);
+	s32 dmic_1_2_clk_cnt;
+	s32 dmic_3_4_clk_cnt;
+	bool dec_active[NUM_DECIMATORS];
+	int version;
+	/* Entry for version info */
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+	char __iomem *dig_base;
+	struct regmap *regmap;
+	struct notifier_block nblock;
+	u32 mute_mask;
+	int dapm_bias_off;
+	void *handle;
+	void (*update_clkdiv)(void *handle, int val);
+	int (*get_cdc_version)(void *handle);
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
+};
+
+struct dig_ctrl_platform_data {
+	void *handle;
+	void (*update_clkdiv)(void *handle, int val);
+	int (*get_cdc_version)(void *handle);
+	int (*register_notifier)(void *handle,
+				 struct notifier_block *nblock,
+				 bool enable);
+};
+
+struct hpf_work {
+	struct msm_dig_priv *dig_cdc;
+	u32 decimator;
+	u8 tx_hpf_cut_of_freq;
+	struct delayed_work dwork;
+};
+
+/* Codec supports 5 bands */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_MAX,
+};
+
+extern void msm_dig_cdc_hph_comp_cb(
+		int (*codec_hph_comp_gpio)(
+			bool enable, struct snd_soc_codec *codec),
+		struct snd_soc_codec *codec);
+int msm_dig_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_codec *codec);
+#endif
diff --git a/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c
new file mode 100644
index 0000000..ee4ec34
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.c
@@ -0,0 +1,413 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/pm_qos.h>
+#include <soc/qcom/pm.h>
+#include <sound/soc.h>
+#include "msm-analog-cdc.h"
+#include "sdm660-cdc-irq.h"
+#include "sdm660-cdc-registers.h"
+
+#define MAX_NUM_IRQS 14
+#define NUM_IRQ_REGS 2
+#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 700
+
+#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
+#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
+
+static irqreturn_t wcd9xxx_spmi_irq_handler(int linux_irq, void *data);
+
+char *irq_names[MAX_NUM_IRQS] = {
+	"spk_cnp_int",
+	"spk_clip_int",
+	"spk_ocp_int",
+	"ins_rem_det1",
+	"but_rel_det",
+	"but_press_det",
+	"ins_rem_det",
+	"mbhc_int",
+	"ear_ocp_int",
+	"hphr_ocp_int",
+	"hphl_ocp_det",
+	"ear_cnp_int",
+	"hphr_cnp_int",
+	"hphl_cnp_int"
+};
+
+int order[MAX_NUM_IRQS] = {
+	MSM89XX_IRQ_SPKR_CNP,
+	MSM89XX_IRQ_SPKR_CLIP,
+	MSM89XX_IRQ_SPKR_OCP,
+	MSM89XX_IRQ_MBHC_INSREM_DET1,
+	MSM89XX_IRQ_MBHC_RELEASE,
+	MSM89XX_IRQ_MBHC_PRESS,
+	MSM89XX_IRQ_MBHC_INSREM_DET,
+	MSM89XX_IRQ_MBHC_HS_DET,
+	MSM89XX_IRQ_EAR_OCP,
+	MSM89XX_IRQ_HPHR_OCP,
+	MSM89XX_IRQ_HPHL_OCP,
+	MSM89XX_IRQ_EAR_CNP,
+	MSM89XX_IRQ_HPHR_CNP,
+	MSM89XX_IRQ_HPHL_CNP,
+};
+
+enum wcd9xxx_spmi_pm_state {
+	WCD9XXX_PM_SLEEPABLE,
+	WCD9XXX_PM_AWAKE,
+	WCD9XXX_PM_ASLEEP,
+};
+
+struct wcd9xxx_spmi_map {
+	uint8_t handled[NUM_IRQ_REGS];
+	uint8_t mask[NUM_IRQ_REGS];
+	int linuxirq[MAX_NUM_IRQS];
+	irq_handler_t handler[MAX_NUM_IRQS];
+	struct platform_device *spmi[NUM_IRQ_REGS];
+	struct snd_soc_codec *codec;
+
+	enum wcd9xxx_spmi_pm_state pm_state;
+	struct mutex pm_lock;
+	/* pm_wq notifies change of pm_state */
+	wait_queue_head_t pm_wq;
+	struct pm_qos_request pm_qos_req;
+	int wlock_holders;
+};
+
+struct wcd9xxx_spmi_map map;
+
+void wcd9xxx_spmi_enable_irq(int irq)
+{
+	pr_debug("%s: irqno =%d\n", __func__, irq);
+
+	if (!(map.mask[BIT_BYTE(irq)] & (BYTE_BIT_MASK(irq))))
+		return;
+
+	map.mask[BIT_BYTE(irq)] &=
+		~(BYTE_BIT_MASK(irq));
+
+	enable_irq(map.linuxirq[irq]);
+}
+
+void wcd9xxx_spmi_disable_irq(int irq)
+{
+	pr_debug("%s: irqno =%d\n", __func__, irq);
+
+	if (map.mask[BIT_BYTE(irq)] & (BYTE_BIT_MASK(irq)))
+		return;
+
+	map.mask[BIT_BYTE(irq)] |=
+		(BYTE_BIT_MASK(irq));
+
+	disable_irq_nosync(map.linuxirq[irq]);
+}
+
+int wcd9xxx_spmi_request_irq(int irq, irq_handler_t handler,
+			const char *name, void *priv)
+{
+	int rc;
+	unsigned long irq_flags;
+
+	map.linuxirq[irq] =
+		platform_get_irq_byname(map.spmi[BIT_BYTE(irq)],
+					irq_names[irq]);
+
+	if (strcmp(name, "mbhc sw intr"))
+		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+			IRQF_ONESHOT;
+	else
+		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+			IRQF_ONESHOT | IRQF_NO_SUSPEND;
+	pr_debug("%s: name:%s irq_flags = %lx\n", __func__, name, irq_flags);
+
+	rc = devm_request_threaded_irq(&map.spmi[BIT_BYTE(irq)]->dev,
+				map.linuxirq[irq], NULL,
+				wcd9xxx_spmi_irq_handler,
+				irq_flags,
+				name, priv);
+		if (rc < 0) {
+			dev_err(&map.spmi[BIT_BYTE(irq)]->dev,
+				"Can't request %d IRQ\n", irq);
+			return rc;
+		}
+
+	dev_dbg(&map.spmi[BIT_BYTE(irq)]->dev,
+			"irq %d linuxIRQ: %d\n", irq, map.linuxirq[irq]);
+	map.mask[BIT_BYTE(irq)] &= ~BYTE_BIT_MASK(irq);
+	map.handler[irq] = handler;
+	enable_irq_wake(map.linuxirq[irq]);
+	return 0;
+}
+
+int wcd9xxx_spmi_free_irq(int irq, void *priv)
+{
+	devm_free_irq(&map.spmi[BIT_BYTE(irq)]->dev, map.linuxirq[irq],
+						priv);
+	map.mask[BIT_BYTE(irq)] |= BYTE_BIT_MASK(irq);
+	return 0;
+}
+
+static int get_irq_bit(int linux_irq)
+{
+	int i = 0;
+
+	for (; i < MAX_NUM_IRQS; i++)
+		if (map.linuxirq[i] == linux_irq)
+			return i;
+
+	return i;
+}
+
+static int get_order_irq(int  i)
+{
+	return order[i];
+}
+
+static irqreturn_t wcd9xxx_spmi_irq_handler(int linux_irq, void *data)
+{
+	int irq, i, j;
+	unsigned long status[NUM_IRQ_REGS] = {0};
+
+	if (unlikely(wcd9xxx_spmi_lock_sleep() == false)) {
+		pr_err("Failed to hold suspend\n");
+		return IRQ_NONE;
+	}
+
+	irq = get_irq_bit(linux_irq);
+	if (irq == MAX_NUM_IRQS)
+		return IRQ_HANDLED;
+
+	status[BIT_BYTE(irq)] |= BYTE_BIT_MASK(irq);
+	for (i = 0; i < NUM_IRQ_REGS; i++) {
+		status[i] |= snd_soc_read(map.codec,
+				BIT_BYTE(irq) * 0x100 +
+			MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS);
+		status[i] &= ~map.mask[i];
+	}
+	for (i = 0; i < MAX_NUM_IRQS; i++) {
+		j = get_order_irq(i);
+		if ((status[BIT_BYTE(j)] & BYTE_BIT_MASK(j)) &&
+			((map.handled[BIT_BYTE(j)] &
+			BYTE_BIT_MASK(j)) == 0)) {
+			map.handler[j](irq, data);
+			map.handled[BIT_BYTE(j)] |=
+					BYTE_BIT_MASK(j);
+		}
+	}
+	map.handled[BIT_BYTE(irq)] &= ~BYTE_BIT_MASK(irq);
+	wcd9xxx_spmi_unlock_sleep();
+
+	return IRQ_HANDLED;
+}
+
+enum wcd9xxx_spmi_pm_state wcd9xxx_spmi_pm_cmpxchg(
+		enum wcd9xxx_spmi_pm_state o,
+		enum wcd9xxx_spmi_pm_state n)
+{
+	enum wcd9xxx_spmi_pm_state old;
+
+	mutex_lock(&map.pm_lock);
+	old = map.pm_state;
+	if (old == o)
+		map.pm_state = n;
+	pr_debug("%s: map.pm_state = %d\n", __func__, map.pm_state);
+	mutex_unlock(&map.pm_lock);
+	return old;
+}
+EXPORT_SYMBOL(wcd9xxx_spmi_pm_cmpxchg);
+
+int wcd9xxx_spmi_suspend(pm_message_t pmesg)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	/*
+	 * pm_qos_update_request() can be called after this suspend chain call
+	 * started. thus suspend can be called while lock is being held
+	 */
+	mutex_lock(&map.pm_lock);
+	if (map.pm_state == WCD9XXX_PM_SLEEPABLE) {
+		pr_debug("%s: suspending system, state %d, wlock %d\n",
+			 __func__, map.pm_state,
+			 map.wlock_holders);
+		map.pm_state = WCD9XXX_PM_ASLEEP;
+	} else if (map.pm_state == WCD9XXX_PM_AWAKE) {
+		/*
+		 * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+		 * then set to WCD9XXX_PM_ASLEEP
+		 */
+		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+			 __func__, map.pm_state,
+			 map.wlock_holders);
+		mutex_unlock(&map.pm_lock);
+		if (!(wait_event_timeout(map.pm_wq,
+					 wcd9xxx_spmi_pm_cmpxchg(
+							WCD9XXX_PM_SLEEPABLE,
+							WCD9XXX_PM_ASLEEP) ==
+							WCD9XXX_PM_SLEEPABLE,
+							HZ))) {
+			pr_debug("%s: suspend failed state %d, wlock %d\n",
+				 __func__, map.pm_state,
+				 map.wlock_holders);
+			ret = -EBUSY;
+		} else {
+			pr_debug("%s: done, state %d, wlock %d\n", __func__,
+				 map.pm_state,
+				 map.wlock_holders);
+		}
+		mutex_lock(&map.pm_lock);
+	} else if (map.pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_warn("%s: system is already suspended, state %d, wlock %dn",
+			__func__, map.pm_state,
+			map.wlock_holders);
+	}
+	mutex_unlock(&map.pm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_spmi_suspend);
+
+int wcd9xxx_spmi_resume(void)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	mutex_lock(&map.pm_lock);
+	if (map.pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+				map.pm_state,
+				map.wlock_holders);
+		map.pm_state = WCD9XXX_PM_SLEEPABLE;
+	} else {
+		pr_warn("%s: system is already awake, state %d wlock %d\n",
+				__func__, map.pm_state,
+				map.wlock_holders);
+	}
+	mutex_unlock(&map.pm_lock);
+	wake_up_all(&map.pm_wq);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_spmi_resume);
+
+bool wcd9xxx_spmi_lock_sleep(void)
+{
+	/*
+	 * wcd9xxx_spmi_{lock/unlock}_sleep will be called by
+	 * wcd9xxx_spmi_irq_thread
+	 * and its subroutines only motly.
+	 * but btn0_lpress_fn is not wcd9xxx_spmi_irq_thread's subroutine and
+	 * It can race with wcd9xxx_spmi_irq_thread.
+	 * So need to embrace wlock_holders with mutex.
+	 */
+	mutex_lock(&map.pm_lock);
+	if (map.wlock_holders++ == 0) {
+		pr_debug("%s: holding wake lock\n", __func__);
+		pm_qos_update_request(&map.pm_qos_req,
+				      msm_cpuidle_get_deep_idle_latency());
+		pm_stay_awake(&map.spmi[0]->dev);
+	}
+	mutex_unlock(&map.pm_lock);
+	pr_debug("%s: wake lock counter %d\n", __func__,
+			map.wlock_holders);
+	pr_debug("%s: map.pm_state = %d\n", __func__, map.pm_state);
+
+	if (!wait_event_timeout(map.pm_wq,
+				((wcd9xxx_spmi_pm_cmpxchg(
+					WCD9XXX_PM_SLEEPABLE,
+					WCD9XXX_PM_AWAKE)) ==
+					WCD9XXX_PM_SLEEPABLE ||
+					(wcd9xxx_spmi_pm_cmpxchg(
+						 WCD9XXX_PM_SLEEPABLE,
+						 WCD9XXX_PM_AWAKE) ==
+						 WCD9XXX_PM_AWAKE)),
+					msecs_to_jiffies(
+					WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
+		pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
+			__func__,
+			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, map.pm_state,
+			map.wlock_holders);
+		wcd9xxx_spmi_unlock_sleep();
+		return false;
+	}
+	wake_up_all(&map.pm_wq);
+	pr_debug("%s: leaving pm_state = %d\n", __func__, map.pm_state);
+	return true;
+}
+EXPORT_SYMBOL(wcd9xxx_spmi_lock_sleep);
+
+void wcd9xxx_spmi_unlock_sleep(void)
+{
+	mutex_lock(&map.pm_lock);
+	if (--map.wlock_holders == 0) {
+		pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
+			 __func__, map.pm_state, WCD9XXX_PM_SLEEPABLE);
+		/*
+		 * if wcd9xxx_spmi_lock_sleep failed, pm_state would be still
+		 * WCD9XXX_PM_ASLEEP, don't overwrite
+		 */
+		if (likely(map.pm_state == WCD9XXX_PM_AWAKE))
+			map.pm_state = WCD9XXX_PM_SLEEPABLE;
+		pm_qos_update_request(&map.pm_qos_req,
+				PM_QOS_DEFAULT_VALUE);
+		pm_relax(&map.spmi[0]->dev);
+	}
+	mutex_unlock(&map.pm_lock);
+	pr_debug("%s: wake lock counter %d\n", __func__,
+			map.wlock_holders);
+	pr_debug("%s: map.pm_state = %d\n", __func__, map.pm_state);
+	wake_up_all(&map.pm_wq);
+}
+EXPORT_SYMBOL(wcd9xxx_spmi_unlock_sleep);
+
+void wcd9xxx_spmi_set_codec(struct snd_soc_codec *codec)
+{
+	map.codec = codec;
+}
+
+void wcd9xxx_spmi_set_dev(struct platform_device *spmi, int i)
+{
+	if (i < NUM_IRQ_REGS)
+		map.spmi[i] = spmi;
+}
+
+int wcd9xxx_spmi_irq_init(void)
+{
+	int i = 0;
+
+	for (; i < MAX_NUM_IRQS; i++)
+		map.mask[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+	mutex_init(&map.pm_lock);
+	map.wlock_holders = 0;
+	map.pm_state = WCD9XXX_PM_SLEEPABLE;
+	init_waitqueue_head(&map.pm_wq);
+	pm_qos_add_request(&map.pm_qos_req,
+				PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
+	return 0;
+}
+
+MODULE_DESCRIPTION("MSM8x16 SPMI IRQ driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h
new file mode 100644
index 0000000..d0f48d0
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/sdm660-cdc-irq.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD9XXX_SPMI_IRQ_H__
+#define __WCD9XXX_SPMI_IRQ_H__
+
+#include <sound/soc.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/pm_qos.h>
+
+extern void wcd9xxx_spmi_enable_irq(int irq);
+extern void wcd9xxx_spmi_disable_irq(int irq);
+extern int wcd9xxx_spmi_request_irq(int irq, irq_handler_t handler,
+				const char *name, void *priv);
+extern int wcd9xxx_spmi_free_irq(int irq, void *priv);
+extern void wcd9xxx_spmi_set_codec(struct snd_soc_codec *codec);
+extern void wcd9xxx_spmi_set_dev(struct platform_device *spmi, int i);
+extern int wcd9xxx_spmi_irq_init(void);
+extern int wcd9xxx_spmi_suspend(pm_message_t pmesg);
+extern int wcd9xxx_spmi_resume(void);
+bool wcd9xxx_spmi_lock_sleep(void);
+void wcd9xxx_spmi_unlock_sleep(void);
+
+#endif
diff --git a/asoc/codecs/sdm660_cdc/sdm660-cdc-registers.h b/asoc/codecs/sdm660_cdc/sdm660-cdc-registers.h
new file mode 100644
index 0000000..1317ce1
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/sdm660-cdc-registers.h
@@ -0,0 +1,603 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef SDM660_WCD_REGISTERS_H
+#define SDM660_WCD_REGISTERS_H
+
+#define CDC_DIG_BASE		0xF000
+#define CDC_ANA_BASE		0xF100
+
+#define MSM89XX_PMIC_DIGITAL_REVISION1		(CDC_DIG_BASE+0x000)
+#define MSM89XX_PMIC_DIGITAL_REVISION1__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_REVISION2		(CDC_DIG_BASE+0x001)
+#define MSM89XX_PMIC_DIGITAL_REVISION2__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_PERPH_TYPE		(CDC_DIG_BASE+0x004)
+#define MSM89XX_PMIC_DIGITAL_PERPH_TYPE__POR		(0x23)
+#define MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE		(CDC_DIG_BASE+0x005)
+#define MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE__POR		(0x01)
+#define MSM89XX_PMIC_DIGITAL_INT_RT_STS		(CDC_DIG_BASE+0x010)
+#define MSM89XX_PMIC_DIGITAL_INT_RT_STS__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_SET_TYPE		(CDC_DIG_BASE+0x011)
+#define MSM89XX_PMIC_DIGITAL_INT_SET_TYPE__POR		(0xFF)
+#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH		(CDC_DIG_BASE+0x012)
+#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH__POR		(0xFF)
+#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW		(CDC_DIG_BASE+0x013)
+#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR		(CDC_DIG_BASE+0x014)
+#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_EN_SET		(CDC_DIG_BASE+0x015)
+#define MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_EN_CLR		(CDC_DIG_BASE+0x016)
+#define MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS		(CDC_DIG_BASE+0x018)
+#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_PENDING_STS		(CDC_DIG_BASE+0x019)
+#define MSM89XX_PMIC_DIGITAL_INT_PENDING_STS__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_MID_SEL		(CDC_DIG_BASE+0x01A)
+#define MSM89XX_PMIC_DIGITAL_INT_MID_SEL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_PRIORITY		(CDC_DIG_BASE+0x01B)
+#define MSM89XX_PMIC_DIGITAL_INT_PRIORITY__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_GPIO_MODE		(CDC_DIG_BASE+0x040)
+#define MSM89XX_PMIC_DIGITAL_GPIO_MODE__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_PIN_CTL_OE		(CDC_DIG_BASE+0x041)
+#define MSM89XX_PMIC_DIGITAL_PIN_CTL_OE__POR		(0x01)
+#define MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA		(CDC_DIG_BASE+0x042)
+#define MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_PIN_STATUS		(CDC_DIG_BASE+0x043)
+#define MSM89XX_PMIC_DIGITAL_PIN_STATUS__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_HDRIVE_CTL		(CDC_DIG_BASE+0x044)
+#define MSM89XX_PMIC_DIGITAL_HDRIVE_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_RST_CTL		(CDC_DIG_BASE+0x046)
+#define MSM89XX_PMIC_DIGITAL_CDC_RST_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL		(CDC_DIG_BASE+0x048)
+#define MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL		(CDC_DIG_BASE+0x049)
+#define MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL		(CDC_DIG_BASE+0x04A)
+#define MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL		(CDC_DIG_BASE+0x050)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL__POR		(0x02)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL		(CDC_DIG_BASE+0x051)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL__POR		(0x02)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL	(CDC_DIG_BASE+0x052)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL		(CDC_DIG_BASE+0x053)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL		(CDC_DIG_BASE+0x054)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL		(CDC_DIG_BASE+0x055)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL	(CDC_DIG_BASE+0x056)
+#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1		(CDC_DIG_BASE+0x058)
+#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1__POR		(0x7C)
+#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2		(CDC_DIG_BASE+0x059)
+#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2__POR		(0x7C)
+#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3		(CDC_DIG_BASE+0x05A)
+#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3__POR		(0x7C)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0		(CDC_DIG_BASE+0x05B)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1		(CDC_DIG_BASE+0x05C)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2		(CDC_DIG_BASE+0x05D)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3		(CDC_DIG_BASE+0x05E)
+#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL		(CDC_DIG_BASE+0x068)
+#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_EN		(CDC_DIG_BASE+0x069)
+#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_EN__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_SPARE_0		(CDC_DIG_BASE+0x070)
+#define MSM89XX_PMIC_DIGITAL_SPARE_0__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_SPARE_1		(CDC_DIG_BASE+0x071)
+#define MSM89XX_PMIC_DIGITAL_SPARE_1__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_SPARE_2		(CDC_DIG_BASE+0x072)
+#define MSM89XX_PMIC_DIGITAL_SPARE_2__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_SEC_ACCESS		(CDC_DIG_BASE+0x0D0)
+#define MSM89XX_PMIC_DIGITAL_SEC_ACCESS__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL1		(CDC_DIG_BASE+0x0D8)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL1__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL2		(CDC_DIG_BASE+0x0D9)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL2__POR		(0x01)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3		(CDC_DIG_BASE+0x0DA)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3__POR		(0x05)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4		(CDC_DIG_BASE+0x0DB)
+#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_TEST1		(CDC_DIG_BASE+0x0E0)
+#define MSM89XX_PMIC_DIGITAL_INT_TEST1__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_INT_TEST_VAL		(CDC_DIG_BASE+0x0E1)
+#define MSM89XX_PMIC_DIGITAL_INT_TEST_VAL__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_TRIM_NUM		(CDC_DIG_BASE+0x0F0)
+#define MSM89XX_PMIC_DIGITAL_TRIM_NUM__POR		(0x00)
+#define MSM89XX_PMIC_DIGITAL_TRIM_CTRL		(CDC_DIG_BASE+0x0F1)
+#define MSM89XX_PMIC_DIGITAL_TRIM_CTRL__POR		(0x00)
+
+#define MSM89XX_PMIC_ANALOG_REVISION1		(CDC_ANA_BASE+0x00)
+#define MSM89XX_PMIC_ANALOG_REVISION1__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_REVISION2		(CDC_ANA_BASE+0x01)
+#define MSM89XX_PMIC_ANALOG_REVISION2__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_REVISION3		(CDC_ANA_BASE+0x02)
+#define MSM89XX_PMIC_ANALOG_REVISION3__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_REVISION4		(CDC_ANA_BASE+0x03)
+#define MSM89XX_PMIC_ANALOG_REVISION4__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_PERPH_TYPE		(CDC_ANA_BASE+0x04)
+#define MSM89XX_PMIC_ANALOG_PERPH_TYPE__POR		(0x23)
+#define MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE		(CDC_ANA_BASE+0x05)
+#define MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE__POR		(0x09)
+#define MSM89XX_PMIC_ANALOG_INT_RT_STS		(CDC_ANA_BASE+0x10)
+#define MSM89XX_PMIC_ANALOG_INT_RT_STS__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_SET_TYPE		(CDC_ANA_BASE+0x11)
+#define MSM89XX_PMIC_ANALOG_INT_SET_TYPE__POR		(0x3F)
+#define MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH		(CDC_ANA_BASE+0x12)
+#define MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH__POR		(0x3F)
+#define MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW		(CDC_ANA_BASE+0x13)
+#define MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR		(CDC_ANA_BASE+0x14)
+#define MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_EN_SET		(CDC_ANA_BASE+0x15)
+#define MSM89XX_PMIC_ANALOG_INT_EN_SET__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_EN_CLR		(CDC_ANA_BASE+0x16)
+#define MSM89XX_PMIC_ANALOG_INT_EN_CLR__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_LATCHED_STS		(CDC_ANA_BASE+0x18)
+#define MSM89XX_PMIC_ANALOG_INT_LATCHED_STS__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_PENDING_STS		(CDC_ANA_BASE+0x19)
+#define MSM89XX_PMIC_ANALOG_INT_PENDING_STS__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_MID_SEL		(CDC_ANA_BASE+0x1A)
+#define MSM89XX_PMIC_ANALOG_INT_MID_SEL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_PRIORITY		(CDC_ANA_BASE+0x1B)
+#define MSM89XX_PMIC_ANALOG_INT_PRIORITY__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MICB_1_EN		(CDC_ANA_BASE+0x40)
+#define MSM89XX_PMIC_ANALOG_MICB_1_EN__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MICB_1_VAL		(CDC_ANA_BASE+0x41)
+#define MSM89XX_PMIC_ANALOG_MICB_1_VAL__POR		(0x20)
+#define MSM89XX_PMIC_ANALOG_MICB_1_CTL		(CDC_ANA_BASE+0x42)
+#define MSM89XX_PMIC_ANALOG_MICB_1_CTL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS		(CDC_ANA_BASE+0x43)
+#define MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS__POR		(0x49)
+#define MSM89XX_PMIC_ANALOG_MICB_2_EN		(CDC_ANA_BASE+0x44)
+#define MSM89XX_PMIC_ANALOG_MICB_2_EN__POR		(0x20)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2		(CDC_ANA_BASE+0x45)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL		(CDC_ANA_BASE+0x46)
+#define MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1		(CDC_ANA_BASE+0x47)
+#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1__POR		(0x35)
+#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2		(CDC_ANA_BASE+0x50)
+#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2__POR		(0x08)
+#define MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL		(CDC_ANA_BASE+0x51)
+#define MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER		(CDC_ANA_BASE+0x52)
+#define MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER__POR		(0x98)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL	(CDC_ANA_BASE+0x53)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL	(CDC_ANA_BASE+0x54)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL__POR		(0x20)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL	(CDC_ANA_BASE+0x55)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL__POR		(0x40)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL		(CDC_ANA_BASE+0x56)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL__POR		(0x61)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL		(CDC_ANA_BASE+0x57)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL__POR		(0x80)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT		(CDC_ANA_BASE+0x58)
+#define MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT	(CDC_ANA_BASE+0x59)
+#define MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT__POR	(0x00)
+#define MSM89XX_PMIC_ANALOG_TX_1_EN		(CDC_ANA_BASE+0x60)
+#define MSM89XX_PMIC_ANALOG_TX_1_EN__POR		(0x03)
+#define MSM89XX_PMIC_ANALOG_TX_2_EN		(CDC_ANA_BASE+0x61)
+#define MSM89XX_PMIC_ANALOG_TX_2_EN__POR		(0x03)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1		(CDC_ANA_BASE+0x62)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1__POR		(0xBF)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2		(CDC_ANA_BASE+0x63)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2__POR		(0x8C)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL		(CDC_ANA_BASE+0x64)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS		(CDC_ANA_BASE+0x65)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS__POR		(0x6B)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV		(CDC_ANA_BASE+0x66)
+#define MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV__POR		(0x51)
+#define MSM89XX_PMIC_ANALOG_TX_3_EN		(CDC_ANA_BASE+0x67)
+#define MSM89XX_PMIC_ANALOG_TX_3_EN__POR		(0x02)
+#define MSM89XX_PMIC_ANALOG_NCP_EN		(CDC_ANA_BASE+0x80)
+#define MSM89XX_PMIC_ANALOG_NCP_EN__POR		(0x26)
+#define MSM89XX_PMIC_ANALOG_NCP_CLK		(CDC_ANA_BASE+0x81)
+#define MSM89XX_PMIC_ANALOG_NCP_CLK__POR		(0x23)
+#define MSM89XX_PMIC_ANALOG_NCP_DEGLITCH		(CDC_ANA_BASE+0x82)
+#define MSM89XX_PMIC_ANALOG_NCP_DEGLITCH__POR		(0x5B)
+#define MSM89XX_PMIC_ANALOG_NCP_FBCTRL		(CDC_ANA_BASE+0x83)
+#define MSM89XX_PMIC_ANALOG_NCP_FBCTRL__POR		(0x08)
+#define MSM89XX_PMIC_ANALOG_NCP_BIAS		(CDC_ANA_BASE+0x84)
+#define MSM89XX_PMIC_ANALOG_NCP_BIAS__POR		(0x29)
+#define MSM89XX_PMIC_ANALOG_NCP_VCTRL		(CDC_ANA_BASE+0x85)
+#define MSM89XX_PMIC_ANALOG_NCP_VCTRL__POR		(0x24)
+#define MSM89XX_PMIC_ANALOG_NCP_TEST		(CDC_ANA_BASE+0x86)
+#define MSM89XX_PMIC_ANALOG_NCP_TEST__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR		(CDC_ANA_BASE+0x87)
+#define MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR__POR		(0xD5)
+#define MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER		(CDC_ANA_BASE+0x90)
+#define MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER__POR		(0xE8)
+#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL		(CDC_ANA_BASE+0x91)
+#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL__POR		(0xCF)
+#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT		(CDC_ANA_BASE+0x92)
+#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT__POR		(0x6E)
+#define MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC		(CDC_ANA_BASE+0x93)
+#define MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC__POR		(0x18)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA		(CDC_ANA_BASE+0x94)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA__POR		(0x5A)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP	(CDC_ANA_BASE+0x95)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP__POR		(0x69)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP		(CDC_ANA_BASE+0x96)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP__POR		(0x29)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN		(CDC_ANA_BASE+0x97)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN__POR		(0x80)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL		(CDC_ANA_BASE+0x98)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL__POR		(0xDA)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME		(CDC_ANA_BASE+0x99)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME__POR		(0x16)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST		(CDC_ANA_BASE+0x9A)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL	(CDC_ANA_BASE+0x9B)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL__POR		(0x20)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST		(CDC_ANA_BASE+0x9C)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL	(CDC_ANA_BASE+0x9D)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL__POR		(0x20)
+#define MSM89XX_PMIC_ANALOG_RX_EAR_CTL		(CDC_ANA_BASE+0x9E)
+#define MSM89XX_PMIC_ANALOG_RX_EAR_CTL___POR		(0x12)
+#define MSM89XX_PMIC_ANALOG_RX_ATEST		(CDC_ANA_BASE+0x9F)
+#define MSM89XX_PMIC_ANALOG_RX_ATEST__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_STATUS		(CDC_ANA_BASE+0xA0)
+#define MSM89XX_PMIC_ANALOG_RX_HPH_STATUS__POR		(0x0C)
+#define MSM89XX_PMIC_ANALOG_RX_EAR_STATUS		(CDC_ANA_BASE+0xA1)
+#define MSM89XX_PMIC_ANALOG_RX_EAR_STATUS__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL		(CDC_ANA_BASE+0xAC)
+#define MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL		(CDC_ANA_BASE+0xAD)
+#define MSM89XX_PMIC_ANALOG_RX_RX_LO_EN_CTL__POR	(0x00)
+#define MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL		(CDC_ANA_BASE+0xB0)
+#define MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL__POR		(0x83)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET		(CDC_ANA_BASE+0xB1)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET__POR		(0x91)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL		(CDC_ANA_BASE+0xB2)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL__POR		(0x29)
+#define MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET		(CDC_ANA_BASE+0xB3)
+#define MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET__POR		(0x4D)
+#define MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL		(CDC_ANA_BASE+0xB4)
+#define MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL__POR		(0xE1)
+#define MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL		(CDC_ANA_BASE+0xB5)
+#define MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL__POR		(0x1E)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC		(CDC_ANA_BASE+0xB6)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC__POR		(0xCB)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG		(CDC_ANA_BASE+0xB7)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_CURRENT_LIMIT		(CDC_ANA_BASE+0xC0)
+#define MSM89XX_PMIC_ANALOG_CURRENT_LIMIT__POR		(0x02)
+#define MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE		(CDC_ANA_BASE+0xC1)
+#define MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE__POR		(0x14)
+#define MSM89XX_PMIC_ANALOG_BYPASS_MODE		(CDC_ANA_BASE+0xC2)
+#define MSM89XX_PMIC_ANALOG_BYPASS_MODE__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_BOOST_EN_CTL		(CDC_ANA_BASE+0xC3)
+#define MSM89XX_PMIC_ANALOG_BOOST_EN_CTL__POR		(0x1F)
+#define MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO		(CDC_ANA_BASE+0xC4)
+#define MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO__POR		(0x8C)
+#define MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE	(CDC_ANA_BASE+0xC5)
+#define MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE__POR		(0xC0)
+#define MSM89XX_PMIC_ANALOG_BOOST_TEST1_1		(CDC_ANA_BASE+0xC6)
+#define MSM89XX_PMIC_ANALOG_BOOST_TEST1_1__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_BOOST_TEST_2		(CDC_ANA_BASE+0xC7)
+#define MSM89XX_PMIC_ANALOG_BOOST_TEST_2__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS		(CDC_ANA_BASE+0xC8)
+#define MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS		(CDC_ANA_BASE+0xC9)
+#define MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR		(CDC_ANA_BASE+0xCE)
+#define MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL		(CDC_ANA_BASE+0xCF)
+#define MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_SEC_ACCESS		(CDC_ANA_BASE+0xD0)
+#define MSM89XX_PMIC_ANALOG_SEC_ACCESS__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL1		(CDC_ANA_BASE+0xD8)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL1__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL2		(CDC_ANA_BASE+0xD9)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL2__POR		(0x01)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3		(CDC_ANA_BASE+0xDA)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3__POR		(0x05)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4		(CDC_ANA_BASE+0xDB)
+#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_TEST1		(CDC_ANA_BASE+0xE0)
+#define MSM89XX_PMIC_ANALOG_INT_TEST1__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_INT_TEST_VAL		(CDC_ANA_BASE+0xE1)
+#define MSM89XX_PMIC_ANALOG_INT_TEST_VAL__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_TRIM_NUM		(CDC_ANA_BASE+0xF0)
+#define MSM89XX_PMIC_ANALOG_TRIM_NUM__POR		(0x04)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL1		(CDC_ANA_BASE+0xF1)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL1__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL2		(CDC_ANA_BASE+0xF2)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL2__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL3		(CDC_ANA_BASE+0xF3)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL3__POR		(0x00)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL4		(CDC_ANA_BASE+0xF4)
+#define MSM89XX_PMIC_ANALOG_TRIM_CTRL4__POR		(0x00)
+
+#define MSM89XX_PMIC_CDC_NUM_REGISTERS \
+		(MSM89XX_PMIC_ANALOG_TRIM_CTRL4+1)
+#define MSM89XX_PMIC_CDC_MAX_REGISTER \
+		(MSM89XX_PMIC_CDC_NUM_REGISTERS-1)
+#define MSM89XX_PMIC_CDC_CACHE_SIZE \
+		MSM89XX_PMIC_CDC_NUM_REGISTERS
+
+
+#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL	(0x00)
+#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL	(0x04)
+#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL	(0x08)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL		(0x0C)
+#define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL__POR		(0x13)
+#define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL		(0x10)
+#define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL__POR		(0x13)
+#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL	(0x14)
+#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL	(0x18)
+#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_CLK_OTHR_CTL		(0x1C)
+#define MSM89XX_CDC_CORE_CLK_OTHR_CTL__POR		(0x04)
+#define MSM89XX_CDC_CORE_CLK_RX_B1_CTL		(0x20)
+#define MSM89XX_CDC_CORE_CLK_RX_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_MCLK_CTL		(0x24)
+#define MSM89XX_CDC_CORE_CLK_MCLK_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_PDM_CTL		(0x28)
+#define MSM89XX_CDC_CORE_CLK_PDM_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_SD_CTL		(0x2C)
+#define MSM89XX_CDC_CORE_CLK_SD_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL	(0x30)
+#define MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_RX_B2_CTL		(0x34)
+#define MSM89XX_CDC_CORE_CLK_RX_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL	(0x38)
+#define MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL__POR		(0x13)
+#define MSM89XX_CDC_CORE_RX1_B1_CTL		(0x40)
+#define MSM89XX_CDC_CORE_RX1_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX2_B1_CTL		(0x60)
+#define MSM89XX_CDC_CORE_RX2_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX3_B1_CTL		(0x80)
+#define MSM89XX_CDC_CORE_RX3_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX1_B2_CTL		(0x44)
+#define MSM89XX_CDC_CORE_RX1_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX2_B2_CTL		(0x64)
+#define MSM89XX_CDC_CORE_RX2_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX3_B2_CTL		(0x84)
+#define MSM89XX_CDC_CORE_RX3_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX1_B3_CTL		(0x48)
+#define MSM89XX_CDC_CORE_RX1_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX2_B3_CTL		(0x68)
+#define MSM89XX_CDC_CORE_RX2_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX3_B3_CTL		(0x88)
+#define MSM89XX_CDC_CORE_RX3_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX1_B4_CTL		(0x4C)
+#define MSM89XX_CDC_CORE_RX1_B4_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX2_B4_CTL		(0x6C)
+#define MSM89XX_CDC_CORE_RX2_B4_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX3_B4_CTL		(0x8C)
+#define MSM89XX_CDC_CORE_RX3_B4_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX1_B5_CTL		(0x50)
+#define MSM89XX_CDC_CORE_RX1_B5_CTL__POR		(0x68)
+#define MSM89XX_CDC_CORE_RX2_B5_CTL		(0x70)
+#define MSM89XX_CDC_CORE_RX2_B5_CTL__POR		(0x68)
+#define MSM89XX_CDC_CORE_RX3_B5_CTL		(0x90)
+#define MSM89XX_CDC_CORE_RX3_B5_CTL__POR		(0x68)
+#define MSM89XX_CDC_CORE_RX1_B6_CTL		(0x54)
+#define MSM89XX_CDC_CORE_RX1_B6_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX2_B6_CTL		(0x74)
+#define MSM89XX_CDC_CORE_RX2_B6_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX3_B6_CTL		(0x94)
+#define MSM89XX_CDC_CORE_RX3_B6_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL	(0x58)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL	(0x78)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL	(0x98)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL	(0x5C)
+#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL	(0x7C)
+#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL	(0x9C)
+#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE	(0xA0)
+#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE__POR		(0x00)
+#define MSM89XX_CDC_CORE_TOP_CTL		(0xA4)
+#define MSM89XX_CDC_CORE_TOP_CTL__POR			(0x01)
+#define MSM89XX_CDC_CORE_COMP0_B1_CTL		(0xB0)
+#define MSM89XX_CDC_CORE_COMP0_B1_CTL__POR		(0x30)
+#define MSM89XX_CDC_CORE_COMP0_B2_CTL		(0xB4)
+#define MSM89XX_CDC_CORE_COMP0_B2_CTL__POR		(0xB5)
+#define MSM89XX_CDC_CORE_COMP0_B3_CTL		(0xB8)
+#define MSM89XX_CDC_CORE_COMP0_B3_CTL__POR		(0x28)
+#define MSM89XX_CDC_CORE_COMP0_B4_CTL		(0xBC)
+#define MSM89XX_CDC_CORE_COMP0_B4_CTL__POR		(0x37)
+#define MSM89XX_CDC_CORE_COMP0_B5_CTL		(0xC0)
+#define MSM89XX_CDC_CORE_COMP0_B5_CTL__POR		(0x7F)
+#define MSM89XX_CDC_CORE_COMP0_B6_CTL		(0xC4)
+#define MSM89XX_CDC_CORE_COMP0_B6_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS	(0xC8)
+#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS__POR	(0x03)
+#define MSM89XX_CDC_CORE_COMP0_FS_CFG		(0xCC)
+#define MSM89XX_CDC_CORE_COMP0_FS_CFG__POR		(0x03)
+#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL	(0xD0)
+#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL__POR	(0x02)
+#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL	(0xE0)
+#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL	(0xE4)
+#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG	(0xE8)
+#define MSM89XX_CDC_CORE_DEBUG_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG	(0xEC)
+#define MSM89XX_CDC_CORE_DEBUG_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG	(0xF0)
+#define MSM89XX_CDC_CORE_DEBUG_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL	(0x100)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL	(0x140)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL	(0x104)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL	(0x144)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL	(0x108)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL	(0x148)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL	(0x10C)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL	(0x14C)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL	(0x110)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL	(0x150)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL	(0x114)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL	(0x154)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL	(0x118)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL	(0x158)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL	(0x11C)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL	(0x15C)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_CTL		(0x120)
+#define MSM89XX_CDC_CORE_IIR1_CTL__POR			(0x40)
+#define MSM89XX_CDC_CORE_IIR2_CTL		(0x160)
+#define MSM89XX_CDC_CORE_IIR2_CTL__POR			(0x40)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL	(0x124)
+#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL	(0x164)
+#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL	(0x128)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL	(0x168)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL	(0x12C)
+#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL	(0x16C)
+#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL	(0x180)
+#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL	(0x184)
+#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL	(0x188)
+#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL	(0x18C)
+#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL	(0x190)
+#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL	(0x194)
+#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL	(0x198)
+#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL	(0x19C)
+#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_TX_B1_CTL		(0x1A0)
+#define MSM89XX_CDC_CORE_CONN_TX_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_TX_B2_CTL		(0x1A4)
+#define MSM89XX_CDC_CORE_CONN_TX_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL	(0x1A8)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL	(0x1AC)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL	(0x1B0)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL	(0x1B4)
+#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL	(0x1B8)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL	(0x1BC)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL	(0x1C0)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL	(0x1C4)
+#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL	(0x1C8)
+#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL__POR	(0x00)
+#define MSM89XX_CDC_CORE_CONN_TX_B3_CTL		(0x1CC)
+#define MSM89XX_CDC_CORE_CONN_TX_B3_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER	(0x1E0)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN	(0x1E4)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG	(0x1E8)
+#define MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_MUX_CTL		(0x1EC)
+#define MSM89XX_CDC_CORE_TX5_MUX_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX5_CLK_FS_CTL		(0x1F0)
+#define MSM89XX_CDC_CORE_TX5_CLK_FS_CTL__POR		(0x03)
+#define MSM89XX_CDC_CORE_TX5_DMIC_CTL		(0x1F4)
+#define MSM89XX_CDC_CORE_TX5_DMIC_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER	(0x280)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER	(0x2A0)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER	(0x2C0)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER	(0x2E0)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN	(0x284)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN	(0x2A4)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN	(0x2C4)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN	(0x2E4)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG	(0x288)
+#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG	(0x2A8)
+#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG	(0x2C8)
+#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG	(0x2E8)
+#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX1_MUX_CTL		(0x28C)
+#define MSM89XX_CDC_CORE_TX1_MUX_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX2_MUX_CTL		(0x2AC)
+#define MSM89XX_CDC_CORE_TX2_MUX_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX3_MUX_CTL		(0x2CC)
+#define MSM89XX_CDC_CORE_TX3_MUX_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX4_MUX_CTL		(0x2EC)
+#define MSM89XX_CDC_CORE_TX4_MUX_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX1_CLK_FS_CTL		(0x290)
+#define MSM89XX_CDC_CORE_TX1_CLK_FS_CTL__POR		(0x03)
+#define MSM89XX_CDC_CORE_TX2_CLK_FS_CTL		(0x2B0)
+#define MSM89XX_CDC_CORE_TX2_CLK_FS_CTL__POR		(0x03)
+#define MSM89XX_CDC_CORE_TX3_CLK_FS_CTL		(0x2D0)
+#define MSM89XX_CDC_CORE_TX3_CLK_FS_CTL__POR		(0x03)
+#define MSM89XX_CDC_CORE_TX4_CLK_FS_CTL		(0x2F0)
+#define MSM89XX_CDC_CORE_TX4_CLK_FS_CTL__POR		(0x03)
+#define MSM89XX_CDC_CORE_TX1_DMIC_CTL		(0x294)
+#define MSM89XX_CDC_CORE_TX1_DMIC_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX2_DMIC_CTL		(0x2B4)
+#define MSM89XX_CDC_CORE_TX2_DMIC_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX3_DMIC_CTL		(0x2D4)
+#define MSM89XX_CDC_CORE_TX3_DMIC_CTL__POR		(0x00)
+#define MSM89XX_CDC_CORE_TX4_DMIC_CTL		(0x2F4)
+#define MSM89XX_CDC_CORE_TX4_DMIC_CTL__POR		(0x00)
+
+#define MSM89XX_CDC_CORE_NUM_REGISTERS \
+		(MSM89XX_CDC_CORE_TX4_DMIC_CTL+1)
+#define MSM89XX_CDC_CORE_MAX_REGISTER \
+		(MSM89XX_CDC_CORE_NUM_REGISTERS-1)
+#define MSM89XX_CDC_CORE_CACHE_SIZE \
+		MSM89XX_CDC_CORE_NUM_REGISTERS
+#endif
diff --git a/asoc/codecs/sdm660_cdc/sdm660-regmap.c b/asoc/codecs/sdm660_cdc/sdm660-regmap.c
new file mode 100644
index 0000000..7d8ac6d
--- /dev/null
+++ b/asoc/codecs/sdm660_cdc/sdm660-regmap.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include "msm-cdc-common.h"
+#include "sdm660-cdc-registers.h"
+
+/*
+ * Default register reset values that are common across different versions
+ * are defined here. If a register reset value is changed based on version
+ * then remove it from this structure and add it in version specific
+ * structures.
+ */
+struct reg_default
+	msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE] = {
+	{MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x13},
+	{MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 0x13},
+	{MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_OTHR_CTL, 0x04},
+	{MSM89XX_CDC_CORE_CLK_RX_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_SD_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL, 0x13},
+	{MSM89XX_CDC_CORE_RX1_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX2_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX3_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX1_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX2_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX3_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX1_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX2_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX3_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX1_B4_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX2_B4_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX3_B4_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX1_B5_CTL, 0x68},
+	{MSM89XX_CDC_CORE_RX2_B5_CTL, 0x68},
+	{MSM89XX_CDC_CORE_RX3_B5_CTL, 0x68},
+	{MSM89XX_CDC_CORE_RX1_B6_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX2_B6_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX3_B6_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TOP_GAIN_UPDATE, 0x00},
+	{MSM89XX_CDC_CORE_TOP_CTL, 0x01},
+	{MSM89XX_CDC_CORE_COMP0_B1_CTL, 0x30},
+	{MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xB5},
+	{MSM89XX_CDC_CORE_COMP0_B3_CTL, 0x28},
+	{MSM89XX_CDC_CORE_COMP0_B4_CTL, 0x37},
+	{MSM89XX_CDC_CORE_COMP0_B5_CTL, 0x7F},
+	{MSM89XX_CDC_CORE_COMP0_B6_CTL, 0x00},
+	{MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS, 0x03},
+	{MSM89XX_CDC_CORE_COMP0_FS_CFG, 0x03},
+	{MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL, 0x02},
+	{MSM89XX_CDC_CORE_DEBUG_DESER1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_DEBUG_DESER2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_CTL, 0x40},
+	{MSM89XX_CDC_CORE_IIR2_CTL, 0x40},
+	{MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX1_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX1_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX1_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX2_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX2_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_RX3_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_TX_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_TX_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL, 0x00},
+	{MSM89XX_CDC_CORE_CONN_TX_B3_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER, 0x00},
+	{MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN, 0x00},
+	{MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_TX5_MUX_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX5_CLK_FS_CTL, 0x03},
+	{MSM89XX_CDC_CORE_TX5_DMIC_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER, 0x00},
+	{MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER, 0x00},
+	{MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER, 0x00},
+	{MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER, 0x00},
+	{MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN, 0x00},
+	{MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN, 0x00},
+	{MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN, 0x00},
+	{MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN, 0x00},
+	{MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG, 0x00},
+	{MSM89XX_CDC_CORE_TX1_MUX_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX2_MUX_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX3_MUX_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX4_MUX_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX1_CLK_FS_CTL, 0x03},
+	{MSM89XX_CDC_CORE_TX2_CLK_FS_CTL, 0x03},
+	{MSM89XX_CDC_CORE_TX3_CLK_FS_CTL, 0x03},
+	{MSM89XX_CDC_CORE_TX4_CLK_FS_CTL, 0x03},
+	{MSM89XX_CDC_CORE_TX1_DMIC_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX2_DMIC_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX3_DMIC_CTL, 0x00},
+	{MSM89XX_CDC_CORE_TX4_DMIC_CTL, 0x00},
+};
+
+struct reg_default
+	msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE] = {
+	{MSM89XX_PMIC_DIGITAL_REVISION1, 0x00},
+	{MSM89XX_PMIC_DIGITAL_REVISION2, 0x00},
+	{MSM89XX_PMIC_DIGITAL_PERPH_TYPE, 0x23},
+	{MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE, 0x01},
+	{MSM89XX_PMIC_DIGITAL_INT_RT_STS, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_SET_TYPE, 0xFF},
+	{MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH, 0xFF},
+	{MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_EN_SET, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_EN_CLR, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_PENDING_STS, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_MID_SEL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_PRIORITY, 0x00},
+	{MSM89XX_PMIC_DIGITAL_GPIO_MODE, 0x00},
+	{MSM89XX_PMIC_DIGITAL_PIN_CTL_OE, 0x01},
+	{MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA, 0x00},
+	{MSM89XX_PMIC_DIGITAL_PIN_STATUS, 0x00},
+	{MSM89XX_PMIC_DIGITAL_HDRIVE_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL, 0x02},
+	{MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL, 0x02},
+	{MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1, 0x7C},
+	{MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2, 0x7C},
+	{MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3, 0x7C},
+	{MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0, 0x00},
+	{MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1, 0x00},
+	{MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2, 0x00},
+	{MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3, 0x00},
+	{MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_DIG_DEBUG_EN, 0x00},
+	{MSM89XX_PMIC_DIGITAL_SPARE_0, 0x00},
+	{MSM89XX_PMIC_DIGITAL_SPARE_1, 0x00},
+	{MSM89XX_PMIC_DIGITAL_SPARE_2, 0x00},
+	{MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0x00},
+	{MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL1, 0x00},
+	{MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL2, 0x02},
+	{MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x05},
+	{MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_TEST1, 0x00},
+	{MSM89XX_PMIC_DIGITAL_INT_TEST_VAL, 0x00},
+	{MSM89XX_PMIC_DIGITAL_TRIM_NUM, 0x00},
+	{MSM89XX_PMIC_DIGITAL_TRIM_CTRL, 0x00},
+	{MSM89XX_PMIC_ANALOG_REVISION1, 0x00},
+	{MSM89XX_PMIC_ANALOG_REVISION2, 0x00},
+	{MSM89XX_PMIC_ANALOG_REVISION3, 0x00},
+	{MSM89XX_PMIC_ANALOG_REVISION4, 0x00},
+	{MSM89XX_PMIC_ANALOG_PERPH_TYPE, 0x23},
+	{MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x09},
+	{MSM89XX_PMIC_ANALOG_INT_RT_STS, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_SET_TYPE, 0x3F},
+	{MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH, 0x3F},
+	{MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_EN_SET, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_EN_CLR, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_LATCHED_STS, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_PENDING_STS, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_MID_SEL, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_PRIORITY, 0x00},
+	{MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x00},
+	{MSM89XX_PMIC_ANALOG_MICB_1_VAL, 0x20},
+	{MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x00},
+	{MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS, 0x49},
+	{MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20},
+	{MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2, 0x00},
+	{MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x00},
+	{MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x35},
+	{MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08},
+	{MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x00},
+	{MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x98},
+	{MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, 0x00},
+	{MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL, 0x20},
+	{MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, 0x40},
+	{MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x61},
+	{MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL, 0x80},
+	{MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0x00},
+	{MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x00},
+	{MSM89XX_PMIC_ANALOG_TX_1_EN, 0x03},
+	{MSM89XX_PMIC_ANALOG_TX_2_EN, 0x03},
+	{MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1, 0xBF},
+	{MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2, 0x8C},
+	{MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL, 0x00},
+	{MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x6B},
+	{MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV, 0x51},
+	{MSM89XX_PMIC_ANALOG_TX_3_EN, 0x02},
+	{MSM89XX_PMIC_ANALOG_NCP_EN, 0x26},
+	{MSM89XX_PMIC_ANALOG_NCP_CLK, 0x23},
+	{MSM89XX_PMIC_ANALOG_NCP_DEGLITCH, 0x5B},
+	{MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x08},
+	{MSM89XX_PMIC_ANALOG_NCP_BIAS, 0x29},
+	{MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0x24},
+	{MSM89XX_PMIC_ANALOG_NCP_TEST, 0x00},
+	{MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR, 0xD5},
+	{MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER, 0xE8},
+	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xCF},
+	{MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0x6E},
+	{MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x18},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0x5A},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP, 0x69},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP, 0x29},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x80},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL, 0xDA},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0x16},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x00},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x00},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20},
+	{MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12},
+	{MSM89XX_PMIC_ANALOG_RX_ATEST, 0x00},
+	{MSM89XX_PMIC_ANALOG_RX_HPH_STATUS, 0x0C},
+	{MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x00},
+	{MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x00},
+	{MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x00},
+	{MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x83},
+	{MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET, 0x91},
+	{MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x29},
+	{MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x4D},
+	{MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1},
+	{MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x1E},
+	{MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC, 0xCB},
+	{MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x00},
+	{MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x02},
+	{MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE, 0x14},
+	{MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x00},
+	{MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x1F},
+	{MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x8C},
+	{MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE, 0xC0},
+	{MSM89XX_PMIC_ANALOG_BOOST_TEST1_1, 0x00},
+	{MSM89XX_PMIC_ANALOG_BOOST_TEST_2, 0x00},
+	{MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS, 0x00},
+	{MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS, 0x00},
+	{MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR, 0x00},
+	{MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL, 0x00},
+	{MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0x00},
+	{MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL1, 0x00},
+	{MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL2, 0x01},
+	{MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x05},
+	{MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_TEST1, 0x00},
+	{MSM89XX_PMIC_ANALOG_INT_TEST_VAL, 0x00},
+	{MSM89XX_PMIC_ANALOG_TRIM_NUM, 0x04},
+	{MSM89XX_PMIC_ANALOG_TRIM_CTRL1, 0x00},
+	{MSM89XX_PMIC_ANALOG_TRIM_CTRL2, 0x00},
+	{MSM89XX_PMIC_ANALOG_TRIM_CTRL3, 0x00},
+	{MSM89XX_PMIC_ANALOG_TRIM_CTRL4, 0x00},
+};
+
+static const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
+		[MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
+		[MSM89XX_CDC_CORE_TOP_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS] = 1,
+		[MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1,
+		[MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX5_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
+};
+
+static const u8 msm89xx_cdc_core_reg_writeable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
+		[MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
+		[MSM89XX_CDC_CORE_TOP_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1,
+		[MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX5_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
+};
+
+bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
+{
+	return msm89xx_cdc_core_reg_readable[reg];
+}
+
+bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return msm89xx_cdc_core_reg_writeable[reg];
+}
+
+bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MSM89XX_CDC_CORE_RX1_B1_CTL:
+	case MSM89XX_CDC_CORE_RX2_B1_CTL:
+	case MSM89XX_CDC_CORE_RX3_B1_CTL:
+	case MSM89XX_CDC_CORE_RX1_B6_CTL:
+	case MSM89XX_CDC_CORE_RX2_B6_CTL:
+	case MSM89XX_CDC_CORE_RX3_B6_CTL:
+	case MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL:
+	case MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL:
+	case MSM89XX_CDC_CORE_CLK_MCLK_CTL:
+	case MSM89XX_CDC_CORE_CLK_PDM_CTL:
+		return true;
+	default:
+		return false;
+	}
+}
diff --git a/asoc/codecs/wcd-dsp-mgr.c b/asoc/codecs/wcd-dsp-mgr.c
new file mode 100644
index 0000000..a6d46ae
--- /dev/null
+++ b/asoc/codecs/wcd-dsp-mgr.c
@@ -0,0 +1,1254 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/stringify.h>
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include <soc/qcom/ramdump.h>
+#include <sound/wcd-dsp-mgr.h>
+#include "wcd-dsp-utils.h"
+
+/* Forward declarations */
+static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type);
+
+/* Component related macros */
+#define WDSP_GET_COMPONENT(wdsp, x) ((x >= WDSP_CMPNT_TYPE_MAX || x < 0) ? \
+					NULL : (&(wdsp->cmpnts[x])))
+#define WDSP_GET_CMPNT_TYPE_STR(x) wdsp_get_cmpnt_type_string(x)
+
+/*
+ * These #defines indicate the bit number in status field
+ * for each of the status. If bit is set, it indicates
+ * the status as done, else if bit is not set, it indicates
+ * the status is either failed or not done.
+ */
+#define WDSP_STATUS_INITIALIZED   BIT(0)
+#define WDSP_STATUS_CODE_DLOADED  BIT(1)
+#define WDSP_STATUS_DATA_DLOADED  BIT(2)
+#define WDSP_STATUS_BOOTED        BIT(3)
+
+/* Helper macros for printing wdsp messages */
+#define WDSP_ERR(wdsp, fmt, ...)		\
+	dev_err(wdsp->mdev, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define WDSP_DBG(wdsp, fmt, ...)	\
+	dev_dbg(wdsp->mdev, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
+
+/* Helper macros for locking */
+#define WDSP_MGR_MUTEX_LOCK(wdsp, lock)         \
+{                                               \
+	WDSP_DBG(wdsp, "mutex_lock(%s)",        \
+		 __stringify_1(lock));          \
+	mutex_lock(&lock);                      \
+}
+
+#define WDSP_MGR_MUTEX_UNLOCK(wdsp, lock)       \
+{                                               \
+	WDSP_DBG(wdsp, "mutex_unlock(%s)",      \
+		 __stringify_1(lock));          \
+	mutex_unlock(&lock);                    \
+}
+
+/* Helper macros for using status mask */
+#define WDSP_SET_STATUS(wdsp, state)                  \
+{                                                     \
+	wdsp->status |= state;                        \
+	WDSP_DBG(wdsp, "set 0x%lx, new_state = 0x%x", \
+		 state, wdsp->status);                \
+}
+
+#define WDSP_CLEAR_STATUS(wdsp, state)                  \
+{                                                       \
+	wdsp->status &= (~state);                       \
+	WDSP_DBG(wdsp, "clear 0x%lx, new_state = 0x%x", \
+		 state, wdsp->status);                  \
+}
+
+#define WDSP_STATUS_IS_SET(wdsp, state) (wdsp->status & state)
+
+/* SSR relate status macros */
+#define WDSP_SSR_STATUS_WDSP_READY    BIT(0)
+#define WDSP_SSR_STATUS_CDC_READY     BIT(1)
+#define WDSP_SSR_STATUS_READY         \
+	(WDSP_SSR_STATUS_WDSP_READY | WDSP_SSR_STATUS_CDC_READY)
+#define WDSP_SSR_READY_WAIT_TIMEOUT   (10 * HZ)
+
+enum wdsp_ssr_type {
+
+	/* Init value, indicates there is no SSR in progress */
+	WDSP_SSR_TYPE_NO_SSR = 0,
+
+	/*
+	 * Indicates WDSP crashed. The manager driver internally
+	 * decides when to perform WDSP restart based on the
+	 * users of wdsp. Hence there is no explicit WDSP_UP.
+	 */
+	WDSP_SSR_TYPE_WDSP_DOWN,
+
+	/* Indicates codec hardware is down */
+	WDSP_SSR_TYPE_CDC_DOWN,
+
+	/* Indicates codec hardware is up, trigger to restart WDSP */
+	WDSP_SSR_TYPE_CDC_UP,
+};
+
+struct wdsp_cmpnt {
+
+	/* OF node of the phandle */
+	struct device_node *np;
+
+	/*
+	 * Child component's dev_name, should be set in DT for the child's
+	 * phandle if child's dev->of_node does not match the phandle->of_node
+	 */
+	const char *cdev_name;
+
+	/* Child component's device node */
+	struct device *cdev;
+
+	/* Private data that component may want back on callbacks */
+	void *priv_data;
+
+	/* Child ops */
+	struct wdsp_cmpnt_ops *ops;
+};
+
+struct wdsp_ramdump_data {
+
+	/* Ramdump device */
+	void *rd_dev;
+
+	/* DMA address of the dump */
+	dma_addr_t rd_addr;
+
+	/* Virtual address of the dump */
+	void *rd_v_addr;
+
+	/* Data provided through error interrupt */
+	struct wdsp_err_signal_arg err_data;
+};
+
+struct wdsp_mgr_priv {
+
+	/* Manager driver's struct device pointer */
+	struct device *mdev;
+
+	/* Match struct for component framework */
+	struct component_match *match;
+
+	/* Manager's ops/function callbacks */
+	struct wdsp_mgr_ops *ops;
+
+	/* Array to store information for all expected components */
+	struct wdsp_cmpnt cmpnts[WDSP_CMPNT_TYPE_MAX];
+
+	/* The filename of image to be downloaded */
+	const char *img_fname;
+
+	/* Keeps track of current state of manager driver */
+	u32 status;
+
+	/* Work to load the firmware image after component binding */
+	struct work_struct load_fw_work;
+
+	/* List of segments in image to be downloaded */
+	struct list_head *seg_list;
+
+	/* Base address of the image in memory */
+	u32 base_addr;
+
+	/* Instances using dsp */
+	int dsp_users;
+
+	/* Lock for serializing ops called by components */
+	struct mutex api_mutex;
+
+	struct wdsp_ramdump_data dump_data;
+
+	/* SSR related */
+	enum wdsp_ssr_type ssr_type;
+	struct mutex ssr_mutex;
+	struct work_struct ssr_work;
+	u16 ready_status;
+	struct completion ready_compl;
+
+	/* Debugfs related */
+	struct dentry *entry;
+	bool panic_on_error;
+};
+
+static char *wdsp_get_ssr_type_string(enum wdsp_ssr_type type)
+{
+	switch (type) {
+	case WDSP_SSR_TYPE_NO_SSR:
+		return "NO_SSR";
+	case WDSP_SSR_TYPE_WDSP_DOWN:
+		return "WDSP_DOWN";
+	case WDSP_SSR_TYPE_CDC_DOWN:
+		return "CDC_DOWN";
+	case WDSP_SSR_TYPE_CDC_UP:
+		return "CDC_UP";
+	default:
+		pr_err("%s: Invalid ssr_type %d\n",
+			__func__, type);
+		return "Invalid";
+	}
+}
+
+static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type type)
+{
+	switch (type) {
+	case WDSP_CMPNT_CONTROL:
+		return "control";
+	case WDSP_CMPNT_IPC:
+		return "ipc";
+	case WDSP_CMPNT_TRANSPORT:
+		return "transport";
+	default:
+		pr_err("%s: Invalid component type %d\n",
+			__func__, type);
+		return "Invalid";
+	}
+}
+
+static void __wdsp_clr_ready_locked(struct wdsp_mgr_priv *wdsp,
+				    u16 value)
+{
+	wdsp->ready_status &= ~(value);
+	WDSP_DBG(wdsp, "ready_status = 0x%x", wdsp->ready_status);
+}
+
+static void __wdsp_set_ready_locked(struct wdsp_mgr_priv *wdsp,
+				    u16 value, bool mark_complete)
+{
+	wdsp->ready_status |= value;
+	WDSP_DBG(wdsp, "ready_status = 0x%x", wdsp->ready_status);
+
+	if (mark_complete &&
+	    wdsp->ready_status == WDSP_SSR_STATUS_READY) {
+		WDSP_DBG(wdsp, "marking ready completion");
+		complete(&wdsp->ready_compl);
+	}
+}
+
+static void wdsp_broadcast_event_upseq(struct wdsp_mgr_priv *wdsp,
+				       enum wdsp_event_type event,
+				       void *data)
+{
+	struct wdsp_cmpnt *cmpnt;
+	int i;
+
+	for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) {
+		cmpnt = WDSP_GET_COMPONENT(wdsp, i);
+		if (cmpnt && cmpnt->ops && cmpnt->ops->event_handler)
+			cmpnt->ops->event_handler(cmpnt->cdev, cmpnt->priv_data,
+						  event, data);
+	}
+}
+
+static void wdsp_broadcast_event_downseq(struct wdsp_mgr_priv *wdsp,
+					 enum wdsp_event_type event,
+					 void *data)
+{
+	struct wdsp_cmpnt *cmpnt;
+	int i;
+
+	for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) {
+		cmpnt = WDSP_GET_COMPONENT(wdsp, i);
+		if (cmpnt && cmpnt->ops && cmpnt->ops->event_handler)
+			cmpnt->ops->event_handler(cmpnt->cdev, cmpnt->priv_data,
+						  event, data);
+	}
+}
+
+static int wdsp_unicast_event(struct wdsp_mgr_priv *wdsp,
+			      enum wdsp_cmpnt_type type,
+			      enum wdsp_event_type event,
+			      void *data)
+{
+	struct wdsp_cmpnt *cmpnt;
+	int ret;
+
+	cmpnt = WDSP_GET_COMPONENT(wdsp, type);
+	if (cmpnt && cmpnt->ops && cmpnt->ops->event_handler) {
+		ret = cmpnt->ops->event_handler(cmpnt->cdev, cmpnt->priv_data,
+						event, data);
+	} else {
+		WDSP_ERR(wdsp, "not valid event_handler for %s",
+			 WDSP_GET_CMPNT_TYPE_STR(type));
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void wdsp_deinit_components(struct wdsp_mgr_priv *wdsp)
+{
+	struct wdsp_cmpnt *cmpnt;
+	int i;
+
+	for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) {
+		cmpnt = WDSP_GET_COMPONENT(wdsp, i);
+		if (cmpnt && cmpnt->ops && cmpnt->ops->deinit)
+			cmpnt->ops->deinit(cmpnt->cdev, cmpnt->priv_data);
+	}
+}
+
+static int wdsp_init_components(struct wdsp_mgr_priv *wdsp)
+{
+	struct wdsp_cmpnt *cmpnt;
+	int fail_idx = WDSP_CMPNT_TYPE_MAX;
+	int i, ret = 0;
+
+	for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) {
+
+		cmpnt = WDSP_GET_COMPONENT(wdsp, i);
+
+		/* Init is allowed to be NULL */
+		if (!cmpnt->ops || !cmpnt->ops->init)
+			continue;
+		ret = cmpnt->ops->init(cmpnt->cdev, cmpnt->priv_data);
+		if (ret) {
+			WDSP_ERR(wdsp, "Init failed (%d) for component %s",
+				 ret, WDSP_GET_CMPNT_TYPE_STR(i));
+				fail_idx = i;
+				break;
+		}
+	}
+
+	if (fail_idx < WDSP_CMPNT_TYPE_MAX) {
+		/* Undo init for already initialized components */
+		for (i = fail_idx - 1; i >= 0; i--) {
+			struct wdsp_cmpnt *cmpnt = WDSP_GET_COMPONENT(wdsp, i);
+
+			if (cmpnt->ops && cmpnt->ops->deinit)
+				cmpnt->ops->deinit(cmpnt->cdev,
+						   cmpnt->priv_data);
+		}
+	} else {
+		wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_INIT, NULL);
+	}
+
+	return ret;
+}
+
+static int wdsp_load_each_segment(struct wdsp_mgr_priv *wdsp,
+				  struct wdsp_img_segment *seg)
+{
+	struct wdsp_img_section img_section;
+	int ret;
+
+	WDSP_DBG(wdsp,
+		 "base_addr 0x%x, split_fname %s, load_addr 0x%x, size 0x%zx",
+		 wdsp->base_addr, seg->split_fname, seg->load_addr, seg->size);
+
+	if (seg->load_addr < wdsp->base_addr) {
+		WDSP_ERR(wdsp, "Invalid addr 0x%x, base_addr = 0x%x",
+			 seg->load_addr, wdsp->base_addr);
+		return -EINVAL;
+	}
+
+	img_section.addr = seg->load_addr - wdsp->base_addr;
+	img_section.size = seg->size;
+	img_section.data = seg->data;
+
+	ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_TRANSPORT,
+				 WDSP_EVENT_DLOAD_SECTION,
+				 &img_section);
+	if (ret < 0)
+		WDSP_ERR(wdsp,
+			 "Failed, err = %d for base_addr = 0x%x split_fname = %s, load_addr = 0x%x, size = 0x%zx",
+			 ret, wdsp->base_addr, seg->split_fname,
+			 seg->load_addr, seg->size);
+	return ret;
+}
+
+static int wdsp_download_segments(struct wdsp_mgr_priv *wdsp,
+				  unsigned int type)
+{
+	struct wdsp_cmpnt *ctl;
+	struct wdsp_img_segment *seg = NULL;
+	enum wdsp_event_type pre, post;
+	long status;
+	int ret;
+
+	ctl = WDSP_GET_COMPONENT(wdsp, WDSP_CMPNT_CONTROL);
+
+	if (type == WDSP_ELF_FLAG_RE) {
+		pre = WDSP_EVENT_PRE_DLOAD_CODE;
+		post = WDSP_EVENT_POST_DLOAD_CODE;
+		status = WDSP_STATUS_CODE_DLOADED;
+	} else if (type == WDSP_ELF_FLAG_WRITE) {
+		pre = WDSP_EVENT_PRE_DLOAD_DATA;
+		post = WDSP_EVENT_POST_DLOAD_DATA;
+		status = WDSP_STATUS_DATA_DLOADED;
+	} else {
+		WDSP_ERR(wdsp, "Invalid type %u", type);
+		return -EINVAL;
+	}
+
+	ret = wdsp_get_segment_list(ctl->cdev, wdsp->img_fname,
+				    type, wdsp->seg_list, &wdsp->base_addr);
+	if (ret < 0 ||
+	    list_empty(wdsp->seg_list)) {
+		WDSP_ERR(wdsp, "Error %d to get image segments for type %d",
+			 ret, type);
+		wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_DLOAD_FAILED,
+					     NULL);
+		goto done;
+	}
+
+	/* Notify all components that image is about to be downloaded */
+	wdsp_broadcast_event_upseq(wdsp, pre, NULL);
+
+	/* Go through the list of segments and download one by one */
+	list_for_each_entry(seg, wdsp->seg_list, list) {
+		ret = wdsp_load_each_segment(wdsp, seg);
+		if (ret < 0) {
+			wdsp_broadcast_event_downseq(wdsp,
+						     WDSP_EVENT_DLOAD_FAILED,
+						     NULL);
+			goto dload_error;
+		}
+	}
+
+	WDSP_SET_STATUS(wdsp, status);
+
+	/* Notify all components that image is downloaded */
+	wdsp_broadcast_event_downseq(wdsp, post, NULL);
+
+dload_error:
+	wdsp_flush_segment_list(wdsp->seg_list);
+done:
+	return ret;
+}
+
+static int wdsp_init_and_dload_code_sections(struct wdsp_mgr_priv *wdsp)
+{
+	int ret;
+	bool is_initialized;
+
+	is_initialized = WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_INITIALIZED);
+
+	if (!is_initialized) {
+		/* Components are not initialized yet, initialize them */
+		ret = wdsp_init_components(wdsp);
+		if (ret < 0) {
+			WDSP_ERR(wdsp, "INIT failed, err = %d", ret);
+			goto done;
+		}
+		WDSP_SET_STATUS(wdsp, WDSP_STATUS_INITIALIZED);
+	}
+
+	/* Download the read-execute sections of image */
+	ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_RE);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Error %d to download code sections", ret);
+		goto done;
+	}
+done:
+	return ret;
+}
+
+static void wdsp_load_fw_image(struct work_struct *work)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int ret;
+
+	wdsp = container_of(work, struct wdsp_mgr_priv, load_fw_work);
+	if (!wdsp) {
+		pr_err("%s: Invalid private_data\n", __func__);
+		return;
+	}
+
+	ret = wdsp_init_and_dload_code_sections(wdsp);
+	if (ret < 0)
+		WDSP_ERR(wdsp, "dload code sections failed, err = %d", ret);
+}
+
+static int wdsp_enable_dsp(struct wdsp_mgr_priv *wdsp)
+{
+	int ret;
+
+	/* Make sure wdsp is in good state */
+	if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_CODE_DLOADED)) {
+		WDSP_ERR(wdsp, "WDSP in invalid state 0x%x", wdsp->status);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/* Download the read-write sections of image */
+	ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_WRITE);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Data section download failed, err = %d", ret);
+		goto done;
+	}
+
+	wdsp_broadcast_event_upseq(wdsp, WDSP_EVENT_PRE_BOOTUP, NULL);
+
+	ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL,
+				 WDSP_EVENT_DO_BOOT, NULL);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Failed to boot dsp, err = %d", ret);
+		WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED);
+		goto done;
+	}
+
+	wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_BOOTUP, NULL);
+	WDSP_SET_STATUS(wdsp, WDSP_STATUS_BOOTED);
+done:
+	return ret;
+}
+
+static int wdsp_disable_dsp(struct wdsp_mgr_priv *wdsp)
+{
+	int ret;
+
+	WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+
+	/*
+	 * If Disable happened while SSR is in progress, then set the SSR
+	 * ready status indicating WDSP is now ready. Ignore the disable
+	 * event here and let the SSR handler go through shutdown.
+	 */
+	if (wdsp->ssr_type != WDSP_SSR_TYPE_NO_SSR) {
+		__wdsp_set_ready_locked(wdsp, WDSP_SSR_STATUS_WDSP_READY, true);
+		WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+		return 0;
+	}
+
+	WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+
+	/* Make sure wdsp is in good state */
+	if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_BOOTED)) {
+		WDSP_ERR(wdsp, "wdsp in invalid state 0x%x", wdsp->status);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_PRE_SHUTDOWN, NULL);
+	ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL,
+				 WDSP_EVENT_DO_SHUTDOWN, NULL);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Failed to shutdown dsp, err = %d", ret);
+		goto done;
+	}
+
+	wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_SHUTDOWN, NULL);
+	WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_BOOTED);
+
+	/* Data sections are to be downloaded per boot */
+	WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED);
+done:
+	return ret;
+}
+
+static int wdsp_register_cmpnt_ops(struct device *wdsp_dev,
+				   struct device *cdev,
+				   void *priv_data,
+				   struct wdsp_cmpnt_ops *ops)
+{
+	struct wdsp_mgr_priv *wdsp;
+	struct wdsp_cmpnt *cmpnt;
+	int i, ret;
+
+	if (!wdsp_dev || !cdev || !ops)
+		return -EINVAL;
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+
+	WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->api_mutex);
+
+	for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) {
+		cmpnt = WDSP_GET_COMPONENT(wdsp, i);
+		if ((cdev->of_node && cdev->of_node == cmpnt->np) ||
+		    (cmpnt->cdev_name &&
+		     !strcmp(dev_name(cdev), cmpnt->cdev_name))) {
+			break;
+		}
+	}
+
+	if (i == WDSP_CMPNT_TYPE_MAX) {
+		WDSP_ERR(wdsp, "Failed to register component dev %s",
+			 dev_name(cdev));
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cmpnt->cdev = cdev;
+	cmpnt->ops = ops;
+	cmpnt->priv_data = priv_data;
+done:
+	WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->api_mutex);
+	return 0;
+}
+
+static struct device *wdsp_get_dev_for_cmpnt(struct device *wdsp_dev,
+					     enum wdsp_cmpnt_type type)
+{
+	struct wdsp_mgr_priv *wdsp;
+	struct wdsp_cmpnt *cmpnt;
+
+	if (!wdsp_dev || type >= WDSP_CMPNT_TYPE_MAX)
+		return NULL;
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+	cmpnt = WDSP_GET_COMPONENT(wdsp, type);
+
+	return cmpnt->cdev;
+}
+
+static int wdsp_get_devops_for_cmpnt(struct device *wdsp_dev,
+				     enum wdsp_cmpnt_type type,
+				     void *data)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int ret = 0;
+
+	if (!wdsp_dev || type >= WDSP_CMPNT_TYPE_MAX)
+		return -EINVAL;
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+	ret = wdsp_unicast_event(wdsp, type,
+				 WDSP_EVENT_GET_DEVOPS, data);
+	if (ret)
+		WDSP_ERR(wdsp, "get_dev_ops failed for cmpnt type %d",
+			 type);
+	return ret;
+}
+
+static void wdsp_collect_ramdumps(struct wdsp_mgr_priv *wdsp)
+{
+	struct wdsp_img_section img_section;
+	struct wdsp_err_signal_arg *data = &wdsp->dump_data.err_data;
+	struct ramdump_segment rd_seg;
+	int ret = 0;
+
+	if (wdsp->ssr_type != WDSP_SSR_TYPE_WDSP_DOWN ||
+	    !data->mem_dumps_enabled) {
+		WDSP_DBG(wdsp, "cannot dump memory, ssr_type %s, dumps %s",
+			 wdsp_get_ssr_type_string(wdsp->ssr_type),
+			 !(data->mem_dumps_enabled) ? "disabled" : "enabled");
+		goto done;
+	}
+
+	if (data->dump_size == 0 ||
+	    data->remote_start_addr < wdsp->base_addr) {
+		WDSP_ERR(wdsp, "Invalid start addr 0x%x or dump_size 0x%zx",
+			 data->remote_start_addr, data->dump_size);
+		goto done;
+	}
+
+	if (!wdsp->dump_data.rd_dev) {
+		WDSP_ERR(wdsp, "Ramdump device is not setup");
+		goto done;
+	}
+
+	WDSP_DBG(wdsp, "base_addr 0x%x, dump_start_addr 0x%x, dump_size 0x%zx",
+		 wdsp->base_addr, data->remote_start_addr, data->dump_size);
+
+	/* Allocate memory for dumps */
+	wdsp->dump_data.rd_v_addr = dma_alloc_coherent(wdsp->mdev,
+						       data->dump_size,
+						       &wdsp->dump_data.rd_addr,
+						       GFP_KERNEL);
+	if (!wdsp->dump_data.rd_v_addr)
+		goto done;
+
+	img_section.addr = data->remote_start_addr - wdsp->base_addr;
+	img_section.size = data->dump_size;
+	img_section.data = wdsp->dump_data.rd_v_addr;
+
+	ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_TRANSPORT,
+				 WDSP_EVENT_READ_SECTION,
+				 &img_section);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Failed to read dumps, size 0x%zx at addr 0x%x",
+			 img_section.size, img_section.addr);
+		goto err_read_dumps;
+	}
+
+	/*
+	 * If panic_on_error flag is explicitly set through the debugfs,
+	 * then cause a BUG here to aid debugging.
+	 */
+	BUG_ON(wdsp->panic_on_error);
+
+	rd_seg.address = (unsigned long) wdsp->dump_data.rd_v_addr;
+	rd_seg.size = img_section.size;
+	rd_seg.v_address = wdsp->dump_data.rd_v_addr;
+
+	ret = do_ramdump(wdsp->dump_data.rd_dev, &rd_seg, 1);
+	if (ret < 0)
+		WDSP_ERR(wdsp, "do_ramdump failed with error %d", ret);
+
+err_read_dumps:
+	dma_free_coherent(wdsp->mdev, data->dump_size,
+			  wdsp->dump_data.rd_v_addr, wdsp->dump_data.rd_addr);
+done:
+	return;
+}
+
+static void wdsp_ssr_work_fn(struct work_struct *work)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int ret;
+
+	wdsp = container_of(work, struct wdsp_mgr_priv, ssr_work);
+	if (!wdsp) {
+		pr_err("%s: Invalid private_data\n", __func__);
+		return;
+	}
+
+	WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+
+	/* Issue ramdumps and shutdown only if DSP is currently booted */
+	if (WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_BOOTED)) {
+		wdsp_collect_ramdumps(wdsp);
+		ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL,
+					 WDSP_EVENT_DO_SHUTDOWN, NULL);
+		if (ret < 0)
+			WDSP_ERR(wdsp, "Failed WDSP shutdown, err = %d", ret);
+
+		wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_SHUTDOWN,
+					     NULL);
+		WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_BOOTED);
+	}
+
+	WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+	ret = wait_for_completion_timeout(&wdsp->ready_compl,
+					  WDSP_SSR_READY_WAIT_TIMEOUT);
+	WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+	if (ret == 0) {
+		WDSP_ERR(wdsp, "wait_for_ready timed out, status = 0x%x",
+			 wdsp->ready_status);
+		goto done;
+	}
+
+	/* Data sections are to downloaded per WDSP boot */
+	WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED);
+
+	/*
+	 * Even though code section could possible be retained on DSP
+	 * crash, go ahead and still re-download just to avoid any
+	 * memory corruption from previous crash.
+	 */
+	WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_CODE_DLOADED);
+
+	/* If codec restarted, then all components must be re-initialized */
+	if (wdsp->ssr_type == WDSP_SSR_TYPE_CDC_UP) {
+		wdsp_deinit_components(wdsp);
+		WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_INITIALIZED);
+	}
+
+	ret = wdsp_init_and_dload_code_sections(wdsp);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Failed to dload code sections err = %d",
+			 ret);
+		goto done;
+	}
+
+	/* SSR handling is finished, mark SSR type as NO_SSR */
+	wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR;
+done:
+	WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+}
+
+static int wdsp_ssr_handler(struct wdsp_mgr_priv *wdsp, void *arg,
+			    enum wdsp_ssr_type ssr_type)
+{
+	enum wdsp_ssr_type current_ssr_type;
+	struct wdsp_err_signal_arg *err_data;
+
+	WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
+
+	current_ssr_type = wdsp->ssr_type;
+	WDSP_DBG(wdsp, "Current ssr_type %s, handling ssr_type %s",
+		 wdsp_get_ssr_type_string(current_ssr_type),
+		 wdsp_get_ssr_type_string(ssr_type));
+	wdsp->ssr_type = ssr_type;
+
+	if (arg) {
+		err_data = (struct wdsp_err_signal_arg *) arg;
+		memcpy(&wdsp->dump_data.err_data, err_data,
+		       sizeof(*err_data));
+	} else {
+		memset(&wdsp->dump_data.err_data, 0,
+		       sizeof(wdsp->dump_data.err_data));
+	}
+
+	switch (ssr_type) {
+
+	case WDSP_SSR_TYPE_WDSP_DOWN:
+		__wdsp_clr_ready_locked(wdsp, WDSP_SSR_STATUS_WDSP_READY);
+		wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_PRE_SHUTDOWN,
+					     NULL);
+		schedule_work(&wdsp->ssr_work);
+		break;
+
+	case WDSP_SSR_TYPE_CDC_DOWN:
+		__wdsp_clr_ready_locked(wdsp, WDSP_SSR_STATUS_CDC_READY);
+		/*
+		 * If DSP is booted when CDC_DOWN is received, it needs
+		 * to be shutdown.
+		 */
+		if (WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_BOOTED)) {
+			__wdsp_clr_ready_locked(wdsp,
+						WDSP_SSR_STATUS_WDSP_READY);
+			wdsp_broadcast_event_downseq(wdsp,
+						     WDSP_EVENT_PRE_SHUTDOWN,
+						     NULL);
+		}
+
+		schedule_work(&wdsp->ssr_work);
+		break;
+
+	case WDSP_SSR_TYPE_CDC_UP:
+		__wdsp_set_ready_locked(wdsp, WDSP_SSR_STATUS_CDC_READY, true);
+		break;
+
+	default:
+		WDSP_ERR(wdsp, "undefined ssr_type %d\n", ssr_type);
+		/* Revert back the ssr_type for undefined events */
+		wdsp->ssr_type = current_ssr_type;
+		break;
+	}
+
+	WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
+
+	return 0;
+}
+
+static int wdsp_signal_handler(struct device *wdsp_dev,
+			       enum wdsp_signal signal, void *arg)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int ret;
+
+	if (!wdsp_dev)
+		return -EINVAL;
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+	WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->api_mutex);
+
+	WDSP_DBG(wdsp, "Raised signal %d", signal);
+
+	switch (signal) {
+	case WDSP_IPC1_INTR:
+		ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_IPC,
+					 WDSP_EVENT_IPC1_INTR, NULL);
+		break;
+	case WDSP_ERR_INTR:
+		ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_WDSP_DOWN);
+		break;
+	case WDSP_CDC_DOWN_SIGNAL:
+		ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_CDC_DOWN);
+		break;
+	case WDSP_CDC_UP_SIGNAL:
+		ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_CDC_UP);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret < 0)
+		WDSP_ERR(wdsp, "handling signal %d failed with error %d",
+			 signal, ret);
+	WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->api_mutex);
+
+	return ret;
+}
+
+static int wdsp_vote_for_dsp(struct device *wdsp_dev,
+			     bool vote)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int ret = 0;
+
+	if (!wdsp_dev)
+		return -EINVAL;
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+
+	WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->api_mutex);
+	WDSP_DBG(wdsp, "request %s, current users = %d",
+		 vote ? "enable" : "disable", wdsp->dsp_users);
+
+	if (vote) {
+		wdsp->dsp_users++;
+		if (wdsp->dsp_users == 1)
+			ret = wdsp_enable_dsp(wdsp);
+	} else {
+		if (wdsp->dsp_users == 0)
+			goto done;
+
+		wdsp->dsp_users--;
+		if (wdsp->dsp_users == 0)
+			ret = wdsp_disable_dsp(wdsp);
+	}
+
+	if (ret < 0)
+		WDSP_DBG(wdsp, "wdsp %s failed, err = %d",
+			 vote ? "enable" : "disable", ret);
+
+done:
+	WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->api_mutex);
+	return ret;
+}
+
+static int wdsp_suspend(struct device *wdsp_dev)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int rc = 0, i;
+
+	if (!wdsp_dev) {
+		pr_err("%s: Invalid handle to device\n", __func__);
+		return -EINVAL;
+	}
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+
+	for (i =  WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) {
+		rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_SUSPEND, NULL);
+		if (rc < 0) {
+			WDSP_ERR(wdsp, "component %s failed to suspend\n",
+				WDSP_GET_CMPNT_TYPE_STR(i));
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int wdsp_resume(struct device *wdsp_dev)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int rc = 0, i;
+
+	if (!wdsp_dev) {
+		pr_err("%s: Invalid handle to device\n", __func__);
+		return -EINVAL;
+	}
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+
+	for (i =  0; i < WDSP_CMPNT_TYPE_MAX; i++) {
+		rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_RESUME, NULL);
+		if (rc < 0) {
+			WDSP_ERR(wdsp, "component %s failed to resume\n",
+				WDSP_GET_CMPNT_TYPE_STR(i));
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static struct wdsp_mgr_ops wdsp_ops = {
+	.register_cmpnt_ops = wdsp_register_cmpnt_ops,
+	.get_dev_for_cmpnt = wdsp_get_dev_for_cmpnt,
+	.get_devops_for_cmpnt = wdsp_get_devops_for_cmpnt,
+	.signal_handler = wdsp_signal_handler,
+	.vote_for_dsp = wdsp_vote_for_dsp,
+	.suspend = wdsp_suspend,
+	.resume = wdsp_resume,
+};
+
+static int wdsp_mgr_compare_of(struct device *dev, void *data)
+{
+	struct wdsp_cmpnt *cmpnt = data;
+
+	/*
+	 * First try to match based on of_node, if of_node is not
+	 * present, try to match on the dev_name
+	 */
+	return ((dev->of_node && dev->of_node == cmpnt->np) ||
+		(cmpnt->cdev_name &&
+		 !strcmp(dev_name(dev), cmpnt->cdev_name)));
+}
+
+static void wdsp_mgr_debugfs_init(struct wdsp_mgr_priv *wdsp)
+{
+	wdsp->entry = debugfs_create_dir("wdsp_mgr", NULL);
+	if (IS_ERR_OR_NULL(wdsp->entry))
+		return;
+
+	debugfs_create_bool("panic_on_error", 0644,
+			    wdsp->entry, &wdsp->panic_on_error);
+}
+
+static void wdsp_mgr_debugfs_remove(struct wdsp_mgr_priv *wdsp)
+{
+	debugfs_remove_recursive(wdsp->entry);
+	wdsp->entry = NULL;
+}
+
+static int wdsp_mgr_bind(struct device *dev)
+{
+	struct wdsp_mgr_priv *wdsp = dev_get_drvdata(dev);
+	struct wdsp_cmpnt *cmpnt;
+	int ret, idx;
+
+	wdsp->ops = &wdsp_ops;
+
+	/* Setup ramdump device */
+	wdsp->dump_data.rd_dev = create_ramdump_device("wdsp", dev);
+	if (!wdsp->dump_data.rd_dev)
+		dev_info(dev, "%s: create_ramdump_device failed\n", __func__);
+
+	ret = component_bind_all(dev, wdsp->ops);
+	if (ret < 0)
+		WDSP_ERR(wdsp, "component_bind_all failed %d\n", ret);
+
+	/* Make sure all components registered ops */
+	for (idx = 0; idx < WDSP_CMPNT_TYPE_MAX; idx++) {
+		cmpnt = WDSP_GET_COMPONENT(wdsp, idx);
+		if (!cmpnt->cdev || !cmpnt->ops) {
+			WDSP_ERR(wdsp, "%s did not register ops\n",
+				 WDSP_GET_CMPNT_TYPE_STR(idx));
+			ret = -EINVAL;
+			component_unbind_all(dev, wdsp->ops);
+			break;
+		}
+	}
+
+	wdsp_mgr_debugfs_init(wdsp);
+
+	/* Schedule the work to download image if binding was successful. */
+	if (!ret)
+		schedule_work(&wdsp->load_fw_work);
+
+	return ret;
+}
+
+static void wdsp_mgr_unbind(struct device *dev)
+{
+	struct wdsp_mgr_priv *wdsp = dev_get_drvdata(dev);
+	struct wdsp_cmpnt *cmpnt;
+	int idx;
+
+	component_unbind_all(dev, wdsp->ops);
+
+	wdsp_mgr_debugfs_remove(wdsp);
+
+	if (wdsp->dump_data.rd_dev) {
+		destroy_ramdump_device(wdsp->dump_data.rd_dev);
+		wdsp->dump_data.rd_dev = NULL;
+	}
+
+	/* Clear all status bits */
+	wdsp->status = 0x00;
+
+	/* clean up the components */
+	for (idx = 0; idx < WDSP_CMPNT_TYPE_MAX; idx++) {
+		cmpnt = WDSP_GET_COMPONENT(wdsp, idx);
+		cmpnt->cdev = NULL;
+		cmpnt->ops = NULL;
+		cmpnt->priv_data = NULL;
+	}
+}
+
+static const struct component_master_ops wdsp_master_ops = {
+	.bind = wdsp_mgr_bind,
+	.unbind = wdsp_mgr_unbind,
+};
+
+static void *wdsp_mgr_parse_phandle(struct wdsp_mgr_priv *wdsp,
+				    int index)
+{
+	struct device *mdev = wdsp->mdev;
+	struct device_node *np;
+	struct wdsp_cmpnt *cmpnt = NULL;
+	struct of_phandle_args pargs;
+	u32 value;
+	int ret;
+
+	ret = of_parse_phandle_with_fixed_args(mdev->of_node,
+					      "qcom,wdsp-components", 1,
+					      index, &pargs);
+	if (ret) {
+		WDSP_ERR(wdsp, "parse_phandle at index %d failed %d",
+			 index, ret);
+		return NULL;
+	}
+
+	np = pargs.np;
+	value = pargs.args[0];
+
+	if (value >= WDSP_CMPNT_TYPE_MAX) {
+		WDSP_ERR(wdsp, "invalid phandle_arg to of_node %s", np->name);
+		goto done;
+	}
+
+	cmpnt = WDSP_GET_COMPONENT(wdsp, value);
+	if (cmpnt->np || cmpnt->cdev_name) {
+		WDSP_ERR(wdsp, "cmpnt %d already added", value);
+		cmpnt = NULL;
+		goto done;
+	}
+
+	cmpnt->np = np;
+	of_property_read_string(np, "qcom,wdsp-cmpnt-dev-name",
+				&cmpnt->cdev_name);
+done:
+	of_node_put(np);
+	return cmpnt;
+}
+
+static int wdsp_mgr_parse_dt_entries(struct wdsp_mgr_priv *wdsp)
+{
+	struct device *dev = wdsp->mdev;
+	void *match_data;
+	int ph_idx, ret;
+
+	ret = of_property_read_string(dev->of_node, "qcom,img-filename",
+				      &wdsp->img_fname);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Reading property %s failed, error = %d",
+			 "qcom,img-filename", ret);
+		return ret;
+	}
+
+	ret = of_count_phandle_with_args(dev->of_node,
+					 "qcom,wdsp-components",
+					 NULL);
+	if (ret == -ENOENT) {
+		WDSP_ERR(wdsp, "Property %s not defined in DT",
+			 "qcom,wdsp-components");
+		goto done;
+	} else if (ret != WDSP_CMPNT_TYPE_MAX * 2) {
+		WDSP_ERR(wdsp, "Invalid phandle + arg count %d, expected %d",
+			 ret, WDSP_CMPNT_TYPE_MAX * 2);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = 0;
+
+	for (ph_idx = 0; ph_idx < WDSP_CMPNT_TYPE_MAX; ph_idx++) {
+
+		match_data = wdsp_mgr_parse_phandle(wdsp, ph_idx);
+		if (!match_data) {
+			WDSP_ERR(wdsp, "component not found at idx %d", ph_idx);
+			ret = -EINVAL;
+			goto done;
+		}
+
+		component_match_add(dev, &wdsp->match,
+				    wdsp_mgr_compare_of, match_data);
+	}
+
+done:
+	return ret;
+}
+
+static int wdsp_mgr_probe(struct platform_device *pdev)
+{
+	struct wdsp_mgr_priv *wdsp;
+	struct device *mdev = &pdev->dev;
+	int ret;
+
+	wdsp = devm_kzalloc(mdev, sizeof(*wdsp), GFP_KERNEL);
+	if (!wdsp)
+		return -ENOMEM;
+	wdsp->mdev = mdev;
+	wdsp->seg_list = devm_kzalloc(mdev, sizeof(struct list_head),
+				      GFP_KERNEL);
+	if (!wdsp->seg_list) {
+		devm_kfree(mdev, wdsp);
+		return -ENOMEM;
+	}
+
+	ret = wdsp_mgr_parse_dt_entries(wdsp);
+	if (ret)
+		goto err_dt_parse;
+
+	INIT_WORK(&wdsp->load_fw_work, wdsp_load_fw_image);
+	INIT_LIST_HEAD(wdsp->seg_list);
+	mutex_init(&wdsp->api_mutex);
+	mutex_init(&wdsp->ssr_mutex);
+	wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR;
+	wdsp->ready_status = WDSP_SSR_STATUS_READY;
+	INIT_WORK(&wdsp->ssr_work, wdsp_ssr_work_fn);
+	init_completion(&wdsp->ready_compl);
+	arch_setup_dma_ops(wdsp->mdev, 0, 0, NULL, 0);
+	dev_set_drvdata(mdev, wdsp);
+
+	ret = component_master_add_with_match(mdev, &wdsp_master_ops,
+					      wdsp->match);
+	if (ret < 0) {
+		WDSP_ERR(wdsp, "Failed to add master, err = %d", ret);
+		goto err_master_add;
+	}
+
+	return 0;
+
+err_master_add:
+	mutex_destroy(&wdsp->api_mutex);
+	mutex_destroy(&wdsp->ssr_mutex);
+err_dt_parse:
+	devm_kfree(mdev, wdsp->seg_list);
+	devm_kfree(mdev, wdsp);
+	dev_set_drvdata(mdev, NULL);
+
+	return ret;
+}
+
+static int wdsp_mgr_remove(struct platform_device *pdev)
+{
+	struct device *mdev = &pdev->dev;
+	struct wdsp_mgr_priv *wdsp = dev_get_drvdata(mdev);
+
+	component_master_del(mdev, &wdsp_master_ops);
+
+	mutex_destroy(&wdsp->api_mutex);
+	mutex_destroy(&wdsp->ssr_mutex);
+	devm_kfree(mdev, wdsp->seg_list);
+	devm_kfree(mdev, wdsp);
+	dev_set_drvdata(mdev, NULL);
+
+	return 0;
+};
+
+static const struct of_device_id wdsp_mgr_dt_match[] = {
+	{.compatible = "qcom,wcd-dsp-mgr" },
+	{ }
+};
+
+static struct platform_driver wdsp_mgr_driver = {
+	.driver = {
+		.name = "wcd-dsp-mgr",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(wdsp_mgr_dt_match),
+	},
+	.probe = wdsp_mgr_probe,
+	.remove = wdsp_mgr_remove,
+};
+
+int wcd_dsp_mgr_init(void)
+{
+	return platform_driver_register(&wdsp_mgr_driver);
+}
+
+void wcd_dsp_mgr_exit(void)
+{
+	platform_driver_unregister(&wdsp_mgr_driver);
+}
+
+MODULE_DESCRIPTION("WCD DSP manager driver");
+MODULE_DEVICE_TABLE(of, wdsp_mgr_dt_match);
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd-dsp-utils.c b/asoc/codecs/wcd-dsp-utils.c
new file mode 100644
index 0000000..4eafd55
--- /dev/null
+++ b/asoc/codecs/wcd-dsp-utils.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/elf.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include "wcd-dsp-utils.h"
+
+static bool wdsp_is_valid_elf_hdr(const struct elf32_hdr *ehdr,
+				  size_t fw_size)
+{
+	if (fw_size < sizeof(*ehdr)) {
+		pr_err("%s: Firmware too small\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+		pr_err("%s: Not an ELF file\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
+		pr_err("%s: Not an executable image\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		pr_err("%s: no segments to load\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
+	    sizeof(struct elf32_hdr) > fw_size) {
+		pr_err("%s: Too small MDT file\n", __func__);
+		goto elf_check_fail;
+	}
+
+	return true;
+
+elf_check_fail:
+	return false;
+}
+
+static int wdsp_add_segment_to_list(struct device *dev,
+				    const char *img_fname,
+				    const struct elf32_phdr *phdr,
+				    int phdr_idx,
+				    struct list_head *seg_list)
+{
+	struct wdsp_img_segment *seg;
+	int ret = 0;
+
+	/* Do not load segments with zero size */
+	if (phdr->p_filesz == 0 || phdr->p_memsz == 0)
+		goto done;
+
+	seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+	if (!seg) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(seg->split_fname, sizeof(seg->split_fname),
+		 "%s.b%02d", img_fname, phdr_idx);
+	ret = request_firmware(&seg->split_fw, seg->split_fname, dev);
+	if (ret < 0) {
+		dev_err(dev, "%s: firmware %s not found\n",
+			__func__, seg->split_fname);
+		goto bad_seg;
+	}
+
+	seg->load_addr = phdr->p_paddr;
+	seg->size = phdr->p_filesz;
+	seg->data = (u8 *) seg->split_fw->data;
+
+	list_add_tail(&seg->list, seg_list);
+done:
+	return ret;
+bad_seg:
+	kfree(seg);
+	return ret;
+}
+
+/*
+ * wdsp_flush_segment_list: Flush the list of segments
+ * @seg_list: List of segments to be flushed
+ * This API will traverse through the list of segments provided in
+ * seg_list, release the firmware for each segment and delete the
+ * segment from the list.
+ */
+void wdsp_flush_segment_list(struct list_head *seg_list)
+{
+	struct wdsp_img_segment *seg, *next;
+
+	list_for_each_entry_safe(seg, next, seg_list, list) {
+		release_firmware(seg->split_fw);
+		list_del(&seg->list);
+		kfree(seg);
+	}
+}
+EXPORT_SYMBOL(wdsp_flush_segment_list);
+
+/*
+ * wdsp_get_segment_list: Get the list of requested segments
+ * @dev: struct device pointer of caller
+ * @img_fname: Image name for the mdt and split firmware files
+ * @segment_type: Requested segment type, should be either
+ *		  WDSP_ELF_FLAG_RE or WDSP_ELF_FLAG_WRITE
+ * @seg_list: An initialized head for list of segmented to be returned
+ * @entry_point: Pointer to return the entry point of the image
+ * This API will parse the mdt file for img_fname and create
+ * an struct wdsp_img_segment for each segment that matches segment_type
+ * and add this structure to list pointed by seg_list
+ */
+int wdsp_get_segment_list(struct device *dev,
+			  const char *img_fname,
+			  unsigned int segment_type,
+			  struct list_head *seg_list,
+			  u32 *entry_point)
+{
+	const struct firmware *fw;
+	const struct elf32_hdr *ehdr;
+	const struct elf32_phdr *phdr;
+	const u8 *elf_ptr;
+	char mdt_name[WDSP_IMG_NAME_LEN_MAX];
+	int ret, phdr_idx;
+	bool segment_match;
+
+	if (!dev) {
+		ret = -EINVAL;
+		pr_err("%s: Invalid device handle\n", __func__);
+		goto done;
+	}
+
+	if (!img_fname || !seg_list || !entry_point) {
+		ret = -EINVAL;
+		dev_err(dev, "%s: Invalid input params\n",
+			__func__);
+		goto done;
+	}
+
+	if (segment_type != WDSP_ELF_FLAG_RE &&
+	    segment_type != WDSP_ELF_FLAG_WRITE) {
+		dev_err(dev, "%s: Invalid request for segment_type %d\n",
+			__func__, segment_type);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	snprintf(mdt_name, sizeof(mdt_name), "%s.mdt", img_fname);
+	ret = request_firmware(&fw, mdt_name, dev);
+	if (ret < 0) {
+		dev_err(dev, "%s: firmware %s not found\n",
+			__func__, mdt_name);
+		goto done;
+	}
+
+	ehdr = (struct elf32_hdr *) fw->data;
+	*entry_point = ehdr->e_entry;
+	if (!wdsp_is_valid_elf_hdr(ehdr, fw->size)) {
+		dev_err(dev, "%s: fw mdt %s is invalid\n",
+			__func__, mdt_name);
+		ret = -EINVAL;
+		goto bad_elf;
+	}
+
+	elf_ptr = fw->data + sizeof(*ehdr);
+	for (phdr_idx = 0; phdr_idx < ehdr->e_phnum; phdr_idx++) {
+		phdr = (struct elf32_phdr *) elf_ptr;
+		segment_match = false;
+
+		switch (segment_type) {
+		case WDSP_ELF_FLAG_RE:
+			/*
+			 * Flag can be READ or EXECUTE or both but
+			 * WRITE flag should not be set.
+			 */
+			if ((phdr->p_flags & segment_type) &&
+			    !(phdr->p_flags & WDSP_ELF_FLAG_WRITE))
+				segment_match = true;
+			break;
+		case WDSP_ELF_FLAG_WRITE:
+			/*
+			 * If WRITE flag is set, other flags do not
+			 * matter.
+			 */
+			if (phdr->p_flags & segment_type)
+				segment_match = true;
+			break;
+		}
+
+		if (segment_match) {
+			ret = wdsp_add_segment_to_list(dev, img_fname, phdr,
+						       phdr_idx, seg_list);
+			if (ret < 0) {
+				wdsp_flush_segment_list(seg_list);
+				goto bad_elf;
+			}
+		}
+		elf_ptr = elf_ptr + sizeof(*phdr);
+	}
+
+bad_elf:
+	release_firmware(fw);
+done:
+	return ret;
+}
+EXPORT_SYMBOL(wdsp_get_segment_list);
diff --git a/asoc/codecs/wcd-dsp-utils.h b/asoc/codecs/wcd-dsp-utils.h
new file mode 100644
index 0000000..a530a1c
--- /dev/null
+++ b/asoc/codecs/wcd-dsp-utils.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD_DSP_UTILS_H__
+#define __WCD_DSP_UTILS_H__
+
+#define WDSP_IMG_NAME_LEN_MAX    64
+
+#define WDSP_ELF_FLAG_EXECUTE    (1 << 0)
+#define WDSP_ELF_FLAG_WRITE      (1 << 1)
+#define WDSP_ELF_FLAG_READ       (1 << 2)
+
+#define WDSP_ELF_FLAG_RE (WDSP_ELF_FLAG_READ | WDSP_ELF_FLAG_EXECUTE)
+
+struct wdsp_img_segment {
+
+	/* Firmware for the slit image */
+	const struct firmware *split_fw;
+
+	/* Name of the split firmware file */
+	char split_fname[WDSP_IMG_NAME_LEN_MAX];
+
+	/* Address where the segment is to be loaded */
+	u32 load_addr;
+
+	/* Buffer to hold the data to be loaded */
+	u8 *data;
+
+	/* Size of the data to be loaded */
+	size_t size;
+
+	/* List node pointing to next segment */
+	struct list_head list;
+};
+
+int wdsp_get_segment_list(struct device *dev, const char *img_fname,
+			  unsigned int segment_type, struct list_head *seg_list,
+			  u32 *entry_point);
+void wdsp_flush_segment_list(struct list_head *seg_list);
+
+#endif /* __WCD_DSP_UTILS_H__ */
diff --git a/asoc/codecs/wcd-mbhc-adc.c b/asoc/codecs/wcd-mbhc-adc.c
new file mode 100644
index 0000000..e44eec9
--- /dev/null
+++ b/asoc/codecs/wcd-mbhc-adc.c
@@ -0,0 +1,1020 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/firmware.h>
+#include <linux/completion.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "wcd-mbhc-adc.h"
+#include "wcd-mbhc-v2.h"
+
+#define WCD_MBHC_ADC_HS_THRESHOLD_MV    1700
+#define WCD_MBHC_ADC_HPH_THRESHOLD_MV   75
+#define WCD_MBHC_ADC_MICBIAS_MV         1800
+
+static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
+{
+	int micbias = 0;
+	u8 vout_ctl = 0;
+
+	/* Read MBHC Micbias (Mic Bias2) voltage */
+	WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl);
+
+	/* Formula for getting micbias from vout
+	 * micbias = 1.0V + VOUT_CTL * 50mV
+	 */
+	micbias = 1000 + (vout_ctl * 50);
+	pr_debug("%s: vout_ctl: %d, micbias: %d\n",
+		 __func__, vout_ctl, micbias);
+
+	return micbias;
+}
+
+static int wcd_get_voltage_from_adc(u8 val, int micbias)
+{
+	/* Formula for calculating voltage from ADC
+	 * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8
+	 */
+	return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10));
+}
+
+static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
+{
+	u8 adc_result = 0;
+	int output_mv = 0;
+	int retry = 3;
+	u8 adc_en = 0;
+
+	pr_debug("%s: enter\n", __func__);
+
+	/* Pre-requisites for ADC continuous measurement */
+	/* Read legacy electircal detection and disable */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
+	/* Set ADC to continuous measurement */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 1);
+	/* Read ADC Enable bit to restore after adc measurement */
+	WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en);
+	/* Disable ADC_ENABLE bit */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
+	/* Disable MBHC FSM */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+	/* Set the MUX selection to IN2P */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
+	/* Enable MBHC FSM */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+	/* Enable ADC_ENABLE bit */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1);
+
+	while (retry--) {
+		/* wait for 3 msec before reading ADC result */
+		usleep_range(3000, 3100);
+
+		/* Read ADC result */
+		WCD_MBHC_REG_READ(WCD_MBHC_ADC_RESULT, adc_result);
+	}
+
+	/* Restore ADC Enable */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en);
+	/* Get voltage from ADC result */
+	output_mv = wcd_get_voltage_from_adc(adc_result,
+					     wcd_mbhc_get_micbias(mbhc));
+	pr_debug("%s: adc_result: 0x%x, output_mv: %d\n",
+		 __func__, adc_result, output_mv);
+
+	return output_mv;
+}
+
+static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
+{
+	u8 adc_timeout = 0;
+	u8 adc_complete = 0;
+	u8 adc_result = 0;
+	int retry = 6;
+	int ret = 0;
+	int output_mv = 0;
+	u8 adc_en = 0;
+
+	pr_debug("%s: enter\n", __func__);
+
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
+	/* Read ADC Enable bit to restore after adc measurement */
+	WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en);
+	/* Trigger ADC one time measurement */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+	/* Set the appropriate MUX selection */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, mux_ctl);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1);
+
+	while (retry--) {
+		/* wait for 600usec to get adc results */
+		usleep_range(600, 610);
+
+		/* check for ADC Timeout */
+		WCD_MBHC_REG_READ(WCD_MBHC_ADC_TIMEOUT, adc_timeout);
+		if (adc_timeout)
+			continue;
+
+		/* Read ADC complete bit */
+		WCD_MBHC_REG_READ(WCD_MBHC_ADC_COMPLETE, adc_complete);
+		if (!adc_complete)
+			continue;
+
+		/* Read ADC result */
+		WCD_MBHC_REG_READ(WCD_MBHC_ADC_RESULT, adc_result);
+
+		pr_debug("%s: ADC result: 0x%x\n", __func__, adc_result);
+		/* Get voltage from ADC result */
+		output_mv = wcd_get_voltage_from_adc(adc_result,
+						wcd_mbhc_get_micbias(mbhc));
+		break;
+	}
+
+	/* Restore ADC Enable */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en);
+
+	if (retry <= 0) {
+		pr_err("%s: adc complete: %d, adc timeout: %d\n",
+			__func__, adc_complete, adc_timeout);
+		ret = -EINVAL;
+	} else {
+		pr_debug("%s: adc complete: %d, adc timeout: %d output_mV: %d\n",
+			__func__, adc_complete, adc_timeout, output_mv);
+		ret = output_mv;
+	}
+
+	pr_debug("%s: leave\n", __func__);
+
+	return ret;
+}
+
+static bool wcd_mbhc_adc_detect_anc_plug_type(struct wcd_mbhc *mbhc)
+{
+	bool anc_mic_found = false;
+	u16 fsm_en = 0;
+	u8 det = 0;
+	unsigned long retry = 0;
+	int valid_plug_cnt = 0, invalid_plug_cnt = 0;
+	int ret = 0;
+	u8 elect_ctl = 0;
+	u8 adc_mode = 0;
+	u8 vref = 0;
+	int vref_mv[] = {1650, 1500, 1600, 1700};
+
+	if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 ||
+	    mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4)
+		return false;
+
+	if (!mbhc->mbhc_cb->mbhc_micbias_control)
+		return false;
+
+	/* Disable Detection done for ADC operation */
+	WCD_MBHC_REG_READ(WCD_MBHC_DETECTION_DONE, det);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
+
+	/* Mask ADC COMPLETE interrupt */
+	wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
+
+	WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
+	mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
+					    mbhc->mbhc_cfg->anc_micbias,
+					    MICB_ENABLE);
+
+	/* Read legacy electircal detection and disable */
+	WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
+
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1);
+	WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode);
+
+	/*
+	 * wait for button debounce time 20ms. If 4-pole plug is inserted
+	 * into 5-pole jack, then there will be a button press interrupt
+	 * during anc plug detection. In that case though Hs_comp_res is 0,
+	 * it should not be declared as ANC plug type
+	 */
+	usleep_range(20000, 20100);
+
+	/*
+	 * After enabling FSM, to handle slow insertion scenarios,
+	 * check IN3 voltage is below the Vref
+	 */
+	WCD_MBHC_REG_READ(WCD_MBHC_HS_VREF, vref);
+
+	do {
+		if (wcd_swch_level_remove(mbhc)) {
+			pr_debug("%s: Switch level is low\n", __func__);
+			goto done;
+		}
+		pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1);
+		ret = wcd_measure_adc_once(mbhc, MUX_CTL_IN3P);
+		/* TODO - check the logic */
+		if (ret && (ret < vref_mv[vref]))
+			valid_plug_cnt++;
+		else
+			invalid_plug_cnt++;
+		retry++;
+	} while (retry < ANC_DETECT_RETRY_CNT);
+
+	pr_debug("%s: valid: %d, invalid: %d\n", __func__, valid_plug_cnt,
+		 invalid_plug_cnt);
+
+	/* decision logic */
+	if (valid_plug_cnt > invalid_plug_cnt)
+		anc_mic_found = true;
+done:
+	/* Restore ADC mode */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, adc_mode);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+	/* Set the MUX selection to AUTO */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en);
+	/* Restore detection done */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, det);
+
+	/* Restore electrical detection */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
+
+	mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
+					    mbhc->mbhc_cfg->anc_micbias,
+					    MICB_DISABLE);
+	pr_debug("%s: anc mic %sfound\n", __func__,
+		 anc_mic_found ? "" : "not ");
+
+	return anc_mic_found;
+}
+
+/* To determine if cross connection occurred */
+static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
+{
+	enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE;
+	int hphl_adc_res = 0, hphr_adc_res = 0;
+	u8 fsm_en = 0;
+	int ret = 0;
+	u8 adc_mode = 0;
+	u8 elect_ctl = 0;
+	u8 adc_en = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	/* Check for button press and plug detection */
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low\n", __func__);
+		return -EINVAL;
+	}
+
+	/* If PA is enabled, dont check for cross-connection */
+	if (mbhc->mbhc_cb->hph_pa_on_status)
+		if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec))
+			return -EINVAL;
+
+	/* Read legacy electircal detection and disable */
+	WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
+
+	/* Read and set ADC to single measurement */
+	WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode);
+	/* Read ADC Enable bit to restore after adc measurement */
+	WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en);
+	/* Read FSM status */
+	WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
+
+	/* Get adc result for HPH L */
+	hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L);
+	if (hphl_adc_res < 0) {
+		pr_err("%s: hphl_adc_res adc measurement failed\n", __func__);
+		ret = hphl_adc_res;
+		goto done;
+	}
+
+	/* Get adc result for HPH R in mV */
+	hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R);
+	if (hphr_adc_res < 0) {
+		pr_err("%s: hphr_adc_res adc measurement failed\n", __func__);
+		ret = hphr_adc_res;
+		goto done;
+	}
+
+	if (hphl_adc_res > 100 && hphr_adc_res > 100) {
+		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+		pr_debug("%s: Cross connection identified\n", __func__);
+	} else {
+		pr_debug("%s: No Cross connection found\n", __func__);
+	}
+
+done:
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+	/* Set the MUX selection to Auto */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+
+	/* Restore ADC Enable */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en);
+
+	/* Restore ADC mode */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, adc_mode);
+
+	/* Restore FSM state */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en);
+
+	/* Restore electrical detection */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
+
+	pr_debug("%s: leave, plug type: %d\n", __func__,  plug_type);
+
+	return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
+}
+
+static bool wcd_mbhc_adc_check_for_spl_headset(struct wcd_mbhc *mbhc,
+					   int *spl_hs_cnt)
+{
+	bool spl_hs = false;
+	int output_mv = 0;
+	int adc_threshold = 0, adc_hph_threshold = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
+		goto exit;
+
+	/* Bump up MB2 to 2.7V */
+	mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
+				mbhc->mbhc_cfg->mbhc_micbias, true);
+	usleep_range(10000, 10100);
+
+	/*
+	 * Use ADC single mode to minimize the chance of missing out
+	 * btn press/relesae for HEADSET type during correct work.
+	 */
+	output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
+	adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
+			  wcd_mbhc_get_micbias(mbhc))/WCD_MBHC_ADC_MICBIAS_MV);
+	adc_hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV *
+			      wcd_mbhc_get_micbias(mbhc))/
+			      WCD_MBHC_ADC_MICBIAS_MV);
+
+	if (output_mv > adc_threshold || output_mv < adc_hph_threshold) {
+		spl_hs = false;
+	} else {
+		spl_hs = true;
+		if (spl_hs_cnt)
+			*spl_hs_cnt += 1;
+	}
+
+	/* MB2 back to 1.8v if the type is not special headset */
+	if (spl_hs_cnt && (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT)) {
+		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
+				mbhc->mbhc_cfg->mbhc_micbias, false);
+		/* Add 10ms delay for micbias to settle */
+		usleep_range(10000, 10100);
+	}
+
+	if (spl_hs)
+		pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);
+
+exit:
+	pr_debug("%s: leave\n", __func__);
+	return spl_hs;
+}
+
+static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
+{
+	int delay = 0;
+	bool ret = false;
+	bool is_spl_hs = false;
+	int output_mv = 0;
+	int adc_threshold = 0;
+
+	/*
+	 * Increase micbias to 2.7V to detect headsets with
+	 * threshold on microphone
+	 */
+	if (mbhc->mbhc_cb->mbhc_micbias_control &&
+	    !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
+		pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n",
+			 __func__);
+		return false;
+	} else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
+		ret = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
+							MIC_BIAS_2, true);
+		if (ret) {
+			pr_err("%s: mbhc_micb_ctrl_thr_mic failed, ret: %d\n",
+				__func__, ret);
+			return false;
+		}
+	}
+
+	adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
+			  wcd_mbhc_get_micbias(mbhc)) /
+			  WCD_MBHC_ADC_MICBIAS_MV);
+
+	while (!is_spl_hs) {
+		if (mbhc->hs_detect_work_stop) {
+			pr_debug("%s: stop requested: %d\n", __func__,
+					mbhc->hs_detect_work_stop);
+			break;
+		}
+		delay += 50;
+		/* Wait for 50ms for FSM to update result */
+		msleep(50);
+		output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
+		if (output_mv <= adc_threshold) {
+			pr_debug("%s: Special headset detected in %d msecs\n",
+					__func__, delay);
+			is_spl_hs = true;
+		}
+
+		if (delay == SPECIAL_HS_DETECT_TIME_MS) {
+			pr_debug("%s: Spl headset not found in 2 sec\n",
+				 __func__);
+			break;
+		}
+	}
+	if (is_spl_hs) {
+		pr_debug("%s: Headset with threshold found\n",  __func__);
+		mbhc->micbias_enable = true;
+		ret = true;
+	}
+	if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
+	    !mbhc->micbias_enable)
+		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec, MIC_BIAS_2,
+						      false);
+	pr_debug("%s: leave, micb_enable: %d\n", __func__,
+		  mbhc->micbias_enable);
+
+	return ret;
+}
+
+static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
+				       enum wcd_mbhc_plug_type plug_type)
+{
+	bool micbias2;
+
+	micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+							MIC_BIAS_2);
+	switch (plug_type) {
+	case MBHC_PLUG_TYPE_HEADPHONE:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
+		break;
+	case MBHC_PLUG_TYPE_HEADSET:
+	case MBHC_PLUG_TYPE_ANC_HEADPHONE:
+		if (!mbhc->is_hs_recording && !micbias2)
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
+		break;
+	default:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
+		break;
+
+	};
+}
+
+/* should be called under interrupt context that hold suspend */
+static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
+					    struct work_struct *work)
+{
+	pr_debug("%s: scheduling correct_swch_plug\n", __func__);
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+	mbhc->hs_detect_work_stop = false;
+	mbhc->mbhc_cb->lock_sleep(mbhc, true);
+	schedule_work(work);
+}
+
+/* called under codec_resource_lock acquisition */
+static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
+					 struct work_struct *work)
+{
+	pr_debug("%s: Canceling correct_plug_swch\n", __func__);
+	mbhc->hs_detect_work_stop = true;
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	if (cancel_work_sync(work)) {
+		pr_debug("%s: correct_plug_swch is canceled\n",
+			 __func__);
+		mbhc->mbhc_cb->lock_sleep(mbhc, false);
+	}
+	WCD_MBHC_RSC_LOCK(mbhc);
+}
+
+/* called under codec_resource_lock acquisition */
+static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
+		mbhc->mbhc_cb->hph_pull_down_ctrl(codec, false);
+
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
+
+	if (mbhc->mbhc_cb->mbhc_micbias_control) {
+		mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
+						    MICB_ENABLE);
+	} else {
+		pr_err("%s: Mic Bias is not enabled\n", __func__);
+		return;
+	}
+
+	/* Re-initialize button press completion object */
+	reinit_completion(&mbhc->btn_press_compl);
+	wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
+{
+	if (mbhc->micbias_enable) {
+		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+			mbhc->codec, MIC_BIAS_2, false);
+		if (mbhc->mbhc_cb->set_micbias_value)
+			mbhc->mbhc_cb->set_micbias_value(
+					mbhc->codec);
+		mbhc->micbias_enable = false;
+	}
+}
+
+static int wcd_mbhc_get_plug_from_adc(int adc_result)
+
+{
+	enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
+
+	if (adc_result < WCD_MBHC_ADC_HPH_THRESHOLD_MV)
+		plug_type = MBHC_PLUG_TYPE_HEADPHONE;
+	else if (adc_result > WCD_MBHC_ADC_HS_THRESHOLD_MV)
+		plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
+	else
+		plug_type = MBHC_PLUG_TYPE_HEADSET;
+	pr_debug("%s: plug type is %d found\n", __func__, plug_type);
+
+	return plug_type;
+}
+
+static void wcd_correct_swch_plug(struct work_struct *work)
+{
+	struct wcd_mbhc *mbhc;
+	struct snd_soc_codec *codec;
+	enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
+	unsigned long timeout;
+	bool wrk_complete = false;
+	int pt_gnd_mic_swap_cnt = 0;
+	int no_gnd_mic_swap_cnt = 0;
+	bool is_pa_on = false, spl_hs = false, spl_hs_reported = false;
+	int ret = 0;
+	int spl_hs_count = 0;
+	int output_mv = 0;
+	int cross_conn;
+	int try = 0;
+
+	pr_debug("%s: enter\n", __func__);
+
+	mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
+	codec = mbhc->codec;
+
+	WCD_MBHC_RSC_LOCK(mbhc);
+	/* Mask ADC COMPLETE interrupt */
+	wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+
+	/* Check for cross connection */
+	do {
+		cross_conn = wcd_check_cross_conn(mbhc);
+		try++;
+	} while (try < GND_MIC_SWAP_THRESHOLD);
+
+	if (cross_conn > 0) {
+		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+		pr_debug("%s: cross connection found, Plug type %d\n",
+			 __func__, plug_type);
+		goto correct_plug_type;
+	}
+	/* Find plug type */
+	output_mv = wcd_measure_adc_continuous(mbhc);
+	plug_type = wcd_mbhc_get_plug_from_adc(output_mv);
+
+	/*
+	 * Report plug type if it is either headset or headphone
+	 * else start the 3 sec loop
+	 */
+	if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
+	     plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
+	    (!wcd_swch_level_remove(mbhc))) {
+		WCD_MBHC_RSC_LOCK(mbhc);
+		wcd_mbhc_find_plug_and_report(mbhc, plug_type);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+	}
+
+	/*
+	 * Set DETECTION_DONE bit for HEADSET and ANC_HEADPHONE,
+	 * so that btn press/release interrupt can be generated.
+	 */
+	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET ||
+		mbhc->current_plug == MBHC_PLUG_TYPE_ANC_HEADPHONE) {
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1);
+	}
+
+correct_plug_type:
+	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
+	while (!time_after(jiffies, timeout)) {
+		if (mbhc->hs_detect_work_stop) {
+			pr_debug("%s: stop requested: %d\n", __func__,
+					mbhc->hs_detect_work_stop);
+			wcd_micbias_disable(mbhc);
+			goto exit;
+		}
+
+		/* allow sometime and re-check stop requested again */
+		msleep(20);
+		if (mbhc->hs_detect_work_stop) {
+			pr_debug("%s: stop requested: %d\n", __func__,
+					mbhc->hs_detect_work_stop);
+			wcd_micbias_disable(mbhc);
+			goto exit;
+		}
+
+		msleep(180);
+		/*
+		 * Use ADC single mode to minimize the chance of missing out
+		 * btn press/release for HEADSET type during correct work.
+		 */
+		output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
+
+		/*
+		 * instead of hogging system by contineous polling, wait for
+		 * sometime and re-check stop request again.
+		 */
+		plug_type = wcd_mbhc_get_plug_from_adc(output_mv);
+
+		if ((output_mv > WCD_MBHC_ADC_HS_THRESHOLD_MV) &&
+		    (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) {
+			spl_hs = wcd_mbhc_adc_check_for_spl_headset(mbhc,
+								&spl_hs_count);
+
+			if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
+				output_mv = WCD_MBHC_ADC_HS_THRESHOLD_MV;
+				spl_hs = true;
+				mbhc->micbias_enable = true;
+			}
+		}
+
+		if (mbhc->mbhc_cb->hph_pa_on_status)
+			is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec);
+
+		if ((output_mv <= WCD_MBHC_ADC_HS_THRESHOLD_MV) &&
+		    (!is_pa_on)) {
+			/* Check for cross connection*/
+			ret = wcd_check_cross_conn(mbhc);
+			if (ret < 0)
+				continue;
+			else if (ret > 0) {
+				pt_gnd_mic_swap_cnt++;
+				no_gnd_mic_swap_cnt = 0;
+				if (pt_gnd_mic_swap_cnt <
+						GND_MIC_SWAP_THRESHOLD) {
+					continue;
+				} else if (pt_gnd_mic_swap_cnt >
+					   GND_MIC_SWAP_THRESHOLD) {
+					/*
+					 * This is due to GND/MIC switch didn't
+					 * work,  Report unsupported plug.
+					 */
+					pr_debug("%s: switch did not work\n",
+						 __func__);
+					plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+					goto report;
+				} else {
+					plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+				}
+			} else {
+				no_gnd_mic_swap_cnt++;
+				pt_gnd_mic_swap_cnt = 0;
+				plug_type = wcd_mbhc_get_plug_from_adc(
+						output_mv);
+				if ((no_gnd_mic_swap_cnt <
+				    GND_MIC_SWAP_THRESHOLD) &&
+				    (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) {
+					continue;
+				} else {
+					no_gnd_mic_swap_cnt = 0;
+				}
+			}
+			if ((pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) &&
+				(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
+				/*
+				 * if switch is toggled, check again,
+				 * otherwise report unsupported plug
+				 */
+				if (mbhc->mbhc_cfg->swap_gnd_mic &&
+					mbhc->mbhc_cfg->swap_gnd_mic(codec,
+					true)) {
+					pr_debug("%s: US_EU gpio present,flip switch\n"
+						, __func__);
+					continue;
+				}
+			}
+		}
+
+		if (output_mv > WCD_MBHC_ADC_HS_THRESHOLD_MV) {
+			pr_debug("%s: cable is extension cable\n", __func__);
+			plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
+			wrk_complete = true;
+		} else {
+			pr_debug("%s: cable might be headset: %d\n", __func__,
+				 plug_type);
+			if (plug_type != MBHC_PLUG_TYPE_GND_MIC_SWAP) {
+				plug_type = wcd_mbhc_get_plug_from_adc(
+						output_mv);
+				if (!spl_hs_reported &&
+				    spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
+					spl_hs_reported = true;
+					WCD_MBHC_RSC_LOCK(mbhc);
+					wcd_mbhc_find_plug_and_report(mbhc,
+								    plug_type);
+					WCD_MBHC_RSC_UNLOCK(mbhc);
+					continue;
+				} else if (spl_hs_reported)
+					continue;
+				/*
+				 * Report headset only if not already reported
+				 * and if there is not button press without
+				 * release
+				 */
+				if ((mbhc->current_plug !=
+				      MBHC_PLUG_TYPE_HEADSET) &&
+				     (mbhc->current_plug !=
+				     MBHC_PLUG_TYPE_ANC_HEADPHONE) &&
+				    !wcd_swch_level_remove(mbhc)) {
+					pr_debug("%s: cable is %s headset\n",
+						 __func__,
+						((spl_hs_count ==
+							WCD_MBHC_SPL_HS_CNT) ?
+							"special ":""));
+					goto report;
+				}
+			}
+			wrk_complete = false;
+		}
+	}
+	if (!wrk_complete) {
+		/*
+		 * If plug_tye is headset, we might have already reported either
+		 * in detect_plug-type or in above while loop, no need to report
+		 * again
+		 */
+		if ((plug_type == MBHC_PLUG_TYPE_HEADSET) ||
+		    (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE)) {
+			pr_debug("%s: plug_type:0x%x already reported\n",
+				 __func__, mbhc->current_plug);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
+			goto enable_supply;
+		}
+	}
+	if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
+		if (wcd_is_special_headset(mbhc)) {
+			pr_debug("%s: Special headset found %d\n",
+					__func__, plug_type);
+			plug_type = MBHC_PLUG_TYPE_HEADSET;
+		} else {
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 1);
+		}
+	}
+
+report:
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low\n", __func__);
+		goto exit;
+	}
+
+	pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
+			__func__, plug_type, wrk_complete,
+			mbhc->btn_press_intr);
+
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
+
+	WCD_MBHC_RSC_LOCK(mbhc);
+	wcd_mbhc_find_plug_and_report(mbhc, plug_type);
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+enable_supply:
+	/*
+	 * Set DETECTION_DONE bit for HEADSET and ANC_HEADPHONE,
+	 * so that btn press/release interrupt can be generated.
+	 * For other plug type, clear the bit.
+	 */
+	if (plug_type == MBHC_PLUG_TYPE_HEADSET ||
+	    plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE)
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1);
+	else
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
+
+	if (mbhc->mbhc_cb->mbhc_micbias_control)
+		wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
+exit:
+	if (mbhc->mbhc_cb->mbhc_micbias_control &&
+	    !mbhc->micbias_enable)
+		mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
+						    MICB_DISABLE);
+
+	/*
+	 * If plug type is corrected from special headset to headphone,
+	 * clear the micbias enable flag, set micbias back to 1.8V and
+	 * disable micbias.
+	 */
+	if (plug_type == MBHC_PLUG_TYPE_HEADPHONE &&
+	    mbhc->micbias_enable) {
+		if (mbhc->mbhc_cb->mbhc_micbias_control)
+			mbhc->mbhc_cb->mbhc_micbias_control(
+					codec, MIC_BIAS_2,
+					MICB_DISABLE);
+		if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
+			mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+					codec,
+					MIC_BIAS_2, false);
+		if (mbhc->mbhc_cb->set_micbias_value) {
+			mbhc->mbhc_cb->set_micbias_value(codec);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
+		}
+		mbhc->micbias_enable = false;
+	}
+
+	if (mbhc->mbhc_cfg->detect_extn_cable &&
+	    ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) ||
+	     (plug_type == MBHC_PLUG_TYPE_HEADSET)) &&
+	    !mbhc->hs_detect_work_stop) {
+		WCD_MBHC_RSC_LOCK(mbhc);
+		wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+	}
+
+	/*
+	 * Enable ADC COMPLETE interrupt for HEADPHONE.
+	 * Btn release may happen after the correct work, ADC COMPLETE
+	 * interrupt needs to be captured to correct plug type.
+	 */
+	if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
+		WCD_MBHC_RSC_LOCK(mbhc);
+		wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
+				     true);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+	}
+
+	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
+		mbhc->mbhc_cb->hph_pull_down_ctrl(codec, true);
+
+	mbhc->mbhc_cb->lock_sleep(mbhc, false);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+	unsigned long timeout;
+	int adc_threshold, output_mv, retry = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD_MBHC_RSC_LOCK(mbhc);
+
+	timeout = jiffies +
+		  msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
+	adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
+			  wcd_mbhc_get_micbias(mbhc)) /
+			  WCD_MBHC_ADC_MICBIAS_MV);
+	do {
+		retry++;
+		/*
+		 * read output_mv every 10ms to look for
+		 * any change in IN2_P
+		 */
+		usleep_range(10000, 10100);
+		output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
+
+		pr_debug("%s: Check for fake removal: output_mv %d\n",
+			 __func__, output_mv);
+		if ((output_mv <= adc_threshold) &&
+		    retry > FAKE_REM_RETRY_ATTEMPTS) {
+			pr_debug("%s: headset is NOT actually removed\n",
+				 __func__);
+			goto exit;
+		}
+	} while (!time_after(jiffies, timeout));
+
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low ", __func__);
+		goto exit;
+	}
+
+	/*
+	 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE,
+	 * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one
+	 * when HEADPHONE is removed.
+	 */
+	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
+		mbhc->extn_cable_hph_rem = true;
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
+	wcd_mbhc_elec_hs_report_unplug(mbhc);
+exit:
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+
+	pr_debug("%s: enter\n", __func__);
+
+	/*
+	 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE,
+	 * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one
+	 * when HEADPHONE is removed.
+	 */
+	if (mbhc->extn_cable_hph_rem == true) {
+		mbhc->extn_cable_hph_rem = false;
+		pr_debug("%s: leave\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	WCD_MBHC_RSC_LOCK(mbhc);
+	/*
+	 * If current plug is headphone then there is no chance to
+	 * get ADC complete interrupt, so connected cable should be
+	 * headset not headphone.
+	 */
+	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
+		wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1);
+		wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+		return IRQ_HANDLED;
+	}
+
+	if (!mbhc->mbhc_cfg->detect_extn_cable) {
+		pr_debug("%s: Returning as Extension cable feature not enabled\n",
+			__func__);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+		return IRQ_HANDLED;
+	}
+
+	pr_debug("%s: Disable electrical headset insertion interrupt\n",
+		 __func__);
+	wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0);
+	mbhc->is_extn_cable = true;
+	mbhc->btn_press_intr = false;
+	wcd_mbhc_adc_detect_plug_type(mbhc);
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+	return IRQ_HANDLED;
+}
+
+static struct wcd_mbhc_fn mbhc_fn = {
+	.wcd_mbhc_hs_ins_irq = wcd_mbhc_adc_hs_ins_irq,
+	.wcd_mbhc_hs_rem_irq = wcd_mbhc_adc_hs_rem_irq,
+	.wcd_mbhc_detect_plug_type = wcd_mbhc_adc_detect_plug_type,
+	.wcd_mbhc_detect_anc_plug_type = wcd_mbhc_adc_detect_anc_plug_type,
+	.wcd_cancel_hs_detect_plug = wcd_cancel_hs_detect_plug,
+};
+
+/* Function: wcd_mbhc_adc_init
+ * @mbhc: MBHC function pointer
+ * Description: Initialize MBHC ADC related function pointers to MBHC structure
+ */
+void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc)
+{
+	if (!mbhc) {
+		pr_err("%s: mbhc is NULL\n", __func__);
+		return;
+	}
+	mbhc->mbhc_fn = &mbhc_fn;
+	INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
+}
+EXPORT_SYMBOL(wcd_mbhc_adc_init);
diff --git a/asoc/codecs/wcd-mbhc-adc.h b/asoc/codecs/wcd-mbhc-adc.h
new file mode 100644
index 0000000..3116108
--- /dev/null
+++ b/asoc/codecs/wcd-mbhc-adc.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD_MBHC_ADC_H__
+#define __WCD_MBHC_ADC_H__
+
+#include "wcd-mbhc-v2.h"
+
+enum wcd_mbhc_adc_mux_ctl {
+	MUX_CTL_AUTO = 0,
+	MUX_CTL_IN2P,
+	MUX_CTL_IN3P,
+	MUX_CTL_IN4P,
+	MUX_CTL_HPH_L,
+	MUX_CTL_HPH_R,
+	MUX_CTL_NONE,
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD_MBHC_ADC)
+void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc);
+#else
+static inline void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc)
+{
+
+}
+#endif
+#endif /* __WCD_MBHC_ADC_H__ */
diff --git a/asoc/codecs/wcd-mbhc-legacy.c b/asoc/codecs/wcd-mbhc-legacy.c
new file mode 100644
index 0000000..745e2e8
--- /dev/null
+++ b/asoc/codecs/wcd-mbhc-legacy.c
@@ -0,0 +1,975 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/firmware.h>
+#include <linux/completion.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "wcd-mbhc-legacy.h"
+#include "wcd-mbhc-v2.h"
+
+static int det_extn_cable_en;
+module_param(det_extn_cable_en, int, 0664);
+MODULE_PARM_DESC(det_extn_cable_en, "enable/disable extn cable detect");
+
+static bool wcd_mbhc_detect_anc_plug_type(struct wcd_mbhc *mbhc)
+{
+	bool anc_mic_found = false;
+	u16 val, hs_comp_res, btn_status = 0;
+	unsigned long retry = 0;
+	int valid_plug_cnt = 0, invalid_plug_cnt = 0;
+	int btn_status_cnt = 0;
+	bool is_check_btn_press = false;
+
+
+	if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 ||
+	    mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4)
+		return false;
+
+	if (!mbhc->mbhc_cb->mbhc_micbias_control)
+		return false;
+
+	WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, val);
+
+	if (val)
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+
+	mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
+					    mbhc->mbhc_cfg->anc_micbias,
+					    MICB_ENABLE);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x2);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+	/*
+	 * wait for button debounce time 20ms. If 4-pole plug is inserted
+	 * into 5-pole jack, then there will be a button press interrupt
+	 * during anc plug detection. In that case though Hs_comp_res is 0,
+	 * it should not be declared as ANC plug type
+	 */
+	usleep_range(20000, 20100);
+
+	/*
+	 * After enabling FSM, to handle slow insertion scenarios,
+	 * check hs_comp_result for few times to see if the IN3 voltage
+	 * is below the Vref
+	 */
+	do {
+		if (wcd_swch_level_remove(mbhc)) {
+			pr_debug("%s: Switch level is low\n", __func__);
+			goto exit;
+		}
+		pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1);
+		WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
+
+		if (!hs_comp_res) {
+			valid_plug_cnt++;
+			is_check_btn_press = true;
+		} else
+			invalid_plug_cnt++;
+		/* Wait 1ms before taking another reading */
+		usleep_range(1000, 1100);
+
+		WCD_MBHC_REG_READ(WCD_MBHC_FSM_STATUS, btn_status);
+		if (btn_status)
+			btn_status_cnt++;
+
+		retry++;
+	} while (retry < ANC_DETECT_RETRY_CNT);
+
+	pr_debug("%s: valid: %d, invalid: %d, btn_status_cnt: %d\n",
+		 __func__, valid_plug_cnt, invalid_plug_cnt, btn_status_cnt);
+
+	/* decision logic */
+	if ((valid_plug_cnt > invalid_plug_cnt) && is_check_btn_press &&
+	    (btn_status_cnt == 0))
+		anc_mic_found = true;
+exit:
+	if (!val)
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0);
+
+	mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
+					    mbhc->mbhc_cfg->anc_micbias,
+					    MICB_DISABLE);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x0);
+	pr_debug("%s: anc mic %sfound\n", __func__,
+		 anc_mic_found ? "" : "not ");
+	return anc_mic_found;
+}
+
+/* To determine if cross connection occurred */
+static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
+{
+	u16 swap_res = 0;
+	enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE;
+	s16 reg1 = 0;
+	bool hphl_sch_res = 0, hphr_sch_res = 0;
+
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low\n", __func__);
+		return -EINVAL;
+	}
+
+	/* If PA is enabled, dont check for cross-connection */
+	if (mbhc->mbhc_cb->hph_pa_on_status)
+		if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec))
+			return false;
+
+	WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
+	/*
+	 * Check if there is any cross connection,
+	 * Micbias and schmitt trigger (HPHL-HPHR)
+	 * needs to be enabled. For some codecs like wcd9335,
+	 * pull-up will already be enabled when this function
+	 * is called for cross-connection identification. No
+	 * need to enable micbias in that case.
+	 */
+	wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 2);
+
+	WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, swap_res);
+	pr_debug("%s: swap_res%x\n", __func__, swap_res);
+
+	/*
+	 * Read reg hphl and hphr schmitt result with cross connection
+	 * bit. These bits will both be "0" in case of cross connection
+	 * otherwise, they stay at 1
+	 */
+	WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch_res);
+	WCD_MBHC_REG_READ(WCD_MBHC_HPHR_SCHMT_RESULT, hphr_sch_res);
+	if (!(hphl_sch_res || hphr_sch_res)) {
+		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+		pr_debug("%s: Cross connection identified\n", __func__);
+	} else {
+		pr_debug("%s: No Cross connection found\n", __func__);
+	}
+
+	/* Disable schmitt trigger and restore micbias */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
+	pr_debug("%s: leave, plug type: %d\n", __func__,  plug_type);
+
+	return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
+}
+
+static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	int delay = 0, rc;
+	bool ret = false;
+	u16 hs_comp_res;
+	bool is_spl_hs = false;
+
+	/*
+	 * Increase micbias to 2.7V to detect headsets with
+	 * threshold on microphone
+	 */
+	if (mbhc->mbhc_cb->mbhc_micbias_control &&
+	    !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
+		pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n",
+			 __func__);
+		return false;
+	} else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
+		rc = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec,
+							MIC_BIAS_2, true);
+		if (rc) {
+			pr_err("%s: Micbias control for thr mic failed, rc: %d\n",
+				__func__, rc);
+			return false;
+		}
+	}
+
+	wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+
+	pr_debug("%s: special headset, start register writes\n", __func__);
+
+	WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
+	while (!is_spl_hs)  {
+		if (mbhc->hs_detect_work_stop) {
+			pr_debug("%s: stop requested: %d\n", __func__,
+					mbhc->hs_detect_work_stop);
+			break;
+		}
+		delay = delay + 50;
+		if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) {
+			mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+					MBHC_COMMON_MICB_PRECHARGE,
+					true);
+			mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+					MBHC_COMMON_MICB_SET_VAL,
+					true);
+		}
+		/* Wait for 50msec for MICBIAS to settle down */
+		msleep(50);
+		if (mbhc->mbhc_cb->set_auto_zeroing)
+			mbhc->mbhc_cb->set_auto_zeroing(codec, true);
+		/* Wait for 50msec for FSM to update result values */
+		msleep(50);
+		WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
+		if (!(hs_comp_res)) {
+			pr_debug("%s: Special headset detected in %d msecs\n",
+					__func__, (delay * 2));
+			is_spl_hs = true;
+		}
+		if (delay == SPECIAL_HS_DETECT_TIME_MS) {
+			pr_debug("%s: Spl headset didn't get detect in 4 sec\n",
+					__func__);
+			break;
+		}
+	}
+	if (is_spl_hs) {
+		pr_debug("%s: Headset with threshold found\n",  __func__);
+		mbhc->micbias_enable = true;
+		ret = true;
+	}
+	if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
+		mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+				MBHC_COMMON_MICB_PRECHARGE,
+				false);
+	if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable)
+		mbhc->mbhc_cb->set_micbias_value(codec);
+	if (mbhc->mbhc_cb->set_auto_zeroing)
+		mbhc->mbhc_cb->set_auto_zeroing(codec, false);
+
+	if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
+	    !mbhc->micbias_enable)
+		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec, MIC_BIAS_2,
+						      false);
+
+	pr_debug("%s: leave, micb_enable: %d\n", __func__,
+		  mbhc->micbias_enable);
+	return ret;
+}
+
+static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc,
+				       enum wcd_mbhc_plug_type plug_type)
+{
+	bool micbias2;
+
+	micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+							MIC_BIAS_2);
+	switch (plug_type) {
+	case MBHC_PLUG_TYPE_HEADPHONE:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
+		break;
+	case MBHC_PLUG_TYPE_HEADSET:
+	case MBHC_PLUG_TYPE_ANC_HEADPHONE:
+		if (!mbhc->is_hs_recording && !micbias2)
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
+		break;
+	default:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
+		break;
+
+	};
+}
+
+static void wcd_enable_mbhc_supply(struct wcd_mbhc *mbhc,
+			enum wcd_mbhc_plug_type plug_type)
+{
+
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	/*
+	 * Do not disable micbias if recording is going on or
+	 * headset is inserted on the other side of the extn
+	 * cable. If headset has been detected current source
+	 * needs to be kept enabled for button detection to work.
+	 * If the accessory type is invalid or unsupported, we
+	 * dont need to enable either of them.
+	 */
+	if (det_extn_cable_en && mbhc->is_extn_cable &&
+		mbhc->mbhc_cb && mbhc->mbhc_cb->extn_use_mb &&
+		mbhc->mbhc_cb->extn_use_mb(codec)) {
+		if (plug_type == MBHC_PLUG_TYPE_HEADPHONE ||
+		    plug_type == MBHC_PLUG_TYPE_HEADSET)
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+	} else {
+		if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
+			if (mbhc->is_hs_recording || mbhc->micbias_enable) {
+				wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+			} else if ((test_bit(WCD_MBHC_EVENT_PA_HPHL,
+					     &mbhc->event_state)) ||
+				   (test_bit(WCD_MBHC_EVENT_PA_HPHR,
+					     &mbhc->event_state))) {
+				wcd_enable_curr_micbias(mbhc,
+						WCD_MBHC_EN_PULLUP);
+			} else {
+				wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
+			}
+		} else if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
+		} else {
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE);
+		}
+	}
+}
+
+static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc,
+					   int *spl_hs_cnt)
+{
+	u16 hs_comp_res_1_8v = 0, hs_comp_res_2_7v = 0;
+	bool spl_hs = false;
+
+	if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
+		goto done;
+
+	if (!spl_hs_cnt) {
+		pr_err("%s: spl_hs_cnt is NULL\n", __func__);
+		goto done;
+	}
+	/* Read back hs_comp_res @ 1.8v Micbias */
+	WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_1_8v);
+	if (!hs_comp_res_1_8v) {
+		spl_hs = false;
+		goto done;
+	}
+
+	/* Bump up MB2 to 2.7v */
+	mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
+				mbhc->mbhc_cfg->mbhc_micbias, true);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+	usleep_range(10000, 10100);
+
+	/* Read back HS_COMP_RESULT */
+	WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_2_7v);
+	if (!hs_comp_res_2_7v && hs_comp_res_1_8v)
+		spl_hs = true;
+
+	if (spl_hs)
+		*spl_hs_cnt += 1;
+
+	/* MB2 back to 1.8v */
+	if (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT) {
+		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
+				mbhc->mbhc_cfg->mbhc_micbias, false);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+		usleep_range(10000, 10100);
+	}
+
+	if (spl_hs)
+		pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);
+
+done:
+	return spl_hs;
+}
+
+/* should be called under interrupt context that hold suspend */
+static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
+					    struct work_struct *work)
+{
+	pr_debug("%s: scheduling correct_swch_plug\n", __func__);
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+	mbhc->hs_detect_work_stop = false;
+	mbhc->mbhc_cb->lock_sleep(mbhc, true);
+	schedule_work(work);
+}
+
+/* called under codec_resource_lock acquisition */
+static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
+					 struct work_struct *work)
+{
+	pr_debug("%s: Canceling correct_plug_swch\n", __func__);
+	mbhc->hs_detect_work_stop = true;
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	if (cancel_work_sync(work)) {
+		pr_debug("%s: correct_plug_swch is canceled\n",
+			 __func__);
+		mbhc->mbhc_cb->lock_sleep(mbhc, false);
+	}
+	WCD_MBHC_RSC_LOCK(mbhc);
+}
+
+/* called under codec_resource_lock acquisition */
+static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	bool micbias1 = false;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
+		mbhc->mbhc_cb->hph_pull_down_ctrl(codec, false);
+
+	if (mbhc->mbhc_cb->micbias_enable_status)
+		micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+								MIC_BIAS_1);
+
+	if (mbhc->mbhc_cb->set_cap_mode)
+		mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true);
+
+	if (mbhc->mbhc_cb->mbhc_micbias_control)
+		mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
+						    MICB_ENABLE);
+	else
+		wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+
+	/* Re-initialize button press completion object */
+	reinit_completion(&mbhc->btn_press_compl);
+	wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static void wcd_correct_swch_plug(struct work_struct *work)
+{
+	struct wcd_mbhc *mbhc;
+	struct snd_soc_codec *codec;
+	enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
+	unsigned long timeout;
+	u16 hs_comp_res = 0, hphl_sch = 0, mic_sch = 0, btn_result = 0;
+	bool wrk_complete = false;
+	int pt_gnd_mic_swap_cnt = 0;
+	int no_gnd_mic_swap_cnt = 0;
+	bool is_pa_on = false, spl_hs = false, spl_hs_reported = false;
+	bool micbias2 = false;
+	bool micbias1 = false;
+	int ret = 0;
+	int rc, spl_hs_count = 0;
+	int cross_conn;
+	int try = 0;
+
+	pr_debug("%s: enter\n", __func__);
+
+	mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
+	codec = mbhc->codec;
+
+	/*
+	 * Enable micbias/pullup for detection in correct work.
+	 * This work will get scheduled from detect_plug_type which
+	 * will already request for pullup/micbias. If the pullup/micbias
+	 * is handled with ref-counts by individual codec drivers, there is
+	 * no need to enabale micbias/pullup here
+	 */
+
+	wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+
+	/* Enable HW FSM */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+	/*
+	 * Check for any button press interrupts before starting 3-sec
+	 * loop.
+	 */
+	rc = wait_for_completion_timeout(&mbhc->btn_press_compl,
+			msecs_to_jiffies(WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS));
+
+	WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result);
+	WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
+
+	if (!rc) {
+		pr_debug("%s No btn press interrupt\n", __func__);
+		if (!btn_result && !hs_comp_res)
+			plug_type = MBHC_PLUG_TYPE_HEADSET;
+		else if (!btn_result && hs_comp_res)
+			plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
+		else
+			plug_type = MBHC_PLUG_TYPE_INVALID;
+	} else {
+		if (!btn_result && !hs_comp_res)
+			plug_type = MBHC_PLUG_TYPE_HEADPHONE;
+		else
+			plug_type = MBHC_PLUG_TYPE_INVALID;
+	}
+
+	do {
+		cross_conn = wcd_check_cross_conn(mbhc);
+		try++;
+	} while (try < GND_MIC_SWAP_THRESHOLD);
+
+	/*
+	 * Check for cross connection 4 times.
+	 * Consider the result of the fourth iteration.
+	 */
+	if (cross_conn > 0) {
+		pr_debug("%s: cross con found, start polling\n",
+			 __func__);
+		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+		pr_debug("%s: Plug found, plug type is %d\n",
+			 __func__, plug_type);
+		goto correct_plug_type;
+	}
+
+	if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
+	     plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
+	    (!wcd_swch_level_remove(mbhc))) {
+		WCD_MBHC_RSC_LOCK(mbhc);
+		if (mbhc->current_plug ==  MBHC_PLUG_TYPE_HIGH_HPH)
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
+						 0);
+		wcd_mbhc_find_plug_and_report(mbhc, plug_type);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+	}
+
+correct_plug_type:
+
+	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
+	while (!time_after(jiffies, timeout)) {
+		if (mbhc->hs_detect_work_stop) {
+			pr_debug("%s: stop requested: %d\n", __func__,
+					mbhc->hs_detect_work_stop);
+			wcd_enable_curr_micbias(mbhc,
+						WCD_MBHC_EN_NONE);
+			if (mbhc->micbias_enable) {
+				mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+					mbhc->codec, MIC_BIAS_2, false);
+				if (mbhc->mbhc_cb->set_micbias_value)
+					mbhc->mbhc_cb->set_micbias_value(
+							mbhc->codec);
+				mbhc->micbias_enable = false;
+			}
+			goto exit;
+		}
+		if (mbhc->btn_press_intr) {
+			wcd_cancel_btn_work(mbhc);
+			mbhc->btn_press_intr = false;
+		}
+		/* Toggle FSM */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+
+		/* allow sometime and re-check stop requested again */
+		msleep(20);
+		if (mbhc->hs_detect_work_stop) {
+			pr_debug("%s: stop requested: %d\n", __func__,
+					mbhc->hs_detect_work_stop);
+			wcd_enable_curr_micbias(mbhc,
+						WCD_MBHC_EN_NONE);
+			if (mbhc->micbias_enable) {
+				mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+					mbhc->codec, MIC_BIAS_2, false);
+				if (mbhc->mbhc_cb->set_micbias_value)
+					mbhc->mbhc_cb->set_micbias_value(
+							mbhc->codec);
+				mbhc->micbias_enable = false;
+			}
+			goto exit;
+		}
+		WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
+
+		pr_debug("%s: hs_comp_res: %x\n", __func__, hs_comp_res);
+		if (mbhc->mbhc_cb->hph_pa_on_status)
+			is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(codec);
+
+		/*
+		 * instead of hogging system by contineous polling, wait for
+		 * sometime and re-check stop request again.
+		 */
+		msleep(180);
+		if (hs_comp_res && (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) {
+			spl_hs = wcd_mbhc_check_for_spl_headset(mbhc,
+								&spl_hs_count);
+
+			if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
+				hs_comp_res = 0;
+				spl_hs = true;
+				mbhc->micbias_enable = true;
+			}
+		}
+
+		if ((!hs_comp_res) && (!is_pa_on)) {
+			/* Check for cross connection*/
+			ret = wcd_check_cross_conn(mbhc);
+			if (ret < 0) {
+				continue;
+			} else if (ret > 0) {
+				pt_gnd_mic_swap_cnt++;
+				no_gnd_mic_swap_cnt = 0;
+				if (pt_gnd_mic_swap_cnt <
+						GND_MIC_SWAP_THRESHOLD) {
+					continue;
+				} else if (pt_gnd_mic_swap_cnt >
+						GND_MIC_SWAP_THRESHOLD) {
+					/*
+					 * This is due to GND/MIC switch didn't
+					 * work,  Report unsupported plug.
+					 */
+					pr_debug("%s: switch didn't work\n",
+						  __func__);
+					plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+					goto report;
+				} else {
+					plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+				}
+			} else {
+				no_gnd_mic_swap_cnt++;
+				pt_gnd_mic_swap_cnt = 0;
+				plug_type = MBHC_PLUG_TYPE_HEADSET;
+				if ((no_gnd_mic_swap_cnt <
+				    GND_MIC_SWAP_THRESHOLD) &&
+				    (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) {
+					continue;
+				} else {
+					no_gnd_mic_swap_cnt = 0;
+				}
+			}
+			if ((pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) &&
+				(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
+				/*
+				 * if switch is toggled, check again,
+				 * otherwise report unsupported plug
+				 */
+				if (mbhc->mbhc_cfg->swap_gnd_mic &&
+					mbhc->mbhc_cfg->swap_gnd_mic(codec,
+					true)) {
+					pr_debug("%s: US_EU gpio present,flip switch\n"
+						, __func__);
+					continue;
+				}
+			}
+		}
+
+		WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
+		WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
+		if (hs_comp_res && !(hphl_sch || mic_sch)) {
+			pr_debug("%s: cable is extension cable\n", __func__);
+			plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
+			wrk_complete = true;
+		} else {
+			pr_debug("%s: cable might be headset: %d\n", __func__,
+					plug_type);
+			if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
+				plug_type = MBHC_PLUG_TYPE_HEADSET;
+				if (!spl_hs_reported &&
+				    spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
+					spl_hs_reported = true;
+					WCD_MBHC_RSC_LOCK(mbhc);
+					wcd_mbhc_find_plug_and_report(mbhc,
+								    plug_type);
+					WCD_MBHC_RSC_UNLOCK(mbhc);
+					continue;
+				} else if (spl_hs_reported)
+					continue;
+				/*
+				 * Report headset only if not already reported
+				 * and if there is not button press without
+				 * release
+				 */
+				if (((mbhc->current_plug !=
+				      MBHC_PLUG_TYPE_HEADSET) &&
+				     (mbhc->current_plug !=
+				      MBHC_PLUG_TYPE_ANC_HEADPHONE)) &&
+				    !wcd_swch_level_remove(mbhc) &&
+				    !mbhc->btn_press_intr) {
+					pr_debug("%s: cable is %sheadset\n",
+						__func__,
+						((spl_hs_count ==
+							WCD_MBHC_SPL_HS_CNT) ?
+							"special ":""));
+					goto report;
+				}
+			}
+			wrk_complete = false;
+		}
+	}
+	if (!wrk_complete && mbhc->btn_press_intr) {
+		pr_debug("%s: Can be slow insertion of headphone\n", __func__);
+		wcd_cancel_btn_work(mbhc);
+		plug_type = MBHC_PLUG_TYPE_HEADPHONE;
+	}
+	/*
+	 * If plug_tye is headset, we might have already reported either in
+	 * detect_plug-type or in above while loop, no need to report again
+	 */
+	if (!wrk_complete && ((plug_type == MBHC_PLUG_TYPE_HEADSET) ||
+	    (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE))) {
+		pr_debug("%s: plug_type:0x%x already reported\n",
+			 __func__, mbhc->current_plug);
+		goto enable_supply;
+	}
+
+	if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH &&
+		(!det_extn_cable_en)) {
+		if (wcd_is_special_headset(mbhc)) {
+			pr_debug("%s: Special headset found %d\n",
+					__func__, plug_type);
+			plug_type = MBHC_PLUG_TYPE_HEADSET;
+			goto report;
+		}
+	}
+
+report:
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low\n", __func__);
+		goto exit;
+	}
+	if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP && mbhc->btn_press_intr) {
+		pr_debug("%s: insertion of headphone with swap\n", __func__);
+		wcd_cancel_btn_work(mbhc);
+		plug_type = MBHC_PLUG_TYPE_HEADPHONE;
+	}
+	pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
+			__func__, plug_type, wrk_complete,
+			mbhc->btn_press_intr);
+	WCD_MBHC_RSC_LOCK(mbhc);
+	wcd_mbhc_find_plug_and_report(mbhc, plug_type);
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+enable_supply:
+	if (mbhc->mbhc_cb->mbhc_micbias_control)
+		wcd_mbhc_update_fsm_source(mbhc, plug_type);
+	else
+		wcd_enable_mbhc_supply(mbhc, plug_type);
+exit:
+	if (mbhc->mbhc_cb->mbhc_micbias_control &&
+	    !mbhc->micbias_enable)
+		mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
+						    MICB_DISABLE);
+
+	/*
+	 * If plug type is corrected from special headset to headphone,
+	 * clear the micbias enable flag, set micbias back to 1.8V and
+	 * disable micbias.
+	 */
+	if (plug_type == MBHC_PLUG_TYPE_HEADPHONE &&
+	    mbhc->micbias_enable) {
+		if (mbhc->mbhc_cb->mbhc_micbias_control)
+			mbhc->mbhc_cb->mbhc_micbias_control(
+					codec, MIC_BIAS_2,
+					MICB_DISABLE);
+		if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
+			mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+					codec,
+					MIC_BIAS_2, false);
+		if (mbhc->mbhc_cb->set_micbias_value) {
+			mbhc->mbhc_cb->set_micbias_value(codec);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
+		}
+		mbhc->micbias_enable = false;
+	}
+
+	if (mbhc->mbhc_cb->micbias_enable_status) {
+		micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+								MIC_BIAS_1);
+		micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+								MIC_BIAS_2);
+	}
+
+	if (mbhc->mbhc_cfg->detect_extn_cable &&
+	    ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) ||
+	     (plug_type == MBHC_PLUG_TYPE_HEADSET)) &&
+	    !mbhc->hs_detect_work_stop) {
+		WCD_MBHC_RSC_LOCK(mbhc);
+		wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+	}
+	if (mbhc->mbhc_cb->set_cap_mode)
+		mbhc->mbhc_cb->set_cap_mode(codec, micbias1, micbias2);
+
+	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
+		mbhc->mbhc_cb->hph_pull_down_ctrl(codec, true);
+
+	mbhc->mbhc_cb->lock_sleep(mbhc, false);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+	u8 hs_comp_result = 0, hphl_sch = 0, mic_sch = 0;
+	static u16 hphl_trigerred;
+	static u16 mic_trigerred;
+	unsigned long timeout;
+	bool removed = true;
+	int retry = 0;
+
+	pr_debug("%s: enter\n", __func__);
+
+	WCD_MBHC_RSC_LOCK(mbhc);
+
+	timeout = jiffies +
+		  msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
+	do {
+		retry++;
+		/*
+		 * read the result register every 10ms to look for
+		 * any change in HS_COMP_RESULT bit
+		 */
+		usleep_range(10000, 10100);
+		WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
+		pr_debug("%s: Check result reg for fake removal: hs_comp_res %x\n",
+			 __func__, hs_comp_result);
+		if ((!hs_comp_result) &&
+		    retry > FAKE_REM_RETRY_ATTEMPTS) {
+			removed = false;
+			break;
+		}
+	} while (!time_after(jiffies, timeout));
+
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low ", __func__);
+		goto exit;
+	}
+	pr_debug("%s: headset %s actually removed\n", __func__,
+		removed ? "" : "not ");
+
+	WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
+	WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
+	WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
+
+	if (removed) {
+		if (!(hphl_sch && mic_sch && hs_comp_result)) {
+			/*
+			 * extension cable is still plugged in
+			 * report it as LINEOUT device
+			 */
+			goto report_unplug;
+		} else {
+			if (!mic_sch) {
+				mic_trigerred++;
+				pr_debug("%s: Removal MIC trigerred %d\n",
+					 __func__, mic_trigerred);
+			}
+			if (!hphl_sch) {
+				hphl_trigerred++;
+				pr_debug("%s: Removal HPHL trigerred %d\n",
+					 __func__, hphl_trigerred);
+			}
+			if (mic_trigerred && hphl_trigerred) {
+				/*
+				 * extension cable is still plugged in
+				 * report it as LINEOUT device
+				 */
+				goto report_unplug;
+			}
+		}
+	}
+exit:
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+	return IRQ_HANDLED;
+
+report_unplug:
+	wcd_mbhc_elec_hs_report_unplug(mbhc);
+	hphl_trigerred = 0;
+	mic_trigerred = 0;
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd_mbhc_hs_ins_irq(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+	bool detection_type = 0, hphl_sch = 0, mic_sch = 0;
+	u16 elect_result = 0;
+	static u16 hphl_trigerred;
+	static u16 mic_trigerred;
+
+	pr_debug("%s: enter\n", __func__);
+	if (!mbhc->mbhc_cfg->detect_extn_cable) {
+		pr_debug("%s: Returning as Extension cable feature not enabled\n",
+			__func__);
+		return IRQ_HANDLED;
+	}
+	WCD_MBHC_RSC_LOCK(mbhc);
+
+	WCD_MBHC_REG_READ(WCD_MBHC_ELECT_DETECTION_TYPE, detection_type);
+	WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, elect_result);
+
+	pr_debug("%s: detection_type %d, elect_result %x\n", __func__,
+				detection_type, elect_result);
+	if (detection_type) {
+		/* check if both Left and MIC Schmitt triggers are triggered */
+		WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
+		WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
+		if (hphl_sch && mic_sch) {
+			/* Go for plug type determination */
+			pr_debug("%s: Go for plug type determination\n",
+				  __func__);
+			goto determine_plug;
+
+		} else {
+			if (mic_sch) {
+				mic_trigerred++;
+				pr_debug("%s: Insertion MIC trigerred %d\n",
+					 __func__, mic_trigerred);
+				WCD_MBHC_REG_UPDATE_BITS(
+						WCD_MBHC_ELECT_SCHMT_ISRC,
+						0);
+				msleep(20);
+				WCD_MBHC_REG_UPDATE_BITS(
+						WCD_MBHC_ELECT_SCHMT_ISRC,
+						1);
+			}
+			if (hphl_sch) {
+				hphl_trigerred++;
+				pr_debug("%s: Insertion HPHL trigerred %d\n",
+					 __func__, hphl_trigerred);
+			}
+			if (mic_trigerred && hphl_trigerred) {
+				/* Go for plug type determination */
+				pr_debug("%s: Go for plug type determination\n",
+					 __func__);
+				goto determine_plug;
+			}
+		}
+	}
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+	return IRQ_HANDLED;
+
+determine_plug:
+	/*
+	 * Disable HPHL trigger and MIC Schmitt triggers.
+	 * Setup for insertion detection.
+	 */
+	pr_debug("%s: Disable insertion interrupt\n", __func__);
+	wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
+			     false);
+
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
+	hphl_trigerred = 0;
+	mic_trigerred = 0;
+	mbhc->is_extn_cable = true;
+	mbhc->btn_press_intr = false;
+	wcd_mbhc_detect_plug_type(mbhc);
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+	return IRQ_HANDLED;
+}
+
+static struct wcd_mbhc_fn mbhc_fn = {
+	.wcd_mbhc_hs_ins_irq = wcd_mbhc_hs_ins_irq,
+	.wcd_mbhc_hs_rem_irq = wcd_mbhc_hs_rem_irq,
+	.wcd_mbhc_detect_plug_type = wcd_mbhc_detect_plug_type,
+	.wcd_mbhc_detect_anc_plug_type = wcd_mbhc_detect_anc_plug_type,
+	.wcd_cancel_hs_detect_plug = wcd_cancel_hs_detect_plug,
+};
+
+/* Function: wcd_mbhc_legacy_init
+ * @mbhc: MBHC function pointer
+ * Description: Initialize MBHC legacy based function pointers to MBHC structure
+ */
+void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc)
+{
+	if (!mbhc) {
+		pr_err("%s: mbhc is NULL\n", __func__);
+		return;
+	}
+	mbhc->mbhc_fn = &mbhc_fn;
+	INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
+}
+EXPORT_SYMBOL(wcd_mbhc_legacy_init);
diff --git a/asoc/codecs/wcd-mbhc-legacy.h b/asoc/codecs/wcd-mbhc-legacy.h
new file mode 100644
index 0000000..594393d
--- /dev/null
+++ b/asoc/codecs/wcd-mbhc-legacy.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD_MBHC_LEGACY_H__
+#define __WCD_MBHC_LEGACY_H__
+
+#include "wcdcal-hwdep.h"
+#include "wcd-mbhc-v2.h"
+
+#ifdef CONFIG_SND_SOC_WCD_MBHC_LEGACY
+void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc);
+#else
+static inline void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc)
+{
+}
+#endif
+
+#endif /* __WCD_MBHC_LEGACY_H__ */
diff --git a/asoc/codecs/wcd-mbhc-v2-api.h b/asoc/codecs/wcd-mbhc-v2-api.h
new file mode 100644
index 0000000..7b6e945
--- /dev/null
+++ b/asoc/codecs/wcd-mbhc-v2-api.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD_MBHC_V2_API_H__
+#define __WCD_MBHC_V2_API_H__
+
+#include "wcd-mbhc-v2.h"
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD_MBHC)
+int wcd_mbhc_start(struct wcd_mbhc *mbhc,
+		       struct wcd_mbhc_config *mbhc_cfg);
+void wcd_mbhc_stop(struct wcd_mbhc *mbhc);
+int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
+		      const struct wcd_mbhc_cb *mbhc_cb,
+		      const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
+		      struct wcd_mbhc_register *wcd_mbhc_regs,
+		      bool impedance_det_en);
+int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
+			   uint32_t *zr);
+void wcd_mbhc_deinit(struct wcd_mbhc *mbhc);
+
+#else
+static inline void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
+{
+}
+int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
+		      const struct wcd_mbhc_cb *mbhc_cb,
+		      const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
+		      struct wcd_mbhc_register *wcd_mbhc_regs,
+		      bool impedance_det_en)
+{
+	return 0;
+}
+static inline int wcd_mbhc_start(struct wcd_mbhc *mbhc,
+				 struct wcd_mbhc_config *mbhc_cfg)
+{
+	return 0;
+}
+static inline int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc,
+					 uint32_t *zl,
+					 uint32_t *zr)
+{
+	*zl = 0;
+	*zr = 0;
+	return -EINVAL;
+}
+static inline void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
+{
+}
+#endif
+
+#endif /* __WCD_MBHC_V2_API_H__ */
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
new file mode 100644
index 0000000..6b3dd86
--- /dev/null
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -0,0 +1,2110 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/firmware.h>
+#include <linux/completion.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "msm-cdc-pinctrl.h"
+#include "wcdcal-hwdep.h"
+#include "wcd-mbhc-legacy.h"
+#include "wcd-mbhc-adc.h"
+#include "wcd-mbhc-v2-api.h"
+
+void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc,
+			  struct snd_soc_jack *jack, int status, int mask)
+{
+	snd_soc_jack_report(jack, status, mask);
+}
+EXPORT_SYMBOL(wcd_mbhc_jack_report);
+
+static void __hphocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status,
+				int irq)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	dev_dbg(codec->dev, "%s: clear ocp status %x\n",
+		__func__, jack_status);
+
+	if (mbhc->hph_status & jack_status) {
+		mbhc->hph_status &= ~jack_status;
+		wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
+				     mbhc->hph_status, WCD_MBHC_JACK_MASK);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
+		/*
+		 * reset retry counter as PA is turned off signifying
+		 * start of new OCP detection session
+		 */
+		if (mbhc->intr_ids->hph_left_ocp)
+			mbhc->hphlocp_cnt = 0;
+		else
+			mbhc->hphrocp_cnt = 0;
+		mbhc->mbhc_cb->irq_control(codec, irq, true);
+	}
+}
+
+static void hphrocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status)
+{
+	__hphocp_off_report(mbhc, SND_JACK_OC_HPHR,
+			    mbhc->intr_ids->hph_right_ocp);
+}
+
+static void hphlocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status)
+{
+	__hphocp_off_report(mbhc, SND_JACK_OC_HPHL,
+			    mbhc->intr_ids->hph_left_ocp);
+}
+
+static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
+{
+	struct wcd_mbhc_plug_type_cfg *plug_type_cfg;
+	struct snd_soc_codec *codec = mbhc->codec;
+	u32 reg_val;
+
+	plug_type_cfg = WCD_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+	reg_val = ((plug_type_cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
+
+	dev_dbg(codec->dev, "%s: reg_val  = %x\n", __func__, reg_val);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_VREF, reg_val);
+}
+
+static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
+{
+	struct wcd_mbhc_btn_detect_cfg *btn_det;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct snd_soc_card *card = codec->component.card;
+	s16 *btn_low, *btn_high;
+
+	if (mbhc->mbhc_cfg->calibration == NULL) {
+		dev_err(card->dev, "%s: calibration data is NULL\n", __func__);
+		return;
+	}
+
+	btn_det = WCD_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+	btn_low = btn_det->_v_btn_low;
+	btn_high = ((void *)&btn_det->_v_btn_low) +
+			(sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn);
+
+	mbhc->mbhc_cb->set_btn_thr(codec, btn_low, btn_high, btn_det->num_btn,
+				   micbias);
+}
+
+void wcd_enable_curr_micbias(const struct wcd_mbhc *mbhc,
+				const enum wcd_mbhc_cs_mb_en_flag cs_mb_en)
+{
+
+	/*
+	 * Some codecs handle micbias/pullup enablement in codec
+	 * drivers itself and micbias is not needed for regular
+	 * plug type detection. So if micbias_control callback function
+	 * is defined, just return.
+	 */
+	if (mbhc->mbhc_cb->mbhc_micbias_control)
+		return;
+
+	pr_debug("%s: enter, cs_mb_en: %d\n", __func__, cs_mb_en);
+
+	switch (cs_mb_en) {
+	case WCD_MBHC_EN_CS:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
+		/* Program Button threshold registers as per CS */
+		wcd_program_btn_threshold(mbhc, false);
+		break;
+	case WCD_MBHC_EN_MB:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+
+		/* Disable PULL_UP_EN & enable MICBIAS */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 2);
+		/* Program Button threshold registers as per MICBIAS */
+		wcd_program_btn_threshold(mbhc, true);
+		break;
+	case WCD_MBHC_EN_PULLUP:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 1);
+		/* Program Button threshold registers as per MICBIAS */
+		wcd_program_btn_threshold(mbhc, true);
+		break;
+	case WCD_MBHC_EN_NONE:
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
+		break;
+	default:
+		pr_debug("%s: Invalid parameter", __func__);
+		break;
+	}
+
+	pr_debug("%s: exit\n", __func__);
+}
+EXPORT_SYMBOL(wcd_enable_curr_micbias);
+
+static const char *wcd_mbhc_get_event_string(int event)
+{
+	switch (event) {
+	case WCD_EVENT_PRE_MICBIAS_2_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_OFF);
+	case WCD_EVENT_POST_MICBIAS_2_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_OFF);
+	case WCD_EVENT_PRE_MICBIAS_2_ON:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_ON);
+	case WCD_EVENT_POST_MICBIAS_2_ON:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_ON);
+	case WCD_EVENT_PRE_HPHL_PA_ON:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_ON);
+	case WCD_EVENT_POST_HPHL_PA_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHL_PA_OFF);
+	case WCD_EVENT_PRE_HPHR_PA_ON:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_ON);
+	case WCD_EVENT_POST_HPHR_PA_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHR_PA_OFF);
+	case WCD_EVENT_PRE_HPHR_PA_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_OFF);
+	case WCD_EVENT_PRE_HPHL_PA_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_OFF);
+	case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_ON);
+	case WCD_EVENT_PRE_DAPM_MICBIAS_2_ON:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_ON);
+	case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
+	case WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF);
+	case WCD_EVENT_OCP_OFF:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_OFF);
+	case WCD_EVENT_OCP_ON:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_ON);
+	case WCD_EVENT_INVALID:
+	default:
+		return WCD_MBHC_STRINGIFY(WCD_EVENT_INVALID);
+	}
+}
+
+static int wcd_event_notify(struct notifier_block *self, unsigned long val,
+			    void *data)
+{
+	struct wcd_mbhc *mbhc = (struct wcd_mbhc *)data;
+	enum wcd_notify_event event = (enum wcd_notify_event)val;
+	struct snd_soc_codec *codec = mbhc->codec;
+	bool micbias2 = false;
+	bool micbias1 = false;
+	u8 fsm_en = 0;
+
+	pr_debug("%s: event %s (%d)\n", __func__,
+		 wcd_mbhc_get_event_string(event), event);
+	if (mbhc->mbhc_cb->micbias_enable_status) {
+		micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+								MIC_BIAS_2);
+		micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+								MIC_BIAS_1);
+	}
+	switch (event) {
+	/* MICBIAS usage change */
+	case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
+		mbhc->is_hs_recording = true;
+		pr_debug("%s: is_capture: %d\n", __func__,
+			  mbhc->is_hs_recording);
+		break;
+	case WCD_EVENT_POST_MICBIAS_2_ON:
+		if (!mbhc->micbias_enable)
+			goto out_micb_en;
+		if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) {
+			mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+					MBHC_COMMON_MICB_PRECHARGE,
+					true);
+			mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+					MBHC_COMMON_MICB_SET_VAL,
+					true);
+			/*
+			 * Special headset needs MICBIAS as 2.7V so wait for
+			 * 50 msec for the MICBIAS to reach 2.7 volts.
+			 */
+			msleep(50);
+		}
+		if (mbhc->mbhc_cb->set_auto_zeroing)
+			mbhc->mbhc_cb->set_auto_zeroing(codec, true);
+		if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
+			mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+					MBHC_COMMON_MICB_PRECHARGE,
+					false);
+out_micb_en:
+		/* Disable current source if micbias enabled */
+		if (mbhc->mbhc_cb->mbhc_micbias_control) {
+			WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
+			if (fsm_en)
+				WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL,
+							 0);
+		} else {
+			mbhc->is_hs_recording = true;
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+		}
+		/* configure cap settings properly when micbias is enabled */
+		if (mbhc->mbhc_cb->set_cap_mode)
+			mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true);
+		break;
+	case WCD_EVENT_PRE_MICBIAS_2_OFF:
+		/*
+		 * Before MICBIAS_2 is turned off, if FSM is enabled,
+		 * make sure current source is enabled so as to detect
+		 * button press/release events
+		 */
+		if (mbhc->mbhc_cb->mbhc_micbias_control &&
+		    !mbhc->micbias_enable) {
+			WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
+			if (fsm_en)
+				WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL,
+							 3);
+		}
+		break;
+	/* MICBIAS usage change */
+	case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
+		mbhc->is_hs_recording = false;
+		pr_debug("%s: is_capture: %d\n", __func__,
+			  mbhc->is_hs_recording);
+		break;
+	case WCD_EVENT_POST_MICBIAS_2_OFF:
+		if (!mbhc->mbhc_cb->mbhc_micbias_control)
+			mbhc->is_hs_recording = false;
+		if (mbhc->micbias_enable) {
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+			break;
+		}
+
+		if (mbhc->mbhc_cb->set_auto_zeroing)
+			mbhc->mbhc_cb->set_auto_zeroing(codec, false);
+		if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable)
+			mbhc->mbhc_cb->set_micbias_value(codec);
+		/* Enable PULL UP if PA's are enabled */
+		if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) ||
+				(test_bit(WCD_MBHC_EVENT_PA_HPHR,
+					  &mbhc->event_state)))
+			/* enable pullup and cs, disable mb */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP);
+		else
+			/* enable current source and disable mb, pullup*/
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
+
+		/* configure cap settings properly when micbias is disabled */
+		if (mbhc->mbhc_cb->set_cap_mode)
+			mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
+		break;
+	case WCD_EVENT_PRE_HPHL_PA_OFF:
+		mutex_lock(&mbhc->hphl_pa_lock);
+		break;
+	case WCD_EVENT_POST_HPHL_PA_OFF:
+		clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
+		if (mbhc->hph_status & SND_JACK_OC_HPHL)
+			hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
+		clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
+		/* check if micbias is enabled */
+		if (micbias2)
+			/* Disable cs, pullup & enable micbias */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+		else
+			/* Disable micbias, pullup & enable cs */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
+		mutex_unlock(&mbhc->hphl_pa_lock);
+		clear_bit(WCD_MBHC_ANC0_OFF_ACK, &mbhc->hph_anc_state);
+		break;
+	case WCD_EVENT_PRE_HPHR_PA_OFF:
+		mutex_lock(&mbhc->hphr_pa_lock);
+		break;
+	case WCD_EVENT_POST_HPHR_PA_OFF:
+		clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
+		if (mbhc->hph_status & SND_JACK_OC_HPHR)
+			hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
+		clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
+		/* check if micbias is enabled */
+		if (micbias2)
+			/* Disable cs, pullup & enable micbias */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+		else
+			/* Disable micbias, pullup & enable cs */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
+		mutex_unlock(&mbhc->hphr_pa_lock);
+		clear_bit(WCD_MBHC_ANC1_OFF_ACK, &mbhc->hph_anc_state);
+		break;
+	case WCD_EVENT_PRE_HPHL_PA_ON:
+		set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
+		/* check if micbias is enabled */
+		if (micbias2)
+			/* Disable cs, pullup & enable micbias */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+		else
+			/* Disable micbias, enable pullup & cs */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP);
+		break;
+	case WCD_EVENT_PRE_HPHR_PA_ON:
+		set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
+		/* check if micbias is enabled */
+		if (micbias2)
+			/* Disable cs, pullup & enable micbias */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+		else
+			/* Disable micbias, enable pullup & cs */
+			wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP);
+		break;
+	case WCD_EVENT_OCP_OFF:
+		mbhc->mbhc_cb->irq_control(mbhc->codec,
+					   mbhc->intr_ids->hph_left_ocp,
+					   false);
+		break;
+	case WCD_EVENT_OCP_ON:
+		mbhc->mbhc_cb->irq_control(mbhc->codec,
+					   mbhc->intr_ids->hph_left_ocp,
+					   true);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
+{
+	int r;
+
+	r = cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
+	/*
+	 * if scheduled mbhc.mbhc_btn_dwork is canceled from here,
+	 * we have to unlock from here instead btn_work
+	 */
+	if (r)
+		mbhc->mbhc_cb->lock_sleep(mbhc, false);
+	return r;
+}
+EXPORT_SYMBOL(wcd_cancel_btn_work);
+
+bool wcd_swch_level_remove(struct wcd_mbhc *mbhc)
+{
+	u16 result2 = 0;
+
+	WCD_MBHC_REG_READ(WCD_MBHC_SWCH_LEVEL_REMOVE, result2);
+	return (result2) ? true : false;
+}
+EXPORT_SYMBOL(wcd_swch_level_remove);
+
+static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc)
+{
+	bool pa_turned_on = false;
+	u8 wg_time = 0;
+
+	WCD_MBHC_REG_READ(WCD_MBHC_HPH_CNP_WG_TIME, wg_time);
+	wg_time += 1;
+
+	mutex_lock(&mbhc->hphr_pa_lock);
+	if (test_and_clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK,
+			       &mbhc->hph_pa_dac_state)) {
+		pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 1);
+		pa_turned_on = true;
+	}
+	mutex_unlock(&mbhc->hphr_pa_lock);
+	mutex_lock(&mbhc->hphl_pa_lock);
+	if (test_and_clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK,
+			       &mbhc->hph_pa_dac_state)) {
+		pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 1);
+		pa_turned_on = true;
+	}
+	mutex_unlock(&mbhc->hphl_pa_lock);
+
+	if (pa_turned_on) {
+		pr_debug("%s: PA was turned on by MBHC and not by DAPM\n",
+			 __func__);
+		usleep_range(wg_time * 1000, wg_time * 1000 + 50);
+	}
+
+	if (test_and_clear_bit(WCD_MBHC_ANC0_OFF_ACK,
+				&mbhc->hph_anc_state)) {
+		usleep_range(20000, 20100);
+		pr_debug("%s: HPHL ANC clear flag and enable ANC_EN\n",
+			__func__);
+		if (mbhc->mbhc_cb->update_anc_state)
+			mbhc->mbhc_cb->update_anc_state(mbhc->codec, true, 0);
+	}
+
+	if (test_and_clear_bit(WCD_MBHC_ANC1_OFF_ACK,
+				&mbhc->hph_anc_state)) {
+		usleep_range(20000, 20100);
+		pr_debug("%s: HPHR ANC clear flag and enable ANC_EN\n",
+			__func__);
+		if (mbhc->mbhc_cb->update_anc_state)
+			mbhc->mbhc_cb->update_anc_state(mbhc->codec, true, 1);
+	}
+
+}
+
+static bool wcd_mbhc_is_hph_pa_on(struct wcd_mbhc *mbhc)
+{
+	bool hph_pa_on = false;
+
+	WCD_MBHC_REG_READ(WCD_MBHC_HPH_PA_EN, hph_pa_on);
+
+	return (hph_pa_on) ? true : false;
+}
+
+static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc)
+{
+	u8 wg_time = 0;
+
+	WCD_MBHC_REG_READ(WCD_MBHC_HPH_CNP_WG_TIME, wg_time);
+	wg_time += 1;
+
+	/* If headphone PA is on, check if userspace receives
+	 * removal event to sync-up PA's state
+	 */
+	if (wcd_mbhc_is_hph_pa_on(mbhc)) {
+		pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
+		set_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
+		set_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 0);
+	} else {
+		pr_debug("%s PA is off\n", __func__);
+	}
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 0);
+	usleep_range(wg_time * 1000, wg_time * 1000 + 50);
+
+
+	if (mbhc->mbhc_cb->is_anc_on && mbhc->mbhc_cb->is_anc_on(mbhc)) {
+		usleep_range(20000, 20100);
+		pr_debug("%s ANC is on, setting ANC_OFF_ACK\n", __func__);
+		set_bit(WCD_MBHC_ANC0_OFF_ACK, &mbhc->hph_anc_state);
+		set_bit(WCD_MBHC_ANC1_OFF_ACK, &mbhc->hph_anc_state);
+		if (mbhc->mbhc_cb->update_anc_state) {
+			mbhc->mbhc_cb->update_anc_state(mbhc->codec, false, 0);
+			mbhc->mbhc_cb->update_anc_state(mbhc->codec, false, 1);
+		} else {
+			pr_debug("%s ANC is off\n", __func__);
+		}
+	}
+}
+
+int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
+			uint32_t *zr)
+{
+	*zl = mbhc->zl;
+	*zr = mbhc->zr;
+
+	if (*zl && *zr)
+		return 0;
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(wcd_mbhc_get_impedance);
+
+void wcd_mbhc_hs_elec_irq(struct wcd_mbhc *mbhc, int irq_type,
+				 bool enable)
+{
+	int irq;
+
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+	if (irq_type == WCD_MBHC_ELEC_HS_INS)
+		irq = mbhc->intr_ids->mbhc_hs_ins_intr;
+	else if (irq_type == WCD_MBHC_ELEC_HS_REM)
+		irq = mbhc->intr_ids->mbhc_hs_rem_intr;
+	else {
+		pr_debug("%s: irq_type: %d, enable: %d\n",
+			__func__, irq_type, enable);
+		return;
+	}
+
+	pr_debug("%s: irq: %d, enable: %d, intr_status:%lu\n",
+		 __func__, irq, enable, mbhc->intr_status);
+	if ((test_bit(irq_type, &mbhc->intr_status)) != enable) {
+		mbhc->mbhc_cb->irq_control(mbhc->codec, irq, enable);
+		if (enable)
+			set_bit(irq_type, &mbhc->intr_status);
+		else
+			clear_bit(irq_type, &mbhc->intr_status);
+	}
+}
+EXPORT_SYMBOL(wcd_mbhc_hs_elec_irq);
+
+static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
+				enum snd_jack_types jack_type)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	bool is_pa_on = false;
+	u8 fsm_en = 0;
+
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+	pr_debug("%s: enter insertion %d hph_status %x\n",
+		 __func__, insertion, mbhc->hph_status);
+	if (!insertion) {
+		/* Report removal */
+		mbhc->hph_status &= ~jack_type;
+		/*
+		 * cancel possibly scheduled btn work and
+		 * report release if we reported button press
+		 */
+		if (wcd_cancel_btn_work(mbhc)) {
+			pr_debug("%s: button press is canceled\n", __func__);
+		} else if (mbhc->buttons_pressed) {
+			pr_debug("%s: release of button press%d\n",
+				 __func__, jack_type);
+			wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, 0,
+					    mbhc->buttons_pressed);
+			mbhc->buttons_pressed &=
+				~WCD_MBHC_JACK_BUTTON_MASK;
+		}
+
+		if (mbhc->micbias_enable) {
+			if (mbhc->mbhc_cb->mbhc_micbias_control)
+				mbhc->mbhc_cb->mbhc_micbias_control(
+						codec, MIC_BIAS_2,
+						MICB_DISABLE);
+			if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
+				mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+						codec,
+						MIC_BIAS_2, false);
+			if (mbhc->mbhc_cb->set_micbias_value) {
+				mbhc->mbhc_cb->set_micbias_value(codec);
+				WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
+			}
+			mbhc->micbias_enable = false;
+		}
+
+		mbhc->hph_type = WCD_MBHC_HPH_NONE;
+		mbhc->zl = mbhc->zr = 0;
+		pr_debug("%s: Reporting removal %d(%x)\n", __func__,
+			 jack_type, mbhc->hph_status);
+		wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
+				mbhc->hph_status, WCD_MBHC_JACK_MASK);
+		wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
+		hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
+		hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
+		mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
+	} else {
+		/*
+		 * Report removal of current jack type.
+		 * Headphone to headset shouldn't report headphone
+		 * removal.
+		 */
+		if (mbhc->mbhc_cfg->detect_extn_cable &&
+		    (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH ||
+		    jack_type == SND_JACK_LINEOUT) &&
+		    (mbhc->hph_status && mbhc->hph_status != jack_type)) {
+
+			if (mbhc->micbias_enable &&
+			    mbhc->hph_status == SND_JACK_HEADSET) {
+				if (mbhc->mbhc_cb->mbhc_micbias_control)
+					mbhc->mbhc_cb->mbhc_micbias_control(
+						codec, MIC_BIAS_2,
+						MICB_DISABLE);
+				if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
+					mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+						codec,
+						MIC_BIAS_2, false);
+				if (mbhc->mbhc_cb->set_micbias_value) {
+					mbhc->mbhc_cb->set_micbias_value(
+							codec);
+					WCD_MBHC_REG_UPDATE_BITS(
+							WCD_MBHC_MICB_CTRL, 0);
+				}
+				mbhc->micbias_enable = false;
+			}
+			mbhc->hph_type = WCD_MBHC_HPH_NONE;
+			mbhc->zl = mbhc->zr = 0;
+			pr_debug("%s: Reporting removal (%x)\n",
+				 __func__, mbhc->hph_status);
+			wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
+					    0, WCD_MBHC_JACK_MASK);
+
+			if (mbhc->hph_status == SND_JACK_LINEOUT) {
+
+				pr_debug("%s: Enable micbias\n", __func__);
+				/* Disable current source and enable micbias */
+				wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
+				pr_debug("%s: set up elec removal detection\n",
+					  __func__);
+				usleep_range(200, 210);
+				wcd_mbhc_hs_elec_irq(mbhc,
+						     WCD_MBHC_ELEC_HS_REM,
+						     true);
+			}
+			mbhc->hph_status &= ~(SND_JACK_HEADSET |
+						SND_JACK_LINEOUT |
+						SND_JACK_ANC_HEADPHONE |
+						SND_JACK_UNSUPPORTED);
+		}
+
+		if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
+			jack_type == SND_JACK_HEADPHONE)
+			mbhc->hph_status &= ~SND_JACK_HEADSET;
+
+		/* Report insertion */
+		if (jack_type == SND_JACK_HEADPHONE)
+			mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
+		else if (jack_type == SND_JACK_UNSUPPORTED)
+			mbhc->current_plug = MBHC_PLUG_TYPE_GND_MIC_SWAP;
+		else if (jack_type == SND_JACK_HEADSET) {
+			mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
+			mbhc->jiffies_atreport = jiffies;
+		} else if (jack_type == SND_JACK_LINEOUT) {
+			mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
+		} else if (jack_type == SND_JACK_ANC_HEADPHONE)
+			mbhc->current_plug = MBHC_PLUG_TYPE_ANC_HEADPHONE;
+
+		if (mbhc->mbhc_cb->hph_pa_on_status)
+			is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(codec);
+
+		if (mbhc->impedance_detect &&
+			mbhc->mbhc_cb->compute_impedance &&
+			(mbhc->mbhc_cfg->linein_th != 0) &&
+			(!is_pa_on)) {
+			/* Set MUX_CTL to AUTO for Z-det */
+			WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL,
+						 MUX_CTL_AUTO);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
+			mbhc->mbhc_cb->compute_impedance(mbhc,
+					&mbhc->zl, &mbhc->zr);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN,
+						 fsm_en);
+			if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
+				mbhc->zl < MAX_IMPED) &&
+				(mbhc->zr > mbhc->mbhc_cfg->linein_th &&
+				 mbhc->zr < MAX_IMPED) &&
+				(jack_type == SND_JACK_HEADPHONE)) {
+				jack_type = SND_JACK_LINEOUT;
+				mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
+				if (mbhc->hph_status) {
+					mbhc->hph_status &= ~(SND_JACK_HEADSET |
+							SND_JACK_LINEOUT |
+							SND_JACK_UNSUPPORTED);
+					wcd_mbhc_jack_report(mbhc,
+							&mbhc->headset_jack,
+							mbhc->hph_status,
+							WCD_MBHC_JACK_MASK);
+				}
+				pr_debug("%s: Marking jack type as SND_JACK_LINEOUT\n",
+				__func__);
+			}
+		}
+
+		mbhc->hph_status |= jack_type;
+
+		pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
+			 jack_type, mbhc->hph_status);
+		wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
+				    (mbhc->hph_status | SND_JACK_MECHANICAL),
+				    WCD_MBHC_JACK_MASK);
+		wcd_mbhc_clr_and_turnon_hph_padac(mbhc);
+	}
+	pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
+}
+
+void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
+{
+	/* cancel pending button press */
+	if (wcd_cancel_btn_work(mbhc))
+		pr_debug("%s: button press is canceled\n", __func__);
+	/* cancel correct work function */
+	if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug)
+		mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc,
+						&mbhc->correct_plug_swch);
+	else
+		pr_info("%s: hs_detect_plug work not cancelled\n", __func__);
+
+	pr_debug("%s: Report extension cable\n", __func__);
+	wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
+	/*
+	 * If PA is enabled HPHL schmitt trigger can
+	 * be unreliable, make sure to disable it
+	 */
+	if (test_bit(WCD_MBHC_EVENT_PA_HPHL,
+		&mbhc->event_state))
+		wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
+	/*
+	 * Disable HPHL trigger and MIC Schmitt triggers.
+	 * Setup for insertion detection.
+	 */
+	wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM,
+			     false);
+	wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE);
+	/* Disable HW FSM */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 3);
+
+	/* Set the detection type appropriately */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, 1);
+	wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
+			     true);
+}
+EXPORT_SYMBOL(wcd_mbhc_elec_hs_report_unplug);
+
+void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
+				   enum wcd_mbhc_plug_type plug_type)
+{
+	bool anc_mic_found = false;
+	enum snd_jack_types jack_type;
+
+	pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
+		 __func__, mbhc->current_plug, plug_type);
+
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+	if (mbhc->current_plug == plug_type) {
+		pr_debug("%s: cable already reported, exit\n", __func__);
+		goto exit;
+	}
+
+	if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
+		/*
+		 * Nothing was reported previously
+		 * report a headphone or unsupported
+		 */
+		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
+	} else if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
+		if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
+			wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
+		if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
+			wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
+		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
+	} else if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
+		if (mbhc->mbhc_cfg->enable_anc_mic_detect &&
+		    mbhc->mbhc_fn->wcd_mbhc_detect_anc_plug_type)
+			anc_mic_found =
+			mbhc->mbhc_fn->wcd_mbhc_detect_anc_plug_type(mbhc);
+		jack_type = SND_JACK_HEADSET;
+		if (anc_mic_found)
+			jack_type = SND_JACK_ANC_HEADPHONE;
+
+		/*
+		 * If Headphone was reported previously, this will
+		 * only report the mic line
+		 */
+		wcd_mbhc_report_plug(mbhc, 1, jack_type);
+	} else if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
+		if (mbhc->mbhc_cfg->detect_extn_cable) {
+			/* High impedance device found. Report as LINEOUT */
+			wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
+			pr_debug("%s: setup mic trigger for further detection\n",
+				 __func__);
+
+			/* Disable HW FSM and current source */
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
+			/* Setup for insertion detection */
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
+						 1);
+			/*
+			 * Enable HPHL trigger and MIC Schmitt triggers
+			 * and request for elec insertion interrupts
+			 */
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC,
+						 3);
+			wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
+					     true);
+		} else {
+			wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
+		}
+	} else {
+		WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
+		     mbhc->current_plug, plug_type);
+	}
+exit:
+	pr_debug("%s: leave\n", __func__);
+}
+EXPORT_SYMBOL(wcd_mbhc_find_plug_and_report);
+
+static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
+{
+	bool detection_type = 0;
+	bool micbias1 = false;
+	struct snd_soc_codec *codec = mbhc->codec;
+	enum snd_jack_types jack_type;
+
+	dev_dbg(codec->dev, "%s: enter\n", __func__);
+	WCD_MBHC_RSC_LOCK(mbhc);
+	mbhc->in_swch_irq_handler = true;
+
+	/* cancel pending button press */
+	if (wcd_cancel_btn_work(mbhc))
+		pr_debug("%s: button press is canceled\n", __func__);
+
+	WCD_MBHC_REG_READ(WCD_MBHC_MECH_DETECTION_TYPE, detection_type);
+
+	/* Set the detection type appropriately */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE,
+				 !detection_type);
+
+	pr_debug("%s: mbhc->current_plug: %d detection_type: %d\n", __func__,
+			mbhc->current_plug, detection_type);
+	if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug)
+		mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc,
+						&mbhc->correct_plug_swch);
+	else
+		pr_info("%s: hs_detect_plug work not cancelled\n", __func__);
+
+	if (mbhc->mbhc_cb->micbias_enable_status)
+		micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
+						MIC_BIAS_1);
+
+	if ((mbhc->current_plug == MBHC_PLUG_TYPE_NONE) &&
+	    detection_type) {
+		/* Make sure MASTER_BIAS_CTL is enabled */
+		mbhc->mbhc_cb->mbhc_bias(codec, true);
+
+		if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
+			mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+					MBHC_COMMON_MICB_TAIL_CURR, true);
+
+		if (!mbhc->mbhc_cfg->hs_ext_micbias &&
+		     mbhc->mbhc_cb->micb_internal)
+			/*
+			 * Enable Tx2 RBias if the headset
+			 * is using internal micbias
+			 */
+			mbhc->mbhc_cb->micb_internal(codec, 1, true);
+
+		/* Remove micbias pulldown */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 0);
+		/* Apply trim if needed on the device */
+		if (mbhc->mbhc_cb->trim_btn_reg)
+			mbhc->mbhc_cb->trim_btn_reg(codec);
+		/* Enable external voltage source to micbias if present */
+		if (mbhc->mbhc_cb->enable_mb_source)
+			mbhc->mbhc_cb->enable_mb_source(mbhc, true);
+		mbhc->btn_press_intr = false;
+		mbhc->is_btn_press = false;
+		if (mbhc->mbhc_fn)
+			mbhc->mbhc_fn->wcd_mbhc_detect_plug_type(mbhc);
+	} else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
+			&& !detection_type) {
+		/* Disable external voltage source to micbias if present */
+		if (mbhc->mbhc_cb->enable_mb_source)
+			mbhc->mbhc_cb->enable_mb_source(mbhc, false);
+		/* Disable HW FSM */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
+		if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
+			mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
+					MBHC_COMMON_MICB_TAIL_CURR, false);
+
+		if (mbhc->mbhc_cb->set_cap_mode)
+			mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
+
+		mbhc->btn_press_intr = false;
+		mbhc->is_btn_press = false;
+		switch (mbhc->current_plug) {
+		case MBHC_PLUG_TYPE_HEADPHONE:
+			jack_type = SND_JACK_HEADPHONE;
+			break;
+		case MBHC_PLUG_TYPE_GND_MIC_SWAP:
+			jack_type = SND_JACK_UNSUPPORTED;
+			break;
+		case MBHC_PLUG_TYPE_HEADSET:
+			/* make sure to turn off Rbias */
+			if (mbhc->mbhc_cb->micb_internal)
+				mbhc->mbhc_cb->micb_internal(codec, 1, false);
+			/* Pulldown micbias */
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 1);
+			jack_type = SND_JACK_HEADSET;
+			break;
+		case MBHC_PLUG_TYPE_HIGH_HPH:
+			mbhc->is_extn_cable = false;
+			jack_type = SND_JACK_LINEOUT;
+			break;
+		case MBHC_PLUG_TYPE_ANC_HEADPHONE:
+			jack_type = SND_JACK_ANC_HEADPHONE;
+			break;
+		default:
+			pr_info("%s: Invalid current plug: %d\n",
+				__func__, mbhc->current_plug);
+			jack_type = SND_JACK_UNSUPPORTED;
+			break;
+		}
+		wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false);
+		wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, 1);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
+		mbhc->extn_cable_hph_rem = false;
+		wcd_mbhc_report_plug(mbhc, 0, jack_type);
+
+	} else if (!detection_type) {
+		/* Disable external voltage source to micbias if present */
+		if (mbhc->mbhc_cb->enable_mb_source)
+			mbhc->mbhc_cb->enable_mb_source(mbhc, false);
+		/* Disable HW FSM */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
+		mbhc->extn_cable_hph_rem = false;
+	}
+
+	mbhc->in_swch_irq_handler = false;
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
+{
+	int r = IRQ_HANDLED;
+	struct wcd_mbhc *mbhc = data;
+
+	pr_debug("%s: enter\n", __func__);
+	if (unlikely((mbhc->mbhc_cb->lock_sleep(mbhc, true)) == false)) {
+		pr_warn("%s: failed to hold suspend\n", __func__);
+		r = IRQ_NONE;
+	} else {
+		/* Call handler */
+		wcd_mbhc_swch_irq_handler(mbhc);
+		mbhc->mbhc_cb->lock_sleep(mbhc, false);
+	}
+	pr_debug("%s: leave %d\n", __func__, r);
+	return r;
+}
+
+int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
+{
+	int mask = 0;
+	int btn;
+
+	btn = mbhc->mbhc_cb->map_btn_code_to_num(mbhc->codec);
+
+	switch (btn) {
+	case 0:
+		mask = SND_JACK_BTN_0;
+		break;
+	case 1:
+		mask = SND_JACK_BTN_1;
+		break;
+	case 2:
+		mask = SND_JACK_BTN_2;
+		break;
+	case 3:
+		mask = SND_JACK_BTN_3;
+		break;
+	case 4:
+		mask = SND_JACK_BTN_4;
+		break;
+	case 5:
+		mask = SND_JACK_BTN_5;
+		break;
+	default:
+		break;
+	}
+
+	return mask;
+}
+EXPORT_SYMBOL(wcd_mbhc_get_button_mask);
+
+static void wcd_btn_lpress_fn(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct wcd_mbhc *mbhc;
+	s16 btn_result = 0;
+
+	pr_debug("%s: Enter\n", __func__);
+
+	dwork = to_delayed_work(work);
+	mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
+
+	WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result);
+	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
+		pr_debug("%s: Reporting long button press event, btn_result: %d\n",
+			 __func__, btn_result);
+		wcd_mbhc_jack_report(mbhc, &mbhc->button_jack,
+				mbhc->buttons_pressed, mbhc->buttons_pressed);
+	}
+	pr_debug("%s: leave\n", __func__);
+	mbhc->mbhc_cb->lock_sleep(mbhc, false);
+}
+
+static bool wcd_mbhc_fw_validate(const void *data, size_t size)
+{
+	u32 cfg_offset;
+	struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+	struct firmware_cal fw;
+
+	fw.data = (void *)data;
+	fw.size = size;
+
+	if (fw.size < WCD_MBHC_CAL_MIN_SIZE)
+		return false;
+
+	/*
+	 * Previous check guarantees that there is enough fw data up
+	 * to num_btn
+	 */
+	btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(fw.data);
+	cfg_offset = (u32) ((void *) btn_cfg - (void *) fw.data);
+	if (fw.size < (cfg_offset + WCD_MBHC_CAL_BTN_SZ(btn_cfg)))
+		return false;
+
+	return true;
+}
+
+static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+	int mask;
+	unsigned long msec_val;
+
+	pr_debug("%s: enter\n", __func__);
+	complete(&mbhc->btn_press_compl);
+	WCD_MBHC_RSC_LOCK(mbhc);
+	wcd_cancel_btn_work(mbhc);
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low ", __func__);
+		goto done;
+	}
+
+	mbhc->is_btn_press = true;
+	msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
+	pr_debug("%s: msec_val = %ld\n", __func__, msec_val);
+	if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) {
+		pr_debug("%s: Too short, ignore button press\n", __func__);
+		goto done;
+	}
+
+	/* If switch interrupt already kicked in, ignore button press */
+	if (mbhc->in_swch_irq_handler) {
+		pr_debug("%s: Swtich level changed, ignore button press\n",
+			 __func__);
+		goto done;
+	}
+	mask = wcd_mbhc_get_button_mask(mbhc);
+	if (mask == SND_JACK_BTN_0)
+		mbhc->btn_press_intr = true;
+
+	if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) {
+		pr_debug("%s: Plug isn't headset, ignore button press\n",
+				__func__);
+		goto done;
+	}
+	mbhc->buttons_pressed |= mask;
+	mbhc->mbhc_cb->lock_sleep(mbhc, true);
+	if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
+				msecs_to_jiffies(400)) == 0) {
+		WARN(1, "Button pressed twice without release event\n");
+		mbhc->mbhc_cb->lock_sleep(mbhc, false);
+	}
+done:
+	pr_debug("%s: leave\n", __func__);
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd_mbhc_release_handler(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+	int ret;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD_MBHC_RSC_LOCK(mbhc);
+	if (wcd_swch_level_remove(mbhc)) {
+		pr_debug("%s: Switch level is low ", __func__);
+		goto exit;
+	}
+
+	if (mbhc->is_btn_press) {
+		mbhc->is_btn_press = false;
+	} else {
+		pr_debug("%s: This release is for fake btn press\n", __func__);
+		goto exit;
+	}
+
+	/*
+	 * If current plug is headphone then there is no chance to
+	 * get btn release interrupt, so connected cable should be
+	 * headset not headphone.
+	 * For ADC MBHC, ADC_COMPLETE interrupt will be generated
+	 * in this case. So skip the check here.
+	 */
+	if (mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY &&
+		mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
+		wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
+		goto exit;
+
+	}
+	if (mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK) {
+		ret = wcd_cancel_btn_work(mbhc);
+		if (ret == 0) {
+			pr_debug("%s: Reporting long button release event\n",
+				 __func__);
+			wcd_mbhc_jack_report(mbhc, &mbhc->button_jack,
+					0, mbhc->buttons_pressed);
+		} else {
+			if (mbhc->in_swch_irq_handler) {
+				pr_debug("%s: Switch irq kicked in, ignore\n",
+					__func__);
+			} else {
+				pr_debug("%s: Reporting btn press\n",
+					 __func__);
+				wcd_mbhc_jack_report(mbhc,
+						     &mbhc->button_jack,
+						     mbhc->buttons_pressed,
+						     mbhc->buttons_pressed);
+				pr_debug("%s: Reporting btn release\n",
+					 __func__);
+				wcd_mbhc_jack_report(mbhc,
+						&mbhc->button_jack,
+						0, mbhc->buttons_pressed);
+			}
+		}
+		mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
+	}
+exit:
+	pr_debug("%s: leave\n", __func__);
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+	int val;
+
+	pr_debug("%s: received HPHL OCP irq\n", __func__);
+	if (mbhc) {
+		if (mbhc->mbhc_cb->hph_register_recovery) {
+			if (mbhc->mbhc_cb->hph_register_recovery(mbhc)) {
+				WCD_MBHC_REG_READ(WCD_MBHC_HPHR_OCP_STATUS,
+						  val);
+				if ((val != -EINVAL) && val)
+					mbhc->is_hph_ocp_pending = true;
+				goto done;
+			}
+		}
+
+		if (mbhc->hphlocp_cnt < OCP_ATTEMPT) {
+			mbhc->hphlocp_cnt++;
+			pr_debug("%s: retry, hphlocp_cnt: %d\n", __func__,
+				 mbhc->hphlocp_cnt);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
+		} else {
+			mbhc->mbhc_cb->irq_control(mbhc->codec,
+						   mbhc->intr_ids->hph_left_ocp,
+						   false);
+			mbhc->hph_status |= SND_JACK_OC_HPHL;
+			wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
+					    mbhc->hph_status,
+					    WCD_MBHC_JACK_MASK);
+		}
+	} else {
+		pr_err("%s: Bad wcd9xxx_spmi private data\n", __func__);
+	}
+done:
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
+{
+	struct wcd_mbhc *mbhc = data;
+
+	pr_debug("%s: received HPHR OCP irq\n", __func__);
+
+	if (!mbhc) {
+		pr_err("%s: Bad mbhc private data\n", __func__);
+		goto done;
+	}
+
+	if (mbhc->is_hph_ocp_pending) {
+		mbhc->is_hph_ocp_pending = false;
+		goto done;
+	}
+
+	if (mbhc->mbhc_cb->hph_register_recovery) {
+		if (mbhc->mbhc_cb->hph_register_recovery(mbhc))
+			/* register corruption, hence reset registers */
+			goto done;
+	}
+	if (mbhc->hphrocp_cnt < OCP_ATTEMPT) {
+		mbhc->hphrocp_cnt++;
+		pr_debug("%s: retry, hphrocp_cnt: %d\n", __func__,
+			 mbhc->hphrocp_cnt);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
+	} else {
+		mbhc->mbhc_cb->irq_control(mbhc->codec,
+					   mbhc->intr_ids->hph_right_ocp,
+					   false);
+		mbhc->hph_status |= SND_JACK_OC_HPHR;
+		wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
+				    mbhc->hph_status, WCD_MBHC_JACK_MASK);
+	}
+done:
+	return IRQ_HANDLED;
+}
+
+static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD_MBHC_RSC_LOCK(mbhc);
+
+	/* enable HS detection */
+	if (mbhc->mbhc_cb->hph_pull_up_control)
+		mbhc->mbhc_cb->hph_pull_up_control(codec, I_DEFAULT);
+	else
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
+
+	if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config)
+		mbhc->mbhc_cb->mbhc_moisture_config(mbhc);
+
+	/*
+	 * For USB analog we need to override the switch configuration.
+	 * Also, disable hph_l pull-up current source as HS_DET_L is driven
+	 * by an external source
+	 */
+	if (mbhc->mbhc_cfg->enable_usbc_analog) {
+		mbhc->hphl_swh = 1;
+		mbhc->gnd_swh = 1;
+
+		if (mbhc->mbhc_cb->hph_pull_up_control)
+			mbhc->mbhc_cb->hph_pull_up_control(codec, I_OFF);
+		else
+			WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL,
+						 0);
+	}
+
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
+	if (mbhc->mbhc_cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl)
+		mbhc->mbhc_cb->mbhc_gnd_det_ctrl(codec, true);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
+
+	if (mbhc->mbhc_cfg->enable_usbc_analog) {
+		/* Insertion debounce set to 48ms */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 4);
+	} else {
+		/* Insertion debounce set to 96ms */
+		WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
+	}
+
+	/* Button Debounce set to 16ms */
+	WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2);
+
+	/* Enable micbias ramp */
+	if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
+		mbhc->mbhc_cb->mbhc_micb_ramp_control(codec, true);
+	/* enable bias */
+	mbhc->mbhc_cb->mbhc_bias(codec, true);
+	/* enable MBHC clock */
+	if (mbhc->mbhc_cb->clk_setup)
+		mbhc->mbhc_cb->clk_setup(codec, true);
+
+	/* program HS_VREF value */
+	wcd_program_hs_vref(mbhc);
+
+	wcd_program_btn_threshold(mbhc, false);
+
+
+	reinit_completion(&mbhc->btn_press_compl);
+
+	WCD_MBHC_RSC_UNLOCK(mbhc);
+	pr_debug("%s: leave\n", __func__);
+	return ret;
+}
+
+static void wcd_mbhc_fw_read(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct wcd_mbhc *mbhc;
+	struct snd_soc_codec *codec;
+	const struct firmware *fw;
+	struct firmware_cal *fw_data = NULL;
+	int ret = -1, retry = 0;
+	bool use_default_cal = false;
+
+	dwork = to_delayed_work(work);
+	mbhc = container_of(dwork, struct wcd_mbhc, mbhc_firmware_dwork);
+	codec = mbhc->codec;
+
+	while (retry < FW_READ_ATTEMPTS) {
+		retry++;
+		pr_debug("%s:Attempt %d to request MBHC firmware\n",
+			__func__, retry);
+		if (mbhc->mbhc_cb->get_hwdep_fw_cal)
+			fw_data = mbhc->mbhc_cb->get_hwdep_fw_cal(mbhc,
+					WCD9XXX_MBHC_CAL);
+		if (!fw_data)
+			ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
+				       codec->dev);
+		/*
+		 * if request_firmware and hwdep cal both fail then
+		 * sleep for 4sec for the userspace to send data to kernel
+		 * retry for few times before bailing out
+		 */
+		if ((ret != 0) && !fw_data) {
+			usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT +
+					WCD_MBHC_USLEEP_RANGE_MARGIN_US);
+		} else {
+			pr_debug("%s: MBHC Firmware read successful\n",
+					__func__);
+			break;
+		}
+	}
+	if (!fw_data)
+		pr_debug("%s: using request_firmware\n", __func__);
+	else
+		pr_debug("%s: using hwdep cal\n", __func__);
+
+	if (ret != 0 && !fw_data) {
+		pr_err("%s: Cannot load MBHC firmware use default cal\n",
+		       __func__);
+		use_default_cal = true;
+	}
+	if (!use_default_cal) {
+		const void *data;
+		size_t size;
+
+		if (fw_data) {
+			data = fw_data->data;
+			size = fw_data->size;
+		} else {
+			data = fw->data;
+			size = fw->size;
+		}
+		if (wcd_mbhc_fw_validate(data, size) == false) {
+			pr_err("%s: Invalid MBHC cal data size use default cal\n",
+				__func__);
+			if (!fw_data)
+				release_firmware(fw);
+		} else {
+			if (fw_data) {
+				mbhc->mbhc_cfg->calibration =
+					(void *)fw_data->data;
+				mbhc->mbhc_cal = fw_data;
+			} else {
+				mbhc->mbhc_cfg->calibration =
+					(void *)fw->data;
+				mbhc->mbhc_fw = fw;
+			}
+		}
+
+	}
+
+	(void) wcd_mbhc_initialise(mbhc);
+}
+
+static int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc)
+{
+	enum snd_jack_types type;
+	int i, ret, result = 0;
+	int *btn_key_code;
+
+	btn_key_code = mbhc->mbhc_cfg->key_code;
+
+	for (i = 0 ; i < WCD_MBHC_KEYCODE_NUM ; i++) {
+		if (btn_key_code[i] != 0) {
+			switch (i) {
+			case 0:
+				type = SND_JACK_BTN_0;
+				break;
+			case 1:
+				type = SND_JACK_BTN_1;
+				break;
+			case 2:
+				type = SND_JACK_BTN_2;
+				break;
+			case 3:
+				type = SND_JACK_BTN_3;
+				break;
+			case 4:
+				type = SND_JACK_BTN_4;
+				break;
+			case 5:
+				type = SND_JACK_BTN_5;
+				break;
+			default:
+				WARN_ONCE(1, "Wrong button number:%d\n", i);
+				result = -1;
+				return result;
+			}
+			ret = snd_jack_set_key(mbhc->button_jack.jack,
+							type,
+							btn_key_code[i]);
+			if (ret) {
+				pr_err("%s: Failed to set code for %d\n",
+					__func__, btn_key_code[i]);
+				result = -1;
+				return result;
+			}
+			input_set_capability(
+				mbhc->button_jack.jack->input_dev,
+				EV_KEY, btn_key_code[i]);
+			pr_debug("%s: set btn%d key code:%d\n", __func__,
+				i, btn_key_code[i]);
+		}
+	}
+	if (btn_key_code[0])
+		mbhc->is_btn_already_regd = true;
+	return result;
+}
+
+static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc,
+					     bool active)
+{
+	int rc = 0;
+	struct usbc_ana_audio_config *config =
+		&mbhc->mbhc_cfg->usbc_analog_cfg;
+	union power_supply_propval pval;
+
+	dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n",
+		__func__, active);
+
+	memset(&pval, 0, sizeof(pval));
+
+	if (active) {
+		pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
+		if (power_supply_set_property(mbhc->usb_psy,
+				POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+			dev_info(mbhc->codec->dev, "%s: force PR_SOURCE mode unsuccessful\n",
+				 __func__);
+		else
+			mbhc->usbc_force_pr_mode = true;
+
+		if (config->usbc_en1_gpio_p)
+			rc = msm_cdc_pinctrl_select_active_state(
+				config->usbc_en1_gpio_p);
+		if (rc == 0 && config->usbc_force_gpio_p)
+			rc = msm_cdc_pinctrl_select_active_state(
+				config->usbc_force_gpio_p);
+		mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
+	} else {
+		/* no delay is required when disabling GPIOs */
+		if (config->usbc_en1_gpio_p)
+			msm_cdc_pinctrl_select_sleep_state(
+				config->usbc_en1_gpio_p);
+		if (config->usbc_force_gpio_p)
+			msm_cdc_pinctrl_select_sleep_state(
+				config->usbc_force_gpio_p);
+
+		if (mbhc->usbc_force_pr_mode) {
+			pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+			if (power_supply_set_property(mbhc->usb_psy,
+				POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+				dev_info(mbhc->codec->dev, "%s: force PR_DUAL mode unsuccessful\n",
+					 __func__);
+
+			mbhc->usbc_force_pr_mode = false;
+		}
+
+		mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE;
+		if (mbhc->mbhc_cfg->swap_gnd_mic)
+			mbhc->mbhc_cfg->swap_gnd_mic(mbhc->codec, false);
+	}
+
+	return rc;
+}
+
+/* workqueue */
+static void wcd_mbhc_usbc_analog_work_fn(struct work_struct *work)
+{
+	struct wcd_mbhc *mbhc =
+		container_of(work, struct wcd_mbhc, usbc_analog_work);
+
+	wcd_mbhc_usb_c_analog_setup_gpios(mbhc,
+			mbhc->usbc_mode != POWER_SUPPLY_TYPEC_NONE);
+}
+
+/* this callback function is used to process PMI notification */
+static int wcd_mbhc_usb_c_event_changed(struct notifier_block *nb,
+					unsigned long evt, void *ptr)
+{
+	int ret;
+	union power_supply_propval mode;
+	struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, psy_nb);
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	if (ptr != mbhc->usb_psy || evt != PSY_EVENT_PROP_CHANGED)
+		return 0;
+
+	ret = power_supply_get_property(mbhc->usb_psy,
+			POWER_SUPPLY_PROP_TYPEC_MODE, &mode);
+	if (ret) {
+		dev_err(codec->dev, "%s: Unable to read USB TYPEC_MODE: %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "%s: USB change event received\n",
+		__func__);
+	dev_dbg(codec->dev, "%s: supply mode %d, expected %d\n", __func__,
+		mode.intval, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER);
+
+	switch (mode.intval) {
+	case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER:
+	case POWER_SUPPLY_TYPEC_NONE:
+		dev_dbg(codec->dev, "%s: usbc_mode: %d; mode.intval: %d\n",
+			__func__, mbhc->usbc_mode, mode.intval);
+
+		if (mbhc->usbc_mode == mode.intval)
+			break; /* filter notifications received before */
+		mbhc->usbc_mode = mode.intval;
+
+		dev_dbg(codec->dev, "%s: queueing usbc_analog_work\n",
+			__func__);
+		schedule_work(&mbhc->usbc_analog_work);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+/* PMI registration code */
+static int wcd_mbhc_usb_c_analog_init(struct wcd_mbhc *mbhc)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	dev_dbg(mbhc->codec->dev, "%s: usb-c analog setup start\n", __func__);
+	INIT_WORK(&mbhc->usbc_analog_work, wcd_mbhc_usbc_analog_work_fn);
+
+	mbhc->usb_psy = power_supply_get_by_name("usb");
+	if (IS_ERR_OR_NULL(mbhc->usb_psy)) {
+		dev_err(codec->dev, "%s: could not get USB psy info\n",
+			__func__);
+		ret = -EPROBE_DEFER;
+		if (IS_ERR(mbhc->usb_psy))
+			ret = PTR_ERR(mbhc->usb_psy);
+		mbhc->usb_psy = NULL;
+		goto err;
+	}
+
+	ret = wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false);
+	if (ret) {
+		dev_err(codec->dev, "%s: error while setting USBC ana gpios\n",
+			__func__);
+		goto err;
+	}
+
+	mbhc->psy_nb.notifier_call = wcd_mbhc_usb_c_event_changed;
+	mbhc->psy_nb.priority = 0;
+	ret = power_supply_reg_notifier(&mbhc->psy_nb);
+	if (ret) {
+		dev_err(codec->dev, "%s: power supply registration failed\n",
+			__func__);
+		goto err;
+	}
+
+	/*
+	 * as part of the init sequence check if there is a connected
+	 * USB C analog adapter
+	 */
+	dev_dbg(mbhc->codec->dev, "%s: verify if USB adapter is already inserted\n",
+		__func__);
+	ret = wcd_mbhc_usb_c_event_changed(&mbhc->psy_nb,
+					   PSY_EVENT_PROP_CHANGED,
+					   mbhc->usb_psy);
+
+err:
+	return ret;
+}
+
+static int wcd_mbhc_usb_c_analog_deinit(struct wcd_mbhc *mbhc)
+{
+	wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false);
+
+	/* deregister from PMI */
+	power_supply_unreg_notifier(&mbhc->psy_nb);
+
+	return 0;
+}
+
+static int wcd_mbhc_init_gpio(struct wcd_mbhc *mbhc,
+			      struct wcd_mbhc_config *mbhc_cfg,
+			      const char *gpio_dt_str,
+			      int *gpio, struct device_node **gpio_dn)
+{
+	int rc = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct snd_soc_card *card = codec->component.card;
+
+	dev_dbg(mbhc->codec->dev, "%s: gpio %s\n", __func__, gpio_dt_str);
+
+	*gpio_dn = of_parse_phandle(card->dev->of_node, gpio_dt_str, 0);
+
+	if (!(*gpio_dn)) {
+		*gpio = of_get_named_gpio(card->dev->of_node, gpio_dt_str, 0);
+		if (!gpio_is_valid(*gpio)) {
+			dev_err(card->dev, "%s, property %s not in node %s",
+				__func__, gpio_dt_str,
+				card->dev->of_node->full_name);
+			rc = -EINVAL;
+		}
+	}
+
+	return rc;
+}
+
+int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg)
+{
+	int rc = 0;
+	struct usbc_ana_audio_config *config;
+	struct snd_soc_codec *codec;
+	struct snd_soc_card *card;
+	const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported";
+
+	if (!mbhc || !mbhc_cfg)
+		return -EINVAL;
+
+	config = &mbhc_cfg->usbc_analog_cfg;
+	codec = mbhc->codec;
+	card = codec->component.card;
+
+	/* update the mbhc config */
+	mbhc->mbhc_cfg = mbhc_cfg;
+
+	dev_dbg(mbhc->codec->dev, "%s: enter\n", __func__);
+
+	/* check if USB C analog is defined on device tree */
+	mbhc_cfg->enable_usbc_analog = 0;
+	if (of_find_property(card->dev->of_node, usb_c_dt, NULL)) {
+		rc = of_property_read_u32(card->dev->of_node, usb_c_dt,
+				&mbhc_cfg->enable_usbc_analog);
+	}
+	if (mbhc_cfg->enable_usbc_analog == 0 || rc != 0) {
+		dev_info(card->dev,
+				"%s: %s in dt node is missing or false\n",
+				__func__, usb_c_dt);
+		dev_info(card->dev,
+			"%s: skipping USB c analog configuration\n", __func__);
+	}
+
+	/* initialize GPIOs */
+	if (mbhc_cfg->enable_usbc_analog) {
+		dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n",
+				__func__);
+		rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+				"qcom,usbc-analog-en1-gpio",
+				&config->usbc_en1_gpio,
+				&config->usbc_en1_gpio_p);
+		if (rc)
+			goto err;
+
+		if (of_find_property(card->dev->of_node,
+				     "qcom,usbc-analog-force_detect_gpio",
+				     NULL)) {
+			rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
+					"qcom,usbc-analog-force_detect_gpio",
+					&config->usbc_force_gpio,
+					&config->usbc_force_gpio_p);
+			if (rc)
+				goto err;
+		}
+
+		dev_dbg(mbhc->codec->dev, "%s: calling usb_c_analog_init\n",
+			__func__);
+		/* init PMI notifier */
+		rc = wcd_mbhc_usb_c_analog_init(mbhc);
+		if (rc) {
+			rc = EPROBE_DEFER;
+			goto err;
+		}
+	}
+
+	/* Set btn key code */
+	if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc))
+		pr_err("Set btn key code error!!!\n");
+
+	if (!mbhc->mbhc_cfg->read_fw_bin ||
+	    (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) ||
+	    (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) {
+		rc = wcd_mbhc_initialise(mbhc);
+	} else {
+		if (!mbhc->mbhc_fw || !mbhc->mbhc_cal)
+			schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
+				      usecs_to_jiffies(FW_READ_TIMEOUT));
+		else
+			pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
+				 __func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
+	}
+
+	return rc;
+err:
+	if (config->usbc_en1_gpio > 0) {
+		dev_dbg(card->dev, "%s free usb en1 gpio %d\n",
+			__func__, config->usbc_en1_gpio);
+		gpio_free(config->usbc_en1_gpio);
+		config->usbc_en1_gpio = 0;
+	}
+	if (config->usbc_force_gpio > 0) {
+		dev_dbg(card->dev, "%s free usb_force gpio %d\n",
+			__func__, config->usbc_force_gpio);
+		gpio_free(config->usbc_force_gpio);
+		config->usbc_force_gpio = 0;
+	}
+	if (config->usbc_en1_gpio_p)
+		of_node_put(config->usbc_en1_gpio_p);
+	if (config->usbc_force_gpio_p)
+		of_node_put(config->usbc_force_gpio_p);
+	dev_dbg(mbhc->codec->dev, "%s: leave %d\n", __func__, rc);
+	return rc;
+}
+EXPORT_SYMBOL(wcd_mbhc_start);
+
+void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
+{
+	struct usbc_ana_audio_config *config = &mbhc->mbhc_cfg->usbc_analog_cfg;
+
+	pr_debug("%s: enter\n", __func__);
+
+	if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect)
+			mbhc->mbhc_cb->skip_imped_detect(mbhc->codec);
+	}
+	mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
+	mbhc->hph_status = 0;
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->irq_control) {
+		mbhc->mbhc_cb->irq_control(mbhc->codec,
+				mbhc->intr_ids->hph_left_ocp,
+				false);
+		mbhc->mbhc_cb->irq_control(mbhc->codec,
+				mbhc->intr_ids->hph_right_ocp,
+				false);
+	}
+	if (mbhc->mbhc_fw || mbhc->mbhc_cal) {
+		cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork);
+		if (!mbhc->mbhc_cal)
+			release_firmware(mbhc->mbhc_fw);
+		mbhc->mbhc_fw = NULL;
+		mbhc->mbhc_cal = NULL;
+	}
+
+	if (mbhc->mbhc_cfg->enable_usbc_analog) {
+		wcd_mbhc_usb_c_analog_deinit(mbhc);
+		/* free GPIOs */
+		if (config->usbc_en1_gpio > 0)
+			gpio_free(config->usbc_en1_gpio);
+		if (config->usbc_force_gpio)
+			gpio_free(config->usbc_force_gpio);
+
+		if (config->usbc_en1_gpio_p)
+			of_node_put(config->usbc_en1_gpio_p);
+		if (config->usbc_force_gpio_p)
+			of_node_put(config->usbc_force_gpio_p);
+	}
+
+	pr_debug("%s: leave\n", __func__);
+}
+EXPORT_SYMBOL(wcd_mbhc_stop);
+
+/*
+ * wcd_mbhc_init : initialize MBHC internal structures.
+ *
+ * NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
+ */
+int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
+		      const struct wcd_mbhc_cb *mbhc_cb,
+		      const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
+		      struct wcd_mbhc_register *wcd_mbhc_regs,
+		      bool impedance_det_en)
+{
+	int ret = 0;
+	int hph_swh = 0;
+	int gnd_swh = 0;
+	u32 hph_moist_config[3];
+	struct snd_soc_card *card = codec->component.card;
+	const char *hph_switch = "qcom,msm-mbhc-hphl-swh";
+	const char *gnd_switch = "qcom,msm-mbhc-gnd-swh";
+
+	pr_debug("%s: enter\n", __func__);
+
+	ret = of_property_read_u32(card->dev->of_node, hph_switch, &hph_swh);
+	if (ret) {
+		dev_err(card->dev,
+			"%s: missing %s in dt node\n", __func__, hph_switch);
+		goto err;
+	}
+
+	ret = of_property_read_u32(card->dev->of_node, gnd_switch, &gnd_swh);
+	if (ret) {
+		dev_err(card->dev,
+			"%s: missing %s in dt node\n", __func__, gnd_switch);
+		goto err;
+	}
+
+	ret = of_property_read_u32_array(card->dev->of_node,
+					 "qcom,msm-mbhc-moist-cfg",
+					 hph_moist_config, 3);
+	if (ret) {
+		dev_dbg(card->dev, "%s: no qcom,msm-mbhc-moist-cfg in DT\n",
+			__func__);
+		mbhc->moist_vref = V_45_MV;
+		mbhc->moist_iref = I_3P0_UA;
+		mbhc->moist_rref = R_24_KOHM;
+	} else {
+		mbhc->moist_vref = hph_moist_config[0];
+		mbhc->moist_iref = hph_moist_config[1];
+		mbhc->moist_rref = hph_moist_config[2];
+	}
+
+	mbhc->in_swch_irq_handler = false;
+	mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
+	mbhc->is_btn_press = false;
+	mbhc->codec = codec;
+	mbhc->intr_ids = mbhc_cdc_intr_ids;
+	mbhc->impedance_detect = impedance_det_en;
+	mbhc->hphl_swh = hph_swh;
+	mbhc->gnd_swh = gnd_swh;
+	mbhc->micbias_enable = false;
+	mbhc->mbhc_cb = mbhc_cb;
+	mbhc->btn_press_intr = false;
+	mbhc->is_hs_recording = false;
+	mbhc->is_extn_cable = false;
+	mbhc->extn_cable_hph_rem = false;
+	mbhc->hph_type = WCD_MBHC_HPH_NONE;
+	mbhc->wcd_mbhc_regs = wcd_mbhc_regs;
+
+	if (mbhc->intr_ids == NULL) {
+		pr_err("%s: Interrupt mapping not provided\n", __func__);
+		return -EINVAL;
+	}
+	if (!mbhc->wcd_mbhc_regs) {
+		dev_err(codec->dev, "%s: mbhc registers are not defined\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	/* Check if IRQ and other required callbacks are defined or not */
+	if (!mbhc_cb || !mbhc_cb->request_irq || !mbhc_cb->irq_control ||
+	    !mbhc_cb->free_irq || !mbhc_cb->map_btn_code_to_num ||
+	    !mbhc_cb->lock_sleep || !mbhc_cb->mbhc_bias ||
+	    !mbhc_cb->set_btn_thr) {
+		dev_err(codec->dev, "%s: required mbhc callbacks are not defined\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	/* No need to create new sound card jacks if is is already created */
+	if (mbhc->headset_jack.jack == NULL) {
+		ret = snd_soc_card_jack_new(codec->component.card,
+					    "Headset Jack", WCD_MBHC_JACK_MASK,
+					    &mbhc->headset_jack, NULL, 0);
+		if (ret) {
+			pr_err("%s: Failed to create new jack\n", __func__);
+			return ret;
+		}
+
+		ret = snd_soc_card_jack_new(codec->component.card,
+					    "Button Jack",
+					    WCD_MBHC_JACK_BUTTON_MASK,
+					    &mbhc->button_jack, NULL, 0);
+		if (ret) {
+			pr_err("Failed to create new jack\n");
+			return ret;
+		}
+
+		ret = snd_jack_set_key(mbhc->button_jack.jack,
+				       SND_JACK_BTN_0,
+				       KEY_MEDIA);
+		if (ret) {
+			pr_err("%s: Failed to set code for btn-0\n",
+				__func__);
+			return ret;
+		}
+
+		INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
+				  wcd_mbhc_fw_read);
+		INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_lpress_fn);
+	}
+	mutex_init(&mbhc->hphl_pa_lock);
+	mutex_init(&mbhc->hphr_pa_lock);
+	init_completion(&mbhc->btn_press_compl);
+
+	/* Register event notifier */
+	mbhc->nblock.notifier_call = wcd_event_notify;
+	if (mbhc->mbhc_cb->register_notifier) {
+		ret = mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock,
+						       true);
+		if (ret) {
+			pr_err("%s: Failed to register notifier %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+
+	init_waitqueue_head(&mbhc->wait_btn_press);
+	mutex_init(&mbhc->codec_resource_lock);
+
+	switch (mbhc->mbhc_detection_logic) {
+	case WCD_DETECTION_LEGACY:
+		wcd_mbhc_legacy_init(mbhc);
+		break;
+	case WCD_DETECTION_ADC:
+		wcd_mbhc_adc_init(mbhc);
+		break;
+	default:
+		pr_err("%s: Unknown detection logic type %d\n",
+			__func__, mbhc->mbhc_detection_logic);
+		break;
+	}
+
+	if (!mbhc->mbhc_fn ||
+	    !mbhc->mbhc_fn->wcd_mbhc_hs_ins_irq ||
+	    !mbhc->mbhc_fn->wcd_mbhc_hs_rem_irq ||
+	    !mbhc->mbhc_fn->wcd_mbhc_detect_plug_type ||
+	    !mbhc->mbhc_fn->wcd_cancel_hs_detect_plug) {
+		pr_err("%s: mbhc function pointer is NULL\n", __func__);
+		goto err_mbhc_sw_irq;
+	}
+	ret = mbhc->mbhc_cb->request_irq(codec, mbhc->intr_ids->mbhc_sw_intr,
+				  wcd_mbhc_mech_plug_detect_irq,
+				  "mbhc sw intr", mbhc);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
+		       mbhc->intr_ids->mbhc_sw_intr, ret);
+		goto err_mbhc_sw_irq;
+	}
+
+	ret = mbhc->mbhc_cb->request_irq(codec,
+					 mbhc->intr_ids->mbhc_btn_press_intr,
+					 wcd_mbhc_btn_press_handler,
+					 "Button Press detect", mbhc);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+		       mbhc->intr_ids->mbhc_btn_press_intr);
+		goto err_btn_press_irq;
+	}
+
+	ret = mbhc->mbhc_cb->request_irq(codec,
+					 mbhc->intr_ids->mbhc_btn_release_intr,
+					 wcd_mbhc_release_handler,
+					 "Button Release detect", mbhc);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+			mbhc->intr_ids->mbhc_btn_release_intr);
+		goto err_btn_release_irq;
+	}
+
+	ret = mbhc->mbhc_cb->request_irq(codec,
+					 mbhc->intr_ids->mbhc_hs_ins_intr,
+					 mbhc->mbhc_fn->wcd_mbhc_hs_ins_irq,
+					 "Elect Insert", mbhc);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+		       mbhc->intr_ids->mbhc_hs_ins_intr);
+		goto err_mbhc_hs_ins_irq;
+	}
+	mbhc->mbhc_cb->irq_control(codec, mbhc->intr_ids->mbhc_hs_ins_intr,
+				   false);
+	clear_bit(WCD_MBHC_ELEC_HS_INS, &mbhc->intr_status);
+
+	ret = mbhc->mbhc_cb->request_irq(codec,
+					 mbhc->intr_ids->mbhc_hs_rem_intr,
+					 mbhc->mbhc_fn->wcd_mbhc_hs_rem_irq,
+					 "Elect Remove", mbhc);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+		       mbhc->intr_ids->mbhc_hs_rem_intr);
+		goto err_mbhc_hs_rem_irq;
+	}
+	mbhc->mbhc_cb->irq_control(codec, mbhc->intr_ids->mbhc_hs_rem_intr,
+				   false);
+	clear_bit(WCD_MBHC_ELEC_HS_REM, &mbhc->intr_status);
+
+	ret = mbhc->mbhc_cb->request_irq(codec, mbhc->intr_ids->hph_left_ocp,
+				  wcd_mbhc_hphl_ocp_irq, "HPH_L OCP detect",
+				  mbhc);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+		       mbhc->intr_ids->hph_left_ocp);
+		goto err_hphl_ocp_irq;
+	}
+
+	ret = mbhc->mbhc_cb->request_irq(codec, mbhc->intr_ids->hph_right_ocp,
+				  wcd_mbhc_hphr_ocp_irq, "HPH_R OCP detect",
+				  mbhc);
+	if (ret) {
+		pr_err("%s: Failed to request irq %d\n", __func__,
+		       mbhc->intr_ids->hph_right_ocp);
+		goto err_hphr_ocp_irq;
+	}
+
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+
+err_hphr_ocp_irq:
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_left_ocp, mbhc);
+err_hphl_ocp_irq:
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
+err_mbhc_hs_rem_irq:
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
+err_mbhc_hs_ins_irq:
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_release_intr,
+				mbhc);
+err_btn_release_irq:
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_press_intr,
+				mbhc);
+err_btn_press_irq:
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_sw_intr, mbhc);
+err_mbhc_sw_irq:
+	if (mbhc->mbhc_cb->register_notifier)
+		mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
+	mutex_destroy(&mbhc->codec_resource_lock);
+err:
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL(wcd_mbhc_init);
+
+void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_sw_intr, mbhc);
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_press_intr,
+				mbhc);
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_release_intr,
+				mbhc);
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_left_ocp, mbhc);
+	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_right_ocp, mbhc);
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier)
+		mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
+	if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug) {
+		WCD_MBHC_RSC_LOCK(mbhc);
+		mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc,
+					&mbhc->correct_plug_swch);
+		WCD_MBHC_RSC_UNLOCK(mbhc);
+	}
+	mutex_destroy(&mbhc->codec_resource_lock);
+	mutex_destroy(&mbhc->hphl_pa_lock);
+	mutex_destroy(&mbhc->hphr_pa_lock);
+}
+EXPORT_SYMBOL(wcd_mbhc_deinit);
+
+MODULE_DESCRIPTION("wcd MBHC v2 module");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd-mbhc-v2.h b/asoc/codecs/wcd-mbhc-v2.h
new file mode 100644
index 0000000..c8714fc
--- /dev/null
+++ b/asoc/codecs/wcd-mbhc-v2.h
@@ -0,0 +1,598 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD_MBHC_V2_H__
+#define __WCD_MBHC_V2_H__
+
+#include <linux/wait.h>
+#include <linux/stringify.h>
+#include <linux/power_supply.h>
+#include "wcdcal-hwdep.h"
+
+#define TOMBAK_MBHC_NC	0
+#define TOMBAK_MBHC_NO	1
+#define WCD_MBHC_DEF_BUTTONS 8
+#define WCD_MBHC_KEYCODE_NUM 8
+#define WCD_MBHC_USLEEP_RANGE_MARGIN_US 100
+#define WCD_MBHC_THR_HS_MICB_MV  2700
+/* z value defined in Ohms */
+#define WCD_MONO_HS_MIN_THR	2
+#define WCD_MBHC_STRINGIFY(s)  __stringify(s)
+
+#define WCD_MBHC_REGISTER(rid, rreg, rmask, rshift, rinvert) \
+{ .id = rid, .reg = rreg, .mask = rmask, .offset = rshift, .invert = rinvert }
+
+#define WCD_MBHC_RSC_LOCK(mbhc)			\
+{							\
+	pr_debug("%s: Acquiring BCL\n", __func__);	\
+	mutex_lock(&mbhc->codec_resource_lock);		\
+	pr_debug("%s: Acquiring BCL done\n", __func__);	\
+}
+
+#define WCD_MBHC_RSC_UNLOCK(mbhc)			\
+{							\
+	pr_debug("%s: Release BCL\n", __func__);	\
+	mutex_unlock(&mbhc->codec_resource_lock);	\
+}
+
+#define WCD_MBHC_RSC_ASSERT_LOCKED(mbhc)		\
+{							\
+	WARN_ONCE(!mutex_is_locked(&mbhc->codec_resource_lock), \
+		  "%s: BCL should have acquired\n", __func__); \
+}
+
+/*
+ * Macros to update and read mbhc register bits. Check for
+ * "0" before updating or reading the register, because it
+ * is possible that one codec wants to write to that bit and
+ * other codec does not.
+ */
+#define WCD_MBHC_REG_UPDATE_BITS(function, val)         \
+do {                                                    \
+	if (mbhc->wcd_mbhc_regs[function].reg) {        \
+		snd_soc_update_bits(mbhc->codec,	\
+		mbhc->wcd_mbhc_regs[function].reg,	\
+		mbhc->wcd_mbhc_regs[function].mask,	\
+		val << (mbhc->wcd_mbhc_regs[function].offset)); \
+	}                                               \
+} while (0)
+
+#define WCD_MBHC_REG_READ(function, val)	        \
+do {                                                    \
+	if (mbhc->wcd_mbhc_regs[function].reg) {        \
+		val = (((snd_soc_read(mbhc->codec,	\
+		mbhc->wcd_mbhc_regs[function].reg)) &	\
+		(mbhc->wcd_mbhc_regs[function].mask)) >> \
+		(mbhc->wcd_mbhc_regs[function].offset)); \
+	} else {                                         \
+		val = -EINVAL;                           \
+	}                                                \
+} while (0)
+
+#define WCD_MBHC_CAL_SIZE(buttons, rload) ( \
+	sizeof(struct wcd_mbhc_general_cfg) + \
+	sizeof(struct wcd_mbhc_plug_detect_cfg) + \
+	((sizeof(s16) + sizeof(s16)) * buttons) + \
+	    sizeof(struct wcd_mbhc_plug_type_cfg) + \
+	sizeof(struct wcd_mbhc_btn_detect_cfg) + \
+	sizeof(struct wcd_mbhc_imped_detect_cfg) + \
+		((sizeof(u16) + sizeof(u16)) * rload) \
+	)
+
+#define WCD_MBHC_CAL_GENERAL_PTR(cali) ( \
+	(struct wcd_mbhc_general_cfg *) cali)
+#define WCD_MBHC_CAL_PLUG_DET_PTR(cali) ( \
+	(struct wcd_mbhc_plug_detect_cfg *) \
+	&(WCD_MBHC_CAL_GENERAL_PTR(cali)[1]))
+#define WCD_MBHC_CAL_PLUG_TYPE_PTR(cali) ( \
+	(struct wcd_mbhc_plug_type_cfg *) \
+	&(WCD_MBHC_CAL_PLUG_DET_PTR(cali)[1]))
+#define WCD_MBHC_CAL_BTN_DET_PTR(cali) ( \
+	    (struct wcd_mbhc_btn_detect_cfg *) \
+	&(WCD_MBHC_CAL_PLUG_TYPE_PTR(cali)[1]))
+#define WCD_MBHC_CAL_IMPED_DET_PTR(cali) ( \
+	(struct wcd_mbhc_imped_detect_cfg *) \
+	(((void *)&WCD_MBHC_CAL_BTN_DET_PTR(cali)[1]) + \
+	(WCD_MBHC_CAL_BTN_DET_PTR(cali)->num_btn * \
+	(sizeof(WCD_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_low[0]) + \
+	sizeof(WCD_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
+	)
+
+#define WCD_MBHC_CAL_MIN_SIZE ( \
+	sizeof(struct wcd_mbhc_general_cfg) + \
+	sizeof(struct wcd_mbhc_plug_detect_cfg) + \
+	sizeof(struct wcd_mbhc_plug_type_cfg) + \
+	sizeof(struct wcd_mbhc_btn_detect_cfg) + \
+	sizeof(struct wcd_mbhc_imped_detect_cfg) + \
+	(sizeof(u16)*2)  \
+	)
+
+#define WCD_MBHC_CAL_BTN_SZ(cfg_ptr) ( \
+	sizeof(struct wcd_mbhc_btn_detect_cfg) + \
+	(cfg_ptr->num_btn * (sizeof(cfg_ptr->_v_btn_low[0]) + \
+			sizeof(cfg_ptr->_v_btn_high[0]))))
+
+#define WCD_MBHC_CAL_IMPED_MIN_SZ ( \
+	sizeof(struct wcd_mbhc_imped_detect_cfg) + sizeof(u16) * 2)
+
+#define WCD_MBHC_CAL_IMPED_SZ(cfg_ptr) ( \
+	sizeof(struct wcd_mbhc_imped_detect_cfg) + \
+	(cfg_ptr->_n_rload * \
+	(sizeof(cfg_ptr->_rload[0]) + sizeof(cfg_ptr->_alpha[0]))))
+
+#define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
+			   SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
+			   SND_JACK_MECHANICAL | SND_JACK_MICROPHONE2 | \
+			   SND_JACK_UNSUPPORTED)
+
+#define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+				  SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
+				  SND_JACK_BTN_4 | SND_JACK_BTN_5)
+#define OCP_ATTEMPT 20
+#define HS_DETECT_PLUG_TIME_MS (3 * 1000)
+#define SPECIAL_HS_DETECT_TIME_MS (2 * 1000)
+#define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
+#define GND_MIC_SWAP_THRESHOLD 4
+#define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100
+#define HS_VREF_MIN_VAL 1400
+#define FW_READ_ATTEMPTS 15
+#define FW_READ_TIMEOUT 4000000
+#define FAKE_REM_RETRY_ATTEMPTS 3
+#define MAX_IMPED 60000
+
+#define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS  50
+#define ANC_DETECT_RETRY_CNT 7
+#define WCD_MBHC_SPL_HS_CNT  1
+
+enum wcd_mbhc_detect_logic {
+	WCD_DETECTION_LEGACY,
+	WCD_DETECTION_ADC,
+};
+
+enum wcd_mbhc_cs_mb_en_flag {
+	WCD_MBHC_EN_CS = 0,
+	WCD_MBHC_EN_MB,
+	WCD_MBHC_EN_PULLUP,
+	WCD_MBHC_EN_NONE,
+};
+
+enum {
+	WCD_MBHC_ELEC_HS_INS,
+	WCD_MBHC_ELEC_HS_REM,
+};
+
+struct wcd_mbhc;
+enum wcd_mbhc_register_function {
+	WCD_MBHC_L_DET_EN,
+	WCD_MBHC_GND_DET_EN,
+	WCD_MBHC_MECH_DETECTION_TYPE,
+	WCD_MBHC_MIC_CLAMP_CTL,
+	WCD_MBHC_ELECT_DETECTION_TYPE,
+	WCD_MBHC_HS_L_DET_PULL_UP_CTRL,
+	WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL,
+	WCD_MBHC_HPHL_PLUG_TYPE,
+	WCD_MBHC_GND_PLUG_TYPE,
+	WCD_MBHC_SW_HPH_LP_100K_TO_GND,
+	WCD_MBHC_ELECT_SCHMT_ISRC,
+	WCD_MBHC_FSM_EN,
+	WCD_MBHC_INSREM_DBNC,
+	WCD_MBHC_BTN_DBNC,
+	WCD_MBHC_HS_VREF,
+	WCD_MBHC_HS_COMP_RESULT,
+	WCD_MBHC_MIC_SCHMT_RESULT,
+	WCD_MBHC_HPHL_SCHMT_RESULT,
+	WCD_MBHC_HPHR_SCHMT_RESULT,
+	WCD_MBHC_OCP_FSM_EN,
+	WCD_MBHC_BTN_RESULT,
+	WCD_MBHC_BTN_ISRC_CTL,
+	WCD_MBHC_ELECT_RESULT,
+	WCD_MBHC_MICB_CTRL,    /* Pull-up and micb control */
+	WCD_MBHC_HPH_CNP_WG_TIME,
+	WCD_MBHC_HPHR_PA_EN,
+	WCD_MBHC_HPHL_PA_EN,
+	WCD_MBHC_HPH_PA_EN,
+	WCD_MBHC_SWCH_LEVEL_REMOVE,
+	WCD_MBHC_PULLDOWN_CTRL,
+	WCD_MBHC_ANC_DET_EN,
+	WCD_MBHC_FSM_STATUS,
+	WCD_MBHC_MUX_CTL,
+	WCD_MBHC_HPHL_OCP_DET_EN,
+	WCD_MBHC_HPHR_OCP_DET_EN,
+	WCD_MBHC_HPHL_OCP_STATUS,
+	WCD_MBHC_HPHR_OCP_STATUS,
+	WCD_MBHC_ADC_EN,
+	WCD_MBHC_ADC_COMPLETE,
+	WCD_MBHC_ADC_TIMEOUT,
+	WCD_MBHC_ADC_RESULT,
+	WCD_MBHC_MICB2_VOUT,
+	WCD_MBHC_ADC_MODE,
+	WCD_MBHC_DETECTION_DONE,
+	WCD_MBHC_ELECT_ISRC_EN,
+	WCD_MBHC_REG_FUNC_MAX,
+};
+
+enum wcd_mbhc_plug_type {
+	MBHC_PLUG_TYPE_INVALID = -1,
+	MBHC_PLUG_TYPE_NONE,
+	MBHC_PLUG_TYPE_HEADSET,
+	MBHC_PLUG_TYPE_HEADPHONE,
+	MBHC_PLUG_TYPE_HIGH_HPH,
+	MBHC_PLUG_TYPE_GND_MIC_SWAP,
+	MBHC_PLUG_TYPE_ANC_HEADPHONE,
+};
+
+enum pa_dac_ack_flags {
+	WCD_MBHC_HPHL_PA_OFF_ACK = 0,
+	WCD_MBHC_HPHR_PA_OFF_ACK,
+};
+
+enum anc_ack_flags {
+	WCD_MBHC_ANC0_OFF_ACK = 0,
+	WCD_MBHC_ANC1_OFF_ACK,
+};
+
+enum wcd_mbhc_btn_det_mem {
+	WCD_MBHC_BTN_DET_V_BTN_LOW,
+	WCD_MBHC_BTN_DET_V_BTN_HIGH
+};
+
+enum {
+	MIC_BIAS_1 = 1,
+	MIC_BIAS_2,
+	MIC_BIAS_3,
+	MIC_BIAS_4
+};
+
+enum {
+	MICB_PULLUP_ENABLE,
+	MICB_PULLUP_DISABLE,
+	MICB_ENABLE,
+	MICB_DISABLE,
+};
+
+enum {
+	MBHC_COMMON_MICB_PRECHARGE,
+	MBHC_COMMON_MICB_SET_VAL,
+	MBHC_COMMON_MICB_TAIL_CURR,
+};
+
+enum wcd_notify_event {
+	WCD_EVENT_INVALID,
+	/* events for micbias ON and OFF */
+	WCD_EVENT_PRE_MICBIAS_2_OFF,
+	WCD_EVENT_POST_MICBIAS_2_OFF,
+	WCD_EVENT_PRE_MICBIAS_2_ON,
+	WCD_EVENT_POST_MICBIAS_2_ON,
+	WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF,
+	WCD_EVENT_POST_DAPM_MICBIAS_2_OFF,
+	WCD_EVENT_PRE_DAPM_MICBIAS_2_ON,
+	WCD_EVENT_POST_DAPM_MICBIAS_2_ON,
+	/* events for PA ON and OFF */
+	WCD_EVENT_PRE_HPHL_PA_ON,
+	WCD_EVENT_POST_HPHL_PA_OFF,
+	WCD_EVENT_PRE_HPHR_PA_ON,
+	WCD_EVENT_POST_HPHR_PA_OFF,
+	WCD_EVENT_PRE_HPHL_PA_OFF,
+	WCD_EVENT_PRE_HPHR_PA_OFF,
+	WCD_EVENT_OCP_OFF,
+	WCD_EVENT_OCP_ON,
+	WCD_EVENT_LAST,
+};
+
+enum wcd_mbhc_event_state {
+	WCD_MBHC_EVENT_PA_HPHL,
+	WCD_MBHC_EVENT_PA_HPHR,
+};
+
+struct wcd_mbhc_general_cfg {
+	u8 t_ldoh;
+	u8 t_bg_fast_settle;
+	u8 t_shutdown_plug_rem;
+	u8 mbhc_nsa;
+	u8 mbhc_navg;
+	u8 v_micbias_l;
+	u8 v_micbias;
+	u8 mbhc_reserved;
+	u16 settle_wait;
+	u16 t_micbias_rampup;
+	u16 t_micbias_rampdown;
+	u16 t_supply_bringup;
+} __packed;
+
+struct wcd_mbhc_plug_detect_cfg {
+	u32 mic_current;
+	u32 hph_current;
+	u16 t_mic_pid;
+	u16 t_ins_complete;
+	u16 t_ins_retry;
+	u16 v_removal_delta;
+	u8 micbias_slow_ramp;
+	u8 reserved0;
+	u8 reserved1;
+	u8 reserved2;
+} __packed;
+
+struct wcd_mbhc_plug_type_cfg {
+	u8 av_detect;
+	u8 mono_detect;
+	u8 num_ins_tries;
+	u8 reserved0;
+	s16 v_no_mic;
+	s16 v_av_min;
+	s16 v_av_max;
+	s16 v_hs_min;
+	s16 v_hs_max;
+	u16 reserved1;
+} __packed;
+
+struct wcd_mbhc_btn_detect_cfg {
+	s8 c[8];
+	u8 nc;
+	u8 n_meas;
+	u8 mbhc_nsc;
+	u8 n_btn_meas;
+	u8 n_btn_con;
+	u8 num_btn;
+	u8 reserved0;
+	u8 reserved1;
+	u16 t_poll;
+	u16 t_bounce_wait;
+	u16 t_rel_timeout;
+	s16 v_btn_press_delta_sta;
+	s16 v_btn_press_delta_cic;
+	u16 t_btn0_timeout;
+	s16 _v_btn_low[0]; /* v_btn_low[num_btn] */
+	s16 _v_btn_high[0]; /* v_btn_high[num_btn] */
+	u8 _n_ready[2];
+	u8 _n_cic[2];
+	u8 _gain[2];
+} __packed;
+
+struct wcd_mbhc_imped_detect_cfg {
+	u8 _hs_imped_detect;
+	u8 _n_rload;
+	u8 _hph_keep_on;
+	u8 _repeat_rload_calc;
+	u16 _t_dac_ramp_time;
+	u16 _rhph_high;
+	u16 _rhph_low;
+	u16 _rload[0]; /* rload[n_rload] */
+	u16 _alpha[0]; /* alpha[n_rload] */
+	u16 _beta[3];
+} __packed;
+
+enum wcd_mbhc_hph_type {
+	WCD_MBHC_HPH_NONE = 0,
+	WCD_MBHC_HPH_MONO,
+	WCD_MBHC_HPH_STEREO,
+};
+
+/*
+ * These enum definitions are directly mapped to the register
+ * definitions
+ */
+enum mbhc_moisture_vref {
+	V_OFF,
+	V_45_MV,
+	V_100_MV,
+	V_225_MV,
+};
+
+enum mbhc_hs_pullup_iref {
+	I_DEFAULT = -1,
+	I_OFF = 0,
+	I_1P0_UA,
+	I_2P0_UA,
+	I_3P0_UA,
+};
+
+enum mbhc_moisture_rref {
+	R_OFF,
+	R_24_KOHM,
+	R_84_KOHM,
+	R_184_KOHM,
+};
+
+struct usbc_ana_audio_config {
+	int usbc_en1_gpio;
+	int usbc_en2_gpio;
+	int usbc_force_gpio;
+	struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */
+	struct device_node *usbc_en2_gpio_p; /* used by pinctrl API */
+	struct device_node *usbc_force_gpio_p; /* used by pinctrl API */
+};
+
+struct wcd_mbhc_config {
+	bool read_fw_bin;
+	void *calibration;
+	bool detect_extn_cable;
+	bool mono_stero_detection;
+	bool (*swap_gnd_mic)(struct snd_soc_codec *codec, bool active);
+	bool hs_ext_micbias;
+	bool gnd_det_en;
+	int key_code[WCD_MBHC_KEYCODE_NUM];
+	uint32_t linein_th;
+	bool moisture_en;
+	int mbhc_micbias;
+	int anc_micbias;
+	bool enable_anc_mic_detect;
+	u32 enable_usbc_analog;
+	struct usbc_ana_audio_config usbc_analog_cfg;
+};
+
+struct wcd_mbhc_intr {
+	int mbhc_sw_intr;
+	int mbhc_btn_press_intr;
+	int mbhc_btn_release_intr;
+	int mbhc_hs_ins_intr;
+	int mbhc_hs_rem_intr;
+	int hph_left_ocp;
+	int hph_right_ocp;
+};
+
+struct wcd_mbhc_register {
+	const char *id;
+	u16 reg;
+	u8 mask;
+	u8 offset;
+	u8 invert;
+};
+
+struct wcd_mbhc_cb {
+	int (*enable_mb_source)(struct wcd_mbhc *, bool);
+	void (*trim_btn_reg)(struct snd_soc_codec *);
+	void (*compute_impedance)(struct wcd_mbhc *, uint32_t *, uint32_t *);
+	void (*set_micbias_value)(struct snd_soc_codec *);
+	void (*set_auto_zeroing)(struct snd_soc_codec *, bool);
+	struct firmware_cal * (*get_hwdep_fw_cal)(struct wcd_mbhc *,
+			enum wcd_cal_type);
+	void (*set_cap_mode)(struct snd_soc_codec *, bool, bool);
+	int (*register_notifier)(struct wcd_mbhc *,
+				 struct notifier_block *nblock,
+				 bool enable);
+	int (*request_irq)(struct snd_soc_codec *,
+			int, irq_handler_t, const char *, void *);
+	void (*irq_control)(struct snd_soc_codec *,
+			int irq, bool enable);
+	int (*free_irq)(struct snd_soc_codec *,
+			int irq, void *);
+	void (*clk_setup)(struct snd_soc_codec *, bool);
+	int (*map_btn_code_to_num)(struct snd_soc_codec *);
+	bool (*lock_sleep)(struct wcd_mbhc *, bool);
+	bool (*micbias_enable_status)(struct wcd_mbhc *, int);
+	void (*mbhc_bias)(struct snd_soc_codec *, bool);
+	void (*mbhc_common_micb_ctrl)(struct snd_soc_codec *,
+				      int event, bool);
+	void (*micb_internal)(struct snd_soc_codec *,
+			int micb_num, bool);
+	bool (*hph_pa_on_status)(struct snd_soc_codec *);
+	void (*set_btn_thr)(struct snd_soc_codec *, s16 *, s16 *,
+			    int num_btn, bool);
+	void (*hph_pull_up_control)(struct snd_soc_codec *,
+				    enum mbhc_hs_pullup_iref);
+	int (*mbhc_micbias_control)(struct snd_soc_codec *, int, int req);
+	void (*mbhc_micb_ramp_control)(struct snd_soc_codec *, bool);
+	void (*skip_imped_detect)(struct snd_soc_codec *);
+	bool (*extn_use_mb)(struct snd_soc_codec *);
+	int (*mbhc_micb_ctrl_thr_mic)(struct snd_soc_codec *, int, bool);
+	void (*mbhc_gnd_det_ctrl)(struct snd_soc_codec *, bool);
+	void (*hph_pull_down_ctrl)(struct snd_soc_codec *, bool);
+	void (*mbhc_moisture_config)(struct wcd_mbhc *);
+	bool (*hph_register_recovery)(struct wcd_mbhc *);
+	void (*update_anc_state)(struct snd_soc_codec *codec,
+				 bool enable, int anc_num);
+	bool (*is_anc_on)(struct wcd_mbhc *mbhc);
+};
+
+struct wcd_mbhc_fn {
+	irqreturn_t (*wcd_mbhc_hs_ins_irq)(int irq, void *data);
+	irqreturn_t (*wcd_mbhc_hs_rem_irq)(int irq, void *data);
+	void (*wcd_mbhc_detect_plug_type)(struct wcd_mbhc *mbhc);
+	bool (*wcd_mbhc_detect_anc_plug_type)(struct wcd_mbhc *mbhc);
+	void (*wcd_cancel_hs_detect_plug)(struct wcd_mbhc *mbhc,
+					  struct work_struct *work);
+};
+
+struct wcd_mbhc {
+	/* Delayed work to report long button press */
+	struct delayed_work mbhc_btn_dwork;
+	int buttons_pressed;
+	struct wcd_mbhc_config *mbhc_cfg;
+	const struct wcd_mbhc_cb *mbhc_cb;
+
+	u32 hph_status; /* track headhpone status */
+	u8 hphlocp_cnt; /* headphone left ocp retry */
+	u8 hphrocp_cnt; /* headphone right ocp retry */
+
+	wait_queue_head_t wait_btn_press;
+	bool is_btn_press;
+	u8 current_plug;
+	bool in_swch_irq_handler;
+	bool hphl_swh; /*track HPHL switch NC / NO */
+	bool gnd_swh; /*track GND switch NC / NO */
+	u32 moist_vref;
+	u32 moist_iref;
+	u32 moist_rref;
+	u8 micbias1_cap_mode; /* track ext cap setting */
+	u8 micbias2_cap_mode; /* track ext cap setting */
+	bool hs_detect_work_stop;
+	bool micbias_enable;
+	bool btn_press_intr;
+	bool is_hs_recording;
+	bool is_extn_cable;
+	bool skip_imped_detection;
+	bool is_btn_already_regd;
+	bool extn_cable_hph_rem;
+
+	struct snd_soc_codec *codec;
+	/* Work to perform MBHC Firmware Read */
+	struct delayed_work mbhc_firmware_dwork;
+	const struct firmware *mbhc_fw;
+	struct firmware_cal *mbhc_cal;
+
+	/* track PA/DAC state to sync with userspace */
+	unsigned long hph_pa_dac_state;
+	unsigned long hph_anc_state;
+	unsigned long event_state;
+	unsigned long jiffies_atreport;
+
+	/* impedance of hphl and hphr */
+	uint32_t zl, zr;
+	bool impedance_detect;
+
+	/* Holds type of Headset - Mono/Stereo */
+	enum wcd_mbhc_hph_type hph_type;
+
+	struct snd_soc_jack headset_jack;
+	struct snd_soc_jack button_jack;
+	struct mutex codec_resource_lock;
+
+	/* Holds codec specific interrupt mapping */
+	const struct wcd_mbhc_intr *intr_ids;
+
+	/* Work to correct accessory type */
+	struct work_struct correct_plug_swch;
+	struct notifier_block nblock;
+
+	struct wcd_mbhc_register *wcd_mbhc_regs;
+
+	struct completion btn_press_compl;
+	struct mutex hphl_pa_lock;
+	struct mutex hphr_pa_lock;
+
+	/* Holds mbhc detection method - ADC/Legacy */
+	unsigned int mbhc_detection_logic;
+
+	unsigned long intr_status;
+	bool is_hph_ocp_pending;
+
+	bool usbc_force_pr_mode;
+	int usbc_mode;
+	struct notifier_block psy_nb;
+	struct power_supply *usb_psy;
+	struct work_struct usbc_analog_work;
+
+	struct wcd_mbhc_fn *mbhc_fn;
+};
+
+void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
+				   enum wcd_mbhc_plug_type plug_type);
+void wcd_mbhc_hs_elec_irq(struct wcd_mbhc *mbhc, int irq_type, bool enable);
+void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc);
+bool wcd_swch_level_remove(struct wcd_mbhc *mbhc);
+void wcd_enable_curr_micbias(const struct wcd_mbhc *mbhc,
+			     const enum wcd_mbhc_cs_mb_en_flag cs_mb_en);
+void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc,
+			  struct snd_soc_jack *jack, int status, int mask);
+int wcd_cancel_btn_work(struct wcd_mbhc *mbhc);
+int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc);
+
+#endif /* __WCD_MBHC_V2_H__ */
diff --git a/asoc/codecs/wcd-spi-registers.h b/asoc/codecs/wcd-spi-registers.h
new file mode 100644
index 0000000..4e57969
--- /dev/null
+++ b/asoc/codecs/wcd-spi-registers.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD_SPI_REGISTERS_H__
+#define __WCD_SPI_REGISTERS_H__
+
+#include <linux/regmap.h>
+
+#define WCD_SPI_SLAVE_SANITY         (0x00)
+#define WCD_SPI_SLAVE_DEVICE_ID      (0x04)
+#define WCD_SPI_SLAVE_STATUS         (0x08)
+#define WCD_SPI_SLAVE_CONFIG         (0x0c)
+#define WCD_SPI_SLAVE_SW_RESET       (0x10)
+#define WCD_SPI_SLAVE_IRQ_STATUS     (0x14)
+#define WCD_SPI_SLAVE_IRQ_EN         (0x18)
+#define WCD_SPI_SLAVE_IRQ_CLR        (0x1c)
+#define WCD_SPI_SLAVE_IRQ_FORCE      (0x20)
+#define WCD_SPI_SLAVE_TX             (0x24)
+#define WCD_SPI_SLAVE_TEST_BUS_DATA  (0x2c)
+#define WCD_SPI_SLAVE_TEST_BUS_CTRL  (0x30)
+#define WCD_SPI_SLAVE_SW_RST_IRQ     (0x34)
+#define WCD_SPI_SLAVE_CHAR_CFG       (0x38)
+#define WCD_SPI_SLAVE_CHAR_DATA_MOSI (0x3c)
+#define WCD_SPI_SLAVE_CHAR_DATA_CS_N (0x40)
+#define WCD_SPI_SLAVE_CHAR_DATA_MISO (0x44)
+#define WCD_SPI_SLAVE_TRNS_BYTE_CNT  (0x4c)
+#define WCD_SPI_SLAVE_TRNS_LEN       (0x50)
+#define WCD_SPI_SLAVE_FIFO_LEVEL     (0x54)
+#define WCD_SPI_SLAVE_GENERICS       (0x58)
+#define WCD_SPI_SLAVE_EXT_BASE_ADDR  (0x5c)
+#define WCD_SPI_MAX_REGISTER         (0x5F)
+
+#endif /* End __WCD_SPI_REGISTERS_H__ */
diff --git a/asoc/codecs/wcd-spi.c b/asoc/codecs/wcd-spi.c
new file mode 100644
index 0000000..957d642
--- /dev/null
+++ b/asoc/codecs/wcd-spi.c
@@ -0,0 +1,1535 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/component.h>
+#include <linux/ratelimit.h>
+#include <sound/wcd-dsp-mgr.h>
+#include <sound/wcd-spi.h>
+#include "wcd-spi-registers.h"
+
+/* Byte manipulations */
+#define SHIFT_1_BYTES    (8)
+#define SHIFT_2_BYTES    (16)
+#define SHIFT_3_BYTES    (24)
+
+/* Command opcodes */
+#define WCD_SPI_CMD_NOP     (0x00)
+#define WCD_SPI_CMD_WREN    (0x06)
+#define WCD_SPI_CMD_CLKREQ  (0xDA)
+#define WCD_SPI_CMD_RDSR    (0x05)
+#define WCD_SPI_CMD_IRR     (0x81)
+#define WCD_SPI_CMD_IRW     (0x82)
+#define WCD_SPI_CMD_MIOR    (0x83)
+#define WCD_SPI_CMD_FREAD   (0x0B)
+#define WCD_SPI_CMD_MIOW    (0x02)
+#define WCD_SPI_WRITE_FRAME_OPCODE \
+	(WCD_SPI_CMD_MIOW << SHIFT_3_BYTES)
+#define WCD_SPI_READ_FRAME_OPCODE \
+	(WCD_SPI_CMD_MIOR << SHIFT_3_BYTES)
+#define WCD_SPI_FREAD_FRAME_OPCODE \
+	(WCD_SPI_CMD_FREAD << SHIFT_3_BYTES)
+
+/* Command lengths */
+#define WCD_SPI_OPCODE_LEN       (0x01)
+#define WCD_SPI_CMD_NOP_LEN      (0x01)
+#define WCD_SPI_CMD_WREN_LEN     (0x01)
+#define WCD_SPI_CMD_CLKREQ_LEN   (0x04)
+#define WCD_SPI_CMD_IRR_LEN      (0x04)
+#define WCD_SPI_CMD_IRW_LEN      (0x06)
+#define WCD_SPI_WRITE_SINGLE_LEN (0x08)
+#define WCD_SPI_READ_SINGLE_LEN  (0x13)
+#define WCD_SPI_CMD_FREAD_LEN    (0x13)
+
+/* Command delays */
+#define WCD_SPI_CLKREQ_DELAY_USECS (500)
+#define WCD_SPI_CLK_OFF_TIMER_MS   (500)
+#define WCD_SPI_RESUME_TIMEOUT_MS 100
+
+/* Command masks */
+#define WCD_CMD_ADDR_MASK            \
+	(0xFF |                      \
+	 (0xFF << SHIFT_1_BYTES) |   \
+	 (0xFF << SHIFT_2_BYTES))
+
+/* Clock ctrl request related */
+#define WCD_SPI_CLK_ENABLE true
+#define WCD_SPI_CLK_DISABLE false
+#define WCD_SPI_CLK_FLAG_DELAYED    (1 << 0)
+#define WCD_SPI_CLK_FLAG_IMMEDIATE  (1 << 1)
+
+/* Internal addresses */
+#define WCD_SPI_ADDR_IPC_CTL_HOST (0x012014)
+
+/* Word sizes and min/max lengths */
+#define WCD_SPI_WORD_BYTE_CNT (4)
+#define WCD_SPI_RW_MULTI_MIN_LEN (16)
+
+/* Max size is 32 bytes less than 64Kbytes */
+#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 32)
+
+/*
+ * Max size for the pre-allocated buffers is the max
+ * possible read/write length + 32 bytes for the SPI
+ * read/write command header itself.
+ */
+#define WCD_SPI_RW_MAX_BUF_SIZE (WCD_SPI_RW_MULTI_MAX_LEN + 32)
+
+/* Alignment requirements */
+#define WCD_SPI_RW_MIN_ALIGN    WCD_SPI_WORD_BYTE_CNT
+#define WCD_SPI_RW_MULTI_ALIGN  (16)
+
+/* Status mask bits */
+#define WCD_SPI_CLK_STATE_ENABLED BIT(0)
+#define WCD_SPI_IS_SUSPENDED BIT(1)
+
+/* Locking related */
+#define WCD_SPI_MUTEX_LOCK(spi, lock)              \
+{                                                  \
+	dev_vdbg(&spi->dev, "%s: mutex_lock(%s)\n", \
+		 __func__, __stringify_1(lock));    \
+	mutex_lock(&lock);                         \
+}
+
+#define WCD_SPI_MUTEX_UNLOCK(spi, lock)              \
+{                                                    \
+	dev_vdbg(&spi->dev, "%s: mutex_unlock(%s)\n", \
+		 __func__, __stringify_1(lock));      \
+	mutex_unlock(&lock);                         \
+}
+
+struct wcd_spi_debug_data {
+	struct dentry *dir;
+	u32 addr;
+	u32 size;
+};
+
+struct wcd_spi_priv {
+	struct spi_device *spi;
+	u32 mem_base_addr;
+
+	struct regmap *regmap;
+
+	/* Message for single transfer */
+	struct spi_message msg1;
+	struct spi_transfer xfer1;
+
+	/* Message for two transfers */
+	struct spi_message msg2;
+	struct spi_transfer xfer2[2];
+
+	/* Register access related */
+	u32 reg_bytes;
+	u32 val_bytes;
+
+	/* Clock requests related */
+	struct mutex clk_mutex;
+	int clk_users;
+	unsigned long status_mask;
+	struct delayed_work clk_dwork;
+
+	/* Transaction related */
+	struct mutex xfer_mutex;
+
+	struct device *m_dev;
+	struct wdsp_mgr_ops *m_ops;
+
+	/* Debugfs related information */
+	struct wcd_spi_debug_data debug_data;
+
+	/* Completion object to indicate system resume completion */
+	struct completion resume_comp;
+
+	/* Buffers to hold memory used for transfers */
+	void *tx_buf;
+	void *rx_buf;
+};
+
+enum xfer_request {
+	WCD_SPI_XFER_WRITE,
+	WCD_SPI_XFER_READ,
+};
+
+
+static char *wcd_spi_xfer_req_str(enum xfer_request req)
+{
+	if (req == WCD_SPI_XFER_WRITE)
+		return "xfer_write";
+	else if (req == WCD_SPI_XFER_READ)
+		return "xfer_read";
+	else
+		return "xfer_invalid";
+}
+
+static void wcd_spi_reinit_xfer(struct spi_transfer *xfer)
+{
+	xfer->tx_buf = NULL;
+	xfer->rx_buf = NULL;
+	xfer->delay_usecs = 0;
+	xfer->len = 0;
+}
+
+static bool wcd_spi_is_suspended(struct wcd_spi_priv *wcd_spi)
+{
+	return test_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+}
+
+static bool wcd_spi_can_suspend(struct wcd_spi_priv *wcd_spi)
+{
+	struct spi_device *spi = wcd_spi->spi;
+
+	if (wcd_spi->clk_users > 0 ||
+	    test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) {
+		dev_err(&spi->dev, "%s: cannot suspend, clk_users = %d\n",
+			__func__, wcd_spi->clk_users);
+		return false;
+	}
+
+	return true;
+}
+
+static int wcd_spi_wait_for_resume(struct wcd_spi_priv *wcd_spi)
+{
+	struct spi_device *spi = wcd_spi->spi;
+	int rc = 0;
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	/* If the system is already in resumed state, return right away */
+	if (!wcd_spi_is_suspended(wcd_spi))
+		goto done;
+
+	/* If suspended then wait for resume to happen */
+	reinit_completion(&wcd_spi->resume_comp);
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+	rc = wait_for_completion_timeout(&wcd_spi->resume_comp,
+				msecs_to_jiffies(WCD_SPI_RESUME_TIMEOUT_MS));
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	if (rc == 0) {
+		dev_err(&spi->dev, "%s: failed to resume in %u msec\n",
+			__func__, WCD_SPI_RESUME_TIMEOUT_MS);
+		rc = -EIO;
+		goto done;
+	}
+
+	dev_dbg(&spi->dev, "%s: resume successful\n", __func__);
+	rc = 0;
+done:
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+	return rc;
+}
+
+static int wcd_spi_read_single(struct spi_device *spi,
+			       u32 remote_addr, u32 *val)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
+	struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
+	u8 *tx_buf = wcd_spi->tx_buf;
+	u32 frame = 0;
+	int ret;
+
+	dev_dbg(&spi->dev, "%s: remote_addr = 0x%x\n",
+		__func__, remote_addr);
+
+	if (!tx_buf) {
+		dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	frame |= WCD_SPI_READ_FRAME_OPCODE;
+	frame |= remote_addr & WCD_CMD_ADDR_MASK;
+
+	wcd_spi_reinit_xfer(tx_xfer);
+	frame = cpu_to_be32(frame);
+	memcpy(tx_buf, &frame, sizeof(frame));
+	tx_xfer->tx_buf = tx_buf;
+	tx_xfer->len = WCD_SPI_READ_SINGLE_LEN;
+
+	wcd_spi_reinit_xfer(rx_xfer);
+	rx_xfer->rx_buf = val;
+	rx_xfer->len = sizeof(*val);
+
+	ret = spi_sync(spi, &wcd_spi->msg2);
+
+	return ret;
+}
+
+static int wcd_spi_read_multi(struct spi_device *spi,
+			      u32 remote_addr, u8 *data,
+			      size_t len)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct spi_transfer *xfer = &wcd_spi->xfer1;
+	u8 *tx_buf = wcd_spi->tx_buf;
+	u8 *rx_buf = wcd_spi->rx_buf;
+	u32 frame = 0;
+	int ret;
+
+	dev_dbg(&spi->dev,  "%s: addr 0x%x, len = %zd\n",
+		__func__, remote_addr, len);
+
+	frame |= WCD_SPI_FREAD_FRAME_OPCODE;
+	frame |= remote_addr & WCD_CMD_ADDR_MASK;
+
+	if (!tx_buf || !rx_buf) {
+		dev_err(&spi->dev, "%s: %s not allocated\n", __func__,
+			(!tx_buf) ? "tx_buf" : "rx_buf");
+		return -ENOMEM;
+	}
+
+	wcd_spi_reinit_xfer(xfer);
+	frame = cpu_to_be32(frame);
+	memcpy(tx_buf, &frame, sizeof(frame));
+	xfer->tx_buf = tx_buf;
+	xfer->rx_buf = rx_buf;
+	xfer->len = WCD_SPI_CMD_FREAD_LEN + len;
+
+	ret = spi_sync(spi, &wcd_spi->msg1);
+	if (ret) {
+		dev_err(&spi->dev, "%s: failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	memcpy(data, rx_buf + WCD_SPI_CMD_FREAD_LEN, len);
+done:
+	return ret;
+}
+
+static int wcd_spi_write_single(struct spi_device *spi,
+				u32 remote_addr, u32 val)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct spi_transfer *xfer = &wcd_spi->xfer1;
+	u8 buf[WCD_SPI_WRITE_SINGLE_LEN];
+	u32 frame = 0;
+
+	dev_dbg(&spi->dev, "%s: remote_addr = 0x%x, val = 0x%x\n",
+		__func__, remote_addr, val);
+
+	memset(buf, 0, WCD_SPI_WRITE_SINGLE_LEN);
+	frame |= WCD_SPI_WRITE_FRAME_OPCODE;
+	frame |= (remote_addr & WCD_CMD_ADDR_MASK);
+
+	frame = cpu_to_be32(frame);
+	memcpy(buf, &frame, sizeof(frame));
+	memcpy(buf + sizeof(frame), &val, sizeof(val));
+
+	wcd_spi_reinit_xfer(xfer);
+	xfer->tx_buf = buf;
+	xfer->len = WCD_SPI_WRITE_SINGLE_LEN;
+
+	return spi_sync(spi, &wcd_spi->msg1);
+}
+
+static int wcd_spi_write_multi(struct spi_device *spi,
+			       u32 remote_addr, u8 *data,
+			       size_t len)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct spi_transfer *xfer = &wcd_spi->xfer1;
+	u32 frame = 0;
+	u8 *tx_buf = wcd_spi->tx_buf;
+	int xfer_len, ret;
+
+	dev_dbg(&spi->dev, "%s: addr = 0x%x len = %zd\n",
+		__func__, remote_addr, len);
+
+	frame |= WCD_SPI_WRITE_FRAME_OPCODE;
+	frame |= (remote_addr & WCD_CMD_ADDR_MASK);
+
+	frame = cpu_to_be32(frame);
+	xfer_len = len + sizeof(frame);
+
+	if (!tx_buf) {
+		dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	memcpy(tx_buf, &frame, sizeof(frame));
+	memcpy(tx_buf + sizeof(frame), data, len);
+
+	wcd_spi_reinit_xfer(xfer);
+	xfer->tx_buf = tx_buf;
+	xfer->len = xfer_len;
+
+	ret = spi_sync(spi, &wcd_spi->msg1);
+	if (ret < 0)
+		dev_err(&spi->dev,
+			"%s: Failed, addr = 0x%x, len = %zd\n",
+			__func__, remote_addr, len);
+	return ret;
+}
+
+static int wcd_spi_transfer_split(struct spi_device *spi,
+				  struct wcd_spi_msg *data_msg,
+				  enum xfer_request xfer_req)
+{
+	u32 addr = data_msg->remote_addr;
+	u8 *data = data_msg->data;
+	int remain_size = data_msg->len;
+	int to_xfer, loop_cnt, ret = 0;
+
+	/* Perform single writes until multi word alignment is met */
+	loop_cnt = 1;
+	while (remain_size &&
+	       !IS_ALIGNED(addr, WCD_SPI_RW_MULTI_ALIGN)) {
+		if (xfer_req == WCD_SPI_XFER_WRITE)
+			ret = wcd_spi_write_single(spi, addr,
+						   (*(u32 *)data));
+		else
+			ret = wcd_spi_read_single(spi, addr,
+						  (u32 *)data);
+		if (ret < 0) {
+			dev_err(&spi->dev,
+				"%s: %s fail iter(%d) start-word addr (0x%x)\n",
+				__func__, wcd_spi_xfer_req_str(xfer_req),
+				loop_cnt, addr);
+			goto done;
+		}
+
+		addr += WCD_SPI_WORD_BYTE_CNT;
+		data += WCD_SPI_WORD_BYTE_CNT;
+		remain_size -= WCD_SPI_WORD_BYTE_CNT;
+		loop_cnt++;
+	}
+
+	/* Perform multi writes for max allowed multi writes */
+	loop_cnt = 1;
+	while (remain_size >= WCD_SPI_RW_MULTI_MAX_LEN) {
+		if (xfer_req == WCD_SPI_XFER_WRITE)
+			ret = wcd_spi_write_multi(spi, addr, data,
+						  WCD_SPI_RW_MULTI_MAX_LEN);
+		else
+			ret = wcd_spi_read_multi(spi, addr, data,
+						 WCD_SPI_RW_MULTI_MAX_LEN);
+		if (ret < 0) {
+			dev_err(&spi->dev,
+				"%s: %s fail iter(%d) max-write addr (0x%x)\n",
+				__func__, wcd_spi_xfer_req_str(xfer_req),
+				loop_cnt, addr);
+			goto done;
+		}
+
+		addr += WCD_SPI_RW_MULTI_MAX_LEN;
+		data += WCD_SPI_RW_MULTI_MAX_LEN;
+		remain_size -= WCD_SPI_RW_MULTI_MAX_LEN;
+		loop_cnt++;
+	}
+
+	/*
+	 * Perform write for max possible data that is multiple
+	 * of the minimum size for multi-write commands.
+	 */
+	to_xfer = remain_size - (remain_size % WCD_SPI_RW_MULTI_MIN_LEN);
+	if (remain_size >= WCD_SPI_RW_MULTI_MIN_LEN &&
+	    to_xfer > 0) {
+		if (xfer_req == WCD_SPI_XFER_WRITE)
+			ret = wcd_spi_write_multi(spi, addr, data, to_xfer);
+		else
+			ret = wcd_spi_read_multi(spi, addr, data, to_xfer);
+		if (ret < 0) {
+			dev_err(&spi->dev,
+				"%s: %s fail write addr (0x%x), size (0x%x)\n",
+				__func__, wcd_spi_xfer_req_str(xfer_req),
+				addr, to_xfer);
+			goto done;
+		}
+
+		addr += to_xfer;
+		data += to_xfer;
+		remain_size -= to_xfer;
+	}
+
+	/* Perform single writes for the last remaining data */
+	loop_cnt = 1;
+	while (remain_size > 0) {
+		if (xfer_req == WCD_SPI_XFER_WRITE)
+			ret = wcd_spi_write_single(spi, addr, (*((u32 *)data)));
+		else
+			ret = wcd_spi_read_single(spi, addr,  (u32 *) data);
+		if (ret < 0) {
+			dev_err(&spi->dev,
+				"%s: %s fail iter(%d) end-write addr (0x%x)\n",
+				__func__, wcd_spi_xfer_req_str(xfer_req),
+				loop_cnt, addr);
+			goto done;
+		}
+
+		addr += WCD_SPI_WORD_BYTE_CNT;
+		data += WCD_SPI_WORD_BYTE_CNT;
+		remain_size -= WCD_SPI_WORD_BYTE_CNT;
+		loop_cnt++;
+	}
+
+done:
+	return ret;
+}
+
+static int wcd_spi_cmd_nop(struct spi_device *spi)
+{
+	u8 nop = WCD_SPI_CMD_NOP;
+
+	return spi_write(spi, &nop, WCD_SPI_CMD_NOP_LEN);
+}
+
+static int wcd_spi_cmd_clkreq(struct spi_device *spi)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct spi_transfer *xfer = &wcd_spi->xfer1;
+	u8 cmd[WCD_SPI_CMD_CLKREQ_LEN] = {
+		WCD_SPI_CMD_CLKREQ,
+		0xBA, 0x80, 0x00};
+
+	wcd_spi_reinit_xfer(xfer);
+	xfer->tx_buf = cmd;
+	xfer->len = WCD_SPI_CMD_CLKREQ_LEN;
+	xfer->delay_usecs = WCD_SPI_CLKREQ_DELAY_USECS;
+
+	return spi_sync(spi, &wcd_spi->msg1);
+}
+
+static int wcd_spi_cmd_wr_en(struct spi_device *spi)
+{
+	u8 wr_en = WCD_SPI_CMD_WREN;
+
+	return spi_write(spi, &wr_en, WCD_SPI_CMD_WREN_LEN);
+}
+
+static int wcd_spi_cmd_rdsr(struct spi_device *spi,
+			    u32 *rdsr_status)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
+	struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
+	u8 rdsr_cmd;
+	u32 status;
+	int ret;
+
+	rdsr_cmd = WCD_SPI_CMD_RDSR;
+	wcd_spi_reinit_xfer(tx_xfer);
+	tx_xfer->tx_buf = &rdsr_cmd;
+	tx_xfer->len = sizeof(rdsr_cmd);
+
+
+	wcd_spi_reinit_xfer(rx_xfer);
+	rx_xfer->rx_buf = &status;
+	rx_xfer->len = sizeof(status);
+
+	ret = spi_sync(spi, &wcd_spi->msg2);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: RDSR failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	*rdsr_status = be32_to_cpu(status);
+
+	dev_dbg(&spi->dev, "%s: RDSR success, value = 0x%x\n",
+		 __func__, *rdsr_status);
+done:
+	return ret;
+}
+
+static int wcd_spi_clk_enable(struct spi_device *spi)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int ret;
+	u32 rd_status = 0;
+
+	ret = wcd_spi_cmd_nop(spi);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: NOP1 failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	ret = wcd_spi_cmd_clkreq(spi);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: CLK_REQ failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	ret = wcd_spi_cmd_nop(spi);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: NOP2 failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+	wcd_spi_cmd_rdsr(spi, &rd_status);
+	/*
+	 * Read status zero means reads are not
+	 * happenning on the bus, possibly because
+	 * clock request failed.
+	 */
+	if (rd_status) {
+		set_bit(WCD_SPI_CLK_STATE_ENABLED,
+			&wcd_spi->status_mask);
+	} else {
+		dev_err(&spi->dev, "%s: RDSR status is zero\n",
+			__func__);
+		ret = -EIO;
+	}
+done:
+	return ret;
+}
+
+static int wcd_spi_clk_disable(struct spi_device *spi)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int ret;
+
+	ret = wcd_spi_write_single(spi, WCD_SPI_ADDR_IPC_CTL_HOST, 0x01);
+	if (ret < 0)
+		dev_err(&spi->dev, "%s: Failed, err = %d\n",
+			__func__, ret);
+	else
+		clear_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask);
+
+	return ret;
+}
+
+static int wcd_spi_clk_ctrl(struct spi_device *spi,
+			    bool request, u32 flags)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int ret = 0;
+	const char *delay_str;
+
+	delay_str = (flags == WCD_SPI_CLK_FLAG_DELAYED) ?
+		    "delayed" : "immediate";
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+
+	/* Reject any unbalanced disable request */
+	if (wcd_spi->clk_users < 0 ||
+	    (!request && wcd_spi->clk_users == 0)) {
+		dev_err(&spi->dev, "%s: Unbalanced clk_users %d for %s\n",
+			 __func__, wcd_spi->clk_users,
+			request ? "enable" : "disable");
+		ret = -EINVAL;
+
+		/* Reset the clk_users to 0 */
+		wcd_spi->clk_users = 0;
+
+		goto done;
+	}
+
+	if (request == WCD_SPI_CLK_ENABLE) {
+		/*
+		 * If the SPI bus is suspended, then return error
+		 * as the transaction cannot be completed.
+		 */
+		if (wcd_spi_is_suspended(wcd_spi)) {
+			dev_err(&spi->dev,
+				"%s: SPI suspended, cannot enable clk\n",
+				__func__);
+			ret = -EIO;
+			goto done;
+		}
+
+		/* Cancel the disable clk work */
+		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+		cancel_delayed_work_sync(&wcd_spi->clk_dwork);
+		WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+
+		wcd_spi->clk_users++;
+
+		/*
+		 * If clk state is already set,
+		 * then clk wasnt really disabled
+		 */
+		if (test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask))
+			goto done;
+		else if (wcd_spi->clk_users == 1)
+			ret = wcd_spi_clk_enable(spi);
+
+	} else {
+		wcd_spi->clk_users--;
+
+		/* Clock is still voted for */
+		if (wcd_spi->clk_users > 0)
+			goto done;
+
+		/*
+		 * If we are here, clk_users must be 0 and needs
+		 * to be disabled. Call the disable based on the
+		 * flags.
+		 */
+		if (flags == WCD_SPI_CLK_FLAG_DELAYED) {
+			schedule_delayed_work(&wcd_spi->clk_dwork,
+				msecs_to_jiffies(WCD_SPI_CLK_OFF_TIMER_MS));
+		} else {
+			ret = wcd_spi_clk_disable(spi);
+			if (ret < 0)
+				dev_err(&spi->dev,
+					"%s: Failed to disable clk err = %d\n",
+					__func__, ret);
+		}
+	}
+
+done:
+	dev_dbg(&spi->dev, "%s: updated clk_users = %d, request_%s %s\n",
+		__func__, wcd_spi->clk_users, request ? "enable" : "disable",
+		request ? "" : delay_str);
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+
+	return ret;
+}
+
+static int wcd_spi_init(struct spi_device *spi)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int ret;
+
+	ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE,
+			       WCD_SPI_CLK_FLAG_IMMEDIATE);
+	if (ret < 0)
+		goto done;
+
+	ret = wcd_spi_cmd_wr_en(spi);
+	if (ret < 0)
+		goto err_wr_en;
+
+	/*
+	 * In case spi_init is called after component deinit,
+	 * it is possible hardware register state is also reset.
+	 * Sync the regcache here so hardware state is updated
+	 * to reflect the cache.
+	 */
+	regcache_sync(wcd_spi->regmap);
+
+	regmap_write(wcd_spi->regmap, WCD_SPI_SLAVE_CONFIG,
+		     0x0F3D0800);
+
+	/* Write the MTU to max allowed size */
+	regmap_update_bits(wcd_spi->regmap,
+			   WCD_SPI_SLAVE_TRNS_LEN,
+			   0xFFFF0000, 0xFFFF0000);
+err_wr_en:
+	wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE,
+			 WCD_SPI_CLK_FLAG_IMMEDIATE);
+done:
+	return ret;
+}
+
+static void wcd_spi_clk_work(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct wcd_spi_priv *wcd_spi;
+	struct spi_device *spi;
+	int ret;
+
+	dwork = to_delayed_work(work);
+	wcd_spi = container_of(dwork, struct wcd_spi_priv, clk_dwork);
+	spi = wcd_spi->spi;
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	ret = wcd_spi_clk_disable(spi);
+	if (ret < 0)
+		dev_err(&spi->dev,
+			"%s: Failed to disable clk, err = %d\n",
+			__func__, ret);
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+}
+
+static int __wcd_spi_data_xfer(struct spi_device *spi,
+			       struct wcd_spi_msg *msg,
+			       enum xfer_request xfer_req)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int ret;
+
+	/* Check for minimum alignment requirements */
+	if (!IS_ALIGNED(msg->remote_addr, WCD_SPI_RW_MIN_ALIGN)) {
+		dev_err(&spi->dev,
+			"%s addr 0x%x is not aligned to 0x%x\n",
+			__func__, msg->remote_addr, WCD_SPI_RW_MIN_ALIGN);
+		return -EINVAL;
+	} else if (msg->len % WCD_SPI_WORD_BYTE_CNT) {
+		dev_err(&spi->dev,
+			"%s len 0x%zx is not multiple of %d\n",
+			__func__, msg->len, WCD_SPI_WORD_BYTE_CNT);
+		return -EINVAL;
+	}
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->xfer_mutex);
+	if (msg->len == WCD_SPI_WORD_BYTE_CNT) {
+		if (xfer_req == WCD_SPI_XFER_WRITE)
+			ret = wcd_spi_write_single(spi, msg->remote_addr,
+						   (*((u32 *)msg->data)));
+		else
+			ret = wcd_spi_read_single(spi, msg->remote_addr,
+						  (u32 *) msg->data);
+	} else {
+		ret = wcd_spi_transfer_split(spi, msg, xfer_req);
+	}
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->xfer_mutex);
+
+	return ret;
+}
+
+static int wcd_spi_data_xfer(struct spi_device *spi,
+			     struct wcd_spi_msg *msg,
+			     enum xfer_request req)
+{
+	int ret, ret1;
+
+	if (msg->len <= 0) {
+		dev_err(&spi->dev, "%s: Invalid size %zd\n",
+			__func__, msg->len);
+		return -EINVAL;
+	}
+
+	/* Request for clock */
+	ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE,
+			       WCD_SPI_CLK_FLAG_IMMEDIATE);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: clk enable failed %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	/* Perform the transaction */
+	ret = __wcd_spi_data_xfer(spi, msg, req);
+	if (ret < 0)
+		dev_err(&spi->dev,
+			"%s: Failed %s, addr = 0x%x, size = 0x%zx, err = %d\n",
+			__func__, wcd_spi_xfer_req_str(req),
+			msg->remote_addr, msg->len, ret);
+
+	/* Release the clock even if xfer failed */
+	ret1 = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE,
+				WCD_SPI_CLK_FLAG_DELAYED);
+	if (ret1 < 0)
+		dev_err(&spi->dev, "%s: clk disable failed %d\n",
+			__func__, ret1);
+done:
+	return ret;
+}
+
+/*
+ * wcd_spi_data_write: Write data to WCD SPI
+ * @spi: spi_device struct
+ * @msg: msg that needs to be written to WCD
+ *
+ * This API writes length of data to address specified. These details
+ * about the write are encapsulated in @msg. Write size should be multiple
+ * of 4 bytes and write address should be 4-byte aligned.
+ */
+static int wcd_spi_data_write(struct spi_device *spi,
+		       struct wcd_spi_msg *msg)
+{
+	if (!spi || !msg) {
+		pr_err("%s: Invalid %s\n", __func__,
+			(!spi) ? "spi device" : "msg");
+		return -EINVAL;
+	}
+
+	dev_dbg_ratelimited(&spi->dev, "%s: addr = 0x%x, len = %zu\n",
+			    __func__, msg->remote_addr, msg->len);
+	return wcd_spi_data_xfer(spi, msg, WCD_SPI_XFER_WRITE);
+}
+
+/*
+ * wcd_spi_data_read: Read data from WCD SPI
+ * @spi: spi_device struct
+ * @msg: msg that needs to be read from WCD
+ *
+ * This API reads length of data from address specified. These details
+ * about the read are encapsulated in @msg. Read size should be multiple
+ * of 4 bytes and read address should be 4-byte aligned.
+ */
+static int wcd_spi_data_read(struct spi_device *spi,
+		      struct wcd_spi_msg *msg)
+{
+	if (!spi || !msg) {
+		pr_err("%s: Invalid %s\n", __func__,
+			(!spi) ? "spi device" : "msg");
+		return -EINVAL;
+	}
+
+	dev_dbg_ratelimited(&spi->dev, "%s: addr = 0x%x,len = %zu\n",
+			    __func__, msg->remote_addr, msg->len);
+	return wcd_spi_data_xfer(spi, msg, WCD_SPI_XFER_READ);
+}
+
+static int wdsp_spi_dload_section(struct spi_device *spi,
+				  void *data)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct wdsp_img_section *sec = data;
+	struct wcd_spi_msg msg;
+	int ret;
+
+	dev_dbg(&spi->dev, "%s: addr = 0x%x, size = 0x%zx\n",
+		__func__, sec->addr, sec->size);
+
+	msg.remote_addr = sec->addr + wcd_spi->mem_base_addr;
+	msg.data = sec->data;
+	msg.len = sec->size;
+
+	ret = __wcd_spi_data_xfer(spi, &msg, WCD_SPI_XFER_WRITE);
+	if (ret < 0)
+		dev_err(&spi->dev, "%s: fail addr (0x%x) size (0x%zx)\n",
+			__func__, msg.remote_addr, msg.len);
+	return ret;
+}
+
+static int wdsp_spi_read_section(struct spi_device *spi, void *data)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct wdsp_img_section *sec = data;
+	struct wcd_spi_msg msg;
+	int ret;
+
+	msg.remote_addr = sec->addr + wcd_spi->mem_base_addr;
+	msg.data = sec->data;
+	msg.len = sec->size;
+
+	dev_dbg(&spi->dev, "%s: addr = 0x%x, size = 0x%zx\n",
+		__func__, msg.remote_addr, msg.len);
+
+	ret = wcd_spi_data_xfer(spi, &msg, WCD_SPI_XFER_READ);
+	if (ret < 0)
+		dev_err(&spi->dev, "%s: fail addr (0x%x) size (0x%zx)\n",
+			__func__, msg.remote_addr, msg.len);
+	return ret;
+}
+
+static int wdsp_spi_event_handler(struct device *dev, void *priv_data,
+				  enum wdsp_event_type event,
+				  void *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct wcd_spi_ops *spi_ops;
+	int ret = 0;
+
+	dev_dbg(&spi->dev, "%s: event type %d\n",
+		__func__, event);
+
+	switch (event) {
+	case WDSP_EVENT_POST_SHUTDOWN:
+		cancel_delayed_work_sync(&wcd_spi->clk_dwork);
+		WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+		if (test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask))
+			wcd_spi_clk_disable(spi);
+		wcd_spi->clk_users = 0;
+		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+		break;
+
+	case WDSP_EVENT_PRE_DLOAD_CODE:
+	case WDSP_EVENT_PRE_DLOAD_DATA:
+		ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE,
+				       WCD_SPI_CLK_FLAG_IMMEDIATE);
+		if (ret < 0)
+			dev_err(&spi->dev, "%s: clk_req failed %d\n",
+				__func__, ret);
+		break;
+
+	case WDSP_EVENT_POST_DLOAD_CODE:
+	case WDSP_EVENT_POST_DLOAD_DATA:
+	case WDSP_EVENT_DLOAD_FAILED:
+
+		ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE,
+				       WCD_SPI_CLK_FLAG_IMMEDIATE);
+		if (ret < 0)
+			dev_err(&spi->dev, "%s: clk unvote failed %d\n",
+				__func__, ret);
+		break;
+
+	case WDSP_EVENT_DLOAD_SECTION:
+		ret = wdsp_spi_dload_section(spi, data);
+		break;
+
+	case WDSP_EVENT_READ_SECTION:
+		ret = wdsp_spi_read_section(spi, data);
+		break;
+
+	case WDSP_EVENT_SUSPEND:
+		WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+		if (!wcd_spi_can_suspend(wcd_spi))
+			ret = -EBUSY;
+		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+		break;
+
+	case WDSP_EVENT_RESUME:
+		ret = wcd_spi_wait_for_resume(wcd_spi);
+		break;
+
+	case WDSP_EVENT_GET_DEVOPS:
+		if (!data) {
+			dev_err(&spi->dev, "%s: invalid data\n",
+				__func__);
+			ret = -EINVAL;
+			break;
+		}
+
+		spi_ops = (struct wcd_spi_ops *) data;
+		spi_ops->spi_dev = spi;
+		spi_ops->read_dev = wcd_spi_data_read;
+		spi_ops->write_dev = wcd_spi_data_write;
+		break;
+
+	default:
+		dev_dbg(&spi->dev, "%s: Unhandled event %d\n",
+			__func__, event);
+		break;
+	}
+
+	return ret;
+}
+
+static int wcd_spi_bus_gwrite(void *context, const void *reg,
+			      size_t reg_len, const void *val,
+			      size_t val_len)
+{
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	u8 tx_buf[WCD_SPI_CMD_IRW_LEN];
+
+	if (!reg || !val || reg_len != wcd_spi->reg_bytes ||
+	    val_len != wcd_spi->val_bytes) {
+		dev_err(&spi->dev,
+			"%s: Invalid input, reg_len = %zd, val_len = %zd",
+			__func__, reg_len, val_len);
+		return -EINVAL;
+	}
+
+	tx_buf[0] = WCD_SPI_CMD_IRW;
+	tx_buf[1] = *((u8 *)reg);
+	memcpy(&tx_buf[WCD_SPI_OPCODE_LEN + reg_len],
+	       val, val_len);
+
+	return spi_write(spi, tx_buf, WCD_SPI_CMD_IRW_LEN);
+}
+
+static int wcd_spi_bus_write(void *context, const void *data,
+			     size_t count)
+{
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+
+	if (count < (wcd_spi->reg_bytes + wcd_spi->val_bytes)) {
+		dev_err(&spi->dev, "%s: Invalid size %zd\n",
+			__func__, count);
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	return wcd_spi_bus_gwrite(context, data, wcd_spi->reg_bytes,
+				  data + wcd_spi->reg_bytes,
+				  count - wcd_spi->reg_bytes);
+}
+
+static int wcd_spi_bus_read(void *context, const void *reg,
+			    size_t reg_len, void *val,
+			    size_t val_len)
+{
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
+	struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
+	u8 tx_buf[WCD_SPI_CMD_IRR_LEN];
+
+	if (!reg || !val || reg_len != wcd_spi->reg_bytes ||
+	    val_len != wcd_spi->val_bytes) {
+		dev_err(&spi->dev,
+			"%s: Invalid input, reg_len = %zd, val_len = %zd",
+			__func__, reg_len, val_len);
+		return -EINVAL;
+	}
+
+	memset(tx_buf, 0, WCD_SPI_OPCODE_LEN);
+	tx_buf[0] = WCD_SPI_CMD_IRR;
+	tx_buf[1] = *((u8 *)reg);
+
+	wcd_spi_reinit_xfer(tx_xfer);
+	tx_xfer->tx_buf = tx_buf;
+	tx_xfer->rx_buf = NULL;
+	tx_xfer->len = WCD_SPI_CMD_IRR_LEN;
+
+	wcd_spi_reinit_xfer(rx_xfer);
+	rx_xfer->tx_buf = NULL;
+	rx_xfer->rx_buf = val;
+	rx_xfer->len = val_len;
+
+	return spi_sync(spi, &wcd_spi->msg2);
+}
+
+static struct regmap_bus wcd_spi_regmap_bus = {
+	.write = wcd_spi_bus_write,
+	.gather_write = wcd_spi_bus_gwrite,
+	.read = wcd_spi_bus_read,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static int wcd_spi_state_show(struct seq_file *f, void *ptr)
+{
+	struct spi_device *spi = f->private;
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	const char *clk_state, *clk_mutex, *xfer_mutex;
+
+	if (test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask))
+		clk_state = "enabled";
+	else
+		clk_state = "disabled";
+
+	clk_mutex = mutex_is_locked(&wcd_spi->clk_mutex) ?
+		    "locked" : "unlocked";
+
+	xfer_mutex = mutex_is_locked(&wcd_spi->xfer_mutex) ?
+		     "locked" : "unlocked";
+
+	seq_printf(f, "clk_state = %s\nclk_users = %d\n"
+		   "clk_mutex = %s\nxfer_mutex = %s\n",
+		   clk_state, wcd_spi->clk_users, clk_mutex,
+		   xfer_mutex);
+	return 0;
+}
+
+static int wcd_spi_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, wcd_spi_state_show, inode->i_private);
+}
+
+static const struct file_operations state_fops = {
+	.open = wcd_spi_state_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static ssize_t wcd_spi_debugfs_mem_read(struct file *file, char __user *ubuf,
+					size_t count, loff_t *ppos)
+{
+	struct spi_device *spi = file->private_data;
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data;
+	struct wcd_spi_msg msg;
+	ssize_t buf_size, read_count = 0;
+	char *buf;
+	int ret;
+
+	if (*ppos < 0 || !count)
+		return -EINVAL;
+
+	if (dbg_data->size == 0 || dbg_data->addr == 0) {
+		dev_err(&spi->dev,
+			"%s: Invalid request, size = %u, addr = 0x%x\n",
+			__func__, dbg_data->size, dbg_data->addr);
+		return 0;
+	}
+
+	buf_size = count < dbg_data->size ? count : dbg_data->size;
+	buf = kzalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	msg.data = buf;
+	msg.remote_addr = dbg_data->addr;
+	msg.len = buf_size;
+	msg.flags = 0;
+
+	ret = wcd_spi_data_read(spi, &msg);
+	if (ret < 0) {
+		dev_err(&spi->dev,
+			"%s: Failed to read %zu bytes from addr 0x%x\n",
+			__func__, buf_size, msg.remote_addr);
+		goto done;
+	}
+
+	read_count = simple_read_from_buffer(ubuf, count, ppos, buf, buf_size);
+
+done:
+	kfree(buf);
+	if (ret < 0)
+		return ret;
+	else
+		return read_count;
+}
+
+static const struct file_operations mem_read_fops = {
+	.open = simple_open,
+	.read = wcd_spi_debugfs_mem_read,
+};
+
+static int wcd_spi_debugfs_init(struct spi_device *spi)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data;
+	int rc = 0;
+
+	dbg_data->dir = debugfs_create_dir("wcd_spi", NULL);
+	if (IS_ERR_OR_NULL(dbg_data->dir)) {
+		dbg_data->dir = NULL;
+		rc = -ENODEV;
+		goto done;
+	}
+
+	debugfs_create_file("state", 0444, dbg_data->dir, spi, &state_fops);
+	debugfs_create_u32("addr", 0644, dbg_data->dir,
+			   &dbg_data->addr);
+	debugfs_create_u32("size", 0644, dbg_data->dir,
+			   &dbg_data->size);
+
+	debugfs_create_file("mem_read", 0444, dbg_data->dir,
+			    spi, &mem_read_fops);
+done:
+	return rc;
+}
+
+
+static const struct reg_default wcd_spi_defaults[] = {
+	{WCD_SPI_SLAVE_SANITY, 0xDEADBEEF},
+	{WCD_SPI_SLAVE_DEVICE_ID, 0x00500000},
+	{WCD_SPI_SLAVE_STATUS, 0x80100000},
+	{WCD_SPI_SLAVE_CONFIG, 0x0F200808},
+	{WCD_SPI_SLAVE_SW_RESET, 0x00000000},
+	{WCD_SPI_SLAVE_IRQ_STATUS, 0x00000000},
+	{WCD_SPI_SLAVE_IRQ_EN, 0x00000000},
+	{WCD_SPI_SLAVE_IRQ_CLR, 0x00000000},
+	{WCD_SPI_SLAVE_IRQ_FORCE, 0x00000000},
+	{WCD_SPI_SLAVE_TX, 0x00000000},
+	{WCD_SPI_SLAVE_TEST_BUS_DATA, 0x00000000},
+	{WCD_SPI_SLAVE_TEST_BUS_CTRL, 0x00000000},
+	{WCD_SPI_SLAVE_SW_RST_IRQ, 0x00000000},
+	{WCD_SPI_SLAVE_CHAR_CFG, 0x00000000},
+	{WCD_SPI_SLAVE_CHAR_DATA_MOSI, 0x00000000},
+	{WCD_SPI_SLAVE_CHAR_DATA_CS_N, 0x00000000},
+	{WCD_SPI_SLAVE_CHAR_DATA_MISO, 0x00000000},
+	{WCD_SPI_SLAVE_TRNS_BYTE_CNT, 0x00000000},
+	{WCD_SPI_SLAVE_TRNS_LEN, 0x00000000},
+	{WCD_SPI_SLAVE_FIFO_LEVEL, 0x00000000},
+	{WCD_SPI_SLAVE_GENERICS, 0x80000000},
+	{WCD_SPI_SLAVE_EXT_BASE_ADDR, 0x00000000},
+};
+
+static bool wcd_spi_is_volatile_reg(struct device *dev,
+				    unsigned int reg)
+{
+	switch (reg) {
+	case WCD_SPI_SLAVE_SANITY:
+	case WCD_SPI_SLAVE_STATUS:
+	case WCD_SPI_SLAVE_IRQ_STATUS:
+	case WCD_SPI_SLAVE_TX:
+	case WCD_SPI_SLAVE_SW_RST_IRQ:
+	case WCD_SPI_SLAVE_TRNS_BYTE_CNT:
+	case WCD_SPI_SLAVE_FIFO_LEVEL:
+	case WCD_SPI_SLAVE_GENERICS:
+		return true;
+	}
+
+	return false;
+}
+
+static bool wcd_spi_is_readable_reg(struct device *dev,
+				    unsigned int reg)
+{
+	switch (reg) {
+	case WCD_SPI_SLAVE_SW_RESET:
+	case WCD_SPI_SLAVE_IRQ_CLR:
+	case WCD_SPI_SLAVE_IRQ_FORCE:
+		return false;
+	}
+
+	return true;
+}
+
+static struct regmap_config wcd_spi_regmap_cfg = {
+	.reg_bits = 8,
+	.val_bits = 32,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wcd_spi_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wcd_spi_defaults),
+	.max_register = WCD_SPI_MAX_REGISTER,
+	.volatile_reg = wcd_spi_is_volatile_reg,
+	.readable_reg = wcd_spi_is_readable_reg,
+};
+
+static int wdsp_spi_init(struct device *dev, void *priv_data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	int ret;
+
+	ret = wcd_spi_init(spi);
+	if (ret < 0)
+		dev_err(&spi->dev, "%s: Init failed, err = %d\n",
+			__func__, ret);
+	return ret;
+}
+
+static int wdsp_spi_deinit(struct device *dev, void *priv_data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+
+	/*
+	 * Deinit means the hardware is reset. Mark the cache
+	 * as dirty here, so init will sync the cache
+	 */
+	regcache_mark_dirty(wcd_spi->regmap);
+
+	return 0;
+}
+
+static struct wdsp_cmpnt_ops wdsp_spi_ops = {
+	.init = wdsp_spi_init,
+	.deinit = wdsp_spi_deinit,
+	.event_handler = wdsp_spi_event_handler,
+};
+
+static int wcd_spi_component_bind(struct device *dev,
+				  struct device *master,
+				  void *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int ret = 0;
+
+	wcd_spi->m_dev = master;
+	wcd_spi->m_ops = data;
+
+	if (wcd_spi->m_ops &&
+	    wcd_spi->m_ops->register_cmpnt_ops)
+		ret = wcd_spi->m_ops->register_cmpnt_ops(master, dev,
+							 wcd_spi,
+							 &wdsp_spi_ops);
+	if (ret) {
+		dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	wcd_spi->reg_bytes = DIV_ROUND_UP(wcd_spi_regmap_cfg.reg_bits, 8);
+	wcd_spi->val_bytes = DIV_ROUND_UP(wcd_spi_regmap_cfg.val_bits, 8);
+
+	wcd_spi->regmap = devm_regmap_init(&spi->dev, &wcd_spi_regmap_bus,
+					   &spi->dev, &wcd_spi_regmap_cfg);
+	if (IS_ERR(wcd_spi->regmap)) {
+		ret = PTR_ERR(wcd_spi->regmap);
+		dev_err(&spi->dev, "%s: Failed to allocate regmap, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	if (wcd_spi_debugfs_init(spi))
+		dev_err(&spi->dev, "%s: Failed debugfs init\n", __func__);
+
+	spi_message_init(&wcd_spi->msg1);
+	spi_message_add_tail(&wcd_spi->xfer1, &wcd_spi->msg1);
+
+	spi_message_init(&wcd_spi->msg2);
+	spi_message_add_tail(&wcd_spi->xfer2[0], &wcd_spi->msg2);
+	spi_message_add_tail(&wcd_spi->xfer2[1], &wcd_spi->msg2);
+
+	/* Pre-allocate the buffers */
+	wcd_spi->tx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+				  GFP_KERNEL | GFP_DMA);
+	if (!wcd_spi->tx_buf) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	wcd_spi->rx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+				  GFP_KERNEL | GFP_DMA);
+	if (!wcd_spi->rx_buf) {
+		kfree(wcd_spi->tx_buf);
+		wcd_spi->tx_buf = NULL;
+		ret = -ENOMEM;
+		goto done;
+	}
+done:
+	return ret;
+}
+
+static void wcd_spi_component_unbind(struct device *dev,
+				     struct device *master,
+				     void *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+
+	wcd_spi->m_dev = NULL;
+	wcd_spi->m_ops = NULL;
+
+	spi_transfer_del(&wcd_spi->xfer1);
+	spi_transfer_del(&wcd_spi->xfer2[0]);
+	spi_transfer_del(&wcd_spi->xfer2[1]);
+
+	kfree(wcd_spi->tx_buf);
+	kfree(wcd_spi->rx_buf);
+	wcd_spi->tx_buf = NULL;
+	wcd_spi->rx_buf = NULL;
+}
+
+static const struct component_ops wcd_spi_component_ops = {
+	.bind = wcd_spi_component_bind,
+	.unbind = wcd_spi_component_unbind,
+};
+
+static int wcd_spi_probe(struct spi_device *spi)
+{
+	struct wcd_spi_priv *wcd_spi;
+	int ret = 0;
+
+	wcd_spi = devm_kzalloc(&spi->dev, sizeof(*wcd_spi),
+			       GFP_KERNEL);
+	if (!wcd_spi)
+		return -ENOMEM;
+
+	ret = of_property_read_u32(spi->dev.of_node,
+				   "qcom,mem-base-addr",
+				   &wcd_spi->mem_base_addr);
+	if (ret < 0) {
+		dev_err(&spi->dev, "%s: Missing %s DT entry",
+			__func__, "qcom,mem-base-addr");
+		goto err_ret;
+	}
+
+	dev_dbg(&spi->dev,
+		"%s: mem_base_addr 0x%x\n", __func__, wcd_spi->mem_base_addr);
+
+	mutex_init(&wcd_spi->clk_mutex);
+	mutex_init(&wcd_spi->xfer_mutex);
+	INIT_DELAYED_WORK(&wcd_spi->clk_dwork, wcd_spi_clk_work);
+	init_completion(&wcd_spi->resume_comp);
+
+	wcd_spi->spi = spi;
+	spi_set_drvdata(spi, wcd_spi);
+
+	ret = component_add(&spi->dev, &wcd_spi_component_ops);
+	if (ret) {
+		dev_err(&spi->dev, "%s: component_add failed err = %d\n",
+			__func__, ret);
+		goto err_component_add;
+	}
+
+	return ret;
+
+err_component_add:
+	mutex_destroy(&wcd_spi->clk_mutex);
+	mutex_destroy(&wcd_spi->xfer_mutex);
+err_ret:
+	devm_kfree(&spi->dev, wcd_spi);
+	spi_set_drvdata(spi, NULL);
+	return ret;
+}
+
+static int wcd_spi_remove(struct spi_device *spi)
+{
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+
+	component_del(&spi->dev, &wcd_spi_component_ops);
+
+	mutex_destroy(&wcd_spi->clk_mutex);
+	mutex_destroy(&wcd_spi->xfer_mutex);
+
+	devm_kfree(&spi->dev, wcd_spi);
+	spi_set_drvdata(spi, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wcd_spi_suspend(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	int rc = 0;
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	if (!wcd_spi_can_suspend(wcd_spi)) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/*
+	 * If we are here, it is okay to let the suspend go
+	 * through for this driver. But, still need to notify
+	 * the master to make sure all other components can suspend
+	 * as well.
+	 */
+	if (wcd_spi->m_dev && wcd_spi->m_ops &&
+	  wcd_spi->m_ops->suspend) {
+		WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+		rc = wcd_spi->m_ops->suspend(wcd_spi->m_dev);
+		WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	}
+
+	if (rc == 0)
+		set_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+	else
+		dev_dbg(&spi->dev, "%s: cannot suspend, err = %d\n",
+			__func__, rc);
+done:
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+	return rc;
+}
+
+static int wcd_spi_resume(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+
+	WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+	clear_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask);
+	complete(&wcd_spi->resume_comp);
+	WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
+
+	return 0;
+}
+
+static const struct dev_pm_ops wcd_spi_pm_ops = {
+	.suspend = wcd_spi_suspend,
+	.resume = wcd_spi_resume,
+};
+#endif
+
+static const struct of_device_id wcd_spi_of_match[] = {
+	{ .compatible = "qcom,wcd-spi-v2", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wcd_spi_of_match);
+
+static struct spi_driver wcd_spi_driver = {
+	.driver = {
+		.name = "wcd-spi-v2",
+		.of_match_table = wcd_spi_of_match,
+#ifdef CONFIG_PM
+		.pm = &wcd_spi_pm_ops,
+#endif
+	},
+	.probe = wcd_spi_probe,
+	.remove = wcd_spi_remove,
+};
+
+module_spi_driver(wcd_spi_driver);
+
+MODULE_DESCRIPTION("WCD SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd9335-regmap.c b/asoc/codecs/wcd9335-regmap.c
new file mode 100644
index 0000000..ffb79b7
--- /dev/null
+++ b/asoc/codecs/wcd9335-regmap.c
@@ -0,0 +1,1611 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "core.h"
+#include "wcd9xxx-regmap.h"
+#include "wcd9335_registers.h"
+
+static const struct reg_sequence wcd9335_1_x_defaults[] = {
+	{ WCD9335_CODEC_RPM_CLK_GATE,                     0x03,  0x00 },
+	{ WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN,       0x1f,  0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,           0x00,  0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_CTL,               0x00,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG,          0x00,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG,          0x00,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG,          0x00,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG,          0x00,  0x00 },
+	{ WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD,       0x14,  0x00 },
+	{ WCD9335_CPE_SS_SS_ERROR_INT_MASK,               0x3f,  0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL,              0x00,  0x00 },
+	{ WCD9335_BIAS_VBG_FINE_ADJ,                      0x55,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_2,                        0x6c,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_3,                        0x2d,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_8,                        0x6c,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_10,                       0x6c,  0x00 },
+	{ WCD9335_SIDO_SIDO_DRIVER_2,                     0x77,  0x00 },
+	{ WCD9335_SIDO_SIDO_DRIVER_3,                     0x77,  0x00 },
+	{ WCD9335_SIDO_SIDO_TEST_2,                       0x00,  0x00 },
+	{ WCD9335_MBHC_ZDET_ANA_CTL,                      0x00,  0x00 },
+	{ WCD9335_MBHC_FSM_DEBUG,                         0xc0,  0x00 },
+	{ WCD9335_TX_1_2_ATEST_REFCTL,                    0x08,  0x00 },
+	{ WCD9335_TX_3_4_ATEST_REFCTL,                    0x08,  0x00 },
+	{ WCD9335_TX_5_6_ATEST_REFCTL,                    0x08,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_1,                    0x67,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_4,                    0x5f,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_9,                    0x50,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_DAC_CTRL_1,                0x65,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_DAC_CTRL_4,                0x40,  0x00 },
+	{ WCD9335_RX_BIAS_HPH_PA,                         0xaa,  0x00 },
+	{ WCD9335_RX_BIAS_HPH_LOWPOWER,                   0x62,  0x00 },
+	{ WCD9335_HPH_PA_CTL2,                            0x40,  0x00 },
+	{ WCD9335_HPH_L_EN,                               0x00,  0x00 },
+	{ WCD9335_HPH_R_EN,                               0x00,  0x00 },
+	{ WCD9335_HPH_R_ATEST,                            0x50,  0x00 },
+	{ WCD9335_HPH_RDAC_LDO_CTL,                       0x00,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_CFG0,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_CFG1,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC2,                   0x00,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC3,                   0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER1_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER2_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER3_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER4_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER5_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER6_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER7_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_COMPANDER8_CTL7,                    0x0c,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_CFG1,                   0x04,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_MIX_CFG,                0x0e,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC0,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC1,                   0x00,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_MIX_SEC0,               0x00,  0x00 },
+	{ WCD9335_SPLINE_SRC0_CLK_RST_CTL_0,              0x00,  0x00 },
+	{ WCD9335_SPLINE_SRC1_CLK_RST_CTL_0,              0x00,  0x00 },
+	{ WCD9335_SPLINE_SRC2_CLK_RST_CTL_0,              0x00,  0x00 },
+	{ WCD9335_SPLINE_SRC3_CLK_RST_CTL_0,              0x00,  0x00 },
+	{ WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,        0x00,  0x00 },
+	{ WCD9335_TEST_DEBUG_NPL_DLY_TEST_1,              0x00,  0x00 },
+	{ WCD9335_TEST_DEBUG_NPL_DLY_TEST_2,              0x00,  0x00 },
+};
+
+static const struct reg_sequence wcd9335_2_0_defaults[] = {
+	{ WCD9335_CODEC_RPM_CLK_GATE,                     0x07,  0x00 },
+	{ WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN,       0x3f,  0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,           0x01,  0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_CTL,               0x10,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG,          0x08,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG,          0x08,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG,          0x08,  0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG,          0x08,  0x00 },
+	{ WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD,       0x13,  0x00 },
+	{ WCD9335_CPE_SS_SS_ERROR_INT_MASK,               0xff,  0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL,              0x40,  0x00 },
+	{ WCD9335_BIAS_VBG_FINE_ADJ,                      0xc5,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_2,                        0x92,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_3,                        0x35,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_8,                        0x6e,  0x00 },
+	{ WCD9335_SIDO_SIDO_CCL_10,                       0x6e,  0x00 },
+	{ WCD9335_SIDO_SIDO_DRIVER_2,                     0x55,  0x00 },
+	{ WCD9335_SIDO_SIDO_DRIVER_3,                     0x55,  0x00 },
+	{ WCD9335_SIDO_SIDO_TEST_2,                       0x0f,  0x00 },
+	{ WCD9335_MBHC_ZDET_ANA_CTL,                      0x0f,  0x00 },
+	{ WCD9335_TX_1_2_ATEST_REFCTL,                    0x0a,  0x00 },
+	{ WCD9335_TX_3_4_ATEST_REFCTL,                    0x0a,  0x00 },
+	{ WCD9335_TX_5_6_ATEST_REFCTL,                    0x0a,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_1,                    0xeb,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_4,                    0x7f,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_9,                    0x64,  0x00 },
+	{ WCD9335_FLYBACK_VNEG_DAC_CTRL_1,                0xed,  0x00 },
+	{ WCD9335_RX_BIAS_HPH_PA,                         0x9a,  0x00 },
+	{ WCD9335_RX_BIAS_HPH_LOWPOWER,                   0x82,  0x00 },
+	{ WCD9335_HPH_PA_CTL2,                            0x50,  0x00 },
+	{ WCD9335_HPH_L_EN,                               0x80,  0x00 },
+	{ WCD9335_HPH_R_EN,                               0x80,  0x00 },
+	{ WCD9335_HPH_R_ATEST,                            0x54,  0x00 },
+	{ WCD9335_HPH_RDAC_LDO_CTL,                       0x33,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_CFG0,                   0x10,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_CFG1,                   0x02,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC2,                   0x01,  0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC3,                   0x3c,  0x00 },
+	{ WCD9335_CDC_COMPANDER1_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_COMPANDER2_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_COMPANDER3_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_COMPANDER4_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_COMPANDER5_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_COMPANDER6_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_COMPANDER7_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_COMPANDER8_CTL7,                    0x08,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_CFG1,                   0x44,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_MIX_CFG,                0x1e,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC0,                   0xfc,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC1,                   0x08,  0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_MIX_SEC0,               0x08,  0x00 },
+	{ WCD9335_SPLINE_SRC0_CLK_RST_CTL_0,              0x20,  0x00 },
+	{ WCD9335_SPLINE_SRC1_CLK_RST_CTL_0,              0x20,  0x00 },
+	{ WCD9335_SPLINE_SRC2_CLK_RST_CTL_0,              0x20,  0x00 },
+	{ WCD9335_SPLINE_SRC3_CLK_RST_CTL_0,              0x20,  0x00 },
+	{ WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,        0x0c,  0x00 },
+	{ WCD9335_TEST_DEBUG_NPL_DLY_TEST_1,              0x10,  0x00 },
+	{ WCD9335_TEST_DEBUG_NPL_DLY_TEST_2,              0x60,  0x00 },
+	{ WCD9335_DATA_HUB_NATIVE_FIFO_SYNC,              0x00,  0x00 },
+	{ WCD9335_DATA_HUB_NATIVE_FIFO_STATUS,            0x00,  0x00 },
+	{ WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD,            0x60,  0x00 },
+	{ WCD9335_CPE_SS_TX_PP_CFG,                       0x3C,  0x00 },
+	{ WCD9335_CPE_SS_SVA_CFG,                         0x00,  0x00 },
+	{ WCD9335_MBHC_FSM_STATUS,                        0x00,  0x00 },
+	{ WCD9335_FLYBACK_CTRL_1,                         0x45,  0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC7,                   0x25,  0x00 },
+	{ WCD9335_SPLINE_SRC0_STATUS,                     0x00,  0x00 },
+	{ WCD9335_SPLINE_SRC1_STATUS,                     0x00,  0x00 },
+	{ WCD9335_SPLINE_SRC2_STATUS,                     0x00,  0x00 },
+	{ WCD9335_SPLINE_SRC3_STATUS,                     0x00,  0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT,    0x00,  0x00 },
+};
+
+static const struct reg_default wcd9335_defaults[] = {
+	/* Page #0 registers */
+	{ WCD9335_PAGE0_PAGE_REGISTER,                    0x00 },
+	{ WCD9335_CODEC_RPM_CLK_BYPASS,                   0x00 },
+	{ WCD9335_CODEC_RPM_CLK_MCLK_CFG,                 0x00 },
+	{ WCD9335_CODEC_RPM_RST_CTL,                      0x00 },
+	{ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,           0x07 },
+	{ WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1,            0x00 },
+	{ WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2,            0x00 },
+	{ WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3,            0x00 },
+	{ WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN,        0x01 },
+	{ WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1,     0xff },
+	{ WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2,     0xff },
+	{ WCD9335_CODEC_RPM_INT_MASK,                     0x3f },
+	{ WCD9335_CODEC_RPM_INT_STATUS,                   0x00 },
+	{ WCD9335_CODEC_RPM_INT_CLEAR,                    0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1,           0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,           0x07 },
+	{ WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3,           0x01 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0,             0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1,             0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10,         0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11,         0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12,         0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13,         0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14,         0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15,         0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS,            0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO,    0x0d },
+	{ WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3,          0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL,      0xCC },
+	{ WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE,              0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL,           0x06 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS,        0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB,       0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB,       0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL,           0x06 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS,        0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB,       0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB,       0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL,           0x06 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS,        0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB,       0x00 },
+	{ WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,           0x0c },
+	{ WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,           0x0c },
+	{ WCD9335_DATA_HUB_DATA_HUB_I2S_CLK,              0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG,          0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG,          0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG,          0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG,          0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG,       0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG,      0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG,      0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG,      0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG,      0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG,      0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG,     0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG,     0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG,     0x00 },
+	{ WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG,     0x00 },
+	{ WCD9335_INTR_CFG,                               0x00 },
+	{ WCD9335_INTR_CLR_COMMIT,                        0x00 },
+	{ WCD9335_INTR_PIN1_MASK0,                        0xff },
+	{ WCD9335_INTR_PIN1_MASK1,                        0xff },
+	{ WCD9335_INTR_PIN1_MASK2,                        0xff },
+	{ WCD9335_INTR_PIN1_MASK3,                        0xff },
+	{ WCD9335_INTR_PIN1_STATUS0,                      0x00 },
+	{ WCD9335_INTR_PIN1_STATUS1,                      0x00 },
+	{ WCD9335_INTR_PIN1_STATUS2,                      0x00 },
+	{ WCD9335_INTR_PIN1_STATUS3,                      0x00 },
+	{ WCD9335_INTR_PIN1_CLEAR0,                       0x00 },
+	{ WCD9335_INTR_PIN1_CLEAR1,                       0x00 },
+	{ WCD9335_INTR_PIN1_CLEAR2,                       0x00 },
+	{ WCD9335_INTR_PIN1_CLEAR3,                       0x00 },
+	{ WCD9335_INTR_PIN2_MASK0,                        0xff },
+	{ WCD9335_INTR_PIN2_MASK1,                        0xff },
+	{ WCD9335_INTR_PIN2_MASK2,                        0xff },
+	{ WCD9335_INTR_PIN2_MASK3,                        0xff },
+	{ WCD9335_INTR_PIN2_STATUS0,                      0x00 },
+	{ WCD9335_INTR_PIN2_STATUS1,                      0x00 },
+	{ WCD9335_INTR_PIN2_STATUS2,                      0x00 },
+	{ WCD9335_INTR_PIN2_STATUS3,                      0x00 },
+	{ WCD9335_INTR_PIN2_CLEAR0,                       0x00 },
+	{ WCD9335_INTR_PIN2_CLEAR1,                       0x00 },
+	{ WCD9335_INTR_PIN2_CLEAR2,                       0x00 },
+	{ WCD9335_INTR_PIN2_CLEAR3,                       0x00 },
+	{ WCD9335_INTR_LEVEL0,                            0x03 },
+	{ WCD9335_INTR_LEVEL1,                            0xe0 },
+	{ WCD9335_INTR_LEVEL2,                            0x10 },
+	{ WCD9335_INTR_LEVEL3,                            0x80 },
+	{ WCD9335_INTR_BYPASS0,                           0x00 },
+	{ WCD9335_INTR_BYPASS1,                           0x00 },
+	{ WCD9335_INTR_BYPASS2,                           0x00 },
+	{ WCD9335_INTR_BYPASS3,                           0x00 },
+	{ WCD9335_INTR_SET0,                              0x00 },
+	{ WCD9335_INTR_SET1,                              0x00 },
+	{ WCD9335_INTR_SET2,                              0x00 },
+	{ WCD9335_INTR_SET3,                              0x00 },
+	/* Page #1 registers */
+	{ WCD9335_PAGE1_PAGE_REGISTER,                    0x00 },
+	{ WCD9335_CPE_FLL_USER_CTL_0,                     0x71 },
+	{ WCD9335_CPE_FLL_USER_CTL_1,                     0x34 },
+	{ WCD9335_CPE_FLL_USER_CTL_2,                     0x0b },
+	{ WCD9335_CPE_FLL_USER_CTL_3,                     0x02 },
+	{ WCD9335_CPE_FLL_USER_CTL_4,                     0x04 },
+	{ WCD9335_CPE_FLL_USER_CTL_5,                     0x02 },
+	{ WCD9335_CPE_FLL_USER_CTL_6,                     0x64 },
+	{ WCD9335_CPE_FLL_USER_CTL_7,                     0x00 },
+	{ WCD9335_CPE_FLL_USER_CTL_8,                     0x94 },
+	{ WCD9335_CPE_FLL_USER_CTL_9,                     0x70 },
+	{ WCD9335_CPE_FLL_L_VAL_CTL_0,                    0x40 },
+	{ WCD9335_CPE_FLL_L_VAL_CTL_1,                    0x00 },
+	{ WCD9335_CPE_FLL_DSM_FRAC_CTL_0,                 0x00 },
+	{ WCD9335_CPE_FLL_DSM_FRAC_CTL_1,                 0xff },
+	{ WCD9335_CPE_FLL_CONFIG_CTL_0,                   0x6b },
+	{ WCD9335_CPE_FLL_CONFIG_CTL_1,                   0x05 },
+	{ WCD9335_CPE_FLL_CONFIG_CTL_2,                   0x08 },
+	{ WCD9335_CPE_FLL_CONFIG_CTL_3,                   0x00 },
+	{ WCD9335_CPE_FLL_CONFIG_CTL_4,                   0x10 },
+	{ WCD9335_CPE_FLL_TEST_CTL_0,                     0x00 },
+	{ WCD9335_CPE_FLL_TEST_CTL_1,                     0x00 },
+	{ WCD9335_CPE_FLL_TEST_CTL_2,                     0x00 },
+	{ WCD9335_CPE_FLL_TEST_CTL_3,                     0x00 },
+	{ WCD9335_CPE_FLL_TEST_CTL_4,                     0x00 },
+	{ WCD9335_CPE_FLL_TEST_CTL_5,                     0x00 },
+	{ WCD9335_CPE_FLL_TEST_CTL_6,                     0x00 },
+	{ WCD9335_CPE_FLL_TEST_CTL_7,                     0x33 },
+	{ WCD9335_CPE_FLL_FREQ_CTL_0,                     0x00 },
+	{ WCD9335_CPE_FLL_FREQ_CTL_1,                     0x00 },
+	{ WCD9335_CPE_FLL_FREQ_CTL_2,                     0x00 },
+	{ WCD9335_CPE_FLL_FREQ_CTL_3,                     0x00 },
+	{ WCD9335_CPE_FLL_SSC_CTL_0,                      0x00 },
+	{ WCD9335_CPE_FLL_SSC_CTL_1,                      0x00 },
+	{ WCD9335_CPE_FLL_SSC_CTL_2,                      0x00 },
+	{ WCD9335_CPE_FLL_SSC_CTL_3,                      0x00 },
+	{ WCD9335_CPE_FLL_FLL_MODE,                       0x20 },
+	{ WCD9335_CPE_FLL_STATUS_0,                       0x00 },
+	{ WCD9335_CPE_FLL_STATUS_1,                       0x00 },
+	{ WCD9335_CPE_FLL_STATUS_2,                       0x00 },
+	{ WCD9335_CPE_FLL_STATUS_3,                       0x00 },
+	{ WCD9335_I2S_FLL_USER_CTL_0,                     0x41 },
+	{ WCD9335_I2S_FLL_USER_CTL_1,                     0x94 },
+	{ WCD9335_I2S_FLL_USER_CTL_2,                     0x08 },
+	{ WCD9335_I2S_FLL_USER_CTL_3,                     0x02 },
+	{ WCD9335_I2S_FLL_USER_CTL_4,                     0x04 },
+	{ WCD9335_I2S_FLL_USER_CTL_5,                     0x02 },
+	{ WCD9335_I2S_FLL_USER_CTL_6,                     0x40 },
+	{ WCD9335_I2S_FLL_USER_CTL_7,                     0x00 },
+	{ WCD9335_I2S_FLL_USER_CTL_8,                     0x5f },
+	{ WCD9335_I2S_FLL_USER_CTL_9,                     0x02 },
+	{ WCD9335_I2S_FLL_L_VAL_CTL_0,                    0x40 },
+	{ WCD9335_I2S_FLL_L_VAL_CTL_1,                    0x00 },
+	{ WCD9335_I2S_FLL_DSM_FRAC_CTL_0,                 0x00 },
+	{ WCD9335_I2S_FLL_DSM_FRAC_CTL_1,                 0xff },
+	{ WCD9335_I2S_FLL_CONFIG_CTL_0,                   0x6b },
+	{ WCD9335_I2S_FLL_CONFIG_CTL_1,                   0x05 },
+	{ WCD9335_I2S_FLL_CONFIG_CTL_2,                   0x08 },
+	{ WCD9335_I2S_FLL_CONFIG_CTL_3,                   0x00 },
+	{ WCD9335_I2S_FLL_CONFIG_CTL_4,                   0x30 },
+	{ WCD9335_I2S_FLL_TEST_CTL_0,                     0x80 },
+	{ WCD9335_I2S_FLL_TEST_CTL_1,                     0x00 },
+	{ WCD9335_I2S_FLL_TEST_CTL_2,                     0x00 },
+	{ WCD9335_I2S_FLL_TEST_CTL_3,                     0x00 },
+	{ WCD9335_I2S_FLL_TEST_CTL_4,                     0x00 },
+	{ WCD9335_I2S_FLL_TEST_CTL_5,                     0x00 },
+	{ WCD9335_I2S_FLL_TEST_CTL_6,                     0x00 },
+	{ WCD9335_I2S_FLL_TEST_CTL_7,                     0xff },
+	{ WCD9335_I2S_FLL_FREQ_CTL_0,                     0x00 },
+	{ WCD9335_I2S_FLL_FREQ_CTL_1,                     0x00 },
+	{ WCD9335_I2S_FLL_FREQ_CTL_2,                     0x00 },
+	{ WCD9335_I2S_FLL_FREQ_CTL_3,                     0x00 },
+	{ WCD9335_I2S_FLL_SSC_CTL_0,                      0x00 },
+	{ WCD9335_I2S_FLL_SSC_CTL_1,                      0x00 },
+	{ WCD9335_I2S_FLL_SSC_CTL_2,                      0x00 },
+	{ WCD9335_I2S_FLL_SSC_CTL_3,                      0x00 },
+	{ WCD9335_I2S_FLL_FLL_MODE,                       0x00 },
+	{ WCD9335_I2S_FLL_STATUS_0,                       0x00 },
+	{ WCD9335_I2S_FLL_STATUS_1,                       0x00 },
+	{ WCD9335_I2S_FLL_STATUS_2,                       0x00 },
+	{ WCD9335_I2S_FLL_STATUS_3,                       0x00 },
+	{ WCD9335_SB_FLL_USER_CTL_0,                      0x41 },
+	{ WCD9335_SB_FLL_USER_CTL_1,                      0x94 },
+	{ WCD9335_SB_FLL_USER_CTL_2,                      0x08 },
+	{ WCD9335_SB_FLL_USER_CTL_3,                      0x02 },
+	{ WCD9335_SB_FLL_USER_CTL_4,                      0x04 },
+	{ WCD9335_SB_FLL_USER_CTL_5,                      0x02 },
+	{ WCD9335_SB_FLL_USER_CTL_6,                      0x40 },
+	{ WCD9335_SB_FLL_USER_CTL_7,                      0x00 },
+	{ WCD9335_SB_FLL_USER_CTL_8,                      0x5e },
+	{ WCD9335_SB_FLL_USER_CTL_9,                      0x01 },
+	{ WCD9335_SB_FLL_L_VAL_CTL_0,                     0x40 },
+	{ WCD9335_SB_FLL_L_VAL_CTL_1,                     0x00 },
+	{ WCD9335_SB_FLL_DSM_FRAC_CTL_0,                  0x00 },
+	{ WCD9335_SB_FLL_DSM_FRAC_CTL_1,                  0xff },
+	{ WCD9335_SB_FLL_CONFIG_CTL_0,                    0x6b },
+	{ WCD9335_SB_FLL_CONFIG_CTL_1,                    0x05 },
+	{ WCD9335_SB_FLL_CONFIG_CTL_2,                    0x08 },
+	{ WCD9335_SB_FLL_CONFIG_CTL_3,                    0x00 },
+	{ WCD9335_SB_FLL_CONFIG_CTL_4,                    0x10 },
+	{ WCD9335_SB_FLL_TEST_CTL_0,                      0x00 },
+	{ WCD9335_SB_FLL_TEST_CTL_1,                      0x00 },
+	{ WCD9335_SB_FLL_TEST_CTL_2,                      0x00 },
+	{ WCD9335_SB_FLL_TEST_CTL_3,                      0x00 },
+	{ WCD9335_SB_FLL_TEST_CTL_4,                      0x00 },
+	{ WCD9335_SB_FLL_TEST_CTL_5,                      0x00 },
+	{ WCD9335_SB_FLL_TEST_CTL_6,                      0x00 },
+	{ WCD9335_SB_FLL_TEST_CTL_7,                      0xff },
+	{ WCD9335_SB_FLL_FREQ_CTL_0,                      0x00 },
+	{ WCD9335_SB_FLL_FREQ_CTL_1,                      0x00 },
+	{ WCD9335_SB_FLL_FREQ_CTL_2,                      0x00 },
+	{ WCD9335_SB_FLL_FREQ_CTL_3,                      0x00 },
+	{ WCD9335_SB_FLL_SSC_CTL_0,                       0x00 },
+	{ WCD9335_SB_FLL_SSC_CTL_1,                       0x00 },
+	{ WCD9335_SB_FLL_SSC_CTL_2,                       0x00 },
+	{ WCD9335_SB_FLL_SSC_CTL_3,                       0x00 },
+	{ WCD9335_SB_FLL_FLL_MODE,                        0x00 },
+	{ WCD9335_SB_FLL_STATUS_0,                        0x00 },
+	{ WCD9335_SB_FLL_STATUS_1,                        0x00 },
+	{ WCD9335_SB_FLL_STATUS_2,                        0x00 },
+	{ WCD9335_SB_FLL_STATUS_3,                        0x00 },
+	/* Page #2 registers */
+	{ WCD9335_PAGE2_PAGE_REGISTER,                    0x00 },
+	{ WCD9335_CPE_SS_MEM_PTR_0,                       0x00 },
+	{ WCD9335_CPE_SS_MEM_PTR_1,                       0x00 },
+	{ WCD9335_CPE_SS_MEM_PTR_2,                       0x00 },
+	{ WCD9335_CPE_SS_MEM_CTRL,                        0x08 },
+	{ WCD9335_CPE_SS_MEM_BANK_0,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_1,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_2,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_3,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_4,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_5,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_6,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_7,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_8,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_9,                      0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_10,                     0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_11,                     0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_12,                     0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_13,                     0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_14,                     0x00 },
+	{ WCD9335_CPE_SS_MEM_BANK_15,                     0x00 },
+	{ WCD9335_CPE_SS_INBOX1_TRG,                      0x00 },
+	{ WCD9335_CPE_SS_INBOX2_TRG,                      0x00 },
+	{ WCD9335_CPE_SS_INBOX1_0,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_1,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_2,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_3,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_4,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_5,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_6,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_7,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_8,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_9,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX1_10,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX1_11,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX1_12,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX1_13,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX1_14,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX1_15,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_0,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_1,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_2,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_3,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_4,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_5,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_6,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_7,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_8,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_9,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_10,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_11,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_12,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_13,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_14,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_15,                      0x00 },
+	{ WCD9335_CPE_SS_INBOX2_0,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_1,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_2,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_3,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_4,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_5,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_6,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_7,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_8,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_9,                        0x00 },
+	{ WCD9335_CPE_SS_INBOX2_10,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX2_11,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX2_12,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX2_13,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX2_14,                       0x00 },
+	{ WCD9335_CPE_SS_INBOX2_15,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_0,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_1,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_2,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_3,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_4,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_5,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_6,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_7,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_8,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_9,                       0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_10,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_11,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_12,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_13,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_14,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_15,                      0x00 },
+	{ WCD9335_CPE_SS_OUTBOX1_ACK,                     0x00 },
+	{ WCD9335_CPE_SS_OUTBOX2_ACK,                     0x00 },
+	{ WCD9335_CPE_SS_EC_BUF_INT_PERIOD,               0x3c },
+	{ WCD9335_CPE_SS_US_BUF_INT_PERIOD,               0x60 },
+	{ WCD9335_CPE_SS_CFG,                             0x41 },
+	{ WCD9335_CPE_SS_US_EC_MUX_CFG,                   0x00 },
+	{ WCD9335_CPE_SS_MAD_CTL,                         0x00 },
+	{ WCD9335_CPE_SS_CPAR_CTL,                        0x00 },
+	{ WCD9335_CPE_SS_DMIC0_CTL,                       0x00 },
+	{ WCD9335_CPE_SS_DMIC1_CTL,                       0x00 },
+	{ WCD9335_CPE_SS_DMIC2_CTL,                       0x00 },
+	{ WCD9335_CPE_SS_DMIC_CFG,                        0x80 },
+	{ WCD9335_CPE_SS_CPAR_CFG,                        0x00 },
+	{ WCD9335_CPE_SS_WDOG_CFG,                        0x01 },
+	{ WCD9335_CPE_SS_BACKUP_INT,                      0x00 },
+	{ WCD9335_CPE_SS_STATUS,                          0x00 },
+	{ WCD9335_CPE_SS_CPE_OCD_CFG,                     0x00 },
+	{ WCD9335_CPE_SS_SS_ERROR_INT_STATUS,             0x00 },
+	{ WCD9335_CPE_SS_SS_ERROR_INT_CLEAR,              0x00 },
+	{ WCD9335_SOC_MAD_MAIN_CTL_1,                     0x00 },
+	{ WCD9335_SOC_MAD_MAIN_CTL_2,                     0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_1,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_2,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_3,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_4,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_5,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_6,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_7,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_CTL_8,                    0x00 },
+	{ WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR,              0x00 },
+	{ WCD9335_SOC_MAD_ULTR_CTL_1,                     0x00 },
+	{ WCD9335_SOC_MAD_ULTR_CTL_2,                     0x00 },
+	{ WCD9335_SOC_MAD_ULTR_CTL_3,                     0x00 },
+	{ WCD9335_SOC_MAD_ULTR_CTL_4,                     0x00 },
+	{ WCD9335_SOC_MAD_ULTR_CTL_5,                     0x00 },
+	{ WCD9335_SOC_MAD_ULTR_CTL_6,                     0x00 },
+	{ WCD9335_SOC_MAD_ULTR_CTL_7,                     0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_1,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_2,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_3,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_4,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_5,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_6,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_7,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_CTL_8,                   0x00 },
+	{ WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR,             0x00 },
+	{ WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL,             0x00 },
+	{ WCD9335_SOC_MAD_INP_SEL,                        0x00 },
+	/* Page #6 registers */
+	{ WCD9335_PAGE6_PAGE_REGISTER,                    0x00 },
+	{ WCD9335_ANA_BIAS,                               0x00 },
+	{ WCD9335_ANA_CLK_TOP,                            0x00 },
+	{ WCD9335_ANA_RCO,                                0x30 },
+	{ WCD9335_ANA_BUCK_VOUT_A,                        0xb4 },
+	{ WCD9335_ANA_BUCK_VOUT_D,                        0xb4 },
+	{ WCD9335_ANA_BUCK_CTL,                           0x00 },
+	{ WCD9335_ANA_BUCK_STATUS,                        0xe0 },
+	{ WCD9335_ANA_RX_SUPPLIES,                        0x00 },
+	{ WCD9335_ANA_HPH,                                0x00 },
+	{ WCD9335_ANA_EAR,                                0x00 },
+	{ WCD9335_ANA_LO_1_2,                             0x00 },
+	{ WCD9335_ANA_LO_3_4,                             0x00 },
+	{ WCD9335_ANA_MAD_SETUP,                          0x81 },
+	{ WCD9335_ANA_AMIC1,                              0x20 },
+	{ WCD9335_ANA_AMIC2,                              0x00 },
+	{ WCD9335_ANA_AMIC3,                              0x20 },
+	{ WCD9335_ANA_AMIC4,                              0x00 },
+	{ WCD9335_ANA_AMIC5,                              0x20 },
+	{ WCD9335_ANA_AMIC6,                              0x00 },
+	{ WCD9335_ANA_MBHC_MECH,                          0x39 },
+	{ WCD9335_ANA_MBHC_ELECT,                         0x08 },
+	{ WCD9335_ANA_MBHC_ZDET,                          0x00 },
+	{ WCD9335_ANA_MBHC_RESULT_1,                      0x00 },
+	{ WCD9335_ANA_MBHC_RESULT_2,                      0x00 },
+	{ WCD9335_ANA_MBHC_RESULT_3,                      0x00 },
+	{ WCD9335_ANA_MBHC_BTN0,                          0x00 },
+	{ WCD9335_ANA_MBHC_BTN1,                          0x10 },
+	{ WCD9335_ANA_MBHC_BTN2,                          0x20 },
+	{ WCD9335_ANA_MBHC_BTN3,                          0x30 },
+	{ WCD9335_ANA_MBHC_BTN4,                          0x40 },
+	{ WCD9335_ANA_MBHC_BTN5,                          0x50 },
+	{ WCD9335_ANA_MBHC_BTN6,                          0x60 },
+	{ WCD9335_ANA_MBHC_BTN7,                          0x70 },
+	{ WCD9335_ANA_MICB1,                              0x10 },
+	{ WCD9335_ANA_MICB2,                              0x10 },
+	{ WCD9335_ANA_MICB2_RAMP,                         0x00 },
+	{ WCD9335_ANA_MICB3,                              0x10 },
+	{ WCD9335_ANA_MICB4,                              0x10 },
+	{ WCD9335_ANA_VBADC,                              0x00 },
+	{ WCD9335_BIAS_CTL,                               0x28 },
+	{ WCD9335_CLOCK_TEST_CTL,                         0x00 },
+	{ WCD9335_RCO_CTRL_1,                             0x44 },
+	{ WCD9335_RCO_CTRL_2,                             0x44 },
+	{ WCD9335_RCO_CAL,                                0x00 },
+	{ WCD9335_RCO_CAL_1,                              0x00 },
+	{ WCD9335_RCO_CAL_2,                              0x00 },
+	{ WCD9335_RCO_TEST_CTRL,                          0x00 },
+	{ WCD9335_RCO_CAL_OUT_1,                          0x00 },
+	{ WCD9335_RCO_CAL_OUT_2,                          0x00 },
+	{ WCD9335_RCO_CAL_OUT_3,                          0x00 },
+	{ WCD9335_RCO_CAL_OUT_4,                          0x00 },
+	{ WCD9335_RCO_CAL_OUT_5,                          0x00 },
+	{ WCD9335_SIDO_SIDO_MODE_1,                       0x84 },
+	{ WCD9335_SIDO_SIDO_MODE_2,                       0xfe },
+	{ WCD9335_SIDO_SIDO_MODE_3,                       0xf6 },
+	{ WCD9335_SIDO_SIDO_MODE_4,                       0x56 },
+	{ WCD9335_SIDO_SIDO_VCL_1,                        0x00 },
+	{ WCD9335_SIDO_SIDO_VCL_2,                        0x6c },
+	{ WCD9335_SIDO_SIDO_VCL_3,                        0x44 },
+	{ WCD9335_SIDO_SIDO_CCL_1,                        0x57 },
+	{ WCD9335_SIDO_SIDO_CCL_4,                        0x61 },
+	{ WCD9335_SIDO_SIDO_CCL_5,                        0x6d },
+	{ WCD9335_SIDO_SIDO_CCL_6,                        0x60 },
+	{ WCD9335_SIDO_SIDO_CCL_7,                        0x6f },
+	{ WCD9335_SIDO_SIDO_CCL_9,                        0x6e },
+	{ WCD9335_SIDO_SIDO_FILTER_1,                     0x92 },
+	{ WCD9335_SIDO_SIDO_FILTER_2,                     0x54 },
+	{ WCD9335_SIDO_SIDO_DRIVER_1,                     0x77 },
+	{ WCD9335_SIDO_SIDO_CAL_CODE_EXT_1,               0x9c },
+	{ WCD9335_SIDO_SIDO_CAL_CODE_EXT_2,               0x82 },
+	{ WCD9335_SIDO_SIDO_CAL_CODE_OUT_1,               0x00 },
+	{ WCD9335_SIDO_SIDO_CAL_CODE_OUT_2,               0x00 },
+	{ WCD9335_SIDO_SIDO_TEST_1,                       0x00 },
+	{ WCD9335_MBHC_CTL_1,                             0x32 },
+	{ WCD9335_MBHC_CTL_2,                             0x01 },
+	{ WCD9335_MBHC_PLUG_DETECT_CTL,                   0x69 },
+	{ WCD9335_MBHC_ZDET_RAMP_CTL,                     0x00 },
+	{ WCD9335_MBHC_TEST_CTL,                          0x00 },
+	{ WCD9335_VBADC_SUBBLOCK_EN,                      0xfe },
+	{ WCD9335_VBADC_IBIAS_FE,                         0x54 },
+	{ WCD9335_VBADC_BIAS_ADC,                         0x51 },
+	{ WCD9335_VBADC_FE_CTRL,                          0x1c },
+	{ WCD9335_VBADC_ADC_REF,                          0x20 },
+	{ WCD9335_VBADC_ADC_IO,                           0x80 },
+	{ WCD9335_VBADC_ADC_SAR,                          0xff },
+	{ WCD9335_VBADC_DEBUG,                            0x00 },
+	{ WCD9335_VBADC_ADC_DOUTMSB,                      0x00 },
+	{ WCD9335_VBADC_ADC_DOUTLSB,                      0x00 },
+	{ WCD9335_LDOH_MODE,                              0x2b },
+	{ WCD9335_LDOH_BIAS,                              0x68 },
+	{ WCD9335_LDOH_STB_LOADS,                         0x00 },
+	{ WCD9335_LDOH_SLOWRAMP,                          0x50 },
+	{ WCD9335_MICB1_TEST_CTL_1,                       0x1a },
+	{ WCD9335_MICB1_TEST_CTL_2,                       0x18 },
+	{ WCD9335_MICB1_TEST_CTL_3,                       0xa4 },
+	{ WCD9335_MICB2_TEST_CTL_1,                       0x1a },
+	{ WCD9335_MICB2_TEST_CTL_2,                       0x18 },
+	{ WCD9335_MICB2_TEST_CTL_3,                       0x24 },
+	{ WCD9335_MICB3_TEST_CTL_1,                       0x1a },
+	{ WCD9335_MICB3_TEST_CTL_2,                       0x18 },
+	{ WCD9335_MICB3_TEST_CTL_3,                       0xa4 },
+	{ WCD9335_MICB4_TEST_CTL_1,                       0x1a },
+	{ WCD9335_MICB4_TEST_CTL_2,                       0x18 },
+	{ WCD9335_MICB4_TEST_CTL_3,                       0xa4 },
+	{ WCD9335_TX_COM_ADC_VCM,                         0x39 },
+	{ WCD9335_TX_COM_BIAS_ATEST,                      0xc0 },
+	{ WCD9335_TX_COM_ADC_INT1_IB,                     0x6f },
+	{ WCD9335_TX_COM_ADC_INT2_IB,                     0x4f },
+	{ WCD9335_TX_COM_TXFE_DIV_CTL,                    0x2e },
+	{ WCD9335_TX_COM_TXFE_DIV_START,                  0x00 },
+	{ WCD9335_TX_COM_TXFE_DIV_STOP_9P6M,              0xc7 },
+	{ WCD9335_TX_COM_TXFE_DIV_STOP_12P288M,           0xff },
+	{ WCD9335_TX_1_2_TEST_EN,                         0xcc },
+	{ WCD9335_TX_1_2_ADC_IB,                          0x09 },
+	{ WCD9335_TX_1_2_TEST_CTL,                        0x38 },
+	{ WCD9335_TX_1_2_TEST_BLK_EN,                     0xff },
+	{ WCD9335_TX_1_2_TXFE_CLKDIV,                     0x00 },
+	{ WCD9335_TX_1_2_SAR1_ERR,                        0x00 },
+	{ WCD9335_TX_1_2_SAR2_ERR,                        0x00 },
+	{ WCD9335_TX_3_4_TEST_EN,                         0xcc },
+	{ WCD9335_TX_3_4_ADC_IB,                          0x09 },
+	{ WCD9335_TX_3_4_TEST_CTL,                        0x38 },
+	{ WCD9335_TX_3_4_TEST_BLK_EN,                     0xff },
+	{ WCD9335_TX_3_4_TXFE_CLKDIV,                     0x00 },
+	{ WCD9335_TX_3_4_SAR1_ERR,                        0x00 },
+	{ WCD9335_TX_3_4_SAR2_ERR,                        0x00 },
+	{ WCD9335_TX_5_6_TEST_EN,                         0xcc },
+	{ WCD9335_TX_5_6_ADC_IB,                          0x09 },
+	{ WCD9335_TX_5_6_TEST_CTL,                        0x38 },
+	{ WCD9335_TX_5_6_TEST_BLK_EN,                     0xff },
+	{ WCD9335_TX_5_6_TXFE_CLKDIV,                     0x00 },
+	{ WCD9335_TX_5_6_SAR1_ERR,                        0x00 },
+	{ WCD9335_TX_5_6_SAR2_ERR,                        0x00 },
+	{ WCD9335_CLASSH_MODE_1,                          0x40 },
+	{ WCD9335_CLASSH_MODE_2,                          0x3a },
+	{ WCD9335_CLASSH_MODE_3,                          0x00 },
+	{ WCD9335_CLASSH_CTRL_VCL_1,                      0x70 },
+	{ WCD9335_CLASSH_CTRL_VCL_2,                      0xa2 },
+	{ WCD9335_CLASSH_CTRL_CCL_1,                      0x51 },
+	{ WCD9335_CLASSH_CTRL_CCL_2,                      0x80 },
+	{ WCD9335_CLASSH_CTRL_CCL_3,                      0x80 },
+	{ WCD9335_CLASSH_CTRL_CCL_4,                      0x51 },
+	{ WCD9335_CLASSH_CTRL_CCL_5,                      0x00 },
+	{ WCD9335_CLASSH_BUCK_TMUX_A_D,                   0x00 },
+	{ WCD9335_CLASSH_BUCK_SW_DRV_CNTL,                0x77 },
+	{ WCD9335_CLASSH_SPARE,                           0x00 },
+	{ WCD9335_FLYBACK_EN,                             0x4e },
+	{ WCD9335_FLYBACK_VNEG_CTRL_2,                    0x45 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_3,                    0x74 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_5,                    0x83 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_6,                    0x98 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_7,                    0xa9 },
+	{ WCD9335_FLYBACK_VNEG_CTRL_8,                    0x68 },
+	{ WCD9335_FLYBACK_VNEG_DAC_CTRL_2,                0x50 },
+	{ WCD9335_FLYBACK_VNEG_DAC_CTRL_3,                0xa6 },
+	{ WCD9335_FLYBACK_TEST_CTL,                       0x00 },
+	{ WCD9335_RX_AUX_SW_CTL,                          0x00 },
+	{ WCD9335_RX_PA_AUX_IN_CONN,                      0x00 },
+	{ WCD9335_RX_TIMER_DIV,                           0x74 },
+	{ WCD9335_RX_OCP_CTL,                             0x1f },
+	{ WCD9335_RX_OCP_COUNT,                           0x77 },
+	{ WCD9335_RX_BIAS_EAR_DAC,                        0xa0 },
+	{ WCD9335_RX_BIAS_EAR_AMP,                        0xaa },
+	{ WCD9335_RX_BIAS_HPH_LDO,                        0xa9 },
+	{ WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2,              0x8a },
+	{ WCD9335_RX_BIAS_HPH_RDAC_LDO,                   0x88 },
+	{ WCD9335_RX_BIAS_HPH_CNP1,                       0x86 },
+	{ WCD9335_RX_BIAS_DIFFLO_PA,                      0x80 },
+	{ WCD9335_RX_BIAS_DIFFLO_REF,                     0x88 },
+	{ WCD9335_RX_BIAS_DIFFLO_LDO,                     0x88 },
+	{ WCD9335_RX_BIAS_SELO_DAC_PA,                    0xa8 },
+	{ WCD9335_RX_BIAS_BUCK_RST,                       0x08 },
+	{ WCD9335_RX_BIAS_BUCK_VREF_ERRAMP,               0x44 },
+	{ WCD9335_RX_BIAS_FLYB_ERRAMP,                    0x40 },
+	{ WCD9335_RX_BIAS_FLYB_BUFF,                      0xaa },
+	{ WCD9335_RX_BIAS_FLYB_MID_RST,                   0x44 },
+	{ WCD9335_HPH_L_STATUS,                           0x04 },
+	{ WCD9335_HPH_R_STATUS,                           0x04 },
+	{ WCD9335_HPH_CNP_EN,                             0x80 },
+	{ WCD9335_HPH_CNP_WG_CTL,                         0xda },
+	{ WCD9335_HPH_CNP_WG_TIME,                        0x15 },
+	{ WCD9335_HPH_OCP_CTL,                            0x28 },
+	{ WCD9335_HPH_AUTO_CHOP,                          0x12 },
+	{ WCD9335_HPH_CHOP_CTL,                           0x83 },
+	{ WCD9335_HPH_PA_CTL1,                            0x46 },
+	{ WCD9335_HPH_L_TEST,                             0x00 },
+	{ WCD9335_HPH_L_ATEST,                            0x50 },
+	{ WCD9335_HPH_R_TEST,                             0x00 },
+	{ WCD9335_HPH_RDAC_CLK_CTL1,                      0x99 },
+	{ WCD9335_HPH_RDAC_CLK_CTL2,                      0x9b },
+	{ WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL,               0x00 },
+	{ WCD9335_HPH_REFBUFF_UHQA_CTL,                   0xa8 },
+	{ WCD9335_HPH_REFBUFF_LP_CTL,                     0x00 },
+	{ WCD9335_HPH_L_DAC_CTL,                          0x00 },
+	{ WCD9335_HPH_R_DAC_CTL,                          0x00 },
+	{ WCD9335_EAR_EN_REG,                             0x60 },
+	{ WCD9335_EAR_CMBUFF,                             0x0d },
+	{ WCD9335_EAR_ICTL,                               0x40 },
+	{ WCD9335_EAR_EN_DBG_CTL,                         0x00 },
+	{ WCD9335_EAR_CNP,                                0xe0 },
+	{ WCD9335_EAR_DAC_CTL_ATEST,                      0x00 },
+	{ WCD9335_EAR_STATUS_REG,                         0x04 },
+	{ WCD9335_EAR_OUT_SHORT,                          0x00 },
+	{ WCD9335_DIFF_LO_MISC,                           0x03 },
+	{ WCD9335_DIFF_LO_LO2_COMPANDER,                  0x00 },
+	{ WCD9335_DIFF_LO_LO1_COMPANDER,                  0x00 },
+	{ WCD9335_DIFF_LO_COMMON,                         0x40 },
+	{ WCD9335_DIFF_LO_BYPASS_EN,                      0x00 },
+	{ WCD9335_DIFF_LO_CNP,                            0x20 },
+	{ WCD9335_DIFF_LO_CORE_OUT_PROG,                  0x00 },
+	{ WCD9335_DIFF_LO_LDO_OUT_PROG,                   0x00 },
+	{ WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ,          0x9b },
+	{ WCD9335_DIFF_LO_COM_PA_FREQ,                    0xb0 },
+	{ WCD9335_DIFF_LO_RESERVED_REG,                   0x60 },
+	{ WCD9335_DIFF_LO_LO1_STATUS_1,                   0x00 },
+	{ WCD9335_DIFF_LO_LO1_STATUS_2,                   0x00 },
+	{ WCD9335_SE_LO_COM1,                             0x80 },
+	{ WCD9335_SE_LO_COM2,                             0x04 },
+	{ WCD9335_SE_LO_LO3_GAIN,                         0x20 },
+	{ WCD9335_SE_LO_LO3_CTRL,                         0x04 },
+	{ WCD9335_SE_LO_LO4_GAIN,                         0x20 },
+	{ WCD9335_SE_LO_LO4_CTRL,                         0x04 },
+	{ WCD9335_SE_LO_LO3_STATUS,                       0x00 },
+	{ WCD9335_SE_LO_LO4_STATUS,                       0x00 },
+	/* Page #10 registers */
+	{ WCD9335_PAGE10_PAGE_REGISTER,                   0x00 },
+	{ WCD9335_CDC_ANC0_CLK_RESET_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC0_MODE_1_CTL,                    0x00 },
+	{ WCD9335_CDC_ANC0_MODE_2_CTL,                    0x00 },
+	{ WCD9335_CDC_ANC0_FF_SHIFT,                      0x00 },
+	{ WCD9335_CDC_ANC0_FB_SHIFT,                      0x00 },
+	{ WCD9335_CDC_ANC0_LPF_FF_A_CTL,                  0x00 },
+	{ WCD9335_CDC_ANC0_LPF_FF_B_CTL,                  0x00 },
+	{ WCD9335_CDC_ANC0_LPF_FB_CTL,                    0x00 },
+	{ WCD9335_CDC_ANC0_SMLPF_CTL,                     0x00 },
+	{ WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL,               0x00 },
+	{ WCD9335_CDC_ANC0_IIR_ADAPT_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC0_IIR_COEFF_1_CTL,               0x00 },
+	{ WCD9335_CDC_ANC0_IIR_COEFF_2_CTL,               0x00 },
+	{ WCD9335_CDC_ANC0_FF_A_GAIN_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC0_FF_B_GAIN_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC0_FB_GAIN_CTL,                   0x00 },
+	{ WCD9335_CDC_ANC1_CLK_RESET_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC1_MODE_1_CTL,                    0x00 },
+	{ WCD9335_CDC_ANC1_MODE_2_CTL,                    0x00 },
+	{ WCD9335_CDC_ANC1_FF_SHIFT,                      0x00 },
+	{ WCD9335_CDC_ANC1_FB_SHIFT,                      0x00 },
+	{ WCD9335_CDC_ANC1_LPF_FF_A_CTL,                  0x00 },
+	{ WCD9335_CDC_ANC1_LPF_FF_B_CTL,                  0x00 },
+	{ WCD9335_CDC_ANC1_LPF_FB_CTL,                    0x00 },
+	{ WCD9335_CDC_ANC1_SMLPF_CTL,                     0x00 },
+	{ WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL,               0x00 },
+	{ WCD9335_CDC_ANC1_IIR_ADAPT_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC1_IIR_COEFF_1_CTL,               0x00 },
+	{ WCD9335_CDC_ANC1_IIR_COEFF_2_CTL,               0x00 },
+	{ WCD9335_CDC_ANC1_FF_A_GAIN_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC1_FF_B_GAIN_CTL,                 0x00 },
+	{ WCD9335_CDC_ANC1_FB_GAIN_CTL,                   0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX0_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX0_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX1_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX1_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX2_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX2_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX3_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX3_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX4_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX4_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX5_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX5_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX6_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX6_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX7_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX7_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_TX8_TX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_192_CTL,                0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_192_CFG,                0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC0,                   0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC1,                   0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC4,                   0x20 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_TX8_TX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL,             0x02 },
+	{ WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0,            0x00 },
+	{ WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL,            0x02 },
+	{ WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0,           0x00 },
+	{ WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL,            0x02 },
+	{ WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0,           0x00 },
+	{ WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL,            0x02 },
+	{ WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0,           0x00 },
+	/* Page #11 registers */
+	{ WCD9335_PAGE11_PAGE_REGISTER,                   0x00 },
+	{ WCD9335_CDC_COMPANDER1_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER1_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER1_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER1_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER1_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER1_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER1_CTL6,                    0x01 },
+	{ WCD9335_CDC_COMPANDER2_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER2_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER2_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER2_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER2_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER2_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER2_CTL6,                    0x01 },
+	{ WCD9335_CDC_COMPANDER3_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER3_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER3_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER3_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER3_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER3_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER3_CTL6,                    0x01 },
+	{ WCD9335_CDC_COMPANDER4_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER4_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER4_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER4_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER4_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER4_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER4_CTL6,                    0x01 },
+	{ WCD9335_CDC_COMPANDER5_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER5_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER5_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER5_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER5_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER5_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER5_CTL6,                    0x01 },
+	{ WCD9335_CDC_COMPANDER6_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER6_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER6_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER6_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER6_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER6_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER6_CTL6,                    0x01 },
+	{ WCD9335_CDC_COMPANDER7_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER7_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER7_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER7_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER7_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER7_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER7_CTL6,                    0x01 },
+	{ WCD9335_CDC_COMPANDER8_CTL0,                    0x60 },
+	{ WCD9335_CDC_COMPANDER8_CTL1,                    0xdb },
+	{ WCD9335_CDC_COMPANDER8_CTL2,                    0xff },
+	{ WCD9335_CDC_COMPANDER8_CTL3,                    0x35 },
+	{ WCD9335_CDC_COMPANDER8_CTL4,                    0xff },
+	{ WCD9335_CDC_COMPANDER8_CTL5,                    0x00 },
+	{ WCD9335_CDC_COMPANDER8_CTL6,                    0x01 },
+	{ WCD9335_CDC_RX0_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX0_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX0_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX0_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX0_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX1_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX1_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX1_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC4,                   0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX1_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX2_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX2_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX2_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC4,                   0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX2_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX3_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX3_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX3_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX3_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX4_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX4_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX4_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX4_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX5_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX5_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX5_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX5_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX6_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX6_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX6_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX6_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX7_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX7_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX7_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX7_RX_PATH_MIX_SEC1,               0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_CTL,                    0x04 },
+	{ WCD9335_CDC_RX8_RX_PATH_CFG0,                   0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_CFG2,                   0x8f },
+	{ WCD9335_CDC_RX8_RX_VOL_CTL,                     0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_MIX_CTL,                0x04 },
+	{ WCD9335_CDC_RX8_RX_VOL_MIX_CTL,                 0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC2,                   0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC3,                   0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC5,                   0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC6,                   0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_SEC7,                   0x00 },
+	{ WCD9335_CDC_RX8_RX_PATH_MIX_SEC1,               0x00 },
+	/* Page #12 registers */
+	{ WCD9335_PAGE12_PAGE_REGISTER,                   0x00 },
+	{ WCD9335_CDC_CLSH_CRC,                           0x00 },
+	{ WCD9335_CDC_CLSH_DLY_CTRL,                      0x03 },
+	{ WCD9335_CDC_CLSH_DECAY_CTRL,                    0x02 },
+	{ WCD9335_CDC_CLSH_HPH_V_PA,                      0x1c },
+	{ WCD9335_CDC_CLSH_EAR_V_PA,                      0x39 },
+	{ WCD9335_CDC_CLSH_HPH_V_HD,                      0x0c },
+	{ WCD9335_CDC_CLSH_EAR_V_HD,                      0x0c },
+	{ WCD9335_CDC_CLSH_K1_MSB,                        0x01 },
+	{ WCD9335_CDC_CLSH_K1_LSB,                        0x00 },
+	{ WCD9335_CDC_CLSH_K2_MSB,                        0x00 },
+	{ WCD9335_CDC_CLSH_K2_LSB,                        0x80 },
+	{ WCD9335_CDC_CLSH_IDLE_CTRL,                     0x00 },
+	{ WCD9335_CDC_CLSH_IDLE_HPH,                      0x00 },
+	{ WCD9335_CDC_CLSH_IDLE_EAR,                      0x00 },
+	{ WCD9335_CDC_CLSH_TEST0,                         0x07 },
+	{ WCD9335_CDC_CLSH_TEST1,                         0x00 },
+	{ WCD9335_CDC_CLSH_OVR_VREF,                      0x00 },
+	{ WCD9335_CDC_BOOST0_BOOST_PATH_CTL,              0x00 },
+	{ WCD9335_CDC_BOOST0_BOOST_CTL,                   0xb2 },
+	{ WCD9335_CDC_BOOST0_BOOST_CFG1,                  0x00 },
+	{ WCD9335_CDC_BOOST0_BOOST_CFG2,                  0x00 },
+	{ WCD9335_CDC_BOOST1_BOOST_PATH_CTL,              0x00 },
+	{ WCD9335_CDC_BOOST1_BOOST_CTL,                   0xb2 },
+	{ WCD9335_CDC_BOOST1_BOOST_CFG1,                  0x00 },
+	{ WCD9335_CDC_BOOST1_BOOST_CFG2,                  0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_DATA_0,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_DATA_1,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_DATA_2,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_DATA_3,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_DATA_0,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_DATA_1,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_DATA_2,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_RD_DATA_3,               0x00 },
+	{ WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG,              0x0f },
+	{ WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS,           0x03 },
+	{ WCD9335_CDC_VBAT_VBAT_PATH_CTL,                 0x00 },
+	{ WCD9335_CDC_VBAT_VBAT_CFG,                      0x0a },
+	{ WCD9335_CDC_VBAT_VBAT_ADC_CAL1,                 0x00 },
+	{ WCD9335_CDC_VBAT_VBAT_ADC_CAL2,                 0x00 },
+	{ WCD9335_CDC_VBAT_VBAT_ADC_CAL3,                 0x04 },
+	{ WCD9335_CDC_VBAT_VBAT_PK_EST1,                  0xe0 },
+	{ WCD9335_CDC_VBAT_VBAT_PK_EST2,                  0x01 },
+	{ WCD9335_CDC_VBAT_VBAT_PK_EST3,                  0x40 },
+	{ WCD9335_CDC_VBAT_VBAT_RF_PROC1,                 0x2a },
+	{ WCD9335_CDC_VBAT_VBAT_RF_PROC2,                 0x86 },
+	{ WCD9335_CDC_VBAT_VBAT_TAC1,                     0x70 },
+	{ WCD9335_CDC_VBAT_VBAT_TAC2,                     0x18 },
+	{ WCD9335_CDC_VBAT_VBAT_TAC3,                     0x18 },
+	{ WCD9335_CDC_VBAT_VBAT_TAC4,                     0x03 },
+	{ WCD9335_CDC_VBAT_VBAT_GAIN_UPD1,                0x01 },
+	{ WCD9335_CDC_VBAT_VBAT_GAIN_UPD2,                0x00 },
+	{ WCD9335_CDC_VBAT_VBAT_GAIN_UPD3,                0x64 },
+	{ WCD9335_CDC_VBAT_VBAT_GAIN_UPD4,                0x01 },
+	{ WCD9335_CDC_VBAT_VBAT_DEBUG1,                   0x00 },
+	{ WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON,             0x00 },
+	{ WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL,             0x00 },
+	{ WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL,      0x04 },
+	{ WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1,     0x00 },
+	{ WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL,      0x04 },
+	{ WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1,     0x00 },
+	/* Page #13 registers */
+	{ WCD9335_PAGE13_PAGE_REGISTER,                   0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1,            0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0,             0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1,             0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2,             0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3,             0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4,             0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0,       0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1,       0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_ANC_CFG0,                0x00 },
+	{ WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0,         0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0,           0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0,          0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0,          0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0,          0x00 },
+	{ WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0,          0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00 },
+	{ WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0,              0x00 },
+	{ WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1,              0x00 },
+	{ WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2,              0x00 },
+	{ WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3,              0x00 },
+	{ WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,          0x00 },
+	{ WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL,           0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_CTL,               0x08 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0,      0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1,      0x4b },
+	{ WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB,   0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB,   0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_STATUS,            0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL,         0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB,     0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB,     0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD,  0x00 },
+	{ WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD,  0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL,         0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_CTL,              0x40 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL,   0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL,         0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_CTL,              0x40 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL,   0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL,      0x00 },
+	{ WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL,      0x00 },
+	{ WCD9335_CDC_TOP_TOP_CFG0,                       0x00 },
+	{ WCD9335_CDC_TOP_TOP_CFG1,                       0x00 },
+	{ WCD9335_CDC_TOP_TOP_CFG2,                       0x00 },
+	{ WCD9335_CDC_TOP_TOP_CFG3,                       0x18 },
+	{ WCD9335_CDC_TOP_TOP_CFG4,                       0x00 },
+	{ WCD9335_CDC_TOP_TOP_CFG5,                       0x00 },
+	{ WCD9335_CDC_TOP_TOP_CFG6,                       0x00 },
+	{ WCD9335_CDC_TOP_TOP_CFG7,                       0x00 },
+	{ WCD9335_CDC_TOP_HPHL_COMP_WR_LSB,               0x00 },
+	{ WCD9335_CDC_TOP_HPHL_COMP_WR_MSB,               0x00 },
+	{ WCD9335_CDC_TOP_HPHL_COMP_LUT,                  0x00 },
+	{ WCD9335_CDC_TOP_HPHL_COMP_RD_LSB,               0x00 },
+	{ WCD9335_CDC_TOP_HPHL_COMP_RD_MSB,               0x00 },
+	{ WCD9335_CDC_TOP_HPHR_COMP_WR_LSB,               0x00 },
+	{ WCD9335_CDC_TOP_HPHR_COMP_WR_MSB,               0x00 },
+	{ WCD9335_CDC_TOP_HPHR_COMP_LUT,                  0x00 },
+	{ WCD9335_CDC_TOP_HPHR_COMP_RD_LSB,               0x00 },
+	{ WCD9335_CDC_TOP_HPHR_COMP_RD_MSB,               0x00 },
+	{ WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB,              0x00 },
+	{ WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB,              0x00 },
+	{ WCD9335_CDC_TOP_DIFFL_COMP_LUT,                 0x00 },
+	{ WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB,              0x00 },
+	{ WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB,              0x00 },
+	{ WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB,              0x00 },
+	{ WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB,              0x00 },
+	{ WCD9335_CDC_TOP_DIFFR_COMP_LUT,                 0x00 },
+	{ WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB,              0x00 },
+	{ WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB,              0x00 },
+	/* Page #0x80 registers */
+	{ WCD9335_PAGE80_PAGE_REGISTER,                   0x00 },
+	{ WCD9335_TLMM_BIST_MODE_PINCFG,                  0x00 },
+	{ WCD9335_TLMM_RF_PA_ON_PINCFG,                   0x00 },
+	{ WCD9335_TLMM_INTR1_PINCFG,                      0x00 },
+	{ WCD9335_TLMM_INTR2_PINCFG,                      0x00 },
+	{ WCD9335_TLMM_SWR_DATA_PINCFG,                   0x00 },
+	{ WCD9335_TLMM_SWR_CLK_PINCFG,                    0x00 },
+	{ WCD9335_TLMM_SLIMBUS_DATA2_PINCFG,              0x00 },
+	{ WCD9335_TLMM_I2C_CLK_PINCFG,                    0x00 },
+	{ WCD9335_TLMM_I2C_DATA_PINCFG,                   0x00 },
+	{ WCD9335_TLMM_I2S_RX_SD0_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_I2S_RX_SD1_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_I2S_RX_SCK_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_I2S_RX_WS_PINCFG,                  0x00 },
+	{ WCD9335_TLMM_I2S_TX_SD0_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_I2S_TX_SD1_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_I2S_TX_SCK_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_I2S_TX_WS_PINCFG,                  0x00 },
+	{ WCD9335_TLMM_DMIC1_CLK_PINCFG,                  0x00 },
+	{ WCD9335_TLMM_DMIC1_DATA_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_DMIC2_CLK_PINCFG,                  0x00 },
+	{ WCD9335_TLMM_DMIC2_DATA_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_DMIC3_CLK_PINCFG,                  0x00 },
+	{ WCD9335_TLMM_DMIC3_DATA_PINCFG,                 0x00 },
+	{ WCD9335_TLMM_JTDI_PINCFG,                       0x00 },
+	{ WCD9335_TLMM_JTDO_PINCFG,                       0x00 },
+	{ WCD9335_TLMM_JTMS_PINCFG,                       0x00 },
+	{ WCD9335_TLMM_JTCK_PINCFG,                       0x00 },
+	{ WCD9335_TLMM_JTRST_PINCFG,                      0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_OE_0,                0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_OE_1,                0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_OE_2,                0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_OE_3,                0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_DATA_0,              0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_DATA_1,              0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_DATA_2,              0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_CTL_DATA_3,              0x00 },
+	{ WCD9335_TEST_DEBUG_PAD_DRVCTL,                  0x00 },
+	{ WCD9335_TEST_DEBUG_PIN_STATUS,                  0x00 },
+	{ WCD9335_TEST_DEBUG_MEM_CTRL,                    0x00 },
+	{ WCD9335_TEST_DEBUG_DEBUG_BUS_SEL,               0x00 },
+	{ WCD9335_TEST_DEBUG_DEBUG_JTAG,                  0x00 },
+	{ WCD9335_TEST_DEBUG_DEBUG_EN_1,                  0x00 },
+	{ WCD9335_TEST_DEBUG_DEBUG_EN_2,                  0x00 },
+	{ WCD9335_TEST_DEBUG_DEBUG_EN_3,                  0x00 },
+};
+
+/*
+ * wcd9335_regmap_register_patch: Update register defaults based on version
+ * @regmap: handle to wcd9xxx regmap
+ * @version: wcd9335 version
+ *
+ * Returns error code in case of failure or 0 for success
+ */
+int wcd9335_regmap_register_patch(struct regmap *regmap, int version)
+{
+	int rc;
+
+	if (!regmap) {
+		pr_err("%s: regmap struct is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (version) {
+	case TASHA_VERSION_1_0:
+	case TASHA_VERSION_1_1:
+		regcache_cache_only(regmap, true);
+		rc = regmap_multi_reg_write(regmap, wcd9335_1_x_defaults,
+					    ARRAY_SIZE(wcd9335_1_x_defaults));
+		regcache_cache_only(regmap, false);
+		break;
+	case TASHA_VERSION_2_0:
+		regcache_cache_only(regmap, true);
+		rc = regmap_multi_reg_write(regmap, wcd9335_2_0_defaults,
+					    ARRAY_SIZE(wcd9335_2_0_defaults));
+		regcache_cache_only(regmap, false);
+		break;
+	default:
+		pr_err("%s: unknown version: %d\n", __func__, version);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(wcd9335_regmap_register_patch);
+
+static bool wcd9335_is_readable_register(struct device *dev, unsigned int reg)
+{
+	u8 pg_num, reg_offset;
+	const u8 *reg_tbl = NULL;
+
+	/*
+	 * Get the page number from MSB of codec register. If its 0x80, assign
+	 * the corresponding page index PAGE_0x80.
+	 */
+	pg_num = reg >> 0x8;
+	if (pg_num == 0x80)
+		pg_num = PAGE_0X80;
+	else if (pg_num >= 0xE)
+		return false;
+
+	reg_tbl = wcd9335_reg[pg_num];
+	reg_offset = reg & 0xFF;
+
+	if (reg_tbl)
+		return reg_tbl[reg_offset];
+	else
+		return false;
+}
+
+static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	/*
+	 * registers from 0x000 to 0x0FF are volatile because
+	 * this space contains registers related to interrupt
+	 * status, mask etc
+	 */
+	if (reg < 0x100)
+		return true;
+
+	/* IIR Coeff registers are not cacheable */
+	if ((reg >= WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL) &&
+	    (reg <= WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL))
+		return true;
+
+	if ((reg >= WCD9335_CDC_ANC0_IIR_COEFF_1_CTL) &&
+	    (reg <= WCD9335_CDC_ANC0_FB_GAIN_CTL))
+		return true;
+
+	if ((reg >= WCD9335_CDC_ANC1_IIR_COEFF_1_CTL) &&
+	    (reg <= WCD9335_CDC_ANC1_FB_GAIN_CTL))
+		return true;
+	/*
+	 * CPE inbox and outbox registers are volatile
+	 * since they can be updated in the codec hardware
+	 * to indicate CPE status
+	 */
+	if (reg >= WCD9335_CPE_SS_MEM_PTR_0 &&
+	    reg <= WCD9335_CPE_SS_OUTBOX2_ACK)
+		return true;
+
+	if (reg >= WCD9335_RCO_CAL_OUT_1 &&
+	    reg <= WCD9335_RCO_CAL_OUT_5)
+		return true;
+
+	switch (reg) {
+	case WCD9335_CPE_SS_INBOX1_TRG:
+	case WCD9335_CPE_SS_INBOX2_TRG:
+	case WCD9335_SWR_AHB_BRIDGE_WR_DATA_0:
+	case WCD9335_SWR_AHB_BRIDGE_WR_DATA_1:
+	case WCD9335_SWR_AHB_BRIDGE_WR_DATA_2:
+	case WCD9335_SWR_AHB_BRIDGE_WR_DATA_3:
+	case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0:
+	case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1:
+	case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2:
+	case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3:
+	case WCD9335_SWR_AHB_BRIDGE_RD_DATA_0:
+	case WCD9335_SWR_AHB_BRIDGE_RD_DATA_1:
+	case WCD9335_SWR_AHB_BRIDGE_RD_DATA_2:
+	case WCD9335_SWR_AHB_BRIDGE_RD_DATA_3:
+	case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0:
+	case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1:
+	case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2:
+	case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3:
+	case WCD9335_ANA_BIAS:
+	case WCD9335_ANA_CLK_TOP:
+	case WCD9335_ANA_RCO:
+	case WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL:
+	case WCD9335_ANA_MBHC_RESULT_3:
+	case WCD9335_ANA_MBHC_RESULT_2:
+	case WCD9335_ANA_MBHC_RESULT_1:
+	case WCD9335_ANA_MBHC_MECH:
+	case WCD9335_ANA_MBHC_ELECT:
+	case WCD9335_ANA_MBHC_ZDET:
+	case WCD9335_ANA_MICB2:
+	case WCD9335_CPE_SS_SS_ERROR_INT_STATUS:
+	case WCD9335_CPE_SS_SS_ERROR_INT_MASK:
+	case WCD9335_CPE_SS_SS_ERROR_INT_CLEAR:
+	case WCD9335_CPE_SS_STATUS:
+	case WCD9335_CPE_SS_BACKUP_INT:
+	case WCD9335_CPE_SS_CFG:
+	case WCD9335_SOC_MAD_MAIN_CTL_1:
+	case WCD9335_SOC_MAD_AUDIO_CTL_3:
+	case WCD9335_SOC_MAD_AUDIO_CTL_4:
+	case WCD9335_FLYBACK_EN:
+	case WCD9335_ANA_RX_SUPPLIES:
+	case WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
+	case WCD9335_SIDO_SIDO_CCL_2:
+	case WCD9335_SIDO_SIDO_CCL_4:
+	case WCD9335_DATA_HUB_NATIVE_FIFO_STATUS:
+	case WCD9335_MBHC_FSM_STATUS:
+	case WCD9335_SPLINE_SRC0_STATUS:
+	case WCD9335_SPLINE_SRC1_STATUS:
+	case WCD9335_SPLINE_SRC2_STATUS:
+	case WCD9335_SPLINE_SRC3_STATUS:
+	case WCD9335_SIDO_SIDO_TEST_2:
+	case WCD9335_SIDO_SIDO_CCL_8:
+	case WCD9335_BIAS_VBG_FINE_ADJ:
+	case WCD9335_VBADC_ADC_DOUTMSB:
+	case WCD9335_VBADC_ADC_DOUTLSB:
+	case WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL:
+	case WCD9335_ANA_BUCK_CTL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct regmap_config wcd9335_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wcd9335_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wcd9335_defaults),
+	.max_register = WCD9335_MAX_REGISTER,
+	.volatile_reg = wcd9335_is_volatile_register,
+	.readable_reg = wcd9335_is_readable_register,
+	.can_multi_write = true,
+};
diff --git a/asoc/codecs/wcd9335-tables.c b/asoc/codecs/wcd9335-tables.c
new file mode 100644
index 0000000..7df2778
--- /dev/null
+++ b/asoc/codecs/wcd9335-tables.c
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include "wcd9335_registers.h"
+
+#define WCD9335_REG(reg)  ((reg) & 0xFF)
+
+const u8 wcd9335_page0_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE0_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_CLK_BYPASS)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_CLK_GATE)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_CLK_MCLK_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_RST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_INT_MASK)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_INT_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CODEC_RPM_INT_CLEAR)] = 0,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_I2S_CLK)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_NATIVE_FIFO_SYNC)] = 1,
+	[WCD9335_REG(WCD9335_DATA_HUB_NATIVE_FIFO_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_INTR_CFG)] = 1,
+	[WCD9335_REG(WCD9335_INTR_CLR_COMMIT)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN1_MASK0)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_MASK1)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_MASK2)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_MASK3)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_STATUS0)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_STATUS1)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_STATUS2)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_STATUS3)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN1_CLEAR0)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN1_CLEAR1)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN1_CLEAR2)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN1_CLEAR3)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN2_MASK0)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_MASK1)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_MASK2)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_MASK3)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_STATUS0)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_STATUS1)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_STATUS2)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_STATUS3)] = 1,
+	[WCD9335_REG(WCD9335_INTR_PIN2_CLEAR0)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN2_CLEAR1)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN2_CLEAR2)] = 0,
+	[WCD9335_REG(WCD9335_INTR_PIN2_CLEAR3)] = 0,
+	[WCD9335_REG(WCD9335_INTR_LEVEL0)] = 1,
+	[WCD9335_REG(WCD9335_INTR_LEVEL1)] = 1,
+	[WCD9335_REG(WCD9335_INTR_LEVEL2)] = 1,
+	[WCD9335_REG(WCD9335_INTR_LEVEL3)] = 1,
+	[WCD9335_REG(WCD9335_INTR_BYPASS0)] = 1,
+	[WCD9335_REG(WCD9335_INTR_BYPASS1)] = 1,
+	[WCD9335_REG(WCD9335_INTR_BYPASS2)] = 1,
+	[WCD9335_REG(WCD9335_INTR_BYPASS3)] = 1,
+	[WCD9335_REG(WCD9335_INTR_SET0)] = 1,
+	[WCD9335_REG(WCD9335_INTR_SET1)] = 1,
+	[WCD9335_REG(WCD9335_INTR_SET2)] = 1,
+	[WCD9335_REG(WCD9335_INTR_SET3)] = 1,
+};
+
+const u8 wcd9335_page1_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE1_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_8)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_9)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_L_VAL_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_L_VAL_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_DSM_FRAC_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_DSM_FRAC_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_FLL_MODE)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_STATUS_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_STATUS_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_STATUS_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_FLL_STATUS_3)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_8)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_9)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_L_VAL_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_L_VAL_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_DSM_FRAC_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_DSM_FRAC_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_FLL_MODE)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_STATUS_0)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_STATUS_1)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_STATUS_2)] = 1,
+	[WCD9335_REG(WCD9335_I2S_FLL_STATUS_3)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_8)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_USER_CTL_9)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_L_VAL_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_L_VAL_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_DSM_FRAC_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_DSM_FRAC_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_FLL_MODE)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_STATUS_0)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_STATUS_1)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_STATUS_2)] = 1,
+	[WCD9335_REG(WCD9335_SB_FLL_STATUS_3)] = 1,
+};
+
+const u8 wcd9335_page2_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE2_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_4)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_5)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_6)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_7)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_8)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_9)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_10)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_11)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_12)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_13)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_14)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_15)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_TRG)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_TRG)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_0)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_1)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_2)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_3)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_4)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_5)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_6)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_7)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_8)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_9)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_10)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_11)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_12)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_13)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_14)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX1_15)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_4)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_5)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_6)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_7)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_8)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_9)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_10)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_11)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_12)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_13)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_14)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_15)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_0)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_1)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_2)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_3)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_4)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_5)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_6)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_7)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_8)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_9)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_10)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_11)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_12)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_13)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_14)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_INBOX2_15)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_0)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_1)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_2)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_3)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_4)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_5)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_6)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_7)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_8)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_9)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_10)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_11)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_12)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_13)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_14)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_15)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_ACK)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_ACK)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_EC_BUF_INT_PERIOD)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_US_BUF_INT_PERIOD)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_US_EC_MUX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_MAD_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_CPAR_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_TX_PP_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_DMIC0_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_DMIC1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_DMIC2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_DMIC_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_SVA_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_CPAR_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_WDOG_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_BACKUP_INT)] = 0,
+	[WCD9335_REG(WCD9335_CPE_SS_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_CPE_OCD_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_MASK)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_CLEAR)] = 0,
+	[WCD9335_REG(WCD9335_SOC_MAD_MAIN_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_MAIN_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_8)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_4)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_5)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_6)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_7)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_8)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL)] = 1,
+	[WCD9335_REG(WCD9335_SOC_MAD_INP_SEL)] = 1,
+};
+
+const u8 wcd9335_page6_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE6_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_ANA_BIAS)] = 1,
+	[WCD9335_REG(WCD9335_ANA_CLK_TOP)] = 1,
+	[WCD9335_REG(WCD9335_ANA_RCO)] = 1,
+	[WCD9335_REG(WCD9335_ANA_BUCK_VOUT_A)] = 1,
+	[WCD9335_REG(WCD9335_ANA_BUCK_VOUT_D)] = 1,
+	[WCD9335_REG(WCD9335_ANA_BUCK_CTL)] = 1,
+	[WCD9335_REG(WCD9335_ANA_BUCK_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_ANA_RX_SUPPLIES)] = 1,
+	[WCD9335_REG(WCD9335_ANA_HPH)] = 1,
+	[WCD9335_REG(WCD9335_ANA_EAR)] = 1,
+	[WCD9335_REG(WCD9335_ANA_LO_1_2)] = 1,
+	[WCD9335_REG(WCD9335_ANA_LO_3_4)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MAD_SETUP)] = 1,
+	[WCD9335_REG(WCD9335_ANA_AMIC1)] = 1,
+	[WCD9335_REG(WCD9335_ANA_AMIC2)] = 1,
+	[WCD9335_REG(WCD9335_ANA_AMIC3)] = 1,
+	[WCD9335_REG(WCD9335_ANA_AMIC4)] = 1,
+	[WCD9335_REG(WCD9335_ANA_AMIC5)] = 1,
+	[WCD9335_REG(WCD9335_ANA_AMIC6)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_MECH)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_ELECT)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_ZDET)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_RESULT_1)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_RESULT_2)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_RESULT_3)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN0)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN1)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN2)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN3)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN4)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN5)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN6)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MBHC_BTN7)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MICB1)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MICB2)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MICB2_RAMP)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MICB3)] = 1,
+	[WCD9335_REG(WCD9335_ANA_MICB4)] = 1,
+	[WCD9335_REG(WCD9335_ANA_VBADC)] = 1,
+	[WCD9335_REG(WCD9335_BIAS_CTL)] = 1,
+	[WCD9335_REG(WCD9335_BIAS_VBG_FINE_ADJ)] = 1,
+	[WCD9335_REG(WCD9335_CLOCK_TEST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CTRL_1)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CTRL_2)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL_1)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL_2)] = 1,
+	[WCD9335_REG(WCD9335_RCO_TEST_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL_OUT_1)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL_OUT_2)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL_OUT_3)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL_OUT_4)] = 1,
+	[WCD9335_REG(WCD9335_RCO_CAL_OUT_5)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_MODE_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_MODE_2)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_MODE_3)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_MODE_4)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_VCL_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_VCL_2)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_VCL_3)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_2)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_3)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_4)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_5)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_6)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_7)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_8)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_9)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CCL_10)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_FILTER_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_FILTER_2)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_2)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_3)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_EXT_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_EXT_2)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_OUT_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_OUT_2)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_TEST_1)] = 1,
+	[WCD9335_REG(WCD9335_SIDO_SIDO_TEST_2)] = 1,
+	[WCD9335_REG(WCD9335_MBHC_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_MBHC_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_MBHC_PLUG_DETECT_CTL)] = 1,
+	[WCD9335_REG(WCD9335_MBHC_ZDET_ANA_CTL)] = 1,
+	[WCD9335_REG(WCD9335_MBHC_ZDET_RAMP_CTL)] = 1,
+	[WCD9335_REG(WCD9335_MBHC_FSM_DEBUG)] = 1,
+	[WCD9335_REG(WCD9335_MBHC_TEST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_SUBBLOCK_EN)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_IBIAS_FE)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_BIAS_ADC)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_FE_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_ADC_REF)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_ADC_IO)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_ADC_SAR)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_DEBUG)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_ADC_DOUTMSB)] = 1,
+	[WCD9335_REG(WCD9335_VBADC_ADC_DOUTLSB)] = 1,
+	[WCD9335_REG(WCD9335_LDOH_MODE)] = 1,
+	[WCD9335_REG(WCD9335_LDOH_BIAS)] = 1,
+	[WCD9335_REG(WCD9335_LDOH_STB_LOADS)] = 1,
+	[WCD9335_REG(WCD9335_LDOH_SLOWRAMP)] = 1,
+	[WCD9335_REG(WCD9335_MICB1_TEST_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_MICB1_TEST_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_MICB1_TEST_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_MICB2_TEST_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_MICB2_TEST_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_MICB2_TEST_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_MICB3_TEST_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_MICB3_TEST_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_MICB3_TEST_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_MICB4_TEST_CTL_1)] = 1,
+	[WCD9335_REG(WCD9335_MICB4_TEST_CTL_2)] = 1,
+	[WCD9335_REG(WCD9335_MICB4_TEST_CTL_3)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_ADC_VCM)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_BIAS_ATEST)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_ADC_INT1_IB)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_ADC_INT2_IB)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_CTL)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_START)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_STOP_9P6M)] = 1,
+	[WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_STOP_12P288M)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_TEST_EN)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_ADC_IB)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_ATEST_REFCTL)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_TEST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_TEST_BLK_EN)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_TXFE_CLKDIV)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_SAR1_ERR)] = 1,
+	[WCD9335_REG(WCD9335_TX_1_2_SAR2_ERR)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_TEST_EN)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_ADC_IB)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_ATEST_REFCTL)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_TEST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_TEST_BLK_EN)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_TXFE_CLKDIV)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_SAR1_ERR)] = 1,
+	[WCD9335_REG(WCD9335_TX_3_4_SAR2_ERR)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_TEST_EN)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_ADC_IB)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_ATEST_REFCTL)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_TEST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_TEST_BLK_EN)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_TXFE_CLKDIV)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_SAR1_ERR)] = 1,
+	[WCD9335_REG(WCD9335_TX_5_6_SAR2_ERR)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_MODE_1)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_MODE_2)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_MODE_3)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_CTRL_VCL_1)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_CTRL_VCL_2)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_1)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_2)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_3)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_4)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_5)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_BUCK_TMUX_A_D)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_BUCK_SW_DRV_CNTL)] = 1,
+	[WCD9335_REG(WCD9335_CLASSH_SPARE)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_EN)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_1)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_2)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_3)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_4)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_5)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_6)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_7)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_8)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_9)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_1)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_2)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_3)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_4)] = 1,
+	[WCD9335_REG(WCD9335_FLYBACK_TEST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_RX_AUX_SW_CTL)] = 1,
+	[WCD9335_REG(WCD9335_RX_PA_AUX_IN_CONN)] = 1,
+	[WCD9335_REG(WCD9335_RX_TIMER_DIV)] = 1,
+	[WCD9335_REG(WCD9335_RX_OCP_CTL)] = 1,
+	[WCD9335_REG(WCD9335_RX_OCP_COUNT)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_EAR_DAC)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_EAR_AMP)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_HPH_LDO)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_HPH_PA)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_HPH_RDAC_LDO)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_HPH_CNP1)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_HPH_LOWPOWER)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_PA)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_REF)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_LDO)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_SELO_DAC_PA)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_BUCK_RST)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_BUCK_VREF_ERRAMP)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_FLYB_ERRAMP)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_FLYB_BUFF)] = 1,
+	[WCD9335_REG(WCD9335_RX_BIAS_FLYB_MID_RST)] = 1,
+	[WCD9335_REG(WCD9335_HPH_L_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_HPH_R_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_HPH_CNP_EN)] = 1,
+	[WCD9335_REG(WCD9335_HPH_CNP_WG_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_CNP_WG_TIME)] = 1,
+	[WCD9335_REG(WCD9335_HPH_OCP_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_AUTO_CHOP)] = 1,
+	[WCD9335_REG(WCD9335_HPH_CHOP_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_PA_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_HPH_PA_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_HPH_L_EN)] = 1,
+	[WCD9335_REG(WCD9335_HPH_L_TEST)] = 1,
+	[WCD9335_REG(WCD9335_HPH_L_ATEST)] = 1,
+	[WCD9335_REG(WCD9335_HPH_R_EN)] = 1,
+	[WCD9335_REG(WCD9335_HPH_R_TEST)] = 1,
+	[WCD9335_REG(WCD9335_HPH_R_ATEST)] = 1,
+	[WCD9335_REG(WCD9335_HPH_RDAC_CLK_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_HPH_RDAC_CLK_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_HPH_RDAC_LDO_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_REFBUFF_UHQA_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_REFBUFF_LP_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_L_DAC_CTL)] = 1,
+	[WCD9335_REG(WCD9335_HPH_R_DAC_CTL)] = 1,
+	[WCD9335_REG(WCD9335_EAR_EN_REG)] = 1,
+	[WCD9335_REG(WCD9335_EAR_CMBUFF)] = 1,
+	[WCD9335_REG(WCD9335_EAR_ICTL)] = 1,
+	[WCD9335_REG(WCD9335_EAR_EN_DBG_CTL)] = 1,
+	[WCD9335_REG(WCD9335_EAR_CNP)] = 1,
+	[WCD9335_REG(WCD9335_EAR_DAC_CTL_ATEST)] = 1,
+	[WCD9335_REG(WCD9335_EAR_STATUS_REG)] = 1,
+	[WCD9335_REG(WCD9335_EAR_OUT_SHORT)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_MISC)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_LO2_COMPANDER)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_LO1_COMPANDER)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_COMMON)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_BYPASS_EN)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_CNP)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_CORE_OUT_PROG)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_LDO_OUT_PROG)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_COM_PA_FREQ)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_RESERVED_REG)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_LO1_STATUS_1)] = 1,
+	[WCD9335_REG(WCD9335_DIFF_LO_LO1_STATUS_2)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_COM1)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_COM2)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_LO3_GAIN)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_LO3_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_LO4_GAIN)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_LO4_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_LO3_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_SE_LO_LO4_STATUS)] = 1,
+};
+
+const u8 wcd9335_page10_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE10_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_CLK_RESET_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_MODE_1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_MODE_2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_FF_SHIFT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_FB_SHIFT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_LPF_FF_A_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_LPF_FF_B_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_LPF_FB_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_SMLPF_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_IIR_ADAPT_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_IIR_COEFF_1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_IIR_COEFF_2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_FF_A_GAIN_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_FF_B_GAIN_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC0_FB_GAIN_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_CLK_RESET_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_MODE_1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_MODE_2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_FF_SHIFT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_FB_SHIFT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_LPF_FF_A_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_LPF_FF_B_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_LPF_FB_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_SMLPF_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_IIR_ADAPT_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_IIR_COEFF_1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_IIR_COEFF_2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_FF_A_GAIN_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_FF_B_GAIN_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_ANC1_FB_GAIN_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_192_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_192_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0)] = 1,
+};
+
+const u8 wcd9335_page11_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE11_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_VOL_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_VOL_MIX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_SEC0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_SEC1)] = 1,
+};
+
+const u8 wcd9335_page12_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE12_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_CRC)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_DLY_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_DECAY_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_HPH_V_PA)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_EAR_V_PA)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_HPH_V_HD)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_EAR_V_HD)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_K1_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_K1_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_K2_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_K2_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_IDLE_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_IDLE_HPH)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_IDLE_EAR)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_TEST0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_TEST1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLSH_OVR_VREF)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_0)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_1)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_2)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_3)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_0)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_1)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_2)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_3)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG)] = 1,
+	[WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_CFG)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_RF_PROC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_RF_PROC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_DEBUG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON)] = 0,
+	[WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC0_CLK_RST_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC0_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC1_CLK_RST_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC1_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC2_CLK_RST_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC2_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC3_CLK_RST_CTL_0)] = 1,
+	[WCD9335_REG(WCD9335_SPLINE_SRC3_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] = 1,
+};
+
+const u8 wcd9335_page13_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE13_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_ANC_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD)] = 1,
+	[WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG0)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG1)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG2)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG3)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG4)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG5)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG6)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG7)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_WR_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_WR_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_LUT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_RD_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_RD_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_WR_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_WR_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_LUT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_RD_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_RD_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_LUT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_LUT)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB)] = 1,
+	[WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB)] = 1,
+};
+
+const u8 wcd9335_page_0x80_reg_readable[WCD9335_PAGE_SIZE] = {
+	[WCD9335_REG(WCD9335_PAGE80_PAGE_REGISTER)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_BIST_MODE_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_RF_PA_ON_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_INTR1_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_INTR2_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_SWR_DATA_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_SWR_CLK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_SLIMBUS_DATA2_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2C_CLK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2C_DATA_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_RX_SD0_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_RX_SD1_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_RX_SCK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_RX_WS_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_TX_SD0_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_TX_SD1_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_TX_SCK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_I2S_TX_WS_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_DMIC1_CLK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_DMIC1_DATA_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_DMIC2_CLK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_DMIC2_DATA_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_DMIC3_CLK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_DMIC3_DATA_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_JTDI_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_JTDO_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_JTMS_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_JTCK_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TLMM_JTRST_PINCFG)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_0)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_1)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_2)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_3)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_0)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_1)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_2)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_3)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PAD_DRVCTL)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_PIN_STATUS)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_NPL_DLY_TEST_1)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_NPL_DLY_TEST_2)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_MEM_CTRL)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_BUS_SEL)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_JTAG)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_1)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_2)] = 1,
+	[WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_3)] = 1,
+};
+
+const u8 *wcd9335_reg[WCD9335_NUM_PAGES] = {
+	[PAGE_0] = wcd9335_page0_reg_readable,
+	[PAGE_1] = wcd9335_page1_reg_readable,
+	[PAGE_2] = wcd9335_page2_reg_readable,
+	[PAGE_6] = wcd9335_page6_reg_readable,
+	[PAGE_10] = wcd9335_page10_reg_readable,
+	[PAGE_11] = wcd9335_page11_reg_readable,
+	[PAGE_12] = wcd9335_page12_reg_readable,
+	[PAGE_13] = wcd9335_page13_reg_readable,
+	[PAGE_0X80] = wcd9335_page_0x80_reg_readable,
+};
diff --git a/asoc/codecs/wcd9335.c b/asoc/codecs/wcd9335.c
new file mode 100644
index 0000000..26a5a9d
--- /dev/null
+++ b/asoc/codecs/wcd9335.c
@@ -0,0 +1,14215 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <soc/swr-wcd.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/info.h>
+#include "core.h"
+#include "pdata.h"
+#include "wcd9335.h"
+#include "wcd-mbhc-v2.h"
+#include "wcd9xxx-common-v2.h"
+#include "wcd9xxx-resmgr-v2.h"
+#include "wcd9xxx-irq.h"
+#include "wcd9335_registers.h"
+#include "wcd9335_irq.h"
+#include "wcd_cpe_core.h"
+#include "wcdcal-hwdep.h"
+#include "wcd-mbhc-v2-api.h"
+
+#define TASHA_RX_PORT_START_NUMBER  16
+
+#define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			    SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+			    SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+/* Fractional Rates */
+#define WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100)
+
+#define WCD9335_MIX_RATES_MASK (SNDRV_PCM_RATE_48000 |\
+				SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define TASHA_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+				  SNDRV_PCM_FMTBIT_S24_LE | \
+				  SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define TASHA_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+				  SNDRV_PCM_FMTBIT_S24_LE | \
+				  SNDRV_PCM_FMTBIT_S24_3LE | \
+				  SNDRV_PCM_FMTBIT_S32_LE)
+
+#define TASHA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+/*
+ * Timeout in milli seconds and it is the wait time for
+ * slim channel removal interrupt to receive.
+ */
+#define TASHA_SLIM_CLOSE_TIMEOUT 1000
+#define TASHA_SLIM_IRQ_OVERFLOW (1 << 0)
+#define TASHA_SLIM_IRQ_UNDERFLOW (1 << 1)
+#define TASHA_SLIM_IRQ_PORT_CLOSED (1 << 2)
+#define TASHA_MCLK_CLK_12P288MHZ 12288000
+#define TASHA_MCLK_CLK_9P6MHZ 9600000
+
+#define TASHA_SLIM_PGD_PORT_INT_TX_EN0 (TASHA_SLIM_PGD_PORT_INT_EN0 + 2)
+
+#define TASHA_NUM_INTERPOLATORS 9
+#define TASHA_NUM_DECIMATORS 9
+
+#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE))
+#define TASHA_MAD_AUDIO_FIRMWARE_PATH "wcd9335/wcd9335_mad_audio.bin"
+#define TASHA_CPE_SS_ERR_STATUS_MEM_ACCESS (1 << 0)
+#define TASHA_CPE_SS_ERR_STATUS_WDOG_BITE (1 << 1)
+
+#define TASHA_CPE_FATAL_IRQS \
+	(TASHA_CPE_SS_ERR_STATUS_WDOG_BITE | \
+	 TASHA_CPE_SS_ERR_STATUS_MEM_ACCESS)
+
+#define SLIM_BW_CLK_GEAR_9 6200000
+#define SLIM_BW_UNVOTE 0
+
+#define CPE_FLL_CLK_75MHZ 75000000
+#define CPE_FLL_CLK_150MHZ 150000000
+#define WCD9335_REG_BITS 8
+
+#define WCD9335_MAX_VALID_ADC_MUX  13
+#define WCD9335_INVALID_ADC_MUX 9
+
+#define TASHA_DIG_CORE_REG_MIN  WCD9335_CDC_ANC0_CLK_RESET_CTL
+#define TASHA_DIG_CORE_REG_MAX  0xDFF
+
+/* Convert from vout ctl to micbias voltage in mV */
+#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50)
+
+#define TASHA_ZDET_NUM_MEASUREMENTS 150
+#define TASHA_MBHC_GET_C1(c)  ((c & 0xC000) >> 14)
+#define TASHA_MBHC_GET_X1(x)  (x & 0x3FFF)
+/* z value compared in milliOhm */
+#define TASHA_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
+#define TASHA_MBHC_ZDET_CONST  (86 * 16384)
+#define TASHA_MBHC_MOISTURE_VREF  V_45_MV
+#define TASHA_MBHC_MOISTURE_IREF  I_3P0_UA
+
+#define TASHA_VERSION_ENTRY_SIZE 17
+
+#define WCD9335_AMIC_PWR_LEVEL_LP 0
+#define WCD9335_AMIC_PWR_LEVEL_DEFAULT 1
+#define WCD9335_AMIC_PWR_LEVEL_HP 2
+#define WCD9335_AMIC_PWR_LVL_MASK 0x60
+#define WCD9335_AMIC_PWR_LVL_SHIFT 0x5
+
+#define WCD9335_DEC_PWR_LVL_MASK 0x06
+#define WCD9335_DEC_PWR_LVL_LP 0x02
+#define WCD9335_DEC_PWR_LVL_HP 0x04
+#define WCD9335_DEC_PWR_LVL_DF 0x00
+#define WCD9335_STRING_LEN 100
+
+#define CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
+
+static int cpe_debug_mode;
+
+#define TASHA_MAX_MICBIAS 4
+#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone"
+#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone"
+#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone"
+#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone"
+
+#define DAPM_LDO_H_STANDALONE "LDO_H"
+module_param(cpe_debug_mode, int, 0664);
+MODULE_PARM_DESC(cpe_debug_mode, "boot cpe in debug mode");
+
+#define TASHA_DIG_CORE_COLLAPSE_TIMER_MS  (5 * 1000)
+
+#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH    64
+
+static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
+	"cdc-vdd-mic-bias",
+};
+
+enum {
+	POWER_COLLAPSE,
+	POWER_RESUME,
+};
+
+enum tasha_sido_voltage {
+	SIDO_VOLTAGE_SVS_MV = 950,
+	SIDO_VOLTAGE_NOMINAL_MV = 1100,
+};
+
+static enum codec_variant codec_ver;
+
+static int dig_core_collapse_enable = 1;
+module_param(dig_core_collapse_enable, int, 0664);
+MODULE_PARM_DESC(dig_core_collapse_enable, "enable/disable power gating");
+
+/* dig_core_collapse timer in seconds */
+static int dig_core_collapse_timer = (TASHA_DIG_CORE_COLLAPSE_TIMER_MS/1000);
+module_param(dig_core_collapse_timer, int, 0664);
+MODULE_PARM_DESC(dig_core_collapse_timer, "timer for power gating");
+
+/* SVS Scaling enable/disable */
+static int svs_scaling_enabled = 1;
+module_param(svs_scaling_enabled, int, 0664);
+MODULE_PARM_DESC(svs_scaling_enabled, "enable/disable svs scaling");
+
+/* SVS buck setting */
+static int sido_buck_svs_voltage = SIDO_VOLTAGE_SVS_MV;
+module_param(sido_buck_svs_voltage, int, 0664);
+MODULE_PARM_DESC(sido_buck_svs_voltage,
+			"setting for SVS voltage for SIDO BUCK");
+
+#define TASHA_TX_UNMUTE_DELAY_MS	40
+
+static int tx_unmute_delay = TASHA_TX_UNMUTE_DELAY_MS;
+module_param(tx_unmute_delay, int, 0664);
+MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path");
+
+static struct afe_param_slimbus_slave_port_cfg tasha_slimbus_slave_port_cfg = {
+	.minor_version = 1,
+	.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
+	.slave_dev_pgd_la = 0,
+	.slave_dev_intfdev_la = 0,
+	.bit_width = 16,
+	.data_format = 0,
+	.num_channels = 1
+};
+
+struct tasha_mbhc_zdet_param {
+	u16 ldo_ctl;
+	u16 noff;
+	u16 nshift;
+	u16 btn5;
+	u16 btn6;
+	u16 btn7;
+};
+
+static struct afe_param_cdc_reg_page_cfg tasha_cdc_reg_page_cfg = {
+	.minor_version = AFE_API_VERSION_CDC_REG_PAGE_CFG,
+	.enable = 1,
+	.proc_id = AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_1,
+};
+
+static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_MAIN_CTL_1),
+		HW_MAD_AUDIO_ENABLE, 0x1, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_AUDIO_CTL_3),
+		HW_MAD_AUDIO_SLEEP_TIME, 0xF, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_AUDIO_CTL_4),
+		HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG),
+		MAD_AUDIO_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3),
+		MAD_AUDIO_INT_MASK_REG, 0x1, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3),
+		MAD_AUDIO_INT_STATUS_REG, 0x1, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3),
+		MAD_AUDIO_INT_CLEAR_REG, 0x1, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG),
+		VBAT_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3),
+		VBAT_INT_MASK_REG, 0x08, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3),
+		VBAT_INT_STATUS_REG, 0x08, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3),
+		VBAT_INT_CLEAR_REG, 0x08, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG),
+		VBAT_RELEASE_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3),
+		VBAT_RELEASE_INT_MASK_REG, 0x10, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3),
+		VBAT_RELEASE_INT_STATUS_REG, 0x10, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3),
+		VBAT_RELEASE_INT_CLEAR_REG, 0x10, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_WATERMARK_N, 0x1E, WCD9335_REG_BITS, 0x1
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_ENABLE_N, 0x1, WCD9335_REG_BITS, 0x1
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_WATERMARK_N, 0x1E, WCD9335_REG_BITS, 0x1
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_ENABLE_N, 0x1, WCD9335_REG_BITS, 0x1
+	},
+	{	1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_IIR_ADAPT_CTL),
+		AANC_FF_GAIN_ADAPTIVE, 0x4, WCD9335_REG_BITS, 0
+	},
+	{	1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_IIR_ADAPT_CTL),
+		AANC_FFGAIN_ADAPTIVE_EN, 0x8, WCD9335_REG_BITS, 0
+	},
+	{
+		1,
+		(TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_FF_A_GAIN_CTL),
+		AANC_GAIN_CONTROL, 0xFF, WCD9335_REG_BITS, 0
+	},
+};
+
+static struct afe_param_cdc_reg_cfg_data tasha_audio_reg_cfg = {
+	.num_registers = ARRAY_SIZE(audio_reg_cfg),
+	.reg_data = audio_reg_cfg,
+};
+
+static struct afe_param_id_cdc_aanc_version tasha_cdc_aanc_version = {
+	.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
+	.aanc_hw_version        = AANC_HW_BLOCK_VERSION_2,
+};
+
+enum {
+	VI_SENSE_1,
+	VI_SENSE_2,
+	AIF4_SWITCH_VALUE,
+	AUDIO_NOMINAL,
+	CPE_NOMINAL,
+	HPH_PA_DELAY,
+	ANC_MIC_AMIC1,
+	ANC_MIC_AMIC2,
+	ANC_MIC_AMIC3,
+	ANC_MIC_AMIC4,
+	ANC_MIC_AMIC5,
+	ANC_MIC_AMIC6,
+	CLASSH_CONFIG,
+};
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	AIF2_PB,
+	AIF2_CAP,
+	AIF3_PB,
+	AIF3_CAP,
+	AIF4_PB,
+	AIF_MIX1_PB,
+	AIF4_MAD_TX,
+	AIF4_VIFEED,
+	AIF5_CPE_TX,
+	NUM_CODEC_DAIS,
+};
+
+enum {
+	INTn_1_MIX_INP_SEL_ZERO = 0,
+	INTn_1_MIX_INP_SEL_DEC0,
+	INTn_1_MIX_INP_SEL_DEC1,
+	INTn_1_MIX_INP_SEL_IIR0,
+	INTn_1_MIX_INP_SEL_IIR1,
+	INTn_1_MIX_INP_SEL_RX0,
+	INTn_1_MIX_INP_SEL_RX1,
+	INTn_1_MIX_INP_SEL_RX2,
+	INTn_1_MIX_INP_SEL_RX3,
+	INTn_1_MIX_INP_SEL_RX4,
+	INTn_1_MIX_INP_SEL_RX5,
+	INTn_1_MIX_INP_SEL_RX6,
+	INTn_1_MIX_INP_SEL_RX7,
+
+};
+
+#define IS_VALID_NATIVE_FIFO_PORT(inp) \
+	((inp >= INTn_1_MIX_INP_SEL_RX0) && \
+	 (inp <= INTn_1_MIX_INP_SEL_RX3))
+
+enum {
+	INTn_2_INP_SEL_ZERO = 0,
+	INTn_2_INP_SEL_RX0,
+	INTn_2_INP_SEL_RX1,
+	INTn_2_INP_SEL_RX2,
+	INTn_2_INP_SEL_RX3,
+	INTn_2_INP_SEL_RX4,
+	INTn_2_INP_SEL_RX5,
+	INTn_2_INP_SEL_RX6,
+	INTn_2_INP_SEL_RX7,
+	INTn_2_INP_SEL_PROXIMITY,
+};
+
+enum {
+	INTERP_EAR = 0,
+	INTERP_HPHL,
+	INTERP_HPHR,
+	INTERP_LO1,
+	INTERP_LO2,
+	INTERP_LO3,
+	INTERP_LO4,
+	INTERP_SPKR1,
+	INTERP_SPKR2,
+};
+
+struct interp_sample_rate {
+	int sample_rate;
+	int rate_val;
+};
+
+static struct interp_sample_rate int_prim_sample_rate_val[] = {
+	{8000, 0x0},	/* 8K */
+	{16000, 0x1},	/* 16K */
+	{24000, -EINVAL},/* 24K */
+	{32000, 0x3},	/* 32K */
+	{48000, 0x4},	/* 48K */
+	{96000, 0x5},	/* 96K */
+	{192000, 0x6},	/* 192K */
+	{384000, 0x7},	/* 384K */
+	{44100, 0x8}, /* 44.1K */
+};
+
+static struct interp_sample_rate int_mix_sample_rate_val[] = {
+	{48000, 0x4},	/* 48K */
+	{96000, 0x5},	/* 96K */
+	{192000, 0x6},	/* 192K */
+};
+
+static const struct wcd9xxx_ch tasha_rx_chs[TASHA_RX_MAX] = {
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER, 0),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 1, 1),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 2, 2),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 3, 3),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 4, 4),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 5, 5),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 6, 6),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 7, 7),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 8, 8),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 9, 9),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 10, 10),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 11, 11),
+	WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 12, 12),
+};
+
+static const struct wcd9xxx_ch tasha_tx_chs[TASHA_TX_MAX] = {
+	WCD9XXX_CH(0, 0),
+	WCD9XXX_CH(1, 1),
+	WCD9XXX_CH(2, 2),
+	WCD9XXX_CH(3, 3),
+	WCD9XXX_CH(4, 4),
+	WCD9XXX_CH(5, 5),
+	WCD9XXX_CH(6, 6),
+	WCD9XXX_CH(7, 7),
+	WCD9XXX_CH(8, 8),
+	WCD9XXX_CH(9, 9),
+	WCD9XXX_CH(10, 10),
+	WCD9XXX_CH(11, 11),
+	WCD9XXX_CH(12, 12),
+	WCD9XXX_CH(13, 13),
+	WCD9XXX_CH(14, 14),
+	WCD9XXX_CH(15, 15),
+};
+
+static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = {
+	/* Needs to define in the same order of DAI enum definitions */
+	0,
+	BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX),
+	0,
+	BIT(AIF1_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX),
+	0,
+	BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX),
+	0,
+	0,
+	BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF5_CPE_TX),
+	0,
+	BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX),
+};
+
+static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
+	0,			/* AIF1_PB */
+	BIT(AIF2_CAP),		/* AIF1_CAP */
+	0,			/* AIF2_PB */
+	BIT(AIF1_CAP),		/* AIF2_CAP */
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR0 = 0,
+	IIR1,
+	IIR_MAX,
+};
+
+/* Each IIR has 5 Filter Stages */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_MAX,
+};
+
+enum {
+	COMPANDER_1, /* HPH_L */
+	COMPANDER_2, /* HPH_R */
+	COMPANDER_3, /* LO1_DIFF */
+	COMPANDER_4, /* LO2_DIFF */
+	COMPANDER_5, /* LO3_SE */
+	COMPANDER_6, /* LO4_SE */
+	COMPANDER_7, /* SWR SPK CH1 */
+	COMPANDER_8, /* SWR SPK CH2 */
+	COMPANDER_MAX,
+};
+
+enum {
+	SRC_IN_HPHL,
+	SRC_IN_LO1,
+	SRC_IN_HPHR,
+	SRC_IN_LO2,
+	SRC_IN_SPKRL,
+	SRC_IN_LO3,
+	SRC_IN_SPKRR,
+	SRC_IN_LO4,
+};
+
+enum {
+	SPLINE_SRC0,
+	SPLINE_SRC1,
+	SPLINE_SRC2,
+	SPLINE_SRC3,
+	SPLINE_SRC_MAX,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+static struct snd_soc_dai_driver tasha_dai[];
+static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv);
+
+static int tasha_config_compander(struct snd_soc_codec *, int, int);
+static void tasha_codec_set_tx_hold(struct snd_soc_codec *, u16, bool);
+static int tasha_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
+				  bool enable);
+
+/* Hold instance to soundwire platform device */
+struct tasha_swr_ctrl_data {
+	struct platform_device *swr_pdev;
+	struct ida swr_ida;
+};
+
+struct wcd_swr_ctrl_platform_data {
+	void *handle; /* holds codec private data */
+	int (*read)(void *handle, int reg);
+	int (*write)(void *handle, int reg, int val);
+	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
+	int (*clk)(void *handle, bool enable);
+	int (*handle_irq)(void *handle,
+			  irqreturn_t (*swrm_irq_handler)(int irq,
+							  void *data),
+			  void *swrm_handle,
+			  int action);
+};
+
+static struct wcd_mbhc_register
+	wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
+	WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
+			  WCD9335_ANA_MBHC_MECH, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+			  WCD9335_ANA_MBHC_MECH, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+			  WCD9335_ANA_MBHC_MECH, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+			  WCD9335_MBHC_PLUG_DETECT_CTL, 0x30, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+			  WCD9335_ANA_MBHC_ELECT, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+			  WCD9335_MBHC_PLUG_DETECT_CTL, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+			  WCD9335_ANA_MBHC_MECH, 0x04, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+			  WCD9335_ANA_MBHC_MECH, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+			  WCD9335_ANA_MBHC_MECH, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+			  WCD9335_ANA_MBHC_MECH, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+			  WCD9335_ANA_MBHC_ELECT, 0x06, 1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+			  WCD9335_ANA_MBHC_ELECT, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+			  WCD9335_MBHC_PLUG_DETECT_CTL, 0x0F, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+			  WCD9335_MBHC_CTL_1, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+			  WCD9335_MBHC_CTL_2, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+			  WCD9335_ANA_MBHC_RESULT_3, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+			  WCD9335_ANA_MBHC_RESULT_3, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+			  WCD9335_ANA_MBHC_RESULT_3, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+			  WCD9335_ANA_MBHC_RESULT_3, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+			  WCD9335_HPH_OCP_CTL, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+			  WCD9335_ANA_MBHC_RESULT_3, 0x07, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+			  WCD9335_ANA_MBHC_ELECT, 0x70, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+			  WCD9335_ANA_MBHC_RESULT_3, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+			  WCD9335_ANA_MICB2, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+			  WCD9335_HPH_CNP_WG_TIME, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+			  WCD9335_ANA_HPH, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+			  WCD9335_ANA_HPH, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+			  WCD9335_ANA_HPH, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+			  WCD9335_ANA_MBHC_RESULT_3, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
+			  0, 0, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
+			  WCD9335_ANA_MBHC_ZDET, 0x01, 0, 0),
+	/*
+	 * MBHC FSM status register is only available in Tasha 2.0.
+	 * So, init with 0 later once the version is known, then values
+	 * will be updated.
+	 */
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
+			  0, 0, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
+			  WCD9335_MBHC_CTL_2, 0x70, 4, 0),
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+	.mbhc_sw_intr =  WCD9335_IRQ_MBHC_SW_DET,
+	.mbhc_btn_press_intr = WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
+	.mbhc_btn_release_intr = WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
+	.mbhc_hs_ins_intr = WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	.mbhc_hs_rem_intr = WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
+	.hph_left_ocp = WCD9335_IRQ_HPH_PA_OCPL_FAULT,
+	.hph_right_ocp = WCD9335_IRQ_HPH_PA_OCPR_FAULT,
+};
+
+struct wcd_vbat {
+	bool is_enabled;
+	bool adc_config;
+	/* Variables to cache Vbat ADC output values */
+	u16 dcp1;
+	u16 dcp2;
+};
+
+struct hpf_work {
+	struct tasha_priv *tasha;
+	u8 decimator;
+	u8 hpf_cut_off_freq;
+	struct delayed_work dwork;
+};
+
+#define WCD9335_SPK_ANC_EN_DELAY_MS 350
+static int spk_anc_en_delay = WCD9335_SPK_ANC_EN_DELAY_MS;
+module_param(spk_anc_en_delay, int, 0664);
+MODULE_PARM_DESC(spk_anc_en_delay, "delay to enable anc in speaker path");
+
+struct spk_anc_work {
+	struct tasha_priv *tasha;
+	struct delayed_work dwork;
+};
+
+struct tx_mute_work {
+	struct tasha_priv *tasha;
+	u8 decimator;
+	struct delayed_work dwork;
+};
+
+struct tasha_priv {
+	struct device *dev;
+	struct wcd9xxx *wcd9xxx;
+
+	struct snd_soc_codec *codec;
+	u32 adc_count;
+	u32 rx_bias_count;
+	s32 dmic_0_1_clk_cnt;
+	s32 dmic_2_3_clk_cnt;
+	s32 dmic_4_5_clk_cnt;
+	s32 ldo_h_users;
+	s32 micb_ref[TASHA_MAX_MICBIAS];
+	s32 pullup_ref[TASHA_MAX_MICBIAS];
+
+	u32 anc_slot;
+	bool anc_func;
+
+	/* Vbat module */
+	struct wcd_vbat vbat;
+
+	/* cal info for codec */
+	struct fw_info *fw_data;
+
+	/*track tasha interface type*/
+	u8 intf_type;
+
+	/* num of slim ports required */
+	struct wcd9xxx_codec_dai_data  dai[NUM_CODEC_DAIS];
+
+	/* SoundWire data structure */
+	struct tasha_swr_ctrl_data *swr_ctrl_data;
+	int nr;
+
+	/*compander*/
+	int comp_enabled[COMPANDER_MAX];
+
+	/* Maintain the status of AUX PGA */
+	int aux_pga_cnt;
+	u8 aux_l_gain;
+	u8 aux_r_gain;
+
+	bool spkr_pa_widget_on;
+	struct regulator *spkdrv_reg;
+	struct regulator *spkdrv2_reg;
+
+	bool mbhc_started;
+	/* class h specific data */
+	struct wcd_clsh_cdc_data clsh_d;
+
+	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
+	/*
+	 * list used to save/restore registers at start and
+	 * end of impedance measurement
+	 */
+	struct list_head reg_save_restore;
+
+	/* handle to cpe core */
+	struct wcd_cpe_core *cpe_core;
+	u32 current_cpe_clk_freq;
+	enum tasha_sido_voltage sido_voltage;
+	int sido_ccl_cnt;
+
+	u32 ana_rx_supplies;
+	/* Multiplication factor used for impedance detection */
+	int zdet_gain_mul_fact;
+
+	/* to track the status */
+	unsigned long status_mask;
+
+	struct work_struct tasha_add_child_devices_work;
+	struct wcd_swr_ctrl_platform_data swr_plat_data;
+
+	/* Port values for Rx and Tx codec_dai */
+	unsigned int rx_port_value[TASHA_RX_MAX];
+	unsigned int tx_port_value;
+
+	unsigned int vi_feed_value;
+	/* Tasha Interpolator Mode Select for EAR, HPH_L and HPH_R */
+	u32 hph_mode;
+
+	u16 prim_int_users[TASHA_NUM_INTERPOLATORS];
+	int spl_src_users[SPLINE_SRC_MAX];
+
+	struct wcd9xxx_resmgr_v2 *resmgr;
+	struct delayed_work power_gate_work;
+	struct mutex power_lock;
+	struct mutex sido_lock;
+
+	/* mbhc module */
+	struct wcd_mbhc mbhc;
+	struct blocking_notifier_head notifier;
+	struct mutex micb_lock;
+
+	struct clk *wcd_ext_clk;
+	struct clk *wcd_native_clk;
+	struct mutex swr_read_lock;
+	struct mutex swr_write_lock;
+	struct mutex swr_clk_lock;
+	int swr_clk_users;
+	int native_clk_users;
+	int (*zdet_gpio_cb)(struct snd_soc_codec *codec, bool high);
+
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+	int power_active_ref;
+
+	struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
+
+	int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
+				      enum wcd9335_codec_event);
+	int spkr_gain_offset;
+	int spkr_mode;
+	int ear_spkr_gain;
+	struct hpf_work tx_hpf_work[TASHA_NUM_DECIMATORS];
+	struct tx_mute_work tx_mute_dwork[TASHA_NUM_DECIMATORS];
+	struct spk_anc_work spk_anc_dwork;
+	struct mutex codec_mutex;
+	int hph_l_gain;
+	int hph_r_gain;
+	int rx_7_count;
+	int rx_8_count;
+	bool clk_mode;
+	bool clk_internal;
+	/* Lock to prevent multiple functions voting at same time */
+	struct mutex sb_clk_gear_lock;
+	/* Count for functions voting or un-voting */
+	u32 ref_count;
+	/* Lock to protect mclk enablement */
+	struct mutex mclk_lock;
+};
+
+static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec,
+				   bool vote);
+
+static const struct tasha_reg_mask_val tasha_spkr_default[] = {
+	{WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+	{WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+	{WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+	{WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+	{WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x50},
+	{WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x50},
+};
+
+static const struct tasha_reg_mask_val tasha_spkr_mode1[] = {
+	{WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x00},
+	{WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x00},
+	{WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x00},
+	{WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x00},
+	{WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x44},
+	{WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
+};
+
+/**
+ * tasha_set_spkr_gain_offset - offset the speaker path
+ * gain with the given offset value.
+ *
+ * @codec: codec instance
+ * @offset: Indicates speaker path gain offset value.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int tasha_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset)
+{
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	if (!priv)
+		return -EINVAL;
+
+	priv->spkr_gain_offset = offset;
+	return 0;
+}
+EXPORT_SYMBOL(tasha_set_spkr_gain_offset);
+
+/**
+ * tasha_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @codec: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int tasha_set_spkr_mode(struct snd_soc_codec *codec, int mode)
+{
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int i;
+	const struct tasha_reg_mask_val *regs;
+	int size;
+
+	if (!priv)
+		return -EINVAL;
+
+	switch (mode) {
+	case SPKR_MODE_1:
+		regs = tasha_spkr_mode1;
+		size = ARRAY_SIZE(tasha_spkr_mode1);
+		break;
+	default:
+		regs = tasha_spkr_default;
+		size = ARRAY_SIZE(tasha_spkr_default);
+		break;
+	}
+
+	priv->spkr_mode = mode;
+	for (i = 0; i < size; i++)
+		snd_soc_update_bits(codec, regs[i].reg,
+				    regs[i].mask, regs[i].val);
+	return 0;
+}
+EXPORT_SYMBOL(tasha_set_spkr_mode);
+
+static void tasha_enable_sido_buck(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_update_bits(codec, WCD9335_ANA_RCO, 0x80, 0x80);
+	snd_soc_update_bits(codec, WCD9335_ANA_BUCK_CTL, 0x02, 0x02);
+	/* 100us sleep needed after IREF settings */
+	usleep_range(100, 110);
+	snd_soc_update_bits(codec, WCD9335_ANA_BUCK_CTL, 0x04, 0x04);
+	/* 100us sleep needed after VREF settings */
+	usleep_range(100, 110);
+	tasha->resmgr->sido_input_src = SIDO_SOURCE_RCO_BG;
+}
+
+static void tasha_cdc_sido_ccl_enable(struct tasha_priv *tasha, bool ccl_flag)
+{
+	struct snd_soc_codec *codec = tasha->codec;
+
+	if (!codec)
+		return;
+
+	if (!TASHA_IS_2_0(tasha->wcd9xxx)) {
+		dev_dbg(codec->dev, "%s: tasha version < 2p0, return\n",
+			__func__);
+		return;
+	}
+	dev_dbg(codec->dev, "%s: sido_ccl_cnt=%d, ccl_flag:%d\n",
+			__func__, tasha->sido_ccl_cnt, ccl_flag);
+	if (ccl_flag) {
+		if (++tasha->sido_ccl_cnt == 1)
+			snd_soc_update_bits(codec,
+				WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x6E);
+	} else {
+		if (tasha->sido_ccl_cnt == 0) {
+			dev_dbg(codec->dev, "%s: sido_ccl already disabled\n",
+				__func__);
+			return;
+		}
+		if (--tasha->sido_ccl_cnt == 0)
+			snd_soc_update_bits(codec,
+				WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x02);
+	}
+}
+
+static bool tasha_cdc_is_svs_enabled(struct tasha_priv *tasha)
+{
+	if (TASHA_IS_2_0(tasha->wcd9xxx) &&
+		svs_scaling_enabled)
+		return true;
+
+	return false;
+}
+
+static int tasha_cdc_req_mclk_enable(struct tasha_priv *tasha,
+				     bool enable)
+{
+	int ret = 0;
+
+	mutex_lock(&tasha->mclk_lock);
+	if (enable) {
+		tasha_cdc_sido_ccl_enable(tasha, true);
+		ret = clk_prepare_enable(tasha->wcd_ext_clk);
+		if (ret) {
+			dev_err(tasha->dev, "%s: ext clk enable failed\n",
+				__func__);
+			goto unlock_mutex;
+		}
+		/* get BG */
+		wcd_resmgr_enable_master_bias(tasha->resmgr);
+		/* get MCLK */
+		wcd_resmgr_enable_clk_block(tasha->resmgr, WCD_CLK_MCLK);
+	} else {
+		/* put MCLK */
+		wcd_resmgr_disable_clk_block(tasha->resmgr, WCD_CLK_MCLK);
+		/* put BG */
+		wcd_resmgr_disable_master_bias(tasha->resmgr);
+		clk_disable_unprepare(tasha->wcd_ext_clk);
+		tasha_cdc_sido_ccl_enable(tasha, false);
+	}
+unlock_mutex:
+	mutex_unlock(&tasha->mclk_lock);
+	return ret;
+}
+
+static int tasha_cdc_check_sido_value(enum tasha_sido_voltage req_mv)
+{
+	if ((req_mv != SIDO_VOLTAGE_SVS_MV) &&
+		(req_mv != SIDO_VOLTAGE_NOMINAL_MV))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void tasha_codec_apply_sido_voltage(
+				struct tasha_priv *tasha,
+				enum tasha_sido_voltage req_mv)
+{
+	u32 vout_d_val;
+	struct snd_soc_codec *codec = tasha->codec;
+	int ret;
+
+	if (!codec)
+		return;
+
+	if (!tasha_cdc_is_svs_enabled(tasha))
+		return;
+
+	if ((sido_buck_svs_voltage != SIDO_VOLTAGE_SVS_MV) &&
+		(sido_buck_svs_voltage != SIDO_VOLTAGE_NOMINAL_MV))
+		sido_buck_svs_voltage = SIDO_VOLTAGE_SVS_MV;
+
+	ret = tasha_cdc_check_sido_value(req_mv);
+	if (ret < 0) {
+		dev_dbg(codec->dev, "%s: requested mv=%d not in range\n",
+			__func__, req_mv);
+		return;
+	}
+	if (req_mv == tasha->sido_voltage) {
+		dev_dbg(codec->dev, "%s: Already at requested mv=%d\n",
+			__func__, req_mv);
+		return;
+	}
+	if (req_mv == sido_buck_svs_voltage) {
+		if (test_bit(AUDIO_NOMINAL, &tasha->status_mask) ||
+			test_bit(CPE_NOMINAL, &tasha->status_mask)) {
+			dev_dbg(codec->dev,
+				"%s: nominal client running, status_mask=%lu\n",
+				__func__, tasha->status_mask);
+			return;
+		}
+	}
+	/* compute the vout_d step value */
+	vout_d_val = CALCULATE_VOUT_D(req_mv);
+	snd_soc_write(codec, WCD9335_ANA_BUCK_VOUT_D, vout_d_val & 0xFF);
+	snd_soc_update_bits(codec, WCD9335_ANA_BUCK_CTL, 0x80, 0x80);
+
+	/* 1 msec sleep required after SIDO Vout_D voltage change */
+	usleep_range(1000, 1100);
+	tasha->sido_voltage = req_mv;
+	dev_dbg(codec->dev,
+		"%s: updated SIDO buck Vout_D to %d, vout_d step = %u\n",
+		__func__, tasha->sido_voltage, vout_d_val);
+
+	snd_soc_update_bits(codec, WCD9335_ANA_BUCK_CTL,
+				0x80, 0x00);
+}
+
+static int tasha_codec_update_sido_voltage(
+				struct tasha_priv *tasha,
+				enum tasha_sido_voltage req_mv)
+{
+	int ret = 0;
+
+	if (!tasha_cdc_is_svs_enabled(tasha))
+		return ret;
+
+	mutex_lock(&tasha->sido_lock);
+	/* enable mclk before setting SIDO voltage */
+	ret = tasha_cdc_req_mclk_enable(tasha, true);
+	if (ret) {
+		dev_err(tasha->dev, "%s: ext clk enable failed\n",
+			__func__);
+		goto err;
+	}
+	tasha_codec_apply_sido_voltage(tasha, req_mv);
+	tasha_cdc_req_mclk_enable(tasha, false);
+
+err:
+	mutex_unlock(&tasha->sido_lock);
+	return ret;
+}
+
+int tasha_enable_efuse_sensing(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	tasha_cdc_mclk_enable(codec, true, false);
+
+	if (!TASHA_IS_2_0(priv->wcd9xxx))
+		snd_soc_update_bits(codec, WCD9335_CHIP_TIER_CTRL_EFUSE_CTL,
+				    0x1E, 0x02);
+	snd_soc_update_bits(codec, WCD9335_CHIP_TIER_CTRL_EFUSE_CTL,
+			    0x01, 0x01);
+	/*
+	 * 5ms sleep required after enabling efuse control
+	 * before checking the status.
+	 */
+	usleep_range(5000, 5500);
+	if (!(snd_soc_read(codec, WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & 0x01))
+		WARN(1, "%s: Efuse sense is not complete\n", __func__);
+
+	if (TASHA_IS_2_0(priv->wcd9xxx)) {
+		if (!(snd_soc_read(codec,
+			WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0) & 0x40))
+			snd_soc_update_bits(codec, WCD9335_HPH_R_ATEST,
+					    0x04, 0x00);
+		tasha_enable_sido_buck(codec);
+	}
+
+	tasha_cdc_mclk_enable(codec, false, false);
+
+	return 0;
+}
+EXPORT_SYMBOL(tasha_enable_efuse_sensing);
+
+void *tasha_get_afe_config(struct snd_soc_codec *codec,
+			   enum afe_config_type config_type)
+{
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		return &priv->slimbus_slave_cfg;
+	case AFE_CDC_REGISTERS_CONFIG:
+		return &tasha_audio_reg_cfg;
+	case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+		return &tasha_slimbus_slave_port_cfg;
+	case AFE_AANC_VERSION:
+		return &tasha_cdc_aanc_version;
+	case AFE_CLIP_BANK_SEL:
+		return NULL;
+	case AFE_CDC_CLIP_REGISTERS_CONFIG:
+		return NULL;
+	case AFE_CDC_REGISTER_PAGE_CONFIG:
+		return &tasha_cdc_reg_page_cfg;
+	default:
+		dev_err(codec->dev, "%s: Unknown config_type 0x%x\n",
+			__func__, config_type);
+		return NULL;
+	}
+}
+EXPORT_SYMBOL(tasha_get_afe_config);
+
+/*
+ * tasha_event_register: Registers a machine driver callback
+ * function with codec private data for post ADSP sub-system
+ * restart (SSR). This callback function will be called from
+ * codec driver once codec comes out of reset after ADSP SSR.
+ *
+ * @machine_event_cb: callback function from machine driver
+ * @codec: Codec instance
+ *
+ * Return: none
+ */
+void tasha_event_register(
+	int (*machine_event_cb)(struct snd_soc_codec *codec,
+				enum wcd9335_codec_event),
+	struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (tasha)
+		tasha->machine_codec_event_cb = machine_event_cb;
+	else
+		dev_dbg(codec->dev, "%s: Invalid tasha_priv data\n", __func__);
+}
+EXPORT_SYMBOL(tasha_event_register);
+
+static int tasha_mbhc_request_irq(struct snd_soc_codec *codec,
+				   int irq, irq_handler_t handler,
+				   const char *name, void *data)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	return wcd9xxx_request_irq(core_res, irq, handler, name, data);
+}
+
+static void tasha_mbhc_irq_control(struct snd_soc_codec *codec,
+				   int irq, bool enable)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+	if (enable)
+		wcd9xxx_enable_irq(core_res, irq);
+	else
+		wcd9xxx_disable_irq(core_res, irq);
+}
+
+static int tasha_mbhc_free_irq(struct snd_soc_codec *codec,
+			       int irq, void *data)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	wcd9xxx_free_irq(core_res, irq, data);
+	return 0;
+}
+
+static void tasha_mbhc_clk_setup(struct snd_soc_codec *codec,
+				 bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD9335_MBHC_CTL_1,
+				    0x80, 0x80);
+	else
+		snd_soc_update_bits(codec, WCD9335_MBHC_CTL_1,
+				    0x80, 0x00);
+}
+
+static int tasha_mbhc_btn_to_num(struct snd_soc_codec *codec)
+{
+	return snd_soc_read(codec, WCD9335_ANA_MBHC_RESULT_3) & 0x7;
+}
+
+static void tasha_mbhc_mbhc_bias_control(struct snd_soc_codec *codec,
+					 bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD9335_ANA_MBHC_ELECT,
+				    0x01, 0x01);
+	else
+		snd_soc_update_bits(codec, WCD9335_ANA_MBHC_ELECT,
+				    0x01, 0x00);
+}
+
+static void tasha_mbhc_program_btn_thr(struct snd_soc_codec *codec,
+				       s16 *btn_low, s16 *btn_high,
+				       int num_btn, bool is_micbias)
+{
+	int i;
+	int vth;
+
+	if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+		dev_err(codec->dev, "%s: invalid number of buttons: %d\n",
+			__func__, num_btn);
+		return;
+	}
+	/*
+	 * Tasha just needs one set of thresholds for button detection
+	 * due to micbias voltage ramp to pullup upon button press. So
+	 * btn_low and is_micbias are ignored and always program button
+	 * thresholds using btn_high.
+	 */
+	for (i = 0; i < num_btn; i++) {
+		vth = ((btn_high[i] * 2) / 25) & 0x3F;
+		snd_soc_update_bits(codec, WCD9335_ANA_MBHC_BTN0 + i,
+				    0xFC, vth << 2);
+		dev_dbg(codec->dev, "%s: btn_high[%d]: %d, vth: %d\n",
+			__func__, i, btn_high[i], vth);
+	}
+}
+
+static bool tasha_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+	if (lock)
+		return wcd9xxx_lock_sleep(core_res);
+	else {
+		wcd9xxx_unlock_sleep(core_res);
+		return 0;
+	}
+}
+
+static int tasha_mbhc_register_notifier(struct wcd_mbhc *mbhc,
+					struct notifier_block *nblock,
+					bool enable)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (enable)
+		return blocking_notifier_chain_register(&tasha->notifier,
+							nblock);
+	else
+		return blocking_notifier_chain_unregister(&tasha->notifier,
+							  nblock);
+}
+
+static bool tasha_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+	u8 val;
+
+	if (micb_num == MIC_BIAS_2) {
+		val = (snd_soc_read(mbhc->codec, WCD9335_ANA_MICB2) >> 6);
+		if (val == 0x01)
+			return true;
+	}
+	return false;
+}
+
+static bool tasha_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
+{
+	return (snd_soc_read(codec, WCD9335_ANA_HPH) & 0xC0) ? true : false;
+}
+
+static void tasha_mbhc_hph_l_pull_up_control(struct snd_soc_codec *codec,
+					enum mbhc_hs_pullup_iref pull_up_cur)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (!tasha)
+		return;
+
+	/* Default pull up current to 2uA */
+	if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA ||
+	    pull_up_cur == I_DEFAULT)
+		pull_up_cur = I_2P0_UA;
+
+	dev_dbg(codec->dev, "%s: HS pull up current:%d\n",
+		__func__, pull_up_cur);
+
+	if (TASHA_IS_2_0(tasha->wcd9xxx))
+		snd_soc_update_bits(codec, WCD9335_MBHC_PLUG_DETECT_CTL,
+			    0xC0, pull_up_cur << 6);
+	else
+		snd_soc_update_bits(codec, WCD9335_MBHC_PLUG_DETECT_CTL,
+			    0xC0, 0x40);
+}
+
+static int tasha_enable_ext_mb_source(struct wcd_mbhc *mbhc,
+		bool turn_on)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+	struct on_demand_supply *supply;
+
+	if (!tasha)
+		return -EINVAL;
+
+	supply =  &tasha->on_demand_list[ON_DEMAND_MICBIAS];
+	if (!supply->supply) {
+		dev_dbg(codec->dev, "%s: warning supply not present ond for %s\n",
+				__func__, "onDemand Micbias");
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
+		supply->ondemand_supply_count);
+
+	if (turn_on) {
+		if (!(supply->ondemand_supply_count)) {
+			ret = snd_soc_dapm_force_enable_pin(
+				snd_soc_codec_get_dapm(codec),
+				"MICBIAS_REGULATOR");
+			snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+		}
+		supply->ondemand_supply_count++;
+	} else {
+		if (supply->ondemand_supply_count > 0)
+			supply->ondemand_supply_count--;
+		if (!(supply->ondemand_supply_count)) {
+			ret = snd_soc_dapm_disable_pin(
+				snd_soc_codec_get_dapm(codec),
+				"MICBIAS_REGULATOR");
+		snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+		}
+	}
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			__func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static int tasha_micbias_control(struct snd_soc_codec *codec,
+				 int micb_num,
+				 int req, bool is_dapm)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int micb_index = micb_num - 1;
+	u16 micb_reg;
+	int pre_off_event = 0, post_off_event = 0;
+	int post_on_event = 0, post_dapm_off = 0;
+	int post_dapm_on = 0;
+
+	if ((micb_index < 0) || (micb_index > TASHA_MAX_MICBIAS - 1)) {
+		dev_err(codec->dev, "%s: Invalid micbias index, micb_ind:%d\n",
+			__func__, micb_index);
+		return -EINVAL;
+	}
+	switch (micb_num) {
+	case MIC_BIAS_1:
+		micb_reg = WCD9335_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD9335_ANA_MICB2;
+		pre_off_event = WCD_EVENT_PRE_MICBIAS_2_OFF;
+		post_off_event = WCD_EVENT_POST_MICBIAS_2_OFF;
+		post_on_event = WCD_EVENT_POST_MICBIAS_2_ON;
+		post_dapm_on = WCD_EVENT_POST_DAPM_MICBIAS_2_ON;
+		post_dapm_off = WCD_EVENT_POST_DAPM_MICBIAS_2_OFF;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD9335_ANA_MICB3;
+		break;
+	case MIC_BIAS_4:
+		micb_reg = WCD9335_ANA_MICB4;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid micbias number: %d\n",
+			__func__, micb_num);
+		return -EINVAL;
+	}
+	mutex_lock(&tasha->micb_lock);
+
+	switch (req) {
+	case MICB_PULLUP_ENABLE:
+		tasha->pullup_ref[micb_index]++;
+		if ((tasha->pullup_ref[micb_index] == 1) &&
+		    (tasha->micb_ref[micb_index] == 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+		break;
+	case MICB_PULLUP_DISABLE:
+		if (tasha->pullup_ref[micb_index] > 0)
+			tasha->pullup_ref[micb_index]--;
+		if ((tasha->pullup_ref[micb_index] == 0) &&
+		    (tasha->micb_ref[micb_index] == 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
+		break;
+	case MICB_ENABLE:
+		tasha->micb_ref[micb_index]++;
+		if (tasha->micb_ref[micb_index] == 1) {
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40);
+			if (post_on_event)
+				blocking_notifier_call_chain(&tasha->notifier,
+						post_on_event, &tasha->mbhc);
+		}
+		if (is_dapm && post_dapm_on)
+			blocking_notifier_call_chain(&tasha->notifier,
+					post_dapm_on, &tasha->mbhc);
+		break;
+	case MICB_DISABLE:
+		if (tasha->micb_ref[micb_index] > 0)
+			tasha->micb_ref[micb_index]--;
+		if ((tasha->micb_ref[micb_index] == 0) &&
+		    (tasha->pullup_ref[micb_index] > 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+		else if ((tasha->micb_ref[micb_index] == 0) &&
+			 (tasha->pullup_ref[micb_index] == 0)) {
+			if (pre_off_event)
+				blocking_notifier_call_chain(&tasha->notifier,
+						pre_off_event, &tasha->mbhc);
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
+			if (post_off_event)
+				blocking_notifier_call_chain(&tasha->notifier,
+						post_off_event, &tasha->mbhc);
+		}
+		if (is_dapm && post_dapm_off)
+			blocking_notifier_call_chain(&tasha->notifier,
+					post_dapm_off, &tasha->mbhc);
+		break;
+	};
+
+	dev_dbg(codec->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
+		__func__, micb_num, tasha->micb_ref[micb_index],
+		tasha->pullup_ref[micb_index]);
+
+	mutex_unlock(&tasha->micb_lock);
+
+	return 0;
+}
+
+static int tasha_mbhc_request_micbias(struct snd_soc_codec *codec,
+				      int micb_num, int req)
+{
+	int ret;
+
+	/*
+	 * If micbias is requested, make sure that there
+	 * is vote to enable mclk
+	 */
+	if (req == MICB_ENABLE)
+		tasha_cdc_mclk_enable(codec, true, false);
+
+	ret = tasha_micbias_control(codec, micb_num, req, false);
+
+	/*
+	 * Release vote for mclk while requesting for
+	 * micbias disable
+	 */
+	if (req == MICB_DISABLE)
+		tasha_cdc_mclk_enable(codec, false, false);
+
+	return ret;
+}
+
+static void tasha_mbhc_micb_ramp_control(struct snd_soc_codec *codec,
+					bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD9335_ANA_MICB2_RAMP,
+				    0x1C, 0x0C);
+		snd_soc_update_bits(codec, WCD9335_ANA_MICB2_RAMP,
+				    0x80, 0x80);
+	} else {
+		snd_soc_update_bits(codec, WCD9335_ANA_MICB2_RAMP,
+				    0x80, 0x00);
+		snd_soc_update_bits(codec, WCD9335_ANA_MICB2_RAMP,
+				    0x1C, 0x00);
+	}
+}
+
+static struct firmware_cal *tasha_get_hwdep_fw_cal(struct wcd_mbhc *mbhc,
+						   enum wcd_cal_type type)
+{
+	struct tasha_priv *tasha;
+	struct firmware_cal *hwdep_cal;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer\n", __func__);
+		return NULL;
+	}
+	tasha = snd_soc_codec_get_drvdata(codec);
+	hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, type);
+	if (!hwdep_cal)
+		dev_err(codec->dev, "%s: cal not sent by %d\n",
+			__func__, type);
+
+	return hwdep_cal;
+}
+
+static int tasha_mbhc_micb_adjust_voltage(struct snd_soc_codec *codec,
+					  int req_volt,
+					  int micb_num)
+{
+	int cur_vout_ctl, req_vout_ctl;
+	int micb_reg, micb_val, micb_en;
+
+	switch (micb_num) {
+	case MIC_BIAS_1:
+		micb_reg = WCD9335_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD9335_ANA_MICB2;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD9335_ANA_MICB3;
+		break;
+	case MIC_BIAS_4:
+		micb_reg = WCD9335_ANA_MICB4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * If requested micbias voltage is same as current micbias
+	 * voltage, then just return. Otherwise, adjust voltage as
+	 * per requested value. If micbias is already enabled, then
+	 * to avoid slow micbias ramp-up or down enable pull-up
+	 * momentarily, change the micbias value and then re-enable
+	 * micbias.
+	 */
+	micb_val = snd_soc_read(codec, micb_reg);
+	micb_en = (micb_val & 0xC0) >> 6;
+	cur_vout_ctl = micb_val & 0x3F;
+
+	req_vout_ctl = wcd9335_get_micb_vout_ctl_val(req_volt);
+	if (req_vout_ctl < 0)
+		return -EINVAL;
+	if (cur_vout_ctl == req_vout_ctl)
+		return 0;
+
+	dev_dbg(codec->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n",
+		 __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl),
+		 req_volt, micb_en);
+
+	if (micb_en == 0x1)
+		snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+
+	snd_soc_update_bits(codec, micb_reg, 0x3F, req_vout_ctl);
+
+	if (micb_en == 0x1) {
+		snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40);
+		/*
+		 * Add 2ms delay as per HW requirement after enabling
+		 * micbias
+		 */
+		usleep_range(2000, 2100);
+	}
+
+	return 0;
+}
+
+static int tasha_mbhc_micb_ctrl_threshold_mic(struct snd_soc_codec *codec,
+					      int micb_num, bool req_en)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent);
+	int rc, micb_mv;
+
+	if (micb_num != MIC_BIAS_2)
+		return -EINVAL;
+
+	/*
+	 * If device tree micbias level is already above the minimum
+	 * voltage needed to detect threshold microphone, then do
+	 * not change the micbias, just return.
+	 */
+	if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+		return 0;
+
+	micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv;
+
+	mutex_lock(&tasha->micb_lock);
+	rc = tasha_mbhc_micb_adjust_voltage(codec, micb_mv, MIC_BIAS_2);
+	mutex_unlock(&tasha->micb_lock);
+
+	return rc;
+}
+
+static inline void tasha_mbhc_get_result_params(struct wcd9xxx *wcd9xxx,
+						s16 *d1_a, u16 noff,
+						int32_t *zdet)
+{
+	int i;
+	int val, val1;
+	s16 c1;
+	s32 x1, d1;
+	int32_t denom;
+	int minCode_param[] = {
+			3277, 1639, 820, 410, 205, 103, 52, 26
+	};
+
+	regmap_update_bits(wcd9xxx->regmap, WCD9335_ANA_MBHC_ZDET, 0x20, 0x20);
+	for (i = 0; i < TASHA_ZDET_NUM_MEASUREMENTS; i++) {
+		regmap_read(wcd9xxx->regmap, WCD9335_ANA_MBHC_RESULT_2, &val);
+		if (val & 0x80)
+			break;
+	}
+	val = val << 0x8;
+	regmap_read(wcd9xxx->regmap, WCD9335_ANA_MBHC_RESULT_1, &val1);
+	val |= val1;
+	regmap_update_bits(wcd9xxx->regmap, WCD9335_ANA_MBHC_ZDET, 0x20, 0x00);
+	x1 = TASHA_MBHC_GET_X1(val);
+	c1 = TASHA_MBHC_GET_C1(val);
+	/* If ramp is not complete, give additional 5ms */
+	if ((c1 < 2) && x1)
+		usleep_range(5000, 5050);
+
+	if (!c1 || !x1) {
+		dev_dbg(wcd9xxx->dev,
+			"%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
+			__func__, c1, x1);
+		goto ramp_down;
+	}
+	d1 = d1_a[c1];
+	denom = (x1 * d1) - (1 << (14 - noff));
+	if (denom > 0)
+		*zdet = (TASHA_MBHC_ZDET_CONST * 1000) / denom;
+	else if (x1 < minCode_param[noff])
+		*zdet = TASHA_ZDET_FLOATING_IMPEDANCE;
+
+	dev_dbg(wcd9xxx->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+		__func__, d1, c1, x1, *zdet);
+ramp_down:
+	i = 0;
+	while (x1) {
+		regmap_bulk_read(wcd9xxx->regmap,
+				 WCD9335_ANA_MBHC_RESULT_1, (u8 *)&val, 2);
+		x1 = TASHA_MBHC_GET_X1(val);
+		i++;
+		if (i == TASHA_ZDET_NUM_MEASUREMENTS)
+			break;
+	}
+}
+
+/*
+ * tasha_mbhc_zdet_gpio_ctrl: Register callback function for
+ * controlling the switch on hifi amps. Default switch state
+ * will put a 51ohm load in parallel to the hph load. So,
+ * impedance detection function will pull the gpio high
+ * to make the switch open.
+ *
+ * @zdet_gpio_cb: callback function from machine driver
+ * @codec: Codec instance
+ *
+ * Return: none
+ */
+void tasha_mbhc_zdet_gpio_ctrl(
+		int (*zdet_gpio_cb)(struct snd_soc_codec *codec, bool high),
+		struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	tasha->zdet_gpio_cb = zdet_gpio_cb;
+}
+EXPORT_SYMBOL(tasha_mbhc_zdet_gpio_ctrl);
+
+static void tasha_mbhc_zdet_ramp(struct snd_soc_codec *codec,
+				 struct tasha_mbhc_zdet_param *zdet_param,
+				 int32_t *zl, int32_t *zr, s16 *d1_a)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	int32_t zdet = 0;
+
+	snd_soc_update_bits(codec, WCD9335_MBHC_ZDET_ANA_CTL, 0x70,
+			    zdet_param->ldo_ctl << 4);
+	snd_soc_update_bits(codec, WCD9335_ANA_MBHC_BTN5, 0xFC,
+			    zdet_param->btn5);
+	snd_soc_update_bits(codec, WCD9335_ANA_MBHC_BTN6, 0xFC,
+			    zdet_param->btn6);
+	snd_soc_update_bits(codec, WCD9335_ANA_MBHC_BTN7, 0xFC,
+			    zdet_param->btn7);
+	snd_soc_update_bits(codec, WCD9335_MBHC_ZDET_ANA_CTL, 0x0F,
+			    zdet_param->noff);
+	snd_soc_update_bits(codec, WCD9335_MBHC_ZDET_RAMP_CTL, 0x0F,
+			    zdet_param->nshift);
+
+	if (!zl)
+		goto z_right;
+	/* Start impedance measurement for HPH_L */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD9335_ANA_MBHC_ZDET, 0x80, 0x80);
+	dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_L, noff = %d\n",
+					__func__, zdet_param->noff);
+	tasha_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD9335_ANA_MBHC_ZDET, 0x80, 0x00);
+
+	*zl = zdet;
+
+z_right:
+	if (!zr)
+		return;
+	/* Start impedance measurement for HPH_R */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD9335_ANA_MBHC_ZDET, 0x40, 0x40);
+	dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_R, noff = %d\n",
+					__func__, zdet_param->noff);
+	tasha_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD9335_ANA_MBHC_ZDET, 0x40, 0x00);
+
+	*zr = zdet;
+}
+
+static inline void tasha_wcd_mbhc_qfuse_cal(struct snd_soc_codec *codec,
+					int32_t *z_val, int flag_l_r)
+{
+	s16 q1;
+	int q1_cal;
+
+	if (*z_val < (TASHA_ZDET_VAL_400/1000))
+		q1 = snd_soc_read(codec,
+			WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 + (2 * flag_l_r));
+	else
+		q1 = snd_soc_read(codec,
+			WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 + (2 * flag_l_r));
+	if (q1 & 0x80)
+		q1_cal = (10000 - ((q1 & 0x7F) * 25));
+	else
+		q1_cal = (10000 + (q1 * 25));
+	if (q1_cal > 0)
+		*z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void tasha_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
+					  uint32_t *zr)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	s16 reg0, reg1, reg2, reg3, reg4;
+	int32_t z1L, z1R, z1Ls;
+	int zMono, z_diff1, z_diff2;
+	bool is_fsm_disable = false;
+	bool is_change = false;
+	struct tasha_mbhc_zdet_param zdet_param[] = {
+		{4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+		{2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+		{1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+		{1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+	};
+	struct tasha_mbhc_zdet_param *zdet_param_ptr = NULL;
+	s16 d1_a[][4] = {
+		{0, 30, 90, 30},
+		{0, 30, 30, 5},
+		{0, 30, 30, 5},
+		{0, 30, 30, 5},
+	};
+	s16 *d1 = NULL;
+
+	if (!TASHA_IS_2_0(wcd9xxx)) {
+		dev_dbg(codec->dev, "%s: Z-det is not supported for this codec version\n",
+					__func__);
+		*zl = 0;
+		*zr = 0;
+		return;
+	}
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+	if (tasha->zdet_gpio_cb)
+		is_change = tasha->zdet_gpio_cb(codec, true);
+
+	reg0 = snd_soc_read(codec, WCD9335_ANA_MBHC_BTN5);
+	reg1 = snd_soc_read(codec, WCD9335_ANA_MBHC_BTN6);
+	reg2 = snd_soc_read(codec, WCD9335_ANA_MBHC_BTN7);
+	reg3 = snd_soc_read(codec, WCD9335_MBHC_CTL_1);
+	reg4 = snd_soc_read(codec, WCD9335_MBHC_ZDET_ANA_CTL);
+
+	if (snd_soc_read(codec, WCD9335_ANA_MBHC_ELECT) & 0x80) {
+		is_fsm_disable = true;
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD9335_ANA_MBHC_ELECT, 0x80, 0x00);
+	}
+
+	/* For NO-jack, disable L_DET_EN before Z-det measurements */
+	if (mbhc->hphl_swh)
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD9335_ANA_MBHC_MECH, 0x80, 0x00);
+
+	/* Enable AZ */
+	snd_soc_update_bits(codec, WCD9335_MBHC_CTL_1, 0x0C, 0x04);
+	/* Turn off 100k pull down on HPHL */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD9335_ANA_MBHC_MECH, 0x01, 0x00);
+
+	/* First get impedance on Left */
+	d1 = d1_a[1];
+	zdet_param_ptr = &zdet_param[1];
+	tasha_mbhc_zdet_ramp(codec, zdet_param_ptr, &z1L, NULL, d1);
+
+	if (!TASHA_MBHC_IS_SECOND_RAMP_REQUIRED(z1L))
+		goto left_ch_impedance;
+
+	/* second ramp for left ch */
+	if (z1L < TASHA_ZDET_VAL_32) {
+		zdet_param_ptr = &zdet_param[0];
+		d1 = d1_a[0];
+	} else if ((z1L > TASHA_ZDET_VAL_400) && (z1L <= TASHA_ZDET_VAL_1200)) {
+		zdet_param_ptr = &zdet_param[2];
+		d1 = d1_a[2];
+	} else if (z1L > TASHA_ZDET_VAL_1200) {
+		zdet_param_ptr = &zdet_param[3];
+		d1 = d1_a[3];
+	}
+	tasha_mbhc_zdet_ramp(codec, zdet_param_ptr, &z1L, NULL, d1);
+
+left_ch_impedance:
+	if ((z1L == TASHA_ZDET_FLOATING_IMPEDANCE) ||
+		(z1L > TASHA_ZDET_VAL_100K)) {
+		*zl = TASHA_ZDET_FLOATING_IMPEDANCE;
+		zdet_param_ptr = &zdet_param[1];
+		d1 = d1_a[1];
+	} else {
+		*zl = z1L/1000;
+		tasha_wcd_mbhc_qfuse_cal(codec, zl, 0);
+	}
+	dev_dbg(codec->dev, "%s: impedance on HPH_L = %d(ohms)\n",
+				__func__, *zl);
+
+	/* start of right impedance ramp and calculation */
+	tasha_mbhc_zdet_ramp(codec, zdet_param_ptr, NULL, &z1R, d1);
+	if (TASHA_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) {
+		if (((z1R > TASHA_ZDET_VAL_1200) &&
+			(zdet_param_ptr->noff == 0x6)) ||
+			((*zl) != TASHA_ZDET_FLOATING_IMPEDANCE))
+			goto right_ch_impedance;
+		/* second ramp for right ch */
+		if (z1R < TASHA_ZDET_VAL_32) {
+			zdet_param_ptr = &zdet_param[0];
+			d1 = d1_a[0];
+		} else if ((z1R > TASHA_ZDET_VAL_400) &&
+			(z1R <= TASHA_ZDET_VAL_1200)) {
+			zdet_param_ptr = &zdet_param[2];
+			d1 = d1_a[2];
+		} else if (z1R > TASHA_ZDET_VAL_1200) {
+			zdet_param_ptr = &zdet_param[3];
+			d1 = d1_a[3];
+		}
+		tasha_mbhc_zdet_ramp(codec, zdet_param_ptr, NULL, &z1R, d1);
+	}
+right_ch_impedance:
+	if ((z1R == TASHA_ZDET_FLOATING_IMPEDANCE) ||
+		(z1R > TASHA_ZDET_VAL_100K)) {
+		*zr = TASHA_ZDET_FLOATING_IMPEDANCE;
+	} else {
+		*zr = z1R/1000;
+		tasha_wcd_mbhc_qfuse_cal(codec, zr, 1);
+	}
+	dev_dbg(codec->dev, "%s: impedance on HPH_R = %d(ohms)\n",
+				__func__, *zr);
+
+	/* mono/stereo detection */
+	if ((*zl == TASHA_ZDET_FLOATING_IMPEDANCE) &&
+		(*zr == TASHA_ZDET_FLOATING_IMPEDANCE)) {
+		dev_dbg(codec->dev,
+			"%s: plug type is invalid or extension cable\n",
+			__func__);
+		goto zdet_complete;
+	}
+	if ((*zl == TASHA_ZDET_FLOATING_IMPEDANCE) ||
+	    (*zr == TASHA_ZDET_FLOATING_IMPEDANCE) ||
+	    ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+	    ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+		dev_dbg(codec->dev,
+			"%s: Mono plug type with one ch floating or shorted to GND\n",
+			__func__);
+		mbhc->hph_type = WCD_MBHC_HPH_MONO;
+		goto zdet_complete;
+	}
+	snd_soc_update_bits(codec, WCD9335_HPH_R_ATEST, 0x02, 0x02);
+	snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x40, 0x01);
+	if (*zl < (TASHA_ZDET_VAL_32/1000))
+		tasha_mbhc_zdet_ramp(codec, &zdet_param[0], &z1Ls, NULL, d1);
+	else
+		tasha_mbhc_zdet_ramp(codec, &zdet_param[1], &z1Ls, NULL, d1);
+	snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x40, 0x00);
+	snd_soc_update_bits(codec, WCD9335_HPH_R_ATEST, 0x02, 0x00);
+	z1Ls /= 1000;
+	tasha_wcd_mbhc_qfuse_cal(codec, &z1Ls, 0);
+	/* parallel of left Z and 9 ohm pull down resistor */
+	zMono = ((*zl) * 9) / ((*zl) + 9);
+	z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls);
+	z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl));
+	if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) {
+		dev_dbg(codec->dev, "%s: stereo plug type detected\n",
+				__func__);
+		mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+	} else {
+		dev_dbg(codec->dev, "%s: MONO plug type detected\n",
+			 __func__);
+		mbhc->hph_type = WCD_MBHC_HPH_MONO;
+	}
+
+zdet_complete:
+	snd_soc_write(codec, WCD9335_ANA_MBHC_BTN5, reg0);
+	snd_soc_write(codec, WCD9335_ANA_MBHC_BTN6, reg1);
+	snd_soc_write(codec, WCD9335_ANA_MBHC_BTN7, reg2);
+	/* Turn on 100k pull down on HPHL */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD9335_ANA_MBHC_MECH, 0x01, 0x01);
+
+	/* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+	if (mbhc->hphl_swh)
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD9335_ANA_MBHC_MECH, 0x80, 0x80);
+
+	snd_soc_write(codec, WCD9335_MBHC_ZDET_ANA_CTL, reg4);
+	snd_soc_write(codec, WCD9335_MBHC_CTL_1, reg3);
+	if (is_fsm_disable)
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD9335_ANA_MBHC_ELECT, 0x80, 0x80);
+	if (tasha->zdet_gpio_cb && is_change)
+		tasha->zdet_gpio_cb(codec, false);
+}
+
+static void tasha_mbhc_gnd_det_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD9335_ANA_MBHC_MECH,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD9335_ANA_MBHC_MECH,
+				    0x40, 0x40);
+	} else {
+		snd_soc_update_bits(codec, WCD9335_ANA_MBHC_MECH,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, WCD9335_ANA_MBHC_MECH,
+				    0x02, 0x00);
+	}
+}
+
+static void tasha_mbhc_hph_pull_down_ctrl(struct snd_soc_codec *codec,
+					  bool enable)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2,
+				    0x40, 0x40);
+		if (TASHA_IS_2_0(tasha->wcd9xxx))
+			snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2,
+					    0x10, 0x10);
+	} else {
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2,
+				    0x40, 0x00);
+		if (TASHA_IS_2_0(tasha->wcd9xxx))
+			snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2,
+					    0x10, 0x00);
+	}
+}
+
+static void tasha_mbhc_moisture_config(struct wcd_mbhc *mbhc)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	if (mbhc->moist_vref == V_OFF)
+		return;
+
+	/* Donot enable moisture detection if jack type is NC */
+	if (!mbhc->hphl_swh) {
+		dev_dbg(codec->dev, "%s: disable moisture detection for NC\n",
+			__func__);
+		return;
+	}
+
+	snd_soc_update_bits(codec, WCD9335_MBHC_CTL_2,
+			    0x0C, mbhc->moist_vref << 2);
+	tasha_mbhc_hph_l_pull_up_control(codec, mbhc->moist_iref);
+}
+
+static void tasha_update_anc_state(struct snd_soc_codec *codec, bool enable,
+				   int anc_num)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CFG0 +
+				(20 * anc_num), 0x10, 0x10);
+	else
+		snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CFG0 +
+				(20 * anc_num), 0x10, 0x00);
+}
+
+static bool tasha_is_anc_on(struct wcd_mbhc *mbhc)
+{
+	bool anc_on = false;
+	u16 ancl, ancr;
+
+	ancl =
+	(snd_soc_read(mbhc->codec, WCD9335_CDC_RX1_RX_PATH_CFG0)) & 0x10;
+	ancr =
+	(snd_soc_read(mbhc->codec, WCD9335_CDC_RX2_RX_PATH_CFG0)) & 0x10;
+
+	anc_on = !!(ancl | ancr);
+
+	return anc_on;
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+	.request_irq = tasha_mbhc_request_irq,
+	.irq_control = tasha_mbhc_irq_control,
+	.free_irq = tasha_mbhc_free_irq,
+	.clk_setup = tasha_mbhc_clk_setup,
+	.map_btn_code_to_num = tasha_mbhc_btn_to_num,
+	.enable_mb_source = tasha_enable_ext_mb_source,
+	.mbhc_bias = tasha_mbhc_mbhc_bias_control,
+	.set_btn_thr = tasha_mbhc_program_btn_thr,
+	.lock_sleep = tasha_mbhc_lock_sleep,
+	.register_notifier = tasha_mbhc_register_notifier,
+	.micbias_enable_status = tasha_mbhc_micb_en_status,
+	.hph_pa_on_status = tasha_mbhc_hph_pa_on_status,
+	.hph_pull_up_control = tasha_mbhc_hph_l_pull_up_control,
+	.mbhc_micbias_control = tasha_mbhc_request_micbias,
+	.mbhc_micb_ramp_control = tasha_mbhc_micb_ramp_control,
+	.get_hwdep_fw_cal = tasha_get_hwdep_fw_cal,
+	.mbhc_micb_ctrl_thr_mic = tasha_mbhc_micb_ctrl_threshold_mic,
+	.compute_impedance = tasha_wcd_mbhc_calc_impedance,
+	.mbhc_gnd_det_ctrl = tasha_mbhc_gnd_det_ctrl,
+	.hph_pull_down_ctrl = tasha_mbhc_hph_pull_down_ctrl,
+	.mbhc_moisture_config = tasha_mbhc_moisture_config,
+	.update_anc_state = tasha_update_anc_state,
+	.is_anc_on = tasha_is_anc_on,
+};
+
+static int tasha_get_anc_slot(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tasha->anc_slot;
+	return 0;
+}
+
+static int tasha_put_anc_slot(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	tasha->anc_slot = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int tasha_get_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = (tasha->anc_func == true ? 1 : 0);
+	return 0;
+}
+
+static int tasha_put_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	mutex_lock(&tasha->codec_mutex);
+	tasha->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
+
+	dev_dbg(codec->dev, "%s: anc_func %x", __func__, tasha->anc_func);
+
+	if (tasha->anc_func == true) {
+		snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT2 PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT2");
+		snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT1 PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT1");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC EAR");
+		snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA");
+		snd_soc_dapm_disable_pin(dapm, "LINEOUT2");
+		snd_soc_dapm_disable_pin(dapm, "LINEOUT2 PA");
+		snd_soc_dapm_disable_pin(dapm, "LINEOUT1");
+		snd_soc_dapm_disable_pin(dapm, "LINEOUT1 PA");
+		snd_soc_dapm_disable_pin(dapm, "HPHR");
+		snd_soc_dapm_disable_pin(dapm, "HPHL");
+		snd_soc_dapm_disable_pin(dapm, "HPHR PA");
+		snd_soc_dapm_disable_pin(dapm, "HPHL PA");
+		snd_soc_dapm_disable_pin(dapm, "EAR PA");
+		snd_soc_dapm_disable_pin(dapm, "EAR");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2 PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2");
+		snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1 PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+		snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA");
+		snd_soc_dapm_enable_pin(dapm, "LINEOUT2");
+		snd_soc_dapm_enable_pin(dapm, "LINEOUT2 PA");
+		snd_soc_dapm_enable_pin(dapm, "LINEOUT1");
+		snd_soc_dapm_enable_pin(dapm, "LINEOUT1 PA");
+		snd_soc_dapm_enable_pin(dapm, "HPHR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL");
+		snd_soc_dapm_enable_pin(dapm, "HPHR PA");
+		snd_soc_dapm_enable_pin(dapm, "HPHL PA");
+		snd_soc_dapm_enable_pin(dapm, "EAR PA");
+		snd_soc_dapm_enable_pin(dapm, "EAR");
+	}
+	mutex_unlock(&tasha->codec_mutex);
+	snd_soc_dapm_sync(dapm);
+	return 0;
+}
+
+static int tasha_get_clkmode(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = tasha->clk_mode;
+	dev_dbg(codec->dev, "%s: clk_mode: %d\n", __func__, tasha->clk_mode);
+
+	return 0;
+}
+
+static int tasha_put_clkmode(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	tasha->clk_mode = ucontrol->value.enumerated.item[0];
+	dev_dbg(codec->dev, "%s: clk_mode: %d\n", __func__, tasha->clk_mode);
+
+	return 0;
+}
+
+static int tasha_get_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	/* IIR filter band registers are at integer multiples of 16 */
+	u16 iir_reg = WCD9335_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx;
+
+	ucontrol->value.integer.value[0] = (snd_soc_read(codec, iir_reg) &
+					    (1 << band_idx)) != 0;
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int tasha_hph_impedance_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	uint32_t zl, zr;
+	bool hphr;
+	struct soc_multi_mixer_control *mc;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+	hphr = mc->shift;
+	wcd_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
+	dev_dbg(codec->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr);
+	ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+		       tasha_hph_impedance_get, NULL),
+	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+		       tasha_hph_impedance_get, NULL),
+};
+
+static int tasha_get_hph_type(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wcd_mbhc *mbhc;
+
+	if (!priv) {
+		dev_dbg(codec->dev, "%s: wcd9335 private data is NULL\n",
+				__func__);
+		return 0;
+	}
+
+	mbhc = &priv->mbhc;
+	if (!mbhc) {
+		dev_dbg(codec->dev, "%s: mbhc not initialized\n", __func__);
+		return 0;
+	}
+
+	ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
+	dev_dbg(codec->dev, "%s: hph_type = %u\n", __func__, mbhc->hph_type);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+	SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+		       tasha_get_hph_type, NULL),
+};
+
+static int tasha_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tasha_p->vi_feed_value;
+
+	return 0;
+}
+
+static int tasha_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = tasha_p->wcd9xxx;
+	struct soc_multi_mixer_control *mixer =
+		((struct soc_multi_mixer_control *)kcontrol->private_value);
+	u32 dai_id = widget->shift;
+	u32 port_id = mixer->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n",
+		__func__, enable, port_id, dai_id);
+
+	tasha_p->vi_feed_value = ucontrol->value.integer.value[0];
+
+	mutex_lock(&tasha_p->codec_mutex);
+	if (enable) {
+		if (port_id == TASHA_TX14 && !test_bit(VI_SENSE_1,
+						&tasha_p->status_mask)) {
+			list_add_tail(&core->tx_chs[TASHA_TX14].list,
+					&tasha_p->dai[dai_id].wcd9xxx_ch_list);
+			set_bit(VI_SENSE_1, &tasha_p->status_mask);
+		}
+		if (port_id == TASHA_TX15 && !test_bit(VI_SENSE_2,
+						&tasha_p->status_mask)) {
+			list_add_tail(&core->tx_chs[TASHA_TX15].list,
+					&tasha_p->dai[dai_id].wcd9xxx_ch_list);
+			set_bit(VI_SENSE_2, &tasha_p->status_mask);
+		}
+	} else {
+		if (port_id == TASHA_TX14 && test_bit(VI_SENSE_1,
+					&tasha_p->status_mask)) {
+			list_del_init(&core->tx_chs[TASHA_TX14].list);
+			clear_bit(VI_SENSE_1, &tasha_p->status_mask);
+		}
+		if (port_id == TASHA_TX15 && test_bit(VI_SENSE_2,
+					&tasha_p->status_mask)) {
+			list_del_init(&core->tx_chs[TASHA_TX15].list);
+			clear_bit(VI_SENSE_2, &tasha_p->status_mask);
+		}
+	}
+	mutex_unlock(&tasha_p->codec_mutex);
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+	return 0;
+}
+
+/* virtual port entries */
+static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tasha_p->tx_port_value;
+	return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_dapm_update *update = NULL;
+	struct soc_multi_mixer_control *mixer =
+		((struct soc_multi_mixer_control *)kcontrol->private_value);
+	u32 dai_id = widget->shift;
+	u32 port_id = mixer->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+	u32 vtable;
+
+
+	dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
+		  __func__,
+		widget->name, ucontrol->id.name, tasha_p->tx_port_value,
+		widget->shift, ucontrol->value.integer.value[0]);
+
+	mutex_lock(&tasha_p->codec_mutex);
+
+	if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		if (dai_id != AIF1_CAP) {
+			dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+				__func__);
+			mutex_unlock(&tasha_p->codec_mutex);
+			return -EINVAL;
+		}
+		vtable = vport_slim_check_table[dai_id];
+	} else {
+		if (dai_id >= ARRAY_SIZE(vport_i2s_check_table)) {
+			dev_err(codec->dev, "%s: dai_id: %d, out of bounds\n",
+				__func__, dai_id);
+			return -EINVAL;
+		}
+		vtable = vport_i2s_check_table[dai_id];
+	}
+	switch (dai_id) {
+	case AIF1_CAP:
+	case AIF2_CAP:
+	case AIF3_CAP:
+		/* only add to the list if value not set */
+		if (enable && !(tasha_p->tx_port_value & 1 << port_id)) {
+
+			if (wcd9xxx_tx_vport_validation(vtable, port_id,
+					tasha_p->dai, NUM_CODEC_DAIS)) {
+				dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
+					__func__, port_id);
+				mutex_unlock(&tasha_p->codec_mutex);
+				return 0;
+			}
+			tasha_p->tx_port_value |= 1 << port_id;
+			list_add_tail(&core->tx_chs[port_id].list,
+			      &tasha_p->dai[dai_id].wcd9xxx_ch_list
+					      );
+		} else if (!enable && (tasha_p->tx_port_value &
+					1 << port_id)) {
+			tasha_p->tx_port_value &= ~(1 << port_id);
+			list_del_init(&core->tx_chs[port_id].list);
+		} else {
+			if (enable)
+				dev_dbg(codec->dev, "%s: TX%u port is used by\n"
+					"this virtual port\n",
+					__func__, port_id);
+			else
+				dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
+					"this virtual port\n",
+					__func__, port_id);
+			/* avoid update power function */
+			mutex_unlock(&tasha_p->codec_mutex);
+			return 0;
+		}
+		break;
+	case AIF4_MAD_TX:
+	case AIF5_CPE_TX:
+		break;
+	default:
+		pr_err("Unknown AIF %d\n", dai_id);
+		mutex_unlock(&tasha_p->codec_mutex);
+		return -EINVAL;
+	}
+	pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
+		widget->name, widget->sname, tasha_p->tx_port_value,
+		widget->shift);
+
+	mutex_unlock(&tasha_p->codec_mutex);
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
+
+	return 0;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] =
+			tasha_p->rx_port_value[widget->shift];
+	return 0;
+}
+
+static const char *const slim_rx_mux_text[] = {
+	"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", "AIF_MIX1_PB"
+};
+
+static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_dapm_update *update = NULL;
+	unsigned int rx_port_value;
+	u32 port_id = widget->shift;
+
+	tasha_p->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
+	rx_port_value = tasha_p->rx_port_value[port_id];
+
+	pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
+		widget->name, ucontrol->id.name, rx_port_value,
+		widget->shift, ucontrol->value.integer.value[0]);
+
+	mutex_lock(&tasha_p->codec_mutex);
+
+	if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		if (rx_port_value > 2) {
+			dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+				__func__);
+			goto err;
+		}
+	}
+	/* value need to match the Virtual port and AIF number */
+	switch (rx_port_value) {
+	case 0:
+		list_del_init(&core->rx_chs[port_id].list);
+		break;
+	case 1:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			TASHA_RX_PORT_START_NUMBER,
+			&tasha_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tasha_p->dai[AIF1_PB].wcd9xxx_ch_list);
+		break;
+	case 2:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			TASHA_RX_PORT_START_NUMBER,
+			&tasha_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tasha_p->dai[AIF2_PB].wcd9xxx_ch_list);
+		break;
+	case 3:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			TASHA_RX_PORT_START_NUMBER,
+			&tasha_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tasha_p->dai[AIF3_PB].wcd9xxx_ch_list);
+		break;
+	case 4:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			TASHA_RX_PORT_START_NUMBER,
+			&tasha_p->dai[AIF4_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tasha_p->dai[AIF4_PB].wcd9xxx_ch_list);
+		break;
+	case 5:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			TASHA_RX_PORT_START_NUMBER,
+			&tasha_p->dai[AIF_MIX1_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tasha_p->dai[AIF_MIX1_PB].wcd9xxx_ch_list);
+		break;
+	default:
+		pr_err("Unknown AIF %d\n", rx_port_value);
+		goto err;
+	}
+rtn:
+	mutex_unlock(&tasha_p->codec_mutex);
+	snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+					rx_port_value, e, update);
+
+	return 0;
+err:
+	mutex_unlock(&tasha_p->codec_mutex);
+	return -EINVAL;
+}
+
+static const struct soc_enum slim_rx_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct snd_kcontrol_new slim_rx_mux[TASHA_RX_MAX] = {
+	SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+};
+
+static const struct snd_kcontrol_new aif4_vi_mixer[] = {
+	SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, TASHA_TX14, 1, 0,
+			tasha_vi_feed_mixer_get, tasha_vi_feed_mixer_put),
+	SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, TASHA_TX15, 1, 0,
+			tasha_vi_feed_mixer_get, tasha_vi_feed_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif1_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, TASHA_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TASHA_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TASHA_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TASHA_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TASHA_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TASHA_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TASHA_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TASHA_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TASHA_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TASHA_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TASHA_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, TASHA_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif2_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, TASHA_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TASHA_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TASHA_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TASHA_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TASHA_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TASHA_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TASHA_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TASHA_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TASHA_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TASHA_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TASHA_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, TASHA_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif3_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, TASHA_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TASHA_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TASHA_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TASHA_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TASHA_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TASHA_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TASHA_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TASHA_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TASHA_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TASHA_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TASHA_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, TASHA_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif4_mad_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX12", SND_SOC_NOPM, TASHA_TX12, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, 0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+
+};
+
+static const struct snd_kcontrol_new rx_int1_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("HPHL Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int2_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("HPHR Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int3_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("LO1 Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int4_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("LO2 Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int5_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("LO3 Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int6_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("LO4 Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int7_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("SPKRL Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int8_spline_mix_switch[] = {
+	SOC_DAPM_SINGLE("SPKRR Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int5_vbat_mix_switch[] = {
+	SOC_DAPM_SINGLE("LO3 VBAT Enable", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int6_vbat_mix_switch[] = {
+	SOC_DAPM_SINGLE("LO4 VBAT Enable", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int7_vbat_mix_switch[] = {
+	SOC_DAPM_SINGLE("SPKRL VBAT Enable", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int8_vbat_mix_switch[] = {
+	SOC_DAPM_SINGLE("SPKRR VBAT Enable", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new cpe_in_mix_switch[] = {
+	SOC_DAPM_SINGLE("MAD_BYPASS", SND_SOC_NOPM, 0, 1, 0)
+};
+
+
+
+static int tasha_put_iir_enable_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	bool iir_band_en_status;
+	int value = ucontrol->value.integer.value[0];
+	u16 iir_reg = WCD9335_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx;
+
+	/* Mask first 5 bits, 6-8 are reserved */
+	snd_soc_update_bits(codec, iir_reg, (1 << band_idx),
+			    (value << band_idx));
+
+	iir_band_en_status = ((snd_soc_read(codec, iir_reg) &
+			      (1 << band_idx)) != 0);
+	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx, iir_band_en_status);
+	return 0;
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				int coeff_idx)
+{
+	uint32_t value = 0;
+
+	/* Address does not automatically update if reading */
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t)) & 0x7F);
+
+	value |= snd_soc_read(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx));
+
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 1) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+			       (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL +
+				16 * iir_idx)) << 8);
+
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 2) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+			       (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL +
+				16 * iir_idx)) << 16);
+
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 3) & 0x7F);
+
+	/* Mask bits top 2 bits since they are reserved */
+	value |= ((snd_soc_read(codec,
+				(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL +
+				 16 * iir_idx)) & 0x3F) << 24);
+
+	return value;
+}
+
+static int tasha_get_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+	ucontrol->value.integer.value[1] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+	ucontrol->value.integer.value[2] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+	ucontrol->value.integer.value[3] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+	ucontrol->value.integer.value[4] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[1],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[2],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[3],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[4]);
+	return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+				int iir_idx, int band_idx,
+				uint32_t value)
+{
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value & 0xFF));
+
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 8) & 0xFF);
+
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 16) & 0xFF);
+
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 24) & 0x3F);
+}
+
+static void tasha_codec_enable_int_port(struct wcd9xxx_codec_dai_data *dai,
+					struct snd_soc_codec *codec)
+{
+	struct wcd9xxx_ch *ch;
+	int port_num = 0;
+	unsigned short reg = 0;
+	u8 val = 0;
+	struct tasha_priv *tasha_p;
+
+	if (!dai || !codec) {
+		pr_err("%s: Invalid params\n", __func__);
+		return;
+	}
+
+	tasha_p = snd_soc_codec_get_drvdata(codec);
+	list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+		if (ch->port >= TASHA_RX_PORT_START_NUMBER) {
+			port_num = ch->port - TASHA_RX_PORT_START_NUMBER;
+			reg = TASHA_SLIM_PGD_PORT_INT_EN0 + (port_num / 8);
+			val = wcd9xxx_interface_reg_read(tasha_p->wcd9xxx,
+				reg);
+			if (!(val & BYTE_BIT_MASK(port_num))) {
+				val |= BYTE_BIT_MASK(port_num);
+				wcd9xxx_interface_reg_write(
+					tasha_p->wcd9xxx, reg, val);
+				val = wcd9xxx_interface_reg_read(
+					tasha_p->wcd9xxx, reg);
+			}
+		} else {
+			port_num = ch->port;
+			reg = TASHA_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
+			val = wcd9xxx_interface_reg_read(tasha_p->wcd9xxx,
+				reg);
+			if (!(val & BYTE_BIT_MASK(port_num))) {
+				val |= BYTE_BIT_MASK(port_num);
+				wcd9xxx_interface_reg_write(tasha_p->wcd9xxx,
+					reg, val);
+				val = wcd9xxx_interface_reg_read(
+					tasha_p->wcd9xxx, reg);
+			}
+		}
+	}
+}
+
+static int tasha_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
+					  bool up)
+{
+	int ret = 0;
+	struct wcd9xxx_ch *ch;
+
+	if (up) {
+		list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+			ret = wcd9xxx_get_slave_port(ch->ch_num);
+			if (ret < 0) {
+				pr_err("%s: Invalid slave port ID: %d\n",
+				       __func__, ret);
+				ret = -EINVAL;
+			} else {
+				set_bit(ret, &dai->ch_mask);
+			}
+		}
+	} else {
+		ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
+					 msecs_to_jiffies(
+						TASHA_SLIM_CLOSE_TIMEOUT));
+		if (!ret) {
+			pr_err("%s: Slim close tx/rx wait timeout, ch_mask:0x%lx\n",
+				__func__, dai->ch_mask);
+			ret = -ETIMEDOUT;
+		} else {
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static int tasha_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct wcd9xxx *core;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+	struct wcd9xxx_codec_dai_data *dai;
+
+	core = dev_get_drvdata(codec->dev->parent);
+
+	dev_dbg(codec->dev, "%s: event called! codec name %s num_dai %d\n"
+		"stream name %s event %d\n",
+		__func__, codec->component.name,
+		codec->component.num_dai, w->sname, event);
+
+	/* Execute the callback only if interface type is slimbus */
+	if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return 0;
+
+	dai = &tasha_p->dai[w->shift];
+	dev_dbg(codec->dev, "%s: w->name %s w->shift %d event %d\n",
+		 __func__, w->name, w->shift, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		dai->bus_down_in_recovery = false;
+		tasha_codec_enable_int_port(dai, codec);
+		(void) tasha_codec_enable_slim_chmask(dai, true);
+		ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+					      dai->rate, dai->bit_width,
+					      &dai->grph);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		tasha_codec_vote_max_bw(codec, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = wcd9xxx_disconnect_port(core, &dai->wcd9xxx_ch_list,
+					      dai->grph);
+		dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
+			__func__, ret);
+
+		if (!dai->bus_down_in_recovery)
+			ret = tasha_codec_enable_slim_chmask(dai, false);
+		else
+			dev_dbg(codec->dev,
+				"%s: bus in recovery skip enable slim_chmask",
+				__func__);
+		ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+						dai->grph);
+		break;
+	}
+	return ret;
+}
+
+static int tasha_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w,
+					      struct snd_kcontrol *kcontrol,
+					      int event)
+{
+	struct wcd9xxx *core = NULL;
+	struct snd_soc_codec *codec = NULL;
+	struct tasha_priv *tasha_p = NULL;
+	int ret = 0;
+	struct wcd9xxx_codec_dai_data *dai = NULL;
+
+	if (!w) {
+		pr_err("%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	codec = snd_soc_dapm_to_codec(w->dapm);
+	tasha_p = snd_soc_codec_get_drvdata(codec);
+	core = tasha_p->wcd9xxx;
+
+	dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
+		__func__, codec->component.num_dai, w->sname);
+
+	/* Execute the callback only if interface type is slimbus */
+	if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		dev_err(codec->dev, "%s Interface is not correct", __func__);
+		return 0;
+	}
+
+	dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
+		__func__, w->name, event, w->shift);
+	if (w->shift != AIF4_VIFEED) {
+		pr_err("%s Error in enabling the tx path\n", __func__);
+		ret = -EINVAL;
+		goto out_vi;
+	}
+	dai = &tasha_p->dai[w->shift];
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (test_bit(VI_SENSE_1, &tasha_p->status_mask)) {
+			dev_dbg(codec->dev, "%s: spkr1 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x0F,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &tasha_p->status_mask)) {
+			pr_debug("%s: spkr2 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x0F,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x0F,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		dai->bus_down_in_recovery = false;
+		tasha_codec_enable_int_port(dai, codec);
+		(void) tasha_codec_enable_slim_chmask(dai, true);
+		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+					      dai->rate, dai->bit_width,
+					      &dai->grph);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+						dai->grph);
+		if (ret)
+			dev_err(codec->dev, "%s error in close_slim_sch_tx %d\n",
+				__func__, ret);
+		if (!dai->bus_down_in_recovery)
+			ret = tasha_codec_enable_slim_chmask(dai, false);
+		if (ret < 0) {
+			ret = wcd9xxx_disconnect_port(core,
+				&dai->wcd9xxx_ch_list,
+				dai->grph);
+			dev_dbg(codec->dev, "%s: Disconnect TX port, ret = %d\n",
+				__func__, ret);
+		}
+		if (test_bit(VI_SENSE_1, &tasha_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr1 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &tasha_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr2 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		break;
+	}
+out_vi:
+	return ret;
+}
+
+/*
+ * __tasha_codec_enable_slimtx: Enable the slimbus slave port
+ *				 for TX path
+ * @codec: Handle to the codec for which the slave port is to be
+ *	   enabled.
+ * @dai_data: The dai specific data for dai which is enabled.
+ */
+static int __tasha_codec_enable_slimtx(struct snd_soc_codec *codec,
+		int event, struct wcd9xxx_codec_dai_data *dai)
+{
+	struct wcd9xxx *core;
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	/* Execute the callback only if interface type is slimbus */
+	if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		return 0;
+
+	dev_dbg(codec->dev,
+		"%s: event = %d\n", __func__, event);
+	core = dev_get_drvdata(codec->dev->parent);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		dai->bus_down_in_recovery = false;
+		tasha_codec_enable_int_port(dai, codec);
+		(void) tasha_codec_enable_slim_chmask(dai, true);
+		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+					      dai->rate, dai->bit_width,
+					      &dai->grph);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+						dai->grph);
+		if (!dai->bus_down_in_recovery)
+			ret = tasha_codec_enable_slim_chmask(dai, false);
+		if (ret < 0) {
+			ret = wcd9xxx_disconnect_port(core,
+						      &dai->wcd9xxx_ch_list,
+						      dai->grph);
+			pr_debug("%s: Disconnect TX port, ret = %d\n",
+				 __func__, ret);
+		}
+
+		break;
+	}
+
+	return ret;
+}
+
+static int tasha_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_codec_dai_data *dai;
+
+	dev_dbg(codec->dev,
+		"%s: w->name %s, w->shift = %d, num_dai %d stream name %s\n",
+		__func__, w->name, w->shift,
+		codec->component.num_dai, w->sname);
+
+	dai = &tasha_p->dai[w->shift];
+	return __tasha_codec_enable_slimtx(codec, event, dai);
+}
+
+static void tasha_codec_cpe_pp_set_cfg(struct snd_soc_codec *codec, int event)
+{
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_codec_dai_data *dai;
+	u8 bit_width, rate, buf_period;
+
+	dai = &tasha_p->dai[AIF4_MAD_TX];
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		switch (dai->bit_width) {
+		case 32:
+			bit_width = 0xF;
+			break;
+		case 24:
+			bit_width = 0xE;
+			break;
+		case 20:
+			bit_width = 0xD;
+			break;
+		case 16:
+		default:
+			bit_width = 0x0;
+			break;
+		}
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_TX_PP_CFG, 0x0F,
+				    bit_width);
+
+		switch (dai->rate) {
+		case 384000:
+			rate = 0x30;
+			break;
+		case 192000:
+			rate = 0x20;
+			break;
+		case 48000:
+			rate = 0x10;
+			break;
+		case 16000:
+		default:
+			rate = 0x00;
+			break;
+		}
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_TX_PP_CFG, 0x70,
+				    rate);
+
+		buf_period = (dai->rate * (dai->bit_width/8)) / (16*1000);
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD,
+				    0xFF, buf_period);
+		dev_dbg(codec->dev, "%s: PP buffer period= 0x%x\n",
+			__func__, buf_period);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_write(codec, WCD9335_CPE_SS_TX_PP_CFG, 0x3C);
+		snd_soc_write(codec, WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD, 0x60);
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*
+ * tasha_codec_get_mad_port_id: Callback function that will be invoked
+ *	to get the port ID for MAD.
+ * @codec: Handle to the codec
+ * @port_id: cpe port_id needs to enable
+ */
+static int tasha_codec_get_mad_port_id(struct snd_soc_codec *codec,
+				       u16 *port_id)
+{
+	struct tasha_priv *tasha_p;
+	struct wcd9xxx_codec_dai_data *dai;
+	struct wcd9xxx_ch *ch;
+
+	if (!port_id || !codec)
+		return -EINVAL;
+
+	tasha_p = snd_soc_codec_get_drvdata(codec);
+	if (!tasha_p)
+		return -EINVAL;
+
+	dai = &tasha_p->dai[AIF4_MAD_TX];
+	list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+		if (ch->port == TASHA_TX12)
+			*port_id = WCD_CPE_AFE_OUT_PORT_2;
+		else if (ch->port == TASHA_TX13)
+			*port_id = WCD_CPE_AFE_OUT_PORT_4;
+		else {
+			dev_err(codec->dev, "%s: invalid mad_port = %d\n",
+					__func__, ch->port);
+			return -EINVAL;
+		}
+	}
+	dev_dbg(codec->dev, "%s: port_id = %d\n", __func__, *port_id);
+
+	return 0;
+}
+
+/*
+ * tasha_codec_enable_slimtx_mad: Callback function that will be invoked
+ *	to setup the slave port for MAD.
+ * @codec: Handle to the codec
+ * @event: Indicates whether to enable or disable the slave port
+ */
+static int tasha_codec_enable_slimtx_mad(struct snd_soc_codec *codec,
+					 u8 event)
+{
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_codec_dai_data *dai;
+	struct wcd9xxx_ch *ch;
+	int dapm_event = SND_SOC_DAPM_POST_PMU;
+	u16 port = 0;
+	int ret = 0;
+
+	dai = &tasha_p->dai[AIF4_MAD_TX];
+
+	if (event == 0)
+		dapm_event = SND_SOC_DAPM_POST_PMD;
+
+	dev_dbg(codec->dev,
+		"%s: mad_channel, event = 0x%x\n",
+		 __func__, event);
+
+	list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+		dev_dbg(codec->dev, "%s: mad_port = %d, event = 0x%x\n",
+			__func__, ch->port, event);
+		if (ch->port == TASHA_TX13) {
+			tasha_codec_cpe_pp_set_cfg(codec, dapm_event);
+			port = TASHA_TX13;
+			break;
+		}
+	}
+
+	ret = __tasha_codec_enable_slimtx(codec, dapm_event, dai);
+
+	if (port == TASHA_TX13) {
+		switch (dapm_event) {
+		case SND_SOC_DAPM_POST_PMU:
+			snd_soc_update_bits(codec,
+				WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN,
+				0x20, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG,
+				0x03, 0x02);
+			snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG,
+					    0x80, 0x80);
+			break;
+		case SND_SOC_DAPM_POST_PMD:
+			snd_soc_update_bits(codec,
+				WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN,
+				0x20, 0x20);
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG,
+				0x03, 0x00);
+			snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG,
+					    0x80, 0x00);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int tasha_put_iir_band_audio_mixer(
+					struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	/*
+	 * Mask top bit it is reserved
+	 * Updates addr automatically for each B2 write
+	 */
+	snd_soc_write(codec,
+		(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+				ucontrol->value.integer.value[0]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+				ucontrol->value.integer.value[1]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+				ucontrol->value.integer.value[2]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+				ucontrol->value.integer.value[3]);
+	set_iir_band_coeff(codec, iir_idx, band_idx,
+				ucontrol->value.integer.value[4]);
+
+	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+	return 0;
+}
+
+static int tasha_get_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tasha->comp_enabled[comp];
+	return 0;
+}
+
+static int tasha_set_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: Compander %d enable current %d, new %d\n",
+		 __func__, comp + 1, tasha->comp_enabled[comp], value);
+	tasha->comp_enabled[comp] = value;
+
+	/* Any specific register configuration for compander */
+	switch (comp) {
+	case COMPANDER_1:
+		/* Set Gain Source Select based on compander enable/disable */
+		snd_soc_update_bits(codec, WCD9335_HPH_L_EN, 0x20,
+				(value ? 0x00:0x20));
+		break;
+	case COMPANDER_2:
+		snd_soc_update_bits(codec, WCD9335_HPH_R_EN, 0x20,
+				(value ? 0x00:0x20));
+		break;
+	case COMPANDER_3:
+		break;
+	case COMPANDER_4:
+		break;
+	case COMPANDER_5:
+		snd_soc_update_bits(codec, WCD9335_SE_LO_LO3_GAIN, 0x20,
+				(value ? 0x00:0x20));
+		break;
+	case COMPANDER_6:
+		snd_soc_update_bits(codec, WCD9335_SE_LO_LO4_GAIN, 0x20,
+				(value ? 0x00:0x20));
+		break;
+	case COMPANDER_7:
+		break;
+	case COMPANDER_8:
+		break;
+	default:
+		/*
+		 * if compander is not enabled for any interpolator,
+		 * it does not cause any audio failure, so do not
+		 * return error in this case, but just print a log
+		 */
+		dev_warn(codec->dev, "%s: unknown compander: %d\n",
+			__func__, comp);
+	};
+	return 0;
+}
+
+static void tasha_codec_init_flyback(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, WCD9335_HPH_L_EN, 0xC0, 0x00);
+	snd_soc_update_bits(codec, WCD9335_HPH_R_EN, 0xC0, 0x00);
+	snd_soc_update_bits(codec, WCD9335_RX_BIAS_FLYB_BUFF, 0x0F, 0x00);
+	snd_soc_update_bits(codec, WCD9335_RX_BIAS_FLYB_BUFF, 0xF0, 0x00);
+}
+
+static int tasha_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tasha->rx_bias_count++;
+		if (tasha->rx_bias_count == 1) {
+			if (TASHA_IS_2_0(tasha->wcd9xxx))
+				tasha_codec_init_flyback(codec);
+			snd_soc_update_bits(codec, WCD9335_ANA_RX_SUPPLIES,
+					    0x01, 0x01);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tasha->rx_bias_count--;
+		if (!tasha->rx_bias_count)
+			snd_soc_update_bits(codec, WCD9335_ANA_RX_SUPPLIES,
+					    0x01, 0x00);
+		break;
+	};
+	dev_dbg(codec->dev, "%s: Current RX BIAS user count: %d\n", __func__,
+		tasha->rx_bias_count);
+
+	return 0;
+}
+
+static void tasha_realign_anc_coeff(struct snd_soc_codec *codec,
+				    u16 reg1, u16 reg2)
+{
+	u8 val1, val2, tmpval1, tmpval2;
+
+	snd_soc_write(codec, reg1, 0x00);
+	tmpval1 = snd_soc_read(codec, reg2);
+	tmpval2 = snd_soc_read(codec, reg2);
+	snd_soc_write(codec, reg1, 0x00);
+	snd_soc_write(codec, reg2, 0xFF);
+	snd_soc_write(codec, reg1, 0x01);
+	snd_soc_write(codec, reg2, 0xFF);
+
+	snd_soc_write(codec, reg1, 0x00);
+	val1 = snd_soc_read(codec, reg2);
+	val2 = snd_soc_read(codec, reg2);
+
+	if (val1 == 0x0F && val2 == 0xFF) {
+		dev_dbg(codec->dev, "%s: ANC0 co-eff index re-aligned\n",
+			__func__);
+		snd_soc_read(codec, reg2);
+		snd_soc_write(codec, reg1, 0x00);
+		snd_soc_write(codec, reg2, tmpval2);
+		snd_soc_write(codec, reg1, 0x01);
+		snd_soc_write(codec, reg2, tmpval1);
+	} else if (val1 == 0xFF && val2 == 0x0F) {
+		dev_dbg(codec->dev, "%s: ANC1 co-eff index already aligned\n",
+			__func__);
+		snd_soc_write(codec, reg1, 0x00);
+		snd_soc_write(codec, reg2, tmpval1);
+		snd_soc_write(codec, reg1, 0x01);
+		snd_soc_write(codec, reg2, tmpval2);
+	} else {
+		dev_err(codec->dev, "%s: ANC0 co-eff index not aligned\n",
+			__func__);
+	}
+}
+
+static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	const char *filename;
+	const struct firmware *fw;
+	int i;
+	int ret = 0;
+	int num_anc_slots;
+	struct wcd9xxx_anc_header *anc_head;
+	struct firmware_cal *hwdep_cal = NULL;
+	u32 anc_writes_size = 0;
+	u32 anc_cal_size = 0;
+	int anc_size_remaining;
+	u32 *anc_ptr;
+	u16 reg;
+	u8 mask, val;
+	size_t cal_size;
+	const void *data;
+
+	if (!tasha->anc_func)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, WCD9XXX_ANC_CAL);
+		if (hwdep_cal) {
+			data = hwdep_cal->data;
+			cal_size = hwdep_cal->size;
+			dev_dbg(codec->dev, "%s: using hwdep calibration\n",
+				__func__);
+		} else {
+			filename = "wcd9335/wcd9335_anc.bin";
+			ret = request_firmware(&fw, filename, codec->dev);
+			if (ret != 0) {
+				dev_err(codec->dev,
+				"Failed to acquire ANC data: %d\n", ret);
+				return -ENODEV;
+			}
+			if (!fw) {
+				dev_err(codec->dev, "failed to get anc fw");
+				return -ENODEV;
+			}
+			data = fw->data;
+			cal_size = fw->size;
+			dev_dbg(codec->dev,
+			"%s: using request_firmware calibration\n", __func__);
+		}
+		if (cal_size < sizeof(struct wcd9xxx_anc_header)) {
+			dev_err(codec->dev, "Not enough data\n");
+			ret = -ENOMEM;
+			goto err;
+		}
+		/* First number is the number of register writes */
+		anc_head = (struct wcd9xxx_anc_header *)(data);
+		anc_ptr = (u32 *)(data +
+				  sizeof(struct wcd9xxx_anc_header));
+		anc_size_remaining = cal_size -
+				     sizeof(struct wcd9xxx_anc_header);
+		num_anc_slots = anc_head->num_anc_slots;
+
+		if (tasha->anc_slot >= num_anc_slots) {
+			dev_err(codec->dev, "Invalid ANC slot selected\n");
+			ret = -EINVAL;
+			goto err;
+		}
+		for (i = 0; i < num_anc_slots; i++) {
+			if (anc_size_remaining < TASHA_PACKED_REG_SIZE) {
+				dev_err(codec->dev,
+					"Invalid register format\n");
+				ret = -EINVAL;
+				goto err;
+			}
+			anc_writes_size = (u32)(*anc_ptr);
+			anc_size_remaining -= sizeof(u32);
+			anc_ptr += 1;
+
+			if (anc_writes_size * TASHA_PACKED_REG_SIZE
+				> anc_size_remaining) {
+				dev_err(codec->dev,
+					"Invalid register format\n");
+				ret = -EINVAL;
+				goto err;
+			}
+
+			if (tasha->anc_slot == i)
+				break;
+
+			anc_size_remaining -= (anc_writes_size *
+				TASHA_PACKED_REG_SIZE);
+			anc_ptr += anc_writes_size;
+		}
+		if (i == num_anc_slots) {
+			dev_err(codec->dev, "Selected ANC slot not present\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		i = 0;
+		anc_cal_size = anc_writes_size;
+
+		if (!strcmp(w->name, "RX INT0 DAC") ||
+		    !strcmp(w->name, "ANC SPK1 PA"))
+			tasha_realign_anc_coeff(codec,
+					WCD9335_CDC_ANC0_IIR_COEFF_1_CTL,
+					WCD9335_CDC_ANC0_IIR_COEFF_2_CTL);
+
+		if (!strcmp(w->name, "RX INT1 DAC") ||
+			!strcmp(w->name, "RX INT3 DAC")) {
+			tasha_realign_anc_coeff(codec,
+					WCD9335_CDC_ANC0_IIR_COEFF_1_CTL,
+					WCD9335_CDC_ANC0_IIR_COEFF_2_CTL);
+			anc_writes_size = anc_cal_size / 2;
+			snd_soc_update_bits(codec,
+			WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x39, 0x39);
+		} else if (!strcmp(w->name, "RX INT2 DAC") ||
+				!strcmp(w->name, "RX INT4 DAC")) {
+			tasha_realign_anc_coeff(codec,
+					WCD9335_CDC_ANC1_IIR_COEFF_1_CTL,
+					WCD9335_CDC_ANC1_IIR_COEFF_2_CTL);
+			i = anc_cal_size / 2;
+			snd_soc_update_bits(codec,
+			WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x39, 0x39);
+		}
+
+		for (; i < anc_writes_size; i++) {
+			TASHA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg, mask, val);
+			snd_soc_write(codec, reg, (val & mask));
+		}
+		if (!strcmp(w->name, "RX INT1 DAC") ||
+			!strcmp(w->name, "RX INT3 DAC")) {
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08);
+		} else if (!strcmp(w->name, "RX INT2 DAC") ||
+				!strcmp(w->name, "RX INT4 DAC")) {
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08);
+		}
+
+		if (!hwdep_cal)
+			release_firmware(fw);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Remove ANC Rx from reset */
+		snd_soc_update_bits(codec, WCD9335_CDC_ANC0_CLK_RESET_CTL,
+				    0x08, 0x00);
+		snd_soc_update_bits(codec, WCD9335_CDC_ANC1_CLK_RESET_CTL,
+				    0x08, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (!strcmp(w->name, "ANC HPHL PA") ||
+		    !strcmp(w->name, "ANC EAR PA") ||
+		    !strcmp(w->name, "ANC SPK1 PA") ||
+		    !strcmp(w->name, "ANC LINEOUT1 PA")) {
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC0_MODE_1_CTL, 0x30, 0x00);
+			msleep(50);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC0_MODE_1_CTL, 0x01, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x38);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x07, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x00);
+		} else if (!strcmp(w->name, "ANC HPHR PA") ||
+			   !strcmp(w->name, "ANC LINEOUT2 PA")) {
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC1_MODE_1_CTL, 0x30, 0x00);
+			msleep(50);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC1_MODE_1_CTL, 0x01, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x38);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x07, 0x00);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x00);
+		}
+		break;
+	}
+
+	return 0;
+err:
+	if (!hwdep_cal)
+		release_firmware(fw);
+	return ret;
+}
+
+static void tasha_codec_clear_anc_tx_hold(struct tasha_priv *tasha)
+{
+	if (test_and_clear_bit(ANC_MIC_AMIC1, &tasha->status_mask))
+		tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC1, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC2, &tasha->status_mask))
+		tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC2, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC3, &tasha->status_mask))
+		tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC3, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC4, &tasha->status_mask))
+		tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC4, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC5, &tasha->status_mask))
+		tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC5, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC6, &tasha->status_mask))
+		tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC6, false);
+}
+
+static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha,
+					   int mode, int event)
+{
+	u8 scale_val = 0;
+
+	if (!TASHA_IS_2_0(tasha->wcd9xxx))
+		return;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		switch (mode) {
+		case CLS_H_HIFI:
+			scale_val = 0x3;
+			break;
+		case CLS_H_LOHIFI:
+			scale_val = 0x1;
+			break;
+		}
+		if (tasha->anc_func) {
+			/* Clear Tx FE HOLD if both PAs are enabled */
+			if ((snd_soc_read(tasha->codec, WCD9335_ANA_HPH) &
+			     0xC0) == 0xC0) {
+				tasha_codec_clear_anc_tx_hold(tasha);
+			}
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		scale_val = 0x6;
+		break;
+	}
+
+	if (scale_val)
+		snd_soc_update_bits(tasha->codec, WCD9335_HPH_PA_CTL1, 0x0E,
+				    scale_val << 1);
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (tasha->comp_enabled[COMPANDER_1] ||
+		    tasha->comp_enabled[COMPANDER_2]) {
+			snd_soc_update_bits(tasha->codec, WCD9335_HPH_L_EN,
+					    0x20, 0x00);
+			snd_soc_update_bits(tasha->codec, WCD9335_HPH_R_EN,
+					    0x20, 0x00);
+			snd_soc_update_bits(tasha->codec, WCD9335_HPH_AUTO_CHOP,
+					    0x20, 0x20);
+		}
+		snd_soc_update_bits(tasha->codec, WCD9335_HPH_L_EN, 0x1F,
+				    tasha->hph_l_gain);
+		snd_soc_update_bits(tasha->codec, WCD9335_HPH_R_EN, 0x1F,
+				    tasha->hph_r_gain);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(tasha->codec, WCD9335_HPH_AUTO_CHOP, 0x20,
+				    0x00);
+	}
+}
+
+static void tasha_codec_override(struct snd_soc_codec *codec,
+				 int mode,
+				 int event)
+{
+	if (mode == CLS_AB) {
+		switch (event) {
+		case SND_SOC_DAPM_POST_PMU:
+			if (!(snd_soc_read(codec,
+					WCD9335_CDC_RX2_RX_PATH_CTL) & 0x10) &&
+				(!(snd_soc_read(codec,
+					WCD9335_CDC_RX1_RX_PATH_CTL) & 0x10)))
+				snd_soc_update_bits(codec,
+					WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02);
+		break;
+		case SND_SOC_DAPM_POST_PMD:
+			snd_soc_update_bits(codec,
+				WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x00);
+		break;
+		}
+	}
+}
+
+static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int hph_mode = tasha->hph_mode;
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if ((!(strcmp(w->name, "ANC HPHR PA"))) &&
+		    (test_bit(HPH_PA_DELAY, &tasha->status_mask))) {
+			snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0xC0, 0xC0);
+		}
+		set_bit(HPH_PA_DELAY, &tasha->status_mask);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (!(strcmp(w->name, "ANC HPHR PA"))) {
+			if ((snd_soc_read(codec, WCD9335_ANA_HPH) & 0xC0)
+							!= 0xC0)
+				/*
+				 * If PA_EN is not set (potentially in ANC case)
+				 * then do nothing for POST_PMU and let left
+				 * channel handle everything.
+				 */
+				break;
+		}
+		/*
+		 * 7ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) {
+			usleep_range(7000, 7100);
+			clear_bit(HPH_PA_DELAY, &tasha->status_mask);
+		}
+		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
+		snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_CTL,
+				    0x10, 0x00);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) &
+				  0x10)
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+					    0x10, 0x00);
+
+		if (!(strcmp(w->name, "ANC HPHR PA"))) {
+			/* Do everything needed for left channel */
+			snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CTL,
+					    0x10, 0x00);
+			/* Remove mix path mute if it is enabled */
+			if ((snd_soc_read(codec,
+					  WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) &
+					  0x10)
+				snd_soc_update_bits(codec,
+						WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+						0x10, 0x00);
+			/* Remove ANC Rx from reset */
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+		}
+		tasha_codec_override(codec, hph_mode, event);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		blocking_notifier_call_chain(&tasha->notifier,
+					WCD_EVENT_PRE_HPHR_PA_OFF,
+					&tasha->mbhc);
+		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
+		if (!(strcmp(w->name, "ANC HPHR PA")))
+			snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0x40, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		tasha_codec_override(codec, hph_mode, event);
+		blocking_notifier_call_chain(&tasha->notifier,
+					WCD_EVENT_POST_HPHR_PA_OFF,
+					&tasha->mbhc);
+
+		if (!(strcmp(w->name, "ANC HPHR PA"))) {
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_RX2_RX_PATH_CFG0, 0x10, 0x00);
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int hph_mode = tasha->hph_mode;
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if ((!(strcmp(w->name, "ANC HPHL PA"))) &&
+		    (test_bit(HPH_PA_DELAY, &tasha->status_mask))) {
+			snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0xC0, 0xC0);
+		}
+		set_bit(HPH_PA_DELAY, &tasha->status_mask);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			if ((snd_soc_read(codec, WCD9335_ANA_HPH) & 0xC0)
+								!= 0xC0)
+				/*
+				 * If PA_EN is not set (potentially in ANC case)
+				 * then do nothing for POST_PMU and let right
+				 * channel handle everything.
+				 */
+				break;
+		}
+		/*
+		 * 7ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) {
+			usleep_range(7000, 7100);
+			clear_bit(HPH_PA_DELAY, &tasha->status_mask);
+		}
+
+		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
+		snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CTL,
+				    0x10, 0x00);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) &
+				  0x10)
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+					    0x10, 0x00);
+
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			/* Do everything needed for right channel */
+			snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_CTL,
+					    0x10, 0x00);
+			/* Remove mix path mute if it is enabled */
+			if ((snd_soc_read(codec,
+					  WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) &
+					  0x10)
+				snd_soc_update_bits(codec,
+						WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+						0x10, 0x00);
+
+			/* Remove ANC Rx from reset */
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+		}
+		tasha_codec_override(codec, hph_mode, event);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		blocking_notifier_call_chain(&tasha->notifier,
+					WCD_EVENT_PRE_HPHL_PA_OFF,
+					&tasha->mbhc);
+		tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
+		if (!(strcmp(w->name, "ANC HPHL PA")))
+			snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0x80, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		tasha_codec_override(codec, hph_mode, event);
+		blocking_notifier_call_chain(&tasha->notifier,
+					WCD_EVENT_POST_HPHL_PA_OFF,
+					&tasha->mbhc);
+
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_RX1_RX_PATH_CFG0, 0x10, 0x00);
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static int tasha_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0;
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	if (w->reg == WCD9335_ANA_LO_1_2) {
+		if (w->shift == 7) {
+			lineout_vol_reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+			lineout_mix_vol_reg = WCD9335_CDC_RX3_RX_PATH_MIX_CTL;
+		} else if (w->shift == 6) {
+			lineout_vol_reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+			lineout_mix_vol_reg = WCD9335_CDC_RX4_RX_PATH_MIX_CTL;
+		}
+	} else if (w->reg == WCD9335_ANA_LO_3_4) {
+		if (w->shift == 7) {
+			lineout_vol_reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+			lineout_mix_vol_reg = WCD9335_CDC_RX5_RX_PATH_MIX_CTL;
+		} else if (w->shift == 6) {
+			lineout_vol_reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+			lineout_mix_vol_reg = WCD9335_CDC_RX6_RX_PATH_MIX_CTL;
+		}
+	} else {
+		dev_err(codec->dev, "%s: Error enabling lineout PA\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* 5ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		snd_soc_update_bits(codec, lineout_vol_reg,
+				    0x10, 0x00);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, lineout_mix_vol_reg)) & 0x10)
+			snd_soc_update_bits(codec,
+					    lineout_mix_vol_reg,
+					    0x10, 0x00);
+		if (!(strcmp(w->name, "ANC LINEOUT1 PA")) ||
+		    !(strcmp(w->name, "ANC LINEOUT2 PA")))
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+		tasha_codec_override(codec, CLS_AB, event);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		tasha_codec_override(codec, CLS_AB, event);
+		if (!(strcmp(w->name, "ANC LINEOUT1 PA")) ||
+			!(strcmp(w->name, "ANC LINEOUT2 PA"))) {
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+			if (!(strcmp(w->name, "ANC LINEOUT1 PA")))
+				snd_soc_update_bits(codec,
+				WCD9335_CDC_RX3_RX_PATH_CFG0, 0x10, 0x10);
+			else
+				snd_soc_update_bits(codec,
+				WCD9335_CDC_RX4_RX_PATH_CFG0, 0x10, 0x10);
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static void tasha_spk_anc_update_callback(struct work_struct *work)
+{
+	struct spk_anc_work *spk_anc_dwork;
+	struct tasha_priv *tasha;
+	struct delayed_work *delayed_work;
+	struct snd_soc_codec *codec;
+
+	delayed_work = to_delayed_work(work);
+	spk_anc_dwork = container_of(delayed_work, struct spk_anc_work, dwork);
+	tasha = spk_anc_dwork->tasha;
+	codec = tasha->codec;
+
+	snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_CFG0, 0x10, 0x10);
+}
+
+static int tasha_codec_enable_spk_anc(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d %d\n", __func__, w->name, event,
+		tasha->anc_func);
+
+	if (!tasha->anc_func)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = tasha_codec_enable_anc(w, kcontrol, event);
+		schedule_delayed_work(&tasha->spk_anc_dwork.dwork,
+				      msecs_to_jiffies(spk_anc_en_delay));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		cancel_delayed_work_sync(&tasha->spk_anc_dwork.dwork);
+		snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_CFG0,
+				    0x10, 0x00);
+		ret = tasha_codec_enable_anc(w, kcontrol, event);
+		break;
+	}
+	return ret;
+}
+
+static int tasha_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* 5ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		snd_soc_update_bits(codec, WCD9335_CDC_RX0_RX_PATH_CTL,
+				    0x10, 0x00);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, WCD9335_CDC_RX0_RX_PATH_MIX_CTL)) &
+		     0x10)
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX0_RX_PATH_MIX_CTL,
+					    0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+
+		if (!(strcmp(w->name, "ANC EAR PA"))) {
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_RX0_RX_PATH_CFG0, 0x10, 0x00);
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static void tasha_codec_hph_mode_gain_opt(struct snd_soc_codec *codec,
+					  u8 gain)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u8 hph_l_en, hph_r_en;
+	u8 l_val, r_val;
+	u8 hph_pa_status;
+	bool is_hphl_pa, is_hphr_pa;
+
+	hph_pa_status = snd_soc_read(codec, WCD9335_ANA_HPH);
+	is_hphl_pa = hph_pa_status >> 7;
+	is_hphr_pa = (hph_pa_status & 0x40) >> 6;
+
+	hph_l_en = snd_soc_read(codec, WCD9335_HPH_L_EN);
+	hph_r_en = snd_soc_read(codec, WCD9335_HPH_R_EN);
+
+	l_val = (hph_l_en & 0xC0) | 0x20 | gain;
+	r_val = (hph_r_en & 0xC0) | 0x20 | gain;
+
+	/*
+	 * Set HPH_L & HPH_R gain source selection to REGISTER
+	 * for better click and pop only if corresponding PAs are
+	 * not enabled. Also cache the values of the HPHL/R
+	 * PA gains to be applied after PAs are enabled
+	 */
+	if ((l_val != hph_l_en) && !is_hphl_pa) {
+		snd_soc_write(codec, WCD9335_HPH_L_EN, l_val);
+		tasha->hph_l_gain = hph_l_en & 0x1F;
+	}
+
+	if ((r_val != hph_r_en) && !is_hphr_pa) {
+		snd_soc_write(codec, WCD9335_HPH_R_EN, r_val);
+		tasha->hph_r_gain = hph_r_en & 0x1F;
+	}
+}
+
+static void tasha_codec_hph_lohifi_config(struct snd_soc_codec *codec,
+					  int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x06);
+		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2,
+				    0xF0, 0x40);
+		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
+		tasha_codec_hph_mode_gain_opt(codec, 0x11);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
+		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
+		snd_soc_write(codec, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A);
+		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x0A);
+	}
+}
+
+static void tasha_codec_hph_lp_config(struct snd_soc_codec *codec,
+				      int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
+		tasha_codec_hph_mode_gain_opt(codec, 0x10);
+		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x04, 0x04);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x20, 0x20);
+		snd_soc_update_bits(codec, WCD9335_HPH_RDAC_LDO_CTL, 0x07,
+				    0x01);
+		snd_soc_update_bits(codec, WCD9335_HPH_RDAC_LDO_CTL, 0x70,
+				    0x10);
+		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_RDAC_LDO,
+				    0x0F, 0x01);
+		snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_RDAC_LDO,
+				    0xF0, 0x10);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_write(codec, WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x88);
+		snd_soc_write(codec, WCD9335_HPH_RDAC_LDO_CTL, 0x33);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x20, 0x00);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x04, 0x00);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
+		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
+		snd_soc_update_bits(codec, WCD9335_HPH_R_EN, 0xC0, 0x80);
+		snd_soc_update_bits(codec, WCD9335_HPH_L_EN, 0xC0, 0x80);
+	}
+}
+
+static void tasha_codec_hph_hifi_config(struct snd_soc_codec *codec,
+					int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
+		tasha_codec_hph_mode_gain_opt(codec, 0x11);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
+		snd_soc_update_bits(codec, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
+	}
+}
+
+static void tasha_codec_hph_mode_config(struct snd_soc_codec *codec,
+					int event, int mode)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (!TASHA_IS_2_0(tasha->wcd9xxx))
+		return;
+
+	switch (mode) {
+	case CLS_H_LP:
+		tasha_codec_hph_lp_config(codec, event);
+		break;
+	case CLS_H_LOHIFI:
+		tasha_codec_hph_lohifi_config(codec, event);
+		break;
+	case CLS_H_HIFI:
+		tasha_codec_hph_hifi_config(codec, event);
+		break;
+	}
+}
+
+static int tasha_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	int hph_mode = tasha->hph_mode;
+	u8 dem_inp;
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__,
+		w->name, event, hph_mode);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tasha->anc_func) {
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+			/* 40 msec delay is needed to avoid click and pop */
+			msleep(40);
+		}
+
+		/* Read DEM INP Select */
+		dem_inp = snd_soc_read(codec, WCD9335_CDC_RX2_RX_PATH_SEC0) &
+			  0x03;
+		if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+		     (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+			dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n",
+					__func__, hph_mode);
+			return -EINVAL;
+		}
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_HPHR,
+			     ((hph_mode == CLS_H_LOHIFI) ?
+			       CLS_H_HIFI : hph_mode));
+
+		tasha_codec_hph_mode_config(codec, event, hph_mode);
+
+		if (tasha->anc_func)
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_RX2_RX_PATH_CFG0, 0x10, 0x10);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+		if ((hph_mode == CLS_H_LP) &&
+		   (TASHA_IS_1_1(wcd9xxx))) {
+			snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL,
+					    0x03, 0x03);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if ((hph_mode == CLS_H_LP) &&
+		   (TASHA_IS_1_1(wcd9xxx))) {
+			snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL,
+					    0x03, 0x00);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+
+		if (!(wcd_clsh_get_clsh_state(&tasha->clsh_d) &
+		     WCD_CLSH_STATE_HPHL))
+			tasha_codec_hph_mode_config(codec, event, hph_mode);
+
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_HPHR,
+			     ((hph_mode == CLS_H_LOHIFI) ?
+			       CLS_H_HIFI : hph_mode));
+		break;
+	};
+
+	return ret;
+}
+
+static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	int hph_mode = tasha->hph_mode;
+	u8 dem_inp;
+	int ret = 0;
+	uint32_t impedl = 0, impedr = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__,
+		w->name, event, hph_mode);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tasha->anc_func) {
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+			/* 40 msec delay is needed to avoid click and pop */
+			msleep(40);
+		}
+
+		/* Read DEM INP Select */
+		dem_inp = snd_soc_read(codec, WCD9335_CDC_RX1_RX_PATH_SEC0) &
+			  0x03;
+		if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+		     (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+			dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n",
+					__func__, hph_mode);
+			return -EINVAL;
+		}
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_HPHL,
+			     ((hph_mode == CLS_H_LOHIFI) ?
+			       CLS_H_HIFI : hph_mode));
+
+		tasha_codec_hph_mode_config(codec, event, hph_mode);
+
+		if (tasha->anc_func)
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_RX1_RX_PATH_CFG0, 0x10, 0x10);
+
+		ret = wcd_mbhc_get_impedance(&tasha->mbhc,
+					&impedl, &impedr);
+		if (!ret) {
+			wcd_clsh_imped_config(codec, impedl, false);
+			set_bit(CLASSH_CONFIG, &tasha->status_mask);
+		} else {
+			dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n",
+						__func__, ret);
+			ret = 0;
+		}
+
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+		if ((hph_mode == CLS_H_LP) &&
+		   (TASHA_IS_1_1(wcd9xxx))) {
+			snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL,
+					    0x03, 0x03);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if ((hph_mode == CLS_H_LP) &&
+		   (TASHA_IS_1_1(wcd9xxx))) {
+			snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL,
+					    0x03, 0x00);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+
+		if (!(wcd_clsh_get_clsh_state(&tasha->clsh_d) &
+		     WCD_CLSH_STATE_HPHR))
+			tasha_codec_hph_mode_config(codec, event, hph_mode);
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_HPHL,
+			     ((hph_mode == CLS_H_LOHIFI) ?
+			       CLS_H_HIFI : hph_mode));
+
+		if (test_bit(CLASSH_CONFIG, &tasha->status_mask)) {
+			wcd_clsh_imped_config(codec, impedl, true);
+			clear_bit(CLASSH_CONFIG, &tasha->status_mask);
+		} else
+			dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n",
+						__func__, ret);
+
+
+		break;
+	};
+
+	return ret;
+}
+
+static int tasha_codec_lineout_dac_event(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tasha->anc_func &&
+			(!strcmp(w->name, "RX INT3 DAC") ||
+				!strcmp(w->name, "RX INT4 DAC")))
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_LO,
+			     CLS_AB);
+
+		if (tasha->anc_func) {
+			if (!strcmp(w->name, "RX INT3 DAC"))
+				snd_soc_update_bits(codec,
+				WCD9335_CDC_RX3_RX_PATH_CFG0, 0x10, 0x10);
+			else if (!strcmp(w->name, "RX INT4 DAC"))
+				snd_soc_update_bits(codec,
+				WCD9335_CDC_RX4_RX_PATH_CFG0, 0x10, 0x10);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_LO,
+			     CLS_AB);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget tasha_dapm_i2s_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CTL", WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+	0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CTL", WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,
+	0, 0, NULL, 0),
+};
+
+static int tasha_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tasha->anc_func)
+			ret = tasha_codec_enable_anc(w, kcontrol, event);
+
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_EAR,
+			     CLS_H_NORMAL);
+		if (tasha->anc_func)
+			snd_soc_update_bits(codec,
+				WCD9335_CDC_RX0_RX_PATH_CFG0, 0x10, 0x10);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_clsh_fsm(codec, &tasha->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_EAR,
+			     CLS_H_NORMAL);
+		break;
+	};
+
+	return ret;
+}
+
+static int tasha_codec_spk_boost_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 boost_path_ctl, boost_path_cfg1;
+	u16 reg, reg_mix;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	if (!strcmp(w->name, "RX INT7 CHAIN")) {
+		boost_path_ctl = WCD9335_CDC_BOOST0_BOOST_PATH_CTL;
+		boost_path_cfg1 = WCD9335_CDC_RX7_RX_PATH_CFG1;
+		reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+		reg_mix = WCD9335_CDC_RX7_RX_PATH_MIX_CTL;
+	} else if (!strcmp(w->name, "RX INT8 CHAIN")) {
+		boost_path_ctl = WCD9335_CDC_BOOST1_BOOST_PATH_CTL;
+		boost_path_cfg1 = WCD9335_CDC_RX8_RX_PATH_CFG1;
+		reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+		reg_mix = WCD9335_CDC_RX8_RX_PATH_MIX_CTL;
+	} else {
+		dev_err(codec->dev, "%s: unknown widget: %s\n",
+			__func__, w->name);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x10);
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x01);
+		snd_soc_update_bits(codec, reg, 0x10, 0x00);
+		if ((snd_soc_read(codec, reg_mix)) & 0x10)
+			snd_soc_update_bits(codec, reg_mix, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x00);
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x00);
+		break;
+	};
+
+	return 0;
+}
+
+static u16 tasha_interp_get_primary_reg(u16 reg, u16 *ind)
+{
+	u16 prim_int_reg = 0;
+
+	switch (reg) {
+	case WCD9335_CDC_RX0_RX_PATH_CTL:
+	case WCD9335_CDC_RX0_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL;
+		*ind = 0;
+		break;
+	case WCD9335_CDC_RX1_RX_PATH_CTL:
+	case WCD9335_CDC_RX1_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+		*ind = 1;
+		break;
+	case WCD9335_CDC_RX2_RX_PATH_CTL:
+	case WCD9335_CDC_RX2_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX2_RX_PATH_CTL;
+		*ind = 2;
+		break;
+	case WCD9335_CDC_RX3_RX_PATH_CTL:
+	case WCD9335_CDC_RX3_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+		*ind = 3;
+		break;
+	case WCD9335_CDC_RX4_RX_PATH_CTL:
+	case WCD9335_CDC_RX4_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+		*ind = 4;
+		break;
+	case WCD9335_CDC_RX5_RX_PATH_CTL:
+	case WCD9335_CDC_RX5_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+		*ind = 5;
+		break;
+	case WCD9335_CDC_RX6_RX_PATH_CTL:
+	case WCD9335_CDC_RX6_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+		*ind = 6;
+		break;
+	case WCD9335_CDC_RX7_RX_PATH_CTL:
+	case WCD9335_CDC_RX7_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+		*ind = 7;
+		break;
+	case WCD9335_CDC_RX8_RX_PATH_CTL:
+	case WCD9335_CDC_RX8_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+		*ind = 8;
+		break;
+	};
+
+	return prim_int_reg;
+}
+
+static void tasha_codec_hd2_control(struct snd_soc_codec *codec,
+				    u16 prim_int_reg, int event)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u16 hd2_scale_reg;
+	u16 hd2_enable_reg = 0;
+
+	if (!TASHA_IS_2_0(tasha->wcd9xxx))
+		return;
+
+	if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) {
+		hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3;
+		hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+	}
+	if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) {
+		hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3;
+		hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01);
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04);
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00);
+	}
+}
+
+static int tasha_codec_enable_prim_interpolator(
+				struct snd_soc_codec *codec,
+				u16 reg, int event)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u16 prim_int_reg;
+	u16 ind = 0;
+
+	prim_int_reg = tasha_interp_get_primary_reg(reg, &ind);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tasha->prim_int_users[ind]++;
+		if (tasha->prim_int_users[ind] == 1) {
+			snd_soc_update_bits(codec, prim_int_reg,
+					    0x10, 0x10);
+			tasha_codec_hd2_control(codec, prim_int_reg, event);
+			snd_soc_update_bits(codec, prim_int_reg,
+					    1 << 0x5, 1 << 0x5);
+		}
+		if ((reg != prim_int_reg) &&
+		    ((snd_soc_read(codec, prim_int_reg)) & 0x10))
+			snd_soc_update_bits(codec, reg, 0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tasha->prim_int_users[ind]--;
+		if (tasha->prim_int_users[ind] == 0) {
+			snd_soc_update_bits(codec, prim_int_reg,
+					1 << 0x5, 0 << 0x5);
+			snd_soc_update_bits(codec, prim_int_reg,
+					0x40, 0x40);
+			snd_soc_update_bits(codec, prim_int_reg,
+					0x40, 0x00);
+			tasha_codec_hd2_control(codec, prim_int_reg, event);
+		}
+		break;
+	};
+
+	dev_dbg(codec->dev, "%s: primary interpolator: INT%d, users: %d\n",
+		__func__, ind, tasha->prim_int_users[ind]);
+	return 0;
+}
+
+static int tasha_codec_enable_spline_src(struct snd_soc_codec *codec,
+					 int src_num,
+					 int event)
+{
+	u16 src_paired_reg = 0;
+	struct tasha_priv *tasha;
+	u16 rx_path_cfg_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+	u16 rx_path_ctl_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+	int *src_users, count, spl_src = SPLINE_SRC0;
+	u16 src_clk_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0;
+
+	tasha = snd_soc_codec_get_drvdata(codec);
+
+	switch (src_num) {
+	case SRC_IN_HPHL:
+		rx_path_cfg_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+		spl_src = SPLINE_SRC0;
+		break;
+	case SRC_IN_LO1:
+		rx_path_cfg_reg = WCD9335_CDC_RX3_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+		spl_src = SPLINE_SRC0;
+		break;
+	case SRC_IN_HPHR:
+		rx_path_cfg_reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX2_RX_PATH_CTL;
+		spl_src = SPLINE_SRC1;
+		break;
+	case SRC_IN_LO2:
+		rx_path_cfg_reg = WCD9335_CDC_RX4_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+		spl_src = SPLINE_SRC1;
+		break;
+	case SRC_IN_SPKRL:
+		rx_path_cfg_reg = WCD9335_CDC_RX7_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+		spl_src = SPLINE_SRC2;
+		break;
+	case SRC_IN_LO3:
+		rx_path_cfg_reg = WCD9335_CDC_RX5_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+		spl_src = SPLINE_SRC2;
+		break;
+	case SRC_IN_SPKRR:
+		rx_path_cfg_reg = WCD9335_CDC_RX8_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+		spl_src = SPLINE_SRC3;
+		break;
+	case SRC_IN_LO4:
+		rx_path_cfg_reg = WCD9335_CDC_RX6_RX_PATH_CFG0;
+		src_clk_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0;
+		src_paired_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0;
+		rx_path_ctl_reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+		spl_src = SPLINE_SRC3;
+		break;
+	};
+
+	src_users = &tasha->spl_src_users[spl_src];
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		count = *src_users;
+		count++;
+		if (count == 1) {
+			if ((snd_soc_read(codec, src_clk_reg) & 0x02) ||
+			    (snd_soc_read(codec, src_paired_reg) & 0x02)) {
+				snd_soc_update_bits(codec, src_clk_reg, 0x02,
+						    0x00);
+				snd_soc_update_bits(codec, src_paired_reg,
+						    0x02, 0x00);
+			}
+			snd_soc_update_bits(codec, src_clk_reg,	0x01, 0x01);
+			snd_soc_update_bits(codec, rx_path_cfg_reg, 0x80,
+					    0x80);
+		}
+		*src_users = count;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		count = *src_users;
+		count--;
+		if (count == 0) {
+			snd_soc_update_bits(codec, rx_path_cfg_reg, 0x80,
+					    0x00);
+			snd_soc_update_bits(codec, src_clk_reg, 0x03, 0x02);
+			/* default sample rate */
+			snd_soc_update_bits(codec, rx_path_ctl_reg, 0x0f,
+					    0x04);
+		}
+		*src_users = count;
+		break;
+	};
+
+	dev_dbg(codec->dev, "%s: Spline SRC%d, users: %d\n",
+		__func__, spl_src, *src_users);
+	return 0;
+}
+
+static int tasha_codec_enable_spline_resampler(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int ret = 0;
+	u8 src_in;
+
+	src_in = snd_soc_read(codec, WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0);
+	if (!(src_in & 0xFF)) {
+		dev_err(codec->dev, "%s: Spline SRC%u input not selected\n",
+			__func__, w->shift);
+		return -EINVAL;
+	}
+
+	switch (w->shift) {
+	case SPLINE_SRC0:
+		ret = tasha_codec_enable_spline_src(codec,
+			((src_in & 0x03) == 1) ? SRC_IN_HPHL : SRC_IN_LO1,
+			event);
+		break;
+	case SPLINE_SRC1:
+		ret = tasha_codec_enable_spline_src(codec,
+			((src_in & 0x0C) == 4) ? SRC_IN_HPHR : SRC_IN_LO2,
+			event);
+		break;
+	case SPLINE_SRC2:
+		ret = tasha_codec_enable_spline_src(codec,
+			((src_in & 0x30) == 0x10) ? SRC_IN_LO3 : SRC_IN_SPKRL,
+			event);
+		break;
+	case SPLINE_SRC3:
+		ret = tasha_codec_enable_spline_src(codec,
+			((src_in & 0xC0) == 0x40) ? SRC_IN_LO4 : SRC_IN_SPKRR,
+			event);
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid spline src:%u\n", __func__,
+			w->shift);
+		ret = -EINVAL;
+	};
+
+	return ret;
+}
+
+static int tasha_codec_enable_swr(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha;
+	int i, ch_cnt;
+
+	tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (!tasha->nr)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) &&
+		    !tasha->rx_7_count)
+			tasha->rx_7_count++;
+		if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) &&
+		    !tasha->rx_8_count)
+			tasha->rx_8_count++;
+		ch_cnt = tasha->rx_7_count + tasha->rx_8_count;
+
+		for (i = 0; i < tasha->nr; i++) {
+			swrm_wcd_notify(tasha->swr_ctrl_data[i].swr_pdev,
+					SWR_DEVICE_UP, NULL);
+			swrm_wcd_notify(tasha->swr_ctrl_data[i].swr_pdev,
+					SWR_SET_NUM_RX_CH, &ch_cnt);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) &&
+		    tasha->rx_7_count)
+			tasha->rx_7_count--;
+		if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) &&
+		    tasha->rx_8_count)
+			tasha->rx_8_count--;
+		ch_cnt = tasha->rx_7_count + tasha->rx_8_count;
+
+		for (i = 0; i < tasha->nr; i++)
+			swrm_wcd_notify(tasha->swr_ctrl_data[i].swr_pdev,
+					SWR_SET_NUM_RX_CH, &ch_cnt);
+
+		break;
+	}
+	dev_dbg(tasha->dev, "%s: current swr ch cnt: %d\n",
+		__func__, tasha->rx_7_count + tasha->rx_8_count);
+
+	return 0;
+}
+
+static int tasha_codec_config_ear_spkr_gain(struct snd_soc_codec *codec,
+					    int event, int gain_reg)
+{
+	int comp_gain_offset, val;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	switch (tasha->spkr_mode) {
+	/* Compander gain in SPKR_MODE1 case is 12 dB */
+	case SPKR_MODE_1:
+		comp_gain_offset = -12;
+		break;
+	/* Default case compander gain is 15 dB */
+	default:
+		comp_gain_offset = -15;
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Apply ear spkr gain only if compander is enabled */
+		if (tasha->comp_enabled[COMPANDER_7] &&
+		    (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL) &&
+		    (tasha->ear_spkr_gain != 0)) {
+			/* For example, val is -8(-12+5-1) for 4dB of gain */
+			val = comp_gain_offset + tasha->ear_spkr_gain - 1;
+			snd_soc_write(codec, gain_reg, val);
+
+			dev_dbg(codec->dev, "%s: RX7 Volume %d dB\n",
+				__func__, val);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * Reset RX7 volume to 0 dB if compander is enabled and
+		 * ear_spkr_gain is non-zero.
+		 */
+		if (tasha->comp_enabled[COMPANDER_7] &&
+		    (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL) &&
+		    (tasha->ear_spkr_gain != 0)) {
+			snd_soc_write(codec, gain_reg, 0x0);
+
+			dev_dbg(codec->dev, "%s: Reset RX7 Volume to 0 dB\n",
+				__func__);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int tasha_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u16 gain_reg;
+	int offset_val = 0;
+	int val = 0;
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+	switch (w->reg) {
+	case WCD9335_CDC_RX0_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX0_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX1_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX1_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX2_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX2_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX3_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX3_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX4_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX4_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX5_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX5_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX6_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX6_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX7_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX7_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX8_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX8_RX_VOL_MIX_CTL;
+		break;
+	default:
+		dev_err(codec->dev, "%s: No gain register avail for %s\n",
+			__func__, w->name);
+		return 0;
+	};
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tasha->comp_enabled[COMPANDER_7] ||
+		     tasha->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL ||
+		     gain_reg == WCD9335_CDC_RX8_RX_VOL_MIX_CTL)) {
+			snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			offset_val = -2;
+		}
+		val = snd_soc_read(codec, gain_reg);
+		val += offset_val;
+		snd_soc_write(codec, gain_reg, val);
+		tasha_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tasha->comp_enabled[COMPANDER_7] ||
+		     tasha->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL ||
+		     gain_reg == WCD9335_CDC_RX8_RX_VOL_MIX_CTL)) {
+			snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			offset_val = 2;
+			val = snd_soc_read(codec, gain_reg);
+			val += offset_val;
+			snd_soc_write(codec, gain_reg, val);
+		}
+		tasha_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	};
+
+	return 0;
+}
+
+static int __tasha_cdc_native_clk_enable(struct tasha_priv *tasha,
+					 bool enable)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = tasha->codec;
+
+	if (!tasha->wcd_native_clk) {
+		dev_err(tasha->dev, "%s: wcd native clock is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(tasha->dev, "%s: native_clk_enable = %u\n", __func__, enable);
+
+	if (enable) {
+		ret = clk_prepare_enable(tasha->wcd_native_clk);
+		if (ret) {
+			dev_err(tasha->dev, "%s: native clk enable failed\n",
+				__func__);
+			goto err;
+		}
+		if (++tasha->native_clk_users == 1) {
+			snd_soc_update_bits(codec, WCD9335_CLOCK_TEST_CTL,
+					    0x10, 0x10);
+			snd_soc_update_bits(codec, WCD9335_CLOCK_TEST_CTL,
+					    0x80, 0x80);
+			snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_GATE,
+					    0x04, 0x00);
+			snd_soc_update_bits(codec,
+					WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x02, 0x02);
+		}
+	} else {
+		if (tasha->native_clk_users &&
+		    (--tasha->native_clk_users == 0)) {
+			snd_soc_update_bits(codec,
+					WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x02, 0x00);
+			snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_GATE,
+					    0x04, 0x04);
+			snd_soc_update_bits(codec, WCD9335_CLOCK_TEST_CTL,
+					    0x80, 0x00);
+			snd_soc_update_bits(codec, WCD9335_CLOCK_TEST_CTL,
+					    0x10, 0x00);
+		}
+		clk_disable_unprepare(tasha->wcd_native_clk);
+	}
+
+	dev_dbg(codec->dev, "%s: native_clk_users: %d\n", __func__,
+		tasha->native_clk_users);
+err:
+	return ret;
+}
+
+static int tasha_codec_get_native_fifo_sync_mask(struct snd_soc_codec *codec,
+						 int interp_n)
+{
+	int mask = 0;
+	u16 reg;
+	u8 val1, val2, inp0 = 0;
+	u8 inp1 = 0, inp2 = 0;
+
+	reg = WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 + (2 * interp_n) - 2;
+
+	val1 = snd_soc_read(codec, reg);
+	val2 = snd_soc_read(codec, reg + 1);
+
+	inp0 = val1 & 0x0F;
+	inp1 = (val1 >> 4) & 0x0F;
+	inp2 = (val2 >> 4) & 0x0F;
+
+	if (IS_VALID_NATIVE_FIFO_PORT(inp0))
+		mask |= (1 << (inp0 - 5));
+	if (IS_VALID_NATIVE_FIFO_PORT(inp1))
+		mask |= (1 << (inp1 - 5));
+	if (IS_VALID_NATIVE_FIFO_PORT(inp2))
+		mask |= (1 << (inp2 - 5));
+
+	dev_dbg(codec->dev, "%s: native fifo mask: 0x%x\n", __func__, mask);
+	if (!mask)
+		dev_err(codec->dev, "native fifo err,int:%d,inp0:%d,inp1:%d,inp2:%d\n",
+			interp_n, inp0, inp1, inp2);
+	return mask;
+}
+
+static int tasha_enable_native_supply(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol, int event)
+{
+	int mask;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u16 interp_reg;
+
+	dev_dbg(codec->dev, "%s: event: %d, shift:%d\n", __func__, event,
+		w->shift);
+
+	if (w->shift < INTERP_HPHL || w->shift > INTERP_LO2)
+		return -EINVAL;
+
+	interp_reg = WCD9335_CDC_RX1_RX_PATH_CTL + 20 * (w->shift - 1);
+
+	mask = tasha_codec_get_native_fifo_sync_mask(codec, w->shift);
+	if (!mask)
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Adjust interpolator rate to 44P1_NATIVE */
+		snd_soc_update_bits(codec, interp_reg, 0x0F, 0x09);
+		__tasha_cdc_native_clk_enable(tasha, true);
+		snd_soc_update_bits(codec, WCD9335_DATA_HUB_NATIVE_FIFO_SYNC,
+				    mask, mask);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, WCD9335_DATA_HUB_NATIVE_FIFO_SYNC,
+				    mask, 0x0);
+		__tasha_cdc_native_clk_enable(tasha, false);
+		/* Adjust interpolator rate to default */
+		snd_soc_update_bits(codec, interp_reg, 0x0F, 0x04);
+		break;
+	}
+
+	return 0;
+}
+
+static int tasha_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u16 gain_reg;
+	u16 reg;
+	int val;
+	int offset_val = 0;
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+	if (!(strcmp(w->name, "RX INT0 INTERP"))) {
+		reg = WCD9335_CDC_RX0_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT1 INTERP"))) {
+		reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT2 INTERP"))) {
+		reg = WCD9335_CDC_RX2_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT3 INTERP"))) {
+		reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT4 INTERP"))) {
+		reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT5 INTERP"))) {
+		reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT6 INTERP"))) {
+		reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT7 INTERP"))) {
+		reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT8 INTERP"))) {
+		reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL;
+	} else {
+		dev_err(codec->dev, "%s: Interpolator reg not found\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tasha_codec_vote_max_bw(codec, true);
+		/* Reset if needed */
+		tasha_codec_enable_prim_interpolator(codec, reg, event);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		tasha_config_compander(codec, w->shift, event);
+		/* apply gain after int clk is enabled */
+		if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tasha->comp_enabled[COMPANDER_7] ||
+		     tasha->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD9335_CDC_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			offset_val = -2;
+		}
+		val = snd_soc_read(codec, gain_reg);
+		val += offset_val;
+		snd_soc_write(codec, gain_reg, val);
+		tasha_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tasha_config_compander(codec, w->shift, event);
+		tasha_codec_enable_prim_interpolator(codec, reg, event);
+		if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tasha->comp_enabled[COMPANDER_7] ||
+		     tasha->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD9335_CDC_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD9335_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			offset_val = 2;
+			val = snd_soc_read(codec, gain_reg);
+			val += offset_val;
+			snd_soc_write(codec, gain_reg, val);
+		}
+		tasha_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	};
+
+	return 0;
+}
+
+static int tasha_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
+				    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU: /* fall through */
+	case SND_SOC_DAPM_PRE_PMD:
+		if (strnstr(w->name, "IIR0", sizeof("IIR0"))) {
+			snd_soc_write(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL,
+				snd_soc_read(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL));
+			snd_soc_write(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL,
+				snd_soc_read(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL));
+			snd_soc_write(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL,
+				snd_soc_read(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL));
+			snd_soc_write(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL,
+				snd_soc_read(codec,
+				WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL));
+		} else {
+			snd_soc_write(codec,
+				WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL,
+				snd_soc_read(codec,
+				WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL));
+			snd_soc_write(codec,
+				WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL,
+				snd_soc_read(codec,
+				WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL));
+			snd_soc_write(codec,
+				WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL,
+				snd_soc_read(codec,
+				WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL));
+		}
+		break;
+	}
+	return 0;
+}
+
+static int tasha_codec_enable_on_demand_supply(
+	struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct on_demand_supply *supply;
+
+	if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
+		dev_err(codec->dev, "%s: error index > MAX Demand supplies",
+			__func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(codec->dev, "%s: supply: %s event: %d\n",
+		__func__, on_demand_supply_name[w->shift], event);
+
+	supply = &tasha->on_demand_list[w->shift];
+	WARN_ONCE(!supply->supply, "%s isn't defined\n",
+		on_demand_supply_name[w->shift]);
+	if (!supply->supply) {
+		dev_err(codec->dev, "%s: err supply not present ond for %d",
+			__func__, w->shift);
+		goto out;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = regulator_enable(supply->supply);
+		if (ret)
+			dev_err(codec->dev, "%s: Failed to enable %s\n",
+				__func__,
+				on_demand_supply_name[w->shift]);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = regulator_disable(supply->supply);
+		if (ret)
+			dev_err(codec->dev, "%s: Failed to disable %s\n",
+				__func__,
+				on_demand_supply_name[w->shift]);
+		break;
+	default:
+		break;
+	};
+
+out:
+	return ret;
+}
+
+static int tasha_codec_find_amic_input(struct snd_soc_codec *codec,
+				       int adc_mux_n)
+{
+	u16 mask, shift, adc_mux_in_reg;
+	u16 amic_mux_sel_reg;
+	bool is_amic;
+
+	if (adc_mux_n < 0 || adc_mux_n > WCD9335_MAX_VALID_ADC_MUX ||
+	    adc_mux_n == WCD9335_INVALID_ADC_MUX)
+		return 0;
+
+	/* Check whether adc mux input is AMIC or DMIC */
+	if (adc_mux_n < 4) {
+		adc_mux_in_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+				 2 * adc_mux_n;
+		amic_mux_sel_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+				   2 * adc_mux_n;
+		mask = 0x03;
+		shift = 0;
+	} else {
+		adc_mux_in_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+				 adc_mux_n - 4;
+		amic_mux_sel_reg = adc_mux_in_reg;
+		mask = 0xC0;
+		shift = 6;
+	}
+	is_amic = (((snd_soc_read(codec, adc_mux_in_reg) & mask) >> shift)
+		    == 1);
+	if (!is_amic)
+		return 0;
+
+	return snd_soc_read(codec, amic_mux_sel_reg) & 0x07;
+}
+
+static void tasha_codec_set_tx_hold(struct snd_soc_codec *codec,
+				    u16 amic_reg, bool set)
+{
+	u8 mask = 0x20;
+	u8 val;
+
+	if (amic_reg == WCD9335_ANA_AMIC1 ||
+	    amic_reg == WCD9335_ANA_AMIC3 ||
+	    amic_reg == WCD9335_ANA_AMIC5)
+		mask = 0x40;
+
+	val = set ? mask : 0x00;
+
+	switch (amic_reg) {
+	case WCD9335_ANA_AMIC1:
+	case WCD9335_ANA_AMIC2:
+		snd_soc_update_bits(codec, WCD9335_ANA_AMIC2, mask, val);
+		break;
+	case WCD9335_ANA_AMIC3:
+	case WCD9335_ANA_AMIC4:
+		snd_soc_update_bits(codec, WCD9335_ANA_AMIC4, mask, val);
+		break;
+	case WCD9335_ANA_AMIC5:
+	case WCD9335_ANA_AMIC6:
+		snd_soc_update_bits(codec, WCD9335_ANA_AMIC6, mask, val);
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: invalid amic: %d\n",
+			__func__, amic_reg);
+		break;
+	}
+}
+
+static int tasha_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	int adc_mux_n = w->shift;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int amic_n;
+
+	dev_dbg(codec->dev, "%s: event: %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		amic_n = tasha_codec_find_amic_input(codec, adc_mux_n);
+		if (amic_n) {
+			/*
+			 * Prevent ANC Rx pop by leaving Tx FE in HOLD
+			 * state until PA is up. Track AMIC being used
+			 * so we can release the HOLD later.
+			 */
+			set_bit(ANC_MIC_AMIC1 + amic_n - 1,
+				&tasha->status_mask);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static u16 tasha_codec_get_amic_pwlvl_reg(struct snd_soc_codec *codec, int amic)
+{
+	u16 pwr_level_reg = 0;
+
+	switch (amic) {
+	case 1:
+	case 2:
+		pwr_level_reg = WCD9335_ANA_AMIC1;
+		break;
+
+	case 3:
+	case 4:
+		pwr_level_reg = WCD9335_ANA_AMIC3;
+		break;
+
+	case 5:
+	case 6:
+		pwr_level_reg = WCD9335_ANA_AMIC5;
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: invalid amic: %d\n",
+			__func__, amic);
+		break;
+	}
+
+	return pwr_level_reg;
+}
+
+#define  TX_HPF_CUT_OFF_FREQ_MASK	0x60
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
+
+static void tasha_tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct tasha_priv *tasha;
+	struct snd_soc_codec *codec;
+	u16 dec_cfg_reg, amic_reg;
+	u8 hpf_cut_off_freq;
+	int amic_n;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	tasha = hpf_work->tasha;
+	codec = tasha->codec;
+	hpf_cut_off_freq = hpf_work->hpf_cut_off_freq;
+
+	dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * hpf_work->decimator;
+
+	dev_dbg(codec->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n",
+		__func__, hpf_work->decimator, hpf_cut_off_freq);
+
+	amic_n = tasha_codec_find_amic_input(codec, hpf_work->decimator);
+	if (amic_n) {
+		amic_reg = WCD9335_ANA_AMIC1 + amic_n - 1;
+		tasha_codec_set_tx_hold(codec, amic_reg, false);
+	}
+	tasha_codec_vote_max_bw(codec, true);
+	snd_soc_update_bits(codec, dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
+			    hpf_cut_off_freq << 5);
+	tasha_codec_vote_max_bw(codec, false);
+}
+
+static void tasha_tx_mute_update_callback(struct work_struct *work)
+{
+	struct tx_mute_work *tx_mute_dwork;
+	struct tasha_priv *tasha;
+	struct delayed_work *delayed_work;
+	struct snd_soc_codec *codec;
+	u16 tx_vol_ctl_reg, hpf_gate_reg;
+
+	delayed_work = to_delayed_work(work);
+	tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork);
+	tasha = tx_mute_dwork->tasha;
+	codec = tasha->codec;
+
+	tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL +
+					16 * tx_mute_dwork->decimator;
+	hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 +
+					16 * tx_mute_dwork->decimator;
+	snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x01);
+	snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00);
+}
+
+static int tasha_codec_enable_dec(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	unsigned int decimator;
+	char *dec_adc_mux_name = NULL;
+	char *widget_name = NULL;
+	char *wname;
+	int ret = 0, amic_n;
+	u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
+	u16 tx_gain_ctl_reg;
+	char *dec;
+	u8 hpf_cut_off_freq;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+
+	wname = widget_name;
+	dec_adc_mux_name = strsep(&widget_name, " ");
+	if (!dec_adc_mux_name) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, w->name);
+		ret =  -EINVAL;
+		goto out;
+	}
+	dec_adc_mux_name = widget_name;
+
+	dec = strpbrk(dec_adc_mux_name, "012345678");
+	if (!dec) {
+		dev_err(codec->dev, "%s: decimator index not found\n",
+			__func__);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(dec, 10, &decimator);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, wname);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(codec->dev, "%s(): widget = %s decimator = %u\n", __func__,
+			w->name, decimator);
+
+	tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator;
+	hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 + 16 * decimator;
+	dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * decimator;
+	tx_gain_ctl_reg = WCD9335_CDC_TX0_TX_VOL_CTL + 16 * decimator;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		amic_n = tasha_codec_find_amic_input(codec, decimator);
+		if (amic_n)
+			pwr_level_reg = tasha_codec_get_amic_pwlvl_reg(codec,
+								       amic_n);
+
+		if (pwr_level_reg) {
+			switch ((snd_soc_read(codec, pwr_level_reg) &
+					      WCD9335_AMIC_PWR_LVL_MASK) >>
+					      WCD9335_AMIC_PWR_LVL_SHIFT) {
+			case WCD9335_AMIC_PWR_LEVEL_LP:
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    WCD9335_DEC_PWR_LVL_MASK,
+						    WCD9335_DEC_PWR_LVL_LP);
+				break;
+
+			case WCD9335_AMIC_PWR_LEVEL_HP:
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    WCD9335_DEC_PWR_LVL_MASK,
+						    WCD9335_DEC_PWR_LVL_HP);
+				break;
+			case WCD9335_AMIC_PWR_LEVEL_DEFAULT:
+			default:
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    WCD9335_DEC_PWR_LVL_MASK,
+						    WCD9335_DEC_PWR_LVL_DF);
+				break;
+			}
+		}
+		hpf_cut_off_freq = (snd_soc_read(codec, dec_cfg_reg) &
+				   TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+		tasha->tx_hpf_work[decimator].hpf_cut_off_freq =
+							hpf_cut_off_freq;
+
+		if (hpf_cut_off_freq != CF_MIN_3DB_150HZ)
+			snd_soc_update_bits(codec, dec_cfg_reg,
+					    TX_HPF_CUT_OFF_FREQ_MASK,
+					    CF_MIN_3DB_150HZ << 5);
+		/* Enable TX PGA Mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x00);
+
+		if (decimator == 0) {
+			snd_soc_write(codec, WCD9335_MBHC_ZDET_RAMP_CTL, 0x83);
+			snd_soc_write(codec, WCD9335_MBHC_ZDET_RAMP_CTL, 0xA3);
+			snd_soc_write(codec, WCD9335_MBHC_ZDET_RAMP_CTL, 0x83);
+			snd_soc_write(codec, WCD9335_MBHC_ZDET_RAMP_CTL, 0x03);
+		}
+		/* schedule work queue to Remove Mute */
+		schedule_delayed_work(&tasha->tx_mute_dwork[decimator].dwork,
+				      msecs_to_jiffies(tx_unmute_delay));
+		if (tasha->tx_hpf_work[decimator].hpf_cut_off_freq !=
+							CF_MIN_3DB_150HZ)
+			schedule_delayed_work(
+					&tasha->tx_hpf_work[decimator].dwork,
+					msecs_to_jiffies(300));
+		/* apply gain after decimator is enabled */
+		snd_soc_write(codec, tx_gain_ctl_reg,
+			      snd_soc_read(codec, tx_gain_ctl_reg));
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		hpf_cut_off_freq =
+			tasha->tx_hpf_work[decimator].hpf_cut_off_freq;
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
+		if (cancel_delayed_work_sync(
+		    &tasha->tx_hpf_work[decimator].dwork)) {
+			if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+				tasha_codec_vote_max_bw(codec, true);
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    TX_HPF_CUT_OFF_FREQ_MASK,
+						    hpf_cut_off_freq << 5);
+				tasha_codec_vote_max_bw(codec, false);
+			}
+		}
+		cancel_delayed_work_sync(
+				&tasha->tx_mute_dwork[decimator].dwork);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00);
+		break;
+	};
+out:
+	kfree(wname);
+	return ret;
+}
+
+static u32 tasha_get_dmic_sample_rate(struct snd_soc_codec *codec,
+				unsigned int dmic, struct wcd9xxx_pdata *pdata)
+{
+	u8 tx_stream_fs;
+	u8 adc_mux_index = 0, adc_mux_sel = 0;
+	bool dec_found = false;
+	u16 adc_mux_ctl_reg, tx_fs_reg;
+	u32 dmic_fs;
+
+	while (dec_found == 0 && adc_mux_index < WCD9335_MAX_VALID_ADC_MUX) {
+		if (adc_mux_index < 4) {
+			adc_mux_ctl_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+						(adc_mux_index * 2);
+			adc_mux_sel = ((snd_soc_read(codec, adc_mux_ctl_reg) &
+						0x78) >> 3) - 1;
+		} else if (adc_mux_index < 9) {
+			adc_mux_ctl_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+						((adc_mux_index - 4) * 1);
+			adc_mux_sel = ((snd_soc_read(codec, adc_mux_ctl_reg) &
+						0x38) >> 3) - 1;
+		} else if (adc_mux_index == 9) {
+			++adc_mux_index;
+			continue;
+		}
+		if (adc_mux_sel == dmic)
+			dec_found = true;
+		else
+			++adc_mux_index;
+	}
+
+	if (dec_found == true && adc_mux_index <= 8) {
+		tx_fs_reg = WCD9335_CDC_TX0_TX_PATH_CTL + (16 * adc_mux_index);
+		tx_stream_fs = snd_soc_read(codec, tx_fs_reg) & 0x0F;
+		dmic_fs = tx_stream_fs <= 4 ? WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ :
+					WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
+
+		/*
+		 * Check for ECPP path selection and DEC1 not connected to
+		 * any other audio path to apply ECPP DMIC sample rate
+		 */
+		if ((adc_mux_index == 1) &&
+		    ((snd_soc_read(codec, WCD9335_CPE_SS_US_EC_MUX_CFG)
+				   & 0x0F) == 0x0A) &&
+		    ((snd_soc_read(codec, WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0)
+				   & 0x0C) == 0x00)) {
+			dmic_fs = pdata->ecpp_dmic_sample_rate;
+		}
+	} else {
+		dmic_fs = pdata->dmic_sample_rate;
+	}
+
+	return dmic_fs;
+}
+
+static u8 tasha_get_dmic_clk_val(struct snd_soc_codec *codec,
+				 u32 mclk_rate, u32 dmic_clk_rate)
+{
+	u32 div_factor;
+	u8 dmic_ctl_val;
+
+	dev_dbg(codec->dev,
+		"%s: mclk_rate = %d, dmic_sample_rate = %d\n",
+		__func__, mclk_rate, dmic_clk_rate);
+
+	/* Default value to return in case of error */
+	if (mclk_rate == TASHA_MCLK_CLK_9P6MHZ)
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
+	else
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
+
+	if (dmic_clk_rate == 0) {
+		dev_err(codec->dev,
+			"%s: dmic_sample_rate cannot be 0\n",
+			__func__);
+		goto done;
+	}
+
+	div_factor = mclk_rate / dmic_clk_rate;
+	switch (div_factor) {
+	case 2:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
+		break;
+	case 3:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
+		break;
+	case 4:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4;
+		break;
+	case 6:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6;
+		break;
+	case 8:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8;
+		break;
+	case 16:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16;
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
+			__func__, div_factor, mclk_rate, dmic_clk_rate);
+		break;
+	}
+
+done:
+	return dmic_ctl_val;
+}
+
+static int tasha_codec_enable_adc(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s: event:%d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tasha_codec_set_tx_hold(codec, w->reg, true);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int tasha_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent);
+	u8  dmic_clk_en = 0x01;
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	u8 dmic_rate_val, dmic_rate_shift = 1;
+	unsigned int dmic;
+	u32 dmic_sample_rate;
+	int ret;
+	char *wname;
+
+	wname = strpbrk(w->name, "012345");
+	if (!wname) {
+		dev_err(codec->dev, "%s: widget not found\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(wname, 10, &dmic);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: Invalid DMIC line on the codec\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 0:
+	case 1:
+		dmic_clk_cnt = &(tasha->dmic_0_1_clk_cnt);
+		dmic_clk_reg = WCD9335_CPE_SS_DMIC0_CTL;
+		break;
+	case 2:
+	case 3:
+		dmic_clk_cnt = &(tasha->dmic_2_3_clk_cnt);
+		dmic_clk_reg = WCD9335_CPE_SS_DMIC1_CTL;
+		break;
+	case 4:
+	case 5:
+		dmic_clk_cnt = &(tasha->dmic_4_5_clk_cnt);
+		dmic_clk_reg = WCD9335_CPE_SS_DMIC2_CTL;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid DMIC Selection\n",
+			__func__);
+		return -EINVAL;
+	};
+	dev_dbg(codec->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		dmic_sample_rate = tasha_get_dmic_sample_rate(codec, dmic,
+						pdata);
+		dmic_rate_val =
+			tasha_get_dmic_clk_val(codec,
+					pdata->mclk_rate,
+					dmic_sample_rate);
+
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1) {
+			snd_soc_update_bits(codec, dmic_clk_reg,
+				0x07 << dmic_rate_shift,
+				dmic_rate_val << dmic_rate_shift);
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, dmic_clk_en);
+		}
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		dmic_rate_val =
+			tasha_get_dmic_clk_val(codec,
+					pdata->mclk_rate,
+					pdata->mad_dmic_sample_rate);
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0) {
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					dmic_clk_en, 0);
+			snd_soc_update_bits(codec, dmic_clk_reg,
+				0x07 << dmic_rate_shift,
+				dmic_rate_val << dmic_rate_shift);
+		}
+		break;
+	};
+
+	return 0;
+}
+
+static int __tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int micb_num;
+
+	dev_dbg(codec->dev, "%s: wname: %s, event: %d\n",
+		__func__, w->name, event);
+
+	if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1")))
+		micb_num = MIC_BIAS_1;
+	else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2")))
+		micb_num = MIC_BIAS_2;
+	else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3")))
+		micb_num = MIC_BIAS_3;
+	else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4")))
+		micb_num = MIC_BIAS_4;
+	else
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/*
+		 * MIC BIAS can also be requested by MBHC,
+		 * so use ref count to handle micbias pullup
+		 * and enable requests
+		 */
+		tasha_micbias_control(codec, micb_num, MICB_ENABLE, true);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* wait for cnp time */
+		usleep_range(1000, 1100);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tasha_micbias_control(codec, micb_num, MICB_DISABLE, true);
+		break;
+	};
+
+	return 0;
+}
+
+static int tasha_codec_ldo_h_control(struct snd_soc_dapm_widget *w,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		tasha->ldo_h_users++;
+
+		if (tasha->ldo_h_users == 1)
+			snd_soc_update_bits(codec, WCD9335_LDOH_MODE,
+					    0x80, 0x80);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		tasha->ldo_h_users--;
+
+		if (tasha->ldo_h_users < 0)
+			tasha->ldo_h_users = 0;
+
+		if (tasha->ldo_h_users == 0)
+			snd_soc_update_bits(codec, WCD9335_LDOH_MODE,
+					    0x80, 0x00);
+	}
+
+	return 0;
+}
+
+static int tasha_codec_force_enable_ldo_h(struct snd_soc_dapm_widget *w,
+					  struct snd_kcontrol *kcontrol,
+					  int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_resmgr_enable_master_bias(tasha->resmgr);
+		tasha_codec_ldo_h_control(w, event);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tasha_codec_ldo_h_control(w, event);
+		wcd_resmgr_disable_master_bias(tasha->resmgr);
+		break;
+	}
+
+	return 0;
+}
+
+static int tasha_codec_force_enable_micbias(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_resmgr_enable_master_bias(tasha->resmgr);
+		tasha_cdc_mclk_enable(codec, true, true);
+		ret = __tasha_codec_enable_micbias(w, SND_SOC_DAPM_PRE_PMU);
+		/* Wait for 1ms for better cnp */
+		usleep_range(1000, 1100);
+		tasha_cdc_mclk_enable(codec, false, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = __tasha_codec_enable_micbias(w, SND_SOC_DAPM_POST_PMD);
+		wcd_resmgr_disable_master_bias(tasha->resmgr);
+		break;
+	}
+
+	return ret;
+}
+
+static int tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	return __tasha_codec_enable_micbias(w, event);
+}
+
+static int tasha_codec_enable_standalone_ldo_h(struct snd_soc_codec *codec,
+					       bool enable)
+{
+	int rc;
+
+	if (enable)
+		rc = snd_soc_dapm_force_enable_pin(
+					snd_soc_codec_get_dapm(codec),
+					DAPM_LDO_H_STANDALONE);
+	else
+		rc = snd_soc_dapm_disable_pin(
+					snd_soc_codec_get_dapm(codec),
+					DAPM_LDO_H_STANDALONE);
+
+	if (!rc)
+		snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+	else
+		dev_err(codec->dev, "%s: ldo_h force %s pin failed\n",
+			__func__, (enable ? "enable" : "disable"));
+
+	return rc;
+}
+
+/*
+ * tasha_codec_enable_standalone_micbias - enable micbias standalone
+ * @codec: pointer to codec instance
+ * @micb_num: number of micbias to be enabled
+ * @enable: true to enable micbias or false to disable
+ *
+ * This function is used to enable micbias (1, 2, 3 or 4) during
+ * standalone independent of whether TX use-case is running or not
+ *
+ * Return: error code in case of failure or 0 for success
+ */
+int tasha_codec_enable_standalone_micbias(struct snd_soc_codec *codec,
+					  int micb_num,
+					  bool enable)
+{
+	const char * const micb_names[] = {
+		DAPM_MICBIAS1_STANDALONE, DAPM_MICBIAS2_STANDALONE,
+		DAPM_MICBIAS3_STANDALONE, DAPM_MICBIAS4_STANDALONE
+	};
+	int micb_index = micb_num - 1;
+	int rc;
+
+	if (!codec) {
+		pr_err("%s: Codec memory is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((micb_index < 0) || (micb_index > TASHA_MAX_MICBIAS - 1)) {
+		dev_err(codec->dev, "%s: Invalid micbias index, micb_ind:%d\n",
+			__func__, micb_index);
+		return -EINVAL;
+	}
+
+	if (enable)
+		rc = snd_soc_dapm_force_enable_pin(
+						 snd_soc_codec_get_dapm(codec),
+						   micb_names[micb_index]);
+	else
+		rc = snd_soc_dapm_disable_pin(snd_soc_codec_get_dapm(codec),
+					      micb_names[micb_index]);
+
+	if (!rc)
+		snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+	else
+		dev_err(codec->dev, "%s: micbias%d force %s pin failed\n",
+			__func__, micb_num, (enable ? "enable" : "disable"));
+
+	return rc;
+}
+EXPORT_SYMBOL(tasha_codec_enable_standalone_micbias);
+
+static const char *const tasha_anc_func_text[] = {"OFF", "ON"};
+static const struct soc_enum tasha_anc_func_enum =
+		SOC_ENUM_SINGLE_EXT(2, tasha_anc_func_text);
+
+static const char *const tasha_clkmode_text[] = {"EXTERNAL", "INTERNAL"};
+static SOC_ENUM_SINGLE_EXT_DECL(tasha_clkmode_enum, tasha_clkmode_text);
+
+/* Cutoff frequency for high pass filter */
+static const char * const cf_text[] = {
+	"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ"
+};
+
+static const char * const rx_cf_text[] = {
+	"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ",
+	"CF_NEG_3DB_0P48HZ"
+};
+
+static const struct soc_enum cf_dec0_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX0_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX1_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX2_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec3_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX3_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec4_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX4_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec5_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX5_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec6_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX6_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec7_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX7_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec8_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX8_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_int0_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int1_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int2_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int3_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int4_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int5_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int5_2_enum, WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int6_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int6_2_enum, WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int7_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int8_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+	{"SLIM RX0 MUX", NULL, "RX_I2S_CTL"},
+	{"SLIM RX1 MUX", NULL, "RX_I2S_CTL"},
+	{"SLIM RX2 MUX", NULL, "RX_I2S_CTL"},
+	{"SLIM RX3 MUX", NULL, "RX_I2S_CTL"},
+
+	{"SLIM TX6 MUX", NULL, "TX_I2S_CTL"},
+	{"SLIM TX7 MUX", NULL, "TX_I2S_CTL"},
+	{"SLIM TX8 MUX", NULL, "TX_I2S_CTL"},
+	{"SLIM TX11 MUX", NULL, "TX_I2S_CTL"},
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	/* MAD */
+	{"MAD_SEL MUX", "SPE", "MAD_CPE_INPUT"},
+	{"MAD_SEL MUX", "MSM", "MADINPUT"},
+	{"MADONOFF", "Switch", "MAD_SEL MUX"},
+	{"MAD_BROADCAST", "Switch", "MAD_SEL MUX"},
+	{"TX13 INP MUX", "CPE_TX_PP", "MADONOFF"},
+
+	/* CPE HW MAD bypass */
+	{"CPE IN Mixer", "MAD_BYPASS", "SLIM TX1 MUX"},
+
+	{"AIF4_MAD Mixer", "SLIM TX1", "CPE IN Mixer"},
+	{"AIF4_MAD Mixer", "SLIM TX12", "MADONOFF"},
+	{"AIF4_MAD Mixer", "SLIM TX13", "TX13 INP MUX"},
+	{"AIF4 MAD", NULL, "AIF4_MAD Mixer"},
+	{"AIF4 MAD", NULL, "AIF4"},
+
+	{"EC BUF MUX INP", "DEC1", "ADC MUX1"},
+	{"AIF5 CPE", NULL, "EC BUF MUX INP"},
+
+	/* SLIMBUS Connections */
+	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+
+	/* VI Feedback */
+	{"AIF4_VI Mixer", "SPKR_VI_1", "VIINPUT"},
+	{"AIF4_VI Mixer", "SPKR_VI_2", "VIINPUT"},
+	{"AIF4 VI", NULL, "AIF4_VI Mixer"},
+
+	/* SLIM_MIXER("AIF1_CAP Mixer"),*/
+	{"AIF1_CAP Mixer", "SLIM TX0", "SLIM TX0 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX11", "SLIM TX11 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX13", "TX13 INP MUX"},
+	/* SLIM_MIXER("AIF2_CAP Mixer"),*/
+	{"AIF2_CAP Mixer", "SLIM TX0", "SLIM TX0 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX11", "SLIM TX11 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX13", "TX13 INP MUX"},
+	/* SLIM_MIXER("AIF3_CAP Mixer"),*/
+	{"AIF3_CAP Mixer", "SLIM TX0", "SLIM TX0 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX11", "SLIM TX11 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX13", "TX13 INP MUX"},
+
+	{"SLIM TX0 MUX", "DEC0", "ADC MUX0"},
+	{"SLIM TX0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"},
+	{"SLIM TX0 MUX", "DEC0_192", "ADC US MUX0"},
+
+	{"SLIM TX1 MUX", "DEC1", "ADC MUX1"},
+	{"SLIM TX1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"},
+	{"SLIM TX1 MUX", "DEC1_192", "ADC US MUX1"},
+
+	{"SLIM TX2 MUX", "DEC2", "ADC MUX2"},
+	{"SLIM TX2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"},
+	{"SLIM TX2 MUX", "DEC2_192", "ADC US MUX2"},
+
+	{"SLIM TX3 MUX", "DEC3", "ADC MUX3"},
+	{"SLIM TX3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"},
+	{"SLIM TX3 MUX", "DEC3_192", "ADC US MUX3"},
+
+	{"SLIM TX4 MUX", "DEC4", "ADC MUX4"},
+	{"SLIM TX4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"},
+	{"SLIM TX4 MUX", "DEC4_192", "ADC US MUX4"},
+
+	{"SLIM TX5 MUX", "DEC5", "ADC MUX5"},
+	{"SLIM TX5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"},
+	{"SLIM TX5 MUX", "DEC5_192", "ADC US MUX5"},
+
+	{"SLIM TX6 MUX", "DEC6", "ADC MUX6"},
+	{"SLIM TX6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"},
+	{"SLIM TX6 MUX", "DEC6_192", "ADC US MUX6"},
+
+	{"SLIM TX7 MUX", "DEC7", "ADC MUX7"},
+	{"SLIM TX7 MUX", "RX_MIX_TX7", "RX MIX TX7 MUX"},
+	{"SLIM TX7 MUX", "DEC7_192", "ADC US MUX7"},
+
+	{"SLIM TX8 MUX", "DEC8", "ADC MUX8"},
+	{"SLIM TX8 MUX", "RX_MIX_TX8", "RX MIX TX8 MUX"},
+	{"SLIM TX8 MUX", "DEC8_192", "ADC US MUX8"},
+
+	{"SLIM TX9 MUX", "DEC7", "ADC MUX7"},
+	{"SLIM TX9 MUX", "DEC7_192", "ADC US MUX7"},
+	{"SLIM TX10 MUX", "DEC6", "ADC MUX6"},
+	{"SLIM TX10 MUX", "DEC6_192", "ADC US MUX6"},
+
+	{"SLIM TX11 MUX", "DEC_0_5", "SLIM TX11 INP1 MUX"},
+	{"SLIM TX11 MUX", "DEC_9_12", "SLIM TX11 INP1 MUX"},
+	{"SLIM TX11 INP1 MUX", "DEC0", "ADC MUX0"},
+	{"SLIM TX11 INP1 MUX", "DEC1", "ADC MUX1"},
+	{"SLIM TX11 INP1 MUX", "DEC2", "ADC MUX2"},
+	{"SLIM TX11 INP1 MUX", "DEC3", "ADC MUX3"},
+	{"SLIM TX11 INP1 MUX", "DEC4", "ADC MUX4"},
+	{"SLIM TX11 INP1 MUX", "DEC5", "ADC MUX5"},
+	{"SLIM TX11 INP1 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"},
+
+	{"TX13 INP MUX", "MAD_BRDCST", "MAD_BROADCAST"},
+	{"TX13 INP MUX", "CDC_DEC_5", "SLIM TX13 MUX"},
+	{"SLIM TX13 MUX", "DEC5", "ADC MUX5"},
+
+	{"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX0 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX0 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX0 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX1 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX1 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX1 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX2 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX2 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX2 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX3 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX3 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX3 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX3 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX4 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX4 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX4 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX4 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX5 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX5 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX5 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX5 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX6 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX6 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX6 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX6 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX7 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX7 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX7 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX7 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"RX MIX TX8 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX5", "RX INT5 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX6", "RX INT6 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"},
+	{"RX MIX TX8 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"},
+	{"RX MIX TX8 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"},
+	{"RX MIX TX8 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"},
+
+	{"ADC US MUX0", "US_Switch", "ADC MUX0"},
+	{"ADC US MUX1", "US_Switch", "ADC MUX1"},
+	{"ADC US MUX2", "US_Switch", "ADC MUX2"},
+	{"ADC US MUX3", "US_Switch", "ADC MUX3"},
+	{"ADC US MUX4", "US_Switch", "ADC MUX4"},
+	{"ADC US MUX5", "US_Switch", "ADC MUX5"},
+	{"ADC US MUX6", "US_Switch", "ADC MUX6"},
+	{"ADC US MUX7", "US_Switch", "ADC MUX7"},
+	{"ADC US MUX8", "US_Switch", "ADC MUX8"},
+	{"ADC MUX0", "DMIC", "DMIC MUX0"},
+	{"ADC MUX0", "AMIC", "AMIC MUX0"},
+	{"ADC MUX1", "DMIC", "DMIC MUX1"},
+	{"ADC MUX1", "AMIC", "AMIC MUX1"},
+	{"ADC MUX2", "DMIC", "DMIC MUX2"},
+	{"ADC MUX2", "AMIC", "AMIC MUX2"},
+	{"ADC MUX3", "DMIC", "DMIC MUX3"},
+	{"ADC MUX3", "AMIC", "AMIC MUX3"},
+	{"ADC MUX4", "DMIC", "DMIC MUX4"},
+	{"ADC MUX4", "AMIC", "AMIC MUX4"},
+	{"ADC MUX5", "DMIC", "DMIC MUX5"},
+	{"ADC MUX5", "AMIC", "AMIC MUX5"},
+	{"ADC MUX6", "DMIC", "DMIC MUX6"},
+	{"ADC MUX6", "AMIC", "AMIC MUX6"},
+	{"ADC MUX7", "DMIC", "DMIC MUX7"},
+	{"ADC MUX7", "AMIC", "AMIC MUX7"},
+	{"ADC MUX8", "DMIC", "DMIC MUX8"},
+	{"ADC MUX8", "AMIC", "AMIC MUX8"},
+	{"ADC MUX10", "DMIC", "DMIC MUX10"},
+	{"ADC MUX10", "AMIC", "AMIC MUX10"},
+	{"ADC MUX11", "DMIC", "DMIC MUX11"},
+	{"ADC MUX11", "AMIC", "AMIC MUX11"},
+	{"ADC MUX12", "DMIC", "DMIC MUX12"},
+	{"ADC MUX12", "AMIC", "AMIC MUX12"},
+	{"ADC MUX13", "DMIC", "DMIC MUX13"},
+	{"ADC MUX13", "AMIC", "AMIC MUX13"},
+
+	{"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX13"},
+
+	{"DMIC MUX0", "DMIC0", "DMIC0"},
+	{"DMIC MUX0", "DMIC1", "DMIC1"},
+	{"DMIC MUX0", "DMIC2", "DMIC2"},
+	{"DMIC MUX0", "DMIC3", "DMIC3"},
+	{"DMIC MUX0", "DMIC4", "DMIC4"},
+	{"DMIC MUX0", "DMIC5", "DMIC5"},
+	{"AMIC MUX0", "ADC1", "ADC1"},
+	{"AMIC MUX0", "ADC2", "ADC2"},
+	{"AMIC MUX0", "ADC3", "ADC3"},
+	{"AMIC MUX0", "ADC4", "ADC4"},
+	{"AMIC MUX0", "ADC5", "ADC5"},
+	{"AMIC MUX0", "ADC6", "ADC6"},
+
+	{"DMIC MUX1", "DMIC0", "DMIC0"},
+	{"DMIC MUX1", "DMIC1", "DMIC1"},
+	{"DMIC MUX1", "DMIC2", "DMIC2"},
+	{"DMIC MUX1", "DMIC3", "DMIC3"},
+	{"DMIC MUX1", "DMIC4", "DMIC4"},
+	{"DMIC MUX1", "DMIC5", "DMIC5"},
+	{"AMIC MUX1", "ADC1", "ADC1"},
+	{"AMIC MUX1", "ADC2", "ADC2"},
+	{"AMIC MUX1", "ADC3", "ADC3"},
+	{"AMIC MUX1", "ADC4", "ADC4"},
+	{"AMIC MUX1", "ADC5", "ADC5"},
+	{"AMIC MUX1", "ADC6", "ADC6"},
+
+	{"DMIC MUX2", "DMIC0", "DMIC0"},
+	{"DMIC MUX2", "DMIC1", "DMIC1"},
+	{"DMIC MUX2", "DMIC2", "DMIC2"},
+	{"DMIC MUX2", "DMIC3", "DMIC3"},
+	{"DMIC MUX2", "DMIC4", "DMIC4"},
+	{"DMIC MUX2", "DMIC5", "DMIC5"},
+	{"AMIC MUX2", "ADC1", "ADC1"},
+	{"AMIC MUX2", "ADC2", "ADC2"},
+	{"AMIC MUX2", "ADC3", "ADC3"},
+	{"AMIC MUX2", "ADC4", "ADC4"},
+	{"AMIC MUX2", "ADC5", "ADC5"},
+	{"AMIC MUX2", "ADC6", "ADC6"},
+
+	{"DMIC MUX3", "DMIC0", "DMIC0"},
+	{"DMIC MUX3", "DMIC1", "DMIC1"},
+	{"DMIC MUX3", "DMIC2", "DMIC2"},
+	{"DMIC MUX3", "DMIC3", "DMIC3"},
+	{"DMIC MUX3", "DMIC4", "DMIC4"},
+	{"DMIC MUX3", "DMIC5", "DMIC5"},
+	{"AMIC MUX3", "ADC1", "ADC1"},
+	{"AMIC MUX3", "ADC2", "ADC2"},
+	{"AMIC MUX3", "ADC3", "ADC3"},
+	{"AMIC MUX3", "ADC4", "ADC4"},
+	{"AMIC MUX3", "ADC5", "ADC5"},
+	{"AMIC MUX3", "ADC6", "ADC6"},
+
+	{"DMIC MUX4", "DMIC0", "DMIC0"},
+	{"DMIC MUX4", "DMIC1", "DMIC1"},
+	{"DMIC MUX4", "DMIC2", "DMIC2"},
+	{"DMIC MUX4", "DMIC3", "DMIC3"},
+	{"DMIC MUX4", "DMIC4", "DMIC4"},
+	{"DMIC MUX4", "DMIC5", "DMIC5"},
+	{"AMIC MUX4", "ADC1", "ADC1"},
+	{"AMIC MUX4", "ADC2", "ADC2"},
+	{"AMIC MUX4", "ADC3", "ADC3"},
+	{"AMIC MUX4", "ADC4", "ADC4"},
+	{"AMIC MUX4", "ADC5", "ADC5"},
+	{"AMIC MUX4", "ADC6", "ADC6"},
+
+	{"DMIC MUX5", "DMIC0", "DMIC0"},
+	{"DMIC MUX5", "DMIC1", "DMIC1"},
+	{"DMIC MUX5", "DMIC2", "DMIC2"},
+	{"DMIC MUX5", "DMIC3", "DMIC3"},
+	{"DMIC MUX5", "DMIC4", "DMIC4"},
+	{"DMIC MUX5", "DMIC5", "DMIC5"},
+	{"AMIC MUX5", "ADC1", "ADC1"},
+	{"AMIC MUX5", "ADC2", "ADC2"},
+	{"AMIC MUX5", "ADC3", "ADC3"},
+	{"AMIC MUX5", "ADC4", "ADC4"},
+	{"AMIC MUX5", "ADC5", "ADC5"},
+	{"AMIC MUX5", "ADC6", "ADC6"},
+
+	{"DMIC MUX6", "DMIC0", "DMIC0"},
+	{"DMIC MUX6", "DMIC1", "DMIC1"},
+	{"DMIC MUX6", "DMIC2", "DMIC2"},
+	{"DMIC MUX6", "DMIC3", "DMIC3"},
+	{"DMIC MUX6", "DMIC4", "DMIC4"},
+	{"DMIC MUX6", "DMIC5", "DMIC5"},
+	{"AMIC MUX6", "ADC1", "ADC1"},
+	{"AMIC MUX6", "ADC2", "ADC2"},
+	{"AMIC MUX6", "ADC3", "ADC3"},
+	{"AMIC MUX6", "ADC4", "ADC4"},
+	{"AMIC MUX6", "ADC5", "ADC5"},
+	{"AMIC MUX6", "ADC6", "ADC6"},
+
+	{"DMIC MUX7", "DMIC0", "DMIC0"},
+	{"DMIC MUX7", "DMIC1", "DMIC1"},
+	{"DMIC MUX7", "DMIC2", "DMIC2"},
+	{"DMIC MUX7", "DMIC3", "DMIC3"},
+	{"DMIC MUX7", "DMIC4", "DMIC4"},
+	{"DMIC MUX7", "DMIC5", "DMIC5"},
+	{"AMIC MUX7", "ADC1", "ADC1"},
+	{"AMIC MUX7", "ADC2", "ADC2"},
+	{"AMIC MUX7", "ADC3", "ADC3"},
+	{"AMIC MUX7", "ADC4", "ADC4"},
+	{"AMIC MUX7", "ADC5", "ADC5"},
+	{"AMIC MUX7", "ADC6", "ADC6"},
+
+	{"DMIC MUX8", "DMIC0", "DMIC0"},
+	{"DMIC MUX8", "DMIC1", "DMIC1"},
+	{"DMIC MUX8", "DMIC2", "DMIC2"},
+	{"DMIC MUX8", "DMIC3", "DMIC3"},
+	{"DMIC MUX8", "DMIC4", "DMIC4"},
+	{"DMIC MUX8", "DMIC5", "DMIC5"},
+	{"AMIC MUX8", "ADC1", "ADC1"},
+	{"AMIC MUX8", "ADC2", "ADC2"},
+	{"AMIC MUX8", "ADC3", "ADC3"},
+	{"AMIC MUX8", "ADC4", "ADC4"},
+	{"AMIC MUX8", "ADC5", "ADC5"},
+	{"AMIC MUX8", "ADC6", "ADC6"},
+
+	{"DMIC MUX10", "DMIC0", "DMIC0"},
+	{"DMIC MUX10", "DMIC1", "DMIC1"},
+	{"DMIC MUX10", "DMIC2", "DMIC2"},
+	{"DMIC MUX10", "DMIC3", "DMIC3"},
+	{"DMIC MUX10", "DMIC4", "DMIC4"},
+	{"DMIC MUX10", "DMIC5", "DMIC5"},
+	{"AMIC MUX10", "ADC1", "ADC1"},
+	{"AMIC MUX10", "ADC2", "ADC2"},
+	{"AMIC MUX10", "ADC3", "ADC3"},
+	{"AMIC MUX10", "ADC4", "ADC4"},
+	{"AMIC MUX10", "ADC5", "ADC5"},
+	{"AMIC MUX10", "ADC6", "ADC6"},
+
+	{"DMIC MUX11", "DMIC0", "DMIC0"},
+	{"DMIC MUX11", "DMIC1", "DMIC1"},
+	{"DMIC MUX11", "DMIC2", "DMIC2"},
+	{"DMIC MUX11", "DMIC3", "DMIC3"},
+	{"DMIC MUX11", "DMIC4", "DMIC4"},
+	{"DMIC MUX11", "DMIC5", "DMIC5"},
+	{"AMIC MUX11", "ADC1", "ADC1"},
+	{"AMIC MUX11", "ADC2", "ADC2"},
+	{"AMIC MUX11", "ADC3", "ADC3"},
+	{"AMIC MUX11", "ADC4", "ADC4"},
+	{"AMIC MUX11", "ADC5", "ADC5"},
+	{"AMIC MUX11", "ADC6", "ADC6"},
+
+	{"DMIC MUX12", "DMIC0", "DMIC0"},
+	{"DMIC MUX12", "DMIC1", "DMIC1"},
+	{"DMIC MUX12", "DMIC2", "DMIC2"},
+	{"DMIC MUX12", "DMIC3", "DMIC3"},
+	{"DMIC MUX12", "DMIC4", "DMIC4"},
+	{"DMIC MUX12", "DMIC5", "DMIC5"},
+	{"AMIC MUX12", "ADC1", "ADC1"},
+	{"AMIC MUX12", "ADC2", "ADC2"},
+	{"AMIC MUX12", "ADC3", "ADC3"},
+	{"AMIC MUX12", "ADC4", "ADC4"},
+	{"AMIC MUX12", "ADC5", "ADC5"},
+	{"AMIC MUX12", "ADC6", "ADC6"},
+
+	{"DMIC MUX13", "DMIC0", "DMIC0"},
+	{"DMIC MUX13", "DMIC1", "DMIC1"},
+	{"DMIC MUX13", "DMIC2", "DMIC2"},
+	{"DMIC MUX13", "DMIC3", "DMIC3"},
+	{"DMIC MUX13", "DMIC4", "DMIC4"},
+	{"DMIC MUX13", "DMIC5", "DMIC5"},
+	{"AMIC MUX13", "ADC1", "ADC1"},
+	{"AMIC MUX13", "ADC2", "ADC2"},
+	{"AMIC MUX13", "ADC3", "ADC3"},
+	{"AMIC MUX13", "ADC4", "ADC4"},
+	{"AMIC MUX13", "ADC5", "ADC5"},
+	{"AMIC MUX13", "ADC6", "ADC6"},
+	/* ADC Connections */
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2", NULL, "AMIC2"},
+	{"ADC3", NULL, "AMIC3"},
+	{"ADC4", NULL, "AMIC4"},
+	{"ADC5", NULL, "AMIC5"},
+	{"ADC6", NULL, "AMIC6"},
+
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"},
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"},
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"},
+	{"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP0"},
+	{"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP1"},
+	{"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP2"},
+	{"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP0"},
+	{"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP1"},
+	{"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP2"},
+	{"RX INT5_1 MIX1", NULL, "RX INT5_1 MIX1 INP0"},
+	{"RX INT5_1 MIX1", NULL, "RX INT5_1 MIX1 INP1"},
+	{"RX INT5_1 MIX1", NULL, "RX INT5_1 MIX1 INP2"},
+	{"RX INT6_1 MIX1", NULL, "RX INT6_1 MIX1 INP0"},
+	{"RX INT6_1 MIX1", NULL, "RX INT6_1 MIX1 INP1"},
+	{"RX INT6_1 MIX1", NULL, "RX INT6_1 MIX1 INP2"},
+	{"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP0"},
+	{"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP1"},
+	{"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP2"},
+	{"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP0"},
+	{"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP1"},
+	{"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP2"},
+
+	{"RX INT0 SEC MIX", NULL, "RX INT0_1 MIX1"},
+	{"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"},
+	{"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"},
+	{"RX INT0 INTERP", NULL, "RX INT0 MIX2"},
+	{"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 INTERP"},
+	{"RX INT0 DAC", NULL, "RX INT0 DEM MUX"},
+	{"RX INT0 DAC", NULL, "RX_BIAS"},
+	{"EAR PA", NULL, "RX INT0 DAC"},
+	{"EAR", NULL, "EAR PA"},
+
+	{"SPL SRC0 MUX", "SRC_IN_HPHL", "RX INT1_1 MIX1"},
+	{"RX INT1 SPLINE MIX", NULL, "RX INT1_1 MIX1"},
+	{"RX INT1 SPLINE MIX", "HPHL Switch", "SPL SRC0 MUX"},
+	{"RX INT1_1 NATIVE MUX", "ON", "RX INT1_1 MIX1"},
+	{"RX INT1 SPLINE MIX", NULL, "RX INT1_1 NATIVE MUX"},
+	{"RX INT1_1 NATIVE MUX", NULL, "RX INT1 NATIVE SUPPLY"},
+	{"RX INT1 SEC MIX", NULL, "RX INT1 SPLINE MIX"},
+	{"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"},
+	{"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"},
+	{"RX INT1 INTERP", NULL, "RX INT1 MIX2"},
+	{"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"},
+	{"RX INT1 DAC", NULL, "RX INT1 DEM MUX"},
+	{"RX INT1 DAC", NULL, "RX_BIAS"},
+	{"HPHL PA", NULL, "RX INT1 DAC"},
+	{"HPHL", NULL, "HPHL PA"},
+
+	{"SPL SRC1 MUX", "SRC_IN_HPHR", "RX INT2_1 MIX1"},
+	{"RX INT2 SPLINE MIX", NULL, "RX INT2_1 MIX1"},
+	{"RX INT2 SPLINE MIX", "HPHR Switch", "SPL SRC1 MUX"},
+	{"RX INT2_1 NATIVE MUX", "ON", "RX INT2_1 MIX1"},
+	{"RX INT2 SPLINE MIX", NULL, "RX INT2_1 NATIVE MUX"},
+	{"RX INT2_1 NATIVE MUX", NULL, "RX INT2 NATIVE SUPPLY"},
+	{"RX INT2 SEC MIX", NULL, "RX INT2 SPLINE MIX"},
+	{"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"},
+	{"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"},
+	{"RX INT2 INTERP", NULL, "RX INT2 MIX2"},
+	{"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"},
+	{"RX INT2 DAC", NULL, "RX INT2 DEM MUX"},
+	{"RX INT2 DAC", NULL, "RX_BIAS"},
+	{"HPHR PA", NULL, "RX INT2 DAC"},
+	{"HPHR", NULL, "HPHR PA"},
+
+	{"SPL SRC0 MUX", "SRC_IN_LO1", "RX INT3_1 MIX1"},
+	{"RX INT3 SPLINE MIX", NULL, "RX INT3_1 MIX1"},
+	{"RX INT3 SPLINE MIX", "LO1 Switch", "SPL SRC0 MUX"},
+	{"RX INT3_1 NATIVE MUX", "ON", "RX INT3_1 MIX1"},
+	{"RX INT3 SPLINE MIX", NULL, "RX INT3_1 NATIVE MUX"},
+	{"RX INT3_1 NATIVE MUX", NULL, "RX INT3 NATIVE SUPPLY"},
+	{"RX INT3 SEC MIX", NULL, "RX INT3 SPLINE MIX"},
+	{"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"},
+	{"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"},
+	{"RX INT3 INTERP", NULL, "RX INT3 MIX2"},
+	{"RX INT3 DAC", NULL, "RX INT3 INTERP"},
+	{"RX INT3 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT1 PA", NULL, "RX INT3 DAC"},
+	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+
+	{"SPL SRC1 MUX", "SRC_IN_LO2", "RX INT4_1 MIX1"},
+	{"RX INT4 SPLINE MIX", NULL, "RX INT4_1 MIX1"},
+	{"RX INT4 SPLINE MIX", "LO2 Switch", "SPL SRC1 MUX"},
+	{"RX INT4_1 NATIVE MUX", "ON", "RX INT4_1 MIX1"},
+	{"RX INT4 SPLINE MIX", NULL, "RX INT4_1 NATIVE MUX"},
+	{"RX INT4_1 NATIVE MUX", NULL, "RX INT4 NATIVE SUPPLY"},
+	{"RX INT4 SEC MIX", NULL, "RX INT4 SPLINE MIX"},
+	{"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"},
+	{"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"},
+	{"RX INT4 INTERP", NULL, "RX INT4 MIX2"},
+	{"RX INT4 DAC", NULL, "RX INT4 INTERP"},
+	{"RX INT4 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT2 PA", NULL, "RX INT4 DAC"},
+	{"LINEOUT2", NULL, "LINEOUT2 PA"},
+
+	{"SPL SRC2 MUX", "SRC_IN_LO3", "RX INT5_1 MIX1"},
+	{"RX INT5 SPLINE MIX", NULL, "RX INT5_1 MIX1"},
+	{"RX INT5 SPLINE MIX", "LO3 Switch", "SPL SRC2 MUX"},
+	{"RX INT5 SEC MIX", NULL, "RX INT5 SPLINE MIX"},
+	{"RX INT5 MIX2", NULL, "RX INT5 SEC MIX"},
+	{"RX INT5 INTERP", NULL, "RX INT5 MIX2"},
+
+	{"RX INT5 VBAT", "LO3 VBAT Enable", "RX INT5 INTERP"},
+	{"RX INT5 DAC", NULL, "RX INT5 VBAT"},
+
+	{"RX INT5 DAC", NULL, "RX INT5 INTERP"},
+	{"RX INT5 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT3 PA", NULL, "RX INT5 DAC"},
+	{"LINEOUT3", NULL, "LINEOUT3 PA"},
+
+	{"SPL SRC3 MUX", "SRC_IN_LO4", "RX INT6_1 MIX1"},
+	{"RX INT6 SPLINE MIX", NULL, "RX INT6_1 MIX1"},
+	{"RX INT6 SPLINE MIX", "LO4 Switch", "SPL SRC3 MUX"},
+	{"RX INT6 SEC MIX", NULL, "RX INT6 SPLINE MIX"},
+	{"RX INT6 MIX2", NULL, "RX INT6 SEC MIX"},
+	{"RX INT6 INTERP", NULL, "RX INT6 MIX2"},
+
+	{"RX INT6 VBAT", "LO4 VBAT Enable", "RX INT6 INTERP"},
+	{"RX INT6 DAC", NULL, "RX INT6 VBAT"},
+
+	{"RX INT6 DAC", NULL, "RX INT6 INTERP"},
+	{"RX INT6 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT4 PA", NULL, "RX INT6 DAC"},
+	{"LINEOUT4", NULL, "LINEOUT4 PA"},
+
+	{"SPL SRC2 MUX", "SRC_IN_SPKRL", "RX INT7_1 MIX1"},
+	{"RX INT7 SPLINE MIX", NULL, "RX INT7_1 MIX1"},
+	{"RX INT7 SPLINE MIX", "SPKRL Switch", "SPL SRC2 MUX"},
+	{"RX INT7 SEC MIX", NULL, "RX INT7 SPLINE MIX"},
+	{"RX INT7 MIX2", NULL, "RX INT7 SEC MIX"},
+	{"RX INT7 MIX2", NULL, "RX INT7 MIX2 INP"},
+
+	{"RX INT7 INTERP", NULL, "RX INT7 MIX2"},
+
+	{"RX INT7 VBAT", "SPKRL VBAT Enable", "RX INT7 INTERP"},
+	{"RX INT7 CHAIN", NULL, "RX INT7 VBAT"},
+
+	{"RX INT7 CHAIN", NULL, "RX INT7 INTERP"},
+	{"RX INT7 CHAIN", NULL, "RX_BIAS"},
+	{"SPK1 OUT", NULL, "RX INT7 CHAIN"},
+
+	{"ANC SPKR PA Enable", "Switch", "RX INT7 CHAIN"},
+	{"ANC SPK1 PA", NULL, "ANC SPKR PA Enable"},
+	{"SPK1 OUT", NULL, "ANC SPK1 PA"},
+
+	{"SPL SRC3 MUX", "SRC_IN_SPKRR", "RX INT8_1 MIX1"},
+	{"RX INT8 SPLINE MIX", NULL, "RX INT8_1 MIX1"},
+	{"RX INT8 SPLINE MIX", "SPKRR Switch", "SPL SRC3 MUX"},
+	{"RX INT8 SEC MIX", NULL, "RX INT8 SPLINE MIX"},
+	{"RX INT8 INTERP", NULL, "RX INT8 SEC MIX"},
+
+	{"RX INT8 VBAT", "SPKRR VBAT Enable", "RX INT8 INTERP"},
+	{"RX INT8 CHAIN", NULL, "RX INT8 VBAT"},
+
+	{"RX INT8 CHAIN", NULL, "RX INT8 INTERP"},
+	{"RX INT8 CHAIN", NULL, "RX_BIAS"},
+	{"SPK2 OUT", NULL, "RX INT8 CHAIN"},
+
+	{"ANC0 FB MUX", "ANC_IN_EAR", "RX INT0 MIX2"},
+	{"ANC0 FB MUX", "ANC_IN_HPHL", "RX INT1 MIX2"},
+	{"ANC0 FB MUX", "ANC_IN_LO1", "RX INT3 MIX2"},
+	{"ANC0 FB MUX", "ANC_IN_EAR_SPKR", "RX INT7 MIX2"},
+	{"ANC1 FB MUX", "ANC_IN_HPHR", "RX INT2 MIX2"},
+	{"ANC1 FB MUX", "ANC_IN_LO2", "RX INT4 MIX2"},
+
+	{"ANC HPHL Enable", "Switch", "ADC MUX10"},
+	{"ANC HPHL Enable", "Switch", "ADC MUX11"},
+	{"RX INT1 MIX2", NULL, "ANC HPHL Enable"},
+
+	{"ANC HPHR Enable", "Switch", "ADC MUX12"},
+	{"ANC HPHR Enable", "Switch", "ADC MUX13"},
+	{"RX INT2 MIX2", NULL, "ANC HPHR Enable"},
+
+	{"ANC EAR Enable", "Switch", "ADC MUX10"},
+	{"ANC EAR Enable", "Switch", "ADC MUX11"},
+	{"RX INT0 MIX2", NULL, "ANC EAR Enable"},
+
+	{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX10"},
+	{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX11"},
+	{"RX INT7 MIX2", NULL, "ANC OUT EAR SPKR Enable"},
+
+	{"ANC LINEOUT1 Enable", "Switch", "ADC MUX10"},
+	{"ANC LINEOUT1 Enable", "Switch", "ADC MUX11"},
+	{"RX INT3 MIX2", NULL, "ANC LINEOUT1 Enable"},
+
+	{"ANC LINEOUT2 Enable", "Switch", "ADC MUX12"},
+	{"ANC LINEOUT2 Enable", "Switch", "ADC MUX13"},
+	{"RX INT4 MIX2", NULL, "ANC LINEOUT2 Enable"},
+
+	{"ANC EAR PA", NULL, "RX INT0 DAC"},
+	{"ANC EAR", NULL, "ANC EAR PA"},
+	{"ANC HPHL PA", NULL, "RX INT1 DAC"},
+	{"ANC HPHL", NULL, "ANC HPHL PA"},
+	{"ANC HPHR PA", NULL, "RX INT2 DAC"},
+	{"ANC HPHR", NULL, "ANC HPHR PA"},
+	{"ANC LINEOUT1 PA", NULL, "RX INT3 DAC"},
+	{"ANC LINEOUT1", NULL, "ANC LINEOUT1 PA"},
+	{"ANC LINEOUT2 PA", NULL, "RX INT4 DAC"},
+	{"ANC LINEOUT2", NULL, "ANC LINEOUT2 PA"},
+
+	/* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
+	{"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
+	/* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
+	{"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
+	/* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
+	{"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
+	/* SLIM_MUX("AIF4_PB", "AIF4 PB"),*/
+	{"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"},
+
+	/* SLIM_MUX("AIF_MIX1_PB", "AIF MIX1 PB"),*/
+	{"SLIM RX0 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+	{"SLIM RX1 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+	{"SLIM RX2 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+	{"SLIM RX3 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+	{"SLIM RX4 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+	{"SLIM RX5 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+	{"SLIM RX6 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+	{"SLIM RX7 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+
+	{"SLIM RX0", NULL, "SLIM RX0 MUX"},
+	{"SLIM RX1", NULL, "SLIM RX1 MUX"},
+	{"SLIM RX2", NULL, "SLIM RX2 MUX"},
+	{"SLIM RX3", NULL, "SLIM RX3 MUX"},
+	{"SLIM RX4", NULL, "SLIM RX4 MUX"},
+	{"SLIM RX5", NULL, "SLIM RX5 MUX"},
+	{"SLIM RX6", NULL, "SLIM RX6 MUX"},
+	{"SLIM RX7", NULL, "SLIM RX7 MUX"},
+
+	{"RX INT0_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT0_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT0_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT0_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT0_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT0_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT0_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT0_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT0_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT0_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT0_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT0_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT0_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT0_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT0_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT0_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT0_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT0_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT0_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT0_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT0_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT0_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT0_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT0_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	/* MIXing path INT0 */
+	{"RX INT0_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT0_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT0_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT0_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT0_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT0_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT0_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT0_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT0 SEC MIX", NULL, "RX INT0_2 MUX"},
+
+	/* MIXing path INT1 */
+	{"RX INT1_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT1_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT1_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT1_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT1_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT1_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT1_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT1_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT1 SEC MIX", NULL, "RX INT1_2 MUX"},
+
+	/* MIXing path INT2 */
+	{"RX INT2_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT2_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT2_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT2_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT2_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT2_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT2_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT2_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT2 SEC MIX", NULL, "RX INT2_2 MUX"},
+
+	/* MIXing path INT3 */
+	{"RX INT3_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT3_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT3_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT3_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT3_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT3_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT3_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT3_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT3 SEC MIX", NULL, "RX INT3_2 MUX"},
+
+	/* MIXing path INT4 */
+	{"RX INT4_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT4_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT4_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT4_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT4_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT4_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT4_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT4_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT4 SEC MIX", NULL, "RX INT4_2 MUX"},
+
+	/* MIXing path INT5 */
+	{"RX INT5_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT5_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT5_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT5_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT5_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT5_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT5_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT5_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT5 SEC MIX", NULL, "RX INT5_2 MUX"},
+
+	/* MIXing path INT6 */
+	{"RX INT6_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT6_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT6_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT6_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT6_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT6_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT6_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT6_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT6 SEC MIX", NULL, "RX INT6_2 MUX"},
+
+	/* MIXing path INT7 */
+	{"RX INT7_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT7_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT7_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT7_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT7_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT7_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT7_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT7_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT7 SEC MIX", NULL, "RX INT7_2 MUX"},
+
+	/* MIXing path INT8 */
+	{"RX INT8_2 MUX", "RX0", "SLIM RX0"},
+	{"RX INT8_2 MUX", "RX1", "SLIM RX1"},
+	{"RX INT8_2 MUX", "RX2", "SLIM RX2"},
+	{"RX INT8_2 MUX", "RX3", "SLIM RX3"},
+	{"RX INT8_2 MUX", "RX4", "SLIM RX4"},
+	{"RX INT8_2 MUX", "RX5", "SLIM RX5"},
+	{"RX INT8_2 MUX", "RX6", "SLIM RX6"},
+	{"RX INT8_2 MUX", "RX7", "SLIM RX7"},
+	{"RX INT8 SEC MIX", NULL, "RX INT8_2 MUX"},
+
+	{"RX INT1_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT1_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT1_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT1_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT1_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT1_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT1_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT1_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT1_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT1_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT1_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT1_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT1_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT1_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT1_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT1_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT1_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT1_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT1_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT1_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT1_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT1_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT1_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT1_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT2_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT2_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT2_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT2_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT2_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT2_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT2_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT2_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT2_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT2_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT2_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT2_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT2_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT2_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT2_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT2_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT2_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT2_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT2_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT2_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT2_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT3_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT3_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT3_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT3_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT3_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT3_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT3_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT3_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT3_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT3_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT3_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT3_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT3_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT3_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT3_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT3_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT3_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT3_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT3_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT3_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT3_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT3_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT3_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT3_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT3_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT3_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT3_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT3_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT3_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT3_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT4_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT4_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT4_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT4_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT4_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT4_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT4_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT4_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT4_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT4_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT4_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT4_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT4_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT4_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT4_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT4_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT4_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT4_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT4_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT4_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT4_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT4_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT4_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT4_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT4_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT4_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT4_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT4_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT4_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT4_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT5_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT5_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT5_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT5_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT5_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT5_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT5_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT5_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT5_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT5_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT5_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT5_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT5_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT5_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT5_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT5_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT5_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT5_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT5_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT5_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT5_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT5_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT5_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT5_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT5_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT5_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT5_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT5_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT5_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT5_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT6_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT6_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT6_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT6_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT6_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT6_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT6_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT6_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT6_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT6_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT6_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT6_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT6_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT6_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT6_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT6_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT6_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT6_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT6_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT6_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT6_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT6_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT6_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT6_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT6_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT6_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT6_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT6_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT6_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT6_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT7_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT7_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT7_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT7_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT7_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT7_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT7_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT7_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT7_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT7_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT7_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT7_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT7_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT7_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT7_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT7_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT7_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT7_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT7_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT7_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT7_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT7_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT7_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT7_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT7_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT7_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT7_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT7_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT7_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT7_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT8_1 MIX1 INP0", "RX0", "SLIM RX0"},
+	{"RX INT8_1 MIX1 INP0", "RX1", "SLIM RX1"},
+	{"RX INT8_1 MIX1 INP0", "RX2", "SLIM RX2"},
+	{"RX INT8_1 MIX1 INP0", "RX3", "SLIM RX3"},
+	{"RX INT8_1 MIX1 INP0", "RX4", "SLIM RX4"},
+	{"RX INT8_1 MIX1 INP0", "RX5", "SLIM RX5"},
+	{"RX INT8_1 MIX1 INP0", "RX6", "SLIM RX6"},
+	{"RX INT8_1 MIX1 INP0", "RX7", "SLIM RX7"},
+	{"RX INT8_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT8_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT8_1 MIX1 INP1", "RX0", "SLIM RX0"},
+	{"RX INT8_1 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX INT8_1 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX INT8_1 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX INT8_1 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX INT8_1 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX INT8_1 MIX1 INP1", "RX6", "SLIM RX6"},
+	{"RX INT8_1 MIX1 INP1", "RX7", "SLIM RX7"},
+	{"RX INT8_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT8_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT8_1 MIX1 INP2", "RX0", "SLIM RX0"},
+	{"RX INT8_1 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX INT8_1 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX INT8_1 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX INT8_1 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX INT8_1 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX INT8_1 MIX1 INP2", "RX6", "SLIM RX6"},
+	{"RX INT8_1 MIX1 INP2", "RX7", "SLIM RX7"},
+	{"RX INT8_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT8_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	/* SRC0, SRC1 inputs to Sidetone RX Mixer
+	 * on RX0, RX1, RX2, RX3, RX4 and RX7 chains
+	 */
+	{"IIR0", NULL, "IIR0 INP0 MUX"},
+	{"IIR0 INP0 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP0 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP0 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP0 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP0 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP0 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP0 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP0 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP0 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP0 MUX", "RX0", "SLIM RX0"},
+	{"IIR0 INP0 MUX", "RX1", "SLIM RX1"},
+	{"IIR0 INP0 MUX", "RX2", "SLIM RX2"},
+	{"IIR0 INP0 MUX", "RX3", "SLIM RX3"},
+	{"IIR0 INP0 MUX", "RX4", "SLIM RX4"},
+	{"IIR0 INP0 MUX", "RX5", "SLIM RX5"},
+	{"IIR0 INP0 MUX", "RX6", "SLIM RX6"},
+	{"IIR0 INP0 MUX", "RX7", "SLIM RX7"},
+	{"IIR0", NULL, "IIR0 INP1 MUX"},
+	{"IIR0 INP1 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP1 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP1 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP1 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP1 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP1 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP1 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP1 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP1 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP1 MUX", "RX0", "SLIM RX0"},
+	{"IIR0 INP1 MUX", "RX1", "SLIM RX1"},
+	{"IIR0 INP1 MUX", "RX2", "SLIM RX2"},
+	{"IIR0 INP1 MUX", "RX3", "SLIM RX3"},
+	{"IIR0 INP1 MUX", "RX4", "SLIM RX4"},
+	{"IIR0 INP1 MUX", "RX5", "SLIM RX5"},
+	{"IIR0 INP1 MUX", "RX6", "SLIM RX6"},
+	{"IIR0 INP1 MUX", "RX7", "SLIM RX7"},
+	{"IIR0", NULL, "IIR0 INP2 MUX"},
+	{"IIR0 INP2 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP2 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP2 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP2 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP2 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP2 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP2 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP2 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP2 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP2 MUX", "RX0", "SLIM RX0"},
+	{"IIR0 INP2 MUX", "RX1", "SLIM RX1"},
+	{"IIR0 INP2 MUX", "RX2", "SLIM RX2"},
+	{"IIR0 INP2 MUX", "RX3", "SLIM RX3"},
+	{"IIR0 INP2 MUX", "RX4", "SLIM RX4"},
+	{"IIR0 INP2 MUX", "RX5", "SLIM RX5"},
+	{"IIR0 INP2 MUX", "RX6", "SLIM RX6"},
+	{"IIR0 INP2 MUX", "RX7", "SLIM RX7"},
+	{"IIR0", NULL, "IIR0 INP3 MUX"},
+	{"IIR0 INP3 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP3 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP3 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP3 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP3 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP3 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP3 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP3 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP3 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP3 MUX", "RX0", "SLIM RX0"},
+	{"IIR0 INP3 MUX", "RX1", "SLIM RX1"},
+	{"IIR0 INP3 MUX", "RX2", "SLIM RX2"},
+	{"IIR0 INP3 MUX", "RX3", "SLIM RX3"},
+	{"IIR0 INP3 MUX", "RX4", "SLIM RX4"},
+	{"IIR0 INP3 MUX", "RX5", "SLIM RX5"},
+	{"IIR0 INP3 MUX", "RX6", "SLIM RX6"},
+	{"IIR0 INP3 MUX", "RX7", "SLIM RX7"},
+
+	{"IIR1", NULL, "IIR1 INP0 MUX"},
+	{"IIR1 INP0 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP0 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP0 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP0 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP0 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP0 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP0 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP0 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP0 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP0 MUX", "RX0", "SLIM RX0"},
+	{"IIR1 INP0 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP0 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP0 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP0 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP0 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP0 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP0 MUX", "RX7", "SLIM RX7"},
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP1 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP1 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP1 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP1 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP1 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP1 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP1 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP1 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP1 MUX", "RX0", "SLIM RX0"},
+	{"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP1 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP1 MUX", "RX7", "SLIM RX7"},
+	{"IIR1", NULL, "IIR1 INP2 MUX"},
+	{"IIR1 INP2 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP2 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP2 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP2 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP2 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP2 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP2 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP2 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP2 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP2 MUX", "RX0", "SLIM RX0"},
+	{"IIR1 INP2 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP2 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP2 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP2 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP2 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP2 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP2 MUX", "RX7", "SLIM RX7"},
+	{"IIR1", NULL, "IIR1 INP3 MUX"},
+	{"IIR1 INP3 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP3 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP3 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP3 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP3 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP3 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP3 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP3 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP3 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP3 MUX", "RX0", "SLIM RX0"},
+	{"IIR1 INP3 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP3 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP3 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP3 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP3 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP3 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP3 MUX", "RX7", "SLIM RX7"},
+
+	{"SRC0", NULL, "IIR0"},
+	{"SRC1", NULL, "IIR1"},
+	{"RX INT0 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT0 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT1 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT1 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT2 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT2 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT3 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT3 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT4 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT4 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT7 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT7 MIX2 INP", "SRC1", "SRC1"},
+};
+
+static int tasha_amic_pwr_lvl_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u16 amic_reg;
+
+	if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE"))
+		amic_reg = WCD9335_ANA_AMIC1;
+	if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
+		amic_reg = WCD9335_ANA_AMIC3;
+	if (!strcmp(kcontrol->id.name, "AMIC_5_6 PWR MODE"))
+		amic_reg = WCD9335_ANA_AMIC5;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec, amic_reg) & WCD9335_AMIC_PWR_LVL_MASK) >>
+			     WCD9335_AMIC_PWR_LVL_SHIFT;
+
+	return 0;
+}
+
+static int tasha_amic_pwr_lvl_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u32 mode_val;
+	u16 amic_reg;
+
+	mode_val = ucontrol->value.enumerated.item[0];
+
+	dev_dbg(codec->dev, "%s: mode: %d\n",
+		__func__, mode_val);
+
+	if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE"))
+		amic_reg = WCD9335_ANA_AMIC1;
+	if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
+		amic_reg = WCD9335_ANA_AMIC3;
+	if (!strcmp(kcontrol->id.name, "AMIC_5_6 PWR MODE"))
+		amic_reg = WCD9335_ANA_AMIC5;
+
+	snd_soc_update_bits(codec, amic_reg, WCD9335_AMIC_PWR_LVL_MASK,
+			    mode_val << WCD9335_AMIC_PWR_LVL_SHIFT);
+
+	return 0;
+}
+
+static int tasha_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tasha->hph_mode;
+	return 0;
+}
+
+static int tasha_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u32 mode_val;
+
+	mode_val = ucontrol->value.enumerated.item[0];
+
+	dev_dbg(codec->dev, "%s: mode: %d\n",
+		__func__, mode_val);
+
+	if (mode_val == 0) {
+		dev_warn(codec->dev, "%s:Invalid HPH Mode, default to Cls-H HiFi\n",
+			__func__);
+		mode_val = CLS_H_HIFI;
+	}
+	tasha->hph_mode = mode_val;
+	return 0;
+}
+
+static const char *const tasha_conn_mad_text[] = {
+	"NOTUSED1", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6",
+	"NOTUSED2", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4",
+	"DMIC5", "NOTUSED3", "NOTUSED4"
+};
+
+static const struct soc_enum tasha_conn_mad_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_conn_mad_text),
+			    tasha_conn_mad_text);
+
+static int tasha_enable_ldo_h_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u8 val = 0;
+
+	if (codec)
+		val = snd_soc_read(codec, WCD9335_LDOH_MODE) & 0x80;
+
+	ucontrol->value.integer.value[0] = !!val;
+
+	return 0;
+}
+
+static int tasha_enable_ldo_h_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int value = ucontrol->value.integer.value[0];
+	bool enable;
+
+	enable = !!value;
+	if (codec)
+		tasha_codec_enable_standalone_ldo_h(codec, enable);
+
+	return 0;
+}
+
+static int tasha_mad_input_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	u8 tasha_mad_input;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	tasha_mad_input = snd_soc_read(codec,
+				WCD9335_SOC_MAD_INP_SEL) & 0x0F;
+	ucontrol->value.integer.value[0] = tasha_mad_input;
+
+	dev_dbg(codec->dev,
+		"%s: tasha_mad_input = %s\n", __func__,
+		tasha_conn_mad_text[tasha_mad_input]);
+	return 0;
+}
+
+static int tasha_mad_input_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	u8 tasha_mad_input;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_card *card = codec->component.card;
+	char mad_amic_input_widget[6];
+	const char *mad_input_widget;
+	const char *source_widget = NULL;
+	u32 adc, i, mic_bias_found = 0;
+	int ret = 0;
+	char *mad_input;
+
+	tasha_mad_input = ucontrol->value.integer.value[0];
+
+	if (tasha_mad_input >= ARRAY_SIZE(tasha_conn_mad_text)) {
+		dev_err(codec->dev,
+			"%s: tasha_mad_input = %d out of bounds\n",
+			__func__, tasha_mad_input);
+		return -EINVAL;
+	}
+
+	if (!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED1") ||
+	    !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED2") ||
+	    !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED3") ||
+	    !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED4")) {
+		dev_err(codec->dev,
+			"%s: Unsupported tasha_mad_input = %s\n",
+			__func__, tasha_conn_mad_text[tasha_mad_input]);
+		return -EINVAL;
+	}
+
+	if (strnstr(tasha_conn_mad_text[tasha_mad_input],
+		    "ADC", sizeof("ADC"))) {
+		mad_input = strpbrk(tasha_conn_mad_text[tasha_mad_input],
+				    "123456");
+		if (!mad_input) {
+			dev_err(codec->dev, "%s: Invalid MAD input %s\n",
+				__func__,
+				tasha_conn_mad_text[tasha_mad_input]);
+			return -EINVAL;
+		}
+		ret = kstrtouint(mad_input, 10, &adc);
+		if ((ret < 0) || (adc > 6)) {
+			dev_err(codec->dev,
+				"%s: Invalid ADC = %s\n", __func__,
+				tasha_conn_mad_text[tasha_mad_input]);
+			ret =  -EINVAL;
+		}
+
+		snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
+
+		mad_input_widget = mad_amic_input_widget;
+	} else {
+		/* DMIC type input widget*/
+		mad_input_widget = tasha_conn_mad_text[tasha_mad_input];
+	}
+
+	dev_dbg(codec->dev,
+		"%s: tasha input widget = %s\n", __func__,
+		mad_input_widget);
+
+	for (i = 0; i < card->num_of_dapm_routes; i++) {
+		if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) {
+			source_widget = card->of_dapm_routes[i].source;
+			if (!source_widget) {
+				dev_err(codec->dev,
+					"%s: invalid source widget\n",
+					__func__);
+				return -EINVAL;
+			}
+
+			if (strnstr(source_widget,
+				"MIC BIAS1", sizeof("MIC BIAS1"))) {
+				mic_bias_found = 1;
+				break;
+			} else if (strnstr(source_widget,
+				"MIC BIAS2", sizeof("MIC BIAS2"))) {
+				mic_bias_found = 2;
+				break;
+			} else if (strnstr(source_widget,
+				"MIC BIAS3", sizeof("MIC BIAS3"))) {
+				mic_bias_found = 3;
+				break;
+			} else if (strnstr(source_widget,
+				"MIC BIAS4", sizeof("MIC BIAS4"))) {
+				mic_bias_found = 4;
+				break;
+			}
+		}
+	}
+
+	if (!mic_bias_found) {
+		dev_err(codec->dev,
+			"%s: mic bias source not found for input = %s\n",
+			__func__, mad_input_widget);
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev,
+		"%s: mic_bias found = %d\n", __func__,
+		mic_bias_found);
+
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_INP_SEL,
+			    0x0F, tasha_mad_input);
+	snd_soc_update_bits(codec, WCD9335_ANA_MAD_SETUP,
+			    0x07, mic_bias_found);
+
+	return 0;
+}
+
+static int tasha_pinctl_mode_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u16 ctl_reg;
+	u8 reg_val, pinctl_position;
+
+	pinctl_position = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	switch (pinctl_position >> 3) {
+	case 0:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_0;
+		break;
+	case 1:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_1;
+		break;
+	case 2:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_2;
+		break;
+	case 3:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_3;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid pinctl position = %d\n",
+			__func__, pinctl_position);
+		return -EINVAL;
+	}
+
+	reg_val = snd_soc_read(codec, ctl_reg);
+	reg_val = (reg_val >> (pinctl_position & 0x07)) & 0x1;
+	ucontrol->value.integer.value[0] = reg_val;
+
+	return 0;
+}
+
+static int tasha_pinctl_mode_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u16 ctl_reg, cfg_reg;
+	u8 ctl_val, cfg_val, pinctl_position, pinctl_mode, mask;
+
+	/* 1- high or low; 0- high Z */
+	pinctl_mode = ucontrol->value.integer.value[0];
+	pinctl_position = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	switch (pinctl_position >> 3) {
+	case 0:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_0;
+		break;
+	case 1:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_1;
+		break;
+	case 2:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_2;
+		break;
+	case 3:
+		ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_3;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid pinctl position = %d\n",
+			__func__, pinctl_position);
+		return -EINVAL;
+	}
+
+	ctl_val = pinctl_mode << (pinctl_position & 0x07);
+	mask = 1 << (pinctl_position & 0x07);
+	snd_soc_update_bits(codec, ctl_reg, mask, ctl_val);
+
+	cfg_reg = WCD9335_TLMM_BIST_MODE_PINCFG + pinctl_position;
+	if (!pinctl_mode) {
+		if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+			cfg_val = 0x4;
+		else
+			cfg_val = 0xC;
+	} else {
+		cfg_val = 0;
+	}
+	snd_soc_update_bits(codec, cfg_reg, 0x07, cfg_val);
+
+	dev_dbg(codec->dev, "%s: reg=0x%x mask=0x%x val=%d reg=0x%x val=%d\n",
+			__func__, ctl_reg, mask, ctl_val, cfg_reg, cfg_val);
+
+	return 0;
+}
+
+static void wcd_vbat_adc_out_config_2_0(struct wcd_vbat *vbat,
+					struct snd_soc_codec *codec)
+{
+	u8 val1, val2;
+
+	/*
+	 * Measure dcp1 by using "ALT" branch of band gap
+	 * voltage(Vbg) and use it in FAST mode
+	 */
+	snd_soc_update_bits(codec, WCD9335_BIAS_CTL, 0x82, 0x82);
+	snd_soc_update_bits(codec, WCD9335_CDC_VBAT_VBAT_PATH_CTL, 0x10, 0x10);
+	snd_soc_update_bits(codec, WCD9335_CDC_VBAT_VBAT_DEBUG1, 0x01, 0x01);
+	snd_soc_update_bits(codec, WCD9335_ANA_VBADC, 0x80, 0x80);
+	snd_soc_update_bits(codec, WCD9335_VBADC_SUBBLOCK_EN, 0x20, 0x00);
+
+	snd_soc_update_bits(codec, WCD9335_VBADC_FE_CTRL, 0x20, 0x20);
+	/* Wait 100 usec after calibration select as Vbg */
+	usleep_range(100, 110);
+
+	snd_soc_update_bits(codec, WCD9335_VBADC_ADC_IO, 0x40, 0x40);
+	val1 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTMSB);
+	val2 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTLSB);
+	snd_soc_update_bits(codec, WCD9335_VBADC_ADC_IO, 0x40, 0x00);
+
+	vbat->dcp1 = (((val1 & 0xFF) << 3) | (val2 & 0x07));
+
+	snd_soc_update_bits(codec, WCD9335_BIAS_CTL, 0x40, 0x40);
+	/* Wait 100 usec after selecting Vbg as 1.05V */
+	usleep_range(100, 110);
+
+	snd_soc_update_bits(codec, WCD9335_VBADC_ADC_IO, 0x40, 0x40);
+	val1 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTMSB);
+	val2 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTLSB);
+	snd_soc_update_bits(codec, WCD9335_VBADC_ADC_IO, 0x40, 0x00);
+
+	vbat->dcp2 = (((val1 & 0xFF) << 3) | (val2 & 0x07));
+
+	dev_dbg(codec->dev, "%s: dcp1:0x%x, dcp2:0x%x\n",
+		__func__, vbat->dcp1, vbat->dcp2);
+
+	snd_soc_write(codec, WCD9335_BIAS_CTL, 0x28);
+	/* Wait 100 usec after selecting Vbg as 0.85V */
+	usleep_range(100, 110);
+
+	snd_soc_update_bits(codec, WCD9335_VBADC_FE_CTRL, 0x20, 0x00);
+	snd_soc_update_bits(codec, WCD9335_VBADC_SUBBLOCK_EN, 0x20, 0x20);
+	snd_soc_update_bits(codec, WCD9335_ANA_VBADC, 0x80, 0x00);
+
+	snd_soc_update_bits(codec, WCD9335_CDC_VBAT_VBAT_PATH_CTL, 0x10, 0x00);
+	snd_soc_update_bits(codec, WCD9335_CDC_VBAT_VBAT_DEBUG1, 0x01, 0x00);
+}
+
+static void wcd_vbat_adc_out_config_1_x(struct wcd_vbat *vbat,
+					struct snd_soc_codec *codec)
+{
+	u8 val1, val2;
+
+	/*
+	 * Measure dcp1 by applying band gap voltage(Vbg)
+	 * of 0.85V
+	 */
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0x20);
+	snd_soc_write(codec, WCD9335_BIAS_CTL, 0x28);
+	snd_soc_write(codec, WCD9335_BIAS_VBG_FINE_ADJ, 0x05);
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0xA0);
+	/* Wait 2 sec after enabling band gap bias */
+	usleep_range(2000000, 2000100);
+
+	snd_soc_write(codec, WCD9335_ANA_CLK_TOP, 0x82);
+	snd_soc_write(codec, WCD9335_ANA_CLK_TOP, 0x87);
+	snd_soc_update_bits(codec, WCD9335_CDC_VBAT_VBAT_PATH_CTL, 0x10, 0x10);
+	snd_soc_write(codec, WCD9335_CDC_VBAT_VBAT_CFG, 0x0D);
+	snd_soc_write(codec, WCD9335_CDC_VBAT_VBAT_DEBUG1, 0x01);
+
+	snd_soc_write(codec, WCD9335_ANA_VBADC, 0x80);
+	snd_soc_write(codec, WCD9335_VBADC_SUBBLOCK_EN, 0xDE);
+	snd_soc_write(codec, WCD9335_VBADC_FE_CTRL, 0x3C);
+	/* Wait 1 msec after calibration select as Vbg */
+	usleep_range(1000, 1100);
+
+	snd_soc_write(codec, WCD9335_VBADC_ADC_IO, 0xC0);
+	val1 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTMSB);
+	val2 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTLSB);
+	snd_soc_write(codec, WCD9335_VBADC_ADC_IO, 0x80);
+
+	vbat->dcp1 = (((val1 & 0xFF) << 3) | (val2 & 0x07));
+
+	/*
+	 * Measure dcp2 by applying band gap voltage(Vbg)
+	 * of 1.05V
+	 */
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0x80);
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0xC0);
+	snd_soc_write(codec, WCD9335_BIAS_CTL, 0x68);
+	/* Wait 2 msec after selecting Vbg as 1.05V */
+	usleep_range(2000, 2100);
+
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0x80);
+	/* Wait 1 sec after enabling band gap bias */
+	usleep_range(1000000, 1000100);
+
+	snd_soc_write(codec, WCD9335_VBADC_ADC_IO, 0xC0);
+	val1 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTMSB);
+	val2 = snd_soc_read(codec, WCD9335_VBADC_ADC_DOUTLSB);
+	snd_soc_write(codec, WCD9335_VBADC_ADC_IO, 0x80);
+
+	vbat->dcp2 = (((val1 & 0xFF) << 3) | (val2 & 0x07));
+
+	dev_dbg(codec->dev, "%s: dcp1:0x%x, dcp2:0x%x\n",
+		__func__, vbat->dcp1, vbat->dcp2);
+
+	/* Reset the Vbat ADC configuration */
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0x80);
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0xC0);
+
+	snd_soc_write(codec, WCD9335_BIAS_CTL, 0x28);
+	/* Wait 2 msec after selecting Vbg as 0.85V */
+	usleep_range(2000, 2100);
+
+	snd_soc_write(codec, WCD9335_ANA_BIAS, 0xA0);
+	/* Wait 1 sec after enabling band gap bias */
+	usleep_range(1000000, 1000100);
+
+	snd_soc_write(codec, WCD9335_VBADC_FE_CTRL, 0x1C);
+	snd_soc_write(codec, WCD9335_VBADC_SUBBLOCK_EN, 0xFE);
+	snd_soc_write(codec, WCD9335_VBADC_ADC_IO, 0x80);
+	snd_soc_write(codec, WCD9335_ANA_VBADC, 0x00);
+
+	snd_soc_write(codec, WCD9335_CDC_VBAT_VBAT_DEBUG1, 0x00);
+	snd_soc_write(codec, WCD9335_CDC_VBAT_VBAT_PATH_CTL, 0x00);
+	snd_soc_write(codec, WCD9335_CDC_VBAT_VBAT_CFG, 0x0A);
+}
+
+static void wcd_vbat_adc_out_config(struct wcd_vbat *vbat,
+				struct snd_soc_codec *codec)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!vbat->adc_config) {
+		tasha_cdc_mclk_enable(codec, true, false);
+
+		if (TASHA_IS_2_0(wcd9xxx))
+			wcd_vbat_adc_out_config_2_0(vbat, codec);
+		else
+			wcd_vbat_adc_out_config_1_x(vbat, codec);
+
+		tasha_cdc_mclk_enable(codec, false, false);
+		vbat->adc_config = true;
+	}
+}
+
+static int tasha_update_vbat_reg_config(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct firmware_cal *hwdep_cal = NULL;
+	struct vbat_monitor_reg *vbat_reg_ptr = NULL;
+	const void *data;
+	size_t cal_size, vbat_size_remaining;
+	int ret = 0, i;
+	u32 vbat_writes_size = 0;
+	u16 reg;
+	u8 mask, val, old_val;
+
+	hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, WCD9XXX_VBAT_CAL);
+	if (hwdep_cal) {
+		data = hwdep_cal->data;
+		cal_size = hwdep_cal->size;
+		dev_dbg(codec->dev, "%s: using hwdep calibration\n",
+			__func__);
+	} else {
+		dev_err(codec->dev, "%s: Vbat cal not received\n",
+			__func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (cal_size < sizeof(*vbat_reg_ptr)) {
+		dev_err(codec->dev,
+			"%s: Incorrect size %zd for Vbat Cal, expected %zd\n",
+			__func__, cal_size, sizeof(*vbat_reg_ptr));
+		ret = -EINVAL;
+		goto done;
+	}
+
+	vbat_reg_ptr = (struct vbat_monitor_reg *) (data);
+
+	if (!vbat_reg_ptr) {
+		dev_err(codec->dev,
+			"%s: Invalid calibration data for Vbat\n",
+			__func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	vbat_writes_size = vbat_reg_ptr->size;
+	vbat_size_remaining = cal_size - sizeof(u32);
+	dev_dbg(codec->dev, "%s: vbat_writes_sz: %d, vbat_sz_remaining: %zd\n",
+			__func__, vbat_writes_size, vbat_size_remaining);
+
+	if ((vbat_writes_size * TASHA_PACKED_REG_SIZE)
+					> vbat_size_remaining) {
+		pr_err("%s: Incorrect Vbat calibration data\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	for (i = 0 ; i < vbat_writes_size; i++) {
+		TASHA_CODEC_UNPACK_ENTRY(vbat_reg_ptr->writes[i],
+					reg, mask, val);
+		old_val = snd_soc_read(codec, reg);
+		snd_soc_write(codec, reg, (old_val & ~mask) | (val & mask));
+	}
+
+done:
+	return ret;
+}
+
+static int tasha_vbat_adc_data_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	wcd_vbat_adc_out_config(&tasha->vbat, codec);
+
+	ucontrol->value.integer.value[0] = tasha->vbat.dcp1;
+	ucontrol->value.integer.value[1] = tasha->vbat.dcp2;
+
+	dev_dbg(codec->dev,
+		"%s: Vbat ADC output values, Dcp1 : %lu, Dcp2: %lu\n",
+		__func__, ucontrol->value.integer.value[0],
+		ucontrol->value.integer.value[1]);
+
+	return 0;
+}
+
+static const char * const tasha_vbat_gsm_mode_text[] = {
+	"OFF", "ON"};
+
+static const struct soc_enum tasha_vbat_gsm_mode_enum =
+	SOC_ENUM_SINGLE_EXT(2, tasha_vbat_gsm_mode_text);
+
+static int tasha_vbat_gsm_mode_func_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	ucontrol->value.integer.value[0] =
+		((snd_soc_read(codec, WCD9335_CDC_VBAT_VBAT_CFG) & 0x04) ?
+		  1 : 0);
+
+	dev_dbg(codec->dev, "%s: value: %lu\n", __func__,
+		ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int tasha_vbat_gsm_mode_func_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	dev_dbg(codec->dev, "%s: value: %lu\n", __func__,
+		ucontrol->value.integer.value[0]);
+
+	/* Set Vbat register configuration for GSM mode bit based on value */
+	if (ucontrol->value.integer.value[0])
+		snd_soc_update_bits(codec, WCD9335_CDC_VBAT_VBAT_CFG,
+						0x04, 0x04);
+	else
+		snd_soc_update_bits(codec, WCD9335_CDC_VBAT_VBAT_CFG,
+						0x04, 0x00);
+
+	return 0;
+}
+
+static int tasha_codec_vbat_enable_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u16 vbat_path_ctl, vbat_cfg, vbat_path_cfg;
+
+	vbat_path_ctl = WCD9335_CDC_VBAT_VBAT_PATH_CTL;
+	vbat_cfg = WCD9335_CDC_VBAT_VBAT_CFG;
+	vbat_path_cfg = WCD9335_CDC_RX8_RX_PATH_CFG1;
+
+	if (!strcmp(w->name, "RX INT8 VBAT"))
+		vbat_path_cfg = WCD9335_CDC_RX8_RX_PATH_CFG1;
+	else if (!strcmp(w->name, "RX INT7 VBAT"))
+		vbat_path_cfg = WCD9335_CDC_RX7_RX_PATH_CFG1;
+	else if (!strcmp(w->name, "RX INT6 VBAT"))
+		vbat_path_cfg = WCD9335_CDC_RX6_RX_PATH_CFG1;
+	else if (!strcmp(w->name, "RX INT5 VBAT"))
+		vbat_path_cfg = WCD9335_CDC_RX5_RX_PATH_CFG1;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = tasha_update_vbat_reg_config(codec);
+		if (ret) {
+			dev_dbg(codec->dev,
+				"%s : VBAT isn't calibrated, So not enabling it\n",
+				__func__);
+			return 0;
+		}
+		snd_soc_write(codec, WCD9335_ANA_VBADC, 0x80);
+		snd_soc_update_bits(codec, vbat_path_cfg, 0x02, 0x02);
+		snd_soc_update_bits(codec, vbat_path_ctl, 0x10, 0x10);
+		snd_soc_update_bits(codec, vbat_cfg, 0x01, 0x01);
+		tasha->vbat.is_enabled = true;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (tasha->vbat.is_enabled) {
+			snd_soc_update_bits(codec, vbat_cfg, 0x01, 0x00);
+			snd_soc_update_bits(codec, vbat_path_ctl, 0x10, 0x00);
+			snd_soc_update_bits(codec, vbat_path_cfg, 0x02, 0x00);
+			snd_soc_write(codec, WCD9335_ANA_VBADC, 0x00);
+			tasha->vbat.is_enabled = false;
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static const char * const rx_hph_mode_mux_text[] = {
+	"CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI"
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text),
+			    rx_hph_mode_mux_text);
+
+static const char * const amic_pwr_lvl_text[] = {
+	"LOW_PWR", "DEFAULT", "HIGH_PERF"
+};
+
+static const struct soc_enum amic_pwr_lvl_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amic_pwr_lvl_text),
+			    amic_pwr_lvl_text);
+
+static const struct snd_kcontrol_new tasha_snd_controls[] = {
+	SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
+		0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
+			  WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
+			  WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
+			  WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
+			  WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
+			  WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume",
+			  WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume",
+			  WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
+			  WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
+			  WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+
+	SOC_SINGLE_SX_TLV("DEC0 Volume", WCD9335_CDC_TX0_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC1 Volume", WCD9335_CDC_TX1_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC2 Volume", WCD9335_CDC_TX2_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC3 Volume", WCD9335_CDC_TX3_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC4 Volume", WCD9335_CDC_TX4_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC5 Volume", WCD9335_CDC_TX5_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC6 Volume", WCD9335_CDC_TX6_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC7 Volume", WCD9335_CDC_TX7_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC8 Volume", WCD9335_CDC_TX8_TX_VOL_CTL, 0,
+					  -84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("IIR0 INP0 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84,
+			  40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR0 INP1 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84,
+			  40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR0 INP2 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84,
+			  40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR0 INP3 Volume",
+			  WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84,
+			  40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP0 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84,
+			  40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84,
+			  40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84,
+			  40, digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
+			  WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84,
+			  40, digital_gain),
+
+	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tasha_get_anc_slot,
+		       tasha_put_anc_slot),
+	SOC_ENUM_EXT("ANC Function", tasha_anc_func_enum, tasha_get_anc_func,
+		     tasha_put_anc_func),
+
+	SOC_ENUM_EXT("CLK MODE", tasha_clkmode_enum, tasha_get_clkmode,
+		     tasha_put_clkmode),
+
+	SOC_ENUM("TX0 HPF cut off", cf_dec0_enum),
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+	SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+	SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
+	SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
+	SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
+	SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
+
+	SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum),
+	SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum),
+	SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum),
+	SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum),
+	SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum),
+	SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum),
+	SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum),
+	SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum),
+	SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum),
+	SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum),
+	SOC_ENUM("RX INT5_1 HPF cut off", cf_int5_1_enum),
+	SOC_ENUM("RX INT5_2 HPF cut off", cf_int5_2_enum),
+	SOC_ENUM("RX INT6_1 HPF cut off", cf_int6_1_enum),
+	SOC_ENUM("RX INT6_2 HPF cut off", cf_int6_2_enum),
+	SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum),
+	SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum),
+	SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum),
+	SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum),
+
+	SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR0 Enable Band2", IIR0, BAND2, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR0 Enable Band3", IIR0, BAND3, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR0 Enable Band4", IIR0, BAND4, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR0 Enable Band5", IIR0, BAND5, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+	tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer),
+
+	SOC_SINGLE_MULTI_EXT("IIR0 Band1", IIR0, BAND1, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band2", IIR0, BAND2, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band3", IIR0, BAND3, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band4", IIR0, BAND4, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band5", IIR0, BAND5, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+	tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer),
+
+	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+	SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+	SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+	SOC_SINGLE_EXT("COMP5 Switch", SND_SOC_NOPM, COMPANDER_5, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+	SOC_SINGLE_EXT("COMP6 Switch", SND_SOC_NOPM, COMPANDER_6, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+	SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+	SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0,
+		       tasha_get_compander, tasha_set_compander),
+
+	SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+		       tasha_rx_hph_mode_get, tasha_rx_hph_mode_put),
+
+	SOC_ENUM_EXT("MAD Input", tasha_conn_mad_enum,
+		     tasha_mad_input_get, tasha_mad_input_put),
+	SOC_SINGLE_EXT("LDO_H Enable", SND_SOC_NOPM, 0, 1, 0,
+			tasha_enable_ldo_h_get, tasha_enable_ldo_h_put),
+
+	SOC_SINGLE_EXT("DMIC1_CLK_PIN_MODE", SND_SOC_NOPM, 17, 1, 0,
+		       tasha_pinctl_mode_get, tasha_pinctl_mode_put),
+
+	SOC_SINGLE_EXT("DMIC1_DATA_PIN_MODE", SND_SOC_NOPM, 18, 1, 0,
+		       tasha_pinctl_mode_get, tasha_pinctl_mode_put),
+
+	SOC_SINGLE_EXT("DMIC2_CLK_PIN_MODE", SND_SOC_NOPM, 19, 1, 0,
+		       tasha_pinctl_mode_get, tasha_pinctl_mode_put),
+
+	SOC_SINGLE_EXT("DMIC2_DATA_PIN_MODE", SND_SOC_NOPM, 20, 1, 0,
+		       tasha_pinctl_mode_get, tasha_pinctl_mode_put),
+
+	SOC_SINGLE_EXT("DMIC3_CLK_PIN_MODE", SND_SOC_NOPM, 21, 1, 0,
+		       tasha_pinctl_mode_get, tasha_pinctl_mode_put),
+
+	SOC_SINGLE_EXT("DMIC3_DATA_PIN_MODE", SND_SOC_NOPM, 22, 1, 0,
+		       tasha_pinctl_mode_get, tasha_pinctl_mode_put),
+	SOC_ENUM_EXT("AMIC_1_2 PWR MODE", amic_pwr_lvl_enum,
+		       tasha_amic_pwr_lvl_get, tasha_amic_pwr_lvl_put),
+	SOC_ENUM_EXT("AMIC_3_4 PWR MODE", amic_pwr_lvl_enum,
+		       tasha_amic_pwr_lvl_get, tasha_amic_pwr_lvl_put),
+	SOC_ENUM_EXT("AMIC_5_6 PWR MODE", amic_pwr_lvl_enum,
+		       tasha_amic_pwr_lvl_get, tasha_amic_pwr_lvl_put),
+
+	SOC_SINGLE_MULTI_EXT("Vbat ADC data", SND_SOC_NOPM, 0, 0xFFFF, 0, 2,
+			tasha_vbat_adc_data_get, NULL),
+
+	SOC_ENUM_EXT("GSM mode Enable", tasha_vbat_gsm_mode_enum,
+			tasha_vbat_gsm_mode_func_get,
+			tasha_vbat_gsm_mode_func_put),
+};
+
+static int tasha_put_dec_enum(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+	u16 mic_sel_reg;
+	u8 mic_sel;
+
+	val = ucontrol->value.enumerated.item[0];
+	if (val > e->items - 1)
+		return -EINVAL;
+
+	dev_dbg(codec->dev, "%s: wname: %s, val: 0x%x\n", __func__,
+		widget->name, val);
+
+	switch (e->reg) {
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1:
+		mic_sel_reg = WCD9335_CDC_TX0_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1:
+		mic_sel_reg = WCD9335_CDC_TX1_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1:
+		mic_sel_reg = WCD9335_CDC_TX2_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1:
+		mic_sel_reg = WCD9335_CDC_TX3_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0:
+		mic_sel_reg = WCD9335_CDC_TX4_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0:
+		mic_sel_reg = WCD9335_CDC_TX5_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0:
+		mic_sel_reg = WCD9335_CDC_TX6_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0:
+		mic_sel_reg = WCD9335_CDC_TX7_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0:
+		mic_sel_reg = WCD9335_CDC_TX8_TX_PATH_CFG0;
+		break;
+	default:
+		dev_err(codec->dev, "%s: e->reg: 0x%x not expected\n",
+			__func__, e->reg);
+		return -EINVAL;
+	}
+
+	/* ADC: 0, DMIC: 1 */
+	mic_sel = val ? 0x0 : 0x1;
+	snd_soc_update_bits(codec, mic_sel_reg, 1 << 7, mic_sel << 7);
+
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int tasha_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+	unsigned short look_ahead_dly_reg = WCD9335_CDC_RX0_RX_PATH_CFG0;
+
+	val = ucontrol->value.enumerated.item[0];
+	if (val >= e->items)
+		return -EINVAL;
+
+	dev_dbg(codec->dev, "%s: wname: %s, val: 0x%x\n", __func__,
+		widget->name, val);
+
+	if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0)
+		look_ahead_dly_reg = WCD9335_CDC_RX0_RX_PATH_CFG0;
+	else if (e->reg == WCD9335_CDC_RX1_RX_PATH_SEC0)
+		look_ahead_dly_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+	else if (e->reg == WCD9335_CDC_RX2_RX_PATH_SEC0)
+		look_ahead_dly_reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
+
+	/* Set Look Ahead Delay */
+	snd_soc_update_bits(codec, look_ahead_dly_reg,
+			    0x08, (val ? 0x08 : 0x00));
+	/* Set DEM INP Select */
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int tasha_ear_pa_gain_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	ear_pa_gain = snd_soc_read(codec, WCD9335_ANA_EAR);
+
+	ear_pa_gain = (ear_pa_gain & 0x70) >> 4;
+
+	ucontrol->value.integer.value[0] = ear_pa_gain;
+
+	dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__,
+		ear_pa_gain);
+
+	return 0;
+}
+
+static int tasha_ear_pa_gain_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0]  = %ld\n",
+			__func__, ucontrol->value.integer.value[0]);
+
+	ear_pa_gain =  ucontrol->value.integer.value[0] << 4;
+
+	snd_soc_update_bits(codec, WCD9335_ANA_EAR, 0x70, ear_pa_gain);
+	return 0;
+}
+
+static int tasha_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tasha->ear_spkr_gain;
+
+	dev_dbg(codec->dev, "%s: ear_spkr_gain = %ld\n", __func__,
+		ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int tasha_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0]  = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	tasha->ear_spkr_gain =  ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int tasha_config_compander(struct snd_soc_codec *codec, int interp_n,
+				  int event)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int comp;
+	u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+	/* EAR does not have compander */
+	if (!interp_n)
+		return 0;
+
+	comp = interp_n - 1;
+	dev_dbg(codec->dev, "%s: event %d compander %d, enabled %d\n",
+		__func__, event, comp + 1, tasha->comp_enabled[comp]);
+
+	if (!tasha->comp_enabled[comp])
+		return 0;
+
+	comp_ctl0_reg = WCD9335_CDC_COMPANDER1_CTL0 + (comp * 8);
+	rx_path_cfg0_reg = WCD9335_CDC_RX1_RX_PATH_CFG0 + (comp * 20);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Compander Clock */
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x01);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x02);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04);
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00);
+	}
+
+	return 0;
+}
+
+static int tasha_codec_config_mad(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+	int idx;
+	const struct firmware *fw;
+	struct firmware_cal *hwdep_cal = NULL;
+	struct wcd_mad_audio_cal *mad_cal = NULL;
+	const void *data;
+	const char *filename = TASHA_MAD_AUDIO_FIRMWARE_PATH;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	size_t cal_size;
+
+	hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, WCD9XXX_MAD_CAL);
+	if (hwdep_cal) {
+		data = hwdep_cal->data;
+		cal_size = hwdep_cal->size;
+		dev_dbg(codec->dev, "%s: using hwdep calibration\n",
+			__func__);
+	} else {
+		ret = request_firmware(&fw, filename, codec->dev);
+		if (ret || !fw) {
+			dev_err(codec->dev,
+				"%s: MAD firmware acquire failed, err = %d\n",
+				__func__, ret);
+			return -ENODEV;
+		}
+		data = fw->data;
+		cal_size = fw->size;
+		dev_dbg(codec->dev, "%s: using request_firmware calibration\n",
+			__func__);
+	}
+
+	if (cal_size < sizeof(*mad_cal)) {
+		dev_err(codec->dev,
+			"%s: Incorrect size %zd for MAD Cal, expected %zd\n",
+			__func__, cal_size, sizeof(*mad_cal));
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	mad_cal = (struct wcd_mad_audio_cal *) (data);
+	if (!mad_cal) {
+		dev_err(codec->dev,
+			"%s: Invalid calibration data\n",
+			__func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	snd_soc_write(codec, WCD9335_SOC_MAD_MAIN_CTL_2,
+		      mad_cal->microphone_info.cycle_time);
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_MAIN_CTL_1, 0xFF << 3,
+			    ((uint16_t)mad_cal->microphone_info.settle_time)
+			    << 3);
+
+	/* Audio */
+	snd_soc_write(codec, WCD9335_SOC_MAD_AUDIO_CTL_8,
+		      mad_cal->audio_info.rms_omit_samples);
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_AUDIO_CTL_1,
+			    0x07 << 4, mad_cal->audio_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03 << 2,
+			    mad_cal->audio_info.detection_mechanism << 2);
+	snd_soc_write(codec, WCD9335_SOC_MAD_AUDIO_CTL_7,
+		      mad_cal->audio_info.rms_diff_threshold & 0x3F);
+	snd_soc_write(codec, WCD9335_SOC_MAD_AUDIO_CTL_5,
+		      mad_cal->audio_info.rms_threshold_lsb);
+	snd_soc_write(codec, WCD9335_SOC_MAD_AUDIO_CTL_6,
+		      mad_cal->audio_info.rms_threshold_msb);
+
+	for (idx = 0; idx < ARRAY_SIZE(mad_cal->audio_info.iir_coefficients);
+	     idx++) {
+		snd_soc_update_bits(codec, WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR,
+				    0x3F, idx);
+		snd_soc_write(codec, WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL,
+			      mad_cal->audio_info.iir_coefficients[idx]);
+		dev_dbg(codec->dev, "%s:MAD Audio IIR Coef[%d] = 0X%x",
+			__func__, idx,
+			mad_cal->audio_info.iir_coefficients[idx]);
+	}
+
+	/* Beacon */
+	snd_soc_write(codec, WCD9335_SOC_MAD_BEACON_CTL_8,
+		      mad_cal->beacon_info.rms_omit_samples);
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_BEACON_CTL_1,
+			    0x07 << 4, mad_cal->beacon_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_BEACON_CTL_2, 0x03 << 2,
+			    mad_cal->beacon_info.detection_mechanism << 2);
+	snd_soc_write(codec, WCD9335_SOC_MAD_BEACON_CTL_7,
+		      mad_cal->beacon_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, WCD9335_SOC_MAD_BEACON_CTL_5,
+		      mad_cal->beacon_info.rms_threshold_lsb);
+	snd_soc_write(codec, WCD9335_SOC_MAD_BEACON_CTL_6,
+		      mad_cal->beacon_info.rms_threshold_msb);
+
+	for (idx = 0; idx < ARRAY_SIZE(mad_cal->beacon_info.iir_coefficients);
+	     idx++) {
+		snd_soc_update_bits(codec, WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR,
+				    0x3F, idx);
+		snd_soc_write(codec, WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL,
+			      mad_cal->beacon_info.iir_coefficients[idx]);
+		dev_dbg(codec->dev, "%s:MAD Beacon IIR Coef[%d] = 0X%x",
+			__func__, idx,
+			mad_cal->beacon_info.iir_coefficients[idx]);
+	}
+
+	/* Ultrasound */
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_ULTR_CTL_1,
+			    0x07 << 4,
+			    mad_cal->ultrasound_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, WCD9335_SOC_MAD_ULTR_CTL_2, 0x03 << 2,
+			    mad_cal->ultrasound_info.detection_mechanism << 2);
+	snd_soc_write(codec, WCD9335_SOC_MAD_ULTR_CTL_7,
+		      mad_cal->ultrasound_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, WCD9335_SOC_MAD_ULTR_CTL_5,
+		      mad_cal->ultrasound_info.rms_threshold_lsb);
+	snd_soc_write(codec, WCD9335_SOC_MAD_ULTR_CTL_6,
+		      mad_cal->ultrasound_info.rms_threshold_msb);
+
+done:
+	if (!hwdep_cal)
+		release_firmware(fw);
+
+	return ret;
+}
+
+static int tasha_codec_enable_mad(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int ret = 0;
+
+	dev_dbg(codec->dev,
+		"%s: event = %d\n", __func__, event);
+
+	/* Return if CPE INPUT is DEC1 */
+	if (snd_soc_read(codec, WCD9335_CPE_SS_SVA_CFG) & 0x01)
+		return ret;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		/* Turn on MAD clk */
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_MAD_CTL,
+				    0x01, 0x01);
+
+		/* Undo reset for MAD */
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_MAD_CTL,
+				    0x02, 0x00);
+		ret = tasha_codec_config_mad(codec);
+		if (ret)
+			dev_err(codec->dev,
+				"%s: Failed to config MAD, err = %d\n",
+				__func__, ret);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Reset the MAD block */
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_MAD_CTL,
+				    0x02, 0x02);
+		/* Turn off MAD clk */
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_MAD_CTL,
+				    0x01, 0x00);
+		break;
+	}
+
+	return ret;
+}
+
+static int tasha_codec_configure_cpe_input(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev,
+		"%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Configure CPE input as DEC1 */
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_SVA_CFG,
+				    0x01, 0x01);
+
+		/* Configure DEC1 Tx out with sample rate as 16K */
+		snd_soc_update_bits(codec, WCD9335_CDC_TX1_TX_PATH_CTL,
+				    0x0F, 0x01);
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Reset DEC1 Tx out sample rate */
+		snd_soc_update_bits(codec, WCD9335_CDC_TX1_TX_PATH_CTL,
+				    0x0F, 0x04);
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_SVA_CFG,
+				    0x01, 0x00);
+
+		break;
+	}
+
+	return 0;
+}
+
+
+static int tasha_codec_aif4_mixer_switch_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+			dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+
+	if (test_bit(AIF4_SWITCH_VALUE, &tasha_p->status_mask))
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	dev_dbg(codec->dev, "%s: AIF4 switch value = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int tasha_codec_aif4_mixer_switch_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+			dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_dapm_update *update = NULL;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: AIF4 switch value = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	if (ucontrol->value.integer.value[0]) {
+		snd_soc_dapm_mixer_update_power(widget->dapm,
+						kcontrol, 1, update);
+		set_bit(AIF4_SWITCH_VALUE, &tasha_p->status_mask);
+	} else {
+		snd_soc_dapm_mixer_update_power(widget->dapm,
+						kcontrol, 0, update);
+		clear_bit(AIF4_SWITCH_VALUE, &tasha_p->status_mask);
+	}
+
+	return 1;
+}
+
+static const char * const tasha_ear_pa_gain_text[] = {
+	"G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
+	"G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB"
+};
+
+static const char * const tasha_ear_spkr_pa_gain_text[] = {
+	"G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB", "G_4_DB",
+	"G_5_DB", "G_6_DB"
+};
+
+static const struct soc_enum tasha_ear_pa_gain_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_ear_pa_gain_text),
+			tasha_ear_pa_gain_text);
+
+static const struct soc_enum tasha_ear_spkr_pa_gain_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_ear_spkr_pa_gain_text),
+			    tasha_ear_spkr_pa_gain_text);
+
+static const struct snd_kcontrol_new tasha_analog_gain_controls[] = {
+	SOC_ENUM_EXT("EAR PA Gain", tasha_ear_pa_gain_enum,
+		tasha_ear_pa_gain_get, tasha_ear_pa_gain_put),
+
+	SOC_ENUM_EXT("EAR SPKR PA Gain", tasha_ear_spkr_pa_gain_enum,
+		     tasha_ear_spkr_pa_gain_get, tasha_ear_spkr_pa_gain_put),
+
+	SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1,
+		line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1,
+		line_gain),
+	SOC_SINGLE_TLV("LINEOUT1 Volume", WCD9335_DIFF_LO_LO1_COMPANDER,
+			3, 16, 1, line_gain),
+	SOC_SINGLE_TLV("LINEOUT2 Volume", WCD9335_DIFF_LO_LO2_COMPANDER,
+			3, 16, 1, line_gain),
+	SOC_SINGLE_TLV("LINEOUT3 Volume", WCD9335_SE_LO_LO3_GAIN, 0, 20, 1,
+			line_gain),
+	SOC_SINGLE_TLV("LINEOUT4 Volume", WCD9335_SE_LO_LO4_GAIN, 0, 20, 1,
+			line_gain),
+
+	SOC_SINGLE_TLV("ADC1 Volume", WCD9335_ANA_AMIC1, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", WCD9335_ANA_AMIC2, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", WCD9335_ANA_AMIC3, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC4 Volume", WCD9335_ANA_AMIC4, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC5 Volume", WCD9335_ANA_AMIC5, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC6 Volume", WCD9335_ANA_AMIC6, 0, 20, 0,
+			analog_gain),
+};
+
+static const char * const spl_src0_mux_text[] = {
+	"ZERO", "SRC_IN_HPHL", "SRC_IN_LO1",
+};
+
+static const char * const spl_src1_mux_text[] = {
+	"ZERO", "SRC_IN_HPHR", "SRC_IN_LO2",
+};
+
+static const char * const spl_src2_mux_text[] = {
+	"ZERO", "SRC_IN_LO3", "SRC_IN_SPKRL",
+};
+
+static const char * const spl_src3_mux_text[] = {
+	"ZERO", "SRC_IN_LO4", "SRC_IN_SPKRR",
+};
+
+static const char * const rx_int0_7_mix_mux_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+	"RX6", "RX7", "PROXIMITY"
+};
+
+static const char * const rx_int_mix_mux_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+	"RX6", "RX7"
+};
+
+static const char * const rx_prim_mix_text[] = {
+	"ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2",
+	"RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_sidetone_mix_text[] = {
+	"ZERO", "SRC0", "SRC1", "SRC_SUM"
+};
+
+static const char * const sb_tx0_mux_text[] = {
+	"ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192"
+};
+
+static const char * const sb_tx1_mux_text[] = {
+	"ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192"
+};
+
+static const char * const sb_tx2_mux_text[] = {
+	"ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192"
+};
+
+static const char * const sb_tx3_mux_text[] = {
+	"ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192"
+};
+
+static const char * const sb_tx4_mux_text[] = {
+	"ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192"
+};
+
+static const char * const sb_tx5_mux_text[] = {
+	"ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192"
+};
+
+static const char * const sb_tx6_mux_text[] = {
+	"ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192"
+};
+
+static const char * const sb_tx7_mux_text[] = {
+	"ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192"
+};
+
+static const char * const sb_tx8_mux_text[] = {
+	"ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192"
+};
+
+static const char * const sb_tx9_mux_text[] = {
+	"ZERO", "DEC7", "DEC7_192"
+};
+
+static const char * const sb_tx10_mux_text[] = {
+	"ZERO", "DEC6", "DEC6_192"
+};
+
+static const char * const sb_tx11_mux_text[] = {
+	"DEC_0_5", "DEC_9_12", "MAD_AUDIO", "MAD_BRDCST"
+};
+
+static const char * const sb_tx11_inp1_mux_text[] = {
+	"ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4",
+	"DEC5", "RX_MIX_TX5", "DEC9_10", "DEC11_12"
+};
+
+static const char * const sb_tx13_mux_text[] = {
+	"ZERO", "DEC5", "DEC5_192"
+};
+
+static const char * const tx13_inp_mux_text[] = {
+	"CDC_DEC_5", "MAD_BRDCST", "CPE_TX_PP"
+};
+
+static const char * const iir_inp_mux_text[] = {
+	"ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6",
+	"DEC7", "DEC8",	"RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_int_dem_inp_mux_text[] = {
+	"NORMAL_DSM_OUT", "CLSH_DSM_OUT",
+};
+
+static const char * const rx_int0_interp_mux_text[] = {
+	"ZERO", "RX INT0 MIX2",
+};
+
+static const char * const rx_int1_interp_mux_text[] = {
+	"ZERO", "RX INT1 MIX2",
+};
+
+static const char * const rx_int2_interp_mux_text[] = {
+	"ZERO", "RX INT2 MIX2",
+};
+
+static const char * const rx_int3_interp_mux_text[] = {
+	"ZERO", "RX INT3 MIX2",
+};
+
+static const char * const rx_int4_interp_mux_text[] = {
+	"ZERO", "RX INT4 MIX2",
+};
+
+static const char * const rx_int5_interp_mux_text[] = {
+	"ZERO", "RX INT5 MIX2",
+};
+
+static const char * const rx_int6_interp_mux_text[] = {
+	"ZERO", "RX INT6 MIX2",
+};
+
+static const char * const rx_int7_interp_mux_text[] = {
+	"ZERO", "RX INT7 MIX2",
+};
+
+static const char * const rx_int8_interp_mux_text[] = {
+	"ZERO", "RX INT8 SEC MIX"
+};
+
+static const char * const mad_sel_text[] = {
+	"SPE", "MSM"
+};
+
+static const char * const adc_mux_text[] = {
+	"DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2"
+};
+
+static const char * const dmic_mux_text[] = {
+	"ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5",
+	"SMIC0", "SMIC1", "SMIC2", "SMIC3"
+};
+
+static const char * const dmic_mux_alt_text[] = {
+	"ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5",
+};
+
+static const char * const amic_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6"
+};
+
+static const char * const rx_echo_mux_text[] = {
+	"ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2", "RX_MIX3", "RX_MIX4",
+	"RX_MIX5", "RX_MIX6", "RX_MIX7", "RX_MIX8", "RX_MIX_VBAT5",
+	"RX_MIX_VBAT6",	"RX_MIX_VBAT7", "RX_MIX_VBAT8"
+};
+
+static const char * const anc0_fb_mux_text[] = {
+	"ZERO", "ANC_IN_HPHL", "ANC_IN_EAR", "ANC_IN_EAR_SPKR",
+	"ANC_IN_LO1"
+};
+
+static const char * const anc1_fb_mux_text[] = {
+	"ZERO", "ANC_IN_HPHR", "ANC_IN_LO2"
+};
+
+static const char * const native_mux_text[] = {
+	"OFF", "ON",
+};
+
+static const struct soc_enum spl_src0_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 0, 3,
+			spl_src0_mux_text);
+
+static const struct soc_enum spl_src1_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 2, 3,
+			spl_src1_mux_text);
+
+static const struct soc_enum spl_src2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 4, 3,
+			spl_src2_mux_text);
+
+static const struct soc_enum spl_src3_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 6, 3,
+			spl_src3_mux_text);
+
+static const struct soc_enum rx_int0_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10,
+			rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int1_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int2_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int3_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int4_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int5_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int6_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int7_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10,
+			rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int8_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum int1_1_native_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text),
+			native_mux_text);
+
+static const struct soc_enum int2_1_native_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text),
+			native_mux_text);
+
+static const struct soc_enum int3_1_native_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text),
+			native_mux_text);
+
+static const struct soc_enum int4_1_native_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text),
+			native_mux_text);
+
+static const struct soc_enum rx_int0_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_sidetone_mix_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0, 4,
+			rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int1_sidetone_mix_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, 4,
+			rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int2_sidetone_mix_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, 4,
+			rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int3_sidetone_mix_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6, 4,
+			rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int4_sidetone_mix_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0, 4,
+			rx_sidetone_mix_text);
+
+static const struct soc_enum rx_int7_sidetone_mix_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 2, 4,
+			rx_sidetone_mix_text);
+
+static const struct soc_enum tx_adc_mux0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux3_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux4_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux5_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux6_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux7_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux8_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux10_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux11_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux12_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux13_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_dmic_mux0_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux2_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux3_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux4_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux5_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux6_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux7_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux8_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux10_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux11_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux12_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux13_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_amic_mux0_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux2_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux3_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux4_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux5_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux6_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux7_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux8_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux10_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux11_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux12_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux13_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum sb_tx0_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0, 4,
+			sb_tx0_mux_text);
+
+static const struct soc_enum sb_tx1_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 2, 4,
+			sb_tx1_mux_text);
+
+static const struct soc_enum sb_tx2_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 4, 4,
+			sb_tx2_mux_text);
+
+static const struct soc_enum sb_tx3_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 6, 4,
+			sb_tx3_mux_text);
+
+static const struct soc_enum sb_tx4_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 0, 4,
+			sb_tx4_mux_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 2, 4,
+			sb_tx5_mux_text);
+
+static const struct soc_enum sb_tx6_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 4, 4,
+			sb_tx6_mux_text);
+
+static const struct soc_enum sb_tx7_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 6, 4,
+			sb_tx7_mux_text);
+
+static const struct soc_enum sb_tx8_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 0, 4,
+			sb_tx8_mux_text);
+
+static const struct soc_enum sb_tx9_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 2, 3,
+			sb_tx9_mux_text);
+
+static const struct soc_enum sb_tx10_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 4, 3,
+			sb_tx10_mux_text);
+
+static const struct soc_enum sb_tx11_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG, 0, 4,
+			sb_tx11_mux_text);
+
+static const struct soc_enum sb_tx11_inp1_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3, 0, 10,
+			sb_tx11_inp1_mux_text);
+
+static const struct soc_enum sb_tx13_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3, 4, 3,
+			sb_tx13_mux_text);
+
+static const struct soc_enum tx13_inp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG, 0, 3,
+			tx13_inp_mux_text);
+
+static const struct soc_enum rx_mix_tx0_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0, 0, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx1_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0, 4, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx2_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1, 0, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx3_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1, 4, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx4_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2, 0, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx5_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2, 4, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx6_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3, 0, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx7_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3, 4, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum rx_mix_tx8_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4, 0, 14,
+			rx_echo_mux_text);
+
+static const struct soc_enum iir0_inp0_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum iir0_inp1_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum iir0_inp2_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum iir0_inp3_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp0_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp2_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum iir1_inp3_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0, 18,
+			iir_inp_mux_text);
+
+static const struct soc_enum rx_int0_dem_inp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_SEC0, 0,
+			ARRAY_SIZE(rx_int_dem_inp_mux_text),
+			rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int1_dem_inp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_SEC0, 0,
+			ARRAY_SIZE(rx_int_dem_inp_mux_text),
+			rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int2_dem_inp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_SEC0, 0,
+			ARRAY_SIZE(rx_int_dem_inp_mux_text),
+			rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int0_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CTL, 5, 2,
+			rx_int0_interp_mux_text);
+
+static const struct soc_enum rx_int1_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CTL, 5, 2,
+			rx_int1_interp_mux_text);
+
+static const struct soc_enum rx_int2_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CTL, 5, 2,
+			rx_int2_interp_mux_text);
+
+static const struct soc_enum rx_int3_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CTL, 5, 2,
+			rx_int3_interp_mux_text);
+
+static const struct soc_enum rx_int4_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CTL, 5, 2,
+			rx_int4_interp_mux_text);
+
+static const struct soc_enum rx_int5_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CTL, 5, 2,
+			rx_int5_interp_mux_text);
+
+static const struct soc_enum rx_int6_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CTL, 5, 2,
+			rx_int6_interp_mux_text);
+
+static const struct soc_enum rx_int7_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CTL, 5, 2,
+			rx_int7_interp_mux_text);
+
+static const struct soc_enum rx_int8_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2,
+			rx_int8_interp_mux_text);
+
+static const struct soc_enum mad_sel_enum =
+	SOC_ENUM_SINGLE(WCD9335_CPE_SS_CFG, 0, 2, mad_sel_text);
+
+static const struct soc_enum anc0_fb_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_ANC_CFG0, 0, 5,
+			anc0_fb_mux_text);
+
+static const struct soc_enum anc1_fb_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_ANC_CFG0, 3, 3,
+			anc1_fb_mux_text);
+
+static const struct snd_kcontrol_new rx_int0_dem_inp_mux =
+	SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
+	SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int2_dem_inp_mux =
+	SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new spl_src0_mux =
+	SOC_DAPM_ENUM("SPL SRC0 MUX Mux", spl_src0_mux_chain_enum);
+
+static const struct snd_kcontrol_new spl_src1_mux =
+	SOC_DAPM_ENUM("SPL SRC1 MUX Mux", spl_src1_mux_chain_enum);
+
+static const struct snd_kcontrol_new spl_src2_mux =
+	SOC_DAPM_ENUM("SPL SRC2 MUX Mux", spl_src2_mux_chain_enum);
+
+static const struct snd_kcontrol_new spl_src3_mux =
+	SOC_DAPM_ENUM("SPL SRC3 MUX Mux", spl_src3_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_2_mux =
+	SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_2_mux =
+	SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_2_mux =
+	SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_2_mux =
+	SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_2_mux =
+	SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_2_mux =
+	SOC_DAPM_ENUM("RX INT5_2 MUX Mux", rx_int5_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_2_mux =
+	SOC_DAPM_ENUM("RX INT6_2 MUX Mux", rx_int6_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_2_mux =
+	SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_2_mux =
+	SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new int1_1_native_mux =
+	SOC_DAPM_ENUM("RX INT1_1 NATIVE MUX Mux", int1_1_native_enum);
+
+static const struct snd_kcontrol_new int2_1_native_mux =
+	SOC_DAPM_ENUM("RX INT2_1 NATIVE MUX Mux", int2_1_native_enum);
+
+static const struct snd_kcontrol_new int3_1_native_mux =
+	SOC_DAPM_ENUM("RX INT3_1 NATIVE MUX Mux", int3_1_native_enum);
+
+static const struct snd_kcontrol_new int4_1_native_mux =
+	SOC_DAPM_ENUM("RX INT4_1 NATIVE MUX Mux", int4_1_native_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT5_1 MIX1 INP0 Mux", rx_int5_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT5_1 MIX1 INP1 Mux", rx_int5_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT5_1 MIX1 INP2 Mux", rx_int5_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT6_1 MIX1 INP0 Mux", rx_int6_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT6_1 MIX1 INP1 Mux", rx_int6_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT6_1 MIX1 INP2 Mux", rx_int6_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_mix2_inp_mux =
+	SOC_DAPM_ENUM("RX INT0 MIX2 INP Mux", rx_int0_sidetone_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_mix2_inp_mux =
+	SOC_DAPM_ENUM("RX INT1 MIX2 INP Mux", rx_int1_sidetone_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_mix2_inp_mux =
+	SOC_DAPM_ENUM("RX INT2 MIX2 INP Mux", rx_int2_sidetone_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_mix2_inp_mux =
+	SOC_DAPM_ENUM("RX INT3 MIX2 INP Mux", rx_int3_sidetone_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_mix2_inp_mux =
+	SOC_DAPM_ENUM("RX INT4 MIX2 INP Mux", rx_int4_sidetone_mix_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_mix2_inp_mux =
+	SOC_DAPM_ENUM("RX INT7 MIX2 INP Mux", rx_int7_sidetone_mix_chain_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux0 =
+	SOC_DAPM_ENUM_EXT("ADC MUX0 Mux", tx_adc_mux0_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux1 =
+	SOC_DAPM_ENUM_EXT("ADC MUX1 Mux", tx_adc_mux1_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux2 =
+	SOC_DAPM_ENUM_EXT("ADC MUX2 Mux", tx_adc_mux2_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux3 =
+	SOC_DAPM_ENUM_EXT("ADC MUX3 Mux", tx_adc_mux3_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux4 =
+	SOC_DAPM_ENUM_EXT("ADC MUX4 Mux", tx_adc_mux4_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux5 =
+	SOC_DAPM_ENUM_EXT("ADC MUX5 Mux", tx_adc_mux5_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux6 =
+	SOC_DAPM_ENUM_EXT("ADC MUX6 Mux", tx_adc_mux6_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux7 =
+	SOC_DAPM_ENUM_EXT("ADC MUX7 Mux", tx_adc_mux7_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux8 =
+	SOC_DAPM_ENUM_EXT("ADC MUX8 Mux", tx_adc_mux8_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  tasha_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux10 =
+	SOC_DAPM_ENUM("ADC MUX10 Mux", tx_adc_mux10_chain_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux11 =
+	SOC_DAPM_ENUM("ADC MUX11 Mux", tx_adc_mux11_chain_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux12 =
+	SOC_DAPM_ENUM("ADC MUX12 Mux", tx_adc_mux12_chain_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux13 =
+	SOC_DAPM_ENUM("ADC MUX13 Mux", tx_adc_mux13_chain_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux0 =
+	SOC_DAPM_ENUM("DMIC MUX0 Mux", tx_dmic_mux0_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux1 =
+	SOC_DAPM_ENUM("DMIC MUX1 Mux", tx_dmic_mux1_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux2 =
+	SOC_DAPM_ENUM("DMIC MUX2 Mux", tx_dmic_mux2_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux3 =
+	SOC_DAPM_ENUM("DMIC MUX3 Mux", tx_dmic_mux3_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux4 =
+	SOC_DAPM_ENUM("DMIC MUX4 Mux", tx_dmic_mux4_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux5 =
+	SOC_DAPM_ENUM("DMIC MUX5 Mux", tx_dmic_mux5_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux6 =
+	SOC_DAPM_ENUM("DMIC MUX6 Mux", tx_dmic_mux6_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux7 =
+	SOC_DAPM_ENUM("DMIC MUX7 Mux", tx_dmic_mux7_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux8 =
+	SOC_DAPM_ENUM("DMIC MUX8 Mux", tx_dmic_mux8_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux10 =
+	SOC_DAPM_ENUM("DMIC MUX10 Mux", tx_dmic_mux10_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux11 =
+	SOC_DAPM_ENUM("DMIC MUX11 Mux", tx_dmic_mux11_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux12 =
+	SOC_DAPM_ENUM("DMIC MUX12 Mux", tx_dmic_mux12_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux13 =
+	SOC_DAPM_ENUM("DMIC MUX13 Mux", tx_dmic_mux13_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux0 =
+	SOC_DAPM_ENUM("AMIC MUX0 Mux", tx_amic_mux0_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux1 =
+	SOC_DAPM_ENUM("AMIC MUX1 Mux", tx_amic_mux1_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux2 =
+	SOC_DAPM_ENUM("AMIC MUX2 Mux", tx_amic_mux2_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux3 =
+	SOC_DAPM_ENUM("AMIC MUX3 Mux", tx_amic_mux3_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux4 =
+	SOC_DAPM_ENUM("AMIC MUX4 Mux", tx_amic_mux4_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux5 =
+	SOC_DAPM_ENUM("AMIC MUX5 Mux", tx_amic_mux5_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux6 =
+	SOC_DAPM_ENUM("AMIC MUX6 Mux", tx_amic_mux6_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux7 =
+	SOC_DAPM_ENUM("AMIC MUX7 Mux", tx_amic_mux7_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux8 =
+	SOC_DAPM_ENUM("AMIC MUX8 Mux", tx_amic_mux8_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux10 =
+	SOC_DAPM_ENUM("AMIC MUX10 Mux", tx_amic_mux10_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux11 =
+	SOC_DAPM_ENUM("AMIC MUX11 Mux", tx_amic_mux11_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux12 =
+	SOC_DAPM_ENUM("AMIC MUX12 Mux", tx_amic_mux12_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux13 =
+	SOC_DAPM_ENUM("AMIC MUX13 Mux", tx_amic_mux13_enum);
+
+static const struct snd_kcontrol_new sb_tx0_mux =
+	SOC_DAPM_ENUM("SLIM TX0 MUX Mux", sb_tx0_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx1_mux =
+	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx2_mux =
+	SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx3_mux =
+	SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx4_mux =
+	SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx5_mux =
+	SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx6_mux =
+	SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx7_mux =
+	SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx8_mux =
+	SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx9_mux =
+	SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx10_mux =
+	SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx11_mux =
+	SOC_DAPM_ENUM("SLIM TX11 MUX Mux", sb_tx11_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx11_inp1_mux =
+	SOC_DAPM_ENUM("SLIM TX11 INP1 MUX Mux", sb_tx11_inp1_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx13_mux =
+	SOC_DAPM_ENUM("SLIM TX13 MUX Mux", sb_tx13_mux_enum);
+
+static const struct snd_kcontrol_new tx13_inp_mux =
+	SOC_DAPM_ENUM("TX13 INP MUX Mux", tx13_inp_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx0_mux =
+	SOC_DAPM_ENUM("RX MIX TX0 MUX Mux", rx_mix_tx0_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx1_mux =
+	SOC_DAPM_ENUM("RX MIX TX1 MUX Mux", rx_mix_tx1_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx2_mux =
+	SOC_DAPM_ENUM("RX MIX TX2 MUX Mux", rx_mix_tx2_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx3_mux =
+	SOC_DAPM_ENUM("RX MIX TX3 MUX Mux", rx_mix_tx3_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx4_mux =
+	SOC_DAPM_ENUM("RX MIX TX4 MUX Mux", rx_mix_tx4_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx5_mux =
+	SOC_DAPM_ENUM("RX MIX TX5 MUX Mux", rx_mix_tx5_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx6_mux =
+	SOC_DAPM_ENUM("RX MIX TX6 MUX Mux", rx_mix_tx6_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx7_mux =
+	SOC_DAPM_ENUM("RX MIX TX7 MUX Mux", rx_mix_tx7_mux_enum);
+
+static const struct snd_kcontrol_new rx_mix_tx8_mux =
+	SOC_DAPM_ENUM("RX MIX TX8 MUX Mux", rx_mix_tx8_mux_enum);
+
+static const struct snd_kcontrol_new iir0_inp0_mux =
+	SOC_DAPM_ENUM("IIR0 INP0 Mux", iir0_inp0_mux_enum);
+
+static const struct snd_kcontrol_new iir0_inp1_mux =
+	SOC_DAPM_ENUM("IIR0 INP1 Mux", iir0_inp1_mux_enum);
+
+static const struct snd_kcontrol_new iir0_inp2_mux =
+	SOC_DAPM_ENUM("IIR0 INP2 Mux", iir0_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir0_inp3_mux =
+	SOC_DAPM_ENUM("IIR0 INP3 Mux", iir0_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp0_mux =
+	SOC_DAPM_ENUM("IIR1 INP0 Mux", iir1_inp0_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp2_mux =
+	SOC_DAPM_ENUM("IIR1 INP2 Mux", iir1_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp3_mux =
+	SOC_DAPM_ENUM("IIR1 INP3 Mux", iir1_inp3_mux_enum);
+
+static const struct snd_kcontrol_new rx_int0_interp_mux =
+	SOC_DAPM_ENUM("RX INT0 INTERP Mux", rx_int0_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int1_interp_mux =
+	SOC_DAPM_ENUM("RX INT1 INTERP Mux", rx_int1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int2_interp_mux =
+	SOC_DAPM_ENUM("RX INT2 INTERP Mux", rx_int2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int3_interp_mux =
+	SOC_DAPM_ENUM("RX INT3 INTERP Mux", rx_int3_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int4_interp_mux =
+	SOC_DAPM_ENUM("RX INT4 INTERP Mux", rx_int4_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int5_interp_mux =
+	SOC_DAPM_ENUM("RX INT5 INTERP Mux", rx_int5_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int6_interp_mux =
+	SOC_DAPM_ENUM("RX INT6 INTERP Mux", rx_int6_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int7_interp_mux =
+	SOC_DAPM_ENUM("RX INT7 INTERP Mux", rx_int7_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int8_interp_mux =
+	SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum);
+
+static const struct snd_kcontrol_new mad_sel_mux =
+	SOC_DAPM_ENUM("MAD_SEL MUX Mux", mad_sel_enum);
+
+static const struct snd_kcontrol_new aif4_mad_switch =
+	SOC_DAPM_SINGLE("Switch", WCD9335_CPE_SS_CFG, 5, 1, 0);
+
+static const struct snd_kcontrol_new mad_brdcst_switch =
+	SOC_DAPM_SINGLE("Switch", WCD9335_CPE_SS_CFG, 6, 1, 0);
+
+static const struct snd_kcontrol_new aif4_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+			0, 1, 0, tasha_codec_aif4_mixer_switch_get,
+			tasha_codec_aif4_mixer_switch_put);
+
+static const struct snd_kcontrol_new anc_hphl_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_hphr_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_ear_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_ear_spkr_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_lineout1_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_lineout2_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_spkr_pa_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux0_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux1_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux2_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux3_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux4_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux5_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux6_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux7_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux8_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc0_fb_mux =
+	SOC_DAPM_ENUM("ANC0 FB MUX Mux", anc0_fb_mux_enum);
+
+static const struct snd_kcontrol_new anc1_fb_mux =
+	SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
+
+static int tasha_codec_ec_buf_mux_enable(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s: event = %d name = %s\n",
+		__func__, event, w->name);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_write(codec, WCD9335_CPE_SS_EC_BUF_INT_PERIOD, 0x3B);
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG, 0x08, 0x08);
+		snd_soc_update_bits(codec, WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0,
+				    0x08, 0x08);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0,
+				    0x08, 0x00);
+		snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG, 0x08, 0x00);
+		snd_soc_write(codec, WCD9335_CPE_SS_EC_BUF_INT_PERIOD, 0x00);
+		break;
+	}
+
+	return 0;
+};
+
+static const char * const ec_buf_mux_text[] = {
+	"ZERO", "RXMIXEC", "SB_RX0", "SB_RX1", "SB_RX2", "SB_RX3",
+	"I2S_RX_SD0_L", "I2S_RX_SD0_R", "I2S_RX_SD1_L", "I2S_RX_SD1_R",
+	"DEC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(ec_buf_mux_enum, WCD9335_CPE_SS_US_EC_MUX_CFG,
+			    0, ec_buf_mux_text);
+
+static const struct snd_kcontrol_new ec_buf_mux =
+	SOC_DAPM_ENUM("EC BUF Mux", ec_buf_mux_enum);
+
+static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("ANC EAR"),
+	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+				AIF1_PB, 0, tasha_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
+				AIF2_PB, 0, tasha_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
+				AIF3_PB, 0, tasha_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM,
+				AIF4_PB, 0, tasha_codec_enable_slimrx,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF MIX1 PB", "AIF Mix Playback", 0,
+			       SND_SOC_NOPM, AIF_MIX1_PB, 0,
+			       tasha_codec_enable_slimrx,
+			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+			       SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, TASHA_RX0, 0,
+				&slim_rx_mux[TASHA_RX0]),
+	SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TASHA_RX1, 0,
+				&slim_rx_mux[TASHA_RX1]),
+	SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TASHA_RX2, 0,
+				&slim_rx_mux[TASHA_RX2]),
+	SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TASHA_RX3, 0,
+				&slim_rx_mux[TASHA_RX3]),
+	SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TASHA_RX4, 0,
+				&slim_rx_mux[TASHA_RX4]),
+	SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TASHA_RX5, 0,
+				&slim_rx_mux[TASHA_RX5]),
+	SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, TASHA_RX6, 0,
+				&slim_rx_mux[TASHA_RX6]),
+	SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, TASHA_RX7, 0,
+				&slim_rx_mux[TASHA_RX7]),
+
+	SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX_E("SPL SRC0 MUX", SND_SOC_NOPM, SPLINE_SRC0, 0,
+			 &spl_src0_mux, tasha_codec_enable_spline_resampler,
+			 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("SPL SRC1 MUX", SND_SOC_NOPM, SPLINE_SRC1, 0,
+			 &spl_src1_mux, tasha_codec_enable_spline_resampler,
+			 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("SPL SRC2 MUX", SND_SOC_NOPM, SPLINE_SRC2, 0,
+			 &spl_src2_mux, tasha_codec_enable_spline_resampler,
+			 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("SPL SRC3 MUX", SND_SOC_NOPM, SPLINE_SRC3, 0,
+			 &spl_src3_mux, tasha_codec_enable_spline_resampler,
+			 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD9335_CDC_RX0_RX_PATH_MIX_CTL,
+			5, 0, &rx_int0_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+			5, 0, &rx_int1_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+			5, 0, &rx_int2_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD9335_CDC_RX3_RX_PATH_MIX_CTL,
+			5, 0, &rx_int3_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD9335_CDC_RX4_RX_PATH_MIX_CTL,
+			5, 0, &rx_int4_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT5_2 MUX", WCD9335_CDC_RX5_RX_PATH_MIX_CTL,
+			5, 0, &rx_int5_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT6_2 MUX", WCD9335_CDC_RX6_RX_PATH_MIX_CTL,
+			5, 0, &rx_int6_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD9335_CDC_RX7_RX_PATH_MIX_CTL,
+			5, 0, &rx_int7_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD9335_CDC_RX8_RX_PATH_MIX_CTL,
+			5, 0, &rx_int8_2_mux, tasha_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int0_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int0_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int0_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int1_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int1_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int1_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int2_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int2_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int2_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int3_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int3_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int3_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int4_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int4_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int4_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int5_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int5_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int5_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int6_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int6_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int6_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp0_mux, tasha_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp1_mux, tasha_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp2_mux, tasha_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp0_mux, tasha_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp1_mux, tasha_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp2_mux, tasha_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int1_spline_mix_switch,
+			ARRAY_SIZE(rx_int1_spline_mix_switch)),
+	SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int2_spline_mix_switch,
+			ARRAY_SIZE(rx_int2_spline_mix_switch)),
+	SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int3_spline_mix_switch,
+			ARRAY_SIZE(rx_int3_spline_mix_switch)),
+	SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int4_spline_mix_switch,
+			ARRAY_SIZE(rx_int4_spline_mix_switch)),
+	SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT5_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT5 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int5_spline_mix_switch,
+			ARRAY_SIZE(rx_int5_spline_mix_switch)),
+	SND_SOC_DAPM_MIXER("RX INT5 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("RX INT6_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT6 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int6_spline_mix_switch,
+			ARRAY_SIZE(rx_int6_spline_mix_switch)),
+	SND_SOC_DAPM_MIXER("RX INT6 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT7 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int7_spline_mix_switch,
+			ARRAY_SIZE(rx_int7_spline_mix_switch)),
+
+	SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT8 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+			rx_int8_spline_mix_switch,
+			ARRAY_SIZE(rx_int8_spline_mix_switch)),
+
+	SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT5 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT6 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0,
+			NULL, 0, tasha_codec_spk_boost_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT8 CHAIN", SND_SOC_NOPM, 0, 0,
+			NULL, 0, tasha_codec_spk_boost_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("RX INT5 VBAT", SND_SOC_NOPM, 0, 0,
+			rx_int5_vbat_mix_switch,
+			ARRAY_SIZE(rx_int5_vbat_mix_switch),
+			tasha_codec_vbat_enable_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT6 VBAT", SND_SOC_NOPM, 0, 0,
+			rx_int6_vbat_mix_switch,
+			ARRAY_SIZE(rx_int6_vbat_mix_switch),
+			tasha_codec_vbat_enable_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT7 VBAT", SND_SOC_NOPM, 0, 0,
+			rx_int7_vbat_mix_switch,
+			ARRAY_SIZE(rx_int7_vbat_mix_switch),
+			tasha_codec_vbat_enable_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT8 VBAT", SND_SOC_NOPM, 0, 0,
+			rx_int8_vbat_mix_switch,
+			ARRAY_SIZE(rx_int8_vbat_mix_switch),
+			tasha_codec_vbat_enable_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("RX INT0 MIX2 INP", WCD9335_CDC_RX0_RX_PATH_CFG1, 4,
+			   0, &rx_int0_mix2_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT1 MIX2 INP", WCD9335_CDC_RX1_RX_PATH_CFG1, 4,
+			   0, &rx_int1_mix2_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT2 MIX2 INP", WCD9335_CDC_RX2_RX_PATH_CFG1, 4,
+			   0, &rx_int2_mix2_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT3 MIX2 INP", WCD9335_CDC_RX3_RX_PATH_CFG1, 4,
+			   0, &rx_int3_mix2_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT4 MIX2 INP", WCD9335_CDC_RX4_RX_PATH_CFG1, 4,
+			   0, &rx_int4_mix2_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT7 MIX2 INP", WCD9335_CDC_RX7_RX_PATH_CFG1, 4,
+			   0, &rx_int7_mix2_inp_mux),
+
+	SND_SOC_DAPM_MUX("SLIM TX0 MUX", SND_SOC_NOPM, TASHA_TX0, 0,
+		&sb_tx0_mux),
+	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TASHA_TX1, 0,
+		&sb_tx1_mux),
+	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TASHA_TX2, 0,
+		&sb_tx2_mux),
+	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TASHA_TX3, 0,
+		&sb_tx3_mux),
+	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TASHA_TX4, 0,
+		&sb_tx4_mux),
+	SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TASHA_TX5, 0,
+		&sb_tx5_mux),
+	SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, TASHA_TX6, 0,
+		&sb_tx6_mux),
+	SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, TASHA_TX7, 0,
+		&sb_tx7_mux),
+	SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, TASHA_TX8, 0,
+		&sb_tx8_mux),
+	SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, TASHA_TX9, 0,
+		&sb_tx9_mux),
+	SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, TASHA_TX10, 0,
+		&sb_tx10_mux),
+	SND_SOC_DAPM_MUX("SLIM TX11 MUX", SND_SOC_NOPM, TASHA_TX11, 0,
+		&sb_tx11_mux),
+	SND_SOC_DAPM_MUX("SLIM TX11 INP1 MUX", SND_SOC_NOPM, TASHA_TX11, 0,
+		&sb_tx11_inp1_mux),
+	SND_SOC_DAPM_MUX("SLIM TX13 MUX", SND_SOC_NOPM, TASHA_TX13, 0,
+		&sb_tx13_mux),
+	SND_SOC_DAPM_MUX("TX13 INP MUX", SND_SOC_NOPM, 0, 0,
+			 &tx13_inp_mux),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX0", WCD9335_CDC_TX0_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux0, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX1", WCD9335_CDC_TX1_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux1, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX2", WCD9335_CDC_TX2_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux2, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX3", WCD9335_CDC_TX3_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux3, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX4", WCD9335_CDC_TX4_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux4, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX5", WCD9335_CDC_TX5_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux5, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX6", WCD9335_CDC_TX6_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux6, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX7", WCD9335_CDC_TX7_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux7, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX8", WCD9335_CDC_TX8_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux8, tasha_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX10", SND_SOC_NOPM, 10, 0,
+			 &tx_adc_mux10, tasha_codec_tx_adc_cfg,
+			 SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX11", SND_SOC_NOPM, 11, 0,
+			 &tx_adc_mux11, tasha_codec_tx_adc_cfg,
+			 SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX12", SND_SOC_NOPM, 12, 0,
+			 &tx_adc_mux12, tasha_codec_tx_adc_cfg,
+			 SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX13", SND_SOC_NOPM, 13, 0,
+			 &tx_adc_mux13, tasha_codec_tx_adc_cfg,
+			 SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX("DMIC MUX0", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux0),
+	SND_SOC_DAPM_MUX("DMIC MUX1", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux1),
+	SND_SOC_DAPM_MUX("DMIC MUX2", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux2),
+	SND_SOC_DAPM_MUX("DMIC MUX3", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux3),
+	SND_SOC_DAPM_MUX("DMIC MUX4", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux4),
+	SND_SOC_DAPM_MUX("DMIC MUX5", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux5),
+	SND_SOC_DAPM_MUX("DMIC MUX6", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux6),
+	SND_SOC_DAPM_MUX("DMIC MUX7", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux7),
+	SND_SOC_DAPM_MUX("DMIC MUX8", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux8),
+	SND_SOC_DAPM_MUX("DMIC MUX10", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux10),
+	SND_SOC_DAPM_MUX("DMIC MUX11", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux11),
+	SND_SOC_DAPM_MUX("DMIC MUX12", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux12),
+	SND_SOC_DAPM_MUX("DMIC MUX13", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux13),
+
+	SND_SOC_DAPM_MUX("AMIC MUX0", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux0),
+	SND_SOC_DAPM_MUX("AMIC MUX1", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux1),
+	SND_SOC_DAPM_MUX("AMIC MUX2", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux2),
+	SND_SOC_DAPM_MUX("AMIC MUX3", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux3),
+	SND_SOC_DAPM_MUX("AMIC MUX4", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux4),
+	SND_SOC_DAPM_MUX("AMIC MUX5", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux5),
+	SND_SOC_DAPM_MUX("AMIC MUX6", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux6),
+	SND_SOC_DAPM_MUX("AMIC MUX7", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux7),
+	SND_SOC_DAPM_MUX("AMIC MUX8", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux8),
+	SND_SOC_DAPM_MUX("AMIC MUX10", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux10),
+	SND_SOC_DAPM_MUX("AMIC MUX11", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux11),
+	SND_SOC_DAPM_MUX("AMIC MUX12", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux12),
+	SND_SOC_DAPM_MUX("AMIC MUX13", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux13),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD9335_ANA_AMIC1, 7, 0,
+			   tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD9335_ANA_AMIC2, 7, 0,
+			   tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD9335_ANA_AMIC3, 7, 0,
+			   tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD9335_ANA_AMIC4, 7, 0,
+			   tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC5", NULL, WCD9335_ANA_AMIC5, 7, 0,
+			   tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC6", NULL, WCD9335_ANA_AMIC6, 7, 0,
+			   tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_SUPPLY("RX INT1 NATIVE SUPPLY", SND_SOC_NOPM,
+			    INTERP_HPHL, 0, tasha_enable_native_supply,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("RX INT2 NATIVE SUPPLY", SND_SOC_NOPM,
+			    INTERP_HPHR, 0, tasha_enable_native_supply,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("RX INT3 NATIVE SUPPLY", SND_SOC_NOPM,
+			    INTERP_LO1, 0, tasha_enable_native_supply,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("RX INT4 NATIVE SUPPLY", SND_SOC_NOPM,
+			    INTERP_LO2, 0, tasha_enable_native_supply,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0,
+			       tasha_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2", SND_SOC_NOPM, 0, 0,
+			       tasha_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3", SND_SOC_NOPM, 0, 0,
+			       tasha_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4", SND_SOC_NOPM, 0, 0,
+			       tasha_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0,
+			       tasha_codec_force_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_STANDALONE, SND_SOC_NOPM, 0, 0,
+			       tasha_codec_force_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS3_STANDALONE, SND_SOC_NOPM, 0, 0,
+			       tasha_codec_force_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0,
+			       tasha_codec_force_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY(DAPM_LDO_H_STANDALONE, SND_SOC_NOPM, 0, 0,
+			    tasha_codec_force_enable_ldo_h,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("ANC0 FB MUX", SND_SOC_NOPM, 0, 0, &anc0_fb_mux),
+	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_INPUT("AMIC4"),
+	SND_SOC_DAPM_INPUT("AMIC5"),
+	SND_SOC_DAPM_INPUT("AMIC6"),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+		AIF1_CAP, 0, tasha_codec_enable_slimtx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
+		AIF2_CAP, 0, tasha_codec_enable_slimtx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
+		AIF3_CAP, 0, tasha_codec_enable_slimtx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
+		AIF4_VIFEED, 0, tasha_codec_enable_slimvi_feedback,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("AIF4_VI Mixer", SND_SOC_NOPM, AIF4_VIFEED, 0,
+		aif4_vi_mixer, ARRAY_SIZE(aif4_vi_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+		aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+		aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+		aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF4_MAD Mixer", SND_SOC_NOPM, AIF4_MAD_TX, 0,
+		aif4_mad_mixer, ARRAY_SIZE(aif4_mad_mixer)),
+
+	SND_SOC_DAPM_INPUT("VIINPUT"),
+
+	SND_SOC_DAPM_AIF_OUT("AIF5 CPE", "AIF5 CPE TX", 0, SND_SOC_NOPM,
+			     AIF5_CPE_TX, 0),
+
+	SND_SOC_DAPM_MUX_E("EC BUF MUX INP", SND_SOC_NOPM, 0, 0, &ec_buf_mux,
+		tasha_codec_ec_buf_mux_enable,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+		tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+		tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("IIR0 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp0_mux),
+	SND_SOC_DAPM_MUX("IIR0 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp1_mux),
+	SND_SOC_DAPM_MUX("IIR0 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp2_mux),
+	SND_SOC_DAPM_MUX("IIR0 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp3_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp0_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp2_mux),
+	SND_SOC_DAPM_MUX("IIR1 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp3_mux),
+
+	SND_SOC_DAPM_MIXER_E("IIR0", WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL,
+			     4, 0, NULL, 0, tasha_codec_set_iir_gain,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER_E("IIR1", WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL,
+			     4, 0, NULL, 0, tasha_codec_set_iir_gain,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER("SRC0", WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL,
+			     4, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SRC1", WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL,
+			     4, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER_E("CPE IN Mixer", SND_SOC_NOPM, 0, 0,
+				cpe_in_mix_switch,
+				ARRAY_SIZE(cpe_in_mix_switch),
+				tasha_codec_configure_cpe_input,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("RX INT1_1 NATIVE MUX", SND_SOC_NOPM, 0, 0,
+		&int1_1_native_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 NATIVE MUX", SND_SOC_NOPM, 0, 0,
+		&int2_1_native_mux),
+	SND_SOC_DAPM_MUX("RX INT3_1 NATIVE MUX", SND_SOC_NOPM, 0, 0,
+		&int3_1_native_mux),
+	SND_SOC_DAPM_MUX("RX INT4_1 NATIVE MUX", SND_SOC_NOPM, 0, 0,
+		&int4_1_native_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX0 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx0_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX1 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx1_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX2 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx2_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX3 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx3_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX4 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx4_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX5 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx5_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX6 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx6_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX7 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx7_mux),
+	SND_SOC_DAPM_MUX("RX MIX TX8 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_mix_tx8_mux),
+
+	SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
+		&rx_int0_dem_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+		&rx_int1_dem_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0,
+		&rx_int2_dem_inp_mux),
+
+	SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM,
+		INTERP_EAR, 0, &rx_int0_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM,
+		INTERP_HPHL, 0, &rx_int1_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM,
+		INTERP_HPHR, 0, &rx_int2_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM,
+		INTERP_LO1, 0, &rx_int3_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM,
+		INTERP_LO2, 0, &rx_int4_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT5 INTERP", SND_SOC_NOPM,
+		INTERP_LO3, 0, &rx_int5_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT6 INTERP", SND_SOC_NOPM,
+		INTERP_LO4, 0, &rx_int6_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM,
+		INTERP_SPKR1, 0, &rx_int7_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM,
+		INTERP_SPKR2, 0, &rx_int8_interp_mux,
+		tasha_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tasha_codec_ear_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD9335_ANA_HPH,
+		5, 0, tasha_codec_hphl_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD9335_ANA_HPH,
+		4, 0, tasha_codec_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tasha_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tasha_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT5 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tasha_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT6 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tasha_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0,
+			   tasha_codec_enable_hphl_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0,
+			   tasha_codec_enable_hphr_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0,
+			   tasha_codec_enable_ear_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0,
+			   tasha_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD9335_ANA_LO_1_2, 6, 0, NULL, 0,
+			   tasha_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT3 PA", WCD9335_ANA_LO_3_4, 7, 0, NULL, 0,
+			   tasha_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT4 PA", WCD9335_ANA_LO_3_4, 6, 0, NULL, 0,
+			   tasha_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0,
+			   tasha_codec_enable_ear_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+			   tasha_codec_enable_hphl_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+			   tasha_codec_enable_hphr_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC LINEOUT1 PA", WCD9335_ANA_LO_1_2,
+				7, 0, NULL, 0,
+				tasha_codec_enable_lineout_pa,
+				SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC LINEOUT2 PA", WCD9335_ANA_LO_1_2,
+				6, 0, NULL, 0,
+				tasha_codec_enable_lineout_pa,
+				SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC SPK1 PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+			   tasha_codec_enable_spk_anc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("HPHL"),
+	SND_SOC_DAPM_OUTPUT("HPHR"),
+	SND_SOC_DAPM_OUTPUT("ANC HPHL"),
+	SND_SOC_DAPM_OUTPUT("ANC HPHR"),
+	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+		tasha_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
+	SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT3"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT4"),
+	SND_SOC_DAPM_OUTPUT("ANC LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("ANC LINEOUT2"),
+	SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
+		ON_DEMAND_MICBIAS, 0,
+		tasha_codec_enable_on_demand_supply,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SWITCH("ADC US MUX0", WCD9335_CDC_TX0_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux0_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX1", WCD9335_CDC_TX1_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux1_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX2", WCD9335_CDC_TX2_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux2_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX3", WCD9335_CDC_TX3_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux3_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX4", WCD9335_CDC_TX4_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux4_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX5", WCD9335_CDC_TX5_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux5_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX6", WCD9335_CDC_TX6_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux6_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX7", WCD9335_CDC_TX7_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux7_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX8", WCD9335_CDC_TX8_TX_PATH_192_CTL, 0,
+			    0, &adc_us_mux8_switch),
+	/* MAD related widgets */
+	SND_SOC_DAPM_AIF_OUT_E("AIF4 MAD", "AIF4 MAD TX", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       tasha_codec_enable_mad,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("MAD_SEL MUX", SND_SOC_NOPM, 0, 0,
+			 &mad_sel_mux),
+	SND_SOC_DAPM_INPUT("MAD_CPE_INPUT"),
+	SND_SOC_DAPM_INPUT("MADINPUT"),
+	SND_SOC_DAPM_SWITCH("MADONOFF", SND_SOC_NOPM, 0, 0,
+			    &aif4_mad_switch),
+	SND_SOC_DAPM_SWITCH("MAD_BROADCAST", SND_SOC_NOPM, 0, 0,
+			    &mad_brdcst_switch),
+	SND_SOC_DAPM_SWITCH("AIF4", SND_SOC_NOPM, 0, 0,
+			    &aif4_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("ANC HPHL Enable", SND_SOC_NOPM, 0, 0,
+			&anc_hphl_switch),
+	SND_SOC_DAPM_SWITCH("ANC HPHR Enable", SND_SOC_NOPM, 0, 0,
+			&anc_hphr_switch),
+	SND_SOC_DAPM_SWITCH("ANC EAR Enable", SND_SOC_NOPM, 0, 0,
+			&anc_ear_switch),
+	SND_SOC_DAPM_SWITCH("ANC OUT EAR SPKR Enable", SND_SOC_NOPM, 0, 0,
+			    &anc_ear_spkr_switch),
+	SND_SOC_DAPM_SWITCH("ANC LINEOUT1 Enable", SND_SOC_NOPM, 0, 0,
+			&anc_lineout1_switch),
+	SND_SOC_DAPM_SWITCH("ANC LINEOUT2 Enable", SND_SOC_NOPM, 0, 0,
+			&anc_lineout2_switch),
+	SND_SOC_DAPM_SWITCH("ANC SPKR PA Enable", SND_SOC_NOPM, 0, 0,
+			    &anc_spkr_pa_switch),
+};
+
+static int tasha_get_channel_map(struct snd_soc_dai *dai,
+				 unsigned int *tx_num, unsigned int *tx_slot,
+				 unsigned int *rx_num, unsigned int *rx_slot)
+{
+	struct tasha_priv *tasha_p = snd_soc_codec_get_drvdata(dai->codec);
+	u32 i = 0;
+	struct wcd9xxx_ch *ch;
+
+	switch (dai->id) {
+	case AIF1_PB:
+	case AIF2_PB:
+	case AIF3_PB:
+	case AIF4_PB:
+	case AIF_MIX1_PB:
+		if (!rx_slot || !rx_num) {
+			pr_err("%s: Invalid rx_slot %pK or rx_num %pK\n",
+				 __func__, rx_slot, rx_num);
+			return -EINVAL;
+		}
+		list_for_each_entry(ch, &tasha_p->dai[dai->id].wcd9xxx_ch_list,
+				    list) {
+			pr_debug("%s: slot_num %u ch->ch_num %d\n",
+				 __func__, i, ch->ch_num);
+			rx_slot[i++] = ch->ch_num;
+		}
+		pr_debug("%s: rx_num %d\n", __func__, i);
+		*rx_num = i;
+		break;
+	case AIF1_CAP:
+	case AIF2_CAP:
+	case AIF3_CAP:
+	case AIF4_MAD_TX:
+	case AIF4_VIFEED:
+		if (!tx_slot || !tx_num) {
+			pr_err("%s: Invalid tx_slot %pK or tx_num %pK\n",
+				 __func__, tx_slot, tx_num);
+			return -EINVAL;
+		}
+		list_for_each_entry(ch, &tasha_p->dai[dai->id].wcd9xxx_ch_list,
+				    list) {
+			pr_debug("%s: slot_num %u ch->ch_num %d\n",
+				 __func__, i,  ch->ch_num);
+			tx_slot[i++] = ch->ch_num;
+		}
+		pr_debug("%s: tx_num %d\n", __func__, i);
+		*tx_num = i;
+		break;
+
+	default:
+		pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
+		break;
+	}
+
+	return 0;
+}
+
+static int tasha_set_channel_map(struct snd_soc_dai *dai,
+				 unsigned int tx_num, unsigned int *tx_slot,
+				 unsigned int rx_num, unsigned int *rx_slot)
+{
+	struct tasha_priv *tasha;
+	struct wcd9xxx *core;
+	struct wcd9xxx_codec_dai_data *dai_data = NULL;
+
+	if (!dai) {
+		pr_err("%s: dai is empty\n", __func__);
+		return -EINVAL;
+	}
+	tasha = snd_soc_codec_get_drvdata(dai->codec);
+	core = dev_get_drvdata(dai->codec->dev->parent);
+
+	if (!tx_slot || !rx_slot) {
+		pr_err("%s: Invalid tx_slot=%pK, rx_slot=%pK\n",
+			__func__, tx_slot, rx_slot);
+		return -EINVAL;
+	}
+	pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n"
+		 "tasha->intf_type %d\n",
+		 __func__, dai->name, dai->id, tx_num, rx_num,
+		 tasha->intf_type);
+
+	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		wcd9xxx_init_slimslave(core, core->slim->laddr,
+					   tx_num, tx_slot, rx_num, rx_slot);
+		/* Reserve TX12/TX13 for MAD data channel */
+		dai_data = &tasha->dai[AIF4_MAD_TX];
+		if (dai_data) {
+			if (TASHA_IS_2_0(tasha->wcd9xxx))
+				list_add_tail(&core->tx_chs[TASHA_TX13].list,
+					      &dai_data->wcd9xxx_ch_list);
+			else
+				list_add_tail(&core->tx_chs[TASHA_TX12].list,
+					      &dai_data->wcd9xxx_ch_list);
+		}
+	}
+	return 0;
+}
+
+static int tasha_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	return 0;
+}
+
+static void tasha_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(dai->codec);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+		return;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		tasha_codec_vote_max_bw(dai->codec, false);
+}
+
+static int tasha_set_decimator_rate(struct snd_soc_dai *dai,
+				    u8 tx_fs_rate_reg_val, u32 sample_rate)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wcd9xxx_ch *ch;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u32 tx_port = 0;
+	u8 shift = 0, shift_val = 0, tx_mux_sel = 0;
+	int decimator = -1;
+	u16 tx_port_reg = 0, tx_fs_reg = 0;
+
+	list_for_each_entry(ch, &tasha->dai[dai->id].wcd9xxx_ch_list, list) {
+		tx_port = ch->port;
+		dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
+			__func__, dai->id, tx_port);
+
+		if ((tx_port < 0) || (tx_port == 12) || (tx_port >= 14)) {
+			dev_err(codec->dev, "%s: Invalid SLIM TX%u port. DAI ID: %d\n",
+				__func__, tx_port, dai->id);
+			return -EINVAL;
+		}
+		/* Find the SB TX MUX input - which decimator is connected */
+		if (tx_port < 4) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0;
+			shift = (tx_port << 1);
+			shift_val = 0x03;
+		} else if ((tx_port >= 4) && (tx_port < 8)) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1;
+			shift = ((tx_port - 4) << 1);
+			shift_val = 0x03;
+		} else if ((tx_port >= 8) && (tx_port < 11)) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2;
+			shift = ((tx_port - 8) << 1);
+			shift_val = 0x03;
+		} else if (tx_port == 11) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3;
+			shift = 0;
+			shift_val = 0x0F;
+		} else if (tx_port == 13) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3;
+			shift = 4;
+			shift_val = 0x03;
+		}
+		tx_mux_sel = snd_soc_read(codec, tx_port_reg) &
+					  (shift_val << shift);
+		tx_mux_sel = tx_mux_sel >> shift;
+
+		if (tx_port <= 8) {
+			if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3))
+				decimator = tx_port;
+		} else if (tx_port <= 10) {
+			if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+				decimator = ((tx_port == 9) ? 7 : 6);
+		} else if (tx_port == 11) {
+			if ((tx_mux_sel >= 1) && (tx_mux_sel < 7))
+				decimator = tx_mux_sel - 1;
+		} else if (tx_port == 13) {
+			if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+				decimator = 5;
+		}
+
+		if (decimator >= 0) {
+			tx_fs_reg = WCD9335_CDC_TX0_TX_PATH_CTL +
+				    16 * decimator;
+			dev_dbg(codec->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
+				__func__, decimator, tx_port, sample_rate);
+			snd_soc_update_bits(codec, tx_fs_reg, 0x0F,
+					    tx_fs_rate_reg_val);
+		} else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) {
+			/* Check if the TX Mux input is RX MIX TXn */
+			dev_dbg(codec->dev, "%s: RX_MIX_TX%u going to SLIM TX%u\n",
+					__func__, tx_port, tx_port);
+		} else {
+			dev_err(codec->dev, "%s: ERROR: Invalid decimator: %d\n",
+				__func__, decimator);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int tasha_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+					   u8 int_mix_fs_rate_reg_val,
+					   u32 sample_rate)
+{
+	u8 int_2_inp;
+	u32 j;
+	u16 int_mux_cfg1, int_fs_reg;
+	u8 int_mux_cfg1_val;
+	struct snd_soc_codec *codec = dai->codec;
+	struct wcd9xxx_ch *ch;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	list_for_each_entry(ch, &tasha->dai[dai->id].wcd9xxx_ch_list, list) {
+		int_2_inp = ch->port + INTn_2_INP_SEL_RX0 -
+				  TASHA_RX_PORT_START_NUMBER;
+		if ((int_2_inp < INTn_2_INP_SEL_RX0) ||
+		   (int_2_inp > INTn_2_INP_SEL_RX7)) {
+			pr_err("%s: Invalid RX%u port, Dai ID is %d\n",
+				__func__,
+				(ch->port - TASHA_RX_PORT_START_NUMBER),
+				dai->id);
+			return -EINVAL;
+		}
+
+		int_mux_cfg1 = WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1;
+		for (j = 0; j < TASHA_NUM_INTERPOLATORS; j++) {
+			int_mux_cfg1_val = snd_soc_read(codec, int_mux_cfg1) &
+						0x0F;
+			if (int_mux_cfg1_val == int_2_inp) {
+				int_fs_reg = WCD9335_CDC_RX0_RX_PATH_MIX_CTL +
+						20 * j;
+				pr_debug("%s: AIF_MIX_PB DAI(%d) connected to INT%u_2\n",
+					  __func__, dai->id, j);
+				pr_debug("%s: set INT%u_2 sample rate to %u\n",
+					__func__, j, sample_rate);
+				snd_soc_update_bits(codec, int_fs_reg,
+						0x0F, int_mix_fs_rate_reg_val);
+			}
+			int_mux_cfg1 += 2;
+		}
+	}
+	return 0;
+}
+
+static int tasha_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+					    u8 int_prim_fs_rate_reg_val,
+					    u32 sample_rate)
+{
+	u8 int_1_mix1_inp;
+	u32 j;
+	u16 int_mux_cfg0, int_mux_cfg1;
+	u16 int_fs_reg;
+	u8 int_mux_cfg0_val, int_mux_cfg1_val;
+	u8 inp0_sel, inp1_sel, inp2_sel;
+	struct snd_soc_codec *codec = dai->codec;
+	struct wcd9xxx_ch *ch;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	list_for_each_entry(ch, &tasha->dai[dai->id].wcd9xxx_ch_list, list) {
+		int_1_mix1_inp = ch->port + INTn_1_MIX_INP_SEL_RX0 -
+				  TASHA_RX_PORT_START_NUMBER;
+		if ((int_1_mix1_inp < INTn_1_MIX_INP_SEL_RX0) ||
+		   (int_1_mix1_inp > INTn_1_MIX_INP_SEL_RX7)) {
+			pr_err("%s: Invalid RX%u port, Dai ID is %d\n",
+				__func__,
+				(ch->port - TASHA_RX_PORT_START_NUMBER),
+				dai->id);
+			return -EINVAL;
+		}
+
+		int_mux_cfg0 = WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0;
+
+		/*
+		 * Loop through all interpolator MUX inputs and find out
+		 * to which interpolator input, the slim rx port
+		 * is connected
+		 */
+		for (j = 0; j < TASHA_NUM_INTERPOLATORS; j++) {
+			int_mux_cfg1 = int_mux_cfg0 + 1;
+
+			int_mux_cfg0_val = snd_soc_read(codec, int_mux_cfg0);
+			int_mux_cfg1_val = snd_soc_read(codec, int_mux_cfg1);
+			inp0_sel = int_mux_cfg0_val & 0x0F;
+			inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F;
+			inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F;
+			if ((inp0_sel == int_1_mix1_inp) ||
+			    (inp1_sel == int_1_mix1_inp) ||
+			    (inp2_sel == int_1_mix1_inp)) {
+				int_fs_reg = WCD9335_CDC_RX0_RX_PATH_CTL +
+					     20 * j;
+				pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_1\n",
+					  __func__, dai->id, j);
+				pr_debug("%s: set INT%u_1 sample rate to %u\n",
+					__func__, j, sample_rate);
+				/* sample_rate is in Hz */
+				if ((j == 0) && (sample_rate == 44100)) {
+					pr_info("%s: Cannot set 44.1KHz on INT0\n",
+						__func__);
+				} else
+					snd_soc_update_bits(codec, int_fs_reg,
+						0x0F, int_prim_fs_rate_reg_val);
+			}
+			int_mux_cfg0 += 2;
+		}
+	}
+
+	return 0;
+}
+
+
+static int tasha_set_interpolator_rate(struct snd_soc_dai *dai,
+				       u32 sample_rate)
+{
+	int rate_val = 0;
+	int i, ret;
+
+	/* set mixing path rate */
+	for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) {
+		if (sample_rate ==
+				int_mix_sample_rate_val[i].sample_rate) {
+			rate_val =
+				int_mix_sample_rate_val[i].rate_val;
+			break;
+		}
+	}
+	if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) ||
+			(rate_val < 0))
+		goto prim_rate;
+	ret = tasha_set_mix_interpolator_rate(dai,
+			(u8) rate_val, sample_rate);
+prim_rate:
+	/* set primary path sample rate */
+	for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) {
+		if (sample_rate ==
+				int_prim_sample_rate_val[i].sample_rate) {
+			rate_val =
+				int_prim_sample_rate_val[i].rate_val;
+			break;
+		}
+	}
+	if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) ||
+			(rate_val < 0))
+		return -EINVAL;
+	ret = tasha_set_prim_interpolator_rate(dai,
+			(u8) rate_val, sample_rate);
+	return ret;
+}
+
+static int tasha_prepare(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		tasha_codec_vote_max_bw(dai->codec, false);
+	return 0;
+}
+
+static int tasha_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(dai->codec);
+	int ret;
+	int tx_fs_rate = -EINVAL;
+	int rx_fs_rate = -EINVAL;
+	int i2s_bit_mode;
+	struct snd_soc_codec *codec = dai->codec;
+
+	pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
+		 dai->name, dai->id, params_rate(params),
+		 params_channels(params));
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = tasha_set_interpolator_rate(dai, params_rate(params));
+		if (ret) {
+			pr_err("%s: cannot set sample rate: %u\n",
+				__func__, params_rate(params));
+			return ret;
+		}
+		switch (params_width(params)) {
+		case 16:
+			tasha->dai[dai->id].bit_width = 16;
+			i2s_bit_mode = 0x01;
+			break;
+		case 24:
+			tasha->dai[dai->id].bit_width = 24;
+			i2s_bit_mode = 0x00;
+			break;
+		default:
+			return -EINVAL;
+		}
+		tasha->dai[dai->id].rate = params_rate(params);
+		if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			switch (params_rate(params)) {
+			case 8000:
+				rx_fs_rate = 0;
+				break;
+			case 16000:
+				rx_fs_rate = 1;
+				break;
+			case 32000:
+				rx_fs_rate = 2;
+				break;
+			case 48000:
+				rx_fs_rate = 3;
+				break;
+			case 96000:
+				rx_fs_rate = 4;
+				break;
+			case 192000:
+				rx_fs_rate = 5;
+				break;
+			default:
+				dev_err(tasha->dev,
+				"%s: Invalid RX sample rate: %d\n",
+				__func__, params_rate(params));
+				return -EINVAL;
+			};
+			snd_soc_update_bits(codec,
+					WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+					0x20, i2s_bit_mode << 5);
+			snd_soc_update_bits(codec,
+					WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+					0x1c, (rx_fs_rate << 2));
+		}
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		switch (params_rate(params)) {
+		case 8000:
+			tx_fs_rate = 0;
+			break;
+		case 16000:
+			tx_fs_rate = 1;
+			break;
+		case 32000:
+			tx_fs_rate = 3;
+			break;
+		case 48000:
+			tx_fs_rate = 4;
+			break;
+		case 96000:
+			tx_fs_rate = 5;
+			break;
+		case 192000:
+			tx_fs_rate = 6;
+			break;
+		case 384000:
+			tx_fs_rate = 7;
+			break;
+		default:
+			dev_err(tasha->dev, "%s: Invalid TX sample rate: %d\n",
+				__func__, params_rate(params));
+			return -EINVAL;
+
+		};
+		if (dai->id != AIF4_VIFEED &&
+		    dai->id != AIF4_MAD_TX) {
+			ret = tasha_set_decimator_rate(dai, tx_fs_rate,
+					params_rate(params));
+			if (ret < 0) {
+				dev_err(tasha->dev, "%s: cannot set TX Decimator rate: %d\n",
+					__func__, tx_fs_rate);
+				return ret;
+			}
+		}
+		tasha->dai[dai->id].rate = params_rate(params);
+		switch (params_width(params)) {
+		case 16:
+			tasha->dai[dai->id].bit_width = 16;
+			i2s_bit_mode = 0x01;
+			break;
+		case 24:
+			tasha->dai[dai->id].bit_width = 24;
+			i2s_bit_mode = 0x00;
+			break;
+		case 32:
+			tasha->dai[dai->id].bit_width = 32;
+			i2s_bit_mode = 0x00;
+			break;
+		default:
+			dev_err(tasha->dev, "%s: Invalid format 0x%x\n",
+				__func__, params_width(params));
+			return -EINVAL;
+		};
+		if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,
+				0x20, i2s_bit_mode << 5);
+			if (tx_fs_rate > 1)
+				tx_fs_rate--;
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,
+				0x1c, tx_fs_rate << 2);
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG,
+				0x05, 0x05);
+
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG,
+				0x05, 0x05);
+
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG,
+				0x05, 0x05);
+
+			snd_soc_update_bits(codec,
+				WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG,
+				0x05, 0x05);
+		}
+		break;
+	default:
+		pr_err("%s: Invalid stream type %d\n", __func__,
+			substream->stream);
+		return -EINVAL;
+	};
+	if (dai->id == AIF4_VIFEED)
+		tasha->dai[dai->id].bit_width = 32;
+
+	return 0;
+}
+
+static int tasha_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(dai->codec);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* CPU is master */
+		if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(dai->codec,
+					WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,
+					0x2, 0);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(dai->codec,
+					WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+					0x2, 0);
+		}
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* CPU is slave */
+		if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(dai->codec,
+					WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,
+					0x2, 0x2);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(dai->codec,
+					WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+					0x2, 0x2);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int tasha_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static struct snd_soc_dai_ops tasha_dai_ops = {
+	.startup = tasha_startup,
+	.shutdown = tasha_shutdown,
+	.hw_params = tasha_hw_params,
+	.prepare = tasha_prepare,
+	.set_sysclk = tasha_set_dai_sysclk,
+	.set_fmt = tasha_set_dai_fmt,
+	.set_channel_map = tasha_set_channel_map,
+	.get_channel_map = tasha_get_channel_map,
+};
+
+static struct snd_soc_dai_driver tasha_dai[] = {
+	{
+		.name = "tasha_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_rx2",
+		.id = AIF2_PB,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_tx2",
+		.id = AIF2_CAP,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_rx3",
+		.id = AIF3_PB,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_tx3",
+		.id = AIF3_CAP,
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_rx4",
+		.id = AIF4_PB,
+		.playback = {
+			.stream_name = "AIF4 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_mix_rx1",
+		.id = AIF_MIX1_PB,
+		.playback = {
+			.stream_name = "AIF Mix Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 8,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_mad1",
+		.id = AIF4_MAD_TX,
+		.capture = {
+			.stream_name = "AIF4 MAD TX",
+			.rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 |
+				 SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000,
+			.formats = TASHA_FORMATS_S16_S24_S32_LE,
+			.rate_min = 16000,
+			.rate_max = 384000,
+			.channels_min = 1,
+			.channels_max = 1,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_vifeedback",
+		.id = AIF4_VIFEED,
+		.capture = {
+			.stream_name = "VIfeed",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+			.formats = TASHA_FORMATS_S16_S24_S32_LE,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		 },
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_cpe",
+		.id = AIF5_CPE_TX,
+		.capture = {
+			.stream_name = "AIF5 CPE TX",
+			.rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000,
+			.formats = TASHA_FORMATS_S16_S24_S32_LE,
+			.rate_min = 16000,
+			.rate_max = 48000,
+			.channels_min = 1,
+			.channels_max = 1,
+		},
+	},
+};
+
+static struct snd_soc_dai_driver tasha_i2s_dai[] = {
+	{
+		.name = "tasha_i2s_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9335_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_i2s_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_i2s_rx2",
+		.id = AIF2_PB,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.rates = WCD9335_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tasha_dai_ops,
+	},
+	{
+		.name = "tasha_i2s_tx2",
+		.id = AIF2_CAP,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = TASHA_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tasha_dai_ops,
+	},
+};
+
+static void tasha_codec_power_gate_digital_core(struct tasha_priv *tasha)
+{
+	struct snd_soc_codec *codec = tasha->codec;
+
+	if (!codec)
+		return;
+
+	mutex_lock(&tasha->power_lock);
+	dev_dbg(codec->dev, "%s: Entering power gating function, %d\n",
+		__func__, tasha->power_active_ref);
+
+	if (tasha->power_active_ref > 0)
+		goto exit;
+
+	wcd9xxx_set_power_state(tasha->wcd9xxx,
+			WCD_REGION_POWER_COLLAPSE_BEGIN,
+			WCD9XXX_DIG_CORE_REGION_1);
+	snd_soc_update_bits(codec, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			0x04, 0x04);
+	snd_soc_update_bits(codec, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			0x01, 0x00);
+	snd_soc_update_bits(codec, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			0x02, 0x00);
+	clear_bit(AUDIO_NOMINAL, &tasha->status_mask);
+	tasha_codec_update_sido_voltage(tasha, sido_buck_svs_voltage);
+	wcd9xxx_set_power_state(tasha->wcd9xxx, WCD_REGION_POWER_DOWN,
+				WCD9XXX_DIG_CORE_REGION_1);
+exit:
+	dev_dbg(codec->dev, "%s: Exiting power gating function, %d\n",
+		__func__, tasha->power_active_ref);
+	mutex_unlock(&tasha->power_lock);
+}
+
+static void tasha_codec_power_gate_work(struct work_struct *work)
+{
+	struct tasha_priv *tasha;
+	struct delayed_work *dwork;
+	struct snd_soc_codec *codec;
+
+	dwork = to_delayed_work(work);
+	tasha = container_of(dwork, struct tasha_priv, power_gate_work);
+	codec = tasha->codec;
+
+	if (!codec)
+		return;
+
+	tasha_codec_power_gate_digital_core(tasha);
+}
+
+/* called under power_lock acquisition */
+static int tasha_dig_core_remove_power_collapse(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	tasha_codec_vote_max_bw(codec, true);
+	snd_soc_write(codec, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
+	snd_soc_write(codec, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
+	snd_soc_write(codec, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+	snd_soc_update_bits(codec, WCD9335_CODEC_RPM_RST_CTL, 0x02, 0x00);
+	snd_soc_update_bits(codec, WCD9335_CODEC_RPM_RST_CTL, 0x02, 0x02);
+
+	wcd9xxx_set_power_state(tasha->wcd9xxx,
+			WCD_REGION_POWER_COLLAPSE_REMOVE,
+			WCD9XXX_DIG_CORE_REGION_1);
+	regcache_mark_dirty(codec->component.regmap);
+	regcache_sync_region(codec->component.regmap,
+			     TASHA_DIG_CORE_REG_MIN, TASHA_DIG_CORE_REG_MAX);
+	tasha_codec_vote_max_bw(codec, false);
+
+	return 0;
+}
+
+static int tasha_dig_core_power_collapse(struct tasha_priv *tasha,
+					 int req_state)
+{
+	struct snd_soc_codec *codec;
+	int cur_state;
+
+	/* Exit if feature is disabled */
+	if (!dig_core_collapse_enable)
+		return 0;
+
+	mutex_lock(&tasha->power_lock);
+	if (req_state == POWER_COLLAPSE)
+		tasha->power_active_ref--;
+	else if (req_state == POWER_RESUME)
+		tasha->power_active_ref++;
+	else
+		goto unlock_mutex;
+
+	if (tasha->power_active_ref < 0) {
+		dev_dbg(tasha->dev, "%s: power_active_ref is negative\n",
+			__func__);
+		goto unlock_mutex;
+	}
+
+	codec = tasha->codec;
+	if (!codec)
+		goto unlock_mutex;
+
+	if (req_state == POWER_COLLAPSE) {
+		if (tasha->power_active_ref == 0) {
+			schedule_delayed_work(&tasha->power_gate_work,
+			msecs_to_jiffies(dig_core_collapse_timer * 1000));
+		}
+	} else if (req_state == POWER_RESUME) {
+		if (tasha->power_active_ref == 1) {
+			/*
+			 * At this point, there can be two cases:
+			 * 1. Core already in power collapse state
+			 * 2. Timer kicked in and still did not expire or
+			 * waiting for the power_lock
+			 */
+			cur_state = wcd9xxx_get_current_power_state(
+						tasha->wcd9xxx,
+						WCD9XXX_DIG_CORE_REGION_1);
+			if (cur_state == WCD_REGION_POWER_DOWN)
+				tasha_dig_core_remove_power_collapse(codec);
+			else {
+				mutex_unlock(&tasha->power_lock);
+				cancel_delayed_work_sync(
+						&tasha->power_gate_work);
+				mutex_lock(&tasha->power_lock);
+			}
+		}
+	}
+
+unlock_mutex:
+	mutex_unlock(&tasha->power_lock);
+
+	return 0;
+}
+
+static int __tasha_cdc_mclk_enable_locked(struct tasha_priv *tasha,
+					  bool enable)
+{
+	int ret = 0;
+
+	if (!tasha->wcd_ext_clk) {
+		dev_err(tasha->dev, "%s: wcd ext clock is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(tasha->dev, "%s: mclk_enable = %u\n", __func__, enable);
+
+	if (enable) {
+		tasha_dig_core_power_collapse(tasha, POWER_RESUME);
+		ret = tasha_cdc_req_mclk_enable(tasha, true);
+		if (ret)
+			goto err;
+
+		set_bit(AUDIO_NOMINAL, &tasha->status_mask);
+		tasha_codec_apply_sido_voltage(tasha,
+				SIDO_VOLTAGE_NOMINAL_MV);
+	} else {
+		if (!dig_core_collapse_enable) {
+			clear_bit(AUDIO_NOMINAL, &tasha->status_mask);
+			tasha_codec_update_sido_voltage(tasha,
+						sido_buck_svs_voltage);
+		}
+		tasha_cdc_req_mclk_enable(tasha, false);
+		tasha_dig_core_power_collapse(tasha, POWER_COLLAPSE);
+	}
+
+err:
+	return ret;
+}
+
+static int __tasha_cdc_mclk_enable(struct tasha_priv *tasha,
+				   bool enable)
+{
+	int ret;
+
+	WCD9XXX_V2_BG_CLK_LOCK(tasha->resmgr);
+	ret = __tasha_cdc_mclk_enable_locked(tasha, enable);
+	WCD9XXX_V2_BG_CLK_UNLOCK(tasha->resmgr);
+
+	return ret;
+}
+
+int tasha_cdc_mclk_enable(struct snd_soc_codec *codec, int enable, bool dapm)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	return __tasha_cdc_mclk_enable(tasha, enable);
+}
+EXPORT_SYMBOL(tasha_cdc_mclk_enable);
+
+int tasha_cdc_mclk_tx_enable(struct snd_soc_codec *codec, int enable, bool dapm)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(tasha->dev, "%s: clk_mode: %d, enable: %d, clk_internal: %d\n",
+		__func__, tasha->clk_mode, enable, tasha->clk_internal);
+	if (tasha->clk_mode || tasha->clk_internal) {
+		if (enable) {
+			tasha_cdc_sido_ccl_enable(tasha, true);
+			wcd_resmgr_enable_master_bias(tasha->resmgr);
+			tasha_dig_core_power_collapse(tasha, POWER_RESUME);
+			snd_soc_update_bits(codec,
+					WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x01, 0x01);
+			snd_soc_update_bits(codec,
+					WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x01, 0x01);
+			set_bit(CPE_NOMINAL, &tasha->status_mask);
+			tasha_codec_update_sido_voltage(tasha,
+						SIDO_VOLTAGE_NOMINAL_MV);
+			tasha->clk_internal = true;
+		} else {
+			tasha->clk_internal = false;
+			clear_bit(CPE_NOMINAL, &tasha->status_mask);
+			tasha_codec_update_sido_voltage(tasha,
+						sido_buck_svs_voltage);
+			tasha_dig_core_power_collapse(tasha, POWER_COLLAPSE);
+			wcd_resmgr_disable_master_bias(tasha->resmgr);
+			tasha_cdc_sido_ccl_enable(tasha, false);
+		}
+	} else {
+		ret = __tasha_cdc_mclk_enable(tasha, enable);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(tasha_cdc_mclk_tx_enable);
+
+static ssize_t tasha_codec_version_read(struct snd_info_entry *entry,
+			       void *file_private_data, struct file *file,
+			       char __user *buf, size_t count, loff_t pos)
+{
+	struct tasha_priv *tasha;
+	struct wcd9xxx *wcd9xxx;
+	char buffer[TASHA_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	tasha = (struct tasha_priv *) entry->private_data;
+	if (!tasha) {
+		pr_err("%s: tasha priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd9xxx = tasha->wcd9xxx;
+
+	if (wcd9xxx->codec_type->id_major == TASHA_MAJOR) {
+		if (TASHA_IS_1_0(wcd9xxx))
+			len = snprintf(buffer, sizeof(buffer), "WCD9335_1_0\n");
+		else if (TASHA_IS_1_1(wcd9xxx))
+			len = snprintf(buffer, sizeof(buffer), "WCD9335_1_1\n");
+		else
+			snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	} else if (wcd9xxx->codec_type->id_major == TASHA2P0_MAJOR) {
+		len = snprintf(buffer, sizeof(buffer), "WCD9335_2_0\n");
+	} else
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops tasha_codec_info_ops = {
+	.read = tasha_codec_version_read,
+};
+
+/*
+ * tasha_codec_info_create_codec_entry - creates wcd9335 module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates wcd9335 module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int tasha_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct tasha_priv *tasha;
+	struct snd_soc_card *card;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	tasha = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	tasha->entry = snd_info_create_subdir(codec_root->module,
+					      "tasha", codec_root);
+	if (!tasha->entry) {
+		dev_dbg(codec->dev, "%s: failed to create wcd9335 entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   tasha->entry);
+	if (!version_entry) {
+		dev_dbg(codec->dev, "%s: failed to create wcd9335 version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = tasha;
+	version_entry->size = TASHA_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &tasha_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	tasha->version_entry = version_entry;
+
+	return 0;
+}
+EXPORT_SYMBOL(tasha_codec_info_create_codec_entry);
+
+static int __tasha_codec_internal_rco_ctrl(
+	struct snd_soc_codec *codec, bool enable)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	if (enable) {
+		tasha_cdc_sido_ccl_enable(tasha, true);
+		if (wcd_resmgr_get_clk_type(tasha->resmgr) ==
+		    WCD_CLK_RCO) {
+			ret = wcd_resmgr_enable_clk_block(tasha->resmgr,
+							  WCD_CLK_RCO);
+		} else {
+			ret = tasha_cdc_req_mclk_enable(tasha, true);
+			ret |= wcd_resmgr_enable_clk_block(tasha->resmgr,
+							   WCD_CLK_RCO);
+			ret |= tasha_cdc_req_mclk_enable(tasha, false);
+		}
+
+	} else {
+		ret = wcd_resmgr_disable_clk_block(tasha->resmgr,
+						   WCD_CLK_RCO);
+		tasha_cdc_sido_ccl_enable(tasha, false);
+	}
+
+	if (ret) {
+		dev_err(codec->dev, "%s: Error in %s RCO\n",
+			__func__, (enable ? "enabling" : "disabling"));
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * tasha_codec_internal_rco_ctrl()
+ * Make sure that the caller does not acquire
+ * BG_CLK_LOCK.
+ */
+static int tasha_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
+				  bool enable)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	WCD9XXX_V2_BG_CLK_LOCK(tasha->resmgr);
+	ret = __tasha_codec_internal_rco_ctrl(codec, enable);
+	WCD9XXX_V2_BG_CLK_UNLOCK(tasha->resmgr);
+	return ret;
+}
+
+/*
+ * tasha_mbhc_hs_detect: starts mbhc insertion/removal functionality
+ * @codec: handle to snd_soc_codec *
+ * @mbhc_cfg: handle to mbhc configuration structure
+ * return 0 if mbhc_start is success or error code in case of failure
+ */
+int tasha_mbhc_hs_detect(struct snd_soc_codec *codec,
+			 struct wcd_mbhc_config *mbhc_cfg)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	return wcd_mbhc_start(&tasha->mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(tasha_mbhc_hs_detect);
+
+/*
+ * tasha_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality
+ * @codec: handle to snd_soc_codec *
+ */
+void tasha_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	wcd_mbhc_stop(&tasha->mbhc);
+}
+EXPORT_SYMBOL(tasha_mbhc_hs_detect_exit);
+
+static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv)
+{
+	/* min micbias voltage is 1V and maximum is 2.85V */
+	if (micb_mv < 1000 || micb_mv > 2850) {
+		pr_err("%s: unsupported micbias voltage\n", __func__);
+		return -EINVAL;
+	}
+
+	return (micb_mv - 1000) / 50;
+}
+
+static const struct tasha_reg_mask_val tasha_reg_update_reset_val_1_1[] = {
+	{WCD9335_RCO_CTRL_2, 0xFF, 0x47},
+	{WCD9335_FLYBACK_VNEG_DAC_CTRL_4, 0xFF, 0x60},
+};
+
+static const struct tasha_reg_mask_val tasha_codec_reg_init_val_1_1[] = {
+	{WCD9335_FLYBACK_VNEG_DAC_CTRL_1, 0xFF, 0x65},
+	{WCD9335_FLYBACK_VNEG_DAC_CTRL_2, 0xFF, 0x52},
+	{WCD9335_FLYBACK_VNEG_DAC_CTRL_3, 0xFF, 0xAF},
+	{WCD9335_FLYBACK_VNEG_DAC_CTRL_4, 0xFF, 0x60},
+	{WCD9335_FLYBACK_VNEG_CTRL_3, 0xFF, 0xF4},
+	{WCD9335_FLYBACK_VNEG_CTRL_9, 0xFF, 0x40},
+	{WCD9335_FLYBACK_VNEG_CTRL_2, 0xFF, 0x4F},
+	{WCD9335_FLYBACK_EN, 0xFF, 0x6E},
+	{WCD9335_CDC_RX2_RX_PATH_SEC0, 0xF8, 0xF8},
+	{WCD9335_CDC_RX1_RX_PATH_SEC0, 0xF8, 0xF8},
+};
+
+static const struct tasha_reg_mask_val tasha_codec_reg_init_val_1_0[] = {
+	{WCD9335_FLYBACK_VNEG_CTRL_3, 0xFF, 0x54},
+	{WCD9335_CDC_RX2_RX_PATH_SEC0, 0xFC, 0xFC},
+	{WCD9335_CDC_RX1_RX_PATH_SEC0, 0xFC, 0xFC},
+};
+
+static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = {
+	{WCD9335_RCO_CTRL_2, 0x0F, 0x08},
+	{WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10},
+	{WCD9335_FLYBACK_CTRL_1, 0x20, 0x20},
+	{WCD9335_HPH_OCP_CTL, 0xFF, 0x7A},
+	{WCD9335_HPH_L_TEST, 0x01, 0x01},
+	{WCD9335_HPH_R_TEST, 0x01, 0x01},
+	{WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+	{WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+	{WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18},
+	{WCD9335_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+	{WCD9335_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+	{WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18},
+	{WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45},
+	{WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4},
+	{WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08},
+	{WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02},
+	{WCD9335_DIFF_LO_CORE_OUT_PROG, 0xFC, 0xA0},
+	{WCD9335_SE_LO_COM1, 0xFF, 0xC0},
+	{WCD9335_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4},
+	{WCD9335_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4},
+	{WCD9335_CDC_RX5_RX_PATH_SEC0, 0xFC, 0xF8},
+	{WCD9335_CDC_RX6_RX_PATH_SEC0, 0xFC, 0xF8},
+};
+
+static const struct tasha_reg_mask_val tasha_codec_reg_defaults[] = {
+	{WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x00},
+	{WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x01},
+	{WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x04, 0x04},
+};
+
+static const struct tasha_reg_mask_val tasha_codec_reg_i2c_defaults[] = {
+	{WCD9335_ANA_CLK_TOP, 0x20, 0x20},
+	{WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x01},
+	{WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x00},
+	{WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x05, 0x05},
+	{WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG, 0x01, 0x01},
+	{WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG, 0x01, 0x01},
+	{WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG, 0x01, 0x01},
+	{WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG, 0x01, 0x01},
+	{WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG, 0x05, 0x05},
+	{WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG, 0x05, 0x05},
+	{WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG, 0x05, 0x05},
+	{WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG, 0x05, 0x05},
+};
+
+static const struct tasha_reg_mask_val tasha_codec_reg_init_common_val[] = {
+	/* Rbuckfly/R_EAR(32) */
+	{WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00},
+	{WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60},
+	{WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00},
+	{WCD9335_CDC_BOOST0_BOOST_CTL, 0x70, 0x50},
+	{WCD9335_CDC_BOOST1_BOOST_CTL, 0x70, 0x50},
+	{WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD9335_ANA_LO_1_2, 0x3C, 0X3C},
+	{WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00},
+	{WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03},
+	{WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02},
+	{WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01},
+	{WCD9335_EAR_CMBUFF, 0x08, 0x00},
+	{WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+	{WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+	{WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+	{WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+	{WCD9335_CDC_RX0_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX1_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX2_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX3_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX4_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX5_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX6_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX7_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX8_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08},
+};
+
+static const struct tasha_reg_mask_val tasha_codec_reg_init_1_x_val[] = {
+	/* Enable TX HPF Filter & Linear Phase */
+	{WCD9335_CDC_TX0_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX1_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX2_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX3_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX4_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX5_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX6_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX7_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_TX8_TX_PATH_CFG0, 0x11, 0x11},
+	{WCD9335_CDC_RX0_RX_PATH_SEC0, 0xF8, 0xF8},
+	{WCD9335_CDC_RX0_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX1_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX2_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX3_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX4_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX5_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX6_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX7_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX8_RX_PATH_SEC1, 0x08, 0x08},
+	{WCD9335_CDC_RX0_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX1_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX2_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX3_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX4_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX5_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX6_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x08, 0x08},
+	{WCD9335_CDC_TX0_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX1_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX2_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX3_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX4_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX5_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX6_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX7_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_TX8_TX_PATH_SEC2, 0x01, 0x01},
+	{WCD9335_CDC_RX3_RX_PATH_SEC0, 0xF8, 0xF0},
+	{WCD9335_CDC_RX4_RX_PATH_SEC0, 0xF8, 0xF0},
+	{WCD9335_CDC_RX5_RX_PATH_SEC0, 0xF8, 0xF8},
+	{WCD9335_CDC_RX6_RX_PATH_SEC0, 0xF8, 0xF8},
+	{WCD9335_RX_OCP_COUNT, 0xFF, 0xFF},
+	{WCD9335_HPH_OCP_CTL, 0xF0, 0x70},
+	{WCD9335_CPE_SS_CPAR_CFG, 0xFF, 0x00},
+	{WCD9335_FLYBACK_VNEG_CTRL_1, 0xFF, 0x63},
+	{WCD9335_FLYBACK_VNEG_CTRL_4, 0xFF, 0x7F},
+	{WCD9335_CLASSH_CTRL_VCL_1, 0xFF, 0x60},
+	{WCD9335_CLASSH_CTRL_CCL_5, 0xFF, 0x40},
+	{WCD9335_RX_TIMER_DIV, 0xFF, 0x32},
+	{WCD9335_SE_LO_COM2, 0xFF, 0x01},
+	{WCD9335_MBHC_ZDET_ANA_CTL, 0x0F, 0x07},
+	{WCD9335_RX_BIAS_HPH_PA, 0xF0, 0x60},
+	{WCD9335_HPH_RDAC_LDO_CTL, 0x88, 0x88},
+	{WCD9335_HPH_L_EN, 0x20, 0x20},
+	{WCD9335_HPH_R_EN, 0x20, 0x20},
+	{WCD9335_DIFF_LO_CORE_OUT_PROG, 0xFC, 0xD8},
+	{WCD9335_CDC_RX5_RX_PATH_SEC3, 0xBD, 0xBD},
+	{WCD9335_CDC_RX6_RX_PATH_SEC3, 0xBD, 0xBD},
+	{WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40},
+};
+
+static void tasha_update_reg_reset_values(struct snd_soc_codec *codec)
+{
+	u32 i;
+	struct wcd9xxx *tasha_core = dev_get_drvdata(codec->dev->parent);
+
+	if (TASHA_IS_1_1(tasha_core)) {
+		for (i = 0; i < ARRAY_SIZE(tasha_reg_update_reset_val_1_1);
+		     i++)
+			snd_soc_write(codec,
+				      tasha_reg_update_reset_val_1_1[i].reg,
+				      tasha_reg_update_reset_val_1_1[i].val);
+	}
+}
+
+static void tasha_codec_init_reg(struct snd_soc_codec *codec)
+{
+	u32 i;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_common_val); i++)
+		snd_soc_update_bits(codec,
+				tasha_codec_reg_init_common_val[i].reg,
+				tasha_codec_reg_init_common_val[i].mask,
+				tasha_codec_reg_init_common_val[i].val);
+
+	if (TASHA_IS_1_1(wcd9xxx) ||
+	    TASHA_IS_1_0(wcd9xxx))
+		for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_1_x_val); i++)
+			snd_soc_update_bits(codec,
+					tasha_codec_reg_init_1_x_val[i].reg,
+					tasha_codec_reg_init_1_x_val[i].mask,
+					tasha_codec_reg_init_1_x_val[i].val);
+
+	if (TASHA_IS_1_1(wcd9xxx)) {
+		for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_1_1); i++)
+			snd_soc_update_bits(codec,
+					tasha_codec_reg_init_val_1_1[i].reg,
+					tasha_codec_reg_init_val_1_1[i].mask,
+					tasha_codec_reg_init_val_1_1[i].val);
+	} else if (TASHA_IS_1_0(wcd9xxx)) {
+		for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_1_0); i++)
+			snd_soc_update_bits(codec,
+					tasha_codec_reg_init_val_1_0[i].reg,
+					tasha_codec_reg_init_val_1_0[i].mask,
+					tasha_codec_reg_init_val_1_0[i].val);
+	} else if (TASHA_IS_2_0(wcd9xxx)) {
+		for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_2_0); i++)
+			snd_soc_update_bits(codec,
+					tasha_codec_reg_init_val_2_0[i].reg,
+					tasha_codec_reg_init_val_2_0[i].mask,
+					tasha_codec_reg_init_val_2_0[i].val);
+	}
+}
+
+static void tasha_update_reg_defaults(struct tasha_priv *tasha)
+{
+	u32 i;
+	struct wcd9xxx *wcd9xxx;
+
+	wcd9xxx = tasha->wcd9xxx;
+	for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_defaults); i++)
+		regmap_update_bits(wcd9xxx->regmap,
+				   tasha_codec_reg_defaults[i].reg,
+				   tasha_codec_reg_defaults[i].mask,
+				   tasha_codec_reg_defaults[i].val);
+
+	tasha->intf_type = wcd9xxx_get_intf_type();
+	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+		for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_i2c_defaults); i++)
+			regmap_update_bits(wcd9xxx->regmap,
+					   tasha_codec_reg_i2c_defaults[i].reg,
+					   tasha_codec_reg_i2c_defaults[i].mask,
+					   tasha_codec_reg_i2c_defaults[i].val);
+
+}
+
+static void tasha_slim_interface_init_reg(struct snd_soc_codec *codec)
+{
+	int i;
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+		wcd9xxx_interface_reg_write(priv->wcd9xxx,
+					    TASHA_SLIM_PGD_PORT_INT_EN0 + i,
+					    0xFF);
+}
+
+static irqreturn_t tasha_slimbus_irq(int irq, void *data)
+{
+	struct tasha_priv *priv = data;
+	unsigned long status = 0;
+	int i, j, port_id, k;
+	u32 bit;
+	u8 val, int_val = 0;
+	bool tx, cleared;
+	unsigned short reg = 0;
+
+	for (i = TASHA_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+	     i <= TASHA_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
+		val = wcd9xxx_interface_reg_read(priv->wcd9xxx, i);
+		status |= ((u32)val << (8 * j));
+	}
+
+	for_each_set_bit(j, &status, 32) {
+		tx = (j >= 16 ? true : false);
+		port_id = (tx ? j - 16 : j);
+		val = wcd9xxx_interface_reg_read(priv->wcd9xxx,
+				TASHA_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
+		if (val) {
+			if (!tx)
+				reg = TASHA_SLIM_PGD_PORT_INT_EN0 +
+					(port_id / 8);
+			else
+				reg = TASHA_SLIM_PGD_PORT_INT_TX_EN0 +
+					(port_id / 8);
+			int_val = wcd9xxx_interface_reg_read(
+				priv->wcd9xxx, reg);
+			/*
+			 * Ignore interrupts for ports for which the
+			 * interrupts are not specifically enabled.
+			 */
+			if (!(int_val & (1 << (port_id % 8))))
+				continue;
+		}
+		if (val & TASHA_SLIM_IRQ_OVERFLOW)
+			pr_err_ratelimited(
+			   "%s: overflow error on %s port %d, value %x\n",
+			   __func__, (tx ? "TX" : "RX"), port_id, val);
+		if (val & TASHA_SLIM_IRQ_UNDERFLOW)
+			pr_err_ratelimited(
+			   "%s: underflow error on %s port %d, value %x\n",
+			   __func__, (tx ? "TX" : "RX"), port_id, val);
+		if ((val & TASHA_SLIM_IRQ_OVERFLOW) ||
+			(val & TASHA_SLIM_IRQ_UNDERFLOW)) {
+			if (!tx)
+				reg = TASHA_SLIM_PGD_PORT_INT_EN0 +
+					(port_id / 8);
+			else
+				reg = TASHA_SLIM_PGD_PORT_INT_TX_EN0 +
+					(port_id / 8);
+			int_val = wcd9xxx_interface_reg_read(
+				priv->wcd9xxx, reg);
+			if (int_val & (1 << (port_id % 8))) {
+				int_val = int_val ^ (1 << (port_id % 8));
+				wcd9xxx_interface_reg_write(priv->wcd9xxx,
+					reg, int_val);
+			}
+		}
+		if (val & TASHA_SLIM_IRQ_PORT_CLOSED) {
+			/*
+			 * INT SOURCE register starts from RX to TX
+			 * but port number in the ch_mask is in opposite way
+			 */
+			bit = (tx ? j - 16 : j + 16);
+			pr_debug("%s: %s port %d closed value %x, bit %u\n",
+				 __func__, (tx ? "TX" : "RX"), port_id, val,
+				 bit);
+			for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
+				pr_debug("%s: priv->dai[%d].ch_mask = 0x%lx\n",
+					 __func__, k, priv->dai[k].ch_mask);
+				if (test_and_clear_bit(bit,
+						       &priv->dai[k].ch_mask)) {
+					cleared = true;
+					if (!priv->dai[k].ch_mask)
+						wake_up(&priv->dai[k].dai_wait);
+					/*
+					 * There are cases when multiple DAIs
+					 * might be using the same slimbus
+					 * channel. Hence don't break here.
+					 */
+				}
+			}
+			WARN(!cleared,
+			     "Couldn't find slimbus %s port %d for closing\n",
+			     (tx ? "TX" : "RX"), port_id);
+		}
+		wcd9xxx_interface_reg_write(priv->wcd9xxx,
+					    TASHA_SLIM_PGD_PORT_INT_CLR_RX_0 +
+					    (j / 8),
+					    1 << (j % 8));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int tasha_setup_irqs(struct tasha_priv *tasha)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = tasha->codec;
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
+				  tasha_slimbus_irq, "SLIMBUS Slave", tasha);
+	if (ret)
+		pr_err("%s: Failed to request irq %d\n", __func__,
+		       WCD9XXX_IRQ_SLIMBUS);
+	else
+		tasha_slim_interface_init_reg(codec);
+
+	return ret;
+}
+
+static void tasha_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct afe_param_cdc_slimbus_slave_cfg *cfg;
+	struct wcd9xxx *wcd9xxx = priv->wcd9xxx;
+	uint64_t eaddr = 0;
+
+	cfg = &priv->slimbus_slave_cfg;
+	cfg->minor_version = 1;
+	cfg->tx_slave_port_offset = 0;
+	cfg->rx_slave_port_offset = 16;
+
+	memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+	WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+	cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+	cfg->device_enum_addr_msw = eaddr >> 32;
+
+	dev_dbg(codec->dev, "%s: slimbus logical address 0x%llx\n",
+		__func__, eaddr);
+}
+
+static void tasha_cleanup_irqs(struct tasha_priv *tasha)
+{
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tasha);
+}
+
+static int tasha_handle_pdata(struct tasha_priv *tasha,
+			      struct wcd9xxx_pdata *pdata)
+{
+	struct snd_soc_codec *codec = tasha->codec;
+	u8 dmic_ctl_val, mad_dmic_ctl_val;
+	u8 anc_ctl_value;
+	u32 def_dmic_rate, dmic_clk_drv;
+	int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
+	int rc = 0;
+
+	if (!pdata) {
+		dev_err(codec->dev, "%s: NULL pdata\n", __func__);
+		return -ENODEV;
+	}
+
+	/* set micbias voltage */
+	vout_ctl_1 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb1_mv);
+	vout_ctl_2 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb2_mv);
+	vout_ctl_3 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb3_mv);
+	vout_ctl_4 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb4_mv);
+	if (vout_ctl_1 < 0 || vout_ctl_2 < 0 ||
+	    vout_ctl_3 < 0 || vout_ctl_4 < 0) {
+		rc = -EINVAL;
+		goto done;
+	}
+	snd_soc_update_bits(codec, WCD9335_ANA_MICB1, 0x3F, vout_ctl_1);
+	snd_soc_update_bits(codec, WCD9335_ANA_MICB2, 0x3F, vout_ctl_2);
+	snd_soc_update_bits(codec, WCD9335_ANA_MICB3, 0x3F, vout_ctl_3);
+	snd_soc_update_bits(codec, WCD9335_ANA_MICB4, 0x3F, vout_ctl_4);
+
+	/* Set the DMIC sample rate */
+	switch (pdata->mclk_rate) {
+	case TASHA_MCLK_CLK_9P6MHZ:
+		def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
+		break;
+	case TASHA_MCLK_CLK_12P288MHZ:
+		def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ;
+		break;
+	default:
+		/* should never happen */
+		dev_err(codec->dev, "%s: Invalid mclk_rate %d\n",
+			__func__, pdata->mclk_rate);
+		rc = -EINVAL;
+		goto done;
+	};
+
+	if (pdata->dmic_sample_rate ==
+	    WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) {
+		dev_info(codec->dev, "%s: dmic_rate invalid default = %d\n",
+			__func__, def_dmic_rate);
+		pdata->dmic_sample_rate = def_dmic_rate;
+	}
+	if (pdata->mad_dmic_sample_rate ==
+	    WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) {
+		dev_info(codec->dev, "%s: mad_dmic_rate invalid default = %d\n",
+			__func__, def_dmic_rate);
+		/*
+		 * use dmic_sample_rate as the default for MAD
+		 * if mad dmic sample rate is undefined
+		 */
+		pdata->mad_dmic_sample_rate = pdata->dmic_sample_rate;
+	}
+	if (pdata->ecpp_dmic_sample_rate ==
+	    WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) {
+		dev_info(codec->dev,
+			 "%s: ecpp_dmic_rate invalid default = %d\n",
+			 __func__, def_dmic_rate);
+		/*
+		 * use dmic_sample_rate as the default for ECPP DMIC
+		 * if ecpp dmic sample rate is undefined
+		 */
+		pdata->ecpp_dmic_sample_rate = pdata->dmic_sample_rate;
+	}
+
+	if (pdata->dmic_clk_drv ==
+	    WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED) {
+		pdata->dmic_clk_drv = WCD9335_DMIC_CLK_DRIVE_DEFAULT;
+		dev_info(codec->dev,
+			 "%s: dmic_clk_strength invalid, default = %d\n",
+			 __func__, pdata->dmic_clk_drv);
+	}
+
+	switch (pdata->dmic_clk_drv) {
+	case 2:
+		dmic_clk_drv = 0;
+		break;
+	case 4:
+		dmic_clk_drv = 1;
+		break;
+	case 8:
+		dmic_clk_drv = 2;
+		break;
+	case 16:
+		dmic_clk_drv = 3;
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: invalid dmic_clk_drv %d, using default\n",
+			__func__, pdata->dmic_clk_drv);
+		dmic_clk_drv = 0;
+		break;
+	}
+
+	snd_soc_update_bits(codec, WCD9335_TEST_DEBUG_PAD_DRVCTL,
+			    0x0C, dmic_clk_drv << 2);
+
+	/*
+	 * Default the DMIC clk rates to mad_dmic_sample_rate,
+	 * whereas, the anc/txfe dmic rates to dmic_sample_rate
+	 * since the anc/txfe are independent of mad block.
+	 */
+	mad_dmic_ctl_val = tasha_get_dmic_clk_val(tasha->codec,
+				pdata->mclk_rate,
+				pdata->mad_dmic_sample_rate);
+	snd_soc_update_bits(codec, WCD9335_CPE_SS_DMIC0_CTL,
+		0x0E, mad_dmic_ctl_val << 1);
+	snd_soc_update_bits(codec, WCD9335_CPE_SS_DMIC1_CTL,
+		0x0E, mad_dmic_ctl_val << 1);
+	snd_soc_update_bits(codec, WCD9335_CPE_SS_DMIC2_CTL,
+		0x0E, mad_dmic_ctl_val << 1);
+
+	dmic_ctl_val = tasha_get_dmic_clk_val(tasha->codec,
+				pdata->mclk_rate,
+				pdata->dmic_sample_rate);
+
+	if (dmic_ctl_val == WCD9335_DMIC_CLK_DIV_2)
+		anc_ctl_value = WCD9335_ANC_DMIC_X2_FULL_RATE;
+	else
+		anc_ctl_value = WCD9335_ANC_DMIC_X2_HALF_RATE;
+
+	snd_soc_update_bits(codec, WCD9335_CDC_ANC0_MODE_2_CTL,
+			    0x40, anc_ctl_value << 6);
+	snd_soc_update_bits(codec, WCD9335_CDC_ANC0_MODE_2_CTL,
+			    0x20, anc_ctl_value << 5);
+	snd_soc_update_bits(codec, WCD9335_CDC_ANC1_MODE_2_CTL,
+			    0x40, anc_ctl_value << 6);
+	snd_soc_update_bits(codec, WCD9335_CDC_ANC1_MODE_2_CTL,
+			    0x20, anc_ctl_value << 5);
+done:
+	return rc;
+}
+
+static struct wcd_cpe_core *tasha_codec_get_cpe_core(
+		struct snd_soc_codec *codec)
+{
+	struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	return priv->cpe_core;
+}
+
+static int tasha_codec_cpe_fll_update_divider(
+	struct snd_soc_codec *codec, u32 cpe_fll_rate)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	u32 div_val = 0, l_val = 0;
+	u32 computed_cpe_fll;
+
+	if (cpe_fll_rate != CPE_FLL_CLK_75MHZ &&
+	    cpe_fll_rate != CPE_FLL_CLK_150MHZ) {
+		dev_err(codec->dev,
+			"%s: Invalid CPE fll rate request %u\n",
+			__func__, cpe_fll_rate);
+		return -EINVAL;
+	}
+
+	if (wcd9xxx->mclk_rate == TASHA_MCLK_CLK_12P288MHZ) {
+		/* update divider to 10 and enable 5x divider */
+		snd_soc_write(codec, WCD9335_CPE_FLL_USER_CTL_1,
+			      0x55);
+		div_val = 10;
+	} else if (wcd9xxx->mclk_rate == TASHA_MCLK_CLK_9P6MHZ) {
+		/* update divider to 8 and enable 2x divider */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_USER_CTL_0,
+				    0x7C, 0x70);
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_USER_CTL_1,
+				    0xE0, 0x20);
+		div_val = 8;
+	} else {
+		dev_err(codec->dev,
+			"%s: Invalid MCLK rate %u\n",
+			__func__, wcd9xxx->mclk_rate);
+		return -EINVAL;
+	}
+
+	l_val = ((cpe_fll_rate / 1000) * div_val) /
+		 (wcd9xxx->mclk_rate / 1000);
+
+	/* If l_val was integer truncated, increment l_val once */
+	computed_cpe_fll = (wcd9xxx->mclk_rate / div_val) * l_val;
+	if (computed_cpe_fll < cpe_fll_rate)
+		l_val++;
+
+
+	/* update L value LSB and MSB */
+	snd_soc_write(codec, WCD9335_CPE_FLL_L_VAL_CTL_0,
+		      (l_val & 0xFF));
+	snd_soc_write(codec, WCD9335_CPE_FLL_L_VAL_CTL_1,
+		      ((l_val >> 8) & 0xFF));
+
+	tasha->current_cpe_clk_freq = cpe_fll_rate;
+	dev_dbg(codec->dev,
+		"%s: updated l_val to %u for cpe_clk %u and mclk %u\n",
+		__func__, l_val, cpe_fll_rate, wcd9xxx->mclk_rate);
+
+	return 0;
+}
+
+static int __tasha_cdc_change_cpe_clk(struct snd_soc_codec *codec,
+		u32 clk_freq)
+{
+	int ret = 0;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (!tasha_cdc_is_svs_enabled(tasha)) {
+		dev_dbg(codec->dev,
+			"%s: SVS not enabled or tasha is not 2p0, return\n",
+			__func__);
+		return 0;
+	}
+	dev_dbg(codec->dev, "%s: clk_freq = %u\n", __func__, clk_freq);
+
+	if (clk_freq == CPE_FLL_CLK_75MHZ) {
+		/* Change to SVS */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+				    0x08, 0x08);
+		if (tasha_codec_cpe_fll_update_divider(codec, clk_freq)) {
+			ret = -EINVAL;
+			goto done;
+		}
+
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+				    0x10, 0x10);
+
+		clear_bit(CPE_NOMINAL, &tasha->status_mask);
+		tasha_codec_update_sido_voltage(tasha, sido_buck_svs_voltage);
+
+	} else if (clk_freq == CPE_FLL_CLK_150MHZ) {
+		/* change to nominal */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+				    0x08, 0x08);
+
+		set_bit(CPE_NOMINAL, &tasha->status_mask);
+		tasha_codec_update_sido_voltage(tasha, SIDO_VOLTAGE_NOMINAL_MV);
+
+		if (tasha_codec_cpe_fll_update_divider(codec, clk_freq)) {
+			ret = -EINVAL;
+			goto done;
+		}
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+				    0x10, 0x10);
+	} else {
+		dev_err(codec->dev,
+			"%s: Invalid clk_freq request %d for CPE FLL\n",
+			__func__, clk_freq);
+		ret = -EINVAL;
+	}
+
+done:
+	snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+			    0x10, 0x00);
+	snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+			    0x08, 0x00);
+	return ret;
+}
+
+
+static int tasha_codec_cpe_fll_enable(struct snd_soc_codec *codec,
+				   bool enable)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u8 clk_sel_reg_val = 0x00;
+
+	dev_dbg(codec->dev, "%s: enable = %s\n",
+			__func__, enable ? "true" : "false");
+
+	if (enable) {
+		if (tasha_cdc_is_svs_enabled(tasha)) {
+			/* FLL enable is always at SVS */
+			if (__tasha_cdc_change_cpe_clk(codec,
+					CPE_FLL_CLK_75MHZ)) {
+				dev_err(codec->dev,
+					"%s: clk change to %d failed\n",
+					__func__, CPE_FLL_CLK_75MHZ);
+				return -EINVAL;
+			}
+		} else {
+			if (tasha_codec_cpe_fll_update_divider(codec,
+							CPE_FLL_CLK_75MHZ)) {
+				dev_err(codec->dev,
+					"%s: clk change to %d failed\n",
+					__func__, CPE_FLL_CLK_75MHZ);
+				return -EINVAL;
+			}
+		}
+
+		if (TASHA_IS_1_0(wcd9xxx)) {
+			tasha_cdc_mclk_enable(codec, true, false);
+			clk_sel_reg_val = 0x02;
+		}
+
+		/* Setup CPE reference clk */
+		snd_soc_update_bits(codec, WCD9335_ANA_CLK_TOP,
+				    0x02, clk_sel_reg_val);
+
+		/* enable CPE FLL reference clk */
+		snd_soc_update_bits(codec, WCD9335_ANA_CLK_TOP,
+				    0x01, 0x01);
+
+		/* program the PLL */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_USER_CTL_0,
+				    0x01, 0x01);
+
+		/* TEST clk setting */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_TEST_CTL_0,
+				    0x80, 0x80);
+		/* set FLL mode to HW controlled */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+				    0x60, 0x00);
+		snd_soc_write(codec, WCD9335_CPE_FLL_FLL_MODE, 0x80);
+	} else {
+		/* disable CPE FLL reference clk */
+		snd_soc_update_bits(codec, WCD9335_ANA_CLK_TOP,
+				    0x01, 0x00);
+		/* undo TEST clk setting */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_TEST_CTL_0,
+				    0x80, 0x00);
+		/* undo FLL mode to HW control */
+		snd_soc_write(codec, WCD9335_CPE_FLL_FLL_MODE, 0x00);
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_FLL_MODE,
+				    0x60, 0x20);
+		/* undo the PLL */
+		snd_soc_update_bits(codec, WCD9335_CPE_FLL_USER_CTL_0,
+				    0x01, 0x00);
+
+		if (TASHA_IS_1_0(wcd9xxx))
+			tasha_cdc_mclk_enable(codec, false, false);
+
+		/*
+		 * FLL could get disabled while at nominal,
+		 * scale it back to SVS
+		 */
+		if (tasha_cdc_is_svs_enabled(tasha))
+			__tasha_cdc_change_cpe_clk(codec,
+						CPE_FLL_CLK_75MHZ);
+	}
+
+	return 0;
+
+}
+
+static void tasha_cdc_query_cpe_clk_plan(void *data,
+		struct cpe_svc_cfg_clk_plan *clk_freq)
+{
+	struct snd_soc_codec *codec = data;
+	struct tasha_priv *tasha;
+	u32 cpe_clk_khz;
+
+	if (!codec) {
+		pr_err("%s: Invalid codec handle\n",
+			__func__);
+		return;
+	}
+
+	tasha = snd_soc_codec_get_drvdata(codec);
+	cpe_clk_khz = tasha->current_cpe_clk_freq / 1000;
+
+	dev_dbg(codec->dev,
+		"%s: current_clk_freq = %u\n",
+		__func__, tasha->current_cpe_clk_freq);
+
+	clk_freq->current_clk_feq = cpe_clk_khz;
+	clk_freq->num_clk_freqs = 2;
+
+	if (tasha_cdc_is_svs_enabled(tasha)) {
+		clk_freq->clk_freqs[0] = CPE_FLL_CLK_75MHZ / 1000;
+		clk_freq->clk_freqs[1] = CPE_FLL_CLK_150MHZ / 1000;
+	} else {
+		clk_freq->clk_freqs[0] = CPE_FLL_CLK_75MHZ;
+		clk_freq->clk_freqs[1] = CPE_FLL_CLK_150MHZ;
+	}
+}
+
+static void tasha_cdc_change_cpe_clk(void *data,
+		u32 clk_freq)
+{
+	struct snd_soc_codec *codec = data;
+	struct tasha_priv *tasha;
+	u32 cpe_clk_khz, req_freq = 0;
+
+	if (!codec) {
+		pr_err("%s: Invalid codec handle\n",
+			__func__);
+		return;
+	}
+
+	tasha = snd_soc_codec_get_drvdata(codec);
+	cpe_clk_khz = tasha->current_cpe_clk_freq / 1000;
+
+	if (tasha_cdc_is_svs_enabled(tasha)) {
+		if ((clk_freq * 1000) <= CPE_FLL_CLK_75MHZ)
+			req_freq = CPE_FLL_CLK_75MHZ;
+		else
+			req_freq = CPE_FLL_CLK_150MHZ;
+	}
+
+	dev_dbg(codec->dev,
+		"%s: requested clk_freq = %u, current clk_freq = %u\n",
+		__func__, clk_freq * 1000,
+		tasha->current_cpe_clk_freq);
+
+	if (tasha_cdc_is_svs_enabled(tasha)) {
+		if (__tasha_cdc_change_cpe_clk(codec, req_freq))
+			dev_err(codec->dev,
+				"%s: clock/voltage scaling failed\n",
+				__func__);
+	}
+}
+
+static int tasha_codec_slim_reserve_bw(struct snd_soc_codec *codec,
+		u32 bw_ops, bool commit)
+{
+	struct wcd9xxx *wcd9xxx;
+
+	if (!codec) {
+		pr_err("%s: Invalid handle to codec\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!wcd9xxx) {
+		dev_err(codec->dev, "%s: Invalid parent drv_data\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	return wcd9xxx_slim_reserve_bw(wcd9xxx, bw_ops, commit);
+}
+
+static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec,
+			bool vote)
+{
+	u32 bw_ops;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+
+	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+		return 0;
+
+	mutex_lock(&tasha->sb_clk_gear_lock);
+	if (vote) {
+		tasha->ref_count++;
+		if (tasha->ref_count == 1) {
+			bw_ops = SLIM_BW_CLK_GEAR_9;
+			tasha_codec_slim_reserve_bw(codec,
+				bw_ops, true);
+		}
+	} else if (!vote && tasha->ref_count > 0) {
+		tasha->ref_count--;
+		if (tasha->ref_count == 0) {
+			bw_ops = SLIM_BW_UNVOTE;
+			tasha_codec_slim_reserve_bw(codec,
+				bw_ops, true);
+		}
+	};
+
+	dev_dbg(codec->dev, "%s Value of counter after vote or un-vote is %d\n",
+		__func__, tasha->ref_count);
+
+	mutex_unlock(&tasha->sb_clk_gear_lock);
+
+	return 0;
+}
+
+static int tasha_cpe_err_irq_control(struct snd_soc_codec *codec,
+	enum cpe_err_irq_cntl_type cntl_type, u8 *status)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	u8 irq_bits;
+
+	if (TASHA_IS_2_0(tasha->wcd9xxx))
+		irq_bits = 0xFF;
+	else
+		irq_bits = 0x3F;
+
+	if (status)
+		irq_bits = (*status) & irq_bits;
+
+	switch (cntl_type) {
+	case CPE_ERR_IRQ_MASK:
+		snd_soc_update_bits(codec,
+				    WCD9335_CPE_SS_SS_ERROR_INT_MASK,
+				    irq_bits, irq_bits);
+		break;
+	case CPE_ERR_IRQ_UNMASK:
+		snd_soc_update_bits(codec,
+				    WCD9335_CPE_SS_SS_ERROR_INT_MASK,
+				    irq_bits, 0x00);
+		break;
+	case CPE_ERR_IRQ_CLEAR:
+		snd_soc_write(codec, WCD9335_CPE_SS_SS_ERROR_INT_CLEAR,
+			      irq_bits);
+		break;
+	case CPE_ERR_IRQ_STATUS:
+		if (!status)
+			return -EINVAL;
+		*status = snd_soc_read(codec,
+				       WCD9335_CPE_SS_SS_ERROR_INT_STATUS);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct wcd_cpe_cdc_cb cpe_cb = {
+	.cdc_clk_en = tasha_codec_internal_rco_ctrl,
+	.cpe_clk_en = tasha_codec_cpe_fll_enable,
+	.get_afe_out_port_id = tasha_codec_get_mad_port_id,
+	.lab_cdc_ch_ctl = tasha_codec_enable_slimtx_mad,
+	.cdc_ext_clk = tasha_cdc_mclk_enable,
+	.bus_vote_bw = tasha_codec_vote_max_bw,
+	.cpe_err_irq_control = tasha_cpe_err_irq_control,
+};
+
+static struct cpe_svc_init_param cpe_svc_params = {
+	.version = CPE_SVC_INIT_PARAM_V1,
+	.query_freq_plans_cb = tasha_cdc_query_cpe_clk_plan,
+	.change_freq_plan_cb = tasha_cdc_change_cpe_clk,
+};
+
+static int tasha_cpe_initialize(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd_cpe_params cpe_params;
+
+	memset(&cpe_params, 0,
+	       sizeof(struct wcd_cpe_params));
+	cpe_params.codec = codec;
+	cpe_params.get_cpe_core = tasha_codec_get_cpe_core;
+	cpe_params.cdc_cb = &cpe_cb;
+	cpe_params.dbg_mode = cpe_debug_mode;
+	cpe_params.cdc_major_ver = CPE_SVC_CODEC_WCD9335;
+	cpe_params.cdc_minor_ver = CPE_SVC_CODEC_V1P0;
+	cpe_params.cdc_id = CPE_SVC_CODEC_WCD9335;
+
+	cpe_params.cdc_irq_info.cpe_engine_irq =
+			WCD9335_IRQ_SVA_OUTBOX1;
+	cpe_params.cdc_irq_info.cpe_err_irq =
+			WCD9335_IRQ_SVA_ERROR;
+	cpe_params.cdc_irq_info.cpe_fatal_irqs =
+			TASHA_CPE_FATAL_IRQS;
+
+	cpe_svc_params.context = codec;
+	cpe_params.cpe_svc_params = &cpe_svc_params;
+
+	tasha->cpe_core = wcd_cpe_init("cpe_9335", codec,
+					&cpe_params);
+	if (IS_ERR_OR_NULL(tasha->cpe_core)) {
+		dev_err(codec->dev,
+			"%s: Failed to enable CPE\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct wcd_resmgr_cb tasha_resmgr_cb = {
+	.cdc_rco_ctrl = __tasha_codec_internal_rco_ctrl,
+};
+
+static int tasha_device_down(struct wcd9xxx *wcd9xxx)
+{
+	struct snd_soc_codec *codec;
+	struct tasha_priv *priv;
+	int count;
+	int i = 0;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	priv = snd_soc_codec_get_drvdata(codec);
+	wcd_cpe_ssr_event(priv->cpe_core, WCD_CPE_BUS_DOWN_EVENT);
+	for (i = 0; i < priv->nr; i++)
+		swrm_wcd_notify(priv->swr_ctrl_data[i].swr_pdev,
+				SWR_DEVICE_DOWN, NULL);
+	snd_soc_card_change_online_state(codec->component.card, 0);
+	for (count = 0; count < NUM_CODEC_DAIS; count++)
+		priv->dai[count].bus_down_in_recovery = true;
+
+	priv->resmgr->sido_input_src = SIDO_SOURCE_INTERNAL;
+
+	return 0;
+}
+
+static int tasha_post_reset_cb(struct wcd9xxx *wcd9xxx)
+{
+	int i, ret = 0;
+	struct wcd9xxx *control;
+	struct snd_soc_codec *codec;
+	struct tasha_priv *tasha;
+	struct wcd9xxx_pdata *pdata;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	tasha = snd_soc_codec_get_drvdata(codec);
+	control = dev_get_drvdata(codec->dev->parent);
+
+	wcd9xxx_set_power_state(tasha->wcd9xxx,
+				WCD_REGION_POWER_COLLAPSE_REMOVE,
+				WCD9XXX_DIG_CORE_REGION_1);
+
+	mutex_lock(&tasha->codec_mutex);
+
+	tasha_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+		control->slim_slave->laddr;
+	tasha_slimbus_slave_port_cfg.slave_dev_pgd_la =
+		control->slim->laddr;
+	tasha_init_slim_slave_cfg(codec);
+	if (tasha->machine_codec_event_cb)
+		tasha->machine_codec_event_cb(codec,
+				WCD9335_CODEC_EVENT_CODEC_UP);
+	snd_soc_card_change_online_state(codec->component.card, 1);
+
+	/* Class-H Init*/
+	wcd_clsh_init(&tasha->clsh_d);
+
+	for (i = 0; i < TASHA_MAX_MICBIAS; i++)
+		tasha->micb_ref[i] = 0;
+
+	tasha_update_reg_defaults(tasha);
+
+	tasha->codec = codec;
+
+	dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
+		__func__, control->mclk_rate);
+
+	if (control->mclk_rate == TASHA_MCLK_CLK_12P288MHZ)
+		snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+				    0x03, 0x00);
+	else if (control->mclk_rate == TASHA_MCLK_CLK_9P6MHZ)
+		snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+				    0x03, 0x01);
+	tasha_codec_init_reg(codec);
+
+	wcd_resmgr_post_ssr_v2(tasha->resmgr);
+
+	tasha_enable_efuse_sensing(codec);
+
+	regcache_mark_dirty(codec->component.regmap);
+	regcache_sync(codec->component.regmap);
+
+	pdata = dev_get_platdata(codec->dev->parent);
+	ret = tasha_handle_pdata(tasha, pdata);
+	if (ret < 0)
+		dev_err(codec->dev, "%s: invalid pdata\n", __func__);
+
+	/* Reset reference counter for voting for max bw */
+	tasha->ref_count = 0;
+	/* MBHC Init */
+	wcd_mbhc_deinit(&tasha->mbhc);
+	tasha->mbhc_started = false;
+
+	/* Initialize MBHC module */
+	ret = wcd_mbhc_init(&tasha->mbhc, codec, &mbhc_cb, &intr_ids,
+		      wcd_mbhc_registers, TASHA_ZDET_SUPPORTED);
+	if (ret)
+		dev_err(codec->dev, "%s: mbhc initialization failed\n",
+			__func__);
+	else
+		tasha_mbhc_hs_detect(codec, tasha->mbhc.mbhc_cfg);
+
+	tasha_cleanup_irqs(tasha);
+	ret = tasha_setup_irqs(tasha);
+	if (ret) {
+		dev_err(codec->dev, "%s: tasha irq setup failed %d\n",
+			__func__, ret);
+		goto err;
+	}
+
+	tasha_set_spkr_mode(codec, tasha->spkr_mode);
+	wcd_cpe_ssr_event(tasha->cpe_core, WCD_CPE_BUS_UP_EVENT);
+
+err:
+	mutex_unlock(&tasha->codec_mutex);
+	return ret;
+}
+
+static struct regulator *tasha_codec_find_ondemand_regulator(
+		struct snd_soc_codec *codec, const char *name)
+{
+	int i;
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
+	struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent);
+
+	for (i = 0; i < wcd9xxx->num_of_supplies; ++i) {
+		if (pdata->regulator[i].ondemand &&
+			wcd9xxx->supplies[i].supply &&
+			!strcmp(wcd9xxx->supplies[i].supply, name))
+			return wcd9xxx->supplies[i].consumer;
+	}
+
+	dev_dbg(tasha->dev, "Warning: regulator not found:%s\n",
+		name);
+	return NULL;
+}
+
+static int tasha_codec_probe(struct snd_soc_codec *codec)
+{
+	struct wcd9xxx *control;
+	struct tasha_priv *tasha;
+	struct wcd9xxx_pdata *pdata;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int i, ret;
+	void *ptr = NULL;
+	struct regulator *supply;
+
+	control = dev_get_drvdata(codec->dev->parent);
+
+	dev_info(codec->dev, "%s()\n", __func__);
+	tasha = snd_soc_codec_get_drvdata(codec);
+	tasha->intf_type = wcd9xxx_get_intf_type();
+
+	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		control->dev_down = tasha_device_down;
+		control->post_reset = tasha_post_reset_cb;
+		control->ssr_priv = (void *)codec;
+	}
+
+	/* Resource Manager post Init */
+	ret = wcd_resmgr_post_init(tasha->resmgr, &tasha_resmgr_cb, codec);
+	if (ret) {
+		dev_err(codec->dev, "%s: wcd resmgr post init failed\n",
+			__func__);
+		goto err;
+	}
+	/* Class-H Init*/
+	wcd_clsh_init(&tasha->clsh_d);
+	/* Default HPH Mode to Class-H HiFi */
+	tasha->hph_mode = CLS_H_HIFI;
+
+	tasha->codec = codec;
+	for (i = 0; i < COMPANDER_MAX; i++)
+		tasha->comp_enabled[i] = 0;
+
+	tasha->spkr_gain_offset = RX_GAIN_OFFSET_0_DB;
+	tasha->intf_type = wcd9xxx_get_intf_type();
+	tasha_update_reg_reset_values(codec);
+	pr_debug("%s: MCLK Rate = %x\n", __func__, control->mclk_rate);
+	if (control->mclk_rate == TASHA_MCLK_CLK_12P288MHZ)
+		snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+				    0x03, 0x00);
+	else if (control->mclk_rate == TASHA_MCLK_CLK_9P6MHZ)
+		snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+				    0x03, 0x01);
+	tasha_codec_init_reg(codec);
+
+	tasha_enable_efuse_sensing(codec);
+
+	pdata = dev_get_platdata(codec->dev->parent);
+	ret = tasha_handle_pdata(tasha, pdata);
+	if (ret < 0) {
+		pr_err("%s: bad pdata\n", __func__);
+		goto err;
+	}
+
+	supply = tasha_codec_find_ondemand_regulator(codec,
+		on_demand_supply_name[ON_DEMAND_MICBIAS]);
+	if (supply) {
+		tasha->on_demand_list[ON_DEMAND_MICBIAS].supply = supply;
+		tasha->on_demand_list[ON_DEMAND_MICBIAS].ondemand_supply_count =
+				0;
+	}
+
+	tasha->fw_data = devm_kzalloc(codec->dev,
+				      sizeof(*(tasha->fw_data)), GFP_KERNEL);
+	if (!tasha->fw_data)
+		goto err;
+	set_bit(WCD9XXX_ANC_CAL, tasha->fw_data->cal_bit);
+	set_bit(WCD9XXX_MBHC_CAL, tasha->fw_data->cal_bit);
+	set_bit(WCD9XXX_MAD_CAL, tasha->fw_data->cal_bit);
+	set_bit(WCD9XXX_VBAT_CAL, tasha->fw_data->cal_bit);
+
+	ret = wcd_cal_create_hwdep(tasha->fw_data,
+				   WCD9XXX_CODEC_HWDEP_NODE, codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
+		goto err_hwdep;
+	}
+
+	/* Initialize MBHC module */
+	if (TASHA_IS_2_0(tasha->wcd9xxx)) {
+		wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].reg =
+			WCD9335_MBHC_FSM_STATUS;
+		wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].mask = 0x01;
+	}
+	ret = wcd_mbhc_init(&tasha->mbhc, codec, &mbhc_cb, &intr_ids,
+		      wcd_mbhc_registers, TASHA_ZDET_SUPPORTED);
+	if (ret) {
+		pr_err("%s: mbhc initialization failed\n", __func__);
+		goto err_hwdep;
+	}
+
+	ptr = devm_kzalloc(codec->dev, (sizeof(tasha_rx_chs) +
+			   sizeof(tasha_tx_chs)), GFP_KERNEL);
+	if (!ptr) {
+		ret = -ENOMEM;
+		goto err_hwdep;
+	}
+
+	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+		snd_soc_dapm_new_controls(dapm, tasha_dapm_i2s_widgets,
+			ARRAY_SIZE(tasha_dapm_i2s_widgets));
+		snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+			ARRAY_SIZE(audio_i2s_map));
+		for (i = 0; i < ARRAY_SIZE(tasha_i2s_dai); i++) {
+			INIT_LIST_HEAD(&tasha->dai[i].wcd9xxx_ch_list);
+			init_waitqueue_head(&tasha->dai[i].dai_wait);
+		}
+	} else if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		for (i = 0; i < NUM_CODEC_DAIS; i++) {
+			INIT_LIST_HEAD(&tasha->dai[i].wcd9xxx_ch_list);
+			init_waitqueue_head(&tasha->dai[i].dai_wait);
+		}
+		tasha_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+					control->slim_slave->laddr;
+		tasha_slimbus_slave_port_cfg.slave_dev_pgd_la =
+					control->slim->laddr;
+		tasha_slimbus_slave_port_cfg.slave_port_mapping[0] =
+					TASHA_TX13;
+		tasha_init_slim_slave_cfg(codec);
+	}
+
+	snd_soc_add_codec_controls(codec, impedance_detect_controls,
+				   ARRAY_SIZE(impedance_detect_controls));
+	snd_soc_add_codec_controls(codec, hph_type_detect_controls,
+				   ARRAY_SIZE(hph_type_detect_controls));
+
+	snd_soc_add_codec_controls(codec,
+			tasha_analog_gain_controls,
+			ARRAY_SIZE(tasha_analog_gain_controls));
+	control->num_rx_port = TASHA_RX_MAX;
+	control->rx_chs = ptr;
+	memcpy(control->rx_chs, tasha_rx_chs, sizeof(tasha_rx_chs));
+	control->num_tx_port = TASHA_TX_MAX;
+	control->tx_chs = ptr + sizeof(tasha_rx_chs);
+	memcpy(control->tx_chs, tasha_tx_chs, sizeof(tasha_tx_chs));
+
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF2 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF2 Capture");
+
+	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		snd_soc_dapm_ignore_suspend(dapm, "AIF3 Playback");
+		snd_soc_dapm_ignore_suspend(dapm, "AIF3 Capture");
+		snd_soc_dapm_ignore_suspend(dapm, "AIF4 Playback");
+		snd_soc_dapm_ignore_suspend(dapm, "AIF Mix Playback");
+		snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX");
+		snd_soc_dapm_ignore_suspend(dapm, "VIfeed");
+		snd_soc_dapm_ignore_suspend(dapm, "AIF5 CPE TX");
+	}
+
+	snd_soc_dapm_sync(dapm);
+
+	ret = tasha_setup_irqs(tasha);
+	if (ret) {
+		pr_err("%s: tasha irq setup failed %d\n", __func__, ret);
+		goto err_pdata;
+	}
+
+	ret = tasha_cpe_initialize(codec);
+	if (ret) {
+		dev_err(codec->dev,
+			"%s: cpe initialization failed, err = %d\n",
+			__func__, ret);
+		/* Do not fail probe if CPE failed */
+		ret = 0;
+	}
+
+	for (i = 0; i < TASHA_NUM_DECIMATORS; i++) {
+		tasha->tx_hpf_work[i].tasha = tasha;
+		tasha->tx_hpf_work[i].decimator = i;
+		INIT_DELAYED_WORK(&tasha->tx_hpf_work[i].dwork,
+			tasha_tx_hpf_corner_freq_callback);
+	}
+
+	for (i = 0; i < TASHA_NUM_DECIMATORS; i++) {
+		tasha->tx_mute_dwork[i].tasha = tasha;
+		tasha->tx_mute_dwork[i].decimator = i;
+		INIT_DELAYED_WORK(&tasha->tx_mute_dwork[i].dwork,
+			  tasha_tx_mute_update_callback);
+	}
+
+	tasha->spk_anc_dwork.tasha = tasha;
+	INIT_DELAYED_WORK(&tasha->spk_anc_dwork.dwork,
+			  tasha_spk_anc_update_callback);
+
+	mutex_lock(&tasha->codec_mutex);
+	snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1");
+	snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2");
+	snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1 PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2 PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+	snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA");
+	mutex_unlock(&tasha->codec_mutex);
+	snd_soc_dapm_sync(dapm);
+
+	return ret;
+
+err_pdata:
+	devm_kfree(codec->dev, ptr);
+	control->rx_chs = NULL;
+	control->tx_chs = NULL;
+err_hwdep:
+	devm_kfree(codec->dev, tasha->fw_data);
+	tasha->fw_data = NULL;
+err:
+	return ret;
+}
+
+static int tasha_codec_remove(struct snd_soc_codec *codec)
+{
+	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *control;
+
+	control = dev_get_drvdata(codec->dev->parent);
+	control->rx_chs = NULL;
+	control->tx_chs = NULL;
+
+	tasha_cleanup_irqs(tasha);
+	/* Cleanup MBHC */
+	/* Cleanup resmgr */
+
+	return 0;
+}
+
+static struct regmap *tasha_get_regmap(struct device *dev)
+{
+	struct wcd9xxx *control = dev_get_drvdata(dev->parent);
+
+	return control->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_tasha = {
+	.probe = tasha_codec_probe,
+	.remove = tasha_codec_remove,
+	.get_regmap = tasha_get_regmap,
+	.component_driver = {
+		.controls = tasha_snd_controls,
+		.num_controls = ARRAY_SIZE(tasha_snd_controls),
+		.dapm_widgets = tasha_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(tasha_dapm_widgets),
+		.dapm_routes = audio_map,
+		.num_dapm_routes = ARRAY_SIZE(audio_map),
+	},
+};
+
+#ifdef CONFIG_PM
+static int tasha_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tasha_priv *tasha = platform_get_drvdata(pdev);
+
+	dev_dbg(dev, "%s: system suspend\n", __func__);
+	if (cancel_delayed_work_sync(&tasha->power_gate_work))
+		tasha_codec_power_gate_digital_core(tasha);
+
+	return 0;
+}
+
+static int tasha_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tasha_priv *tasha = platform_get_drvdata(pdev);
+
+	if (!tasha) {
+		dev_err(dev, "%s: tasha private data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_dbg(dev, "%s: system resume\n", __func__);
+	return 0;
+}
+
+static const struct dev_pm_ops tasha_pm_ops = {
+	.suspend = tasha_suspend,
+	.resume = tasha_resume,
+};
+#endif
+
+static int tasha_swrm_read(void *handle, int reg)
+{
+	struct tasha_priv *tasha;
+	struct wcd9xxx *wcd9xxx;
+	unsigned short swr_rd_addr_base;
+	unsigned short swr_rd_data_base;
+	int val, ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	tasha = (struct tasha_priv *)handle;
+	wcd9xxx = tasha->wcd9xxx;
+
+	dev_dbg(tasha->dev, "%s: Reading soundwire register, 0x%x\n",
+		__func__, reg);
+	swr_rd_addr_base = WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0;
+	swr_rd_data_base = WCD9335_SWR_AHB_BRIDGE_RD_DATA_0;
+	/* read_lock */
+	mutex_lock(&tasha->swr_read_lock);
+	ret = regmap_bulk_write(wcd9xxx->regmap, swr_rd_addr_base,
+				(u8 *)&reg, 4);
+	if (ret < 0) {
+		pr_err("%s: RD Addr Failure\n", __func__);
+		goto err;
+	}
+	/* Check for RD status */
+	ret = regmap_bulk_read(wcd9xxx->regmap, swr_rd_data_base,
+			       (u8 *)&val, 4);
+	if (ret < 0) {
+		pr_err("%s: RD Data Failure\n", __func__);
+		goto err;
+	}
+	ret = val;
+err:
+	/* read_unlock */
+	mutex_unlock(&tasha->swr_read_lock);
+	return ret;
+}
+
+static int tasha_swrm_i2s_bulk_write(struct wcd9xxx *wcd9xxx,
+				struct wcd9xxx_reg_val *bulk_reg,
+				size_t len)
+{
+	int i, ret = 0;
+	unsigned short swr_wr_addr_base;
+	unsigned short swr_wr_data_base;
+
+	swr_wr_addr_base = WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0;
+	swr_wr_data_base = WCD9335_SWR_AHB_BRIDGE_WR_DATA_0;
+
+	for (i = 0; i < (len * 2); i += 2) {
+		/* First Write the Data to register */
+		ret = regmap_bulk_write(wcd9xxx->regmap,
+			swr_wr_data_base, bulk_reg[i].buf, 4);
+		if (ret < 0) {
+			dev_err(wcd9xxx->dev, "%s: WR Data Failure\n",
+				__func__);
+			break;
+		}
+		/* Next Write Address */
+		ret = regmap_bulk_write(wcd9xxx->regmap,
+			swr_wr_addr_base, bulk_reg[i+1].buf, 4);
+		if (ret < 0) {
+			dev_err(wcd9xxx->dev, "%s: WR Addr Failure\n",
+				__func__);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int tasha_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len)
+{
+	struct tasha_priv *tasha;
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_reg_val *bulk_reg;
+	unsigned short swr_wr_addr_base;
+	unsigned short swr_wr_data_base;
+	int i, j, ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	if (len <= 0) {
+		pr_err("%s: Invalid size: %zu\n", __func__, len);
+		return -EINVAL;
+	}
+	tasha = (struct tasha_priv *)handle;
+	wcd9xxx = tasha->wcd9xxx;
+
+	swr_wr_addr_base = WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0;
+	swr_wr_data_base = WCD9335_SWR_AHB_BRIDGE_WR_DATA_0;
+
+	bulk_reg = kzalloc((2 * len * sizeof(struct wcd9xxx_reg_val)),
+			   GFP_KERNEL);
+	if (!bulk_reg)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < (len * 2); i += 2, j++) {
+		bulk_reg[i].reg = swr_wr_data_base;
+		bulk_reg[i].buf = (u8 *)(&val[j]);
+		bulk_reg[i].bytes = 4;
+		bulk_reg[i+1].reg = swr_wr_addr_base;
+		bulk_reg[i+1].buf = (u8 *)(&reg[j]);
+		bulk_reg[i+1].bytes = 4;
+	}
+	mutex_lock(&tasha->swr_write_lock);
+
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+		ret = tasha_swrm_i2s_bulk_write(wcd9xxx, bulk_reg, len);
+		if (ret) {
+			dev_err(tasha->dev, "%s: i2s bulk write failed, ret: %d\n",
+				__func__, ret);
+		}
+	} else {
+		ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg,
+				 (len * 2), false);
+		if (ret) {
+			dev_err(tasha->dev, "%s: swrm bulk write failed, ret: %d\n",
+				__func__, ret);
+		}
+	}
+
+	mutex_unlock(&tasha->swr_write_lock);
+	kfree(bulk_reg);
+
+	return ret;
+}
+
+static int tasha_swrm_write(void *handle, int reg, int val)
+{
+	struct tasha_priv *tasha;
+	struct wcd9xxx *wcd9xxx;
+	unsigned short swr_wr_addr_base;
+	unsigned short swr_wr_data_base;
+	struct wcd9xxx_reg_val bulk_reg[2];
+	int ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	tasha = (struct tasha_priv *)handle;
+	wcd9xxx = tasha->wcd9xxx;
+
+	swr_wr_addr_base = WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0;
+	swr_wr_data_base = WCD9335_SWR_AHB_BRIDGE_WR_DATA_0;
+
+	/* First Write the Data to register */
+	bulk_reg[0].reg = swr_wr_data_base;
+	bulk_reg[0].buf = (u8 *)(&val);
+	bulk_reg[0].bytes = 4;
+	bulk_reg[1].reg = swr_wr_addr_base;
+	bulk_reg[1].buf = (u8 *)(&reg);
+	bulk_reg[1].bytes = 4;
+
+	mutex_lock(&tasha->swr_write_lock);
+
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+		ret = tasha_swrm_i2s_bulk_write(wcd9xxx, bulk_reg, 1);
+		if (ret) {
+			dev_err(tasha->dev, "%s: i2s swrm write failed, ret: %d\n",
+				__func__, ret);
+		}
+	} else {
+		ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2, false);
+		if (ret < 0)
+			pr_err("%s: WR Data Failure\n", __func__);
+	}
+
+	mutex_unlock(&tasha->swr_write_lock);
+	return ret;
+}
+
+static int tasha_swrm_clock(void *handle, bool enable)
+{
+	struct tasha_priv *tasha = (struct tasha_priv *) handle;
+
+	mutex_lock(&tasha->swr_clk_lock);
+
+	dev_dbg(tasha->dev, "%s: swrm clock %s\n",
+		__func__, (enable?"enable" : "disable"));
+	if (enable) {
+		tasha->swr_clk_users++;
+		if (tasha->swr_clk_users == 1) {
+			if (TASHA_IS_2_0(tasha->wcd9xxx))
+				regmap_update_bits(
+					tasha->wcd9xxx->regmap,
+					WCD9335_TEST_DEBUG_NPL_DLY_TEST_1,
+					0x10, 0x00);
+			__tasha_cdc_mclk_enable(tasha, true);
+			regmap_update_bits(tasha->wcd9xxx->regmap,
+				WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x01);
+		}
+	} else {
+		tasha->swr_clk_users--;
+		if (tasha->swr_clk_users == 0) {
+			regmap_update_bits(tasha->wcd9xxx->regmap,
+				WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x00);
+			__tasha_cdc_mclk_enable(tasha, false);
+			if (TASHA_IS_2_0(tasha->wcd9xxx))
+				regmap_update_bits(
+					tasha->wcd9xxx->regmap,
+					WCD9335_TEST_DEBUG_NPL_DLY_TEST_1,
+					0x10, 0x10);
+		}
+	}
+	dev_dbg(tasha->dev, "%s: swrm clock users %d\n",
+		__func__, tasha->swr_clk_users);
+	mutex_unlock(&tasha->swr_clk_lock);
+	return 0;
+}
+
+static int tasha_swrm_handle_irq(void *handle,
+				   irqreturn_t (*swrm_irq_handler)(int irq,
+								   void *data),
+				    void *swrm_handle,
+				    int action)
+{
+	struct tasha_priv *tasha;
+	int ret = 0;
+	struct wcd9xxx *wcd9xxx;
+
+	if (!handle) {
+		pr_err("%s: null handle received\n", __func__);
+		return -EINVAL;
+	}
+	tasha = (struct tasha_priv *) handle;
+	wcd9xxx = tasha->wcd9xxx;
+
+	if (action) {
+		ret = wcd9xxx_request_irq(&wcd9xxx->core_res,
+					  WCD9335_IRQ_SOUNDWIRE,
+					  swrm_irq_handler,
+					  "Tasha SWR Master", swrm_handle);
+		if (ret)
+			dev_err(tasha->dev, "%s: Failed to request irq %d\n",
+				__func__, WCD9335_IRQ_SOUNDWIRE);
+	} else
+		wcd9xxx_free_irq(&wcd9xxx->core_res, WCD9335_IRQ_SOUNDWIRE,
+				 swrm_handle);
+
+	return ret;
+}
+
+static void tasha_add_child_devices(struct work_struct *work)
+{
+	struct tasha_priv *tasha;
+	struct platform_device *pdev;
+	struct device_node *node;
+	struct wcd9xxx *wcd9xxx;
+	struct tasha_swr_ctrl_data *swr_ctrl_data = NULL, *temp;
+	int ret, ctrl_num = 0;
+	struct wcd_swr_ctrl_platform_data *platdata;
+	char plat_dev_name[WCD9335_STRING_LEN];
+
+	tasha = container_of(work, struct tasha_priv,
+			     tasha_add_child_devices_work);
+	if (!tasha) {
+		pr_err("%s: Memory for WCD9335 does not exist\n",
+			__func__);
+		return;
+	}
+	wcd9xxx = tasha->wcd9xxx;
+	if (!wcd9xxx) {
+		pr_err("%s: Memory for WCD9XXX does not exist\n",
+			__func__);
+		return;
+	}
+	if (!wcd9xxx->dev->of_node) {
+		pr_err("%s: DT node for wcd9xxx does not exist\n",
+			__func__);
+		return;
+	}
+
+	platdata = &tasha->swr_plat_data;
+
+	for_each_child_of_node(wcd9xxx->dev->of_node, node) {
+		if (!strcmp(node->name, "swr_master"))
+			strlcpy(plat_dev_name, "tasha_swr_ctrl",
+				(WCD9335_STRING_LEN - 1));
+		else if (strnstr(node->name, "msm_cdc_pinctrl",
+				 strlen("msm_cdc_pinctrl")) != NULL)
+			strlcpy(plat_dev_name, node->name,
+				(WCD9335_STRING_LEN - 1));
+		else
+			continue;
+
+		pdev = platform_device_alloc(plat_dev_name, -1);
+		if (!pdev) {
+			dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err;
+		}
+		pdev->dev.parent = tasha->dev;
+		pdev->dev.of_node = node;
+
+		if (!strcmp(node->name, "swr_master")) {
+			ret = platform_device_add_data(pdev, platdata,
+						       sizeof(*platdata));
+			if (ret) {
+				dev_err(&pdev->dev,
+					"%s: cannot add plat data ctrl:%d\n",
+					__func__, ctrl_num);
+				goto fail_pdev_add;
+			}
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s: Cannot add platform device\n",
+				__func__);
+			goto fail_pdev_add;
+		}
+
+		if (!strcmp(node->name, "swr_master")) {
+			temp = krealloc(swr_ctrl_data,
+					(ctrl_num + 1) * sizeof(
+					struct tasha_swr_ctrl_data),
+					GFP_KERNEL);
+			if (!temp) {
+				dev_err(wcd9xxx->dev, "out of memory\n");
+				ret = -ENOMEM;
+				goto err;
+			}
+			swr_ctrl_data = temp;
+			swr_ctrl_data[ctrl_num].swr_pdev = pdev;
+			ctrl_num++;
+			dev_dbg(&pdev->dev,
+				"%s: Added soundwire ctrl device(s)\n",
+				__func__);
+			tasha->nr = ctrl_num;
+			tasha->swr_ctrl_data = swr_ctrl_data;
+		}
+	}
+
+	return;
+fail_pdev_add:
+	platform_device_put(pdev);
+err:
+	return;
+}
+
+/*
+ * tasha_codec_ver: to get tasha codec version
+ * @codec: handle to snd_soc_codec *
+ * return enum codec_variant - version
+ */
+enum codec_variant tasha_codec_ver(void)
+{
+	return codec_ver;
+}
+EXPORT_SYMBOL(tasha_codec_ver);
+
+static int __tasha_enable_efuse_sensing(struct tasha_priv *tasha)
+{
+	int val, rc;
+
+	__tasha_cdc_mclk_enable(tasha, true);
+
+	regmap_update_bits(tasha->wcd9xxx->regmap,
+			   WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x20);
+	regmap_update_bits(tasha->wcd9xxx->regmap,
+			   WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
+
+	/*
+	 * 5ms sleep required after enabling efuse control
+	 * before checking the status.
+	 */
+	usleep_range(5000, 5500);
+	rc = regmap_read(tasha->wcd9xxx->regmap,
+			 WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
+
+	if (rc || (!(val & 0x01)))
+		WARN(1, "%s: Efuse sense is not complete\n", __func__);
+
+	__tasha_cdc_mclk_enable(tasha, false);
+
+	return rc;
+}
+
+void tasha_get_codec_ver(struct tasha_priv *tasha)
+{
+	int i;
+	int val;
+	struct tasha_reg_mask_val codec_reg[] = {
+		{WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10, 0xFF, 0xFF},
+		{WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11, 0xFF, 0x83},
+		{WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12, 0xFF, 0x0A},
+	};
+
+	__tasha_enable_efuse_sensing(tasha);
+	for (i = 0; i < ARRAY_SIZE(codec_reg); i++) {
+		regmap_read(tasha->wcd9xxx->regmap, codec_reg[i].reg, &val);
+		if (!(val && codec_reg[i].val)) {
+			codec_ver = WCD9335;
+			goto ret;
+		}
+	}
+	codec_ver = WCD9326;
+ret:
+	pr_debug("%s: codec is %d\n", __func__, codec_ver);
+}
+EXPORT_SYMBOL(tasha_get_codec_ver);
+
+static int tasha_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct tasha_priv *tasha;
+	struct clk *wcd_ext_clk, *wcd_native_clk;
+	struct wcd9xxx_resmgr_v2 *resmgr;
+	struct wcd9xxx_power_region *cdc_pwr;
+
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+		if (apr_get_subsys_state() == APR_SUBSYS_DOWN) {
+			dev_err(&pdev->dev, "%s: dsp down\n", __func__);
+			return -EPROBE_DEFER;
+		}
+	}
+
+	tasha = devm_kzalloc(&pdev->dev, sizeof(struct tasha_priv),
+			    GFP_KERNEL);
+	if (!tasha)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, tasha);
+
+	tasha->wcd9xxx = dev_get_drvdata(pdev->dev.parent);
+	tasha->dev = &pdev->dev;
+	INIT_DELAYED_WORK(&tasha->power_gate_work, tasha_codec_power_gate_work);
+	mutex_init(&tasha->power_lock);
+	mutex_init(&tasha->sido_lock);
+	INIT_WORK(&tasha->tasha_add_child_devices_work,
+		  tasha_add_child_devices);
+	BLOCKING_INIT_NOTIFIER_HEAD(&tasha->notifier);
+	mutex_init(&tasha->micb_lock);
+	mutex_init(&tasha->swr_read_lock);
+	mutex_init(&tasha->swr_write_lock);
+	mutex_init(&tasha->swr_clk_lock);
+	mutex_init(&tasha->sb_clk_gear_lock);
+	mutex_init(&tasha->mclk_lock);
+
+	cdc_pwr = devm_kzalloc(&pdev->dev, sizeof(struct wcd9xxx_power_region),
+			       GFP_KERNEL);
+	if (!cdc_pwr) {
+		ret = -ENOMEM;
+		goto err_cdc_pwr;
+	}
+	tasha->wcd9xxx->wcd9xxx_pwr[WCD9XXX_DIG_CORE_REGION_1] = cdc_pwr;
+	cdc_pwr->pwr_collapse_reg_min = TASHA_DIG_CORE_REG_MIN;
+	cdc_pwr->pwr_collapse_reg_max = TASHA_DIG_CORE_REG_MAX;
+	wcd9xxx_set_power_state(tasha->wcd9xxx,
+				WCD_REGION_POWER_COLLAPSE_REMOVE,
+				WCD9XXX_DIG_CORE_REGION_1);
+
+	mutex_init(&tasha->codec_mutex);
+	/*
+	 * Init resource manager so that if child nodes such as SoundWire
+	 * requests for clock, resource manager can honor the request
+	 */
+	resmgr = wcd_resmgr_init(&tasha->wcd9xxx->core_res, NULL);
+	if (IS_ERR(resmgr)) {
+		ret = PTR_ERR(resmgr);
+		dev_err(&pdev->dev, "%s: Failed to initialize wcd resmgr\n",
+			__func__);
+		goto err_resmgr;
+	}
+	tasha->resmgr = resmgr;
+	tasha->swr_plat_data.handle = (void *) tasha;
+	tasha->swr_plat_data.read = tasha_swrm_read;
+	tasha->swr_plat_data.write = tasha_swrm_write;
+	tasha->swr_plat_data.bulk_write = tasha_swrm_bulk_write;
+	tasha->swr_plat_data.clk = tasha_swrm_clock;
+	tasha->swr_plat_data.handle_irq = tasha_swrm_handle_irq;
+
+	/* Register for Clock */
+	wcd_ext_clk = clk_get(tasha->wcd9xxx->dev, "wcd_clk");
+	if (IS_ERR(wcd_ext_clk)) {
+		dev_err(tasha->wcd9xxx->dev, "%s: clk get %s failed\n",
+			__func__, "wcd_ext_clk");
+		goto err_clk;
+	}
+	tasha->wcd_ext_clk = wcd_ext_clk;
+	tasha->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV;
+	set_bit(AUDIO_NOMINAL, &tasha->status_mask);
+	tasha->sido_ccl_cnt = 0;
+
+	/* Register native clk for 44.1 playback */
+	wcd_native_clk = clk_get(tasha->wcd9xxx->dev, "wcd_native_clk");
+	if (IS_ERR(wcd_native_clk))
+		dev_dbg(tasha->wcd9xxx->dev, "%s: clk get %s failed\n",
+			__func__, "wcd_native_clk");
+	else
+		tasha->wcd_native_clk = wcd_native_clk;
+
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha,
+					     tasha_dai, ARRAY_SIZE(tasha_dai));
+	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha,
+					     tasha_i2s_dai,
+					     ARRAY_SIZE(tasha_i2s_dai));
+	else
+		ret = -EINVAL;
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Codec registration failed, ret = %d\n",
+			__func__, ret);
+		goto err_cdc_reg;
+	}
+	/* Update codec register default values */
+	tasha_update_reg_defaults(tasha);
+	schedule_work(&tasha->tasha_add_child_devices_work);
+	tasha_get_codec_ver(tasha);
+
+	dev_info(&pdev->dev, "%s: Tasha driver probe done\n", __func__);
+	return ret;
+
+err_cdc_reg:
+	clk_put(tasha->wcd_ext_clk);
+	if (tasha->wcd_native_clk)
+		clk_put(tasha->wcd_native_clk);
+err_clk:
+	wcd_resmgr_remove(tasha->resmgr);
+err_resmgr:
+	devm_kfree(&pdev->dev, cdc_pwr);
+err_cdc_pwr:
+	mutex_destroy(&tasha->mclk_lock);
+	devm_kfree(&pdev->dev, tasha);
+	return ret;
+}
+
+static int tasha_remove(struct platform_device *pdev)
+{
+	struct tasha_priv *tasha;
+
+	tasha = platform_get_drvdata(pdev);
+
+	mutex_destroy(&tasha->codec_mutex);
+	clk_put(tasha->wcd_ext_clk);
+	if (tasha->wcd_native_clk)
+		clk_put(tasha->wcd_native_clk);
+	mutex_destroy(&tasha->mclk_lock);
+	devm_kfree(&pdev->dev, tasha);
+	snd_soc_unregister_codec(&pdev->dev);
+	mutex_destroy(&tasha->sb_clk_gear_lock);
+	return 0;
+}
+
+static struct platform_driver tasha_codec_driver = {
+	.probe = tasha_probe,
+	.remove = tasha_remove,
+	.driver = {
+		.name = "tasha_codec",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &tasha_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(tasha_codec_driver);
+
+MODULE_DESCRIPTION("Tasha Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd9335.h b/asoc/codecs/wcd9335.h
new file mode 100644
index 0000000..48826e6
--- /dev/null
+++ b/asoc/codecs/wcd9335.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef WCD9335_H
+#define WCD9335_H
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <dsp/apr_audio-v2.h>
+#include "wcd9xxx-slimslave.h"
+#include "wcd-mbhc-v2.h"
+
+#define TASHA_REG_VAL(reg, val)      {reg, 0, val}
+
+#define TASHA_REGISTER_START_OFFSET  0x800
+#define TASHA_SB_PGD_PORT_RX_BASE   0x40
+#define TASHA_SB_PGD_PORT_TX_BASE   0x50
+
+#define TASHA_ZDET_SUPPORTED true
+/* z value defined in milliohm */
+#define TASHA_ZDET_VAL_32	32000
+#define TASHA_ZDET_VAL_400	400000
+#define TASHA_ZDET_VAL_1200	1200000
+#define TASHA_ZDET_VAL_100K	100000000
+/* z floating defined in ohms */
+#define TASHA_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
+
+#define WCD9335_DMIC_CLK_DIV_2  0x0
+#define WCD9335_DMIC_CLK_DIV_3  0x1
+#define WCD9335_DMIC_CLK_DIV_4  0x2
+#define WCD9335_DMIC_CLK_DIV_6  0x3
+#define WCD9335_DMIC_CLK_DIV_8  0x4
+#define WCD9335_DMIC_CLK_DIV_16  0x5
+#define WCD9335_DMIC_CLK_DRIVE_DEFAULT 0x02
+
+#define WCD9335_ANC_DMIC_X2_FULL_RATE 1
+#define WCD9335_ANC_DMIC_X2_HALF_RATE 0
+
+/* Number of input and output Slimbus port */
+enum {
+	TASHA_RX0 = 0,
+	TASHA_RX1,
+	TASHA_RX2,
+	TASHA_RX3,
+	TASHA_RX4,
+	TASHA_RX5,
+	TASHA_RX6,
+	TASHA_RX7,
+	TASHA_RX8,
+	TASHA_RX9,
+	TASHA_RX10,
+	TASHA_RX11,
+	TASHA_RX12,
+	TASHA_RX_MAX,
+};
+
+enum {
+	TASHA_TX0 = 0,
+	TASHA_TX1,
+	TASHA_TX2,
+	TASHA_TX3,
+	TASHA_TX4,
+	TASHA_TX5,
+	TASHA_TX6,
+	TASHA_TX7,
+	TASHA_TX8,
+	TASHA_TX9,
+	TASHA_TX10,
+	TASHA_TX11,
+	TASHA_TX12,
+	TASHA_TX13,
+	TASHA_TX14,
+	TASHA_TX15,
+	TASHA_TX_MAX,
+};
+
+enum wcd9335_codec_event {
+	WCD9335_CODEC_EVENT_CODEC_UP = 0,
+};
+
+enum tasha_on_demand_supply {
+	ON_DEMAND_MICBIAS = 0,
+	ON_DEMAND_SUPPLIES_MAX,
+};
+
+/* structure used to put the defined
+ * ondemand supply for codec
+ * and count being used.
+ */
+struct on_demand_supply {
+	struct regulator *supply;
+	int ondemand_supply_count;
+};
+
+/* Dai data structure holds the
+ * dai specific info like rate,
+ * channel number etc.
+ */
+struct tasha_codec_dai_data {
+	u32 rate;
+	u32 *ch_num;
+	u32 ch_act;
+	u32 ch_tot;
+};
+
+/* Structure used to update codec
+ * register defaults after reset
+ */
+struct tasha_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+/* Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+	SPKR_MODE_DEFAULT,
+	SPKR_MODE_1,          /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+/*
+ * Rx path gain offsets
+ */
+enum {
+	RX_GAIN_OFFSET_M1P5_DB,
+	RX_GAIN_OFFSET_0_DB,
+};
+
+extern void *tasha_get_afe_config(struct snd_soc_codec *codec,
+				  enum afe_config_type config_type);
+extern int tasha_cdc_mclk_enable(struct snd_soc_codec *codec, int enable,
+				 bool dapm);
+extern int tasha_cdc_mclk_tx_enable(struct snd_soc_codec *codec, int enable,
+				    bool dapm);
+extern int tasha_enable_efuse_sensing(struct snd_soc_codec *codec);
+extern int tasha_mbhc_hs_detect(struct snd_soc_codec *codec,
+				struct wcd_mbhc_config *mbhc_cfg);
+extern void tasha_mbhc_hs_detect_exit(struct snd_soc_codec *codec);
+extern void tasha_mbhc_zdet_gpio_ctrl(
+		int (*zdet_gpio_cb)(struct snd_soc_codec *codec, bool high),
+		struct snd_soc_codec *codec);
+extern int tasha_codec_info_create_codec_entry(
+		struct snd_info_entry *codec_root,
+		struct snd_soc_codec *codec);
+extern void tasha_event_register(
+	int (*machine_event_cb)(struct snd_soc_codec *codec,
+				enum wcd9335_codec_event),
+	struct snd_soc_codec *codec);
+extern int tasha_codec_enable_standalone_micbias(struct snd_soc_codec *codec,
+						 int micb_num,
+						 bool enable);
+extern int tasha_set_spkr_mode(struct snd_soc_codec *codec, int mode);
+extern int tasha_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset);
+extern enum codec_variant tasha_codec_ver(void);
+#endif
diff --git a/asoc/codecs/wcd9335_irq.h b/asoc/codecs/wcd9335_irq.h
new file mode 100644
index 0000000..c666d31
--- /dev/null
+++ b/asoc/codecs/wcd9335_irq.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD9335_IRQ_H_
+#define __WCD9335_IRQ_H_
+
+enum {
+	/* INTR_REG 0 */
+	WCD9335_IRQ_FLL_LOCK_LOSS = 1,
+	WCD9335_IRQ_HPH_PA_OCPL_FAULT,
+	WCD9335_IRQ_HPH_PA_OCPR_FAULT,
+	WCD9335_IRQ_EAR_PA_OCP_FAULT,
+	WCD9335_IRQ_HPH_PA_CNPL_COMPLETE,
+	WCD9335_IRQ_HPH_PA_CNPR_COMPLETE,
+	WCD9335_IRQ_EAR_PA_CNP_COMPLETE,
+	/* INTR_REG 1 */
+	WCD9335_IRQ_MBHC_SW_DET,
+	WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
+	WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
+	WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
+	WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	WCD9335_IRQ_RESERVED_0,
+	WCD9335_IRQ_RESERVED_1,
+	WCD9335_IRQ_RESERVED_2,
+	/* INTR_REG 2 */
+	WCD9335_IRQ_LINE_PA1_CNP_COMPLETE,
+	WCD9335_IRQ_LINE_PA2_CNP_COMPLETE,
+	WCD9335_IRQ_LINE_PA3_CNP_COMPLETE,
+	WCD9335_IRQ_LINE_PA4_CNP_COMPLETE,
+	WCD9335_IRQ_SOUNDWIRE,
+	WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE,
+	WCD9335_IRQ_RCO_ERROR,
+	WCD9335_IRQ_SVA_ERROR,
+	/* INTR_REG 3 */
+	WCD9335_IRQ_MAD_AUDIO,
+	WCD9335_IRQ_MAD_BEACON,
+	WCD9335_IRQ_MAD_ULTRASOUND,
+	WCD9335_IRQ_VBAT_ATTACK,
+	WCD9335_IRQ_VBAT_RESTORE,
+	WCD9335_IRQ_SVA_OUTBOX1,
+	WCD9335_IRQ_SVA_OUTBOX2,
+	WCD9335_NUM_IRQS,
+};
+
+#endif
diff --git a/asoc/codecs/wcd9335_registers.h b/asoc/codecs/wcd9335_registers.h
new file mode 100644
index 0000000..c50430d
--- /dev/null
+++ b/asoc/codecs/wcd9335_registers.h
@@ -0,0 +1,1348 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WCD9335_REGISTERS_H
+#define _WCD9335_REGISTERS_H
+
+#define WCD9335_PAGE_SIZE 256
+#define WCD9335_NUM_PAGES 256
+
+extern const u8 *wcd9335_reg[WCD9335_NUM_PAGES];
+
+enum {
+	PAGE_0 = 0,
+	PAGE_1,
+	PAGE_2,
+	PAGE_6 = 6,
+	PAGE_10 = 0xA,
+	PAGE_11,
+	PAGE_12,
+	PAGE_13,
+	PAGE_0X80,
+};
+
+/* Page-0 Registers */
+#define WCD9335_PAGE0_PAGE_REGISTER                      0x0000
+#define WCD9335_CODEC_RPM_CLK_BYPASS                     0x0001
+#define WCD9335_CODEC_RPM_CLK_GATE                       0x0002
+#define WCD9335_CODEC_RPM_CLK_MCLK_CFG                   0x0003
+#define WCD9335_CODEC_RPM_RST_CTL                        0x0009
+#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL             0x0011
+#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1              0x0012
+#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2              0x0013
+#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3              0x0014
+#define WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN          0x0015
+#define WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN         0x0016
+#define WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1       0x0017
+#define WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2       0x0018
+#define WCD9335_CODEC_RPM_INT_MASK                       0x001d
+#define WCD9335_CODEC_RPM_INT_STATUS                     0x001e
+#define WCD9335_CODEC_RPM_INT_CLEAR                      0x001f
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0             0x0021
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1             0x0022
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2             0x0023
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3             0x0024
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL                 0x0025
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0               0x0026
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1               0x0027
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0            0x0029
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1            0x002a
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2            0x002b
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3            0x002c
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4            0x002d
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5            0x002e
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6            0x002f
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7            0x0030
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8            0x0031
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9            0x0032
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10           0x0033
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11           0x0034
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12           0x0035
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13           0x0036
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14           0x0037
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15           0x0038
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS              0x0039
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO      0x003a
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1            0x003b
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2            0x003c
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3            0x003d
+#define WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL        0x003e
+#define WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE                0x003f
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL             0x0041
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS          0x0042
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB         0x0043
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB         0x0044
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL             0x0045
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS          0x0046
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB         0x0047
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB         0x0048
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL             0x0049
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS          0x004a
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB         0x004b
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB         0x004c
+#define WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL             0x0051
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL             0x0052
+#define WCD9335_DATA_HUB_DATA_HUB_I2S_CLK                0x0053
+#define WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG            0x0054
+#define WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG            0x0055
+#define WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG            0x0056
+#define WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG            0x0057
+#define WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG            0x0058
+#define WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG            0x0059
+#define WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG            0x005a
+#define WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG            0x005b
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG         0x0061
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG         0x0062
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG         0x0063
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG         0x0064
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG         0x0065
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG         0x0066
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG         0x0067
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG         0x0068
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG         0x0069
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG         0x006a
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG        0x006b
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG        0x006c
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG        0x006e
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG        0x006f
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG        0x0070
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG       0x0071
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG       0x0072
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG       0x0073
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG       0x0074
+#define WCD9335_DATA_HUB_NATIVE_FIFO_SYNC                0x0075
+#define WCD9335_DATA_HUB_NATIVE_FIFO_STATUS              0x007D
+#define WCD9335_INTR_CFG                                 0x0081
+#define WCD9335_INTR_CLR_COMMIT                          0x0082
+#define WCD9335_INTR_PIN1_MASK0                          0x0089
+#define WCD9335_INTR_PIN1_MASK1                          0x008a
+#define WCD9335_INTR_PIN1_MASK2                          0x008b
+#define WCD9335_INTR_PIN1_MASK3                          0x008c
+#define WCD9335_INTR_PIN1_STATUS0                        0x0091
+#define WCD9335_INTR_PIN1_STATUS1                        0x0092
+#define WCD9335_INTR_PIN1_STATUS2                        0x0093
+#define WCD9335_INTR_PIN1_STATUS3                        0x0094
+#define WCD9335_INTR_PIN1_CLEAR0                         0x0099
+#define WCD9335_INTR_PIN1_CLEAR1                         0x009a
+#define WCD9335_INTR_PIN1_CLEAR2                         0x009b
+#define WCD9335_INTR_PIN1_CLEAR3                         0x009c
+#define WCD9335_INTR_PIN2_MASK0                          0x00a1
+#define WCD9335_INTR_PIN2_MASK1                          0x00a2
+#define WCD9335_INTR_PIN2_MASK2                          0x00a3
+#define WCD9335_INTR_PIN2_MASK3                          0x00a4
+#define WCD9335_INTR_PIN2_STATUS0                        0x00a9
+#define WCD9335_INTR_PIN2_STATUS1                        0x00aa
+#define WCD9335_INTR_PIN2_STATUS2                        0x00ab
+#define WCD9335_INTR_PIN2_STATUS3                        0x00ac
+#define WCD9335_INTR_PIN2_CLEAR0                         0x00b1
+#define WCD9335_INTR_PIN2_CLEAR1                         0x00b2
+#define WCD9335_INTR_PIN2_CLEAR2                         0x00b3
+#define WCD9335_INTR_PIN2_CLEAR3                         0x00b4
+#define WCD9335_INTR_LEVEL0                              0x00e1
+#define WCD9335_INTR_LEVEL1                              0x00e2
+#define WCD9335_INTR_LEVEL2                              0x00e3
+#define WCD9335_INTR_LEVEL3                              0x00e4
+#define WCD9335_INTR_BYPASS0                             0x00e9
+#define WCD9335_INTR_BYPASS1                             0x00ea
+#define WCD9335_INTR_BYPASS2                             0x00eb
+#define WCD9335_INTR_BYPASS3                             0x00ec
+#define WCD9335_INTR_SET0                                0x00f1
+#define WCD9335_INTR_SET1                                0x00f2
+#define WCD9335_INTR_SET2                                0x00f3
+#define WCD9335_INTR_SET3                                0x00f4
+
+/* Page-1 Registers */
+#define WCD9335_PAGE1_PAGE_REGISTER                      0x0100
+#define WCD9335_CPE_FLL_USER_CTL_0                       0x0101
+#define WCD9335_CPE_FLL_USER_CTL_1                       0x0102
+#define WCD9335_CPE_FLL_USER_CTL_2                       0x0103
+#define WCD9335_CPE_FLL_USER_CTL_3                       0x0104
+#define WCD9335_CPE_FLL_USER_CTL_4                       0x0105
+#define WCD9335_CPE_FLL_USER_CTL_5                       0x0106
+#define WCD9335_CPE_FLL_USER_CTL_6                       0x0107
+#define WCD9335_CPE_FLL_USER_CTL_7                       0x0108
+#define WCD9335_CPE_FLL_USER_CTL_8                       0x0109
+#define WCD9335_CPE_FLL_USER_CTL_9                       0x010a
+#define WCD9335_CPE_FLL_L_VAL_CTL_0                      0x010b
+#define WCD9335_CPE_FLL_L_VAL_CTL_1                      0x010c
+#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0                   0x010d
+#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1                   0x010e
+#define WCD9335_CPE_FLL_CONFIG_CTL_0                     0x010f
+#define WCD9335_CPE_FLL_CONFIG_CTL_1                     0x0110
+#define WCD9335_CPE_FLL_CONFIG_CTL_2                     0x0111
+#define WCD9335_CPE_FLL_CONFIG_CTL_3                     0x0112
+#define WCD9335_CPE_FLL_CONFIG_CTL_4                     0x0113
+#define WCD9335_CPE_FLL_TEST_CTL_0                       0x0114
+#define WCD9335_CPE_FLL_TEST_CTL_1                       0x0115
+#define WCD9335_CPE_FLL_TEST_CTL_2                       0x0116
+#define WCD9335_CPE_FLL_TEST_CTL_3                       0x0117
+#define WCD9335_CPE_FLL_TEST_CTL_4                       0x0118
+#define WCD9335_CPE_FLL_TEST_CTL_5                       0x0119
+#define WCD9335_CPE_FLL_TEST_CTL_6                       0x011a
+#define WCD9335_CPE_FLL_TEST_CTL_7                       0x011b
+#define WCD9335_CPE_FLL_FREQ_CTL_0                       0x011c
+#define WCD9335_CPE_FLL_FREQ_CTL_1                       0x011d
+#define WCD9335_CPE_FLL_FREQ_CTL_2                       0x011e
+#define WCD9335_CPE_FLL_FREQ_CTL_3                       0x011f
+#define WCD9335_CPE_FLL_SSC_CTL_0                        0x0120
+#define WCD9335_CPE_FLL_SSC_CTL_1                        0x0121
+#define WCD9335_CPE_FLL_SSC_CTL_2                        0x0122
+#define WCD9335_CPE_FLL_SSC_CTL_3                        0x0123
+#define WCD9335_CPE_FLL_FLL_MODE                         0x0124
+#define WCD9335_CPE_FLL_STATUS_0                         0x0125
+#define WCD9335_CPE_FLL_STATUS_1                         0x0126
+#define WCD9335_CPE_FLL_STATUS_2                         0x0127
+#define WCD9335_CPE_FLL_STATUS_3                         0x0128
+#define WCD9335_I2S_FLL_USER_CTL_0                       0x0141
+#define WCD9335_I2S_FLL_USER_CTL_1                       0x0142
+#define WCD9335_I2S_FLL_USER_CTL_2                       0x0143
+#define WCD9335_I2S_FLL_USER_CTL_3                       0x0144
+#define WCD9335_I2S_FLL_USER_CTL_4                       0x0145
+#define WCD9335_I2S_FLL_USER_CTL_5                       0x0146
+#define WCD9335_I2S_FLL_USER_CTL_6                       0x0147
+#define WCD9335_I2S_FLL_USER_CTL_7                       0x0148
+#define WCD9335_I2S_FLL_USER_CTL_8                       0x0149
+#define WCD9335_I2S_FLL_USER_CTL_9                       0x014a
+#define WCD9335_I2S_FLL_L_VAL_CTL_0                      0x014b
+#define WCD9335_I2S_FLL_L_VAL_CTL_1                      0x014c
+#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0                   0x014d
+#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1                   0x014e
+#define WCD9335_I2S_FLL_CONFIG_CTL_0                     0x014f
+#define WCD9335_I2S_FLL_CONFIG_CTL_1                     0x0150
+#define WCD9335_I2S_FLL_CONFIG_CTL_2                     0x0151
+#define WCD9335_I2S_FLL_CONFIG_CTL_3                     0x0152
+#define WCD9335_I2S_FLL_CONFIG_CTL_4                     0x0153
+#define WCD9335_I2S_FLL_TEST_CTL_0                       0x0154
+#define WCD9335_I2S_FLL_TEST_CTL_1                       0x0155
+#define WCD9335_I2S_FLL_TEST_CTL_2                       0x0156
+#define WCD9335_I2S_FLL_TEST_CTL_3                       0x0157
+#define WCD9335_I2S_FLL_TEST_CTL_4                       0x0158
+#define WCD9335_I2S_FLL_TEST_CTL_5                       0x0159
+#define WCD9335_I2S_FLL_TEST_CTL_6                       0x015a
+#define WCD9335_I2S_FLL_TEST_CTL_7                       0x015b
+#define WCD9335_I2S_FLL_FREQ_CTL_0                       0x015c
+#define WCD9335_I2S_FLL_FREQ_CTL_1                       0x015d
+#define WCD9335_I2S_FLL_FREQ_CTL_2                       0x015e
+#define WCD9335_I2S_FLL_FREQ_CTL_3                       0x015f
+#define WCD9335_I2S_FLL_SSC_CTL_0                        0x0160
+#define WCD9335_I2S_FLL_SSC_CTL_1                        0x0161
+#define WCD9335_I2S_FLL_SSC_CTL_2                        0x0162
+#define WCD9335_I2S_FLL_SSC_CTL_3                        0x0163
+#define WCD9335_I2S_FLL_FLL_MODE                         0x0164
+#define WCD9335_I2S_FLL_STATUS_0                         0x0165
+#define WCD9335_I2S_FLL_STATUS_1                         0x0166
+#define WCD9335_I2S_FLL_STATUS_2                         0x0167
+#define WCD9335_I2S_FLL_STATUS_3                         0x0168
+#define WCD9335_SB_FLL_USER_CTL_0                        0x0181
+#define WCD9335_SB_FLL_USER_CTL_1                        0x0182
+#define WCD9335_SB_FLL_USER_CTL_2                        0x0183
+#define WCD9335_SB_FLL_USER_CTL_3                        0x0184
+#define WCD9335_SB_FLL_USER_CTL_4                        0x0185
+#define WCD9335_SB_FLL_USER_CTL_5                        0x0186
+#define WCD9335_SB_FLL_USER_CTL_6                        0x0187
+#define WCD9335_SB_FLL_USER_CTL_7                        0x0188
+#define WCD9335_SB_FLL_USER_CTL_8                        0x0189
+#define WCD9335_SB_FLL_USER_CTL_9                        0x018a
+#define WCD9335_SB_FLL_L_VAL_CTL_0                       0x018b
+#define WCD9335_SB_FLL_L_VAL_CTL_1                       0x018c
+#define WCD9335_SB_FLL_DSM_FRAC_CTL_0                    0x018d
+#define WCD9335_SB_FLL_DSM_FRAC_CTL_1                    0x018e
+#define WCD9335_SB_FLL_CONFIG_CTL_0                      0x018f
+#define WCD9335_SB_FLL_CONFIG_CTL_1                      0x0190
+#define WCD9335_SB_FLL_CONFIG_CTL_2                      0x0191
+#define WCD9335_SB_FLL_CONFIG_CTL_3                      0x0192
+#define WCD9335_SB_FLL_CONFIG_CTL_4                      0x0193
+#define WCD9335_SB_FLL_TEST_CTL_0                        0x0194
+#define WCD9335_SB_FLL_TEST_CTL_1                        0x0195
+#define WCD9335_SB_FLL_TEST_CTL_2                        0x0196
+#define WCD9335_SB_FLL_TEST_CTL_3                        0x0197
+#define WCD9335_SB_FLL_TEST_CTL_4                        0x0198
+#define WCD9335_SB_FLL_TEST_CTL_5                        0x0199
+#define WCD9335_SB_FLL_TEST_CTL_6                        0x019a
+#define WCD9335_SB_FLL_TEST_CTL_7                        0x019b
+#define WCD9335_SB_FLL_FREQ_CTL_0                        0x019c
+#define WCD9335_SB_FLL_FREQ_CTL_1                        0x019d
+#define WCD9335_SB_FLL_FREQ_CTL_2                        0x019e
+#define WCD9335_SB_FLL_FREQ_CTL_3                        0x019f
+#define WCD9335_SB_FLL_SSC_CTL_0                         0x01a0
+#define WCD9335_SB_FLL_SSC_CTL_1                         0x01a1
+#define WCD9335_SB_FLL_SSC_CTL_2                         0x01a2
+#define WCD9335_SB_FLL_SSC_CTL_3                         0x01a3
+#define WCD9335_SB_FLL_FLL_MODE                          0x01a4
+#define WCD9335_SB_FLL_STATUS_0                          0x01a5
+#define WCD9335_SB_FLL_STATUS_1                          0x01a6
+#define WCD9335_SB_FLL_STATUS_2                          0x01a7
+#define WCD9335_SB_FLL_STATUS_3                          0x01a8
+
+/* Page-2 Registers */
+#define WCD9335_PAGE2_PAGE_REGISTER                      0x0200
+#define WCD9335_CPE_SS_MEM_PTR_0                         0x0201
+#define WCD9335_CPE_SS_MEM_PTR_1                         0x0202
+#define WCD9335_CPE_SS_MEM_PTR_2                         0x0203
+#define WCD9335_CPE_SS_MEM_CTRL                          0x0205
+#define WCD9335_CPE_SS_MEM_BANK_0                        0x0206
+#define WCD9335_CPE_SS_MEM_BANK_1                        0x0207
+#define WCD9335_CPE_SS_MEM_BANK_2                        0x0208
+#define WCD9335_CPE_SS_MEM_BANK_3                        0x0209
+#define WCD9335_CPE_SS_MEM_BANK_4                        0x020a
+#define WCD9335_CPE_SS_MEM_BANK_5                        0x020b
+#define WCD9335_CPE_SS_MEM_BANK_6                        0x020c
+#define WCD9335_CPE_SS_MEM_BANK_7                        0x020d
+#define WCD9335_CPE_SS_MEM_BANK_8                        0x020e
+#define WCD9335_CPE_SS_MEM_BANK_9                        0x020f
+#define WCD9335_CPE_SS_MEM_BANK_10                       0x0210
+#define WCD9335_CPE_SS_MEM_BANK_11                       0x0211
+#define WCD9335_CPE_SS_MEM_BANK_12                       0x0212
+#define WCD9335_CPE_SS_MEM_BANK_13                       0x0213
+#define WCD9335_CPE_SS_MEM_BANK_14                       0x0214
+#define WCD9335_CPE_SS_MEM_BANK_15                       0x0215
+#define WCD9335_CPE_SS_INBOX1_TRG                        0x0216
+#define WCD9335_CPE_SS_INBOX2_TRG                        0x0217
+#define WCD9335_CPE_SS_INBOX1_0                          0x0218
+#define WCD9335_CPE_SS_INBOX1_1                          0x0219
+#define WCD9335_CPE_SS_INBOX1_2                          0x021a
+#define WCD9335_CPE_SS_INBOX1_3                          0x021b
+#define WCD9335_CPE_SS_INBOX1_4                          0x021c
+#define WCD9335_CPE_SS_INBOX1_5                          0x021d
+#define WCD9335_CPE_SS_INBOX1_6                          0x021e
+#define WCD9335_CPE_SS_INBOX1_7                          0x021f
+#define WCD9335_CPE_SS_INBOX1_8                          0x0220
+#define WCD9335_CPE_SS_INBOX1_9                          0x0221
+#define WCD9335_CPE_SS_INBOX1_10                         0x0222
+#define WCD9335_CPE_SS_INBOX1_11                         0x0223
+#define WCD9335_CPE_SS_INBOX1_12                         0x0224
+#define WCD9335_CPE_SS_INBOX1_13                         0x0225
+#define WCD9335_CPE_SS_INBOX1_14                         0x0226
+#define WCD9335_CPE_SS_INBOX1_15                         0x0227
+#define WCD9335_CPE_SS_OUTBOX1_0                         0x0228
+#define WCD9335_CPE_SS_OUTBOX1_1                         0x0229
+#define WCD9335_CPE_SS_OUTBOX1_2                         0x022a
+#define WCD9335_CPE_SS_OUTBOX1_3                         0x022b
+#define WCD9335_CPE_SS_OUTBOX1_4                         0x022c
+#define WCD9335_CPE_SS_OUTBOX1_5                         0x022d
+#define WCD9335_CPE_SS_OUTBOX1_6                         0x022e
+#define WCD9335_CPE_SS_OUTBOX1_7                         0x022f
+#define WCD9335_CPE_SS_OUTBOX1_8                         0x0230
+#define WCD9335_CPE_SS_OUTBOX1_9                         0x0231
+#define WCD9335_CPE_SS_OUTBOX1_10                        0x0232
+#define WCD9335_CPE_SS_OUTBOX1_11                        0x0233
+#define WCD9335_CPE_SS_OUTBOX1_12                        0x0234
+#define WCD9335_CPE_SS_OUTBOX1_13                        0x0235
+#define WCD9335_CPE_SS_OUTBOX1_14                        0x0236
+#define WCD9335_CPE_SS_OUTBOX1_15                        0x0237
+#define WCD9335_CPE_SS_INBOX2_0                          0x0238
+#define WCD9335_CPE_SS_INBOX2_1                          0x0239
+#define WCD9335_CPE_SS_INBOX2_2                          0x023a
+#define WCD9335_CPE_SS_INBOX2_3                          0x023b
+#define WCD9335_CPE_SS_INBOX2_4                          0x023c
+#define WCD9335_CPE_SS_INBOX2_5                          0x023d
+#define WCD9335_CPE_SS_INBOX2_6                          0x023e
+#define WCD9335_CPE_SS_INBOX2_7                          0x023f
+#define WCD9335_CPE_SS_INBOX2_8                          0x0240
+#define WCD9335_CPE_SS_INBOX2_9                          0x0241
+#define WCD9335_CPE_SS_INBOX2_10                         0x0242
+#define WCD9335_CPE_SS_INBOX2_11                         0x0243
+#define WCD9335_CPE_SS_INBOX2_12                         0x0244
+#define WCD9335_CPE_SS_INBOX2_13                         0x0245
+#define WCD9335_CPE_SS_INBOX2_14                         0x0246
+#define WCD9335_CPE_SS_INBOX2_15                         0x0247
+#define WCD9335_CPE_SS_OUTBOX2_0                         0x0248
+#define WCD9335_CPE_SS_OUTBOX2_1                         0x0249
+#define WCD9335_CPE_SS_OUTBOX2_2                         0x024a
+#define WCD9335_CPE_SS_OUTBOX2_3                         0x024b
+#define WCD9335_CPE_SS_OUTBOX2_4                         0x024c
+#define WCD9335_CPE_SS_OUTBOX2_5                         0x024d
+#define WCD9335_CPE_SS_OUTBOX2_6                         0x024e
+#define WCD9335_CPE_SS_OUTBOX2_7                         0x024f
+#define WCD9335_CPE_SS_OUTBOX2_8                         0x0250
+#define WCD9335_CPE_SS_OUTBOX2_9                         0x0251
+#define WCD9335_CPE_SS_OUTBOX2_10                        0x0252
+#define WCD9335_CPE_SS_OUTBOX2_11                        0x0253
+#define WCD9335_CPE_SS_OUTBOX2_12                        0x0254
+#define WCD9335_CPE_SS_OUTBOX2_13                        0x0255
+#define WCD9335_CPE_SS_OUTBOX2_14                        0x0256
+#define WCD9335_CPE_SS_OUTBOX2_15                        0x0257
+#define WCD9335_CPE_SS_OUTBOX1_ACK                       0x0258
+#define WCD9335_CPE_SS_OUTBOX2_ACK                       0x0259
+#define WCD9335_CPE_SS_EC_BUF_INT_PERIOD                 0x025a
+#define WCD9335_CPE_SS_US_BUF_INT_PERIOD                 0x025b
+#define WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD         0x025c
+#define WCD9335_CPE_SS_CFG                               0x025d
+#define WCD9335_CPE_SS_US_EC_MUX_CFG                     0x025e
+#define WCD9335_CPE_SS_MAD_CTL                           0x025f
+#define WCD9335_CPE_SS_CPAR_CTL                          0x0260
+#define WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD              0x0261
+#define WCD9335_CPE_SS_TX_PP_CFG                         0x0262
+#define WCD9335_CPE_SS_DMIC0_CTL                         0x0263
+#define WCD9335_CPE_SS_DMIC1_CTL                         0x0264
+#define WCD9335_CPE_SS_DMIC2_CTL                         0x0265
+#define WCD9335_CPE_SS_DMIC_CFG                          0x0266
+#define WCD9335_CPE_SS_SVA_CFG                           0x0267
+#define WCD9335_CPE_SS_CPAR_CFG                          0x0271
+#define WCD9335_CPE_SS_WDOG_CFG                          0x0272
+#define WCD9335_CPE_SS_BACKUP_INT                        0x0273
+#define WCD9335_CPE_SS_STATUS                            0x0274
+#define WCD9335_CPE_SS_CPE_OCD_CFG                       0x0275
+#define WCD9335_CPE_SS_SS_ERROR_INT_MASK                 0x0276
+#define WCD9335_CPE_SS_SS_ERROR_INT_STATUS               0x0277
+#define WCD9335_CPE_SS_SS_ERROR_INT_CLEAR                0x0278
+#define WCD9335_SOC_MAD_MAIN_CTL_1                       0x0281
+#define WCD9335_SOC_MAD_MAIN_CTL_2                       0x0282
+#define WCD9335_SOC_MAD_AUDIO_CTL_1                      0x0283
+#define WCD9335_SOC_MAD_AUDIO_CTL_2                      0x0284
+#define WCD9335_SOC_MAD_AUDIO_CTL_3                      0x0285
+#define WCD9335_SOC_MAD_AUDIO_CTL_4                      0x0286
+#define WCD9335_SOC_MAD_AUDIO_CTL_5                      0x0287
+#define WCD9335_SOC_MAD_AUDIO_CTL_6                      0x0288
+#define WCD9335_SOC_MAD_AUDIO_CTL_7                      0x0289
+#define WCD9335_SOC_MAD_AUDIO_CTL_8                      0x028a
+#define WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR                0x028b
+#define WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL                0x028c
+#define WCD9335_SOC_MAD_ULTR_CTL_1                       0x028d
+#define WCD9335_SOC_MAD_ULTR_CTL_2                       0x028e
+#define WCD9335_SOC_MAD_ULTR_CTL_3                       0x028f
+#define WCD9335_SOC_MAD_ULTR_CTL_4                       0x0290
+#define WCD9335_SOC_MAD_ULTR_CTL_5                       0x0291
+#define WCD9335_SOC_MAD_ULTR_CTL_6                       0x0292
+#define WCD9335_SOC_MAD_ULTR_CTL_7                       0x0293
+#define WCD9335_SOC_MAD_BEACON_CTL_1                     0x0294
+#define WCD9335_SOC_MAD_BEACON_CTL_2                     0x0295
+#define WCD9335_SOC_MAD_BEACON_CTL_3                     0x0296
+#define WCD9335_SOC_MAD_BEACON_CTL_4                     0x0297
+#define WCD9335_SOC_MAD_BEACON_CTL_5                     0x0298
+#define WCD9335_SOC_MAD_BEACON_CTL_6                     0x0299
+#define WCD9335_SOC_MAD_BEACON_CTL_7                     0x029a
+#define WCD9335_SOC_MAD_BEACON_CTL_8                     0x029b
+#define WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR               0x029c
+#define WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL               0x029d
+#define WCD9335_SOC_MAD_INP_SEL                          0x029e
+
+/* Page-6 Registers */
+#define WCD9335_PAGE6_PAGE_REGISTER                      0x0600
+#define WCD9335_ANA_BIAS                                 0x0601
+#define WCD9335_ANA_CLK_TOP                              0x0602
+#define WCD9335_ANA_RCO                                  0x0603
+#define WCD9335_ANA_BUCK_VOUT_A                          0x0604
+#define WCD9335_ANA_BUCK_VOUT_D                          0x0605
+#define WCD9335_ANA_BUCK_CTL                             0x0606
+#define WCD9335_ANA_BUCK_STATUS                          0x0607
+#define WCD9335_ANA_RX_SUPPLIES                          0x0608
+#define WCD9335_ANA_HPH                                  0x0609
+#define WCD9335_ANA_EAR                                  0x060a
+#define WCD9335_ANA_LO_1_2                               0x060b
+#define WCD9335_ANA_LO_3_4                               0x060c
+#define WCD9335_ANA_MAD_SETUP                            0x060d
+#define WCD9335_ANA_AMIC1                                0x060e
+#define WCD9335_ANA_AMIC2                                0x060f
+#define WCD9335_ANA_AMIC3                                0x0610
+#define WCD9335_ANA_AMIC4                                0x0611
+#define WCD9335_ANA_AMIC5                                0x0612
+#define WCD9335_ANA_AMIC6                                0x0613
+#define WCD9335_ANA_MBHC_MECH                            0x0614
+#define WCD9335_ANA_MBHC_ELECT                           0x0615
+#define WCD9335_ANA_MBHC_ZDET                            0x0616
+#define WCD9335_ANA_MBHC_RESULT_1                        0x0617
+#define WCD9335_ANA_MBHC_RESULT_2                        0x0618
+#define WCD9335_ANA_MBHC_RESULT_3                        0x0619
+#define WCD9335_ANA_MBHC_BTN0                            0x061a
+#define WCD9335_ANA_MBHC_BTN1                            0x061b
+#define WCD9335_ANA_MBHC_BTN2                            0x061c
+#define WCD9335_ANA_MBHC_BTN3                            0x061d
+#define WCD9335_ANA_MBHC_BTN4                            0x061e
+#define WCD9335_ANA_MBHC_BTN5                            0x061f
+#define WCD9335_ANA_MBHC_BTN6                            0x0620
+#define WCD9335_ANA_MBHC_BTN7                            0x0621
+#define WCD9335_ANA_MICB1                                0x0622
+#define WCD9335_ANA_MICB2                                0x0623
+#define WCD9335_ANA_MICB2_RAMP                           0x0624
+#define WCD9335_ANA_MICB3                                0x0625
+#define WCD9335_ANA_MICB4                                0x0626
+#define WCD9335_ANA_VBADC                                0x0627
+#define WCD9335_BIAS_CTL                                 0x0628
+#define WCD9335_BIAS_VBG_FINE_ADJ                        0x0629
+#define WCD9335_CLOCK_TEST_CTL                           0x062d
+#define WCD9335_RCO_CTRL_1                               0x062e
+#define WCD9335_RCO_CTRL_2                               0x062f
+#define WCD9335_RCO_CAL                                  0x0630
+#define WCD9335_RCO_CAL_1                                0x0631
+#define WCD9335_RCO_CAL_2                                0x0632
+#define WCD9335_RCO_TEST_CTRL                            0x0633
+#define WCD9335_RCO_CAL_OUT_1                            0x0634
+#define WCD9335_RCO_CAL_OUT_2                            0x0635
+#define WCD9335_RCO_CAL_OUT_3                            0x0636
+#define WCD9335_RCO_CAL_OUT_4                            0x0637
+#define WCD9335_RCO_CAL_OUT_5                            0x0638
+#define WCD9335_SIDO_SIDO_MODE_1                         0x063a
+#define WCD9335_SIDO_SIDO_MODE_2                         0x063b
+#define WCD9335_SIDO_SIDO_MODE_3                         0x063c
+#define WCD9335_SIDO_SIDO_MODE_4                         0x063d
+#define WCD9335_SIDO_SIDO_VCL_1                          0x063e
+#define WCD9335_SIDO_SIDO_VCL_2                          0x063f
+#define WCD9335_SIDO_SIDO_VCL_3                          0x0640
+#define WCD9335_SIDO_SIDO_CCL_1                          0x0641
+#define WCD9335_SIDO_SIDO_CCL_2                          0x0642
+#define WCD9335_SIDO_SIDO_CCL_3                          0x0643
+#define WCD9335_SIDO_SIDO_CCL_4                          0x0644
+#define WCD9335_SIDO_SIDO_CCL_5                          0x0645
+#define WCD9335_SIDO_SIDO_CCL_6                          0x0646
+#define WCD9335_SIDO_SIDO_CCL_7                          0x0647
+#define WCD9335_SIDO_SIDO_CCL_8                          0x0648
+#define WCD9335_SIDO_SIDO_CCL_9                          0x0649
+#define WCD9335_SIDO_SIDO_CCL_10                         0x064a
+#define WCD9335_SIDO_SIDO_FILTER_1                       0x064b
+#define WCD9335_SIDO_SIDO_FILTER_2                       0x064c
+#define WCD9335_SIDO_SIDO_DRIVER_1                       0x064d
+#define WCD9335_SIDO_SIDO_DRIVER_2                       0x064e
+#define WCD9335_SIDO_SIDO_DRIVER_3                       0x064f
+#define WCD9335_SIDO_SIDO_CAL_CODE_EXT_1                 0x0650
+#define WCD9335_SIDO_SIDO_CAL_CODE_EXT_2                 0x0651
+#define WCD9335_SIDO_SIDO_CAL_CODE_OUT_1                 0x0652
+#define WCD9335_SIDO_SIDO_CAL_CODE_OUT_2                 0x0653
+#define WCD9335_SIDO_SIDO_TEST_1                         0x0654
+#define WCD9335_SIDO_SIDO_TEST_2                         0x0655
+#define WCD9335_MBHC_CTL_1                               0x0656
+#define WCD9335_MBHC_CTL_2                               0x0657
+#define WCD9335_MBHC_PLUG_DETECT_CTL                     0x0658
+#define WCD9335_MBHC_ZDET_ANA_CTL                        0x0659
+#define WCD9335_MBHC_ZDET_RAMP_CTL                       0x065a
+#define WCD9335_MBHC_FSM_DEBUG                           0x065b /* v1.x */
+#define WCD9335_MBHC_FSM_STATUS                          0x065b /* v2.0 */
+#define WCD9335_MBHC_TEST_CTL                            0x065c
+#define WCD9335_VBADC_SUBBLOCK_EN                        0x065d
+#define WCD9335_VBADC_IBIAS_FE                           0x065e
+#define WCD9335_VBADC_BIAS_ADC                           0x065f
+#define WCD9335_VBADC_FE_CTRL                            0x0660
+#define WCD9335_VBADC_ADC_REF                            0x0661
+#define WCD9335_VBADC_ADC_IO                             0x0662
+#define WCD9335_VBADC_ADC_SAR                            0x0663
+#define WCD9335_VBADC_DEBUG                              0x0664
+#define WCD9335_VBADC_ADC_DOUTMSB                        0x0665
+#define WCD9335_VBADC_ADC_DOUTLSB                        0x0666
+#define WCD9335_LDOH_MODE                                0x0667
+#define WCD9335_LDOH_BIAS                                0x0668
+#define WCD9335_LDOH_STB_LOADS                           0x0669
+#define WCD9335_LDOH_SLOWRAMP                            0x066a
+#define WCD9335_MICB1_TEST_CTL_1                         0x066b
+#define WCD9335_MICB1_TEST_CTL_2                         0x066c
+#define WCD9335_MICB1_TEST_CTL_3                         0x066d
+#define WCD9335_MICB2_TEST_CTL_1                         0x066e
+#define WCD9335_MICB2_TEST_CTL_2                         0x066f
+#define WCD9335_MICB2_TEST_CTL_3                         0x0670
+#define WCD9335_MICB3_TEST_CTL_1                         0x0671
+#define WCD9335_MICB3_TEST_CTL_2                         0x0672
+#define WCD9335_MICB3_TEST_CTL_3                         0x0673
+#define WCD9335_MICB4_TEST_CTL_1                         0x0674
+#define WCD9335_MICB4_TEST_CTL_2                         0x0675
+#define WCD9335_MICB4_TEST_CTL_3                         0x0676
+#define WCD9335_TX_COM_ADC_VCM                           0x0677
+#define WCD9335_TX_COM_BIAS_ATEST                        0x0678
+#define WCD9335_TX_COM_ADC_INT1_IB                       0x0679
+#define WCD9335_TX_COM_ADC_INT2_IB                       0x067a
+#define WCD9335_TX_COM_TXFE_DIV_CTL                      0x067b
+#define WCD9335_TX_COM_TXFE_DIV_START                    0x067c
+#define WCD9335_TX_COM_TXFE_DIV_STOP_9P6M                0x067d
+#define WCD9335_TX_COM_TXFE_DIV_STOP_12P288M             0x067e
+#define WCD9335_TX_1_2_TEST_EN                           0x067f
+#define WCD9335_TX_1_2_ADC_IB                            0x0680
+#define WCD9335_TX_1_2_ATEST_REFCTL                      0x0681
+#define WCD9335_TX_1_2_TEST_CTL                          0x0682
+#define WCD9335_TX_1_2_TEST_BLK_EN                       0x0683
+#define WCD9335_TX_1_2_TXFE_CLKDIV                       0x0684
+#define WCD9335_TX_1_2_SAR1_ERR                          0x0685
+#define WCD9335_TX_1_2_SAR2_ERR                          0x0686
+#define WCD9335_TX_3_4_TEST_EN                           0x0687
+#define WCD9335_TX_3_4_ADC_IB                            0x0688
+#define WCD9335_TX_3_4_ATEST_REFCTL                      0x0689
+#define WCD9335_TX_3_4_TEST_CTL                          0x068a
+#define WCD9335_TX_3_4_TEST_BLK_EN                       0x068b
+#define WCD9335_TX_3_4_TXFE_CLKDIV                       0x068c
+#define WCD9335_TX_3_4_SAR1_ERR                          0x068d
+#define WCD9335_TX_3_4_SAR2_ERR                          0x068e
+#define WCD9335_TX_5_6_TEST_EN                           0x068f
+#define WCD9335_TX_5_6_ADC_IB                            0x0690
+#define WCD9335_TX_5_6_ATEST_REFCTL                      0x0691
+#define WCD9335_TX_5_6_TEST_CTL                          0x0692
+#define WCD9335_TX_5_6_TEST_BLK_EN                       0x0693
+#define WCD9335_TX_5_6_TXFE_CLKDIV                       0x0694
+#define WCD9335_TX_5_6_SAR1_ERR                          0x0695
+#define WCD9335_TX_5_6_SAR2_ERR                          0x0696
+#define WCD9335_CLASSH_MODE_1                            0x0697
+#define WCD9335_CLASSH_MODE_2                            0x0698
+#define WCD9335_CLASSH_MODE_3                            0x0699
+#define WCD9335_CLASSH_CTRL_VCL_1                        0x069a
+#define WCD9335_CLASSH_CTRL_VCL_2                        0x069b
+#define WCD9335_CLASSH_CTRL_CCL_1                        0x069c
+#define WCD9335_CLASSH_CTRL_CCL_2                        0x069d
+#define WCD9335_CLASSH_CTRL_CCL_3                        0x069e
+#define WCD9335_CLASSH_CTRL_CCL_4                        0x069f
+#define WCD9335_CLASSH_CTRL_CCL_5                        0x06a0
+#define WCD9335_CLASSH_BUCK_TMUX_A_D                     0x06a1
+#define WCD9335_CLASSH_BUCK_SW_DRV_CNTL                  0x06a2
+#define WCD9335_CLASSH_SPARE                             0x06a3
+#define WCD9335_FLYBACK_EN                               0x06a4
+#define WCD9335_FLYBACK_VNEG_CTRL_1                      0x06a5
+#define WCD9335_FLYBACK_VNEG_CTRL_2                      0x06a6
+#define WCD9335_FLYBACK_VNEG_CTRL_3                      0x06a7
+#define WCD9335_FLYBACK_VNEG_CTRL_4                      0x06a8
+#define WCD9335_FLYBACK_VNEG_CTRL_5                      0x06a9
+#define WCD9335_FLYBACK_VNEG_CTRL_6                      0x06aa
+#define WCD9335_FLYBACK_VNEG_CTRL_7                      0x06ab
+#define WCD9335_FLYBACK_VNEG_CTRL_8                      0x06ac
+#define WCD9335_FLYBACK_VNEG_CTRL_9                      0x06ad
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_1                  0x06ae
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_2                  0x06af
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_3                  0x06b0
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_4                  0x06b1 /* v1.x */
+#define WCD9335_FLYBACK_CTRL_1                           0x06b1 /* v2.0 */
+#define WCD9335_FLYBACK_TEST_CTL                         0x06b2
+#define WCD9335_RX_AUX_SW_CTL                            0x06b3
+#define WCD9335_RX_PA_AUX_IN_CONN                        0x06b4
+#define WCD9335_RX_TIMER_DIV                             0x06b5
+#define WCD9335_RX_OCP_CTL                               0x06b6
+#define WCD9335_RX_OCP_COUNT                             0x06b7
+#define WCD9335_RX_BIAS_EAR_DAC                          0x06b8
+#define WCD9335_RX_BIAS_EAR_AMP                          0x06b9
+#define WCD9335_RX_BIAS_HPH_LDO                          0x06ba
+#define WCD9335_RX_BIAS_HPH_PA                           0x06bb
+#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2                0x06bc
+#define WCD9335_RX_BIAS_HPH_RDAC_LDO                     0x06bd
+#define WCD9335_RX_BIAS_HPH_CNP1                         0x06be
+#define WCD9335_RX_BIAS_HPH_LOWPOWER                     0x06bf
+#define WCD9335_RX_BIAS_DIFFLO_PA                        0x06c0
+#define WCD9335_RX_BIAS_DIFFLO_REF                       0x06c1
+#define WCD9335_RX_BIAS_DIFFLO_LDO                       0x06c2
+#define WCD9335_RX_BIAS_SELO_DAC_PA                      0x06c3
+#define WCD9335_RX_BIAS_BUCK_RST                         0x06c4
+#define WCD9335_RX_BIAS_BUCK_VREF_ERRAMP                 0x06c5
+#define WCD9335_RX_BIAS_FLYB_ERRAMP                      0x06c6
+#define WCD9335_RX_BIAS_FLYB_BUFF                        0x06c7
+#define WCD9335_RX_BIAS_FLYB_MID_RST                     0x06c8
+#define WCD9335_HPH_L_STATUS                             0x06c9
+#define WCD9335_HPH_R_STATUS                             0x06ca
+#define WCD9335_HPH_CNP_EN                               0x06cb
+#define WCD9335_HPH_CNP_WG_CTL                           0x06cc
+#define WCD9335_HPH_CNP_WG_TIME                          0x06cd
+#define WCD9335_HPH_OCP_CTL                              0x06ce
+#define WCD9335_HPH_AUTO_CHOP                            0x06cf
+#define WCD9335_HPH_CHOP_CTL                             0x06d0
+#define WCD9335_HPH_PA_CTL1                              0x06d1
+#define WCD9335_HPH_PA_CTL2                              0x06d2
+#define WCD9335_HPH_L_EN                                 0x06d3
+#define WCD9335_HPH_L_TEST                               0x06d4
+#define WCD9335_HPH_L_ATEST                              0x06d5
+#define WCD9335_HPH_R_EN                                 0x06d6
+#define WCD9335_HPH_R_TEST                               0x06d7
+#define WCD9335_HPH_R_ATEST                              0x06d8
+#define WCD9335_HPH_RDAC_CLK_CTL1                        0x06d9
+#define WCD9335_HPH_RDAC_CLK_CTL2                        0x06da
+#define WCD9335_HPH_RDAC_LDO_CTL                         0x06db
+#define WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL                 0x06dc
+#define WCD9335_HPH_REFBUFF_UHQA_CTL                     0x06dd
+#define WCD9335_HPH_REFBUFF_LP_CTL                       0x06de
+#define WCD9335_HPH_L_DAC_CTL                            0x06df
+#define WCD9335_HPH_R_DAC_CTL                            0x06e0
+#define WCD9335_EAR_EN_REG                               0x06e1
+#define WCD9335_EAR_CMBUFF                               0x06e2
+#define WCD9335_EAR_ICTL                                 0x06e3
+#define WCD9335_EAR_EN_DBG_CTL                           0x06e4
+#define WCD9335_EAR_CNP                                  0x06e5
+#define WCD9335_EAR_DAC_CTL_ATEST                        0x06e6
+#define WCD9335_EAR_STATUS_REG                           0x06e7
+#define WCD9335_EAR_OUT_SHORT                            0x06e8
+#define WCD9335_DIFF_LO_MISC                             0x06e9
+#define WCD9335_DIFF_LO_LO2_COMPANDER                    0x06ea
+#define WCD9335_DIFF_LO_LO1_COMPANDER                    0x06eb
+#define WCD9335_DIFF_LO_COMMON                           0x06ec
+#define WCD9335_DIFF_LO_BYPASS_EN                        0x06ed
+#define WCD9335_DIFF_LO_CNP                              0x06ee
+#define WCD9335_DIFF_LO_CORE_OUT_PROG                    0x06ef
+#define WCD9335_DIFF_LO_LDO_OUT_PROG                     0x06f0
+#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ            0x06f1
+#define WCD9335_DIFF_LO_COM_PA_FREQ                      0x06f2
+#define WCD9335_DIFF_LO_RESERVED_REG                     0x06f3
+#define WCD9335_DIFF_LO_LO1_STATUS_1                     0x06f4
+#define WCD9335_DIFF_LO_LO1_STATUS_2                     0x06f5
+#define WCD9335_SE_LO_COM1                               0x06f6
+#define WCD9335_SE_LO_COM2                               0x06f7
+#define WCD9335_SE_LO_LO3_GAIN                           0x06f8
+#define WCD9335_SE_LO_LO3_CTRL                           0x06f9
+#define WCD9335_SE_LO_LO4_GAIN                           0x06fa
+#define WCD9335_SE_LO_LO4_CTRL                           0x06fb
+#define WCD9335_SE_LO_LO3_STATUS                         0x06fe
+#define WCD9335_SE_LO_LO4_STATUS                         0x06ff
+
+/* Page-10 Registers */
+#define WCD9335_PAGE10_PAGE_REGISTER                     0x0a00
+#define WCD9335_CDC_ANC0_CLK_RESET_CTL                   0x0a01
+#define WCD9335_CDC_ANC0_MODE_1_CTL                      0x0a02
+#define WCD9335_CDC_ANC0_MODE_2_CTL                      0x0a03
+#define WCD9335_CDC_ANC0_FF_SHIFT                        0x0a04
+#define WCD9335_CDC_ANC0_FB_SHIFT                        0x0a05
+#define WCD9335_CDC_ANC0_LPF_FF_A_CTL                    0x0a06
+#define WCD9335_CDC_ANC0_LPF_FF_B_CTL                    0x0a07
+#define WCD9335_CDC_ANC0_LPF_FB_CTL                      0x0a08
+#define WCD9335_CDC_ANC0_SMLPF_CTL                       0x0a09
+#define WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL                 0x0a0a
+#define WCD9335_CDC_ANC0_IIR_ADAPT_CTL                   0x0a0b
+#define WCD9335_CDC_ANC0_IIR_COEFF_1_CTL                 0x0a0c
+#define WCD9335_CDC_ANC0_IIR_COEFF_2_CTL                 0x0a0d
+#define WCD9335_CDC_ANC0_FF_A_GAIN_CTL                   0x0a0e
+#define WCD9335_CDC_ANC0_FF_B_GAIN_CTL                   0x0a0f
+#define WCD9335_CDC_ANC0_FB_GAIN_CTL                     0x0a10
+#define WCD9335_CDC_ANC1_CLK_RESET_CTL                   0x0a19
+#define WCD9335_CDC_ANC1_MODE_1_CTL                      0x0a1a
+#define WCD9335_CDC_ANC1_MODE_2_CTL                      0x0a1b
+#define WCD9335_CDC_ANC1_FF_SHIFT                        0x0a1c
+#define WCD9335_CDC_ANC1_FB_SHIFT                        0x0a1d
+#define WCD9335_CDC_ANC1_LPF_FF_A_CTL                    0x0a1e
+#define WCD9335_CDC_ANC1_LPF_FF_B_CTL                    0x0a1f
+#define WCD9335_CDC_ANC1_LPF_FB_CTL                      0x0a20
+#define WCD9335_CDC_ANC1_SMLPF_CTL                       0x0a21
+#define WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL                 0x0a22
+#define WCD9335_CDC_ANC1_IIR_ADAPT_CTL                   0x0a23
+#define WCD9335_CDC_ANC1_IIR_COEFF_1_CTL                 0x0a24
+#define WCD9335_CDC_ANC1_IIR_COEFF_2_CTL                 0x0a25
+#define WCD9335_CDC_ANC1_FF_A_GAIN_CTL                   0x0a26
+#define WCD9335_CDC_ANC1_FF_B_GAIN_CTL                   0x0a27
+#define WCD9335_CDC_ANC1_FB_GAIN_CTL                     0x0a28
+#define WCD9335_CDC_TX0_TX_PATH_CTL                      0x0a31
+#define WCD9335_CDC_TX0_TX_PATH_CFG0                     0x0a32
+#define WCD9335_CDC_TX0_TX_PATH_CFG1                     0x0a33
+#define WCD9335_CDC_TX0_TX_VOL_CTL                       0x0a34
+#define WCD9335_CDC_TX0_TX_PATH_192_CTL                  0x0a35
+#define WCD9335_CDC_TX0_TX_PATH_192_CFG                  0x0a36
+#define WCD9335_CDC_TX0_TX_PATH_SEC0                     0x0a37
+#define WCD9335_CDC_TX0_TX_PATH_SEC1                     0x0a38
+#define WCD9335_CDC_TX0_TX_PATH_SEC2                     0x0a39
+#define WCD9335_CDC_TX0_TX_PATH_SEC3                     0x0a3a
+#define WCD9335_CDC_TX0_TX_PATH_SEC4                     0x0a3b
+#define WCD9335_CDC_TX0_TX_PATH_SEC5                     0x0a3c
+#define WCD9335_CDC_TX0_TX_PATH_SEC6                     0x0a3d
+#define WCD9335_CDC_TX0_TX_PATH_SEC7                     0x0a3e
+#define WCD9335_CDC_TX1_TX_PATH_CTL                      0x0a41
+#define WCD9335_CDC_TX1_TX_PATH_CFG0                     0x0a42
+#define WCD9335_CDC_TX1_TX_PATH_CFG1                     0x0a43
+#define WCD9335_CDC_TX1_TX_VOL_CTL                       0x0a44
+#define WCD9335_CDC_TX1_TX_PATH_192_CTL                  0x0a45
+#define WCD9335_CDC_TX1_TX_PATH_192_CFG                  0x0a46
+#define WCD9335_CDC_TX1_TX_PATH_SEC0                     0x0a47
+#define WCD9335_CDC_TX1_TX_PATH_SEC1                     0x0a48
+#define WCD9335_CDC_TX1_TX_PATH_SEC2                     0x0a49
+#define WCD9335_CDC_TX1_TX_PATH_SEC3                     0x0a4a
+#define WCD9335_CDC_TX1_TX_PATH_SEC4                     0x0a4b
+#define WCD9335_CDC_TX1_TX_PATH_SEC5                     0x0a4c
+#define WCD9335_CDC_TX1_TX_PATH_SEC6                     0x0a4d
+#define WCD9335_CDC_TX2_TX_PATH_CTL                      0x0a51
+#define WCD9335_CDC_TX2_TX_PATH_CFG0                     0x0a52
+#define WCD9335_CDC_TX2_TX_PATH_CFG1                     0x0a53
+#define WCD9335_CDC_TX2_TX_VOL_CTL                       0x0a54
+#define WCD9335_CDC_TX2_TX_PATH_192_CTL                  0x0a55
+#define WCD9335_CDC_TX2_TX_PATH_192_CFG                  0x0a56
+#define WCD9335_CDC_TX2_TX_PATH_SEC0                     0x0a57
+#define WCD9335_CDC_TX2_TX_PATH_SEC1                     0x0a58
+#define WCD9335_CDC_TX2_TX_PATH_SEC2                     0x0a59
+#define WCD9335_CDC_TX2_TX_PATH_SEC3                     0x0a5a
+#define WCD9335_CDC_TX2_TX_PATH_SEC4                     0x0a5b
+#define WCD9335_CDC_TX2_TX_PATH_SEC5                     0x0a5c
+#define WCD9335_CDC_TX2_TX_PATH_SEC6                     0x0a5d
+#define WCD9335_CDC_TX3_TX_PATH_CTL                      0x0a61
+#define WCD9335_CDC_TX3_TX_PATH_CFG0                     0x0a62
+#define WCD9335_CDC_TX3_TX_PATH_CFG1                     0x0a63
+#define WCD9335_CDC_TX3_TX_VOL_CTL                       0x0a64
+#define WCD9335_CDC_TX3_TX_PATH_192_CTL                  0x0a65
+#define WCD9335_CDC_TX3_TX_PATH_192_CFG                  0x0a66
+#define WCD9335_CDC_TX3_TX_PATH_SEC0                     0x0a67
+#define WCD9335_CDC_TX3_TX_PATH_SEC1                     0x0a68
+#define WCD9335_CDC_TX3_TX_PATH_SEC2                     0x0a69
+#define WCD9335_CDC_TX3_TX_PATH_SEC3                     0x0a6a
+#define WCD9335_CDC_TX3_TX_PATH_SEC4                     0x0a6b
+#define WCD9335_CDC_TX3_TX_PATH_SEC5                     0x0a6c
+#define WCD9335_CDC_TX3_TX_PATH_SEC6                     0x0a6d
+#define WCD9335_CDC_TX4_TX_PATH_CTL                      0x0a71
+#define WCD9335_CDC_TX4_TX_PATH_CFG0                     0x0a72
+#define WCD9335_CDC_TX4_TX_PATH_CFG1                     0x0a73
+#define WCD9335_CDC_TX4_TX_VOL_CTL                       0x0a74
+#define WCD9335_CDC_TX4_TX_PATH_192_CTL                  0x0a75
+#define WCD9335_CDC_TX4_TX_PATH_192_CFG                  0x0a76
+#define WCD9335_CDC_TX4_TX_PATH_SEC0                     0x0a77
+#define WCD9335_CDC_TX4_TX_PATH_SEC1                     0x0a78
+#define WCD9335_CDC_TX4_TX_PATH_SEC2                     0x0a79
+#define WCD9335_CDC_TX4_TX_PATH_SEC3                     0x0a7a
+#define WCD9335_CDC_TX4_TX_PATH_SEC4                     0x0a7b
+#define WCD9335_CDC_TX4_TX_PATH_SEC5                     0x0a7c
+#define WCD9335_CDC_TX4_TX_PATH_SEC6                     0x0a7d
+#define WCD9335_CDC_TX5_TX_PATH_CTL                      0x0a81
+#define WCD9335_CDC_TX5_TX_PATH_CFG0                     0x0a82
+#define WCD9335_CDC_TX5_TX_PATH_CFG1                     0x0a83
+#define WCD9335_CDC_TX5_TX_VOL_CTL                       0x0a84
+#define WCD9335_CDC_TX5_TX_PATH_192_CTL                  0x0a85
+#define WCD9335_CDC_TX5_TX_PATH_192_CFG                  0x0a86
+#define WCD9335_CDC_TX5_TX_PATH_SEC0                     0x0a87
+#define WCD9335_CDC_TX5_TX_PATH_SEC1                     0x0a88
+#define WCD9335_CDC_TX5_TX_PATH_SEC2                     0x0a89
+#define WCD9335_CDC_TX5_TX_PATH_SEC3                     0x0a8a
+#define WCD9335_CDC_TX5_TX_PATH_SEC4                     0x0a8b
+#define WCD9335_CDC_TX5_TX_PATH_SEC5                     0x0a8c
+#define WCD9335_CDC_TX5_TX_PATH_SEC6                     0x0a8d
+#define WCD9335_CDC_TX6_TX_PATH_CTL                      0x0a91
+#define WCD9335_CDC_TX6_TX_PATH_CFG0                     0x0a92
+#define WCD9335_CDC_TX6_TX_PATH_CFG1                     0x0a93
+#define WCD9335_CDC_TX6_TX_VOL_CTL                       0x0a94
+#define WCD9335_CDC_TX6_TX_PATH_192_CTL                  0x0a95
+#define WCD9335_CDC_TX6_TX_PATH_192_CFG                  0x0a96
+#define WCD9335_CDC_TX6_TX_PATH_SEC0                     0x0a97
+#define WCD9335_CDC_TX6_TX_PATH_SEC1                     0x0a98
+#define WCD9335_CDC_TX6_TX_PATH_SEC2                     0x0a99
+#define WCD9335_CDC_TX6_TX_PATH_SEC3                     0x0a9a
+#define WCD9335_CDC_TX6_TX_PATH_SEC4                     0x0a9b
+#define WCD9335_CDC_TX6_TX_PATH_SEC5                     0x0a9c
+#define WCD9335_CDC_TX6_TX_PATH_SEC6                     0x0a9d
+#define WCD9335_CDC_TX7_TX_PATH_CTL                      0x0aa1
+#define WCD9335_CDC_TX7_TX_PATH_CFG0                     0x0aa2
+#define WCD9335_CDC_TX7_TX_PATH_CFG1                     0x0aa3
+#define WCD9335_CDC_TX7_TX_VOL_CTL                       0x0aa4
+#define WCD9335_CDC_TX7_TX_PATH_192_CTL                  0x0aa5
+#define WCD9335_CDC_TX7_TX_PATH_192_CFG                  0x0aa6
+#define WCD9335_CDC_TX7_TX_PATH_SEC0                     0x0aa7
+#define WCD9335_CDC_TX7_TX_PATH_SEC1                     0x0aa8
+#define WCD9335_CDC_TX7_TX_PATH_SEC2                     0x0aa9
+#define WCD9335_CDC_TX7_TX_PATH_SEC3                     0x0aaa
+#define WCD9335_CDC_TX7_TX_PATH_SEC4                     0x0aab
+#define WCD9335_CDC_TX7_TX_PATH_SEC5                     0x0aac
+#define WCD9335_CDC_TX7_TX_PATH_SEC6                     0x0aad
+#define WCD9335_CDC_TX8_TX_PATH_CTL                      0x0ab1
+#define WCD9335_CDC_TX8_TX_PATH_CFG0                     0x0ab2
+#define WCD9335_CDC_TX8_TX_PATH_CFG1                     0x0ab3
+#define WCD9335_CDC_TX8_TX_VOL_CTL                       0x0ab4
+#define WCD9335_CDC_TX8_TX_PATH_192_CTL                  0x0ab5
+#define WCD9335_CDC_TX8_TX_PATH_192_CFG                  0x0ab6
+#define WCD9335_CDC_TX8_TX_PATH_SEC0                     0x0ab7
+#define WCD9335_CDC_TX8_TX_PATH_SEC1                     0x0ab8
+#define WCD9335_CDC_TX8_TX_PATH_SEC2                     0x0ab9
+#define WCD9335_CDC_TX8_TX_PATH_SEC3                     0x0aba
+#define WCD9335_CDC_TX8_TX_PATH_SEC4                     0x0abb
+#define WCD9335_CDC_TX8_TX_PATH_SEC5                     0x0abc
+#define WCD9335_CDC_TX8_TX_PATH_SEC6                     0x0abd
+#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL               0x0ac2
+#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0              0x0ac3
+#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL              0x0ac6
+#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0             0x0ac7
+#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL              0x0aca
+#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0             0x0acb
+#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL              0x0ace
+#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0             0x0acf
+
+/* Page-11 Registers */
+#define WCD9335_PAGE11_PAGE_REGISTER                     0x0b00
+#define WCD9335_CDC_COMPANDER1_CTL0                      0x0b01
+#define WCD9335_CDC_COMPANDER1_CTL1                      0x0b02
+#define WCD9335_CDC_COMPANDER1_CTL2                      0x0b03
+#define WCD9335_CDC_COMPANDER1_CTL3                      0x0b04
+#define WCD9335_CDC_COMPANDER1_CTL4                      0x0b05
+#define WCD9335_CDC_COMPANDER1_CTL5                      0x0b06
+#define WCD9335_CDC_COMPANDER1_CTL6                      0x0b07
+#define WCD9335_CDC_COMPANDER1_CTL7                      0x0b08
+#define WCD9335_CDC_COMPANDER2_CTL0                      0x0b09
+#define WCD9335_CDC_COMPANDER2_CTL1                      0x0b0a
+#define WCD9335_CDC_COMPANDER2_CTL2                      0x0b0b
+#define WCD9335_CDC_COMPANDER2_CTL3                      0x0b0c
+#define WCD9335_CDC_COMPANDER2_CTL4                      0x0b0d
+#define WCD9335_CDC_COMPANDER2_CTL5                      0x0b0e
+#define WCD9335_CDC_COMPANDER2_CTL6                      0x0b0f
+#define WCD9335_CDC_COMPANDER2_CTL7                      0x0b10
+#define WCD9335_CDC_COMPANDER3_CTL0                      0x0b11
+#define WCD9335_CDC_COMPANDER3_CTL1                      0x0b12
+#define WCD9335_CDC_COMPANDER3_CTL2                      0x0b13
+#define WCD9335_CDC_COMPANDER3_CTL3                      0x0b14
+#define WCD9335_CDC_COMPANDER3_CTL4                      0x0b15
+#define WCD9335_CDC_COMPANDER3_CTL5                      0x0b16
+#define WCD9335_CDC_COMPANDER3_CTL6                      0x0b17
+#define WCD9335_CDC_COMPANDER3_CTL7                      0x0b18
+#define WCD9335_CDC_COMPANDER4_CTL0                      0x0b19
+#define WCD9335_CDC_COMPANDER4_CTL1                      0x0b1a
+#define WCD9335_CDC_COMPANDER4_CTL2                      0x0b1b
+#define WCD9335_CDC_COMPANDER4_CTL3                      0x0b1c
+#define WCD9335_CDC_COMPANDER4_CTL4                      0x0b1d
+#define WCD9335_CDC_COMPANDER4_CTL5                      0x0b1e
+#define WCD9335_CDC_COMPANDER4_CTL6                      0x0b1f
+#define WCD9335_CDC_COMPANDER4_CTL7                      0x0b20
+#define WCD9335_CDC_COMPANDER5_CTL0                      0x0b21
+#define WCD9335_CDC_COMPANDER5_CTL1                      0x0b22
+#define WCD9335_CDC_COMPANDER5_CTL2                      0x0b23
+#define WCD9335_CDC_COMPANDER5_CTL3                      0x0b24
+#define WCD9335_CDC_COMPANDER5_CTL4                      0x0b25
+#define WCD9335_CDC_COMPANDER5_CTL5                      0x0b26
+#define WCD9335_CDC_COMPANDER5_CTL6                      0x0b27
+#define WCD9335_CDC_COMPANDER5_CTL7                      0x0b28
+#define WCD9335_CDC_COMPANDER6_CTL0                      0x0b29
+#define WCD9335_CDC_COMPANDER6_CTL1                      0x0b2a
+#define WCD9335_CDC_COMPANDER6_CTL2                      0x0b2b
+#define WCD9335_CDC_COMPANDER6_CTL3                      0x0b2c
+#define WCD9335_CDC_COMPANDER6_CTL4                      0x0b2d
+#define WCD9335_CDC_COMPANDER6_CTL5                      0x0b2e
+#define WCD9335_CDC_COMPANDER6_CTL6                      0x0b2f
+#define WCD9335_CDC_COMPANDER6_CTL7                      0x0b30
+#define WCD9335_CDC_COMPANDER7_CTL0                      0x0b31
+#define WCD9335_CDC_COMPANDER7_CTL1                      0x0b32
+#define WCD9335_CDC_COMPANDER7_CTL2                      0x0b33
+#define WCD9335_CDC_COMPANDER7_CTL3                      0x0b34
+#define WCD9335_CDC_COMPANDER7_CTL4                      0x0b35
+#define WCD9335_CDC_COMPANDER7_CTL5                      0x0b36
+#define WCD9335_CDC_COMPANDER7_CTL6                      0x0b37
+#define WCD9335_CDC_COMPANDER7_CTL7                      0x0b38
+#define WCD9335_CDC_COMPANDER8_CTL0                      0x0b39
+#define WCD9335_CDC_COMPANDER8_CTL1                      0x0b3a
+#define WCD9335_CDC_COMPANDER8_CTL2                      0x0b3b
+#define WCD9335_CDC_COMPANDER8_CTL3                      0x0b3c
+#define WCD9335_CDC_COMPANDER8_CTL4                      0x0b3d
+#define WCD9335_CDC_COMPANDER8_CTL5                      0x0b3e
+#define WCD9335_CDC_COMPANDER8_CTL6                      0x0b3f
+#define WCD9335_CDC_COMPANDER8_CTL7                      0x0b40
+#define WCD9335_CDC_RX0_RX_PATH_CTL                      0x0b41
+#define WCD9335_CDC_RX0_RX_PATH_CFG0                     0x0b42
+#define WCD9335_CDC_RX0_RX_PATH_CFG1                     0x0b43
+#define WCD9335_CDC_RX0_RX_PATH_CFG2                     0x0b44
+#define WCD9335_CDC_RX0_RX_VOL_CTL                       0x0b45
+#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL                  0x0b46
+#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG                  0x0b47
+#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL                   0x0b48
+#define WCD9335_CDC_RX0_RX_PATH_SEC0                     0x0b49
+#define WCD9335_CDC_RX0_RX_PATH_SEC1                     0x0b4a
+#define WCD9335_CDC_RX0_RX_PATH_SEC2                     0x0b4b
+#define WCD9335_CDC_RX0_RX_PATH_SEC3                     0x0b4c
+#define WCD9335_CDC_RX0_RX_PATH_SEC5                     0x0b4e
+#define WCD9335_CDC_RX0_RX_PATH_SEC6                     0x0b4f
+#define WCD9335_CDC_RX0_RX_PATH_SEC7                     0x0b50
+#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0                 0x0b51
+#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC1                 0x0b52
+#define WCD9335_CDC_RX1_RX_PATH_CTL                      0x0b55
+#define WCD9335_CDC_RX1_RX_PATH_CFG0                     0x0b56
+#define WCD9335_CDC_RX1_RX_PATH_CFG1                     0x0b57
+#define WCD9335_CDC_RX1_RX_PATH_CFG2                     0x0b58
+#define WCD9335_CDC_RX1_RX_VOL_CTL                       0x0b59
+#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL                  0x0b5a
+#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG                  0x0b5b
+#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL                   0x0b5c
+#define WCD9335_CDC_RX1_RX_PATH_SEC0                     0x0b5d
+#define WCD9335_CDC_RX1_RX_PATH_SEC1                     0x0b5e
+#define WCD9335_CDC_RX1_RX_PATH_SEC2                     0x0b5f
+#define WCD9335_CDC_RX1_RX_PATH_SEC3                     0x0b60
+#define WCD9335_CDC_RX1_RX_PATH_SEC4                     0x0b61
+#define WCD9335_CDC_RX1_RX_PATH_SEC5                     0x0b62
+#define WCD9335_CDC_RX1_RX_PATH_SEC6                     0x0b63
+#define WCD9335_CDC_RX1_RX_PATH_SEC7                     0x0b64
+#define WCD9335_CDC_RX1_RX_PATH_MIX_SEC0                 0x0b65
+#define WCD9335_CDC_RX1_RX_PATH_MIX_SEC1                 0x0b66
+#define WCD9335_CDC_RX2_RX_PATH_CTL                      0x0b69
+#define WCD9335_CDC_RX2_RX_PATH_CFG0                     0x0b6a
+#define WCD9335_CDC_RX2_RX_PATH_CFG1                     0x0b6b
+#define WCD9335_CDC_RX2_RX_PATH_CFG2                     0x0b6c
+#define WCD9335_CDC_RX2_RX_VOL_CTL                       0x0b6d
+#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL                  0x0b6e
+#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG                  0x0b6f
+#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL                   0x0b70
+#define WCD9335_CDC_RX2_RX_PATH_SEC0                     0x0b71
+#define WCD9335_CDC_RX2_RX_PATH_SEC1                     0x0b72
+#define WCD9335_CDC_RX2_RX_PATH_SEC2                     0x0b73
+#define WCD9335_CDC_RX2_RX_PATH_SEC3                     0x0b74
+#define WCD9335_CDC_RX2_RX_PATH_SEC4                     0x0b75
+#define WCD9335_CDC_RX2_RX_PATH_SEC5                     0x0b76
+#define WCD9335_CDC_RX2_RX_PATH_SEC6                     0x0b77
+#define WCD9335_CDC_RX2_RX_PATH_SEC7                     0x0b78
+#define WCD9335_CDC_RX2_RX_PATH_MIX_SEC0                 0x0b79
+#define WCD9335_CDC_RX2_RX_PATH_MIX_SEC1                 0x0b7a
+#define WCD9335_CDC_RX3_RX_PATH_CTL                      0x0b7d
+#define WCD9335_CDC_RX3_RX_PATH_CFG0                     0x0b7e
+#define WCD9335_CDC_RX3_RX_PATH_CFG1                     0x0b7f
+#define WCD9335_CDC_RX3_RX_PATH_CFG2                     0x0b80
+#define WCD9335_CDC_RX3_RX_VOL_CTL                       0x0b81
+#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL                  0x0b82
+#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG                  0x0b83
+#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL                   0x0b84
+#define WCD9335_CDC_RX3_RX_PATH_SEC0                     0x0b85
+#define WCD9335_CDC_RX3_RX_PATH_SEC1                     0x0b86
+#define WCD9335_CDC_RX3_RX_PATH_SEC2                     0x0b87
+#define WCD9335_CDC_RX3_RX_PATH_SEC3                     0x0b88
+#define WCD9335_CDC_RX3_RX_PATH_SEC5                     0x0b8a
+#define WCD9335_CDC_RX3_RX_PATH_SEC6                     0x0b8b
+#define WCD9335_CDC_RX3_RX_PATH_SEC7                     0x0b8c
+#define WCD9335_CDC_RX3_RX_PATH_MIX_SEC0                 0x0b8d
+#define WCD9335_CDC_RX3_RX_PATH_MIX_SEC1                 0x0b8e
+#define WCD9335_CDC_RX4_RX_PATH_CTL                      0x0b91
+#define WCD9335_CDC_RX4_RX_PATH_CFG0                     0x0b92
+#define WCD9335_CDC_RX4_RX_PATH_CFG1                     0x0b93
+#define WCD9335_CDC_RX4_RX_PATH_CFG2                     0x0b94
+#define WCD9335_CDC_RX4_RX_VOL_CTL                       0x0b95
+#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL                  0x0b96
+#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG                  0x0b97
+#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL                   0x0b98
+#define WCD9335_CDC_RX4_RX_PATH_SEC0                     0x0b99
+#define WCD9335_CDC_RX4_RX_PATH_SEC1                     0x0b9a
+#define WCD9335_CDC_RX4_RX_PATH_SEC2                     0x0b9b
+#define WCD9335_CDC_RX4_RX_PATH_SEC3                     0x0b9c
+#define WCD9335_CDC_RX4_RX_PATH_SEC5                     0x0b9e
+#define WCD9335_CDC_RX4_RX_PATH_SEC6                     0x0b9f
+#define WCD9335_CDC_RX4_RX_PATH_SEC7                     0x0ba0
+#define WCD9335_CDC_RX4_RX_PATH_MIX_SEC0                 0x0ba1
+#define WCD9335_CDC_RX4_RX_PATH_MIX_SEC1                 0x0ba2
+#define WCD9335_CDC_RX5_RX_PATH_CTL                      0x0ba5
+#define WCD9335_CDC_RX5_RX_PATH_CFG0                     0x0ba6
+#define WCD9335_CDC_RX5_RX_PATH_CFG1                     0x0ba7
+#define WCD9335_CDC_RX5_RX_PATH_CFG2                     0x0ba8
+#define WCD9335_CDC_RX5_RX_VOL_CTL                       0x0ba9
+#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL                  0x0baa
+#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG                  0x0bab
+#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL                   0x0bac
+#define WCD9335_CDC_RX5_RX_PATH_SEC0                     0x0bad
+#define WCD9335_CDC_RX5_RX_PATH_SEC1                     0x0bae
+#define WCD9335_CDC_RX5_RX_PATH_SEC2                     0x0baf
+#define WCD9335_CDC_RX5_RX_PATH_SEC3                     0x0bb0
+#define WCD9335_CDC_RX5_RX_PATH_SEC5                     0x0bb2
+#define WCD9335_CDC_RX5_RX_PATH_SEC6                     0x0bb3
+#define WCD9335_CDC_RX5_RX_PATH_SEC7                     0x0bb4
+#define WCD9335_CDC_RX5_RX_PATH_MIX_SEC0                 0x0bb5
+#define WCD9335_CDC_RX5_RX_PATH_MIX_SEC1                 0x0bb6
+#define WCD9335_CDC_RX6_RX_PATH_CTL                      0x0bb9
+#define WCD9335_CDC_RX6_RX_PATH_CFG0                     0x0bba
+#define WCD9335_CDC_RX6_RX_PATH_CFG1                     0x0bbb
+#define WCD9335_CDC_RX6_RX_PATH_CFG2                     0x0bbc
+#define WCD9335_CDC_RX6_RX_VOL_CTL                       0x0bbd
+#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL                  0x0bbe
+#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG                  0x0bbf
+#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL                   0x0bc0
+#define WCD9335_CDC_RX6_RX_PATH_SEC0                     0x0bc1
+#define WCD9335_CDC_RX6_RX_PATH_SEC1                     0x0bc2
+#define WCD9335_CDC_RX6_RX_PATH_SEC2                     0x0bc3
+#define WCD9335_CDC_RX6_RX_PATH_SEC3                     0x0bc4
+#define WCD9335_CDC_RX6_RX_PATH_SEC5                     0x0bc6
+#define WCD9335_CDC_RX6_RX_PATH_SEC6                     0x0bc7
+#define WCD9335_CDC_RX6_RX_PATH_SEC7                     0x0bc8
+#define WCD9335_CDC_RX6_RX_PATH_MIX_SEC0                 0x0bc9
+#define WCD9335_CDC_RX6_RX_PATH_MIX_SEC1                 0x0bca
+#define WCD9335_CDC_RX7_RX_PATH_CTL                      0x0bcd
+#define WCD9335_CDC_RX7_RX_PATH_CFG0                     0x0bce
+#define WCD9335_CDC_RX7_RX_PATH_CFG1                     0x0bcf
+#define WCD9335_CDC_RX7_RX_PATH_CFG2                     0x0bd0
+#define WCD9335_CDC_RX7_RX_VOL_CTL                       0x0bd1
+#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL                  0x0bd2
+#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG                  0x0bd3
+#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL                   0x0bd4
+#define WCD9335_CDC_RX7_RX_PATH_SEC0                     0x0bd5
+#define WCD9335_CDC_RX7_RX_PATH_SEC1                     0x0bd6
+#define WCD9335_CDC_RX7_RX_PATH_SEC2                     0x0bd7
+#define WCD9335_CDC_RX7_RX_PATH_SEC3                     0x0bd8
+#define WCD9335_CDC_RX7_RX_PATH_SEC5                     0x0bda
+#define WCD9335_CDC_RX7_RX_PATH_SEC6                     0x0bdb
+#define WCD9335_CDC_RX7_RX_PATH_SEC7                     0x0bdc
+#define WCD9335_CDC_RX7_RX_PATH_MIX_SEC0                 0x0bdd
+#define WCD9335_CDC_RX7_RX_PATH_MIX_SEC1                 0x0bde
+#define WCD9335_CDC_RX8_RX_PATH_CTL                      0x0be1
+#define WCD9335_CDC_RX8_RX_PATH_CFG0                     0x0be2
+#define WCD9335_CDC_RX8_RX_PATH_CFG1                     0x0be3
+#define WCD9335_CDC_RX8_RX_PATH_CFG2                     0x0be4
+#define WCD9335_CDC_RX8_RX_VOL_CTL                       0x0be5
+#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL                  0x0be6
+#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG                  0x0be7
+#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL                   0x0be8
+#define WCD9335_CDC_RX8_RX_PATH_SEC0                     0x0be9
+#define WCD9335_CDC_RX8_RX_PATH_SEC1                     0x0bea
+#define WCD9335_CDC_RX8_RX_PATH_SEC2                     0x0beb
+#define WCD9335_CDC_RX8_RX_PATH_SEC3                     0x0bec
+#define WCD9335_CDC_RX8_RX_PATH_SEC5                     0x0bee
+#define WCD9335_CDC_RX8_RX_PATH_SEC6                     0x0bef
+#define WCD9335_CDC_RX8_RX_PATH_SEC7                     0x0bf0
+#define WCD9335_CDC_RX8_RX_PATH_MIX_SEC0                 0x0bf1
+#define WCD9335_CDC_RX8_RX_PATH_MIX_SEC1                 0x0bf2
+
+/* Page-12 Registers */
+#define WCD9335_PAGE12_PAGE_REGISTER                     0x0c00
+#define WCD9335_CDC_CLSH_CRC                             0x0c01
+#define WCD9335_CDC_CLSH_DLY_CTRL                        0x0c02
+#define WCD9335_CDC_CLSH_DECAY_CTRL                      0x0c03
+#define WCD9335_CDC_CLSH_HPH_V_PA                        0x0c04
+#define WCD9335_CDC_CLSH_EAR_V_PA                        0x0c05
+#define WCD9335_CDC_CLSH_HPH_V_HD                        0x0c06
+#define WCD9335_CDC_CLSH_EAR_V_HD                        0x0c07
+#define WCD9335_CDC_CLSH_K1_MSB                          0x0c08
+#define WCD9335_CDC_CLSH_K1_LSB                          0x0c09
+#define WCD9335_CDC_CLSH_K2_MSB                          0x0c0a
+#define WCD9335_CDC_CLSH_K2_LSB                          0x0c0b
+#define WCD9335_CDC_CLSH_IDLE_CTRL                       0x0c0c
+#define WCD9335_CDC_CLSH_IDLE_HPH                        0x0c0d
+#define WCD9335_CDC_CLSH_IDLE_EAR                        0x0c0e
+#define WCD9335_CDC_CLSH_TEST0                           0x0c0f
+#define WCD9335_CDC_CLSH_TEST1                           0x0c10
+#define WCD9335_CDC_CLSH_OVR_VREF                        0x0c11
+#define WCD9335_CDC_BOOST0_BOOST_PATH_CTL                0x0c19
+#define WCD9335_CDC_BOOST0_BOOST_CTL                     0x0c1a
+#define WCD9335_CDC_BOOST0_BOOST_CFG1                    0x0c1b
+#define WCD9335_CDC_BOOST0_BOOST_CFG2                    0x0c1c
+#define WCD9335_CDC_BOOST1_BOOST_PATH_CTL                0x0c21
+#define WCD9335_CDC_BOOST1_BOOST_CTL                     0x0c22
+#define WCD9335_CDC_BOOST1_BOOST_CFG1                    0x0c23
+#define WCD9335_CDC_BOOST1_BOOST_CFG2                    0x0c24
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_0                 0x0c29
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_1                 0x0c2a
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_2                 0x0c2b
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_3                 0x0c2c
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0                 0x0c2d
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1                 0x0c2e
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2                 0x0c2f
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3                 0x0c30
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0                 0x0c31
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1                 0x0c32
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2                 0x0c33
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3                 0x0c34
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_0                 0x0c35
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_1                 0x0c36
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_2                 0x0c37
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_3                 0x0c38
+#define WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG                0x0c39
+#define WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS             0x0c3a
+#define WCD9335_CDC_VBAT_VBAT_PATH_CTL                   0x0c3d
+#define WCD9335_CDC_VBAT_VBAT_CFG                        0x0c3e
+#define WCD9335_CDC_VBAT_VBAT_ADC_CAL1                   0x0c3f
+#define WCD9335_CDC_VBAT_VBAT_ADC_CAL2                   0x0c40
+#define WCD9335_CDC_VBAT_VBAT_ADC_CAL3                   0x0c41
+#define WCD9335_CDC_VBAT_VBAT_PK_EST1                    0x0c42
+#define WCD9335_CDC_VBAT_VBAT_PK_EST2                    0x0c43
+#define WCD9335_CDC_VBAT_VBAT_PK_EST3                    0x0c44
+#define WCD9335_CDC_VBAT_VBAT_RF_PROC1                   0x0c45
+#define WCD9335_CDC_VBAT_VBAT_RF_PROC2                   0x0c46
+#define WCD9335_CDC_VBAT_VBAT_TAC1                       0x0c47
+#define WCD9335_CDC_VBAT_VBAT_TAC2                       0x0c48
+#define WCD9335_CDC_VBAT_VBAT_TAC3                       0x0c49
+#define WCD9335_CDC_VBAT_VBAT_TAC4                       0x0c4a
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD1                  0x0c4b
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD2                  0x0c4c
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD3                  0x0c4d
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD4                  0x0c4e
+#define WCD9335_CDC_VBAT_VBAT_DEBUG1                     0x0c4f
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON               0x0c50
+#define WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL               0x0c51
+#define WCD9335_SPLINE_SRC0_CLK_RST_CTL_0                0x0c55
+#define WCD9335_SPLINE_SRC0_STATUS                       0x0c56
+#define WCD9335_SPLINE_SRC1_CLK_RST_CTL_0                0x0c6d
+#define WCD9335_SPLINE_SRC1_STATUS                       0x0c6e
+#define WCD9335_SPLINE_SRC2_CLK_RST_CTL_0                0x0c85
+#define WCD9335_SPLINE_SRC2_STATUS                       0x0c86
+#define WCD9335_SPLINE_SRC3_CLK_RST_CTL_0                0x0c9d
+#define WCD9335_SPLINE_SRC3_STATUS                       0x0c9e
+#define WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL        0x0cb5
+#define WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1       0x0cb6
+#define WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL        0x0cb9
+#define WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1       0x0cba
+
+/* Page-13 Registers */
+#define WCD9335_PAGE13_PAGE_REGISTER                     0x0d00
+#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0              0x0d01
+#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1              0x0d02
+#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0              0x0d03
+#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1              0x0d04
+#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0              0x0d05
+#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1              0x0d06
+#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0              0x0d07
+#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1              0x0d08
+#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0              0x0d09
+#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1              0x0d0a
+#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0              0x0d0b
+#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1              0x0d0c
+#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0              0x0d0d
+#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1              0x0d0e
+#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0              0x0d0f
+#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1              0x0d10
+#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0              0x0d11
+#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1              0x0d12
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0               0x0d13
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1               0x0d14
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2               0x0d15
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3               0x0d16
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4               0x0d17
+#define WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0         0x0d18
+#define WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1         0x0d19
+#define WCD9335_CDC_RX_INP_MUX_ANC_CFG0                  0x0d1a
+#define WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0           0x0d1b
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0             0x0d1d
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1             0x0d1e
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0             0x0d1f
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1             0x0d20
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0             0x0d21
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1             0x0d22
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0             0x0d23
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1             0x0d24
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0             0x0d25
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0             0x0d26
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0             0x0d27
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0             0x0d28
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0             0x0d29
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0            0x0d2b
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0            0x0d2c
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0            0x0d2d
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0            0x0d2e
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0   0x0d31
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1   0x0d32
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2   0x0d33
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3   0x0d34
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0   0x0d35
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1   0x0d36
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2   0x0d37
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3   0x0d38
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0                0x0d3a
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1                0x0d3b
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2                0x0d3c
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3                0x0d3d
+#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL            0x0d41
+#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL          0x0d42
+#define WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL             0x0d43
+#define WCD9335_CDC_PROX_DETECT_PROX_CTL                 0x0d49
+#define WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0        0x0d4a
+#define WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1        0x0d4b
+#define WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB     0x0d4c
+#define WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB     0x0d4d
+#define WCD9335_CDC_PROX_DETECT_PROX_STATUS              0x0d4e
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL           0x0d4f
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB       0x0d50
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB       0x0d51
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD    0x0d52
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD    0x0d53
+#define WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT      0x0d54
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL           0x0d55
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL        0x0d56
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL        0x0d57
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL        0x0d58
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL        0x0d59
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL        0x0d5a
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL        0x0d5b
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL        0x0d5c
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL        0x0d5d
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_CTL                0x0d5e
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL     0x0d5f
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL        0x0d60
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL        0x0d61
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL           0x0d65
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL        0x0d66
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL        0x0d67
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL        0x0d68
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL        0x0d69
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL        0x0d6a
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL        0x0d6b
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL        0x0d6c
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL        0x0d6d
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_CTL                0x0d6e
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL     0x0d6f
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL        0x0d70
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL        0x0d71
+#define WCD9335_CDC_TOP_TOP_CFG0                         0x0d81
+#define WCD9335_CDC_TOP_TOP_CFG1                         0x0d82
+#define WCD9335_CDC_TOP_TOP_CFG2                         0x0d83
+#define WCD9335_CDC_TOP_TOP_CFG3                         0x0d84
+#define WCD9335_CDC_TOP_TOP_CFG4                         0x0d85
+#define WCD9335_CDC_TOP_TOP_CFG5                         0x0d86
+#define WCD9335_CDC_TOP_TOP_CFG6                         0x0d87
+#define WCD9335_CDC_TOP_TOP_CFG7                         0x0d88
+#define WCD9335_CDC_TOP_HPHL_COMP_WR_LSB                 0x0d89
+#define WCD9335_CDC_TOP_HPHL_COMP_WR_MSB                 0x0d8a
+#define WCD9335_CDC_TOP_HPHL_COMP_LUT                    0x0d8b
+#define WCD9335_CDC_TOP_HPHL_COMP_RD_LSB                 0x0d8c
+#define WCD9335_CDC_TOP_HPHL_COMP_RD_MSB                 0x0d8d
+#define WCD9335_CDC_TOP_HPHR_COMP_WR_LSB                 0x0d8e
+#define WCD9335_CDC_TOP_HPHR_COMP_WR_MSB                 0x0d8f
+#define WCD9335_CDC_TOP_HPHR_COMP_LUT                    0x0d90
+#define WCD9335_CDC_TOP_HPHR_COMP_RD_LSB                 0x0d91
+#define WCD9335_CDC_TOP_HPHR_COMP_RD_MSB                 0x0d92
+#define WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB                0x0d93
+#define WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB                0x0d94
+#define WCD9335_CDC_TOP_DIFFL_COMP_LUT                   0x0d95
+#define WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB                0x0d96
+#define WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB                0x0d97
+#define WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB                0x0d98
+#define WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB                0x0d99
+#define WCD9335_CDC_TOP_DIFFR_COMP_LUT                   0x0d9a
+#define WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB                0x0d9b
+#define WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB                0x0d9c
+
+/* Page-0x80 Registers */
+#define WCD9335_PAGE80_PAGE_REGISTER                     0x8000
+#define WCD9335_TLMM_BIST_MODE_PINCFG                    0x8001
+#define WCD9335_TLMM_RF_PA_ON_PINCFG                     0x8002
+#define WCD9335_TLMM_INTR1_PINCFG                        0x8003
+#define WCD9335_TLMM_INTR2_PINCFG                        0x8004
+#define WCD9335_TLMM_SWR_DATA_PINCFG                     0x8005
+#define WCD9335_TLMM_SWR_CLK_PINCFG                      0x8006
+#define WCD9335_TLMM_SLIMBUS_DATA2_PINCFG                0x8007
+#define WCD9335_TLMM_I2C_CLK_PINCFG                      0x8008
+#define WCD9335_TLMM_I2C_DATA_PINCFG                     0x8009
+#define WCD9335_TLMM_I2S_RX_SD0_PINCFG                   0x800a
+#define WCD9335_TLMM_I2S_RX_SD1_PINCFG                   0x800b
+#define WCD9335_TLMM_I2S_RX_SCK_PINCFG                   0x800c
+#define WCD9335_TLMM_I2S_RX_WS_PINCFG                    0x800d
+#define WCD9335_TLMM_I2S_TX_SD0_PINCFG                   0x800e
+#define WCD9335_TLMM_I2S_TX_SD1_PINCFG                   0x800f
+#define WCD9335_TLMM_I2S_TX_SCK_PINCFG                   0x8010
+#define WCD9335_TLMM_I2S_TX_WS_PINCFG                    0x8011
+#define WCD9335_TLMM_DMIC1_CLK_PINCFG                    0x8012
+#define WCD9335_TLMM_DMIC1_DATA_PINCFG                   0x8013
+#define WCD9335_TLMM_DMIC2_CLK_PINCFG                    0x8014
+#define WCD9335_TLMM_DMIC2_DATA_PINCFG                   0x8015
+#define WCD9335_TLMM_DMIC3_CLK_PINCFG                    0x8016
+#define WCD9335_TLMM_DMIC3_DATA_PINCFG                   0x8017
+#define WCD9335_TLMM_JTDI_PINCFG                         0x8018
+#define WCD9335_TLMM_JTDO_PINCFG                         0x8019
+#define WCD9335_TLMM_JTMS_PINCFG                         0x801a
+#define WCD9335_TLMM_JTCK_PINCFG                         0x801b
+#define WCD9335_TLMM_JTRST_PINCFG                        0x801c
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_0                  0x8031
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_1                  0x8032
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_2                  0x8033
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_3                  0x8034
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_0                0x8035
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_1                0x8036
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_2                0x8037
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_3                0x8038
+#define WCD9335_TEST_DEBUG_PAD_DRVCTL                    0x8039
+#define WCD9335_TEST_DEBUG_PIN_STATUS                    0x803a
+#define WCD9335_TEST_DEBUG_NPL_DLY_TEST_1                0x803b
+#define WCD9335_TEST_DEBUG_NPL_DLY_TEST_2                0x803c
+#define WCD9335_TEST_DEBUG_MEM_CTRL                      0x803d
+#define WCD9335_TEST_DEBUG_DEBUG_BUS_SEL                 0x8041
+#define WCD9335_TEST_DEBUG_DEBUG_JTAG                    0x8042
+#define WCD9335_TEST_DEBUG_DEBUG_EN_1                    0x8043
+#define WCD9335_TEST_DEBUG_DEBUG_EN_2                    0x8044
+#define WCD9335_TEST_DEBUG_DEBUG_EN_3                    0x8045
+#define WCD9335_MAX_REGISTER                             0x80FF
+
+/* SLIMBUS Slave Registers */
+#define TASHA_SLIM_PGD_PORT_INT_EN0                     (0x30)
+#define TASHA_SLIM_PGD_PORT_INT_STATUS_RX_0             (0x34)
+#define TASHA_SLIM_PGD_PORT_INT_STATUS_RX_1             (0x35)
+#define TASHA_SLIM_PGD_PORT_INT_STATUS_TX_0             (0x36)
+#define TASHA_SLIM_PGD_PORT_INT_STATUS_TX_1             (0x37)
+#define TASHA_SLIM_PGD_PORT_INT_CLR_RX_0                (0x38)
+#define TASHA_SLIM_PGD_PORT_INT_CLR_RX_1                (0x39)
+#define TASHA_SLIM_PGD_PORT_INT_CLR_TX_0                (0x3A)
+#define TASHA_SLIM_PGD_PORT_INT_CLR_TX_1                (0x3B)
+#define TASHA_SLIM_PGD_PORT_INT_RX_SOURCE0		(0x60)
+#define TASHA_SLIM_PGD_PORT_INT_TX_SOURCE0		(0x70)
+
+/* Macros for Packing Register Writes into a U32 */
+#define TASHA_PACKED_REG_SIZE sizeof(u32)
+
+#define TASHA_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\
+	((mask & 0xff) << 8)|((reg & 0xffff) << 16))
+#define TASHA_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+	do { \
+		((reg) = ((packed >> 16) & (0xffff))); \
+		((mask) = ((packed >> 8) & (0xff))); \
+		((val) = ((packed) & (0xff))); \
+	} while (0)
+#endif
diff --git a/asoc/codecs/wcd934x/Makefile b/asoc/codecs/wcd934x/Makefile
new file mode 100644
index 0000000..c4db59b
--- /dev/null
+++ b/asoc/codecs/wcd934x/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for wcd934x codec driver.
+#
+snd-soc-wcd934x-objs := wcd934x.o wcd934x-dsp-cntl.o \
+			wcd934x-mbhc.o wcd934x-dsd.o \
+			wcd934x-regmap.o wcd934x-tables.o
+obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o
diff --git a/asoc/codecs/wcd934x/wcd934x-dsd.c b/asoc/codecs/wcd934x/wcd934x-dsd.c
new file mode 100644
index 0000000..eea18c3
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-dsd.c
@@ -0,0 +1,772 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <sound/tlv.h>
+#include <sound/control.h>
+#include <asoc/wcd934x_registers.h>
+#include "wcd934x-dsd.h"
+
+#define DSD_VOLUME_MAX_0dB      0
+#define DSD_VOLUME_MIN_M110dB   -110
+
+#define DSD_VOLUME_RANGE_CHECK(x)   ((x >= DSD_VOLUME_MIN_M110dB) &&\
+				     (x <= DSD_VOLUME_MAX_0dB))
+#define DSD_VOLUME_STEPS            3
+#define DSD_VOLUME_UPDATE_DELAY_MS  30
+#define DSD_VOLUME_USLEEP_MARGIN_US 100
+#define DSD_VOLUME_STEP_DELAY_US    ((1000 * DSD_VOLUME_UPDATE_DELAY_MS) / \
+				     (2 * DSD_VOLUME_STEPS))
+
+#define TAVIL_VERSION_1_0  0
+#define TAVIL_VERSION_1_1  1
+
+static const DECLARE_TLV_DB_MINMAX(tavil_dsd_db_scale, DSD_VOLUME_MIN_M110dB,
+				   DSD_VOLUME_MAX_0dB);
+
+static const char *const dsd_if_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
+	"DSD_DATA_PAD"
+};
+
+static const char * const dsd_filt0_mux_text[] = {
+	"ZERO", "DSD_L IF MUX",
+};
+
+static const char * const dsd_filt1_mux_text[] = {
+	"ZERO", "DSD_R IF MUX",
+};
+
+static const struct soc_enum dsd_filt0_mux_enum =
+	SOC_ENUM_SINGLE(WCD934X_CDC_DSD0_PATH_CTL, 0,
+			ARRAY_SIZE(dsd_filt0_mux_text), dsd_filt0_mux_text);
+
+static const struct soc_enum dsd_filt1_mux_enum =
+	SOC_ENUM_SINGLE(WCD934X_CDC_DSD1_PATH_CTL, 0,
+			ARRAY_SIZE(dsd_filt1_mux_text), dsd_filt1_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(dsd_l_if_enum, WCD934X_CDC_DSD0_CFG0,
+			    2, dsd_if_text);
+static SOC_ENUM_SINGLE_DECL(dsd_r_if_enum, WCD934X_CDC_DSD1_CFG0,
+			    2, dsd_if_text);
+
+static const struct snd_kcontrol_new dsd_filt0_mux =
+		SOC_DAPM_ENUM("DSD Filt0 Mux", dsd_filt0_mux_enum);
+
+static const struct snd_kcontrol_new dsd_filt1_mux =
+		SOC_DAPM_ENUM("DSD Filt1 Mux", dsd_filt1_mux_enum);
+
+static const struct snd_kcontrol_new dsd_l_if_mux =
+		SOC_DAPM_ENUM("DSD Left If Mux", dsd_l_if_enum);
+static const struct snd_kcontrol_new dsd_r_if_mux =
+		SOC_DAPM_ENUM("DSD Right If Mux", dsd_r_if_enum);
+
+static const struct snd_soc_dapm_route tavil_dsd_audio_map[] = {
+	{"DSD_L IF MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"DSD_L IF MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"DSD_L IF MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"DSD_L IF MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"DSD_L IF MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"DSD_L IF MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"DSD_L IF MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"DSD_L IF MUX", "RX7", "CDC_IF RX7 MUX"},
+
+	{"DSD_FILTER_0", NULL, "DSD_L IF MUX"},
+	{"DSD_FILTER_0", NULL, "RX INT1 NATIVE SUPPLY"},
+	{"RX INT1 MIX3", "DSD HPHL Switch", "DSD_FILTER_0"},
+
+	{"DSD_R IF MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"DSD_R IF MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"DSD_R IF MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"DSD_R IF MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"DSD_R IF MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"DSD_R IF MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"DSD_R IF MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"DSD_R IF MUX", "RX7", "CDC_IF RX7 MUX"},
+
+	{"DSD_FILTER_1", NULL, "DSD_R IF MUX"},
+	{"DSD_FILTER_1", NULL, "RX INT2 NATIVE SUPPLY"},
+	{"RX INT2 MIX3", "DSD HPHR Switch", "DSD_FILTER_1"},
+
+	{"DSD_FILTER_0", NULL, "RX INT3 NATIVE SUPPLY"},
+	{"RX INT3 MIX3", "DSD LO1 Switch", "DSD_FILTER_0"},
+	{"DSD_FILTER_1", NULL, "RX INT4 NATIVE SUPPLY"},
+	{"RX INT4 MIX3", "DSD LO2 Switch", "DSD_FILTER_1"},
+};
+
+static bool is_valid_dsd_interpolator(int interp_num)
+{
+	if ((interp_num == INTERP_HPHL) || (interp_num == INTERP_HPHR) ||
+	    (interp_num == INTERP_LO1) || (interp_num == INTERP_LO2))
+		return true;
+
+	return false;
+}
+
+/**
+ * tavil_dsd_set_mixer_value - Set DSD HPH/LO mixer value
+ *
+ * @dsd_conf: pointer to dsd config
+ * @interp_num: Interpolator number (HPHL/R, LO1/2)
+ * @sw_value: Mixer switch value
+ *
+ * Returns 0 on success or -EINVAL on failure
+ */
+int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf,
+			      int interp_num, int sw_value)
+{
+	if (!dsd_conf)
+		return -EINVAL;
+
+	if (!is_valid_dsd_interpolator(interp_num))
+		return -EINVAL;
+
+	dsd_conf->dsd_interp_mixer[interp_num] = !!sw_value;
+
+	return 0;
+}
+EXPORT_SYMBOL(tavil_dsd_set_mixer_value);
+
+/**
+ * tavil_dsd_get_current_mixer_value - Get DSD HPH/LO mixer value
+ *
+ * @dsd_conf: pointer to dsd config
+ * @interp_num: Interpolator number (HPHL/R, LO1/2)
+ *
+ * Returns current mixer val for success or -EINVAL for failure
+ */
+int tavil_dsd_get_current_mixer_value(struct tavil_dsd_config *dsd_conf,
+				      int interp_num)
+{
+	if (!dsd_conf)
+		return -EINVAL;
+
+	if (!is_valid_dsd_interpolator(interp_num))
+		return -EINVAL;
+
+	return dsd_conf->dsd_interp_mixer[interp_num];
+}
+EXPORT_SYMBOL(tavil_dsd_get_current_mixer_value);
+
+/**
+ * tavil_dsd_set_out_select - DSD0/1 out select to HPH or LO
+ *
+ * @dsd_conf: pointer to dsd config
+ * @interp_num: Interpolator number (HPHL/R, LO1/2)
+ *
+ * Returns 0 for success or -EINVAL for failure
+ */
+int tavil_dsd_set_out_select(struct tavil_dsd_config *dsd_conf,
+			     int interp_num)
+{
+	unsigned int reg, val;
+	struct snd_soc_codec *codec;
+
+	if (!dsd_conf || !dsd_conf->codec)
+		return -EINVAL;
+
+	codec = dsd_conf->codec;
+
+	if (!is_valid_dsd_interpolator(interp_num)) {
+		dev_err(codec->dev, "%s: Invalid Interpolator: %d for DSD\n",
+			__func__, interp_num);
+		return -EINVAL;
+	}
+
+	switch (interp_num) {
+	case INTERP_HPHL:
+		reg = WCD934X_CDC_DSD0_CFG0;
+		val = 0x00;
+		break;
+	case INTERP_HPHR:
+		reg = WCD934X_CDC_DSD1_CFG0;
+		val = 0x00;
+		break;
+	case INTERP_LO1:
+		reg = WCD934X_CDC_DSD0_CFG0;
+		val = 0x02;
+		break;
+	case INTERP_LO2:
+		reg = WCD934X_CDC_DSD1_CFG0;
+		val = 0x02;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, reg, 0x02, val);
+
+	return 0;
+}
+EXPORT_SYMBOL(tavil_dsd_set_out_select);
+
+/**
+ * tavil_dsd_reset - Reset DSD block
+ *
+ * @dsd_conf: pointer to dsd config
+ *
+ */
+void tavil_dsd_reset(struct tavil_dsd_config *dsd_conf)
+{
+	if (!dsd_conf || !dsd_conf->codec)
+		return;
+
+	snd_soc_update_bits(dsd_conf->codec, WCD934X_CDC_DSD0_PATH_CTL,
+			    0x02, 0x02);
+	snd_soc_update_bits(dsd_conf->codec, WCD934X_CDC_DSD0_PATH_CTL,
+			    0x01, 0x00);
+	snd_soc_update_bits(dsd_conf->codec, WCD934X_CDC_DSD1_PATH_CTL,
+			    0x02, 0x02);
+	snd_soc_update_bits(dsd_conf->codec, WCD934X_CDC_DSD1_PATH_CTL,
+			    0x01, 0x00);
+}
+EXPORT_SYMBOL(tavil_dsd_reset);
+
+/**
+ * tavil_dsd_set_interp_rate - Set interpolator rate for DSD
+ *
+ * @dsd_conf: pointer to dsd config
+ * @rx_port: RX port number
+ * @sample_rate: Sample rate of the RX interpolator
+ * @sample_rate_val: Interpolator rate value
+ */
+void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port,
+			       u32 sample_rate, u8 sample_rate_val)
+{
+	u8 dsd_inp_sel;
+	u8 dsd0_inp, dsd1_inp;
+	u8 val0, val1;
+	u8 dsd0_out_sel, dsd1_out_sel;
+	u16 int_fs_reg, interp_num = 0;
+	struct snd_soc_codec *codec;
+
+	if (!dsd_conf || !dsd_conf->codec)
+		return;
+
+	codec = dsd_conf->codec;
+
+	dsd_inp_sel = DSD_INP_SEL_RX0 + rx_port - WCD934X_RX_PORT_START_NUMBER;
+
+	val0 = snd_soc_read(codec, WCD934X_CDC_DSD0_CFG0);
+	val1 = snd_soc_read(codec, WCD934X_CDC_DSD1_CFG0);
+	dsd0_inp = (val0 & 0x3C) >> 2;
+	dsd1_inp = (val1 & 0x3C) >> 2;
+	dsd0_out_sel = (val0 & 0x02) >> 1;
+	dsd1_out_sel = (val1 & 0x02) >> 1;
+
+	/* Set HPHL or LO1 interp rate based on out select */
+	if (dsd_inp_sel == dsd0_inp) {
+		interp_num = dsd0_out_sel ? INTERP_LO1 : INTERP_HPHL;
+		dsd_conf->base_sample_rate[DSD0] = sample_rate;
+	}
+
+	/* Set HPHR or LO2 interp rate based on out select */
+	if (dsd_inp_sel == dsd1_inp) {
+		interp_num = dsd1_out_sel ? INTERP_LO2 : INTERP_HPHR;
+		dsd_conf->base_sample_rate[DSD1] = sample_rate;
+	}
+
+	if (interp_num) {
+		int_fs_reg = WCD934X_CDC_RX0_RX_PATH_CTL + 20 * interp_num;
+		if ((snd_soc_read(codec, int_fs_reg) & 0x0f) < 0x09) {
+			dev_dbg(codec->dev, "%s: Set Interp %d to sample_rate val 0x%x\n",
+				__func__, interp_num, sample_rate_val);
+			snd_soc_update_bits(codec, int_fs_reg, 0x0F,
+					    sample_rate_val);
+		}
+	}
+}
+EXPORT_SYMBOL(tavil_dsd_set_interp_rate);
+
+static int tavil_set_dsd_mode(struct snd_soc_codec *codec, int dsd_num,
+			      u8 *pcm_rate_val)
+{
+	unsigned int dsd_out_sel_reg;
+	u8 dsd_mode;
+	u32 sample_rate;
+	struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(codec);
+
+	if (!dsd_conf)
+		return -EINVAL;
+
+	if ((dsd_num < 0) || (dsd_num > 1))
+		return -EINVAL;
+
+	sample_rate = dsd_conf->base_sample_rate[dsd_num];
+	dsd_out_sel_reg = WCD934X_CDC_DSD0_CFG0 + dsd_num * 16;
+
+	switch (sample_rate) {
+	case 176400:
+		dsd_mode = 0; /* DSD_64 */
+		*pcm_rate_val = 0xb;
+		break;
+	case 352800:
+		dsd_mode = 1; /* DSD_128 */
+		*pcm_rate_val = 0xc;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid DSD rate: %d\n",
+			__func__, sample_rate);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, dsd_out_sel_reg, 0x01, dsd_mode);
+
+	return 0;
+}
+
+static void tavil_dsd_data_pull(struct snd_soc_codec *codec, int dsd_num,
+				u8 pcm_rate_val, bool enable)
+{
+	u8 clk_en, mute_en;
+	u8 dsd_inp_sel;
+
+	if (enable) {
+		clk_en = 0x20;
+		mute_en = 0x10;
+	} else {
+		clk_en = 0x00;
+		mute_en = 0x00;
+	}
+
+	if (dsd_num & 0x01) {
+		snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_MIX_CTL,
+				    0x20, clk_en);
+		dsd_inp_sel = (snd_soc_read(codec, WCD934X_CDC_DSD0_CFG0) &
+				0x3C) >> 2;
+		dsd_inp_sel = (enable) ? dsd_inp_sel : 0;
+		if (dsd_inp_sel < 9) {
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1,
+					0x0F, dsd_inp_sel);
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_RX7_RX_PATH_MIX_CTL,
+					0x0F, pcm_rate_val);
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_RX7_RX_PATH_MIX_CTL,
+					0x10, mute_en);
+		}
+	}
+	if (dsd_num & 0x02) {
+		snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_MIX_CTL,
+				    0x20, clk_en);
+		dsd_inp_sel = (snd_soc_read(codec, WCD934X_CDC_DSD1_CFG0) &
+				0x3C) >> 2;
+		dsd_inp_sel = (enable) ? dsd_inp_sel : 0;
+		if (dsd_inp_sel < 9) {
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1,
+					0x0F, dsd_inp_sel);
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_RX8_RX_PATH_MIX_CTL,
+					0x0F, pcm_rate_val);
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_RX8_RX_PATH_MIX_CTL,
+					0x10, mute_en);
+		}
+	}
+}
+
+static void tavil_dsd_update_volume(struct tavil_dsd_config *dsd_conf)
+{
+	snd_soc_update_bits(dsd_conf->codec, WCD934X_CDC_TOP_TOP_CFG0,
+			    0x01, 0x01);
+	snd_soc_update_bits(dsd_conf->codec, WCD934X_CDC_TOP_TOP_CFG0,
+			    0x01, 0x00);
+}
+
+static int tavil_enable_dsd(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(codec);
+	int rc, clk_users;
+	int interp_idx;
+	u8 pcm_rate_val;
+
+	if (!dsd_conf) {
+		dev_err(codec->dev, "%s: null dsd_config pointer\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "%s: DSD%d, event: %d\n", __func__,
+		w->shift, event);
+
+	if (w->shift == DSD0) {
+		/* Read out select */
+		if (snd_soc_read(codec, WCD934X_CDC_DSD0_CFG0) & 0x02)
+			interp_idx = INTERP_LO1;
+		else
+			interp_idx = INTERP_HPHL;
+	} else if (w->shift == DSD1) {
+		/* Read out select */
+		if (snd_soc_read(codec, WCD934X_CDC_DSD1_CFG0) & 0x02)
+			interp_idx = INTERP_LO2;
+		else
+			interp_idx = INTERP_HPHR;
+	} else {
+		dev_err(codec->dev, "%s: Unsupported DSD:%d\n",
+			__func__, w->shift);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		clk_users = tavil_codec_enable_interp_clk(codec, event,
+							  interp_idx);
+
+		rc = tavil_set_dsd_mode(codec, w->shift, &pcm_rate_val);
+		if (rc)
+			return rc;
+
+		tavil_dsd_data_pull(codec, (1 << w->shift), pcm_rate_val,
+				    true);
+
+		snd_soc_update_bits(codec,
+				    WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL, 0x01,
+				    0x01);
+		if (w->shift == DSD0) {
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_PATH_CTL,
+					    0x02, 0x02);
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_PATH_CTL,
+					    0x02, 0x00);
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_PATH_CTL,
+					    0x01, 0x01);
+			/* Apply Gain */
+			snd_soc_write(codec, WCD934X_CDC_DSD0_CFG1,
+				      dsd_conf->volume[DSD0]);
+			if (dsd_conf->version == TAVIL_VERSION_1_1)
+				tavil_dsd_update_volume(dsd_conf);
+
+		} else if (w->shift == DSD1) {
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_PATH_CTL,
+					    0x02, 0x02);
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_PATH_CTL,
+					    0x02, 0x00);
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_PATH_CTL,
+					    0x01, 0x01);
+			/* Apply Gain */
+			snd_soc_write(codec, WCD934X_CDC_DSD1_CFG1,
+				      dsd_conf->volume[DSD1]);
+			if (dsd_conf->version == TAVIL_VERSION_1_1)
+				tavil_dsd_update_volume(dsd_conf);
+		}
+		/* 10msec sleep required after DSD clock is set */
+		usleep_range(10000, 10100);
+
+		if (clk_users > 1) {
+			snd_soc_update_bits(codec, WCD934X_ANA_RX_SUPPLIES,
+					    0x02, 0x02);
+			if (w->shift == DSD0)
+				snd_soc_update_bits(codec,
+						    WCD934X_CDC_DSD0_CFG2,
+						    0x04, 0x00);
+			if (w->shift == DSD1)
+				snd_soc_update_bits(codec,
+						    WCD934X_CDC_DSD1_CFG2,
+						    0x04, 0x00);
+
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (w->shift == DSD0) {
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2,
+					    0x04, 0x04);
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_PATH_CTL,
+					    0x01, 0x00);
+		} else if (w->shift == DSD1) {
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2,
+					    0x04, 0x04);
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_PATH_CTL,
+					    0x01, 0x00);
+		}
+
+		tavil_codec_enable_interp_clk(codec, event, interp_idx);
+
+		if (!(snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01) &&
+		    !(snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) {
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL,
+					0x01, 0x00);
+			tavil_dsd_data_pull(codec, 0x03, 0x04, false);
+			tavil_dsd_reset(dsd_conf);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int tavil_dsd_vol_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = DSD_VOLUME_MIN_M110dB;
+	uinfo->value.integer.max = DSD_VOLUME_MAX_0dB;
+
+	return 0;
+}
+
+static int tavil_dsd_vol_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(codec);
+	int nv[DSD_MAX], cv[DSD_MAX];
+	int step_size, nv1;
+	int i, dsd_idx;
+
+	if (!dsd_conf)
+		return 0;
+
+	mutex_lock(&dsd_conf->vol_mutex);
+
+	for (dsd_idx = DSD0; dsd_idx < DSD_MAX; dsd_idx++) {
+		cv[dsd_idx] = dsd_conf->volume[dsd_idx];
+		nv[dsd_idx] = ucontrol->value.integer.value[dsd_idx];
+	}
+
+	if ((!DSD_VOLUME_RANGE_CHECK(nv[DSD0])) ||
+	    (!DSD_VOLUME_RANGE_CHECK(nv[DSD1])))
+		goto done;
+
+	for (dsd_idx = DSD0; dsd_idx < DSD_MAX; dsd_idx++) {
+		if (cv[dsd_idx] == nv[dsd_idx])
+			continue;
+
+		dev_dbg(codec->dev, "%s: DSD%d cur.vol: %d, new vol: %d\n",
+			__func__, dsd_idx, cv[dsd_idx], nv[dsd_idx]);
+
+		step_size =  (nv[dsd_idx] - cv[dsd_idx]) /
+			      DSD_VOLUME_STEPS;
+
+		nv1 = cv[dsd_idx];
+
+		for (i = 0; i < DSD_VOLUME_STEPS; i++) {
+			nv1 += step_size;
+			snd_soc_write(codec,
+				      WCD934X_CDC_DSD0_CFG1 + 16 * dsd_idx,
+				      nv1);
+			if (dsd_conf->version == TAVIL_VERSION_1_1)
+				tavil_dsd_update_volume(dsd_conf);
+
+			/* sleep required after each volume step */
+			usleep_range(DSD_VOLUME_STEP_DELAY_US,
+				     (DSD_VOLUME_STEP_DELAY_US +
+				      DSD_VOLUME_USLEEP_MARGIN_US));
+		}
+		if (nv1 != nv[dsd_idx]) {
+			snd_soc_write(codec,
+				      WCD934X_CDC_DSD0_CFG1 + 16 * dsd_idx,
+				      nv[dsd_idx]);
+
+			if (dsd_conf->version == TAVIL_VERSION_1_1)
+				tavil_dsd_update_volume(dsd_conf);
+		}
+
+		dsd_conf->volume[dsd_idx] = nv[dsd_idx];
+	}
+
+done:
+	mutex_unlock(&dsd_conf->vol_mutex);
+
+	return 0;
+}
+
+static int tavil_dsd_vol_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(codec);
+
+	if (dsd_conf) {
+		ucontrol->value.integer.value[0] = dsd_conf->volume[DSD0];
+		ucontrol->value.integer.value[1] = dsd_conf->volume[DSD1];
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new tavil_dsd_vol_controls[] = {
+	{
+	   .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	   .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		      SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	   .name = "DSD Volume",
+	   .info = tavil_dsd_vol_info,
+	   .get = tavil_dsd_vol_get,
+	   .put = tavil_dsd_vol_put,
+	   .tlv = { .p = tavil_dsd_db_scale },
+	},
+};
+
+static const struct snd_soc_dapm_widget tavil_dsd_widgets[] = {
+	SND_SOC_DAPM_MUX("DSD_L IF MUX", SND_SOC_NOPM, 0, 0, &dsd_l_if_mux),
+	SND_SOC_DAPM_MUX_E("DSD_FILTER_0", SND_SOC_NOPM, 0, 0, &dsd_filt0_mux,
+			   tavil_enable_dsd,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("DSD_R IF MUX", SND_SOC_NOPM, 0, 0, &dsd_r_if_mux),
+	SND_SOC_DAPM_MUX_E("DSD_FILTER_1", SND_SOC_NOPM, 1, 0, &dsd_filt1_mux,
+			   tavil_enable_dsd,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+/**
+ * tavil_dsd_post_ssr_init - DSD intialization after subsystem restart
+ *
+ * @codec: pointer to snd_soc_codec
+ *
+ * Returns 0 on success or error on failure
+ */
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_conf)
+{
+	struct snd_soc_codec *codec;
+
+	if (!dsd_conf || !dsd_conf->codec)
+		return -EINVAL;
+
+	codec = dsd_conf->codec;
+	/* Disable DSD Interrupts */
+	snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x08);
+
+	/* DSD registers init */
+	if (dsd_conf->version == TAVIL_VERSION_1_0) {
+		snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x02, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x02, 0x00);
+	}
+	/* DSD0: Mute EN */
+	snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x04, 0x04);
+	/* DSD1: Mute EN */
+	snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x04, 0x04);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, 0x10,
+			    0x10);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, 0x10,
+			    0x10);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, 0x0E,
+			    0x0A);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, 0x0E,
+			    0x0A);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, 0x07,
+			    0x04);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, 0x07,
+			    0x04);
+
+	/* Enable DSD Interrupts */
+	snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x00);
+
+	return 0;
+}
+EXPORT_SYMBOL(tavil_dsd_post_ssr_init);
+
+/**
+ * tavil_dsd_init - DSD intialization
+ *
+ * @codec: pointer to snd_soc_codec
+ *
+ * Returns pointer to tavil_dsd_config for success or NULL for failure
+ */
+struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm;
+	struct tavil_dsd_config *dsd_conf;
+	u8 val;
+
+	if (!codec)
+		return NULL;
+
+	dapm = snd_soc_codec_get_dapm(codec);
+
+	/* Read efuse register to check if DSD is supported */
+	val = snd_soc_read(codec, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14);
+	if (val & 0x80) {
+		dev_info(codec->dev, "%s: DSD unsupported for this codec version\n",
+			 __func__);
+		return NULL;
+	}
+
+	dsd_conf = devm_kzalloc(codec->dev, sizeof(struct tavil_dsd_config),
+				GFP_KERNEL);
+	if (!dsd_conf)
+		return NULL;
+
+	dsd_conf->codec = codec;
+
+	/* Read version */
+	dsd_conf->version = snd_soc_read(codec,
+					 WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0);
+	/* DSD registers init */
+	if (dsd_conf->version == TAVIL_VERSION_1_0) {
+		snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x02, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x02, 0x00);
+	}
+	/* DSD0: Mute EN */
+	snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x04, 0x04);
+	/* DSD1: Mute EN */
+	snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x04, 0x04);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, 0x10,
+			    0x10);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, 0x10,
+			    0x10);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, 0x0E,
+			    0x0A);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, 0x0E,
+			    0x0A);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, 0x07,
+			    0x04);
+	snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, 0x07,
+			    0x04);
+
+	snd_soc_dapm_new_controls(dapm, tavil_dsd_widgets,
+				  ARRAY_SIZE(tavil_dsd_widgets));
+
+	snd_soc_dapm_add_routes(dapm, tavil_dsd_audio_map,
+				ARRAY_SIZE(tavil_dsd_audio_map));
+
+	mutex_init(&dsd_conf->vol_mutex);
+	dsd_conf->volume[DSD0] = DSD_VOLUME_MAX_0dB;
+	dsd_conf->volume[DSD1] = DSD_VOLUME_MAX_0dB;
+
+	snd_soc_add_codec_controls(codec, tavil_dsd_vol_controls,
+				   ARRAY_SIZE(tavil_dsd_vol_controls));
+
+	/* Enable DSD Interrupts */
+	snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x00);
+
+	return dsd_conf;
+}
+EXPORT_SYMBOL(tavil_dsd_init);
+
+/**
+ * tavil_dsd_deinit - DSD de-intialization
+ *
+ * @dsd_conf: pointer to tavil_dsd_config
+ */
+void tavil_dsd_deinit(struct tavil_dsd_config *dsd_conf)
+{
+	struct snd_soc_codec *codec;
+
+	if (!dsd_conf)
+		return;
+
+	codec = dsd_conf->codec;
+
+	mutex_destroy(&dsd_conf->vol_mutex);
+
+	/* Disable DSD Interrupts */
+	snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x08);
+
+	devm_kfree(codec->dev, dsd_conf);
+}
+EXPORT_SYMBOL(tavil_dsd_deinit);
diff --git a/asoc/codecs/wcd934x/wcd934x-dsd.h b/asoc/codecs/wcd934x/wcd934x-dsd.h
new file mode 100644
index 0000000..834b96c
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-dsd.h
@@ -0,0 +1,97 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD934X_DSD_H__
+#define __WCD934X_DSD_H__
+
+#include <sound/soc.h>
+#include "wcd934x.h"
+
+enum {
+	DSD0,
+	DSD1,
+	DSD_MAX,
+};
+
+enum {
+	DSD_INP_SEL_ZERO = 0,
+	DSD_INP_SEL_RX0,
+	DSD_INP_SEL_RX1,
+	DSD_INP_SEL_RX2,
+	DSD_INP_SEL_RX3,
+	DSD_INP_SEL_RX4,
+	DSD_INP_SEL_RX5,
+	DSD_INP_SEL_RX6,
+	DSD_INP_SEL_RX7,
+};
+
+struct tavil_dsd_config {
+	struct snd_soc_codec *codec;
+	unsigned int dsd_interp_mixer[INTERP_MAX];
+	u32 base_sample_rate[DSD_MAX];
+	int volume[DSD_MAX];
+	struct mutex vol_mutex;
+	int version;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD934X_DSD)
+int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf,
+			      int interp_num, int sw_value);
+int tavil_dsd_get_current_mixer_value(struct tavil_dsd_config *dsd_conf,
+				      int interp_num);
+int tavil_dsd_set_out_select(struct tavil_dsd_config *dsd_conf,
+			     int interp_num);
+void tavil_dsd_reset(struct tavil_dsd_config *dsd_conf);
+void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port,
+			       u32 sample_rate, u8 sample_rate_val);
+struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_codec *codec);
+void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config);
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config);
+#else
+int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf,
+			      int interp_num, int sw_value)
+{
+	return 0;
+}
+
+int tavil_dsd_get_current_mixer_value(struct tavil_dsd_config *dsd_conf,
+				      int interp_num)
+{
+	return 0;
+}
+
+int tavil_dsd_set_out_select(struct tavil_dsd_config *dsd_conf,
+			     int interp_num)
+{
+	return 0;
+}
+
+void tavil_dsd_reset(struct tavil_dsd_config *dsd_conf)
+{  }
+
+void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port,
+			       u32 sample_rate, u8 sample_rate_val)
+{  }
+
+struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_codec *codec)
+{
+	return NULL;
+}
+
+void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config)
+{  }
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config)
+{
+	return 0;
+}
+#endif
+#endif
diff --git a/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c b/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c
new file mode 100644
index 0000000..d82748b
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -0,0 +1,1369 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/component.h>
+#include <linux/debugfs.h>
+#include <sound/soc.h>
+#include <sound/wcd-dsp-mgr.h>
+#include <asoc/wcd934x_registers.h>
+#include "wcd934x.h"
+#include "wcd934x-dsp-cntl.h"
+#include "../wcd9xxx-irq.h"
+#include "../core.h"
+
+#define WCD_CNTL_DIR_NAME_LEN_MAX 32
+#define WCD_CPE_FLL_MAX_RETRIES 5
+#define WCD_MEM_ENABLE_MAX_RETRIES 20
+#define WCD_DSP_BOOT_TIMEOUT_MS 3000
+#define WCD_SYSFS_ENTRY_MAX_LEN 8
+#define WCD_PROCFS_ENTRY_MAX_LEN 16
+#define WCD_934X_RAMDUMP_START_ADDR 0x20100000
+#define WCD_934X_RAMDUMP_SIZE ((1024 * 1024) - 128)
+
+#define WCD_CNTL_MUTEX_LOCK(codec, lock)             \
+{                                                    \
+	dev_dbg(codec->dev, "%s: mutex_lock(%s)\n",  \
+		__func__, __stringify_1(lock));      \
+	mutex_lock(&lock);                           \
+}
+
+#define WCD_CNTL_MUTEX_UNLOCK(codec, lock)            \
+{                                                     \
+	dev_dbg(codec->dev, "%s: mutex_unlock(%s)\n", \
+		__func__, __stringify_1(lock));       \
+	mutex_unlock(&lock);                          \
+}
+
+enum wcd_mem_type {
+	WCD_MEM_TYPE_ALWAYS_ON,
+	WCD_MEM_TYPE_SWITCHABLE,
+};
+
+struct wcd_cntl_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct wcd_dsp_cntl *cntl, char *buf);
+	ssize_t (*store)(struct wcd_dsp_cntl *cntl, const char *buf,
+			 ssize_t count);
+};
+
+#define WCD_CNTL_ATTR(_name, _mode, _show, _store) \
+static struct wcd_cntl_attribute cntl_attr_##_name = {	\
+	.attr = {.name = __stringify(_name), .mode = _mode},	\
+	.show = _show,	\
+	.store = _store,	\
+}
+
+#define to_wcd_cntl_attr(a) \
+	container_of((a), struct wcd_cntl_attribute, attr)
+
+#define to_wcd_cntl(kobj) \
+	container_of((kobj), struct wcd_dsp_cntl, wcd_kobj)
+
+static u8 mem_enable_values[] = {
+	0xFE, 0xFC, 0xF8, 0xF0,
+	0xE0, 0xC0, 0x80, 0x00,
+};
+
+static ssize_t wdsp_boot_show(struct wcd_dsp_cntl *cntl, char *buf)
+{
+	return snprintf(buf, WCD_SYSFS_ENTRY_MAX_LEN,
+			"%u", cntl->boot_reqs);
+}
+
+static ssize_t wdsp_boot_store(struct wcd_dsp_cntl *cntl,
+			       const char *buf, ssize_t count)
+{
+	u32 val;
+	bool vote;
+	int ret;
+
+	ret = kstrtou32(buf, 10, &val);
+	if (ret) {
+		dev_err(cntl->codec->dev,
+			"%s: Invalid entry, ret = %d\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	if (val > 0) {
+		cntl->boot_reqs++;
+		vote = true;
+	} else {
+		cntl->boot_reqs--;
+		vote = false;
+	}
+
+	if (cntl->m_dev && cntl->m_ops &&
+	    cntl->m_ops->vote_for_dsp)
+		ret = cntl->m_ops->vote_for_dsp(cntl->m_dev, vote);
+	else
+		ret = -EINVAL;
+
+	if (ret < 0)
+		dev_err(cntl->codec->dev,
+			"%s: failed to %s dsp\n", __func__,
+			vote ? "enable" : "disable");
+	return count;
+}
+
+WCD_CNTL_ATTR(boot, 0660, wdsp_boot_show, wdsp_boot_store);
+
+static ssize_t wcd_cntl_sysfs_show(struct kobject *kobj,
+				   struct attribute *attr, char *buf)
+{
+	struct wcd_cntl_attribute *wcd_attr = to_wcd_cntl_attr(attr);
+	struct wcd_dsp_cntl *cntl = to_wcd_cntl(kobj);
+	ssize_t ret = -EINVAL;
+
+	if (cntl && wcd_attr->show)
+		ret = wcd_attr->show(cntl, buf);
+
+	return ret;
+}
+
+static ssize_t wcd_cntl_sysfs_store(struct kobject *kobj,
+				    struct attribute *attr, const char *buf,
+				    size_t count)
+{
+	struct wcd_cntl_attribute *wcd_attr = to_wcd_cntl_attr(attr);
+	struct wcd_dsp_cntl *cntl = to_wcd_cntl(kobj);
+	ssize_t ret = -EINVAL;
+
+	if (cntl && wcd_attr->store)
+		ret = wcd_attr->store(cntl, buf, count);
+
+	return ret;
+}
+
+static const struct sysfs_ops wcd_cntl_sysfs_ops = {
+	.show = wcd_cntl_sysfs_show,
+	.store = wcd_cntl_sysfs_store,
+};
+
+static struct kobj_type wcd_cntl_ktype = {
+	.sysfs_ops = &wcd_cntl_sysfs_ops,
+};
+
+static void wcd_cntl_change_online_state(struct wcd_dsp_cntl *cntl,
+					 u8 online)
+{
+	struct wdsp_ssr_entry *ssr_entry = &cntl->ssr_entry;
+	unsigned long ret;
+
+	WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
+	ssr_entry->offline = !online;
+	/* Make sure the write is complete */
+	wmb();
+	ret = xchg(&ssr_entry->offline_change, 1);
+	wake_up_interruptible(&ssr_entry->offline_poll_wait);
+	dev_dbg(cntl->codec->dev,
+		"%s: requested %u, offline %u offline_change %u, ret = %ldn",
+		__func__, online, ssr_entry->offline,
+		ssr_entry->offline_change, ret);
+	WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
+}
+
+static ssize_t wdsp_ssr_entry_read(struct snd_info_entry *entry,
+				   void *file_priv_data, struct file *file,
+				   char __user *buf, size_t count, loff_t pos)
+{
+	int len = 0;
+	char buffer[WCD_PROCFS_ENTRY_MAX_LEN];
+	struct wcd_dsp_cntl *cntl;
+	struct wdsp_ssr_entry *ssr_entry;
+	ssize_t ret;
+	u8 offline;
+
+	cntl = (struct wcd_dsp_cntl *) entry->private_data;
+	if (!cntl) {
+		pr_err("%s: Invalid private data for SSR procfs entry\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	ssr_entry = &cntl->ssr_entry;
+
+	WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
+	offline = ssr_entry->offline;
+	/* Make sure the read is complete */
+	rmb();
+	dev_dbg(cntl->codec->dev, "%s: offline = %s\n", __func__,
+		offline ? "true" : "false");
+	len = snprintf(buffer, sizeof(buffer), "%s\n",
+		       offline ? "OFFLINE" : "ONLINE");
+	ret = simple_read_from_buffer(buf, count, &pos, buffer, len);
+	WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
+
+	return ret;
+}
+
+static unsigned int wdsp_ssr_entry_poll(struct snd_info_entry *entry,
+					void *private_data, struct file *file,
+					poll_table *wait)
+{
+	struct wcd_dsp_cntl *cntl;
+	struct wdsp_ssr_entry *ssr_entry;
+	unsigned int ret = 0;
+
+	if (!entry || !entry->private_data) {
+		pr_err("%s: %s is NULL\n", __func__,
+		       (!entry) ? "entry" : "private_data");
+		return -EINVAL;
+	}
+
+	cntl = (struct wcd_dsp_cntl *) entry->private_data;
+	ssr_entry = &cntl->ssr_entry;
+
+	dev_dbg(cntl->codec->dev, "%s: Poll wait, offline = %u\n",
+		__func__, ssr_entry->offline);
+	poll_wait(file, &ssr_entry->offline_poll_wait, wait);
+	dev_dbg(cntl->codec->dev, "%s: Woken up Poll wait, offline = %u\n",
+		__func__, ssr_entry->offline);
+
+	WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
+	if (xchg(&ssr_entry->offline_change, 0))
+		ret = POLLIN | POLLPRI | POLLRDNORM;
+	dev_dbg(cntl->codec->dev, "%s: ret (%d) from poll_wait\n",
+		__func__, ret);
+	WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
+
+	return ret;
+}
+
+static struct snd_info_entry_ops wdsp_ssr_entry_ops = {
+	.read = wdsp_ssr_entry_read,
+	.poll = wdsp_ssr_entry_poll,
+};
+
+static int wcd_cntl_cpe_fll_calibrate(struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	int ret = 0, retry = 0;
+	u8 cal_lsb, cal_msb;
+	u8 lock_det;
+
+	/* Make sure clocks are gated */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
+			    0x05, 0x00);
+
+	/* Enable CPE FLL reference clock */
+	snd_soc_update_bits(codec, WCD934X_CLK_SYS_MCLK2_PRG1,
+			    0x80, 0x80);
+
+	snd_soc_update_bits(codec, WCD934X_CPE_FLL_USER_CTL_5,
+			    0xF3, 0x13);
+	snd_soc_write(codec, WCD934X_CPE_FLL_L_VAL_CTL_0, 0x50);
+
+	/* Disable CPAR reset and Enable CPAR clk */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL,
+			    0x02, 0x02);
+
+	/* Write calibration l-value based on cdc clk rate */
+	if (cntl->clk_rate == 9600000) {
+		cal_lsb = 0x6d;
+		cal_msb = 0x00;
+	} else {
+		cal_lsb = 0x56;
+		cal_msb = 0x00;
+	}
+	snd_soc_write(codec, WCD934X_CPE_FLL_USER_CTL_6, cal_lsb);
+	snd_soc_write(codec, WCD934X_CPE_FLL_USER_CTL_7, cal_msb);
+
+	/* FLL mode to follow power up sequence */
+	snd_soc_update_bits(codec, WCD934X_CPE_FLL_FLL_MODE,
+			    0x60, 0x00);
+
+	/* HW controlled CPE FLL */
+	snd_soc_update_bits(codec, WCD934X_CPE_FLL_FLL_MODE,
+			    0x80, 0x80);
+
+	/* Force on CPE FLL */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CFG,
+			    0x04, 0x04);
+
+	do {
+		/* Time for FLL calibration to complete */
+		usleep_range(1000, 1100);
+		lock_det = snd_soc_read(codec, WCD934X_CPE_FLL_STATUS_3);
+		retry++;
+	} while (!(lock_det & 0x01) &&
+		 retry <= WCD_CPE_FLL_MAX_RETRIES);
+
+	if (!(lock_det & 0x01)) {
+		dev_err(codec->dev, "%s: lock detect not set, 0x%02x\n",
+			__func__, lock_det);
+		ret = -EIO;
+		goto err_lock_det;
+	}
+
+	snd_soc_update_bits(codec, WCD934X_CPE_FLL_FLL_MODE,
+			    0x60, 0x20);
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CFG,
+			    0x04, 0x00);
+	return ret;
+
+err_lock_det:
+	/* Undo the register settings */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CFG,
+			    0x04, 0x00);
+	snd_soc_update_bits(codec, WCD934X_CPE_FLL_FLL_MODE,
+			    0x80, 0x00);
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL,
+			    0x02, 0x00);
+	return ret;
+}
+
+static void wcd_cntl_config_cpar(struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	u8 nom_lo, nom_hi, svs2_lo, svs2_hi;
+
+	/* Configure CPAR */
+	nom_hi = svs2_hi = 0;
+	if (cntl->clk_rate == 9600000) {
+		nom_lo = 0x90;
+		svs2_lo = 0x50;
+	} else {
+		nom_lo = 0x70;
+		svs2_lo = 0x3e;
+	}
+
+	snd_soc_write(codec, WCD934X_TEST_DEBUG_LVAL_NOM_LOW, nom_lo);
+	snd_soc_write(codec, WCD934X_TEST_DEBUG_LVAL_NOM_HIGH, nom_hi);
+	snd_soc_write(codec, WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW, svs2_lo);
+	snd_soc_write(codec, WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH, svs2_hi);
+
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_PWR_CPEFLL_CTL,
+			    0x03, 0x03);
+}
+
+static int wcd_cntl_cpe_fll_ctrl(struct wcd_dsp_cntl *cntl,
+				 bool enable)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	int ret = 0;
+
+	if (enable) {
+		ret = wcd_cntl_cpe_fll_calibrate(cntl);
+		if (ret < 0) {
+			dev_err(codec->dev,
+				"%s: cpe_fll_cal failed, err = %d\n",
+				__func__, ret);
+			goto done;
+		}
+
+		wcd_cntl_config_cpar(cntl);
+
+		/* Enable AHB CLK and CPE CLK*/
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
+				    0x05, 0x05);
+	} else {
+		/* Disable AHB CLK and CPE CLK */
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
+				    0x05, 0x00);
+		/* Reset the CPAR mode for CPE FLL */
+		snd_soc_write(codec, WCD934X_CPE_FLL_FLL_MODE, 0x20);
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CFG,
+				    0x04, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL,
+				    0x02, 0x00);
+	}
+done:
+	return ret;
+}
+
+static int wcd_cntl_clocks_enable(struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	int ret;
+
+	WCD_CNTL_MUTEX_LOCK(codec, cntl->clk_mutex);
+	/* Enable codec clock */
+	if (cntl->cdc_cb && cntl->cdc_cb->cdc_clk_en)
+		ret = cntl->cdc_cb->cdc_clk_en(codec, true);
+	else
+		ret = -EINVAL;
+
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Failed to enable cdc clk, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+	/* Pull CPAR out of reset */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL, 0x04, 0x00);
+
+	/* Configure and Enable CPE FLL clock */
+	ret = wcd_cntl_cpe_fll_ctrl(cntl, true);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Failed to enable cpe clk, err = %d\n",
+			__func__, ret);
+		goto err_cpe_clk;
+	}
+	cntl->is_clk_enabled = true;
+
+	/* Ungate the CPR clock  */
+	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_GATE, 0x10, 0x00);
+done:
+	WCD_CNTL_MUTEX_UNLOCK(codec, cntl->clk_mutex);
+	return ret;
+
+err_cpe_clk:
+	if (cntl->cdc_cb && cntl->cdc_cb->cdc_clk_en)
+		cntl->cdc_cb->cdc_clk_en(codec, false);
+
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL, 0x04, 0x04);
+	WCD_CNTL_MUTEX_UNLOCK(codec, cntl->clk_mutex);
+	return ret;
+}
+
+static int wcd_cntl_clocks_disable(struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	int ret = 0;
+
+	WCD_CNTL_MUTEX_LOCK(codec, cntl->clk_mutex);
+	if (!cntl->is_clk_enabled) {
+		dev_info(codec->dev, "%s: clocks already disabled\n",
+			__func__);
+		goto done;
+	}
+
+	/* Gate the CPR clock  */
+	snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_GATE, 0x10, 0x10);
+
+	/* Disable CPE FLL clock */
+	ret = wcd_cntl_cpe_fll_ctrl(cntl, false);
+	if (ret < 0)
+		dev_err(codec->dev,
+			"%s: Failed to disable cpe clk, err = %d\n",
+			__func__, ret);
+
+	/*
+	 * Even if CPE FLL disable failed, go ahead and disable
+	 * the codec clock
+	 */
+	if (cntl->cdc_cb && cntl->cdc_cb->cdc_clk_en)
+		ret = cntl->cdc_cb->cdc_clk_en(codec, false);
+	else
+		ret = -EINVAL;
+
+	cntl->is_clk_enabled = false;
+
+	/* Put CPAR in reset */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL, 0x04, 0x04);
+done:
+	WCD_CNTL_MUTEX_UNLOCK(codec, cntl->clk_mutex);
+	return ret;
+}
+
+static void wcd_cntl_cpar_ctrl(struct wcd_dsp_cntl *cntl,
+			       bool enable)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+
+	if (enable)
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL, 0x03, 0x03);
+	else
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_CPAR_CTL, 0x03, 0x00);
+}
+
+static int wcd_cntl_enable_memory(struct wcd_dsp_cntl *cntl,
+				  enum wcd_mem_type mem_type)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	int loop_cnt = 0;
+	u8 status;
+	int ret = 0;
+
+
+	switch (mem_type) {
+
+	case WCD_MEM_TYPE_ALWAYS_ON:
+
+		/* 512KB of always on region */
+		wcd9xxx_slim_write_repeat(wcd9xxx,
+				WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0,
+				ARRAY_SIZE(mem_enable_values),
+				mem_enable_values);
+		wcd9xxx_slim_write_repeat(wcd9xxx,
+				WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1,
+				ARRAY_SIZE(mem_enable_values),
+				mem_enable_values);
+		break;
+
+	case WCD_MEM_TYPE_SWITCHABLE:
+
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
+				    0x04, 0x00);
+		snd_soc_update_bits(codec, WCD934X_TEST_DEBUG_MEM_CTRL,
+				    0x80, 0x80);
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
+				    0x01, 0x01);
+		do {
+			loop_cnt++;
+			/* Time to enable the power domain for memory */
+			usleep_range(100, 150);
+			status = snd_soc_read(codec,
+					WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL);
+		} while ((status & 0x02) != 0x02 &&
+			  loop_cnt != WCD_MEM_ENABLE_MAX_RETRIES);
+
+		if ((status & 0x02) != 0x02) {
+			dev_err(cntl->codec->dev,
+				"%s: power domain not enabled, status = 0x%02x\n",
+				__func__, status);
+			ret = -EIO;
+			goto done;
+		}
+
+		/* Rest of the memory */
+		wcd9xxx_slim_write_repeat(wcd9xxx,
+				WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2,
+				ARRAY_SIZE(mem_enable_values),
+				mem_enable_values);
+		wcd9xxx_slim_write_repeat(wcd9xxx,
+				WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3,
+				ARRAY_SIZE(mem_enable_values),
+				mem_enable_values);
+
+		snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN,
+			      0x05);
+		break;
+
+	default:
+		dev_err(cntl->codec->dev, "%s: Invalid mem_type %d\n",
+			__func__, mem_type);
+		ret = -EINVAL;
+		break;
+	}
+done:
+	/* Make sure Deep sleep of memories is enabled for all banks */
+	snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xFF);
+	snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0F);
+
+	return ret;
+}
+
+static void wcd_cntl_disable_memory(struct wcd_dsp_cntl *cntl,
+				    enum wcd_mem_type mem_type)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	u8 val;
+
+	switch (mem_type) {
+	case WCD_MEM_TYPE_ALWAYS_ON:
+		snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1,
+			      0xFF);
+		snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0,
+			      0xFF);
+		break;
+	case WCD_MEM_TYPE_SWITCHABLE:
+		snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3,
+			      0xFF);
+		snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2,
+			      0xFF);
+		snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN,
+			      0x07);
+
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
+				    0x01, 0x00);
+		val = snd_soc_read(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL);
+		if (val & 0x02)
+			dev_err(codec->dev,
+				"%s: Disable switchable failed, val = 0x%02x",
+				__func__, val);
+
+		snd_soc_update_bits(codec, WCD934X_TEST_DEBUG_MEM_CTRL,
+				    0x80, 0x00);
+		break;
+	default:
+		dev_err(cntl->codec->dev, "%s: Invalid mem_type %d\n",
+			__func__, mem_type);
+		break;
+	}
+
+	snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xFF);
+	snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0F);
+}
+
+static void wcd_cntl_do_shutdown(struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+
+	/* Disable WDOG */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
+			    0x3F, 0x01);
+
+	/* Put WDSP in reset state */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
+			    0x02, 0x00);
+
+	/* If DSP transitions from boot to shutdown, then vote for SVS */
+	if (cntl->is_wdsp_booted)
+		cntl->cdc_cb->cdc_vote_svs(codec, true);
+	cntl->is_wdsp_booted = false;
+}
+
+static int wcd_cntl_do_boot(struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	int ret = 0;
+
+	/*
+	 * Debug mode is set from debugfs file node. If debug_mode
+	 * is set, then do not configure the watchdog timer. This
+	 * will be required for debugging the DSP firmware.
+	 */
+	if (cntl->debug_mode) {
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
+				    0x3F, 0x01);
+	} else {
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
+				    0x3F, 0x21);
+	}
+
+	/* Make sure all the error interrupts are cleared */
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A, 0xFF);
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B, 0xFF);
+
+	reinit_completion(&cntl->boot_complete);
+
+	/* Remove WDSP out of reset */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_CPE_CTL,
+			    0x02, 0x02);
+
+	/*
+	 * In debug mode, DSP may not boot up normally,
+	 * wait indefinitely for DSP to boot.
+	 */
+	if (cntl->debug_mode) {
+		wait_for_completion(&cntl->boot_complete);
+		dev_dbg(codec->dev, "%s: WDSP booted in dbg mode\n", __func__);
+		cntl->is_wdsp_booted = true;
+		goto done;
+	}
+
+	/* Boot in normal mode */
+	ret = wait_for_completion_timeout(&cntl->boot_complete,
+				msecs_to_jiffies(WCD_DSP_BOOT_TIMEOUT_MS));
+	if (!ret) {
+		dev_err(codec->dev, "%s: WDSP boot timed out\n",
+			__func__);
+		ret = -ETIMEDOUT;
+		goto err_boot;
+	} else {
+		/*
+		 * Re-initialize the return code to 0, as in success case,
+		 * it will hold the remaining time for completion timeout
+		 */
+		ret = 0;
+	}
+
+	dev_dbg(codec->dev, "%s: WDSP booted in normal mode\n", __func__);
+	cntl->is_wdsp_booted = true;
+
+	/* Enable WDOG */
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_WDOG_CFG,
+			    0x10, 0x10);
+done:
+	/* If dsp booted up, then remove vote on SVS */
+	if (cntl->is_wdsp_booted)
+		cntl->cdc_cb->cdc_vote_svs(codec, false);
+
+	return ret;
+err_boot:
+	/* call shutdown to perform cleanup */
+	wcd_cntl_do_shutdown(cntl);
+	return ret;
+}
+
+static irqreturn_t wcd_cntl_ipc_irq(int irq, void *data)
+{
+	struct wcd_dsp_cntl *cntl = data;
+	int ret;
+
+	complete(&cntl->boot_complete);
+
+	if (cntl->m_dev && cntl->m_ops &&
+	    cntl->m_ops->signal_handler)
+		ret = cntl->m_ops->signal_handler(cntl->m_dev, WDSP_IPC1_INTR,
+						  NULL);
+	else
+		ret = -EINVAL;
+
+	if (ret < 0)
+		dev_err(cntl->codec->dev,
+			"%s: Failed to handle irq %d\n", __func__, irq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd_cntl_err_irq(int irq, void *data)
+{
+	struct wcd_dsp_cntl *cntl = data;
+	struct snd_soc_codec *codec = cntl->codec;
+	struct wdsp_err_signal_arg arg;
+	u16 status = 0;
+	u8 reg_val;
+	int ret = 0;
+
+	reg_val = snd_soc_read(codec, WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A);
+	status = status | reg_val;
+
+	reg_val = snd_soc_read(codec, WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B);
+	status = status | (reg_val << 8);
+
+	dev_info(codec->dev, "%s: error interrupt status = 0x%x\n",
+		__func__, status);
+
+	if ((status & cntl->irqs.fatal_irqs) &&
+	    (cntl->m_dev && cntl->m_ops && cntl->m_ops->signal_handler)) {
+		arg.mem_dumps_enabled = cntl->ramdump_enable;
+		arg.remote_start_addr = WCD_934X_RAMDUMP_START_ADDR;
+		arg.dump_size = WCD_934X_RAMDUMP_SIZE;
+		ret = cntl->m_ops->signal_handler(cntl->m_dev, WDSP_ERR_INTR,
+						  &arg);
+		if (ret < 0)
+			dev_err(cntl->codec->dev,
+				"%s: Failed to handle fatal irq 0x%x\n",
+				__func__, status & cntl->irqs.fatal_irqs);
+		wcd_cntl_change_online_state(cntl, 0);
+	} else {
+		dev_err(cntl->codec->dev, "%s: Invalid signal_handler\n",
+			__func__);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int wcd_control_handler(struct device *dev, void *priv_data,
+			       enum wdsp_event_type event, void *data)
+{
+	struct wcd_dsp_cntl *cntl = priv_data;
+	struct snd_soc_codec *codec = cntl->codec;
+	int ret = 0;
+
+	switch (event) {
+	case WDSP_EVENT_POST_INIT:
+	case WDSP_EVENT_POST_DLOAD_CODE:
+	case WDSP_EVENT_DLOAD_FAILED:
+	case WDSP_EVENT_POST_SHUTDOWN:
+
+		if (event == WDSP_EVENT_POST_DLOAD_CODE)
+			/* Mark DSP online since code download is complete */
+			wcd_cntl_change_online_state(cntl, 1);
+
+		/* Disable CPAR */
+		wcd_cntl_cpar_ctrl(cntl, false);
+		/* Disable all the clocks */
+		ret = wcd_cntl_clocks_disable(cntl);
+		if (ret < 0)
+			dev_err(codec->dev,
+				"%s: Failed to disable clocks, err = %d\n",
+				__func__, ret);
+		break;
+
+	case WDSP_EVENT_PRE_DLOAD_DATA:
+	case WDSP_EVENT_PRE_DLOAD_CODE:
+
+		/* Enable all the clocks */
+		ret = wcd_cntl_clocks_enable(cntl);
+		if (ret < 0) {
+			dev_err(codec->dev,
+				"%s: Failed to enable clocks, err = %d\n",
+				__func__, ret);
+			goto done;
+		}
+
+		/* Enable CPAR */
+		wcd_cntl_cpar_ctrl(cntl, true);
+
+		if (event == WDSP_EVENT_PRE_DLOAD_CODE)
+			wcd_cntl_enable_memory(cntl, WCD_MEM_TYPE_ALWAYS_ON);
+		else if (event == WDSP_EVENT_PRE_DLOAD_DATA)
+			wcd_cntl_enable_memory(cntl, WCD_MEM_TYPE_SWITCHABLE);
+		break;
+
+	case WDSP_EVENT_DO_BOOT:
+
+		ret = wcd_cntl_do_boot(cntl);
+		if (ret < 0)
+			dev_err(codec->dev,
+				"%s: WDSP boot failed, err = %d\n",
+				__func__, ret);
+		break;
+
+	case WDSP_EVENT_DO_SHUTDOWN:
+
+		wcd_cntl_do_shutdown(cntl);
+		wcd_cntl_disable_memory(cntl, WCD_MEM_TYPE_SWITCHABLE);
+		break;
+
+	default:
+		dev_dbg(codec->dev, "%s: unhandled event %d\n",
+			__func__, event);
+	}
+
+done:
+	return ret;
+}
+
+static int wcd_cntl_sysfs_init(char *dir, struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+	int ret = 0;
+
+	ret = kobject_init_and_add(&cntl->wcd_kobj, &wcd_cntl_ktype,
+				   kernel_kobj, dir);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Failed to add kobject %s, err = %d\n",
+			__func__, dir, ret);
+		goto done;
+	}
+
+	ret = sysfs_create_file(&cntl->wcd_kobj, &cntl_attr_boot.attr);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Failed to add wdsp_boot sysfs entry to %s\n",
+			__func__, dir);
+		goto fail_create_file;
+	}
+
+	return ret;
+
+fail_create_file:
+	kobject_put(&cntl->wcd_kobj);
+done:
+	return ret;
+}
+
+static void wcd_cntl_sysfs_remove(struct wcd_dsp_cntl *cntl)
+{
+	sysfs_remove_file(&cntl->wcd_kobj, &cntl_attr_boot.attr);
+	kobject_put(&cntl->wcd_kobj);
+}
+
+static void wcd_cntl_debugfs_init(char *dir, struct wcd_dsp_cntl *cntl)
+{
+	struct snd_soc_codec *codec = cntl->codec;
+
+	cntl->entry = debugfs_create_dir(dir, NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		dev_err(codec->dev, "%s debugfs_create_dir failed for %s\n",
+			__func__, dir);
+		goto done;
+	}
+
+	debugfs_create_u32("debug_mode", 0644,
+			   cntl->entry, &cntl->debug_mode);
+	debugfs_create_bool("ramdump_enable", 0644,
+			    cntl->entry, &cntl->ramdump_enable);
+done:
+	return;
+}
+
+static void wcd_cntl_debugfs_remove(struct wcd_dsp_cntl *cntl)
+{
+	if (cntl)
+		debugfs_remove(cntl->entry);
+}
+
+static int wcd_miscdev_release(struct inode *inode, struct file *filep)
+{
+	struct wcd_dsp_cntl *cntl = container_of(filep->private_data,
+						 struct wcd_dsp_cntl, miscdev);
+	if (!cntl->m_dev || !cntl->m_ops ||
+	    !cntl->m_ops->vote_for_dsp) {
+		dev_err(cntl->codec->dev,
+			"%s: DSP not ready to boot\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Make sure the DSP users goes to zero upon closing dev node */
+	while (cntl->boot_reqs > 0) {
+		cntl->m_ops->vote_for_dsp(cntl->m_dev, false);
+		cntl->boot_reqs--;
+	}
+
+	return 0;
+}
+
+static ssize_t wcd_miscdev_write(struct file *filep, const char __user *ubuf,
+				 size_t count, loff_t *pos)
+{
+	struct wcd_dsp_cntl *cntl = container_of(filep->private_data,
+						 struct wcd_dsp_cntl, miscdev);
+	char val[count];
+	bool vote;
+	int ret = 0;
+
+	if (count == 0 || count > 2) {
+		pr_err("%s: Invalid count = %zd\n", __func__, count);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = copy_from_user(val, ubuf, count);
+	if (ret < 0) {
+		dev_err(cntl->codec->dev,
+			"%s: copy_from_user failed, err = %d\n",
+			__func__, ret);
+		ret = -EFAULT;
+		goto done;
+	}
+
+	if (val[0] == '1') {
+		cntl->boot_reqs++;
+		vote = true;
+	} else if (val[0] == '0') {
+		if (cntl->boot_reqs == 0) {
+			dev_err(cntl->codec->dev,
+				"%s: WDSP already disabled\n", __func__);
+			ret = -EINVAL;
+			goto done;
+		}
+		cntl->boot_reqs--;
+		vote = false;
+	} else {
+		dev_err(cntl->codec->dev, "%s: Invalid value %s\n",
+			__func__, val);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	dev_dbg(cntl->codec->dev,
+		"%s: booted = %s, ref_cnt = %d, vote = %s\n",
+		__func__, cntl->is_wdsp_booted ? "true" : "false",
+		cntl->boot_reqs, vote ? "true" : "false");
+
+	if (cntl->m_dev && cntl->m_ops &&
+	    cntl->m_ops->vote_for_dsp)
+		ret = cntl->m_ops->vote_for_dsp(cntl->m_dev, vote);
+	else
+		ret = -EINVAL;
+done:
+	if (ret)
+		return ret;
+	else
+		return count;
+}
+
+static const struct file_operations wcd_miscdev_fops = {
+	.write = wcd_miscdev_write,
+	.release = wcd_miscdev_release,
+};
+
+static int wcd_cntl_miscdev_create(struct wcd_dsp_cntl *cntl)
+{
+	snprintf(cntl->miscdev_name, ARRAY_SIZE(cntl->miscdev_name),
+		"wcd_dsp%u_control", cntl->dsp_instance);
+	cntl->miscdev.minor = MISC_DYNAMIC_MINOR;
+	cntl->miscdev.name = cntl->miscdev_name;
+	cntl->miscdev.fops = &wcd_miscdev_fops;
+	cntl->miscdev.parent = cntl->codec->dev;
+
+	return misc_register(&cntl->miscdev);
+}
+
+static void wcd_cntl_miscdev_destroy(struct wcd_dsp_cntl *cntl)
+{
+	misc_deregister(&cntl->miscdev);
+}
+
+static int wcd_control_init(struct device *dev, void *priv_data)
+{
+	struct wcd_dsp_cntl *cntl = priv_data;
+	struct snd_soc_codec *codec = cntl->codec;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+	int ret;
+	bool err_irq_requested = false;
+
+	ret = wcd9xxx_request_irq(core_res,
+				  cntl->irqs.cpe_ipc1_irq,
+				  wcd_cntl_ipc_irq, "CPE IPC1",
+				  cntl);
+	if (ret < 0) {
+		dev_err(codec->dev,
+			"%s: Failed to request cpe ipc irq, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	/* Unmask the fatal irqs */
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A,
+		      ~(cntl->irqs.fatal_irqs & 0xFF));
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B,
+		      ~((cntl->irqs.fatal_irqs >> 8) & 0xFF));
+
+	/*
+	 * CPE ERR irq is used only for error reporting from WCD DSP,
+	 * even if this request fails, DSP can be function normally.
+	 * Continuing with init even if the CPE ERR irq request fails.
+	 */
+	if (wcd9xxx_request_irq(core_res, cntl->irqs.cpe_err_irq,
+				wcd_cntl_err_irq, "CPE ERR", cntl))
+		dev_info(codec->dev, "%s: Failed request_irq(cpe_err_irq)",
+			__func__);
+	else
+		err_irq_requested = true;
+
+
+	/* Enable all the clocks */
+	ret = wcd_cntl_clocks_enable(cntl);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: Failed to enable clocks, err = %d\n",
+			__func__, ret);
+		goto err_clk_enable;
+	}
+	wcd_cntl_cpar_ctrl(cntl, true);
+
+	return 0;
+
+err_clk_enable:
+	/* Mask all error interrupts */
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, 0xFF);
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, 0xFF);
+
+	/* Free the irq's requested */
+	wcd9xxx_free_irq(core_res, cntl->irqs.cpe_ipc1_irq, cntl);
+
+	if (err_irq_requested)
+		wcd9xxx_free_irq(core_res, cntl->irqs.cpe_err_irq, cntl);
+done:
+	return ret;
+}
+
+static int wcd_control_deinit(struct device *dev, void *priv_data)
+{
+	struct wcd_dsp_cntl *cntl = priv_data;
+	struct snd_soc_codec *codec = cntl->codec;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+
+	wcd_cntl_clocks_disable(cntl);
+	wcd_cntl_cpar_ctrl(cntl, false);
+
+	/* Mask all error interrupts */
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, 0xFF);
+	snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, 0xFF);
+
+	/* Free the irq's requested */
+	wcd9xxx_free_irq(core_res, cntl->irqs.cpe_err_irq, cntl);
+	wcd9xxx_free_irq(core_res, cntl->irqs.cpe_ipc1_irq, cntl);
+
+	return 0;
+}
+
+static struct wdsp_cmpnt_ops control_ops = {
+	.init = wcd_control_init,
+	.deinit = wcd_control_deinit,
+	.event_handler = wcd_control_handler,
+};
+
+static int wcd_ctrl_component_bind(struct device *dev,
+				   struct device *master,
+				   void *data)
+{
+	struct wcd_dsp_cntl *cntl;
+	struct snd_soc_codec *codec;
+	struct snd_card *card;
+	struct snd_info_entry *entry;
+	char proc_name[WCD_PROCFS_ENTRY_MAX_LEN];
+	char wcd_cntl_dir_name[WCD_CNTL_DIR_NAME_LEN_MAX];
+	int ret = 0;
+
+	if (!dev || !master || !data) {
+		pr_err("%s: Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	cntl = tavil_get_wcd_dsp_cntl(dev);
+	if (!cntl) {
+		dev_err(dev, "%s: Failed to get cntl reference\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	cntl->m_dev = master;
+	cntl->m_ops = data;
+
+	if (!cntl->m_ops->register_cmpnt_ops) {
+		dev_err(dev, "%s: invalid master callback register_cmpnt_ops\n",
+			__func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = cntl->m_ops->register_cmpnt_ops(master, dev, cntl, &control_ops);
+	if (ret) {
+		dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	ret = wcd_cntl_miscdev_create(cntl);
+	if (ret < 0) {
+		dev_err(dev, "%s: misc dev register failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	snprintf(wcd_cntl_dir_name, WCD_CNTL_DIR_NAME_LEN_MAX,
+		 "%s%d", "wdsp", cntl->dsp_instance);
+	ret = wcd_cntl_sysfs_init(wcd_cntl_dir_name, cntl);
+	if (ret < 0) {
+		dev_err(dev, "%s: sysfs_init failed, err = %d\n",
+			__func__, ret);
+		goto err_sysfs_init;
+	}
+
+	wcd_cntl_debugfs_init(wcd_cntl_dir_name, cntl);
+
+	codec = cntl->codec;
+	card = codec->component.card->snd_card;
+	snprintf(proc_name, WCD_PROCFS_ENTRY_MAX_LEN, "%s%d%s", "cpe",
+		 cntl->dsp_instance, "_state");
+	entry = snd_info_create_card_entry(card, proc_name, card->proc_root);
+	if (!entry) {
+		/* Do not treat this as Fatal error */
+		dev_err(dev, "%s: Failed to create procfs entry %s\n",
+			__func__, proc_name);
+		goto err_sysfs_init;
+	}
+
+	cntl->ssr_entry.entry = entry;
+	cntl->ssr_entry.offline = 1;
+	entry->size = WCD_PROCFS_ENTRY_MAX_LEN;
+	entry->content = SNDRV_INFO_CONTENT_DATA;
+	entry->c.ops = &wdsp_ssr_entry_ops;
+	entry->private_data = cntl;
+	ret = snd_info_register(entry);
+	if (ret < 0) {
+		dev_err(dev, "%s: Failed to register entry %s, err = %d\n",
+			__func__, proc_name, ret);
+		snd_info_free_entry(entry);
+		/* Let bind still happen even if creating the entry failed */
+		ret = 0;
+	}
+done:
+	return ret;
+
+err_sysfs_init:
+	wcd_cntl_miscdev_destroy(cntl);
+	return ret;
+}
+
+static void wcd_ctrl_component_unbind(struct device *dev,
+				      struct device *master,
+				      void *data)
+{
+	struct wcd_dsp_cntl *cntl;
+
+	if (!dev) {
+		pr_err("%s: Invalid device\n", __func__);
+		return;
+	}
+
+	cntl = tavil_get_wcd_dsp_cntl(dev);
+	if (!cntl) {
+		dev_err(dev, "%s: Failed to get cntl reference\n",
+			__func__);
+		return;
+	}
+
+	cntl->m_dev = NULL;
+	cntl->m_ops = NULL;
+
+	/* Remove the sysfs entries */
+	wcd_cntl_sysfs_remove(cntl);
+
+	/* Remove the debugfs entries */
+	wcd_cntl_debugfs_remove(cntl);
+
+	/* Remove the misc device */
+	wcd_cntl_miscdev_destroy(cntl);
+}
+
+static const struct component_ops wcd_ctrl_component_ops = {
+	.bind = wcd_ctrl_component_bind,
+	.unbind = wcd_ctrl_component_unbind,
+};
+
+/*
+ * wcd_dsp_ssr_event: handle the SSR event raised by caller.
+ * @cntl: Handle to the wcd_dsp_cntl structure
+ * @event: The SSR event to be handled
+ *
+ * Notifies the manager driver about the SSR event.
+ * Returns 0 on success and negative error code on error.
+ */
+int wcd_dsp_ssr_event(struct wcd_dsp_cntl *cntl, enum cdc_ssr_event event)
+{
+	int ret = 0;
+
+	if (!cntl) {
+		pr_err("%s: Invalid handle to control\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!cntl->m_dev || !cntl->m_ops || !cntl->m_ops->signal_handler) {
+		dev_err(cntl->codec->dev,
+			"%s: Invalid signal_handler callback\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case WCD_CDC_DOWN_EVENT:
+		ret = cntl->m_ops->signal_handler(cntl->m_dev,
+						  WDSP_CDC_DOWN_SIGNAL,
+						  NULL);
+		if (ret < 0)
+			dev_err(cntl->codec->dev,
+				"%s: WDSP_CDC_DOWN_SIGNAL failed, err = %d\n",
+				__func__, ret);
+		wcd_cntl_change_online_state(cntl, 0);
+		break;
+	case WCD_CDC_UP_EVENT:
+		ret = cntl->m_ops->signal_handler(cntl->m_dev,
+						  WDSP_CDC_UP_SIGNAL,
+						  NULL);
+		if (ret < 0)
+			dev_err(cntl->codec->dev,
+				"%s: WDSP_CDC_UP_SIGNAL failed, err = %d\n",
+				__func__, ret);
+		break;
+	default:
+		dev_err(cntl->codec->dev, "%s: Invalid event %d\n",
+			__func__, event);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd_dsp_ssr_event);
+
+/*
+ * wcd_dsp_cntl_init: Initialize the wcd-dsp control
+ * @codec: pointer to the codec handle
+ * @params: Parameters required to initialize wcd-dsp control
+ *
+ * This API is expected to be invoked by the codec driver and
+ * provide information essential for the wcd dsp control to
+ * configure and initialize the dsp
+ */
+void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
+		       struct wcd_dsp_params *params,
+		       struct wcd_dsp_cntl **cntl)
+{
+	struct wcd_dsp_cntl *control;
+	int ret;
+
+	if (!codec || !params) {
+		pr_err("%s: Invalid handle to %s\n", __func__,
+		       (!codec) ? "codec" : "params");
+		*cntl = NULL;
+		return;
+	}
+
+	if (*cntl) {
+		pr_err("%s: cntl is non NULL, maybe already initialized ?\n",
+			__func__);
+		return;
+	}
+
+	if (!params->cb || !params->cb->cdc_clk_en ||
+	    !params->cb->cdc_vote_svs) {
+		dev_err(codec->dev,
+			"%s: clk_en and vote_svs callbacks must be provided\n",
+			__func__);
+		return;
+	}
+
+	control = kzalloc(sizeof(*control), GFP_KERNEL);
+	if (!(control))
+		return;
+
+	control->codec = codec;
+	control->clk_rate = params->clk_rate;
+	control->cdc_cb = params->cb;
+	control->dsp_instance = params->dsp_instance;
+	memcpy(&control->irqs, &params->irqs, sizeof(control->irqs));
+	init_completion(&control->boot_complete);
+	mutex_init(&control->clk_mutex);
+	mutex_init(&control->ssr_mutex);
+	init_waitqueue_head(&control->ssr_entry.offline_poll_wait);
+
+	/*
+	 * The default state of WDSP is in SVS mode.
+	 * Vote for SVS now, the vote will be removed only
+	 * after DSP is booted up.
+	 */
+	control->cdc_cb->cdc_vote_svs(codec, true);
+
+	/*
+	 * If this is the last component needed by master to be ready,
+	 * then component_bind will be called within the component_add.
+	 * Hence, the data pointer should be assigned before component_add,
+	 * so that we can access it during this component's bind call.
+	 */
+	*cntl = control;
+	ret = component_add(codec->dev, &wcd_ctrl_component_ops);
+	if (ret) {
+		dev_err(codec->dev, "%s: component_add failed, err = %d\n",
+			__func__, ret);
+		kfree(*cntl);
+		*cntl = NULL;
+	}
+}
+EXPORT_SYMBOL(wcd_dsp_cntl_init);
+
+/*
+ * wcd_dsp_cntl_deinit: De-initialize the wcd-dsp control
+ * @cntl: The struct wcd_dsp_cntl to de-initialize
+ *
+ * This API is intended to be invoked by the codec driver
+ * to de-initialize the wcd dsp control
+ */
+void wcd_dsp_cntl_deinit(struct wcd_dsp_cntl **cntl)
+{
+	struct wcd_dsp_cntl *control = *cntl;
+	struct snd_soc_codec *codec;
+
+	/* If control is NULL, there is nothing to de-initialize */
+	if (!control)
+		return;
+	codec = control->codec;
+
+	/*
+	 * Calling shutdown will cleanup all register states,
+	 * irrespective of DSP was booted up or not.
+	 */
+	wcd_cntl_do_shutdown(control);
+	wcd_cntl_disable_memory(control, WCD_MEM_TYPE_SWITCHABLE);
+	wcd_cntl_disable_memory(control, WCD_MEM_TYPE_ALWAYS_ON);
+
+	component_del(codec->dev, &wcd_ctrl_component_ops);
+
+	mutex_destroy(&control->clk_mutex);
+	mutex_destroy(&control->ssr_mutex);
+	kfree(*cntl);
+	*cntl = NULL;
+}
+EXPORT_SYMBOL(wcd_dsp_cntl_deinit);
diff --git a/asoc/codecs/wcd934x/wcd934x-dsp-cntl.h b/asoc/codecs/wcd934x/wcd934x-dsp-cntl.h
new file mode 100644
index 0000000..e934638
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-dsp-cntl.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD934X_DSP_CNTL_H__
+#define __WCD934X_DSP_CNTL_H__
+
+#include <sound/soc.h>
+#include <sound/wcd-dsp-mgr.h>
+
+enum cdc_ssr_event {
+	WCD_CDC_DOWN_EVENT,
+	WCD_CDC_UP_EVENT,
+};
+
+struct wcd_dsp_cdc_cb {
+	/* Callback to enable codec clock */
+	int (*cdc_clk_en)(struct snd_soc_codec *, bool);
+	/* Callback to vote and unvote for SVS2 mode */
+	void (*cdc_vote_svs)(struct snd_soc_codec *, bool);
+};
+
+struct wcd_dsp_irq_info {
+	/* IPC interrupt */
+	int cpe_ipc1_irq;
+
+	/* CPE error summary interrupt */
+	int cpe_err_irq;
+
+	/*
+	 * Bit mask to indicate which of the
+	 * error interrupts are to be considered
+	 * as fatal.
+	 */
+	u16 fatal_irqs;
+};
+
+struct wcd_dsp_params {
+	struct wcd_dsp_cdc_cb *cb;
+	struct wcd_dsp_irq_info irqs;
+
+	/* Rate at which the codec clock operates */
+	u32 clk_rate;
+
+	/*
+	 * Represents the dsp instance, will be used
+	 * to create sysfs and debugfs entries with
+	 * directory wdsp<dsp-instance>
+	 */
+	u32 dsp_instance;
+};
+
+struct wdsp_ssr_entry {
+	u8 offline;
+	u8 offline_change;
+	wait_queue_head_t offline_poll_wait;
+	struct snd_info_entry *entry;
+};
+
+struct wcd_dsp_cntl {
+	/* Handle to codec */
+	struct snd_soc_codec *codec;
+
+	/* Clk rate of the codec clock */
+	u32 clk_rate;
+
+	/* Callbacks to codec driver */
+	const struct wcd_dsp_cdc_cb *cdc_cb;
+
+	/* Completion to indicate WDSP boot done */
+	struct completion boot_complete;
+
+	struct wcd_dsp_irq_info irqs;
+	u32 dsp_instance;
+
+	/* Sysfs entries related */
+	int boot_reqs;
+	struct kobject wcd_kobj;
+
+	/* Debugfs related */
+	struct dentry *entry;
+	u32 debug_mode;
+	bool ramdump_enable;
+
+	/* WDSP manager drivers data */
+	struct device *m_dev;
+	struct wdsp_mgr_ops *m_ops;
+
+	/* clk related */
+	struct mutex clk_mutex;
+	bool is_clk_enabled;
+
+	/* Keep track of WDSP boot status */
+	bool is_wdsp_booted;
+
+	/* SSR related */
+	struct wdsp_ssr_entry ssr_entry;
+	struct mutex ssr_mutex;
+
+	/* Misc device related */
+	char miscdev_name[256];
+	struct miscdevice miscdev;
+};
+
+void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
+		       struct wcd_dsp_params *params,
+		       struct wcd_dsp_cntl **cntl);
+void wcd_dsp_cntl_deinit(struct wcd_dsp_cntl **cntl);
+int wcd_dsp_ssr_event(struct wcd_dsp_cntl *cntl, enum cdc_ssr_event event);
+#endif /* end __WCD_DSP_CONTROL_H__ */
diff --git a/asoc/codecs/wcd934x/wcd934x-mbhc.c b/asoc/codecs/wcd934x/wcd934x-mbhc.c
new file mode 100644
index 0000000..9595ba8
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-mbhc.c
@@ -0,0 +1,1144 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "wcd934x.h"
+#include "wcd934x-mbhc.h"
+#include <asoc/wcd934x_registers.h>
+#include "wcd934x_irq.h"
+#include "../core.h"
+#include "../pdata.h"
+#include "../wcd9xxx-irq.h"
+#include "../wcdcal-hwdep.h"
+#include "../wcd-mbhc-v2-api.h"
+
+#define TAVIL_ZDET_SUPPORTED          true
+/* Z value defined in milliohm */
+#define TAVIL_ZDET_VAL_32             32000
+#define TAVIL_ZDET_VAL_400            400000
+#define TAVIL_ZDET_VAL_1200           1200000
+#define TAVIL_ZDET_VAL_100K           100000000
+/* Z floating defined in ohms */
+#define TAVIL_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
+
+#define TAVIL_ZDET_NUM_MEASUREMENTS   150
+#define TAVIL_MBHC_GET_C1(c)          ((c & 0xC000) >> 14)
+#define TAVIL_MBHC_GET_X1(x)          (x & 0x3FFF)
+/* Z value compared in milliOhm */
+#define TAVIL_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
+#define TAVIL_MBHC_ZDET_CONST         (86 * 16384)
+#define TAVIL_MBHC_MOISTURE_RREF      R_24_KOHM
+
+static struct wcd_mbhc_register
+	wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
+	WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
+			  WCD934X_ANA_MBHC_MECH, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+			  WCD934X_ANA_MBHC_MECH, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+			  WCD934X_ANA_MBHC_MECH, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+			  WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0x30, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+			  WCD934X_ANA_MBHC_ELECT, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+			  WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+			  WCD934X_ANA_MBHC_MECH, 0x04, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+			  WCD934X_ANA_MBHC_MECH, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+			  WCD934X_ANA_MBHC_MECH, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+			  WCD934X_ANA_MBHC_MECH, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+			  WCD934X_ANA_MBHC_ELECT, 0x06, 1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+			  WCD934X_ANA_MBHC_ELECT, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+			  WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+			  WCD934X_MBHC_NEW_CTL_1, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+			  WCD934X_MBHC_NEW_CTL_2, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+			  WCD934X_ANA_MBHC_RESULT_3, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+			  WCD934X_ANA_MBHC_RESULT_3, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+			  WCD934X_ANA_MBHC_RESULT_3, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+			  WCD934X_ANA_MBHC_RESULT_3, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+			  WCD934X_HPH_OCP_CTL, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+			  WCD934X_ANA_MBHC_RESULT_3, 0x07, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+			  WCD934X_ANA_MBHC_ELECT, 0x70, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+			  WCD934X_ANA_MBHC_RESULT_3, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+			  WCD934X_ANA_MICB2, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+			  WCD934X_HPH_CNP_WG_TIME, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+			  WCD934X_ANA_HPH, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+			  WCD934X_ANA_HPH, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+			  WCD934X_ANA_HPH, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+			  WCD934X_ANA_MBHC_RESULT_3, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
+			  0, 0, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
+			  WCD934X_MBHC_CTL_BCS, 0x02, 1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
+			  WCD934X_MBHC_STATUS_SPARE_1, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
+			  WCD934X_MBHC_NEW_CTL_2, 0x70, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN",
+			  WCD934X_HPH_L_TEST, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN",
+			  WCD934X_HPH_R_TEST, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS",
+			  WCD934X_INTR_PIN1_STATUS0, 0x04, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS",
+			  WCD934X_INTR_PIN1_STATUS0, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN",
+			  WCD934X_MBHC_NEW_CTL_1, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD934X_MBHC_NEW_FSM_STATUS,
+			  0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD934X_MBHC_NEW_FSM_STATUS,
+			  0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD934X_MBHC_NEW_ADC_RESULT,
+			  0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD934X_ANA_MICB2, 0x3F, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE",
+			  WCD934X_MBHC_NEW_CTL_1, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE",
+			  WCD934X_MBHC_NEW_CTL_1, 0x04, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN",
+			  WCD934X_ANA_MBHC_ZDET, 0x02, 1, 0),
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+	.mbhc_sw_intr =  WCD934X_IRQ_MBHC_SW_DET,
+	.mbhc_btn_press_intr = WCD934X_IRQ_MBHC_BUTTON_PRESS_DET,
+	.mbhc_btn_release_intr = WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET,
+	.mbhc_hs_ins_intr = WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	.mbhc_hs_rem_intr = WCD934X_IRQ_MBHC_ELECT_INS_REM_DET,
+	.hph_left_ocp = WCD934X_IRQ_HPH_PA_OCPL_FAULT,
+	.hph_right_ocp = WCD934X_IRQ_HPH_PA_OCPR_FAULT,
+};
+
+
+static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
+	"cdc-vdd-mic-bias",
+};
+
+struct tavil_mbhc_zdet_param {
+	u16 ldo_ctl;
+	u16 noff;
+	u16 nshift;
+	u16 btn5;
+	u16 btn6;
+	u16 btn7;
+};
+
+static int tavil_mbhc_request_irq(struct snd_soc_codec *codec,
+				  int irq, irq_handler_t handler,
+				  const char *name, void *data)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	return wcd9xxx_request_irq(core_res, irq, handler, name, data);
+}
+
+static void tavil_mbhc_irq_control(struct snd_soc_codec *codec,
+				   int irq, bool enable)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+	if (enable)
+		wcd9xxx_enable_irq(core_res, irq);
+	else
+		wcd9xxx_disable_irq(core_res, irq);
+}
+
+static int tavil_mbhc_free_irq(struct snd_soc_codec *codec,
+			       int irq, void *data)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	wcd9xxx_free_irq(core_res, irq, data);
+	return 0;
+}
+
+static void tavil_mbhc_clk_setup(struct snd_soc_codec *codec,
+				 bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1,
+				    0x80, 0x80);
+	else
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1,
+				    0x80, 0x00);
+}
+
+static int tavil_mbhc_btn_to_num(struct snd_soc_codec *codec)
+{
+	return snd_soc_read(codec, WCD934X_ANA_MBHC_RESULT_3) & 0x7;
+}
+
+static int tavil_enable_ext_mb_source(struct wcd_mbhc *mbhc,
+				      bool turn_on)
+{
+	struct wcd934x_mbhc *wcd934x_mbhc;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd934x_on_demand_supply *supply;
+	int ret = 0;
+
+	wcd934x_mbhc = container_of(mbhc, struct wcd934x_mbhc, wcd_mbhc);
+
+	supply =  &wcd934x_mbhc->on_demand_list[WCD934X_ON_DEMAND_MICBIAS];
+	if (!supply->supply) {
+		dev_dbg(codec->dev, "%s: warning supply not present ond for %s\n",
+				__func__, "onDemand Micbias");
+		return ret;
+	}
+
+	dev_dbg(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
+		supply->ondemand_supply_count);
+
+	if (turn_on) {
+		if (!(supply->ondemand_supply_count)) {
+			ret = snd_soc_dapm_force_enable_pin(
+				snd_soc_codec_get_dapm(codec),
+				"MICBIAS_REGULATOR");
+			snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+		}
+		supply->ondemand_supply_count++;
+	} else {
+		if (supply->ondemand_supply_count > 0)
+			supply->ondemand_supply_count--;
+		if (!(supply->ondemand_supply_count)) {
+			ret = snd_soc_dapm_disable_pin(
+				snd_soc_codec_get_dapm(codec),
+				"MICBIAS_REGULATOR");
+		snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+		}
+	}
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			__func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static void tavil_mbhc_mbhc_bias_control(struct snd_soc_codec *codec,
+					 bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD934X_ANA_MBHC_ELECT,
+				    0x01, 0x01);
+	else
+		snd_soc_update_bits(codec, WCD934X_ANA_MBHC_ELECT,
+				    0x01, 0x00);
+}
+
+static void tavil_mbhc_program_btn_thr(struct snd_soc_codec *codec,
+				       s16 *btn_low, s16 *btn_high,
+				       int num_btn, bool is_micbias)
+{
+	int i;
+	int vth;
+
+	if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+		dev_err(codec->dev, "%s: invalid number of buttons: %d\n",
+			__func__, num_btn);
+		return;
+	}
+	/*
+	 * Tavil just needs one set of thresholds for button detection
+	 * due to micbias voltage ramp to pullup upon button press. So
+	 * btn_low and is_micbias are ignored and always program button
+	 * thresholds using btn_high.
+	 */
+	for (i = 0; i < num_btn; i++) {
+		vth = ((btn_high[i] * 2) / 25) & 0x3F;
+		snd_soc_update_bits(codec, WCD934X_ANA_MBHC_BTN0 + i,
+				    0xFC, vth << 2);
+		dev_dbg(codec->dev, "%s: btn_high[%d]: %d, vth: %d\n",
+			__func__, i, btn_high[i], vth);
+	}
+}
+
+static bool tavil_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+	bool ret = 0;
+
+	if (lock)
+		ret = wcd9xxx_lock_sleep(core_res);
+	else
+		wcd9xxx_unlock_sleep(core_res);
+
+	return ret;
+}
+
+static int tavil_mbhc_register_notifier(struct wcd_mbhc *mbhc,
+					struct notifier_block *nblock,
+					bool enable)
+{
+	struct wcd934x_mbhc *wcd934x_mbhc;
+
+	wcd934x_mbhc = container_of(mbhc, struct wcd934x_mbhc, wcd_mbhc);
+
+	if (enable)
+		return blocking_notifier_chain_register(&wcd934x_mbhc->notifier,
+							nblock);
+	else
+		return blocking_notifier_chain_unregister(
+				&wcd934x_mbhc->notifier, nblock);
+}
+
+static bool tavil_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+	u8 val;
+
+	if (micb_num == MIC_BIAS_2) {
+		val = (snd_soc_read(mbhc->codec, WCD934X_ANA_MICB2) >> 6);
+		if (val == 0x01)
+			return true;
+	}
+	return false;
+}
+
+static bool tavil_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
+{
+	return (snd_soc_read(codec, WCD934X_ANA_HPH) & 0xC0) ? true : false;
+}
+
+static void tavil_mbhc_hph_l_pull_up_control(
+		struct snd_soc_codec *codec,
+		enum mbhc_hs_pullup_iref pull_up_cur)
+{
+	/* Default pull up current to 2uA */
+	if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA ||
+	    pull_up_cur == I_DEFAULT)
+		pull_up_cur = I_2P0_UA;
+
+	dev_dbg(codec->dev, "%s: HS pull up current:%d\n",
+		__func__, pull_up_cur);
+
+	snd_soc_update_bits(codec, WCD934X_MBHC_NEW_PLUG_DETECT_CTL,
+			    0xC0, pull_up_cur << 6);
+}
+
+static int tavil_mbhc_request_micbias(struct snd_soc_codec *codec,
+				      int micb_num, int req)
+{
+	int ret;
+
+	/*
+	 * If micbias is requested, make sure that there
+	 * is vote to enable mclk
+	 */
+	if (req == MICB_ENABLE)
+		tavil_cdc_mclk_enable(codec, true);
+
+	ret = tavil_micbias_control(codec, micb_num, req, false);
+
+	/*
+	 * Release vote for mclk while requesting for
+	 * micbias disable
+	 */
+	if (req == MICB_DISABLE)
+		tavil_cdc_mclk_enable(codec, false);
+
+	return ret;
+}
+
+static void tavil_mbhc_micb_ramp_control(struct snd_soc_codec *codec,
+					 bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD934X_ANA_MICB2_RAMP,
+				    0x1C, 0x0C);
+		snd_soc_update_bits(codec, WCD934X_ANA_MICB2_RAMP,
+				    0x80, 0x80);
+	} else {
+		snd_soc_update_bits(codec, WCD934X_ANA_MICB2_RAMP,
+				    0x80, 0x00);
+		snd_soc_update_bits(codec, WCD934X_ANA_MICB2_RAMP,
+				    0x1C, 0x00);
+	}
+}
+
+static struct firmware_cal *tavil_get_hwdep_fw_cal(struct wcd_mbhc *mbhc,
+						   enum wcd_cal_type type)
+{
+	struct wcd934x_mbhc *wcd934x_mbhc;
+	struct firmware_cal *hwdep_cal;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	wcd934x_mbhc = container_of(mbhc, struct wcd934x_mbhc, wcd_mbhc);
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer\n", __func__);
+		return NULL;
+	}
+	hwdep_cal = wcdcal_get_fw_cal(wcd934x_mbhc->fw_data, type);
+	if (!hwdep_cal)
+		dev_err(codec->dev, "%s: cal not sent by %d\n",
+			__func__, type);
+
+	return hwdep_cal;
+}
+
+static int tavil_mbhc_micb_ctrl_threshold_mic(struct snd_soc_codec *codec,
+					      int micb_num, bool req_en)
+{
+	struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent);
+	int rc, micb_mv;
+
+	if (micb_num != MIC_BIAS_2)
+		return -EINVAL;
+
+	/*
+	 * If device tree micbias level is already above the minimum
+	 * voltage needed to detect threshold microphone, then do
+	 * not change the micbias, just return.
+	 */
+	if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+		return 0;
+
+	micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv;
+
+	rc = tavil_mbhc_micb_adjust_voltage(codec, micb_mv, MIC_BIAS_2);
+
+	return rc;
+}
+
+static inline void tavil_mbhc_get_result_params(struct wcd9xxx *wcd9xxx,
+						s16 *d1_a, u16 noff,
+						int32_t *zdet)
+{
+	int i;
+	int val, val1;
+	s16 c1;
+	s32 x1, d1;
+	int32_t denom;
+	int minCode_param[] = {
+			3277, 1639, 820, 410, 205, 103, 52, 26
+	};
+
+	regmap_update_bits(wcd9xxx->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x20);
+	for (i = 0; i < TAVIL_ZDET_NUM_MEASUREMENTS; i++) {
+		regmap_read(wcd9xxx->regmap, WCD934X_ANA_MBHC_RESULT_2, &val);
+		if (val & 0x80)
+			break;
+	}
+	val = val << 0x8;
+	regmap_read(wcd9xxx->regmap, WCD934X_ANA_MBHC_RESULT_1, &val1);
+	val |= val1;
+	regmap_update_bits(wcd9xxx->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x00);
+	x1 = TAVIL_MBHC_GET_X1(val);
+	c1 = TAVIL_MBHC_GET_C1(val);
+	/* If ramp is not complete, give additional 5ms */
+	if ((c1 < 2) && x1)
+		usleep_range(5000, 5050);
+
+	if (!c1 || !x1) {
+		dev_dbg(wcd9xxx->dev,
+			"%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
+			__func__, c1, x1);
+		goto ramp_down;
+	}
+	d1 = d1_a[c1];
+	denom = (x1 * d1) - (1 << (14 - noff));
+	if (denom > 0)
+		*zdet = (TAVIL_MBHC_ZDET_CONST * 1000) / denom;
+	else if (x1 < minCode_param[noff])
+		*zdet = TAVIL_ZDET_FLOATING_IMPEDANCE;
+
+	dev_dbg(wcd9xxx->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+		__func__, d1, c1, x1, *zdet);
+ramp_down:
+	i = 0;
+	while (x1) {
+		regmap_bulk_read(wcd9xxx->regmap,
+				 WCD934X_ANA_MBHC_RESULT_1, (u8 *)&val, 2);
+		x1 = TAVIL_MBHC_GET_X1(val);
+		i++;
+		if (i == TAVIL_ZDET_NUM_MEASUREMENTS)
+			break;
+	}
+}
+
+static void tavil_mbhc_zdet_ramp(struct snd_soc_codec *codec,
+				 struct tavil_mbhc_zdet_param *zdet_param,
+				 int32_t *zl, int32_t *zr, s16 *d1_a)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	int32_t zdet = 0;
+
+	snd_soc_update_bits(codec, WCD934X_MBHC_NEW_ZDET_ANA_CTL, 0x70,
+			    zdet_param->ldo_ctl << 4);
+	snd_soc_update_bits(codec, WCD934X_ANA_MBHC_BTN5, 0xFC,
+			    zdet_param->btn5);
+	snd_soc_update_bits(codec, WCD934X_ANA_MBHC_BTN6, 0xFC,
+			    zdet_param->btn6);
+	snd_soc_update_bits(codec, WCD934X_ANA_MBHC_BTN7, 0xFC,
+			    zdet_param->btn7);
+	snd_soc_update_bits(codec, WCD934X_MBHC_NEW_ZDET_ANA_CTL, 0x0F,
+			    zdet_param->noff);
+	snd_soc_update_bits(codec, WCD934X_MBHC_NEW_ZDET_RAMP_CTL, 0x0F,
+			    zdet_param->nshift);
+
+	if (!zl)
+		goto z_right;
+	/* Start impedance measurement for HPH_L */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD934X_ANA_MBHC_ZDET, 0x80, 0x80);
+	dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_L, noff = %d\n",
+		__func__, zdet_param->noff);
+	tavil_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD934X_ANA_MBHC_ZDET, 0x80, 0x00);
+
+	*zl = zdet;
+
+z_right:
+	if (!zr)
+		return;
+	/* Start impedance measurement for HPH_R */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD934X_ANA_MBHC_ZDET, 0x40, 0x40);
+	dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_R, noff = %d\n",
+		__func__, zdet_param->noff);
+	tavil_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD934X_ANA_MBHC_ZDET, 0x40, 0x00);
+
+	*zr = zdet;
+}
+
+static inline void tavil_wcd_mbhc_qfuse_cal(struct snd_soc_codec *codec,
+					    int32_t *z_val, int flag_l_r)
+{
+	s16 q1;
+	int q1_cal;
+
+	if (*z_val < (TAVIL_ZDET_VAL_400/1000))
+		q1 = snd_soc_read(codec,
+			WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 + (2 * flag_l_r));
+	else
+		q1 = snd_soc_read(codec,
+			WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 + (2 * flag_l_r));
+	if (q1 & 0x80)
+		q1_cal = (10000 - ((q1 & 0x7F) * 25));
+	else
+		q1_cal = (10000 + (q1 * 25));
+	if (q1_cal > 0)
+		*z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void tavil_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
+					  uint32_t *zr)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	s16 reg0, reg1, reg2, reg3, reg4;
+	int32_t z1L, z1R, z1Ls;
+	int zMono, z_diff1, z_diff2;
+	bool is_fsm_disable = false;
+	struct tavil_mbhc_zdet_param zdet_param[] = {
+		{4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+		{2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+		{1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+		{1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+	};
+	struct tavil_mbhc_zdet_param *zdet_param_ptr = NULL;
+	s16 d1_a[][4] = {
+		{0, 30, 90, 30},
+		{0, 30, 30, 5},
+		{0, 30, 30, 5},
+		{0, 30, 30, 5},
+	};
+	s16 *d1 = NULL;
+
+	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+	reg0 = snd_soc_read(codec, WCD934X_ANA_MBHC_BTN5);
+	reg1 = snd_soc_read(codec, WCD934X_ANA_MBHC_BTN6);
+	reg2 = snd_soc_read(codec, WCD934X_ANA_MBHC_BTN7);
+	reg3 = snd_soc_read(codec, WCD934X_MBHC_CTL_CLK);
+	reg4 = snd_soc_read(codec, WCD934X_MBHC_NEW_ZDET_ANA_CTL);
+
+	if (snd_soc_read(codec, WCD934X_ANA_MBHC_ELECT) & 0x80) {
+		is_fsm_disable = true;
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD934X_ANA_MBHC_ELECT, 0x80, 0x00);
+	}
+
+	/* For NO-jack, disable L_DET_EN before Z-det measurements */
+	if (mbhc->hphl_swh)
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD934X_ANA_MBHC_MECH, 0x80, 0x00);
+
+	/* Turn off 100k pull down on HPHL */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD934X_ANA_MBHC_MECH, 0x01, 0x00);
+
+	/* First get impedance on Left */
+	d1 = d1_a[1];
+	zdet_param_ptr = &zdet_param[1];
+	tavil_mbhc_zdet_ramp(codec, zdet_param_ptr, &z1L, NULL, d1);
+
+	if (!TAVIL_MBHC_IS_SECOND_RAMP_REQUIRED(z1L))
+		goto left_ch_impedance;
+
+	/* Second ramp for left ch */
+	if (z1L < TAVIL_ZDET_VAL_32) {
+		zdet_param_ptr = &zdet_param[0];
+		d1 = d1_a[0];
+	} else if ((z1L > TAVIL_ZDET_VAL_400) && (z1L <= TAVIL_ZDET_VAL_1200)) {
+		zdet_param_ptr = &zdet_param[2];
+		d1 = d1_a[2];
+	} else if (z1L > TAVIL_ZDET_VAL_1200) {
+		zdet_param_ptr = &zdet_param[3];
+		d1 = d1_a[3];
+	}
+	tavil_mbhc_zdet_ramp(codec, zdet_param_ptr, &z1L, NULL, d1);
+
+left_ch_impedance:
+	if ((z1L == TAVIL_ZDET_FLOATING_IMPEDANCE) ||
+		(z1L > TAVIL_ZDET_VAL_100K)) {
+		*zl = TAVIL_ZDET_FLOATING_IMPEDANCE;
+		zdet_param_ptr = &zdet_param[1];
+		d1 = d1_a[1];
+	} else {
+		*zl = z1L/1000;
+		tavil_wcd_mbhc_qfuse_cal(codec, zl, 0);
+	}
+	dev_dbg(codec->dev, "%s: impedance on HPH_L = %d(ohms)\n",
+		__func__, *zl);
+
+	/* Start of right impedance ramp and calculation */
+	tavil_mbhc_zdet_ramp(codec, zdet_param_ptr, NULL, &z1R, d1);
+	if (TAVIL_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) {
+		if (((z1R > TAVIL_ZDET_VAL_1200) &&
+			(zdet_param_ptr->noff == 0x6)) ||
+			((*zl) != TAVIL_ZDET_FLOATING_IMPEDANCE))
+			goto right_ch_impedance;
+		/* Second ramp for right ch */
+		if (z1R < TAVIL_ZDET_VAL_32) {
+			zdet_param_ptr = &zdet_param[0];
+			d1 = d1_a[0];
+		} else if ((z1R > TAVIL_ZDET_VAL_400) &&
+			(z1R <= TAVIL_ZDET_VAL_1200)) {
+			zdet_param_ptr = &zdet_param[2];
+			d1 = d1_a[2];
+		} else if (z1R > TAVIL_ZDET_VAL_1200) {
+			zdet_param_ptr = &zdet_param[3];
+			d1 = d1_a[3];
+		}
+		tavil_mbhc_zdet_ramp(codec, zdet_param_ptr, NULL, &z1R, d1);
+	}
+right_ch_impedance:
+	if ((z1R == TAVIL_ZDET_FLOATING_IMPEDANCE) ||
+		(z1R > TAVIL_ZDET_VAL_100K)) {
+		*zr = TAVIL_ZDET_FLOATING_IMPEDANCE;
+	} else {
+		*zr = z1R/1000;
+		tavil_wcd_mbhc_qfuse_cal(codec, zr, 1);
+	}
+	dev_dbg(codec->dev, "%s: impedance on HPH_R = %d(ohms)\n",
+		__func__, *zr);
+
+	/* Mono/stereo detection */
+	if ((*zl == TAVIL_ZDET_FLOATING_IMPEDANCE) &&
+		(*zr == TAVIL_ZDET_FLOATING_IMPEDANCE)) {
+		dev_dbg(codec->dev,
+			"%s: plug type is invalid or extension cable\n",
+			__func__);
+		goto zdet_complete;
+	}
+	if ((*zl == TAVIL_ZDET_FLOATING_IMPEDANCE) ||
+	    (*zr == TAVIL_ZDET_FLOATING_IMPEDANCE) ||
+	    ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+	    ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+		dev_dbg(codec->dev,
+			"%s: Mono plug type with one ch floating or shorted to GND\n",
+			__func__);
+		mbhc->hph_type = WCD_MBHC_HPH_MONO;
+		goto zdet_complete;
+	}
+	snd_soc_update_bits(codec, WCD934X_HPH_R_ATEST, 0x02, 0x02);
+	snd_soc_update_bits(codec, WCD934X_HPH_PA_CTL2, 0x40, 0x01);
+	if (*zl < (TAVIL_ZDET_VAL_32/1000))
+		tavil_mbhc_zdet_ramp(codec, &zdet_param[0], &z1Ls, NULL, d1);
+	else
+		tavil_mbhc_zdet_ramp(codec, &zdet_param[1], &z1Ls, NULL, d1);
+	snd_soc_update_bits(codec, WCD934X_HPH_PA_CTL2, 0x40, 0x00);
+	snd_soc_update_bits(codec, WCD934X_HPH_R_ATEST, 0x02, 0x00);
+	z1Ls /= 1000;
+	tavil_wcd_mbhc_qfuse_cal(codec, &z1Ls, 0);
+	/* Parallel of left Z and 9 ohm pull down resistor */
+	zMono = ((*zl) * 9) / ((*zl) + 9);
+	z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls);
+	z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl));
+	if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) {
+		dev_dbg(codec->dev, "%s: stereo plug type detected\n",
+			__func__);
+		mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+	} else {
+		dev_dbg(codec->dev, "%s: MONO plug type detected\n",
+			__func__);
+		mbhc->hph_type = WCD_MBHC_HPH_MONO;
+	}
+
+zdet_complete:
+	snd_soc_write(codec, WCD934X_ANA_MBHC_BTN5, reg0);
+	snd_soc_write(codec, WCD934X_ANA_MBHC_BTN6, reg1);
+	snd_soc_write(codec, WCD934X_ANA_MBHC_BTN7, reg2);
+	/* Turn on 100k pull down on HPHL */
+	regmap_update_bits(wcd9xxx->regmap,
+			   WCD934X_ANA_MBHC_MECH, 0x01, 0x01);
+
+	/* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+	if (mbhc->hphl_swh)
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD934X_ANA_MBHC_MECH, 0x80, 0x80);
+
+	snd_soc_write(codec, WCD934X_MBHC_NEW_ZDET_ANA_CTL, reg4);
+	snd_soc_write(codec, WCD934X_MBHC_CTL_CLK, reg3);
+	if (is_fsm_disable)
+		regmap_update_bits(wcd9xxx->regmap,
+				   WCD934X_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+
+static void tavil_mbhc_gnd_det_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD934X_ANA_MBHC_MECH,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD934X_ANA_MBHC_MECH,
+				    0x40, 0x40);
+	} else {
+		snd_soc_update_bits(codec, WCD934X_ANA_MBHC_MECH,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, WCD934X_ANA_MBHC_MECH,
+				    0x02, 0x00);
+	}
+}
+
+static void tavil_mbhc_hph_pull_down_ctrl(struct snd_soc_codec *codec,
+					  bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD934X_HPH_PA_CTL2,
+				    0x40, 0x40);
+		snd_soc_update_bits(codec, WCD934X_HPH_PA_CTL2,
+				    0x10, 0x10);
+	} else {
+		snd_soc_update_bits(codec, WCD934X_HPH_PA_CTL2,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, WCD934X_HPH_PA_CTL2,
+				    0x10, 0x00);
+	}
+}
+static void tavil_mbhc_moisture_config(struct wcd_mbhc *mbhc)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	if ((mbhc->moist_rref == R_OFF) ||
+	    (mbhc->mbhc_cfg->enable_usbc_analog)) {
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
+				    0x0C, R_OFF << 2);
+		return;
+	}
+
+	/* Donot enable moisture detection if jack type is NC */
+	if (!mbhc->hphl_swh) {
+		dev_dbg(codec->dev, "%s: disable moisture detection for NC\n",
+			__func__);
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
+				    0x0C, R_OFF << 2);
+		return;
+	}
+
+	snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
+			    0x0C, mbhc->moist_rref << 2);
+}
+
+static bool tavil_hph_register_recovery(struct wcd_mbhc *mbhc)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
+
+	if (!wcd934x_mbhc)
+		return false;
+
+	wcd934x_mbhc->is_hph_recover = false;
+	snd_soc_dapm_force_enable_pin(snd_soc_codec_get_dapm(codec),
+				      "RESET_HPH_REGISTERS");
+	snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+
+	snd_soc_dapm_disable_pin(snd_soc_codec_get_dapm(codec),
+				 "RESET_HPH_REGISTERS");
+	snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+
+	return wcd934x_mbhc->is_hph_recover;
+}
+
+static void tavil_update_anc_state(struct snd_soc_codec *codec, bool enable,
+				   int anc_num)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CFG0 +
+				(20 * anc_num), 0x10, 0x10);
+	else
+		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CFG0 +
+				(20 * anc_num), 0x10, 0x00);
+}
+
+static bool tavil_is_anc_on(struct wcd_mbhc *mbhc)
+{
+	bool anc_on = false;
+	u16 ancl, ancr;
+
+	ancl =
+	(snd_soc_read(mbhc->codec, WCD934X_CDC_RX1_RX_PATH_CFG0)) & 0x10;
+	ancr =
+	(snd_soc_read(mbhc->codec, WCD934X_CDC_RX2_RX_PATH_CFG0)) & 0x10;
+
+	anc_on = !!(ancl | ancr);
+
+	return anc_on;
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+	.request_irq = tavil_mbhc_request_irq,
+	.irq_control = tavil_mbhc_irq_control,
+	.free_irq = tavil_mbhc_free_irq,
+	.clk_setup = tavil_mbhc_clk_setup,
+	.map_btn_code_to_num = tavil_mbhc_btn_to_num,
+	.enable_mb_source = tavil_enable_ext_mb_source,
+	.mbhc_bias = tavil_mbhc_mbhc_bias_control,
+	.set_btn_thr = tavil_mbhc_program_btn_thr,
+	.lock_sleep = tavil_mbhc_lock_sleep,
+	.register_notifier = tavil_mbhc_register_notifier,
+	.micbias_enable_status = tavil_mbhc_micb_en_status,
+	.hph_pa_on_status = tavil_mbhc_hph_pa_on_status,
+	.hph_pull_up_control = tavil_mbhc_hph_l_pull_up_control,
+	.mbhc_micbias_control = tavil_mbhc_request_micbias,
+	.mbhc_micb_ramp_control = tavil_mbhc_micb_ramp_control,
+	.get_hwdep_fw_cal = tavil_get_hwdep_fw_cal,
+	.mbhc_micb_ctrl_thr_mic = tavil_mbhc_micb_ctrl_threshold_mic,
+	.compute_impedance = tavil_wcd_mbhc_calc_impedance,
+	.mbhc_gnd_det_ctrl = tavil_mbhc_gnd_det_ctrl,
+	.hph_pull_down_ctrl = tavil_mbhc_hph_pull_down_ctrl,
+	.mbhc_moisture_config = tavil_mbhc_moisture_config,
+	.hph_register_recovery = tavil_hph_register_recovery,
+	.update_anc_state = tavil_update_anc_state,
+	.is_anc_on = tavil_is_anc_on,
+};
+
+static struct regulator *tavil_codec_find_ondemand_regulator(
+		struct snd_soc_codec *codec, const char *name)
+{
+	int i;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent);
+
+	for (i = 0; i < wcd9xxx->num_of_supplies; ++i) {
+		if (pdata->regulator[i].ondemand &&
+		    wcd9xxx->supplies[i].supply &&
+		    !strcmp(wcd9xxx->supplies[i].supply, name))
+			return wcd9xxx->supplies[i].consumer;
+	}
+
+	dev_dbg(codec->dev, "Warning: regulator not found:%s\n",
+		name);
+	return NULL;
+}
+
+static int tavil_get_hph_type(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
+	struct wcd_mbhc *mbhc;
+
+	if (!wcd934x_mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__);
+		return -EINVAL;
+	}
+
+	mbhc = &wcd934x_mbhc->wcd_mbhc;
+
+	ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
+	dev_dbg(codec->dev, "%s: hph_type = %u\n", __func__, mbhc->hph_type);
+
+	return 0;
+}
+
+static int tavil_hph_impedance_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	uint32_t zl, zr;
+	bool hphr;
+	struct soc_multi_mixer_control *mc;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
+
+	if (!wcd934x_mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__);
+		return -EINVAL;
+	}
+
+	mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+	hphr = mc->shift;
+	wcd_mbhc_get_impedance(&wcd934x_mbhc->wcd_mbhc, &zl, &zr);
+	dev_dbg(codec->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr);
+	ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+	SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+		       tavil_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+		       tavil_hph_impedance_get, NULL),
+	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+		       tavil_hph_impedance_get, NULL),
+};
+
+/*
+ * tavil_mbhc_get_impedance: get impedance of headphone left and right channels
+ * @wcd934x_mbhc: handle to struct wcd934x_mbhc *
+ * @zl: handle to left-ch impedance
+ * @zr: handle to right-ch impedance
+ * return 0 for success or error code in case of failure
+ */
+int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc,
+			     uint32_t *zl, uint32_t *zr)
+{
+	if (!wcd934x_mbhc) {
+		pr_err("%s: mbhc not initialized!\n", __func__);
+		return -EINVAL;
+	}
+	if (!zl || !zr) {
+		pr_err("%s: zl or zr null!\n", __func__);
+		return -EINVAL;
+	}
+
+	return wcd_mbhc_get_impedance(&wcd934x_mbhc->wcd_mbhc, zl, zr);
+}
+EXPORT_SYMBOL(tavil_mbhc_get_impedance);
+
+/*
+ * tavil_mbhc_hs_detect: starts mbhc insertion/removal functionality
+ * @codec: handle to snd_soc_codec *
+ * @mbhc_cfg: handle to mbhc configuration structure
+ * return 0 if mbhc_start is success or error code in case of failure
+ */
+int tavil_mbhc_hs_detect(struct snd_soc_codec *codec,
+			 struct wcd_mbhc_config *mbhc_cfg)
+{
+	struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
+
+	if (!wcd934x_mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__);
+		return -EINVAL;
+	}
+
+	return wcd_mbhc_start(&wcd934x_mbhc->wcd_mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(tavil_mbhc_hs_detect);
+
+/*
+ * tavil_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality
+ * @codec: handle to snd_soc_codec *
+ */
+void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
+
+	if (!wcd934x_mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__);
+		return;
+	}
+	wcd_mbhc_stop(&wcd934x_mbhc->wcd_mbhc);
+}
+EXPORT_SYMBOL(tavil_mbhc_hs_detect_exit);
+
+/*
+ * tavil_mbhc_post_ssr_init: initialize mbhc for tavil post subsystem restart
+ * @mbhc: poniter to wcd934x_mbhc structure
+ * @codec: handle to snd_soc_codec *
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+			     struct snd_soc_codec *codec)
+{
+	int ret;
+	struct wcd_mbhc *wcd_mbhc;
+
+	if (!mbhc || !codec)
+		return -EINVAL;
+
+	wcd_mbhc = &mbhc->wcd_mbhc;
+	if (wcd_mbhc == NULL) {
+		pr_err("%s: wcd_mbhc is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd_mbhc_deinit(wcd_mbhc);
+	ret = wcd_mbhc_init(wcd_mbhc, codec, &mbhc_cb, &intr_ids,
+			    wcd_mbhc_registers, TAVIL_ZDET_SUPPORTED);
+	if (ret) {
+		dev_err(codec->dev, "%s: mbhc initialization failed\n",
+			__func__);
+		goto done;
+	}
+	if (wcd_mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY) {
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1, 0x04, 0x04);
+		snd_soc_update_bits(codec, WCD934X_MBHC_CTL_BCS, 0x01, 0x01);
+	}
+
+done:
+	return ret;
+}
+EXPORT_SYMBOL(tavil_mbhc_post_ssr_init);
+
+/*
+ * tavil_mbhc_init: initialize mbhc for tavil
+ * @mbhc: poniter to wcd934x_mbhc struct pointer to store the configs
+ * @codec: handle to snd_soc_codec *
+ * @fw_data: handle to firmware data
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec,
+		    struct fw_info *fw_data)
+{
+	struct regulator *supply;
+	struct wcd934x_mbhc *wcd934x_mbhc;
+	struct wcd_mbhc *wcd_mbhc;
+	int ret;
+
+	wcd934x_mbhc = devm_kzalloc(codec->dev, sizeof(struct wcd934x_mbhc),
+				    GFP_KERNEL);
+	if (!wcd934x_mbhc)
+		return -ENOMEM;
+
+	wcd934x_mbhc->wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	wcd934x_mbhc->fw_data = fw_data;
+	BLOCKING_INIT_NOTIFIER_HEAD(&wcd934x_mbhc->notifier);
+	wcd_mbhc = &wcd934x_mbhc->wcd_mbhc;
+	if (wcd_mbhc == NULL) {
+		pr_err("%s: wcd_mbhc is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+
+	/* Setting default mbhc detection logic to ADC for Tavil */
+	wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
+
+	ret = wcd_mbhc_init(wcd_mbhc, codec, &mbhc_cb,
+				&intr_ids, wcd_mbhc_registers,
+				TAVIL_ZDET_SUPPORTED);
+	if (ret) {
+		dev_err(codec->dev, "%s: mbhc initialization failed\n",
+			__func__);
+		goto err;
+	}
+
+	supply = tavil_codec_find_ondemand_regulator(codec,
+			on_demand_supply_name[WCD934X_ON_DEMAND_MICBIAS]);
+	if (supply) {
+		wcd934x_mbhc->on_demand_list[
+			WCD934X_ON_DEMAND_MICBIAS].supply =
+				supply;
+		wcd934x_mbhc->on_demand_list[
+			WCD934X_ON_DEMAND_MICBIAS].ondemand_supply_count =
+				0;
+	}
+
+	(*mbhc) = wcd934x_mbhc;
+	snd_soc_add_codec_controls(codec, impedance_detect_controls,
+				   ARRAY_SIZE(impedance_detect_controls));
+	snd_soc_add_codec_controls(codec, hph_type_detect_controls,
+				   ARRAY_SIZE(hph_type_detect_controls));
+
+	if (wcd_mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY) {
+		snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1, 0x04, 0x04);
+		snd_soc_update_bits(codec, WCD934X_MBHC_CTL_BCS, 0x01, 0x01);
+	}
+
+	return 0;
+err:
+	devm_kfree(codec->dev, wcd934x_mbhc);
+	return ret;
+}
+EXPORT_SYMBOL(tavil_mbhc_init);
+
+/*
+ * tavil_mbhc_deinit: deinitialize mbhc for tavil
+ * @codec: handle to snd_soc_codec *
+ */
+void tavil_mbhc_deinit(struct snd_soc_codec *codec)
+{
+	struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
+
+	if (wcd934x_mbhc) {
+		wcd_mbhc_deinit(&wcd934x_mbhc->wcd_mbhc);
+		devm_kfree(codec->dev, wcd934x_mbhc);
+	}
+}
+EXPORT_SYMBOL(tavil_mbhc_deinit);
diff --git a/asoc/codecs/wcd934x/wcd934x-mbhc.h b/asoc/codecs/wcd934x/wcd934x-mbhc.h
new file mode 100644
index 0000000..53c886d
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-mbhc.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD934X_MBHC_H__
+#define __WCD934X_MBHC_H__
+#include "../wcd-mbhc-v2.h"
+
+enum wcd934x_on_demand_supply_name {
+	WCD934X_ON_DEMAND_MICBIAS = 0,
+	WCD934X_ON_DEMAND_SUPPLIES_MAX,
+};
+
+struct wcd934x_on_demand_supply {
+	struct regulator *supply;
+	int ondemand_supply_count;
+};
+
+struct wcd934x_mbhc {
+	struct wcd_mbhc wcd_mbhc;
+	struct blocking_notifier_head notifier;
+	struct wcd934x_on_demand_supply on_demand_list[
+			WCD934X_ON_DEMAND_SUPPLIES_MAX];
+	struct wcd9xxx *wcd9xxx;
+	struct fw_info *fw_data;
+	bool mbhc_started;
+	bool is_hph_recover;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD934X_MBHC)
+extern int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
+			   struct snd_soc_codec *codec,
+			   struct fw_info *fw_data);
+extern void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec);
+extern int tavil_mbhc_hs_detect(struct snd_soc_codec *codec,
+				struct wcd_mbhc_config *mbhc_cfg);
+extern void tavil_mbhc_deinit(struct snd_soc_codec *codec);
+extern int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+				    struct snd_soc_codec *codec);
+extern int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc,
+				    uint32_t *zl, uint32_t *zr);
+#else
+static inline int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
+				  struct snd_soc_codec *codec,
+				  struct fw_info *fw_data)
+{
+	return 0;
+}
+static inline void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+}
+static inline int tavil_mbhc_hs_detect(struct snd_soc_codec *codec,
+				       struct wcd_mbhc_config *mbhc_cfg)
+{
+		return 0;
+}
+static inline void tavil_mbhc_deinit(struct snd_soc_codec *codec)
+{
+}
+static inline int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+					   struct snd_soc_codec *codec)
+{
+	return 0;
+}
+static inline int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc,
+					   uint32_t *zl, uint32_t *zr)
+{
+	if (zl)
+		*zl = 0;
+	if (zr)
+		*zr = 0;
+	return -EINVAL;
+}
+#endif
+
+#endif /* __WCD934X_MBHC_H__ */
diff --git a/asoc/codecs/wcd934x/wcd934x-regmap.c b/asoc/codecs/wcd934x/wcd934x-regmap.c
new file mode 100644
index 0000000..7f648fe
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-regmap.c
@@ -0,0 +1,1957 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <asoc/wcd934x_registers.h>
+#include "../core.h"
+#include "../wcd9xxx-regmap.h"
+
+
+static const struct reg_sequence wcd934x_1_1_defaults[] = {
+	{ WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,             0x01 },
+	{ WCD934X_BIAS_VBG_FINE_ADJ,                        0x75 },
+	{ WCD934X_HPH_REFBUFF_LP_CTL,                       0x0E },
+	{ WCD934X_EAR_DAC_CTL_ATEST,                        0x08 },
+	{ WCD934X_SIDO_NEW_VOUT_A_STARTUP,                  0x17 },
+	{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,                0x40 },
+	{ WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L,               0x81 },
+	{ WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R,               0x81 },
+};
+
+static const struct reg_default wcd934x_defaults[] = {
+	{ WCD934X_PAGE0_PAGE_REGISTER,                      0x00 },
+	{ WCD934X_CODEC_RPM_CLK_BYPASS,                     0x00 },
+	{ WCD934X_CODEC_RPM_CLK_GATE,                       0x1f },
+	{ WCD934X_CODEC_RPM_CLK_MCLK_CFG,                   0x00 },
+	{ WCD934X_CODEC_RPM_CLK_MCLK2_CFG,                  0x02 },
+	{ WCD934X_CODEC_RPM_I2S_DSD_CLK_SEL,                0x00 },
+	{ WCD934X_CODEC_RPM_RST_CTL,                        0x00 },
+	{ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,             0x04 },
+	{ WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,             0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE1,             0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,             0x08 },
+	{ WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE3,             0x01 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_CTL,                 0x10 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_TEST0,               0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_TEST1,               0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT3,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT4,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT5,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT6,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT7,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT8,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT10,           0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT11,           0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT12,           0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT13,           0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14,           0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15,           0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS,              0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO,      0x0d },
+	{ WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_1,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_2,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_3,            0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL,        0xcc },
+	{ WCD934X_CHIP_TIER_CTRL_SLNQ_WAIT_STATE_CTL,       0xcc },
+	{ WCD934X_CHIP_TIER_CTRL_I2C_ACTIVE,                0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN,               0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE,               0x00 },
+	{ WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA,             0x00 },
+	{ WCD934X_DATA_HUB_RX0_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_RX1_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_RX2_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_RX3_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_RX4_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_RX5_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_RX6_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_RX7_CFG,                         0x00 },
+	{ WCD934X_DATA_HUB_SB_TX0_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX1_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX2_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX3_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX4_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX5_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX6_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX7_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX8_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX9_INP_CFG,                  0x00 },
+	{ WCD934X_DATA_HUB_SB_TX10_INP_CFG,                 0x00 },
+	{ WCD934X_DATA_HUB_SB_TX11_INP_CFG,                 0x00 },
+	{ WCD934X_DATA_HUB_SB_TX13_INP_CFG,                 0x00 },
+	{ WCD934X_DATA_HUB_SB_TX14_INP_CFG,                 0x00 },
+	{ WCD934X_DATA_HUB_SB_TX15_INP_CFG,                 0x00 },
+	{ WCD934X_DATA_HUB_I2S_TX0_CFG,                     0x00 },
+	{ WCD934X_DATA_HUB_I2S_TX1_0_CFG,                   0x00 },
+	{ WCD934X_DATA_HUB_I2S_TX1_1_CFG,                   0x00 },
+	{ WCD934X_DATA_HUB_I2S_0_CTL,                       0x0c },
+	{ WCD934X_DATA_HUB_I2S_1_CTL,                       0x0c },
+	{ WCD934X_DATA_HUB_I2S_2_CTL,                       0x0c },
+	{ WCD934X_DATA_HUB_I2S_3_CTL,                       0x0c },
+	{ WCD934X_DATA_HUB_I2S_CLKSRC_CTL,                  0x00 },
+	{ WCD934X_DATA_HUB_I2S_COMMON_CTL,                  0x00 },
+	{ WCD934X_DATA_HUB_I2S_0_TDM_CTL,                   0x00 },
+	{ WCD934X_DATA_HUB_I2S_STATUS,                      0x00 },
+	{ WCD934X_DMA_RDMA_CTL_0,                           0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_RDMA_0,                    0xff },
+	{ WCD934X_DMA_CH_0_1_CFG_RDMA_0,                    0xff },
+	{ WCD934X_DMA_RDMA_CTL_1,                           0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_RDMA_1,                    0xff },
+	{ WCD934X_DMA_CH_0_1_CFG_RDMA_1,                    0xff },
+	{ WCD934X_DMA_RDMA_CTL_2,                           0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_RDMA_2,                    0xff },
+	{ WCD934X_DMA_CH_0_1_CFG_RDMA_2,                    0xff },
+	{ WCD934X_DMA_RDMA_CTL_3,                           0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_RDMA_3,                    0xff },
+	{ WCD934X_DMA_CH_0_1_CFG_RDMA_3,                    0xff },
+	{ WCD934X_DMA_RDMA_CTL_4,                           0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_RDMA_4,                    0xff },
+	{ WCD934X_DMA_CH_0_1_CFG_RDMA_4,                    0xff },
+	{ WCD934X_DMA_RDMA4_PRT_CFG,                       0x00 },
+	{ WCD934X_DMA_RDMA_SBTX0_7_CFG,                    0x00 },
+	{ WCD934X_DMA_RDMA_SBTX8_11_CFG,                   0x00 },
+	{ WCD934X_DMA_WDMA_CTL_0,                          0x00 },
+	{ WCD934X_DMA_CH_4_5_CFG_WDMA_0,                   0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_WDMA_0,                   0x00 },
+	{ WCD934X_DMA_CH_0_1_CFG_WDMA_0,                   0x00 },
+	{ WCD934X_DMA_WDMA_CTL_1,                          0x00 },
+	{ WCD934X_DMA_CH_4_5_CFG_WDMA_1,                   0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_WDMA_1,                   0x00 },
+	{ WCD934X_DMA_CH_0_1_CFG_WDMA_1,                   0x00 },
+	{ WCD934X_DMA_WDMA_CTL_2,                          0x00 },
+	{ WCD934X_DMA_CH_4_5_CFG_WDMA_2,                   0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_WDMA_2,                   0x00 },
+	{ WCD934X_DMA_CH_0_1_CFG_WDMA_2,                   0x00 },
+	{ WCD934X_DMA_WDMA_CTL_3,                          0x00 },
+	{ WCD934X_DMA_CH_4_5_CFG_WDMA_3,                   0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_WDMA_3,                   0x00 },
+	{ WCD934X_DMA_CH_0_1_CFG_WDMA_3,                   0x00 },
+	{ WCD934X_DMA_WDMA_CTL_4,                          0x00 },
+	{ WCD934X_DMA_CH_4_5_CFG_WDMA_4,                   0x00 },
+	{ WCD934X_DMA_CH_2_3_CFG_WDMA_4,                   0x00 },
+	{ WCD934X_DMA_CH_0_1_CFG_WDMA_4,                   0x00 },
+	{ WCD934X_DMA_WDMA0_PRT_CFG,                       0x00 },
+	{ WCD934X_DMA_WDMA3_PRT_CFG,                       0x00 },
+	{ WCD934X_DMA_WDMA4_PRT0_3_CFG,                    0x00 },
+	{ WCD934X_DMA_WDMA4_PRT4_7_CFG,                    0x00 },
+	{ WCD934X_PAGE1_PAGE_REGISTER,                     0x00 },
+	{ WCD934X_CPE_FLL_USER_CTL_0,                      0x71 },
+	{ WCD934X_CPE_FLL_USER_CTL_1,                      0x34 },
+	{ WCD934X_CPE_FLL_USER_CTL_2,                      0x0b },
+	{ WCD934X_CPE_FLL_USER_CTL_3,                      0x02 },
+	{ WCD934X_CPE_FLL_USER_CTL_4,                      0x04 },
+	{ WCD934X_CPE_FLL_USER_CTL_5,                      0x02 },
+	{ WCD934X_CPE_FLL_USER_CTL_6,                      0x6e },
+	{ WCD934X_CPE_FLL_USER_CTL_7,                      0x00 },
+	{ WCD934X_CPE_FLL_USER_CTL_8,                      0x94 },
+	{ WCD934X_CPE_FLL_USER_CTL_9,                      0x50 },
+	{ WCD934X_CPE_FLL_L_VAL_CTL_0,                     0x53 },
+	{ WCD934X_CPE_FLL_L_VAL_CTL_1,                     0x00 },
+	{ WCD934X_CPE_FLL_DSM_FRAC_CTL_0,                  0x00 },
+	{ WCD934X_CPE_FLL_DSM_FRAC_CTL_1,                  0xff },
+	{ WCD934X_CPE_FLL_CONFIG_CTL_0,                    0x6b },
+	{ WCD934X_CPE_FLL_CONFIG_CTL_1,                    0x05 },
+	{ WCD934X_CPE_FLL_CONFIG_CTL_2,                    0x08 },
+	{ WCD934X_CPE_FLL_CONFIG_CTL_3,                    0x00 },
+	{ WCD934X_CPE_FLL_CONFIG_CTL_4,                    0x10 },
+	{ WCD934X_CPE_FLL_TEST_CTL_0,                      0x80 },
+	{ WCD934X_CPE_FLL_TEST_CTL_1,                      0x00 },
+	{ WCD934X_CPE_FLL_TEST_CTL_2,                      0x00 },
+	{ WCD934X_CPE_FLL_TEST_CTL_3,                      0x00 },
+	{ WCD934X_CPE_FLL_TEST_CTL_4,                      0x00 },
+	{ WCD934X_CPE_FLL_TEST_CTL_5,                      0x00 },
+	{ WCD934X_CPE_FLL_TEST_CTL_6,                      0x00 },
+	{ WCD934X_CPE_FLL_TEST_CTL_7,                      0x33 },
+	{ WCD934X_CPE_FLL_FREQ_CTL_0,                      0x00 },
+	{ WCD934X_CPE_FLL_FREQ_CTL_1,                      0x00 },
+	{ WCD934X_CPE_FLL_FREQ_CTL_2,                      0x00 },
+	{ WCD934X_CPE_FLL_FREQ_CTL_3,                      0x00 },
+	{ WCD934X_CPE_FLL_SSC_CTL_0,                       0x00 },
+	{ WCD934X_CPE_FLL_SSC_CTL_1,                       0x00 },
+	{ WCD934X_CPE_FLL_SSC_CTL_2,                       0x00 },
+	{ WCD934X_CPE_FLL_SSC_CTL_3,                       0x00 },
+	{ WCD934X_CPE_FLL_FLL_MODE,                        0x20 },
+	{ WCD934X_CPE_FLL_STATUS_0,                        0x00 },
+	{ WCD934X_CPE_FLL_STATUS_1,                        0x00 },
+	{ WCD934X_CPE_FLL_STATUS_2,                        0x00 },
+	{ WCD934X_CPE_FLL_STATUS_3,                        0x00 },
+	{ WCD934X_I2S_FLL_USER_CTL_0,                      0x41 },
+	{ WCD934X_I2S_FLL_USER_CTL_1,                      0x94 },
+	{ WCD934X_I2S_FLL_USER_CTL_2,                      0x08 },
+	{ WCD934X_I2S_FLL_USER_CTL_3,                      0x02 },
+	{ WCD934X_I2S_FLL_USER_CTL_4,                      0x04 },
+	{ WCD934X_I2S_FLL_USER_CTL_5,                      0x02 },
+	{ WCD934X_I2S_FLL_USER_CTL_6,                      0x40 },
+	{ WCD934X_I2S_FLL_USER_CTL_7,                      0x00 },
+	{ WCD934X_I2S_FLL_USER_CTL_8,                      0x5f },
+	{ WCD934X_I2S_FLL_USER_CTL_9,                      0x02 },
+	{ WCD934X_I2S_FLL_L_VAL_CTL_0,                     0x40 },
+	{ WCD934X_I2S_FLL_L_VAL_CTL_1,                     0x00 },
+	{ WCD934X_I2S_FLL_DSM_FRAC_CTL_0,                  0x00 },
+	{ WCD934X_I2S_FLL_DSM_FRAC_CTL_1,                  0xff },
+	{ WCD934X_I2S_FLL_CONFIG_CTL_0,                    0x6b },
+	{ WCD934X_I2S_FLL_CONFIG_CTL_1,                    0x05 },
+	{ WCD934X_I2S_FLL_CONFIG_CTL_2,                    0x08 },
+	{ WCD934X_I2S_FLL_CONFIG_CTL_3,                    0x00 },
+	{ WCD934X_I2S_FLL_CONFIG_CTL_4,                    0x30 },
+	{ WCD934X_I2S_FLL_TEST_CTL_0,                      0x80 },
+	{ WCD934X_I2S_FLL_TEST_CTL_1,                      0x00 },
+	{ WCD934X_I2S_FLL_TEST_CTL_2,                      0x00 },
+	{ WCD934X_I2S_FLL_TEST_CTL_3,                      0x00 },
+	{ WCD934X_I2S_FLL_TEST_CTL_4,                      0x00 },
+	{ WCD934X_I2S_FLL_TEST_CTL_5,                      0x00 },
+	{ WCD934X_I2S_FLL_TEST_CTL_6,                      0x00 },
+	{ WCD934X_I2S_FLL_TEST_CTL_7,                      0xff },
+	{ WCD934X_I2S_FLL_FREQ_CTL_0,                      0x00 },
+	{ WCD934X_I2S_FLL_FREQ_CTL_1,                      0x00 },
+	{ WCD934X_I2S_FLL_FREQ_CTL_2,                      0x00 },
+	{ WCD934X_I2S_FLL_FREQ_CTL_3,                      0x00 },
+	{ WCD934X_I2S_FLL_SSC_CTL_0,                       0x00 },
+	{ WCD934X_I2S_FLL_SSC_CTL_1,                       0x00 },
+	{ WCD934X_I2S_FLL_SSC_CTL_2,                       0x00 },
+	{ WCD934X_I2S_FLL_SSC_CTL_3,                       0x00 },
+	{ WCD934X_I2S_FLL_FLL_MODE,                        0x00 },
+	{ WCD934X_I2S_FLL_STATUS_0,                        0x00 },
+	{ WCD934X_I2S_FLL_STATUS_1,                        0x00 },
+	{ WCD934X_I2S_FLL_STATUS_2,                        0x00 },
+	{ WCD934X_I2S_FLL_STATUS_3,                        0x00 },
+	{ WCD934X_SB_FLL_USER_CTL_0,                       0x41 },
+	{ WCD934X_SB_FLL_USER_CTL_1,                       0x94 },
+	{ WCD934X_SB_FLL_USER_CTL_2,                       0x08 },
+	{ WCD934X_SB_FLL_USER_CTL_3,                       0x02 },
+	{ WCD934X_SB_FLL_USER_CTL_4,                       0x04 },
+	{ WCD934X_SB_FLL_USER_CTL_5,                       0x02 },
+	{ WCD934X_SB_FLL_USER_CTL_6,                       0x40 },
+	{ WCD934X_SB_FLL_USER_CTL_7,                       0x00 },
+	{ WCD934X_SB_FLL_USER_CTL_8,                       0x5e },
+	{ WCD934X_SB_FLL_USER_CTL_9,                       0x01 },
+	{ WCD934X_SB_FLL_L_VAL_CTL_0,                      0x40 },
+	{ WCD934X_SB_FLL_L_VAL_CTL_1,                      0x00 },
+	{ WCD934X_SB_FLL_DSM_FRAC_CTL_0,                   0x00 },
+	{ WCD934X_SB_FLL_DSM_FRAC_CTL_1,                   0xff },
+	{ WCD934X_SB_FLL_CONFIG_CTL_0,                     0x6b },
+	{ WCD934X_SB_FLL_CONFIG_CTL_1,                     0x05 },
+	{ WCD934X_SB_FLL_CONFIG_CTL_2,                     0x08 },
+	{ WCD934X_SB_FLL_CONFIG_CTL_3,                     0x00 },
+	{ WCD934X_SB_FLL_CONFIG_CTL_4,                     0x10 },
+	{ WCD934X_SB_FLL_TEST_CTL_0,                       0x00 },
+	{ WCD934X_SB_FLL_TEST_CTL_1,                       0x00 },
+	{ WCD934X_SB_FLL_TEST_CTL_2,                       0x00 },
+	{ WCD934X_SB_FLL_TEST_CTL_3,                       0x00 },
+	{ WCD934X_SB_FLL_TEST_CTL_4,                       0x00 },
+	{ WCD934X_SB_FLL_TEST_CTL_5,                       0x00 },
+	{ WCD934X_SB_FLL_TEST_CTL_6,                       0x00 },
+	{ WCD934X_SB_FLL_TEST_CTL_7,                       0xff },
+	{ WCD934X_SB_FLL_FREQ_CTL_0,                       0x00 },
+	{ WCD934X_SB_FLL_FREQ_CTL_1,                       0x00 },
+	{ WCD934X_SB_FLL_FREQ_CTL_2,                       0x00 },
+	{ WCD934X_SB_FLL_FREQ_CTL_3,                       0x00 },
+	{ WCD934X_SB_FLL_SSC_CTL_0,                        0x00 },
+	{ WCD934X_SB_FLL_SSC_CTL_1,                        0x00 },
+	{ WCD934X_SB_FLL_SSC_CTL_2,                        0x00 },
+	{ WCD934X_SB_FLL_SSC_CTL_3,                        0x00 },
+	{ WCD934X_SB_FLL_FLL_MODE,                         0x00 },
+	{ WCD934X_SB_FLL_STATUS_0,                         0x00 },
+	{ WCD934X_SB_FLL_STATUS_1,                         0x00 },
+	{ WCD934X_SB_FLL_STATUS_2,                         0x00 },
+	{ WCD934X_SB_FLL_STATUS_3,                         0x00 },
+	{ WCD934X_PAGE2_PAGE_REGISTER,                     0x00 },
+	{ WCD934X_CPE_SS_CPE_CTL,                          0x05 },
+	{ WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0,             0x01 },
+	{ WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1,             0x00 },
+	{ WCD934X_CPE_SS_PWR_CPEFLL_CTL,                   0x02 },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0,         0xff },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1,         0x0f },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE,  0x00 },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0,        0xff },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1,        0xff },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2,        0xff },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3,        0xff },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4,        0xff },
+	{ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5,        0xff },
+	{ WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN,           0x07 },
+	{ WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,              0x00 },
+	{ WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL,     0x20 },
+	{ WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL1,    0x00 },
+	{ WCD934X_CPE_SS_US_BUF_INT_PERIOD,                0x60 },
+	{ WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD,        0x13 },
+	{ WCD934X_CPE_SS_SVA_CFG,                          0x41 },
+	{ WCD934X_CPE_SS_US_CFG,                           0x00 },
+	{ WCD934X_CPE_SS_MAD_CTL,                          0x00 },
+	{ WCD934X_CPE_SS_CPAR_CTL,                         0x00 },
+	{ WCD934X_CPE_SS_DMIC0_CTL,                        0x00 },
+	{ WCD934X_CPE_SS_DMIC1_CTL,                        0x00 },
+	{ WCD934X_CPE_SS_DMIC2_CTL,                        0x00 },
+	{ WCD934X_CPE_SS_DMIC_CFG,                         0x80 },
+	{ WCD934X_CPE_SS_CPAR_CFG,                         0x00 },
+	{ WCD934X_CPE_SS_WDOG_CFG,                         0x01 },
+	{ WCD934X_CPE_SS_BACKUP_INT,                       0x00 },
+	{ WCD934X_CPE_SS_STATUS,                           0x00 },
+	{ WCD934X_CPE_SS_CPE_OCD_CFG,                      0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A,             0xff },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B,             0x3f },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A,             0xff },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B,             0x3f },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A,           0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B,           0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A,           0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B,           0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A,            0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B,            0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1A,            0x00 },
+	{ WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1B,            0x00 },
+	{ WCD934X_SOC_MAD_MAIN_CTL_1,                      0x00 },
+	{ WCD934X_SOC_MAD_MAIN_CTL_2,                      0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_1,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_2,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_3,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_4,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_5,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_6,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_7,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_CTL_8,                     0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR,               0x00 },
+	{ WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL,               0x40 },
+	{ WCD934X_SOC_MAD_ULTR_CTL_1,                      0x00 },
+	{ WCD934X_SOC_MAD_ULTR_CTL_2,                      0x00 },
+	{ WCD934X_SOC_MAD_ULTR_CTL_3,                      0x00 },
+	{ WCD934X_SOC_MAD_ULTR_CTL_4,                      0x00 },
+	{ WCD934X_SOC_MAD_ULTR_CTL_5,                      0x00 },
+	{ WCD934X_SOC_MAD_ULTR_CTL_6,                      0x00 },
+	{ WCD934X_SOC_MAD_ULTR_CTL_7,                      0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_1,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_2,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_3,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_4,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_5,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_6,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_7,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_CTL_8,                    0x00 },
+	{ WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR,              0x00 },
+	{ WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL,              0x00 },
+	{ WCD934X_SOC_MAD_INP_SEL,                         0x00 },
+	{ WCD934X_PAGE4_PAGE_REGISTER,                     0x00 },
+	{ WCD934X_INTR_CFG,                                0x00 },
+	{ WCD934X_INTR_CLR_COMMIT,                         0x00 },
+	{ WCD934X_INTR_PIN1_MASK0,                         0xff },
+	{ WCD934X_INTR_PIN1_MASK1,                         0xff },
+	{ WCD934X_INTR_PIN1_MASK2,                         0xff },
+	{ WCD934X_INTR_PIN1_MASK3,                         0xff },
+	{ WCD934X_INTR_PIN1_STATUS0,                       0x00 },
+	{ WCD934X_INTR_PIN1_STATUS1,                       0x00 },
+	{ WCD934X_INTR_PIN1_STATUS2,                       0x00 },
+	{ WCD934X_INTR_PIN1_STATUS3,                       0x00 },
+	{ WCD934X_INTR_PIN1_CLEAR0,                        0x00 },
+	{ WCD934X_INTR_PIN1_CLEAR1,                        0x00 },
+	{ WCD934X_INTR_PIN1_CLEAR2,                        0x00 },
+	{ WCD934X_INTR_PIN1_CLEAR3,                        0x00 },
+	{ WCD934X_INTR_PIN2_MASK3,                         0xff },
+	{ WCD934X_INTR_PIN2_STATUS3,                       0x00 },
+	{ WCD934X_INTR_PIN2_CLEAR3,                        0x00 },
+	{ WCD934X_INTR_CPESS_SUMRY_MASK2,                  0xff },
+	{ WCD934X_INTR_CPESS_SUMRY_MASK3,                  0xff },
+	{ WCD934X_INTR_CPESS_SUMRY_STATUS2,                0x00 },
+	{ WCD934X_INTR_CPESS_SUMRY_STATUS3,                0x00 },
+	{ WCD934X_INTR_CPESS_SUMRY_CLEAR2,                 0x00 },
+	{ WCD934X_INTR_CPESS_SUMRY_CLEAR3,                 0x00 },
+	{ WCD934X_INTR_LEVEL0,                             0x03 },
+	{ WCD934X_INTR_LEVEL1,                             0xe0 },
+	{ WCD934X_INTR_LEVEL2,                             0x94 },
+	{ WCD934X_INTR_LEVEL3,                             0x80 },
+	{ WCD934X_INTR_BYPASS0,                            0x00 },
+	{ WCD934X_INTR_BYPASS1,                            0x00 },
+	{ WCD934X_INTR_BYPASS2,                            0x00 },
+	{ WCD934X_INTR_BYPASS3,                            0x00 },
+	{ WCD934X_INTR_SET0,                               0x00 },
+	{ WCD934X_INTR_SET1,                               0x00 },
+	{ WCD934X_INTR_SET2,                               0x00 },
+	{ WCD934X_INTR_SET3,                               0x00 },
+	{ WCD934X_INTR_CODEC_MISC_MASK,                    0x7f },
+	{ WCD934X_INTR_CODEC_MISC_STATUS,                  0x00 },
+	{ WCD934X_INTR_CODEC_MISC_CLEAR,                   0x00 },
+	{ WCD934X_PAGE5_PAGE_REGISTER,                     0x00 },
+	{ WCD934X_SLNQ_DIG_DEVICE,                         0x49 },
+	{ WCD934X_SLNQ_DIG_REVISION,                       0x01 },
+	{ WCD934X_SLNQ_DIG_H_COMMAND,                      0x00 },
+	{ WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_MSB,             0x00 },
+	{ WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_LSB,             0x00 },
+	{ WCD934X_SLNQ_DIG_MASTER_ADDRESS_MSB,             0x00 },
+	{ WCD934X_SLNQ_DIG_MASTER_ADDRESS_LSB,             0x00 },
+	{ WCD934X_SLNQ_DIG_SLAVE_ADDRESS_MSB,              0x00 },
+	{ WCD934X_SLNQ_DIG_SLAVE_ADDRESS_LSB,              0x00 },
+	{ WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_MSB,           0x40 },
+	{ WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_LSB,           0x00 },
+	{ WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_MSB,           0x40 },
+	{ WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_LSB,           0x00 },
+	{ WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_MSB,           0x40 },
+	{ WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_LSB,           0x00 },
+	{ WCD934X_SLNQ_DIG_COMM_CTL,                       0x00 },
+	{ WCD934X_SLNQ_DIG_FRAME_CTRL,                     0x01 },
+	{ WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH1_2,             0x77 },
+	{ WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH3_4,             0x77 },
+	{ WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH5,               0x70 },
+	{ WCD934X_SLNQ_DIG_SW_EVENT_RD,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SW_EVENT_CTRL,                  0x00 },
+	{ WCD934X_SLNQ_DIG_PDM_SELECT_1,                   0x12 },
+	{ WCD934X_SLNQ_DIG_PDM_SELECT_2,                   0x34 },
+	{ WCD934X_SLNQ_DIG_PDM_SELECT_3,                   0x55 },
+	{ WCD934X_SLNQ_DIG_PDM_SAMPLING_FREQ,              0x01 },
+	{ WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_CTL,          0x00 },
+	{ WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_SEL,          0x11 },
+	{ WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_MSB,            0x00 },
+	{ WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_LSB,            0x00 },
+	{ WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_MSB,            0x00 },
+	{ WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_LSB,            0x00 },
+	{ WCD934X_SLNQ_DIG_RAM_CNTRL,                      0x01 },
+	{ WCD934X_SLNQ_DIG_SRAM_BANK,                      0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_0,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_1,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_2,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_3,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_4,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_5,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_6,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_7,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_8,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_9,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_A,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_B,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_C,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_D,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_E,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_F,                    0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_10,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_11,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_12,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_13,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_14,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_15,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_16,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_17,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_18,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_19,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_1A,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_1B,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_1C,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_1D,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_1E,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_1F,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_20,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_21,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_22,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_23,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_24,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_25,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_26,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_27,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_28,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_29,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_2A,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_2B,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_2C,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_2D,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_2E,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_2F,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_30,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_31,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_32,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_33,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_34,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_35,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_36,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_37,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_38,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_39,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_3A,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_3B,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_3C,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_3D,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_3E,                   0x00 },
+	{ WCD934X_SLNQ_DIG_SRAM_BYTE_3F,                   0x00 },
+	{ WCD934X_SLNQ_DIG_TOP_CTRL1,                      0x00 },
+	{ WCD934X_SLNQ_DIG_TOP_CTRL2,                      0x00 },
+	{ WCD934X_SLNQ_DIG_PDM_CTRL,                       0x00 },
+	{ WCD934X_SLNQ_DIG_PDM_MUTE_CTRL,                  0x20 },
+	{ WCD934X_SLNQ_DIG_DEC_BYPASS_CTRL,                0x00 },
+	{ WCD934X_SLNQ_DIG_DEC_BYPASS_STATUS,              0x00 },
+	{ WCD934X_SLNQ_DIG_DEC_BYPASS_FS,                  0x00 },
+	{ WCD934X_SLNQ_DIG_DEC_BYPASS_IN_SEL,              0x00 },
+	{ WCD934X_SLNQ_DIG_GPOUT_ENABLE,                   0x00 },
+	{ WCD934X_SLNQ_DIG_GPOUT_VAL,                      0x00 },
+	{ WCD934X_SLNQ_DIG_ANA_INTERRUPT_MASK,             0x00 },
+	{ WCD934X_SLNQ_DIG_ANA_INTERRUPT_STATUS,           0x00 },
+	{ WCD934X_SLNQ_DIG_ANA_INTERRUPT_CLR,              0x00 },
+	{ WCD934X_SLNQ_DIG_IP_TESTING,                     0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CNTRL,                0x0f },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CNT,                  0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CNT_MSB,              0xff },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CNT_LSB,              0xff },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_MASK0,                0xff },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_MASK1,                0xff },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_MASK2,                0xff },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_MASK3,                0xff },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_MASK4,                0x1f },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_STATUS0,              0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_STATUS1,              0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_STATUS2,              0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_STATUS3,              0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_STATUS4,              0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CLR0,                 0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CLR1,                 0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CLR2,                 0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CLR3,                 0x00 },
+	{ WCD934X_SLNQ_DIG_INTERRUPT_CLR4,                 0x00 },
+	{ WCD934X_ANA_PAGE_REGISTER,                       0x00 },
+	{ WCD934X_ANA_BIAS,                                0x00 },
+	{ WCD934X_ANA_RCO,                                 0x00 },
+	{ WCD934X_ANA_PAGE6_SPARE2,                        0x00 },
+	{ WCD934X_ANA_PAGE6_SPARE3,                        0x00 },
+	{ WCD934X_ANA_BUCK_CTL,                            0x00 },
+	{ WCD934X_ANA_BUCK_STATUS,                         0x00 },
+	{ WCD934X_ANA_RX_SUPPLIES,                         0x00 },
+	{ WCD934X_ANA_HPH,                                 0x0c },
+	{ WCD934X_ANA_EAR,                                 0x00 },
+	{ WCD934X_ANA_LO_1_2,                              0x3c },
+	{ WCD934X_ANA_MAD_SETUP,                           0x01 },
+	{ WCD934X_ANA_AMIC1,                               0x20 },
+	{ WCD934X_ANA_AMIC2,                               0x00 },
+	{ WCD934X_ANA_AMIC3,                               0x20 },
+	{ WCD934X_ANA_AMIC4,                               0x00 },
+	{ WCD934X_ANA_MBHC_MECH,                           0x39 },
+	{ WCD934X_ANA_MBHC_ELECT,                          0x08 },
+	{ WCD934X_ANA_MBHC_ZDET,                           0x00 },
+	{ WCD934X_ANA_MBHC_RESULT_1,                       0x00 },
+	{ WCD934X_ANA_MBHC_RESULT_2,                       0x00 },
+	{ WCD934X_ANA_MBHC_RESULT_3,                       0x00 },
+	{ WCD934X_ANA_MBHC_BTN0,                           0x00 },
+	{ WCD934X_ANA_MBHC_BTN1,                           0x10 },
+	{ WCD934X_ANA_MBHC_BTN2,                           0x20 },
+	{ WCD934X_ANA_MBHC_BTN3,                           0x30 },
+	{ WCD934X_ANA_MBHC_BTN4,                           0x40 },
+	{ WCD934X_ANA_MBHC_BTN5,                           0x50 },
+	{ WCD934X_ANA_MBHC_BTN6,                           0x60 },
+	{ WCD934X_ANA_MBHC_BTN7,                           0x70 },
+	{ WCD934X_ANA_MICB1,                               0x10 },
+	{ WCD934X_ANA_MICB2,                               0x10 },
+	{ WCD934X_ANA_MICB2_RAMP,                          0x00 },
+	{ WCD934X_ANA_MICB3,                               0x10 },
+	{ WCD934X_ANA_MICB4,                               0x10 },
+	{ WCD934X_ANA_VBADC,                               0x00 },
+	{ WCD934X_BIAS_CTL,                                0x28 },
+	{ WCD934X_BIAS_VBG_FINE_ADJ,                       0x65 },
+	{ WCD934X_RCO_CTRL_1,                              0x44 },
+	{ WCD934X_RCO_CTRL_2,                              0x48 },
+	{ WCD934X_RCO_CAL,                                 0x00 },
+	{ WCD934X_RCO_CAL_1,                               0x00 },
+	{ WCD934X_RCO_CAL_2,                               0x00 },
+	{ WCD934X_RCO_TEST_CTRL,                           0x00 },
+	{ WCD934X_RCO_CAL_OUT_1,                           0x00 },
+	{ WCD934X_RCO_CAL_OUT_2,                           0x00 },
+	{ WCD934X_RCO_CAL_OUT_3,                           0x00 },
+	{ WCD934X_RCO_CAL_OUT_4,                           0x00 },
+	{ WCD934X_RCO_CAL_OUT_5,                           0x00 },
+	{ WCD934X_SIDO_MODE_1,                             0x84 },
+	{ WCD934X_SIDO_MODE_2,                             0xfe },
+	{ WCD934X_SIDO_MODE_3,                             0xf6 },
+	{ WCD934X_SIDO_MODE_4,                             0x56 },
+	{ WCD934X_SIDO_VCL_1,                              0x00 },
+	{ WCD934X_SIDO_VCL_2,                              0x6c },
+	{ WCD934X_SIDO_VCL_3,                              0x44 },
+	{ WCD934X_SIDO_CCL_1,                              0x57 },
+	{ WCD934X_SIDO_CCL_2,                              0x92 },
+	{ WCD934X_SIDO_CCL_3,                              0x35 },
+	{ WCD934X_SIDO_CCL_4,                              0x61 },
+	{ WCD934X_SIDO_CCL_5,                              0x6d },
+	{ WCD934X_SIDO_CCL_6,                              0x60 },
+	{ WCD934X_SIDO_CCL_7,                              0x6f },
+	{ WCD934X_SIDO_CCL_8,                              0x6f },
+	{ WCD934X_SIDO_CCL_9,                              0x6e },
+	{ WCD934X_SIDO_CCL_10,                             0x26 },
+	{ WCD934X_SIDO_FILTER_1,                           0x92 },
+	{ WCD934X_SIDO_FILTER_2,                           0x54 },
+	{ WCD934X_SIDO_DRIVER_1,                           0x77 },
+	{ WCD934X_SIDO_DRIVER_2,                           0x55 },
+	{ WCD934X_SIDO_DRIVER_3,                           0x55 },
+	{ WCD934X_SIDO_CAL_CODE_EXT_1,                     0x9c },
+	{ WCD934X_SIDO_CAL_CODE_EXT_2,                     0x82 },
+	{ WCD934X_SIDO_CAL_CODE_OUT_1,                     0x00 },
+	{ WCD934X_SIDO_CAL_CODE_OUT_2,                     0x00 },
+	{ WCD934X_SIDO_TEST_1,                             0x00 },
+	{ WCD934X_SIDO_TEST_2,                             0x00 },
+	{ WCD934X_MBHC_CTL_CLK,                            0x30 },
+	{ WCD934X_MBHC_CTL_ANA,                            0x00 },
+	{ WCD934X_MBHC_CTL_SPARE_1,                        0x00 },
+	{ WCD934X_MBHC_CTL_SPARE_2,                        0x00 },
+	{ WCD934X_MBHC_CTL_BCS,                            0x00 },
+	{ WCD934X_MBHC_STATUS_SPARE_1,                     0x00 },
+	{ WCD934X_MBHC_TEST_CTL,                           0x00 },
+	{ WCD934X_VBADC_SUBBLOCK_EN,                       0xde },
+	{ WCD934X_VBADC_IBIAS_FE,                          0x58 },
+	{ WCD934X_VBADC_BIAS_ADC,                          0x51 },
+	{ WCD934X_VBADC_FE_CTRL,                           0x1c },
+	{ WCD934X_VBADC_ADC_REF,                           0x20 },
+	{ WCD934X_VBADC_ADC_IO,                            0x80 },
+	{ WCD934X_VBADC_ADC_SAR,                           0xff },
+	{ WCD934X_VBADC_DEBUG,                             0x00 },
+	{ WCD934X_LDOH_MODE,                               0x2b },
+	{ WCD934X_LDOH_BIAS,                               0x68 },
+	{ WCD934X_LDOH_STB_LOADS,                          0x00 },
+	{ WCD934X_LDOH_SLOWRAMP,                           0x50 },
+	{ WCD934X_MICB1_TEST_CTL_1,                        0x1a },
+	{ WCD934X_MICB1_TEST_CTL_2,                        0x18 },
+	{ WCD934X_MICB1_TEST_CTL_3,                        0xa4 },
+	{ WCD934X_MICB2_TEST_CTL_1,                        0x1a },
+	{ WCD934X_MICB2_TEST_CTL_2,                        0x18 },
+	{ WCD934X_MICB2_TEST_CTL_3,                        0xa4 },
+	{ WCD934X_MICB3_TEST_CTL_1,                        0x1a },
+	{ WCD934X_MICB3_TEST_CTL_2,                        0x18 },
+	{ WCD934X_MICB3_TEST_CTL_3,                        0xa4 },
+	{ WCD934X_MICB4_TEST_CTL_1,                        0x1a },
+	{ WCD934X_MICB4_TEST_CTL_2,                        0x18 },
+	{ WCD934X_MICB4_TEST_CTL_3,                        0xa4 },
+	{ WCD934X_TX_COM_ADC_VCM,                          0x39 },
+	{ WCD934X_TX_COM_BIAS_ATEST,                       0xc0 },
+	{ WCD934X_TX_COM_ADC_INT1_IB,                      0x6f },
+	{ WCD934X_TX_COM_ADC_INT2_IB,                      0x4f },
+	{ WCD934X_TX_COM_TXFE_DIV_CTL,                     0x2e },
+	{ WCD934X_TX_COM_TXFE_DIV_START,                   0x00 },
+	{ WCD934X_TX_COM_TXFE_DIV_STOP_9P6M,               0xc7 },
+	{ WCD934X_TX_COM_TXFE_DIV_STOP_12P288M,            0xff },
+	{ WCD934X_TX_1_2_TEST_EN,                          0xcc },
+	{ WCD934X_TX_1_2_ADC_IB,                           0x09 },
+	{ WCD934X_TX_1_2_ATEST_REFCTL,                     0x0a },
+	{ WCD934X_TX_1_2_TEST_CTL,                         0x38 },
+	{ WCD934X_TX_1_2_TEST_BLK_EN,                      0xff },
+	{ WCD934X_TX_1_2_TXFE_CLKDIV,                      0x00 },
+	{ WCD934X_TX_1_2_SAR1_ERR,                         0x00 },
+	{ WCD934X_TX_1_2_SAR2_ERR,                         0x00 },
+	{ WCD934X_TX_3_4_TEST_EN,                          0xcc },
+	{ WCD934X_TX_3_4_ADC_IB,                           0x09 },
+	{ WCD934X_TX_3_4_ATEST_REFCTL,                     0x0a },
+	{ WCD934X_TX_3_4_TEST_CTL,                         0x38 },
+	{ WCD934X_TX_3_4_TEST_BLK_EN,                      0xff },
+	{ WCD934X_TX_3_4_TXFE_CLKDIV,                      0x00 },
+	{ WCD934X_TX_3_4_SAR1_ERR,                         0x00 },
+	{ WCD934X_TX_3_4_SAR2_ERR,                         0x00 },
+	{ WCD934X_CLASSH_MODE_1,                           0x40 },
+	{ WCD934X_CLASSH_MODE_2,                           0x3a },
+	{ WCD934X_CLASSH_MODE_3,                           0x00 },
+	{ WCD934X_CLASSH_CTRL_VCL_1,                       0x70 },
+	{ WCD934X_CLASSH_CTRL_VCL_2,                       0x82 },
+	{ WCD934X_CLASSH_CTRL_CCL_1,                       0x31 },
+	{ WCD934X_CLASSH_CTRL_CCL_2,                       0x80 },
+	{ WCD934X_CLASSH_CTRL_CCL_3,                       0x80 },
+	{ WCD934X_CLASSH_CTRL_CCL_4,                       0x51 },
+	{ WCD934X_CLASSH_CTRL_CCL_5,                       0x00 },
+	{ WCD934X_CLASSH_BUCK_TMUX_A_D,                    0x00 },
+	{ WCD934X_CLASSH_BUCK_SW_DRV_CNTL,                 0x77 },
+	{ WCD934X_CLASSH_SPARE,                            0x00 },
+	{ WCD934X_FLYBACK_EN,                              0x4e },
+	{ WCD934X_FLYBACK_VNEG_CTRL_1,                     0x0b },
+	{ WCD934X_FLYBACK_VNEG_CTRL_2,                     0x45 },
+	{ WCD934X_FLYBACK_VNEG_CTRL_3,                     0x74 },
+	{ WCD934X_FLYBACK_VNEG_CTRL_4,                     0x7f },
+	{ WCD934X_FLYBACK_VNEG_CTRL_5,                     0x83 },
+	{ WCD934X_FLYBACK_VNEG_CTRL_6,                     0x98 },
+	{ WCD934X_FLYBACK_VNEG_CTRL_7,                     0xa9 },
+	{ WCD934X_FLYBACK_VNEG_CTRL_8,                     0x68 },
+	{ WCD934X_FLYBACK_VNEG_CTRL_9,                     0x64 },
+	{ WCD934X_FLYBACK_VNEGDAC_CTRL_1,                  0xed },
+	{ WCD934X_FLYBACK_VNEGDAC_CTRL_2,                  0xf0 },
+	{ WCD934X_FLYBACK_VNEGDAC_CTRL_3,                  0xa6 },
+	{ WCD934X_FLYBACK_CTRL_1,                          0x65 },
+	{ WCD934X_FLYBACK_TEST_CTL,                        0x00 },
+	{ WCD934X_RX_AUX_SW_CTL,                           0x00 },
+	{ WCD934X_RX_PA_AUX_IN_CONN,                       0x00 },
+	{ WCD934X_RX_TIMER_DIV,                            0x32 },
+	{ WCD934X_RX_OCP_CTL,                              0x1f },
+	{ WCD934X_RX_OCP_COUNT,                            0x77 },
+	{ WCD934X_RX_BIAS_EAR_DAC,                         0xa0 },
+	{ WCD934X_RX_BIAS_EAR_AMP,                         0xaa },
+	{ WCD934X_RX_BIAS_HPH_LDO,                         0xa9 },
+	{ WCD934X_RX_BIAS_HPH_PA,                          0xaa },
+	{ WCD934X_RX_BIAS_HPH_RDACBUFF_CNP2,               0x8a },
+	{ WCD934X_RX_BIAS_HPH_RDAC_LDO,                    0x88 },
+	{ WCD934X_RX_BIAS_HPH_CNP1,                        0x82 },
+	{ WCD934X_RX_BIAS_HPH_LOWPOWER,                    0x82 },
+	{ WCD934X_RX_BIAS_DIFFLO_PA,                       0x80 },
+	{ WCD934X_RX_BIAS_DIFFLO_REF,                      0x88 },
+	{ WCD934X_RX_BIAS_DIFFLO_LDO,                      0x88 },
+	{ WCD934X_RX_BIAS_SELO_DAC_PA,                     0xa8 },
+	{ WCD934X_RX_BIAS_BUCK_RST,                        0x08 },
+	{ WCD934X_RX_BIAS_BUCK_VREF_ERRAMP,                0x44 },
+	{ WCD934X_RX_BIAS_FLYB_ERRAMP,                     0x40 },
+	{ WCD934X_RX_BIAS_FLYB_BUFF,                       0xaa },
+	{ WCD934X_RX_BIAS_FLYB_MID_RST,                    0x14 },
+	{ WCD934X_HPH_L_STATUS,                            0x04 },
+	{ WCD934X_HPH_R_STATUS,                            0x04 },
+	{ WCD934X_HPH_CNP_EN,                              0x80 },
+	{ WCD934X_HPH_CNP_WG_CTL,                          0x9a },
+	{ WCD934X_HPH_CNP_WG_TIME,                         0x14 },
+	{ WCD934X_HPH_OCP_CTL,                             0x28 },
+	{ WCD934X_HPH_AUTO_CHOP,                           0x16 },
+	{ WCD934X_HPH_CHOP_CTL,                            0x83 },
+	{ WCD934X_HPH_PA_CTL1,                             0x46 },
+	{ WCD934X_HPH_PA_CTL2,                             0x50 },
+	{ WCD934X_HPH_L_EN,                                0x80 },
+	{ WCD934X_HPH_L_TEST,                              0xe0 },
+	{ WCD934X_HPH_L_ATEST,                             0x50 },
+	{ WCD934X_HPH_R_EN,                                0x80 },
+	{ WCD934X_HPH_R_TEST,                              0xe0 },
+	{ WCD934X_HPH_R_ATEST,                             0x54 },
+	{ WCD934X_HPH_RDAC_CLK_CTL1,                       0x99 },
+	{ WCD934X_HPH_RDAC_CLK_CTL2,                       0x9b },
+	{ WCD934X_HPH_RDAC_LDO_CTL,                        0x33 },
+	{ WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL,                0x00 },
+	{ WCD934X_HPH_REFBUFF_UHQA_CTL,                    0xa8 },
+	{ WCD934X_HPH_REFBUFF_LP_CTL,                      0x0a },
+	{ WCD934X_HPH_L_DAC_CTL,                           0x00 },
+	{ WCD934X_HPH_R_DAC_CTL,                           0x00 },
+	{ WCD934X_EAR_EN_REG,                              0x60 },
+	{ WCD934X_EAR_CMBUFF,                              0x05 },
+	{ WCD934X_EAR_ICTL,                                0x40 },
+	{ WCD934X_EAR_EN_DBG_CTL,                          0x00 },
+	{ WCD934X_EAR_CNP,                                 0xe0 },
+	{ WCD934X_EAR_DAC_CTL_ATEST,                       0x00 },
+	{ WCD934X_EAR_STATUS_REG,                          0x04 },
+	{ WCD934X_EAR_EAR_MISC,                            0x28 },
+	{ WCD934X_DIFF_LO_MISC,                            0x03 },
+	{ WCD934X_DIFF_LO_LO2_COMPANDER,                   0x00 },
+	{ WCD934X_DIFF_LO_LO1_COMPANDER,                   0x00 },
+	{ WCD934X_DIFF_LO_COMMON,                          0x40 },
+	{ WCD934X_DIFF_LO_BYPASS_EN,                       0x00 },
+	{ WCD934X_DIFF_LO_CNP,                             0x20 },
+	{ WCD934X_DIFF_LO_CORE_OUT_PROG,                   0xa0 },
+	{ WCD934X_DIFF_LO_LDO_OUT_PROG,                    0x00 },
+	{ WCD934X_DIFF_LO_COM_SWCAP_REFBUF_FREQ,           0x8b },
+	{ WCD934X_DIFF_LO_COM_PA_FREQ,                     0xb0 },
+	{ WCD934X_DIFF_LO_RESERVED_REG,                    0x60 },
+	{ WCD934X_DIFF_LO_LO1_STATUS_1,                    0x00 },
+	{ WCD934X_DIFF_LO_LO1_STATUS_2,                    0x00 },
+	{ WCD934X_ANA_NEW_PAGE_REGISTER,                   0x00 },
+	{ WCD934X_HPH_NEW_ANA_HPH2,                        0x00 },
+	{ WCD934X_HPH_NEW_ANA_HPH3,                        0x00 },
+	{ WCD934X_SLNQ_ANA_EN,                             0x02 },
+	{ WCD934X_SLNQ_ANA_STATUS,                         0x00 },
+	{ WCD934X_SLNQ_ANA_LDO_CONFIG,                     0xea },
+	{ WCD934X_SLNQ_ANA_LDO_OCP_CONFIG,                 0x95 },
+	{ WCD934X_SLNQ_ANA_TX_LDO_CONFIG,                  0xb6 },
+	{ WCD934X_SLNQ_ANA_TX_DRV_CONFIG,                  0x26 },
+	{ WCD934X_SLNQ_ANA_RX_CONFIG_1,                    0x64 },
+	{ WCD934X_SLNQ_ANA_RX_CONFIG_2,                    0x40 },
+	{ WCD934X_SLNQ_ANA_PLL_ENABLES,                    0x00 },
+	{ WCD934X_SLNQ_ANA_PLL_PRESET,                     0x08 },
+	{ WCD934X_SLNQ_ANA_PLL_STATUS,                     0x00 },
+	{ WCD934X_CLK_SYS_PLL_ENABLES,                     0x00 },
+	{ WCD934X_CLK_SYS_PLL_PRESET,                      0x00 },
+	{ WCD934X_CLK_SYS_PLL_STATUS,                      0x00 },
+	{ WCD934X_CLK_SYS_MCLK_PRG,                        0x00 },
+	{ WCD934X_CLK_SYS_MCLK2_PRG1,                      0x00 },
+	{ WCD934X_CLK_SYS_MCLK2_PRG2,                      0x00 },
+	{ WCD934X_CLK_SYS_XO_PRG,                          0x00 },
+	{ WCD934X_CLK_SYS_XO_CAP_XTP,                      0x00 },
+	{ WCD934X_CLK_SYS_XO_CAP_XTM,                      0x00 },
+	{ WCD934X_BOOST_BST_EN_DLY,                        0x40 },
+	{ WCD934X_BOOST_CTRL_ILIM,                         0x9c },
+	{ WCD934X_BOOST_VOUT_SETTING,                      0xca },
+	{ WCD934X_SIDO_NEW_VOUT_A_STARTUP,                 0x05 },
+	{ WCD934X_SIDO_NEW_VOUT_D_STARTUP,                 0x0d },
+	{ WCD934X_SIDO_NEW_VOUT_D_FREQ1,                   0x07 },
+	{ WCD934X_SIDO_NEW_VOUT_D_FREQ2,                   0x00 },
+	{ WCD934X_MBHC_NEW_ELECT_REM_CLAMP_CTL,            0x00 },
+	{ WCD934X_MBHC_NEW_CTL_1,                          0x02 },
+	{ WCD934X_MBHC_NEW_CTL_2,                          0x05 },
+	{ WCD934X_MBHC_NEW_PLUG_DETECT_CTL,                0xe9 },
+	{ WCD934X_MBHC_NEW_ZDET_ANA_CTL,                   0x0f },
+	{ WCD934X_MBHC_NEW_ZDET_RAMP_CTL,                  0x00 },
+	{ WCD934X_MBHC_NEW_FSM_STATUS,                     0x00 },
+	{ WCD934X_MBHC_NEW_ADC_RESULT,                     0x00 },
+	{ WCD934X_TX_NEW_AMIC_4_5_SEL,                     0x00 },
+	{ WCD934X_VBADC_NEW_ADC_MODE,                      0x10 },
+	{ WCD934X_VBADC_NEW_ADC_DOUTMSB,                   0x00 },
+	{ WCD934X_VBADC_NEW_ADC_DOUTLSB,                   0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,               0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_HD2_CTL,                0xa0 },
+	{ WCD934X_HPH_NEW_INT_RDAC_VREF_CTL,               0x10 },
+	{ WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL,           0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_MISC1,                  0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC1,                    0x22 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC2,                    0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC,                0x00 },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER1,                  0xfe },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER2,                  0x02 },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER3,                  0x4e },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER4,                  0x54 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC2,               0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC3,               0x00 },
+	{ WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI,         0x62 },
+	{ WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_ULP,            0x01 },
+	{ WCD934X_RX_NEW_INT_HPH_RDAC_LDO_LP,              0x11 },
+	{ WCD934X_SLNQ_INT_ANA_INT_LDO_TEST,               0x0d },
+	{ WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_1,            0x85 },
+	{ WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_2,            0xb4 },
+	{ WCD934X_SLNQ_INT_ANA_INT_TX_LDO_TEST,            0x16 },
+	{ WCD934X_SLNQ_INT_ANA_INT_TX_DRV_TEST,            0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_RX_TEST,                0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_RX_TEST_STATUS,         0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_1,             0x50 },
+	{ WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_2,             0x04 },
+	{ WCD934X_SLNQ_INT_ANA_INT_CLK_CTRL,               0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_RESERVED_1,             0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_RESERVED_2,             0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG0,      0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG1,      0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG0,       0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG1,       0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG0,        0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG1,        0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_L_VAL,              0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_M_VAL,              0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_N_VAL,              0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG0,          0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_PFD_CP_DSM_PROG,    0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_VCO_PROG,           0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG1,          0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_LDO_LOCK_CFG,       0x00 },
+	{ WCD934X_SLNQ_INT_ANA_INT_PLL_DIG_LOCK_DET_CFG,   0x00 },
+	{ WCD934X_CLK_SYS_INT_POST_DIV_REG0,               0x00 },
+	{ WCD934X_CLK_SYS_INT_POST_DIV_REG1,               0x00 },
+	{ WCD934X_CLK_SYS_INT_REF_DIV_REG0,                0x00 },
+	{ WCD934X_CLK_SYS_INT_REF_DIV_REG1,                0x00 },
+	{ WCD934X_CLK_SYS_INT_FILTER_REG0,                 0x00 },
+	{ WCD934X_CLK_SYS_INT_FILTER_REG1,                 0x00 },
+	{ WCD934X_CLK_SYS_INT_PLL_L_VAL,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_PLL_M_VAL,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_PLL_N_VAL,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_TEST_REG0,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG,             0x00 },
+	{ WCD934X_CLK_SYS_INT_VCO_PROG,                    0x00 },
+	{ WCD934X_CLK_SYS_INT_TEST_REG1,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_LDO_LOCK_CFG,                0x00 },
+	{ WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG,            0x00 },
+	{ WCD934X_CLK_SYS_INT_CLK_TEST1,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_CLK_TEST2,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_CLK_TEST3,                   0x00 },
+	{ WCD934X_CLK_SYS_INT_XO_TEST1,                    0x98 },
+	{ WCD934X_CLK_SYS_INT_XO_TEST2,                    0x00 },
+	{ WCD934X_BOOST_INT_VCOMP_HYST,                    0x02 },
+	{ WCD934X_BOOST_INT_VLOOP_FILTER,                  0xef },
+	{ WCD934X_BOOST_INT_CTRL_IDELTA,                   0xa8 },
+	{ WCD934X_BOOST_INT_CTRL_ILIM_STARTUP,             0x17 },
+	{ WCD934X_BOOST_INT_CTRL_MIN_ONTIME,               0x5f },
+	{ WCD934X_BOOST_INT_CTRL_MAX_ONTIME,               0x88 },
+	{ WCD934X_BOOST_INT_CTRL_TIMING,                   0x0a },
+	{ WCD934X_BOOST_INT_TMUX_A_D,                      0x00 },
+	{ WCD934X_BOOST_INT_SW_DRV_CNTL,                   0xf8 },
+	{ WCD934X_BOOST_INT_SPARE1,                        0x00 },
+	{ WCD934X_BOOST_INT_SPARE2,                        0x00 },
+	{ WCD934X_SIDO_NEW_INT_RAMP_STATUS,                0x00 },
+	{ WCD934X_SIDO_NEW_INT_SPARE_1,                    0x00 },
+	{ WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_A,       0x64 },
+	{ WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_D,       0x40 },
+	{ WCD934X_SIDO_NEW_INT_RAMP_INC_WAIT,              0x24 },
+	{ WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_CTL,          0x09 },
+	{ WCD934X_SIDO_NEW_INT_RAMP_IBLEED_CTL,            0x7d },
+	{ WCD934X_SIDO_NEW_INT_DEBUG_CPROVR_TEST,          0x00 },
+	{ WCD934X_SIDO_NEW_INT_RAMP_CTL_A,                 0x14 },
+	{ WCD934X_SIDO_NEW_INT_RAMP_CTL_D,                 0x14 },
+	{ WCD934X_SIDO_NEW_INT_RAMP_TIMEOUT_PERIOD,        0x33 },
+	{ WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING1,     0x3f },
+	{ WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING2,     0x74 },
+	{ WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING3,     0x33 },
+	{ WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL1,        0x1d },
+	{ WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL2,        0x0a },
+	{ WCD934X_MBHC_NEW_INT_SLNQ_HPF,                   0x50 },
+	{ WCD934X_MBHC_NEW_INT_SLNQ_REF,                   0x24 },
+	{ WCD934X_MBHC_NEW_INT_SLNQ_COMP,                  0x50 },
+	{ WCD934X_MBHC_NEW_INT_SPARE_2,                    0x00 },
+	{ WCD934X_PAGE10_PAGE_REGISTER,                    0x00 },
+	{ WCD934X_CDC_ANC0_CLK_RESET_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC0_MODE_1_CTL,                     0x00 },
+	{ WCD934X_CDC_ANC0_MODE_2_CTL,                     0x00 },
+	{ WCD934X_CDC_ANC0_FF_SHIFT,                       0x00 },
+	{ WCD934X_CDC_ANC0_FB_SHIFT,                       0x00 },
+	{ WCD934X_CDC_ANC0_LPF_FF_A_CTL,                   0x00 },
+	{ WCD934X_CDC_ANC0_LPF_FF_B_CTL,                   0x00 },
+	{ WCD934X_CDC_ANC0_LPF_FB_CTL,                     0x00 },
+	{ WCD934X_CDC_ANC0_SMLPF_CTL,                      0x00 },
+	{ WCD934X_CDC_ANC0_DCFLT_SHIFT_CTL,                0x00 },
+	{ WCD934X_CDC_ANC0_IIR_ADAPT_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC0_IIR_COEFF_1_CTL,                0x00 },
+	{ WCD934X_CDC_ANC0_IIR_COEFF_2_CTL,                0x00 },
+	{ WCD934X_CDC_ANC0_FF_A_GAIN_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC0_FF_B_GAIN_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC0_FB_GAIN_CTL,                    0x00 },
+	{ WCD934X_CDC_ANC0_RC_COMMON_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC0_FIFO_COMMON_CTL,                0x88 },
+	{ WCD934X_CDC_ANC0_RC0_STATUS_FMIN_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC0_RC1_STATUS_FMIN_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC0_RC0_STATUS_FMAX_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC0_RC1_STATUS_FMAX_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC0_STATUS_FIFO,                    0x00 },
+	{ WCD934X_CDC_ANC1_CLK_RESET_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC1_MODE_1_CTL,                     0x00 },
+	{ WCD934X_CDC_ANC1_MODE_2_CTL,                     0x00 },
+	{ WCD934X_CDC_ANC1_FF_SHIFT,                       0x00 },
+	{ WCD934X_CDC_ANC1_FB_SHIFT,                       0x00 },
+	{ WCD934X_CDC_ANC1_LPF_FF_A_CTL,                   0x00 },
+	{ WCD934X_CDC_ANC1_LPF_FF_B_CTL,                   0x00 },
+	{ WCD934X_CDC_ANC1_LPF_FB_CTL,                     0x00 },
+	{ WCD934X_CDC_ANC1_SMLPF_CTL,                      0x00 },
+	{ WCD934X_CDC_ANC1_DCFLT_SHIFT_CTL,                0x00 },
+	{ WCD934X_CDC_ANC1_IIR_ADAPT_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC1_IIR_COEFF_1_CTL,                0x00 },
+	{ WCD934X_CDC_ANC1_IIR_COEFF_2_CTL,                0x00 },
+	{ WCD934X_CDC_ANC1_FF_A_GAIN_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC1_FF_B_GAIN_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC1_FB_GAIN_CTL,                    0x00 },
+	{ WCD934X_CDC_ANC1_RC_COMMON_CTL,                  0x00 },
+	{ WCD934X_CDC_ANC1_FIFO_COMMON_CTL,                0x88 },
+	{ WCD934X_CDC_ANC1_RC0_STATUS_FMIN_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC1_RC1_STATUS_FMIN_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC1_RC0_STATUS_FMAX_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC1_RC1_STATUS_FMAX_CNTR,           0x00 },
+	{ WCD934X_CDC_ANC1_STATUS_FIFO,                    0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX0_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX0_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX0_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX0_TX_PATH_SEC7,                    0x25 },
+	{ WCD934X_CDC_TX1_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX1_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX1_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX1_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX1_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX1_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX1_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX1_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX1_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX1_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX1_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX1_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX1_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX2_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX2_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX2_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX2_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX2_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX2_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX2_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX2_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX2_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX2_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX2_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX2_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX2_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX3_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX3_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX3_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX3_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX3_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX3_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX3_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX3_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX3_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX3_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX3_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX3_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX3_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX4_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX4_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX4_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX4_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX4_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX4_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX4_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX4_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX4_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX4_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX4_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX4_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX4_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX5_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX5_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX5_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX5_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX5_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX5_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX5_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX5_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX5_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX5_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX5_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX5_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX5_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX6_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX6_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX6_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX6_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX6_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX6_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX6_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX6_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX6_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX6_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX6_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX6_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX6_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX7_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX7_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX7_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX7_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX7_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX7_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX7_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX7_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX7_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX7_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX7_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX7_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX7_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX8_TX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_TX8_TX_PATH_CFG0,                    0x10 },
+	{ WCD934X_CDC_TX8_TX_PATH_CFG1,                    0x03 },
+	{ WCD934X_CDC_TX8_TX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_TX8_TX_PATH_192_CTL,                 0x00 },
+	{ WCD934X_CDC_TX8_TX_PATH_192_CFG,                 0x00 },
+	{ WCD934X_CDC_TX8_TX_PATH_SEC0,                    0x00 },
+	{ WCD934X_CDC_TX8_TX_PATH_SEC1,                    0x00 },
+	{ WCD934X_CDC_TX8_TX_PATH_SEC2,                    0x01 },
+	{ WCD934X_CDC_TX8_TX_PATH_SEC3,                    0x3c },
+	{ WCD934X_CDC_TX8_TX_PATH_SEC4,                    0x20 },
+	{ WCD934X_CDC_TX8_TX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_TX8_TX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL,              0x02 },
+	{ WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0,             0x00 },
+	{ WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL,             0x02 },
+	{ WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0,            0x00 },
+	{ WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL,             0x02 },
+	{ WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0,            0x00 },
+	{ WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL,             0x02 },
+	{ WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0,            0x00 },
+	{ WCD934X_PAGE11_PAGE_REGISTER,                    0x00 },
+	{ WCD934X_CDC_COMPANDER1_CTL0,                     0x60 },
+	{ WCD934X_CDC_COMPANDER1_CTL1,                     0xdb },
+	{ WCD934X_CDC_COMPANDER1_CTL2,                     0xff },
+	{ WCD934X_CDC_COMPANDER1_CTL3,                     0x35 },
+	{ WCD934X_CDC_COMPANDER1_CTL4,                     0xff },
+	{ WCD934X_CDC_COMPANDER1_CTL5,                     0x00 },
+	{ WCD934X_CDC_COMPANDER1_CTL6,                     0x01 },
+	{ WCD934X_CDC_COMPANDER1_CTL7,                     0x08 },
+	{ WCD934X_CDC_COMPANDER2_CTL0,                     0x60 },
+	{ WCD934X_CDC_COMPANDER2_CTL1,                     0xdb },
+	{ WCD934X_CDC_COMPANDER2_CTL2,                     0xff },
+	{ WCD934X_CDC_COMPANDER2_CTL3,                     0x35 },
+	{ WCD934X_CDC_COMPANDER2_CTL4,                     0xff },
+	{ WCD934X_CDC_COMPANDER2_CTL5,                     0x00 },
+	{ WCD934X_CDC_COMPANDER2_CTL6,                     0x01 },
+	{ WCD934X_CDC_COMPANDER2_CTL7,                     0x08 },
+	{ WCD934X_CDC_COMPANDER3_CTL0,                     0x60 },
+	{ WCD934X_CDC_COMPANDER3_CTL1,                     0xdb },
+	{ WCD934X_CDC_COMPANDER3_CTL2,                     0xff },
+	{ WCD934X_CDC_COMPANDER3_CTL3,                     0x35 },
+	{ WCD934X_CDC_COMPANDER3_CTL4,                     0xff },
+	{ WCD934X_CDC_COMPANDER3_CTL5,                     0x00 },
+	{ WCD934X_CDC_COMPANDER3_CTL6,                     0x01 },
+	{ WCD934X_CDC_COMPANDER3_CTL7,                     0x08 },
+	{ WCD934X_CDC_COMPANDER4_CTL0,                     0x60 },
+	{ WCD934X_CDC_COMPANDER4_CTL1,                     0xdb },
+	{ WCD934X_CDC_COMPANDER4_CTL2,                     0xff },
+	{ WCD934X_CDC_COMPANDER4_CTL3,                     0x35 },
+	{ WCD934X_CDC_COMPANDER4_CTL4,                     0xff },
+	{ WCD934X_CDC_COMPANDER4_CTL5,                     0x00 },
+	{ WCD934X_CDC_COMPANDER4_CTL6,                     0x01 },
+	{ WCD934X_CDC_COMPANDER4_CTL7,                     0x08 },
+	{ WCD934X_CDC_COMPANDER7_CTL0,                     0x60 },
+	{ WCD934X_CDC_COMPANDER7_CTL1,                     0xdb },
+	{ WCD934X_CDC_COMPANDER7_CTL2,                     0xff },
+	{ WCD934X_CDC_COMPANDER7_CTL3,                     0x35 },
+	{ WCD934X_CDC_COMPANDER7_CTL4,                     0xff },
+	{ WCD934X_CDC_COMPANDER7_CTL5,                     0x00 },
+	{ WCD934X_CDC_COMPANDER7_CTL6,                     0x01 },
+	{ WCD934X_CDC_COMPANDER7_CTL7,                     0x08 },
+	{ WCD934X_CDC_COMPANDER8_CTL0,                     0x60 },
+	{ WCD934X_CDC_COMPANDER8_CTL1,                     0xdb },
+	{ WCD934X_CDC_COMPANDER8_CTL2,                     0xff },
+	{ WCD934X_CDC_COMPANDER8_CTL3,                     0x35 },
+	{ WCD934X_CDC_COMPANDER8_CTL4,                     0xff },
+	{ WCD934X_CDC_COMPANDER8_CTL5,                     0x00 },
+	{ WCD934X_CDC_COMPANDER8_CTL6,                     0x01 },
+	{ WCD934X_CDC_COMPANDER8_CTL7,                     0x08 },
+	{ WCD934X_CDC_RX0_RX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_RX0_RX_PATH_CFG0,                    0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_CFG1,                    0x64 },
+	{ WCD934X_CDC_RX0_RX_PATH_CFG2,                    0x8f },
+	{ WCD934X_CDC_RX0_RX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_MIX_CTL,                 0x04 },
+	{ WCD934X_CDC_RX0_RX_PATH_MIX_CFG,                 0x7e },
+	{ WCD934X_CDC_RX0_RX_VOL_MIX_CTL,                  0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_SEC0,                    0xfc },
+	{ WCD934X_CDC_RX0_RX_PATH_SEC1,                    0x08 },
+	{ WCD934X_CDC_RX0_RX_PATH_SEC2,                    0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_SEC3,                    0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_SEC7,                    0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_MIX_SEC0,                0x08 },
+	{ WCD934X_CDC_RX0_RX_PATH_MIX_SEC1,                0x00 },
+	{ WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL,              0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_RX1_RX_PATH_CFG0,                    0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_CFG1,                    0x64 },
+	{ WCD934X_CDC_RX1_RX_PATH_CFG2,                    0x8f },
+	{ WCD934X_CDC_RX1_RX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_MIX_CTL,                 0x04 },
+	{ WCD934X_CDC_RX1_RX_PATH_MIX_CFG,                 0x7e },
+	{ WCD934X_CDC_RX1_RX_VOL_MIX_CTL,                  0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC0,                    0xfc },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC1,                    0x08 },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC2,                    0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC3,                    0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC4,                    0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_SEC7,                    0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_MIX_SEC0,                0x08 },
+	{ WCD934X_CDC_RX1_RX_PATH_MIX_SEC1,                0x00 },
+	{ WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL,              0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_RX2_RX_PATH_CFG0,                    0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_CFG1,                    0x64 },
+	{ WCD934X_CDC_RX2_RX_PATH_CFG2,                    0x8f },
+	{ WCD934X_CDC_RX2_RX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_MIX_CTL,                 0x04 },
+	{ WCD934X_CDC_RX2_RX_PATH_MIX_CFG,                 0x7e },
+	{ WCD934X_CDC_RX2_RX_VOL_MIX_CTL,                  0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC0,                    0xfc },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC1,                    0x08 },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC2,                    0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC3,                    0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC4,                    0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_SEC7,                    0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_MIX_SEC0,                0x08 },
+	{ WCD934X_CDC_RX2_RX_PATH_MIX_SEC1,                0x00 },
+	{ WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL,              0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_RX3_RX_PATH_CFG0,                    0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_CFG1,                    0x64 },
+	{ WCD934X_CDC_RX3_RX_PATH_CFG2,                    0x8f },
+	{ WCD934X_CDC_RX3_RX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_MIX_CTL,                 0x04 },
+	{ WCD934X_CDC_RX3_RX_PATH_MIX_CFG,                 0x7e },
+	{ WCD934X_CDC_RX3_RX_VOL_MIX_CTL,                  0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_SEC0,                    0xfc },
+	{ WCD934X_CDC_RX3_RX_PATH_SEC1,                    0x08 },
+	{ WCD934X_CDC_RX3_RX_PATH_SEC2,                    0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_SEC3,                    0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_SEC7,                    0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_MIX_SEC0,                0x08 },
+	{ WCD934X_CDC_RX3_RX_PATH_MIX_SEC1,                0x00 },
+	{ WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL,              0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_RX4_RX_PATH_CFG0,                    0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_CFG1,                    0x64 },
+	{ WCD934X_CDC_RX4_RX_PATH_CFG2,                    0x8f },
+	{ WCD934X_CDC_RX4_RX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_MIX_CTL,                 0x04 },
+	{ WCD934X_CDC_RX4_RX_PATH_MIX_CFG,                 0x7e },
+	{ WCD934X_CDC_RX4_RX_VOL_MIX_CTL,                  0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_SEC0,                    0xfc },
+	{ WCD934X_CDC_RX4_RX_PATH_SEC1,                    0x08 },
+	{ WCD934X_CDC_RX4_RX_PATH_SEC2,                    0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_SEC3,                    0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_SEC7,                    0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_MIX_SEC0,                0x08 },
+	{ WCD934X_CDC_RX4_RX_PATH_MIX_SEC1,                0x00 },
+	{ WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL,              0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_RX7_RX_PATH_CFG0,                    0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_CFG1,                    0x64 },
+	{ WCD934X_CDC_RX7_RX_PATH_CFG2,                    0x8f },
+	{ WCD934X_CDC_RX7_RX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_MIX_CTL,                 0x04 },
+	{ WCD934X_CDC_RX7_RX_PATH_MIX_CFG,                 0x7e },
+	{ WCD934X_CDC_RX7_RX_VOL_MIX_CTL,                  0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_SEC0,                    0x04 },
+	{ WCD934X_CDC_RX7_RX_PATH_SEC1,                    0x08 },
+	{ WCD934X_CDC_RX7_RX_PATH_SEC2,                    0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_SEC3,                    0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_SEC7,                    0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_MIX_SEC0,                0x08 },
+	{ WCD934X_CDC_RX7_RX_PATH_MIX_SEC1,                0x00 },
+	{ WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL,              0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_CTL,                     0x04 },
+	{ WCD934X_CDC_RX8_RX_PATH_CFG0,                    0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_CFG1,                    0x64 },
+	{ WCD934X_CDC_RX8_RX_PATH_CFG2,                    0x8f },
+	{ WCD934X_CDC_RX8_RX_VOL_CTL,                      0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_MIX_CTL,                 0x04 },
+	{ WCD934X_CDC_RX8_RX_PATH_MIX_CFG,                 0x7e },
+	{ WCD934X_CDC_RX8_RX_VOL_MIX_CTL,                  0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_SEC0,                    0x04 },
+	{ WCD934X_CDC_RX8_RX_PATH_SEC1,                    0x08 },
+	{ WCD934X_CDC_RX8_RX_PATH_SEC2,                    0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_SEC3,                    0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_SEC5,                    0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_SEC6,                    0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_SEC7,                    0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_MIX_SEC0,                0x08 },
+	{ WCD934X_CDC_RX8_RX_PATH_MIX_SEC1,                0x00 },
+	{ WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL,              0x00 },
+	{ WCD934X_PAGE12_PAGE_REGISTER,                    0x00 },
+	{ WCD934X_CDC_CLSH_CRC,                            0x00 },
+	{ WCD934X_CDC_CLSH_DLY_CTRL,                       0x03 },
+	{ WCD934X_CDC_CLSH_DECAY_CTRL,                     0x02 },
+	{ WCD934X_CDC_CLSH_HPH_V_PA,                       0x1c },
+	{ WCD934X_CDC_CLSH_EAR_V_PA,                       0x39 },
+	{ WCD934X_CDC_CLSH_HPH_V_HD,                       0x0c },
+	{ WCD934X_CDC_CLSH_EAR_V_HD,                       0x0c },
+	{ WCD934X_CDC_CLSH_K1_MSB,                         0x01 },
+	{ WCD934X_CDC_CLSH_K1_LSB,                         0x00 },
+	{ WCD934X_CDC_CLSH_K2_MSB,                         0x00 },
+	{ WCD934X_CDC_CLSH_K2_LSB,                         0x80 },
+	{ WCD934X_CDC_CLSH_IDLE_CTRL,                      0x00 },
+	{ WCD934X_CDC_CLSH_IDLE_HPH,                       0x00 },
+	{ WCD934X_CDC_CLSH_IDLE_EAR,                       0x00 },
+	{ WCD934X_CDC_CLSH_TEST0,                          0x07 },
+	{ WCD934X_CDC_CLSH_TEST1,                          0x00 },
+	{ WCD934X_CDC_CLSH_OVR_VREF,                       0x00 },
+	{ WCD934X_CDC_BOOST0_BOOST_PATH_CTL,               0x00 },
+	{ WCD934X_CDC_BOOST0_BOOST_CTL,                    0xb2 },
+	{ WCD934X_CDC_BOOST0_BOOST_CFG1,                   0x00 },
+	{ WCD934X_CDC_BOOST0_BOOST_CFG2,                   0x00 },
+	{ WCD934X_CDC_BOOST1_BOOST_PATH_CTL,               0x00 },
+	{ WCD934X_CDC_BOOST1_BOOST_CTL,                    0xb2 },
+	{ WCD934X_CDC_BOOST1_BOOST_CFG1,                   0x00 },
+	{ WCD934X_CDC_BOOST1_BOOST_CFG2,                   0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_PATH_CTL,                  0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_CFG,                       0x1a },
+	{ WCD934X_CDC_VBAT_VBAT_ADC_CAL1,                  0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_ADC_CAL2,                  0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_ADC_CAL3,                  0x04 },
+	{ WCD934X_CDC_VBAT_VBAT_PK_EST1,                   0xe0 },
+	{ WCD934X_CDC_VBAT_VBAT_PK_EST2,                   0x01 },
+	{ WCD934X_CDC_VBAT_VBAT_PK_EST3,                   0x40 },
+	{ WCD934X_CDC_VBAT_VBAT_RF_PROC1,                  0x2a },
+	{ WCD934X_CDC_VBAT_VBAT_RF_PROC2,                  0x86 },
+	{ WCD934X_CDC_VBAT_VBAT_TAC1,                      0x70 },
+	{ WCD934X_CDC_VBAT_VBAT_TAC2,                      0x18 },
+	{ WCD934X_CDC_VBAT_VBAT_TAC3,                      0x18 },
+	{ WCD934X_CDC_VBAT_VBAT_TAC4,                      0x03 },
+	{ WCD934X_CDC_VBAT_VBAT_GAIN_UPD1,                 0x01 },
+	{ WCD934X_CDC_VBAT_VBAT_GAIN_UPD2,                 0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_GAIN_UPD3,                 0x64 },
+	{ WCD934X_CDC_VBAT_VBAT_GAIN_UPD4,                 0x01 },
+	{ WCD934X_CDC_VBAT_VBAT_DEBUG1,                    0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_GAIN_UPD_MON,              0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_GAIN_MON_VAL,              0x00 },
+	{ WCD934X_CDC_VBAT_VBAT_BAN,                       0x0c },
+	{ WCD934X_MIXING_ASRC0_CLK_RST_CTL,                0x00 },
+	{ WCD934X_MIXING_ASRC0_CTL0,                       0x00 },
+	{ WCD934X_MIXING_ASRC0_CTL1,                       0x00 },
+	{ WCD934X_MIXING_ASRC0_FIFO_CTL,                   0xa8 },
+	{ WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC0_STATUS_FIFO,                0x00 },
+	{ WCD934X_MIXING_ASRC1_CLK_RST_CTL,                0x00 },
+	{ WCD934X_MIXING_ASRC1_CTL0,                       0x00 },
+	{ WCD934X_MIXING_ASRC1_CTL1,                       0x00 },
+	{ WCD934X_MIXING_ASRC1_FIFO_CTL,                   0xa8 },
+	{ WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC1_STATUS_FIFO,                0x00 },
+	{ WCD934X_MIXING_ASRC2_CLK_RST_CTL,                0x00 },
+	{ WCD934X_MIXING_ASRC2_CTL0,                       0x00 },
+	{ WCD934X_MIXING_ASRC2_CTL1,                       0x00 },
+	{ WCD934X_MIXING_ASRC2_FIFO_CTL,                   0xa8 },
+	{ WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC2_STATUS_FIFO,                0x00 },
+	{ WCD934X_MIXING_ASRC3_CLK_RST_CTL,                0x00 },
+	{ WCD934X_MIXING_ASRC3_CTL0,                       0x00 },
+	{ WCD934X_MIXING_ASRC3_CTL1,                       0x00 },
+	{ WCD934X_MIXING_ASRC3_FIFO_CTL,                   0xa8 },
+	{ WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_LSB,       0x00 },
+	{ WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_MSB,       0x00 },
+	{ WCD934X_MIXING_ASRC3_STATUS_FIFO,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_DATA_0,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_DATA_1,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_DATA_2,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_DATA_3,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_ADDR_1,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_ADDR_2,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_WR_ADDR_3,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_ADDR_1,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_ADDR_2,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_ADDR_3,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_DATA_0,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_DATA_1,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_DATA_2,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_RD_DATA_3,                0x00 },
+	{ WCD934X_SWR_AHB_BRIDGE_ACCESS_CFG,               0x0f },
+	{ WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS,            0x03 },
+	{ WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL,       0x04 },
+	{ WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1,      0x00 },
+	{ WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL,       0x04 },
+	{ WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1,      0x00 },
+	{ WCD934X_SIDETONE_ASRC0_CLK_RST_CTL,              0x00 },
+	{ WCD934X_SIDETONE_ASRC0_CTL0,                     0x00 },
+	{ WCD934X_SIDETONE_ASRC0_CTL1,                     0x00 },
+	{ WCD934X_SIDETONE_ASRC0_FIFO_CTL,                 0xa8 },
+	{ WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC0_STATUS_FIFO,              0x00 },
+	{ WCD934X_SIDETONE_ASRC1_CLK_RST_CTL,              0x00 },
+	{ WCD934X_SIDETONE_ASRC1_CTL0,                     0x00 },
+	{ WCD934X_SIDETONE_ASRC1_CTL1,                     0x00 },
+	{ WCD934X_SIDETONE_ASRC1_FIFO_CTL,                 0xa8 },
+	{ WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_LSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_MSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_LSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_MSB,     0x00 },
+	{ WCD934X_SIDETONE_ASRC1_STATUS_FIFO,              0x00 },
+	{ WCD934X_EC_REF_HQ0_EC_REF_HQ_PATH_CTL,           0x00 },
+	{ WCD934X_EC_REF_HQ0_EC_REF_HQ_CFG0,               0x01 },
+	{ WCD934X_EC_REF_HQ1_EC_REF_HQ_PATH_CTL,           0x00 },
+	{ WCD934X_EC_REF_HQ1_EC_REF_HQ_CFG0,               0x01 },
+	{ WCD934X_EC_ASRC0_CLK_RST_CTL,                    0x00 },
+	{ WCD934X_EC_ASRC0_CTL0,                           0x00 },
+	{ WCD934X_EC_ASRC0_CTL1,                           0x00 },
+	{ WCD934X_EC_ASRC0_FIFO_CTL,                       0xa8 },
+	{ WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_LSB,           0x00 },
+	{ WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_MSB,           0x00 },
+	{ WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_LSB,           0x00 },
+	{ WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_MSB,           0x00 },
+	{ WCD934X_EC_ASRC0_STATUS_FIFO,                    0x00 },
+	{ WCD934X_EC_ASRC1_CLK_RST_CTL,                    0x00 },
+	{ WCD934X_EC_ASRC1_CTL0,                           0x00 },
+	{ WCD934X_EC_ASRC1_CTL1,                           0x00 },
+	{ WCD934X_EC_ASRC1_FIFO_CTL,                       0xa8 },
+	{ WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_LSB,           0x00 },
+	{ WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_MSB,           0x00 },
+	{ WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_LSB,           0x00 },
+	{ WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_MSB,           0x00 },
+	{ WCD934X_EC_ASRC1_STATUS_FIFO,                    0x00 },
+	{ WCD934X_PAGE13_PAGE_REGISTER,                    0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1,             0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0,              0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1,              0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2,              0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3,              0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4,              0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0,        0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1,        0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_ANC_CFG0,                 0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0,         0x00 },
+	{ WCD934X_CDC_RX_INP_MUX_EC_REF_HQ_CFG0,           0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0,            0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0,           0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0,           0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0,           0x00 },
+	{ WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0,           0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0,  0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1,  0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2,  0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3,  0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0,  0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1,  0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2,  0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3,  0x00 },
+	{ WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0,               0x00 },
+	{ WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1,               0x00 },
+	{ WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2,               0x00 },
+	{ WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3,               0x00 },
+	{ WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL,           0x00 },
+	{ WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,         0x0c },
+	{ WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,            0x00 },
+	{ WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL,            0x00 },
+	{ WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL,     0x0f },
+	{ WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL,            0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_CTL,                0x08 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD0,       0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD1,       0x4b },
+	{ WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB,    0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB,    0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_STATUS,             0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_TEST_CTRL,          0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB,      0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB,      0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD,   0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD,   0x00 },
+	{ WCD934X_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT,     0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL,          0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_CTL,               0x40 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL,    0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL,          0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_CTL,               0x40 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL,    0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL,       0x00 },
+	{ WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL,       0x00 },
+	{ WCD934X_CDC_TOP_TOP_CFG0,                        0x00 },
+	{ WCD934X_CDC_TOP_TOP_CFG1,                        0x00 },
+	{ WCD934X_CDC_TOP_TOP_CFG7,                        0x00 },
+	{ WCD934X_CDC_TOP_HPHL_COMP_WR_LSB,                0x00 },
+	{ WCD934X_CDC_TOP_HPHL_COMP_WR_MSB,                0x00 },
+	{ WCD934X_CDC_TOP_HPHL_COMP_LUT,                   0x00 },
+	{ WCD934X_CDC_TOP_HPHL_COMP_RD_LSB,                0x00 },
+	{ WCD934X_CDC_TOP_HPHL_COMP_RD_MSB,                0x00 },
+	{ WCD934X_CDC_TOP_HPHR_COMP_WR_LSB,                0x00 },
+	{ WCD934X_CDC_TOP_HPHR_COMP_WR_MSB,                0x00 },
+	{ WCD934X_CDC_TOP_HPHR_COMP_LUT,                   0x00 },
+	{ WCD934X_CDC_TOP_HPHR_COMP_RD_LSB,                0x00 },
+	{ WCD934X_CDC_TOP_HPHR_COMP_RD_MSB,                0x00 },
+	{ WCD934X_CDC_TOP_DIFFL_COMP_WR_LSB,               0x00 },
+	{ WCD934X_CDC_TOP_DIFFL_COMP_WR_MSB,               0x00 },
+	{ WCD934X_CDC_TOP_DIFFL_COMP_LUT,                  0x00 },
+	{ WCD934X_CDC_TOP_DIFFL_COMP_RD_LSB,               0x00 },
+	{ WCD934X_CDC_TOP_DIFFL_COMP_RD_MSB,               0x00 },
+	{ WCD934X_CDC_TOP_DIFFR_COMP_WR_LSB,               0x00 },
+	{ WCD934X_CDC_TOP_DIFFR_COMP_WR_MSB,               0x00 },
+	{ WCD934X_CDC_TOP_DIFFR_COMP_LUT,                  0x00 },
+	{ WCD934X_CDC_TOP_DIFFR_COMP_RD_LSB,               0x00 },
+	{ WCD934X_CDC_TOP_DIFFR_COMP_RD_MSB,               0x00 },
+	{ WCD934X_CDC_DSD0_PATH_CTL,                       0x00 },
+	{ WCD934X_CDC_DSD0_CFG0,                           0x00 },
+	{ WCD934X_CDC_DSD0_CFG1,                           0x00 },
+	{ WCD934X_CDC_DSD0_CFG2,                           0x42 },
+	{ WCD934X_CDC_DSD0_CFG3,                           0x00 },
+	{ WCD934X_CDC_DSD0_CFG4,                           0x02 },
+	{ WCD934X_CDC_DSD0_CFG5,                           0x00 },
+	{ WCD934X_CDC_DSD1_PATH_CTL,                       0x00 },
+	{ WCD934X_CDC_DSD1_CFG0,                           0x00 },
+	{ WCD934X_CDC_DSD1_CFG1,                           0x00 },
+	{ WCD934X_CDC_DSD1_CFG2,                           0x42 },
+	{ WCD934X_CDC_DSD1_CFG3,                           0x00 },
+	{ WCD934X_CDC_DSD1_CFG4,                           0x02 },
+	{ WCD934X_CDC_DSD1_CFG5,                           0x00 },
+	{ WCD934X_CDC_RX_IDLE_DET_PATH_CTL,                0x00 },
+	{ WCD934X_CDC_RX_IDLE_DET_CFG0,                    0x07 },
+	{ WCD934X_CDC_RX_IDLE_DET_CFG1,                    0x3c },
+	{ WCD934X_CDC_RX_IDLE_DET_CFG2,                    0x00 },
+	{ WCD934X_CDC_RX_IDLE_DET_CFG3,                    0x00 },
+	{ WCD934X_PAGE14_PAGE_REGISTER,                    0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_CLK_RST_CTL,            0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_CTL,                    0x09 },
+	{ WCD934X_CDC_RATE_EST0_RE_PULSE_SUPR_CTL,         0x06 },
+	{ WCD934X_CDC_RATE_EST0_RE_TIMER,                  0x01 },
+	{ WCD934X_CDC_RATE_EST0_RE_BW_SW,                  0x20 },
+	{ WCD934X_CDC_RATE_EST0_RE_THRESH,                 0xa0 },
+	{ WCD934X_CDC_RATE_EST0_RE_STATUS,                 0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_CTRL,              0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_TIMER2,            0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW1,        0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW2,        0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW3,        0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW4,        0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW5,        0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW1,         0x08 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW2,         0x07 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW3,         0x05 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW4,         0x05 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW5,         0x05 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW1,       0x08 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW2,       0x07 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW3,       0x05 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW4,       0x05 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW5,       0x05 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW1,          0x03 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW2,          0x03 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW3,          0x03 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW4,          0x03 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW5,          0x03 },
+	{ WCD934X_CDC_RATE_EST0_RE_RMAX_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_RMIN_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_PH_DET,                 0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_DIAG_CLR,               0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_MB_SW_STATE,            0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_MAST_DIAG_STATE,        0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_RATE_OUT_7_0,           0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_RATE_OUT_15_8,          0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_RATE_OUT_23_16,         0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_RATE_OUT_31_24,         0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_RATE_OUT_39_32,         0x00 },
+	{ WCD934X_CDC_RATE_EST0_RE_RATE_OUT_40_43,         0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_CLK_RST_CTL,            0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_CTL,                    0x09 },
+	{ WCD934X_CDC_RATE_EST1_RE_PULSE_SUPR_CTL,         0x06 },
+	{ WCD934X_CDC_RATE_EST1_RE_TIMER,                  0x01 },
+	{ WCD934X_CDC_RATE_EST1_RE_BW_SW,                  0x20 },
+	{ WCD934X_CDC_RATE_EST1_RE_THRESH,                 0xa0 },
+	{ WCD934X_CDC_RATE_EST1_RE_STATUS,                 0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_CTRL,              0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_TIMER2,            0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW1,        0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW2,        0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW3,        0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW4,        0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW5,        0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW1,         0x08 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW2,         0x07 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW3,         0x05 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW4,         0x05 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW5,         0x05 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW1,       0x08 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW2,       0x07 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW3,       0x05 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW4,       0x05 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW5,       0x05 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW1,          0x03 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW2,          0x03 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW3,          0x03 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW4,          0x03 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW5,          0x03 },
+	{ WCD934X_CDC_RATE_EST1_RE_RMAX_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_RMIN_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_PH_DET,                 0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_DIAG_CLR,               0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_MB_SW_STATE,            0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_MAST_DIAG_STATE,        0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_RATE_OUT_7_0,           0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_RATE_OUT_15_8,          0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_RATE_OUT_23_16,         0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_RATE_OUT_31_24,         0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_RATE_OUT_39_32,         0x00 },
+	{ WCD934X_CDC_RATE_EST1_RE_RATE_OUT_40_43,         0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_CLK_RST_CTL,            0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_CTL,                    0x09 },
+	{ WCD934X_CDC_RATE_EST2_RE_PULSE_SUPR_CTL,         0x06 },
+	{ WCD934X_CDC_RATE_EST2_RE_TIMER,                  0x01 },
+	{ WCD934X_CDC_RATE_EST2_RE_BW_SW,                  0x20 },
+	{ WCD934X_CDC_RATE_EST2_RE_THRESH,                 0xa0 },
+	{ WCD934X_CDC_RATE_EST2_RE_STATUS,                 0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_CTRL,              0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_TIMER2,            0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW1,        0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW2,        0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW3,        0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW4,        0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW5,        0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW1,         0x08 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW2,         0x07 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW3,         0x05 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW4,         0x05 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW5,         0x05 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW1,       0x08 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW2,       0x07 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW3,       0x05 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW4,       0x05 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW5,       0x05 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW1,          0x03 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW2,          0x03 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW3,          0x03 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW4,          0x03 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW5,          0x03 },
+	{ WCD934X_CDC_RATE_EST2_RE_RMAX_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_RMIN_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_PH_DET,                 0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_DIAG_CLR,               0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_MB_SW_STATE,            0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_MAST_DIAG_STATE,        0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_RATE_OUT_7_0,           0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_RATE_OUT_15_8,          0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_RATE_OUT_23_16,         0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_RATE_OUT_31_24,         0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_RATE_OUT_39_32,         0x00 },
+	{ WCD934X_CDC_RATE_EST2_RE_RATE_OUT_40_43,         0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_CLK_RST_CTL,            0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_CTL,                    0x09 },
+	{ WCD934X_CDC_RATE_EST3_RE_PULSE_SUPR_CTL,         0x06 },
+	{ WCD934X_CDC_RATE_EST3_RE_TIMER,                  0x01 },
+	{ WCD934X_CDC_RATE_EST3_RE_BW_SW,                  0x20 },
+	{ WCD934X_CDC_RATE_EST3_RE_THRESH,                 0xa0 },
+	{ WCD934X_CDC_RATE_EST3_RE_STATUS,                 0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_CTRL,              0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_TIMER2,            0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW1,        0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW2,        0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW3,        0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW4,        0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW5,        0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW1,         0x08 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW2,         0x07 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW3,         0x05 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW4,         0x05 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW5,         0x05 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW1,       0x08 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW2,       0x07 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW3,       0x05 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW4,       0x05 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW5,       0x05 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW1,          0x03 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW2,          0x03 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW3,          0x03 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW4,          0x03 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW5,          0x03 },
+	{ WCD934X_CDC_RATE_EST3_RE_RMAX_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_RMIN_DIAG,              0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_PH_DET,                 0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_DIAG_CLR,               0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_MB_SW_STATE,            0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_MAST_DIAG_STATE,        0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_RATE_OUT_7_0,           0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_RATE_OUT_15_8,          0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_RATE_OUT_23_16,         0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_RATE_OUT_31_24,         0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_RATE_OUT_39_32,         0x00 },
+	{ WCD934X_CDC_RATE_EST3_RE_RATE_OUT_40_43,         0x00 },
+	{ WCD934X_PAGE15_PAGE_REGISTER,                    0x00 },
+	{ WCD934X_SPLINE_SRC0_CLK_RST_CTL_0,               0x20 },
+	{ WCD934X_SPLINE_SRC0_STATUS,                      0x00 },
+	{ WCD934X_SPLINE_SRC1_CLK_RST_CTL_0,               0x20 },
+	{ WCD934X_SPLINE_SRC1_STATUS,                      0x00 },
+	{ WCD934X_SPLINE_SRC2_CLK_RST_CTL_0,               0x20 },
+	{ WCD934X_SPLINE_SRC2_STATUS,                      0x00 },
+	{ WCD934X_SPLINE_SRC3_CLK_RST_CTL_0,               0x20 },
+	{ WCD934X_SPLINE_SRC3_STATUS,                      0x00 },
+	{ WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0,               0x11 },
+	{ WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1,               0x20 },
+	{ WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG2,               0x00 },
+	{ WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3,               0x08 },
+	{ WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0,               0x11 },
+	{ WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1,               0x20 },
+	{ WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG2,               0x00 },
+	{ WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3,               0x08 },
+	{ WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG0,         0x00 },
+	{ WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG1,         0x00 },
+	{ WCD934X_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0,         0x00 },
+	{ WCD934X_CDC_DEBUG_ANC0_RC0_FIFO_CTL,             0x4c },
+	{ WCD934X_CDC_DEBUG_ANC0_RC1_FIFO_CTL,             0x4c },
+	{ WCD934X_CDC_DEBUG_ANC1_RC0_FIFO_CTL,             0x4c },
+	{ WCD934X_CDC_DEBUG_ANC1_RC1_FIFO_CTL,             0x4c },
+	{ WCD934X_CDC_DEBUG_ANC_RC_RST_DBG_CNTR,           0x00 },
+	{ WCD934X_PAGE80_PAGE_REGISTER,                    0x00 },
+	{ WCD934X_CODEC_CPR_WR_DATA_0,                     0x00 },
+	{ WCD934X_CODEC_CPR_WR_DATA_1,                     0x00 },
+	{ WCD934X_CODEC_CPR_WR_DATA_2,                     0x00 },
+	{ WCD934X_CODEC_CPR_WR_DATA_3,                     0x00 },
+	{ WCD934X_CODEC_CPR_WR_ADDR_0,                     0x00 },
+	{ WCD934X_CODEC_CPR_WR_ADDR_1,                     0x00 },
+	{ WCD934X_CODEC_CPR_WR_ADDR_2,                     0x00 },
+	{ WCD934X_CODEC_CPR_WR_ADDR_3,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_ADDR_0,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_ADDR_1,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_ADDR_2,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_ADDR_3,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_DATA_0,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_DATA_1,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_DATA_2,                     0x00 },
+	{ WCD934X_CODEC_CPR_RD_DATA_3,                     0x00 },
+	{ WCD934X_CODEC_CPR_ACCESS_CFG,                    0x0f },
+	{ WCD934X_CODEC_CPR_ACCESS_STATUS,                 0x03 },
+	{ WCD934X_CODEC_CPR_NOM_CX_VDD,                    0xb4 },
+	{ WCD934X_CODEC_CPR_SVS_CX_VDD,                    0x5c },
+	{ WCD934X_CODEC_CPR_SVS2_CX_VDD,                   0x40 },
+	{ WCD934X_CODEC_CPR_NOM_MX_VDD,                    0xb4 },
+	{ WCD934X_CODEC_CPR_SVS_MX_VDD,                    0xb4 },
+	{ WCD934X_CODEC_CPR_SVS2_MX_VDD,                   0xa0 },
+	{ WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD,               0x28 },
+	{ WCD934X_CODEC_CPR_MAX_SVS2_STEP,                 0x08 },
+	{ WCD934X_CODEC_CPR_CTL,                           0x00 },
+	{ WCD934X_CODEC_CPR_SW_MODECHNG_STATUS,            0x00 },
+	{ WCD934X_CODEC_CPR_SW_MODECHNG_START,             0x00 },
+	{ WCD934X_CODEC_CPR_CPR_STATUS,                    0x00 },
+	{ WCD934X_PAGE128_PAGE_REGISTER,                   0x00 },
+	{ WCD934X_TLMM_BIST_MODE_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_RF_PA_ON_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_INTR1_PINCFG,                       0x00 },
+	{ WCD934X_TLMM_INTR2_PINCFG,                       0x00 },
+	{ WCD934X_TLMM_SWR_DATA_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_SWR_CLK_PINCFG,                     0x00 },
+	{ WCD934X_TLMM_I2S_2_SCK_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_SLIMBUS_DATA1_PINCFG,               0x00 },
+	{ WCD934X_TLMM_SLIMBUS_DATA2_PINCFG,               0x00 },
+	{ WCD934X_TLMM_SLIMBUS_CLK_PINCFG,                 0x00 },
+	{ WCD934X_TLMM_I2C_CLK_PINCFG,                     0x00 },
+	{ WCD934X_TLMM_I2C_DATA_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_I2S_0_RX_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_I2S_0_TX_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_I2S_0_SCK_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_I2S_0_WS_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_I2S_1_RX_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_I2S_1_TX_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_I2S_1_SCK_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_I2S_1_WS_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_DMIC1_CLK_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_DMIC1_DATA_PINCFG,                  0x00 },
+	{ WCD934X_TLMM_DMIC2_CLK_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_DMIC2_DATA_PINCFG,                  0x00 },
+	{ WCD934X_TLMM_DMIC3_CLK_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_DMIC3_DATA_PINCFG,                  0x00 },
+	{ WCD934X_TLMM_JTCK_PINCFG,                        0x00 },
+	{ WCD934X_TLMM_GPIO1_PINCFG,                       0x00 },
+	{ WCD934X_TLMM_GPIO2_PINCFG,                       0x00 },
+	{ WCD934X_TLMM_GPIO3_PINCFG,                       0x00 },
+	{ WCD934X_TLMM_GPIO4_PINCFG,                       0x00 },
+	{ WCD934X_TLMM_SPI_S_CSN_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_SPI_S_CLK_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_SPI_S_DOUT_PINCFG,                  0x00 },
+	{ WCD934X_TLMM_SPI_S_DIN_PINCFG,                   0x00 },
+	{ WCD934X_TLMM_BA_N_PINCFG,                        0x00 },
+	{ WCD934X_TLMM_GPIO0_PINCFG,                       0x00 },
+	{ WCD934X_TLMM_I2S_2_RX_PINCFG,                    0x00 },
+	{ WCD934X_TLMM_I2S_2_WS_PINCFG,                    0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_OE_0,                 0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_OE_1,                 0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_OE_2,                 0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_OE_3,                 0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_OE_4,                 0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_DATA_0,               0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_DATA_1,               0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_DATA_2,               0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_DATA_3,               0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_CTL_DATA_4,               0x00 },
+	{ WCD934X_TEST_DEBUG_PAD_DRVCTL_0,                 0x00 },
+	{ WCD934X_TEST_DEBUG_PAD_DRVCTL_1,                 0x00 },
+	{ WCD934X_TEST_DEBUG_PIN_STATUS,                   0x00 },
+	{ WCD934X_TEST_DEBUG_NPL_DLY_TEST_1,               0x10 },
+	{ WCD934X_TEST_DEBUG_NPL_DLY_TEST_2,               0x60 },
+	{ WCD934X_TEST_DEBUG_MEM_CTRL,                     0x00 },
+	{ WCD934X_TEST_DEBUG_DEBUG_BUS_SEL,                0x00 },
+	{ WCD934X_TEST_DEBUG_DEBUG_JTAG,                   0x00 },
+	{ WCD934X_TEST_DEBUG_DEBUG_EN_1,                   0x00 },
+	{ WCD934X_TEST_DEBUG_DEBUG_EN_2,                   0x00 },
+	{ WCD934X_TEST_DEBUG_DEBUG_EN_3,                   0x00 },
+	{ WCD934X_TEST_DEBUG_DEBUG_EN_4,                   0x00 },
+	{ WCD934X_TEST_DEBUG_DEBUG_EN_5,                   0x00 },
+	{ WCD934X_TEST_DEBUG_ANA_DTEST_DIR,                0x00 },
+	{ WCD934X_TEST_DEBUG_PAD_INP_DISABLE_0,            0x00 },
+	{ WCD934X_TEST_DEBUG_PAD_INP_DISABLE_1,            0x00 },
+	{ WCD934X_TEST_DEBUG_PAD_INP_DISABLE_2,            0x00 },
+	{ WCD934X_TEST_DEBUG_PAD_INP_DISABLE_3,            0x00 },
+	{ WCD934X_TEST_DEBUG_PAD_INP_DISABLE_4,            0x00 },
+	{ WCD934X_TEST_DEBUG_SYSMEM_CTRL,                  0x00 },
+	{ WCD934X_TEST_DEBUG_SOC_SW_PWR_SEQ_DELAY,         0x00 },
+	{ WCD934X_TEST_DEBUG_LVAL_NOM_LOW,                 0x96 },
+	{ WCD934X_TEST_DEBUG_LVAL_NOM_HIGH,                0x00 },
+	{ WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW,            0x53 },
+	{ WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH,           0x00 },
+	{ WCD934X_TEST_DEBUG_SPI_SLAVE_CHAR,               0x00 },
+	{ WCD934X_TEST_DEBUG_CODEC_DIAGS,                  0x00 },
+};
+
+/*
+ * wcd934x_regmap_register_patch: Update register defaults based on version
+ * @regmap: handle to wcd9xxx regmap
+ * @version: wcd934x version
+ *
+ * Returns error code in case of failure or 0 for success
+ */
+int wcd934x_regmap_register_patch(struct regmap *regmap, int revision)
+{
+	int rc = 0;
+
+	if (!regmap) {
+		pr_err("%s: regmap struct is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (revision) {
+	case TAVIL_VERSION_1_1:
+	case TAVIL_VERSION_WCD9340_1_1:
+	case TAVIL_VERSION_WCD9341_1_1:
+		regcache_cache_only(regmap, true);
+		rc = regmap_multi_reg_write(regmap, wcd934x_1_1_defaults,
+					    ARRAY_SIZE(wcd934x_1_1_defaults));
+		regcache_cache_only(regmap, false);
+		break;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(wcd934x_regmap_register_patch);
+
+static bool wcd934x_is_readable_register(struct device *dev, unsigned int reg)
+{
+	u8 pg_num, reg_offset;
+	const u8 *reg_tbl = NULL;
+
+	/*
+	 * Get the page number from MSB of codec register. If its 0x80, assign
+	 * the corresponding page index PAGE_0x80.
+	 */
+	pg_num = reg >> 0x8;
+	if (pg_num == 0x80)
+		pg_num = WCD934X_PAGE_0X80;
+	else if (pg_num == 0x50)
+		pg_num = WCD934X_PAGE_0x50;
+	else if (pg_num > 0xF)
+		return false;
+
+	reg_tbl = wcd934x_reg[pg_num];
+	reg_offset = reg & 0xFF;
+
+	if (reg_tbl && reg_tbl[reg_offset])
+		return true;
+	else
+		return false;
+}
+
+static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	u8 pg_num, reg_offset;
+	const u8 *reg_tbl = NULL;
+
+	pg_num = reg >> 0x8;
+	if (pg_num == 0x80)
+		pg_num = WCD934X_PAGE_0X80;
+	else if (pg_num == 0x50)
+		pg_num = WCD934X_PAGE_0x50;
+	else if (pg_num > 0xF)
+		return false;
+
+	reg_tbl = wcd934x_reg[pg_num];
+	reg_offset = reg & 0xFF;
+
+	if (reg_tbl && reg_tbl[reg_offset] == WCD934X_READ)
+		return true;
+
+	/* IIR Coeff registers are not cacheable */
+	if ((reg >= WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL) &&
+	    (reg <= WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL))
+		return true;
+
+	if ((reg >= WCD934X_CDC_ANC0_IIR_COEFF_1_CTL) &&
+	    (reg <= WCD934X_CDC_ANC0_FB_GAIN_CTL))
+		return true;
+
+	if ((reg >= WCD934X_CDC_ANC1_IIR_COEFF_1_CTL) &&
+	    (reg <= WCD934X_CDC_ANC1_FB_GAIN_CTL))
+		return true;
+
+	if ((reg >= WCD934X_CODEC_CPR_WR_DATA_0) &&
+	    (reg <= WCD934X_CODEC_CPR_RD_DATA_3))
+		return true;
+
+	/*
+	 * Need to mark volatile for registers that are writable but
+	 * only few bits are read-only
+	 */
+	switch (reg) {
+	case WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL:
+	case WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0:
+	case WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1:
+	case WCD934X_CPE_SS_CPAR_CTL:
+	case WCD934X_CPE_SS_STATUS:
+	case WCD934X_CODEC_RPM_RST_CTL:
+	case WCD934X_SIDO_NEW_VOUT_A_STARTUP:
+	case WCD934X_SIDO_NEW_VOUT_D_STARTUP:
+	case WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL:
+	case WCD934X_ANA_MBHC_MECH:
+	case WCD934X_ANA_MBHC_ELECT:
+	case WCD934X_ANA_MBHC_ZDET:
+	case WCD934X_ANA_MICB2:
+	case WCD934X_CODEC_RPM_CLK_MCLK_CFG:
+	case WCD934X_CLK_SYS_MCLK_PRG:
+	case WCD934X_CHIP_TIER_CTRL_EFUSE_CTL:
+	case WCD934X_ANA_BIAS:
+	case WCD934X_ANA_BUCK_CTL:
+	case WCD934X_ANA_RCO:
+	case WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL:
+	case WCD934X_CODEC_RPM_CLK_GATE:
+	case WCD934X_BIAS_VBG_FINE_ADJ:
+	case WCD934X_CODEC_CPR_SVS_CX_VDD:
+	case WCD934X_CODEC_CPR_SVS2_CX_VDD:
+	case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
+		return true;
+	}
+
+	return false;
+}
+
+struct regmap_config wcd934x_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wcd934x_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wcd934x_defaults),
+	.max_register = WCD934X_MAX_REGISTER,
+	.volatile_reg = wcd934x_is_volatile_register,
+	.readable_reg = wcd934x_is_readable_register,
+	.can_multi_write = true,
+};
diff --git a/asoc/codecs/wcd934x/wcd934x-routing.h b/asoc/codecs/wcd934x/wcd934x-routing.h
new file mode 100644
index 0000000..93a1ad3
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-routing.h
@@ -0,0 +1,1235 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef WCD934X_ROUTING_H
+#define WCD934X_ROUTING_H
+
+#include <sound/soc-dapm.h>
+
+const struct snd_soc_dapm_route tavil_slim_audio_map[] = {
+
+	/* Virtual input widgets */
+	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+	{"AIF4 MAD", NULL, "AIF4_MAD Mixer"},
+
+	/* Virtual input widget Mixer */
+	{"AIF1_CAP Mixer", "SLIM TX0", "SLIM TX0"},
+	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1"},
+	{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2"},
+	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3"},
+	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4"},
+	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5"},
+	{"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6"},
+	{"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7"},
+	{"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8"},
+	{"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9"},
+	{"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10"},
+	{"AIF1_CAP Mixer", "SLIM TX11", "SLIM TX11"},
+	{"AIF1_CAP Mixer", "SLIM TX13", "SLIM TX13"},
+
+	{"AIF2_CAP Mixer", "SLIM TX0", "SLIM TX0"},
+	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1"},
+	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2"},
+	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3"},
+	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4"},
+	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5"},
+	{"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6"},
+	{"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7"},
+	{"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8"},
+	{"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9"},
+	{"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10"},
+	{"AIF2_CAP Mixer", "SLIM TX11", "SLIM TX11"},
+	{"AIF2_CAP Mixer", "SLIM TX13", "SLIM TX13"},
+
+	{"AIF3_CAP Mixer", "SLIM TX0", "SLIM TX0"},
+	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1"},
+	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2"},
+	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3"},
+	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4"},
+	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5"},
+	{"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6"},
+	{"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7"},
+	{"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8"},
+	{"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9"},
+	{"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10"},
+	{"AIF3_CAP Mixer", "SLIM TX11", "SLIM TX11"},
+	{"AIF3_CAP Mixer", "SLIM TX13", "SLIM TX13"},
+
+	{"AIF4_MAD Mixer", "SLIM TX13", "SLIM TX13"},
+
+	{"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
+
+	{"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
+
+	{"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
+
+	{"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"},
+
+	{"SLIM RX0", NULL, "SLIM RX0 MUX"},
+	{"SLIM RX1", NULL, "SLIM RX1 MUX"},
+	{"SLIM RX2", NULL, "SLIM RX2 MUX"},
+	{"SLIM RX3", NULL, "SLIM RX3 MUX"},
+	{"SLIM RX4", NULL, "SLIM RX4 MUX"},
+	{"SLIM RX5", NULL, "SLIM RX5 MUX"},
+	{"SLIM RX6", NULL, "SLIM RX6 MUX"},
+	{"SLIM RX7", NULL, "SLIM RX7 MUX"},
+
+};
+
+const struct snd_soc_dapm_route tavil_audio_map[] = {
+
+	/* WDMA3 */
+	{"WDMA3 PORT0 MUX", "DEC0", "ADC MUX0"},
+	{"WDMA3 PORT0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"},
+	{"WDMA3 PORT1 MUX", "DEC1", "ADC MUX1"},
+	{"WDMA3 PORT1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"},
+	{"WDMA3 PORT2 MUX", "DEC2", "ADC MUX2"},
+	{"WDMA3 PORT2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"},
+	{"WDMA3 PORT3 MUX", "DEC3", "ADC MUX3"},
+	{"WDMA3 PORT3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"},
+	{"WDMA3 PORT4 MUX", "DEC4", "ADC MUX4"},
+	{"WDMA3 PORT4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"},
+	{"WDMA3 PORT5 MUX", "DEC5", "ADC MUX5"},
+	{"WDMA3 PORT5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"},
+	{"WDMA3 PORT6 MUX", "DEC6", "ADC MUX6"},
+	{"WDMA3 PORT6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"},
+
+	{"WDMA3 CH0 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+	{"WDMA3 CH0 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+	{"WDMA3 CH0 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+	{"WDMA3 CH0 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+	{"WDMA3 CH0 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+	{"WDMA3 CH0 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+	{"WDMA3 CH0 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+	{"WDMA3 CH0 MUX", "PORT_7", "ADC MUX7"},
+	{"WDMA3 CH0 MUX", "PORT_8", "ADC MUX8"},
+
+	{"WDMA3 CH1 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+	{"WDMA3 CH1 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+	{"WDMA3 CH1 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+	{"WDMA3 CH1 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+	{"WDMA3 CH1 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+	{"WDMA3 CH1 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+	{"WDMA3 CH1 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+	{"WDMA3 CH1 MUX", "PORT_7", "ADC MUX7"},
+	{"WDMA3 CH1 MUX", "PORT_8", "ADC MUX8"},
+
+	{"WDMA3 CH2 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+	{"WDMA3 CH2 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+	{"WDMA3 CH2 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+	{"WDMA3 CH2 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+	{"WDMA3 CH2 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+	{"WDMA3 CH2 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+	{"WDMA3 CH2 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+	{"WDMA3 CH2 MUX", "PORT_7", "ADC MUX7"},
+	{"WDMA3 CH2 MUX", "PORT_8", "ADC MUX8"},
+
+	{"WDMA3 CH3 MUX", "PORT_0", "WDMA3 PORT0 MUX"},
+	{"WDMA3 CH3 MUX", "PORT_1", "WDMA3 PORT1 MUX"},
+	{"WDMA3 CH3 MUX", "PORT_2", "WDMA3 PORT2 MUX"},
+	{"WDMA3 CH3 MUX", "PORT_3", "WDMA3 PORT3 MUX"},
+	{"WDMA3 CH3 MUX", "PORT_4", "WDMA3 PORT4 MUX"},
+	{"WDMA3 CH3 MUX", "PORT_5", "WDMA3 PORT5 MUX"},
+	{"WDMA3 CH3 MUX", "PORT_6", "WDMA3 PORT6 MUX"},
+	{"WDMA3 CH3 MUX", "PORT_7", "ADC MUX7"},
+	{"WDMA3 CH3 MUX", "PORT_8", "ADC MUX8"},
+
+	{"WDMA3_CH_MIXER", NULL, "WDMA3 CH0 MUX"},
+	{"WDMA3_CH_MIXER", NULL, "WDMA3 CH1 MUX"},
+	{"WDMA3_CH_MIXER", NULL, "WDMA3 CH2 MUX"},
+	{"WDMA3_CH_MIXER", NULL, "WDMA3 CH3 MUX"},
+
+	{"WDMA3_ON_OFF", "Switch", "WDMA3_CH_MIXER"},
+	{"WDMA3_OUT", NULL, "WDMA3_ON_OFF"},
+
+	/* MAD */
+	{"MAD_SEL MUX", "SPE", "MAD_CPE_INPUT"},
+	{"MAD_SEL MUX", "MSM", "MADINPUT"},
+
+	{"MAD_INP MUX", "MAD", "MAD_SEL MUX"},
+	{"MAD_INP MUX", "DEC1", "ADC MUX1"},
+
+	{"MAD_BROADCAST", "Switch", "MAD_INP MUX"},
+	{"MAD_CPE1", "Switch", "MAD_INP MUX"},
+	{"MAD_CPE2", "Switch", "MAD_INP MUX"},
+
+	{"MAD_CPE_OUT1", NULL, "MAD_CPE1"},
+	{"MAD_CPE_OUT2", NULL, "MAD_CPE2"},
+
+	/* VI Feedback */
+	{"AIF4_VI Mixer", "SPKR_VI_1", "VIINPUT"},
+	{"AIF4_VI Mixer", "SPKR_VI_2", "VIINPUT"},
+	{"AIF4 VI", NULL, "AIF4_VI Mixer"},
+
+	/* CDC Tx interface with SLIMBUS */
+	{"SLIM TX0", NULL, "CDC_IF TX0 MUX"},
+	{"SLIM TX1", NULL, "CDC_IF TX1 MUX"},
+	{"SLIM TX2", NULL, "CDC_IF TX2 MUX"},
+	{"SLIM TX3", NULL, "CDC_IF TX3 MUX"},
+	{"SLIM TX4", NULL, "CDC_IF TX4 MUX"},
+	{"SLIM TX5", NULL, "CDC_IF TX5 MUX"},
+	{"SLIM TX6", NULL, "CDC_IF TX6 MUX"},
+	{"SLIM TX7", NULL, "CDC_IF TX7 MUX"},
+	{"SLIM TX8", NULL, "CDC_IF TX8 MUX"},
+	{"SLIM TX9", NULL, "CDC_IF TX9 MUX"},
+	{"SLIM TX10", NULL, "CDC_IF TX10 MUX"},
+	{"SLIM TX11", NULL, "CDC_IF TX11 MUX"},
+	{"SLIM TX13", NULL, "CDC_IF TX13 MUX"},
+
+	{"CDC_IF TX0 MUX", "DEC0", "ADC MUX0"},
+	{"CDC_IF TX0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"},
+	{"CDC_IF TX0 MUX", "DEC0_192", "ADC US MUX0"},
+
+	{"CDC_IF TX1 MUX", "DEC1", "ADC MUX1"},
+	{"CDC_IF TX1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"},
+	{"CDC_IF TX1 MUX", "DEC1_192", "ADC US MUX1"},
+
+	{"CDC_IF TX2 MUX", "DEC2", "ADC MUX2"},
+	{"CDC_IF TX2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"},
+	{"CDC_IF TX2 MUX", "DEC2_192", "ADC US MUX2"},
+
+	{"CDC_IF TX3 MUX", "DEC3", "ADC MUX3"},
+	{"CDC_IF TX3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"},
+	{"CDC_IF TX3 MUX", "DEC3_192", "ADC US MUX3"},
+
+	{"CDC_IF TX4 MUX", "DEC4", "ADC MUX4"},
+	{"CDC_IF TX4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"},
+	{"CDC_IF TX4 MUX", "DEC4_192", "ADC US MUX4"},
+
+	{"CDC_IF TX5 MUX", "DEC5", "ADC MUX5"},
+	{"CDC_IF TX5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"},
+	{"CDC_IF TX5 MUX", "DEC5_192", "ADC US MUX5"},
+
+	{"CDC_IF TX6 MUX", "DEC6", "ADC MUX6"},
+	{"CDC_IF TX6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"},
+	{"CDC_IF TX6 MUX", "DEC6_192", "ADC US MUX6"},
+
+	{"CDC_IF TX7 MUX", "DEC7", "ADC MUX7"},
+	{"CDC_IF TX7 MUX", "RX_MIX_TX7", "RX MIX TX7 MUX"},
+	{"CDC_IF TX7 MUX", "DEC7_192", "ADC US MUX7"},
+
+	{"CDC_IF TX8 MUX", "DEC8", "ADC MUX8"},
+	{"CDC_IF TX8 MUX", "RX_MIX_TX8", "RX MIX TX8 MUX"},
+	{"CDC_IF TX8 MUX", "DEC8_192", "ADC US MUX8"},
+
+	{"CDC_IF TX9 MUX", "DEC7", "ADC MUX7"},
+	{"CDC_IF TX9 MUX", "DEC7_192", "ADC US MUX7"},
+	{"CDC_IF TX10 MUX", "DEC6", "ADC MUX6"},
+	{"CDC_IF TX10 MUX", "DEC6_192", "ADC US MUX6"},
+
+	{"CDC_IF TX11 MUX", "DEC_0_5", "CDC_IF TX11 INP1 MUX"},
+	{"CDC_IF TX11 MUX", "DEC_9_12", "CDC_IF TX11 INP1 MUX"},
+	{"CDC_IF TX11 INP1 MUX", "DEC0", "ADC MUX0"},
+	{"CDC_IF TX11 INP1 MUX", "DEC1", "ADC MUX1"},
+	{"CDC_IF TX11 INP1 MUX", "DEC2", "ADC MUX2"},
+	{"CDC_IF TX11 INP1 MUX", "DEC3", "ADC MUX3"},
+	{"CDC_IF TX11 INP1 MUX", "DEC4", "ADC MUX4"},
+	{"CDC_IF TX11 INP1 MUX", "DEC5", "ADC MUX5"},
+	{"CDC_IF TX11 INP1 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"},
+
+	{"CDC_IF TX13 MUX", "MAD_BRDCST", "MAD_BROADCAST"},
+	{"CDC_IF TX13 MUX", "CDC_DEC_5", "CDC_IF TX13 INP1 MUX"},
+	{"CDC_IF TX13 INP1 MUX", "DEC5", "ADC MUX5"},
+	{"CDC_IF TX13 INP1 MUX", "DEC5_192", "ADC US MUX5"},
+
+	{"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX0 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX1 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX2 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX3 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX3 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX4 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX4 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX5 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX5 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX6 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX6 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX7 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX7 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"RX MIX TX8 MUX", "RX_MIX0", "RX INT0 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX1", "RX INT1 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX2", "RX INT2 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX3", "RX INT3 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX4", "RX INT4 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX7", "RX INT7 SEC MIX"},
+	{"RX MIX TX8 MUX", "RX_MIX8", "RX INT8 SEC MIX"},
+
+	{"ADC US MUX0", "US_Switch", "ADC MUX0"},
+	{"ADC US MUX1", "US_Switch", "ADC MUX1"},
+	{"ADC US MUX2", "US_Switch", "ADC MUX2"},
+	{"ADC US MUX3", "US_Switch", "ADC MUX3"},
+	{"ADC US MUX4", "US_Switch", "ADC MUX4"},
+	{"ADC US MUX5", "US_Switch", "ADC MUX5"},
+	{"ADC US MUX6", "US_Switch", "ADC MUX6"},
+	{"ADC US MUX7", "US_Switch", "ADC MUX7"},
+	{"ADC US MUX8", "US_Switch", "ADC MUX8"},
+
+	{"ADC MUX0", "DMIC", "DMIC MUX0"},
+	{"ADC MUX0", "AMIC", "AMIC MUX0"},
+	{"ADC MUX1", "DMIC", "DMIC MUX1"},
+	{"ADC MUX1", "AMIC", "AMIC MUX1"},
+	{"ADC MUX2", "DMIC", "DMIC MUX2"},
+	{"ADC MUX2", "AMIC", "AMIC MUX2"},
+	{"ADC MUX3", "DMIC", "DMIC MUX3"},
+	{"ADC MUX3", "AMIC", "AMIC MUX3"},
+	{"ADC MUX4", "DMIC", "DMIC MUX4"},
+	{"ADC MUX4", "AMIC", "AMIC MUX4"},
+	{"ADC MUX5", "DMIC", "DMIC MUX5"},
+	{"ADC MUX5", "AMIC", "AMIC MUX5"},
+	{"ADC MUX6", "DMIC", "DMIC MUX6"},
+	{"ADC MUX6", "AMIC", "AMIC MUX6"},
+	{"ADC MUX7", "DMIC", "DMIC MUX7"},
+	{"ADC MUX7", "AMIC", "AMIC MUX7"},
+	{"ADC MUX8", "DMIC", "DMIC MUX8"},
+	{"ADC MUX8", "AMIC", "AMIC MUX8"},
+	{"ADC MUX10", "DMIC", "DMIC MUX10"},
+	{"ADC MUX10", "AMIC", "AMIC MUX10"},
+	{"ADC MUX11", "DMIC", "DMIC MUX11"},
+	{"ADC MUX11", "AMIC", "AMIC MUX11"},
+	{"ADC MUX12", "DMIC", "DMIC MUX12"},
+	{"ADC MUX12", "AMIC", "AMIC MUX12"},
+	{"ADC MUX13", "DMIC", "DMIC MUX13"},
+	{"ADC MUX13", "AMIC", "AMIC MUX13"},
+
+	{"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX13"},
+	{"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX10"},
+	{"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX11"},
+	{"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX12"},
+	{"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX13"},
+
+	{"DMIC MUX0", "DMIC0", "DMIC0"},
+	{"DMIC MUX0", "DMIC1", "DMIC1"},
+	{"DMIC MUX0", "DMIC2", "DMIC2"},
+	{"DMIC MUX0", "DMIC3", "DMIC3"},
+	{"DMIC MUX0", "DMIC4", "DMIC4"},
+	{"DMIC MUX0", "DMIC5", "DMIC5"},
+	{"AMIC MUX0", "ADC1", "ADC1"},
+	{"AMIC MUX0", "ADC2", "ADC2"},
+	{"AMIC MUX0", "ADC3", "ADC3"},
+	{"AMIC MUX0", "ADC4", "ADC4"},
+
+	{"DMIC MUX1", "DMIC0", "DMIC0"},
+	{"DMIC MUX1", "DMIC1", "DMIC1"},
+	{"DMIC MUX1", "DMIC2", "DMIC2"},
+	{"DMIC MUX1", "DMIC3", "DMIC3"},
+	{"DMIC MUX1", "DMIC4", "DMIC4"},
+	{"DMIC MUX1", "DMIC5", "DMIC5"},
+	{"AMIC MUX1", "ADC1", "ADC1"},
+	{"AMIC MUX1", "ADC2", "ADC2"},
+	{"AMIC MUX1", "ADC3", "ADC3"},
+	{"AMIC MUX1", "ADC4", "ADC4"},
+
+	{"DMIC MUX2", "DMIC0", "DMIC0"},
+	{"DMIC MUX2", "DMIC1", "DMIC1"},
+	{"DMIC MUX2", "DMIC2", "DMIC2"},
+	{"DMIC MUX2", "DMIC3", "DMIC3"},
+	{"DMIC MUX2", "DMIC4", "DMIC4"},
+	{"DMIC MUX2", "DMIC5", "DMIC5"},
+	{"AMIC MUX2", "ADC1", "ADC1"},
+	{"AMIC MUX2", "ADC2", "ADC2"},
+	{"AMIC MUX2", "ADC3", "ADC3"},
+	{"AMIC MUX2", "ADC4", "ADC4"},
+
+	{"DMIC MUX3", "DMIC0", "DMIC0"},
+	{"DMIC MUX3", "DMIC1", "DMIC1"},
+	{"DMIC MUX3", "DMIC2", "DMIC2"},
+	{"DMIC MUX3", "DMIC3", "DMIC3"},
+	{"DMIC MUX3", "DMIC4", "DMIC4"},
+	{"DMIC MUX3", "DMIC5", "DMIC5"},
+	{"AMIC MUX3", "ADC1", "ADC1"},
+	{"AMIC MUX3", "ADC2", "ADC2"},
+	{"AMIC MUX3", "ADC3", "ADC3"},
+	{"AMIC MUX3", "ADC4", "ADC4"},
+
+	{"DMIC MUX4", "DMIC0", "DMIC0"},
+	{"DMIC MUX4", "DMIC1", "DMIC1"},
+	{"DMIC MUX4", "DMIC2", "DMIC2"},
+	{"DMIC MUX4", "DMIC3", "DMIC3"},
+	{"DMIC MUX4", "DMIC4", "DMIC4"},
+	{"DMIC MUX4", "DMIC5", "DMIC5"},
+	{"AMIC MUX4", "ADC1", "ADC1"},
+	{"AMIC MUX4", "ADC2", "ADC2"},
+	{"AMIC MUX4", "ADC3", "ADC3"},
+	{"AMIC MUX4", "ADC4", "ADC4"},
+
+	{"DMIC MUX5", "DMIC0", "DMIC0"},
+	{"DMIC MUX5", "DMIC1", "DMIC1"},
+	{"DMIC MUX5", "DMIC2", "DMIC2"},
+	{"DMIC MUX5", "DMIC3", "DMIC3"},
+	{"DMIC MUX5", "DMIC4", "DMIC4"},
+	{"DMIC MUX5", "DMIC5", "DMIC5"},
+	{"AMIC MUX5", "ADC1", "ADC1"},
+	{"AMIC MUX5", "ADC2", "ADC2"},
+	{"AMIC MUX5", "ADC3", "ADC3"},
+	{"AMIC MUX5", "ADC4", "ADC4"},
+
+	{"DMIC MUX6", "DMIC0", "DMIC0"},
+	{"DMIC MUX6", "DMIC1", "DMIC1"},
+	{"DMIC MUX6", "DMIC2", "DMIC2"},
+	{"DMIC MUX6", "DMIC3", "DMIC3"},
+	{"DMIC MUX6", "DMIC4", "DMIC4"},
+	{"DMIC MUX6", "DMIC5", "DMIC5"},
+	{"AMIC MUX6", "ADC1", "ADC1"},
+	{"AMIC MUX6", "ADC2", "ADC2"},
+	{"AMIC MUX6", "ADC3", "ADC3"},
+	{"AMIC MUX6", "ADC4", "ADC4"},
+
+	{"DMIC MUX7", "DMIC0", "DMIC0"},
+	{"DMIC MUX7", "DMIC1", "DMIC1"},
+	{"DMIC MUX7", "DMIC2", "DMIC2"},
+	{"DMIC MUX7", "DMIC3", "DMIC3"},
+	{"DMIC MUX7", "DMIC4", "DMIC4"},
+	{"DMIC MUX7", "DMIC5", "DMIC5"},
+	{"AMIC MUX7", "ADC1", "ADC1"},
+	{"AMIC MUX7", "ADC2", "ADC2"},
+	{"AMIC MUX7", "ADC3", "ADC3"},
+	{"AMIC MUX7", "ADC4", "ADC4"},
+
+	{"DMIC MUX8", "DMIC0", "DMIC0"},
+	{"DMIC MUX8", "DMIC1", "DMIC1"},
+	{"DMIC MUX8", "DMIC2", "DMIC2"},
+	{"DMIC MUX8", "DMIC3", "DMIC3"},
+	{"DMIC MUX8", "DMIC4", "DMIC4"},
+	{"DMIC MUX8", "DMIC5", "DMIC5"},
+	{"AMIC MUX8", "ADC1", "ADC1"},
+	{"AMIC MUX8", "ADC2", "ADC2"},
+	{"AMIC MUX8", "ADC3", "ADC3"},
+	{"AMIC MUX8", "ADC4", "ADC4"},
+
+	{"DMIC MUX10", "DMIC0", "DMIC0"},
+	{"DMIC MUX10", "DMIC1", "DMIC1"},
+	{"DMIC MUX10", "DMIC2", "DMIC2"},
+	{"DMIC MUX10", "DMIC3", "DMIC3"},
+	{"DMIC MUX10", "DMIC4", "DMIC4"},
+	{"DMIC MUX10", "DMIC5", "DMIC5"},
+	{"AMIC MUX10", "ADC1", "ADC1"},
+	{"AMIC MUX10", "ADC2", "ADC2"},
+	{"AMIC MUX10", "ADC3", "ADC3"},
+	{"AMIC MUX10", "ADC4", "ADC4"},
+
+	{"DMIC MUX11", "DMIC0", "DMIC0"},
+	{"DMIC MUX11", "DMIC1", "DMIC1"},
+	{"DMIC MUX11", "DMIC2", "DMIC2"},
+	{"DMIC MUX11", "DMIC3", "DMIC3"},
+	{"DMIC MUX11", "DMIC4", "DMIC4"},
+	{"DMIC MUX11", "DMIC5", "DMIC5"},
+	{"AMIC MUX11", "ADC1", "ADC1"},
+	{"AMIC MUX11", "ADC2", "ADC2"},
+	{"AMIC MUX11", "ADC3", "ADC3"},
+	{"AMIC MUX11", "ADC4", "ADC4"},
+
+	{"DMIC MUX12", "DMIC0", "DMIC0"},
+	{"DMIC MUX12", "DMIC1", "DMIC1"},
+	{"DMIC MUX12", "DMIC2", "DMIC2"},
+	{"DMIC MUX12", "DMIC3", "DMIC3"},
+	{"DMIC MUX12", "DMIC4", "DMIC4"},
+	{"DMIC MUX12", "DMIC5", "DMIC5"},
+	{"AMIC MUX12", "ADC1", "ADC1"},
+	{"AMIC MUX12", "ADC2", "ADC2"},
+	{"AMIC MUX12", "ADC3", "ADC3"},
+	{"AMIC MUX12", "ADC4", "ADC4"},
+
+	{"DMIC MUX13", "DMIC0", "DMIC0"},
+	{"DMIC MUX13", "DMIC1", "DMIC1"},
+	{"DMIC MUX13", "DMIC2", "DMIC2"},
+	{"DMIC MUX13", "DMIC3", "DMIC3"},
+	{"DMIC MUX13", "DMIC4", "DMIC4"},
+	{"DMIC MUX13", "DMIC5", "DMIC5"},
+	{"AMIC MUX13", "ADC1", "ADC1"},
+	{"AMIC MUX13", "ADC2", "ADC2"},
+	{"AMIC MUX13", "ADC3", "ADC3"},
+	{"AMIC MUX13", "ADC4", "ADC4"},
+
+	{"AMIC4_5 SEL", "AMIC4", "AMIC4"},
+	{"AMIC4_5 SEL", "AMIC5", "AMIC5"},
+
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2", NULL, "AMIC2"},
+	{"ADC3", NULL, "AMIC3"},
+	{"ADC4", NULL, "AMIC4_5 SEL"},
+
+	/* CDC Rx interface with SLIMBUS */
+	{"CDC_IF RX0 MUX", "SLIM RX0", "SLIM RX0"},
+	{"CDC_IF RX1 MUX", "SLIM RX1", "SLIM RX1"},
+	{"CDC_IF RX2 MUX", "SLIM RX2", "SLIM RX2"},
+	{"CDC_IF RX3 MUX", "SLIM RX3", "SLIM RX3"},
+	{"CDC_IF RX4 MUX", "SLIM RX4", "SLIM RX4"},
+	{"CDC_IF RX5 MUX", "SLIM RX5", "SLIM RX5"},
+	{"CDC_IF RX6 MUX", "SLIM RX6", "SLIM RX6"},
+	{"CDC_IF RX7 MUX", "SLIM RX7", "SLIM RX7"},
+
+	{"RX INT0_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT0_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT0_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT0_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT0_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT0_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT0_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT0_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT0_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT0_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT0_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT0_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT0_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT0_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT0_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT0_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT0_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT0_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT0_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT0_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT0_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT0_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT0_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT0_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT1_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT1_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT1_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT1_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT1_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT1_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT1_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT1_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT1_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT1_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT1_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT1_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT1_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT1_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT1_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT1_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT1_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT1_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT1_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT1_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT1_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT1_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT1_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT1_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT2_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT2_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT2_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT2_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT2_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT2_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT2_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT2_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT2_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT2_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT2_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT2_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT2_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT2_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT2_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT2_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT2_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT2_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT2_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT2_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT2_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT2_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT3_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT3_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT3_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT3_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT3_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT3_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT3_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT3_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT3_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT3_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT3_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT3_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT3_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT3_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT3_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT3_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT3_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT3_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT3_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT3_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT3_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT3_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT3_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT3_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT3_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT3_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT3_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT3_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT3_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT3_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT4_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT4_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT4_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT4_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT4_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT4_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT4_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT4_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT4_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT4_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT4_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT4_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT4_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT4_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT4_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT4_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT4_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT4_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT4_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT4_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT4_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT4_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT4_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT4_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT4_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT4_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT4_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT4_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT4_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT4_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT7_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT7_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT7_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT7_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT7_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT7_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT7_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT7_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT7_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT7_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT7_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT7_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT7_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT7_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT7_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT7_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT7_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT7_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT7_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT7_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT7_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT7_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT7_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT7_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT7_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT7_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT7_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT7_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT7_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT7_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT8_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT8_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT8_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT8_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT8_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT8_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT8_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT8_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT8_1 MIX1 INP0", "IIR0", "IIR0"},
+	{"RX INT8_1 MIX1 INP0", "IIR1", "IIR1"},
+	{"RX INT8_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT8_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT8_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT8_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT8_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT8_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT8_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT8_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT8_1 MIX1 INP1", "IIR0", "IIR0"},
+	{"RX INT8_1 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX INT8_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT8_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT8_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT8_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT8_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT8_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT8_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT8_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT8_1 MIX1 INP2", "IIR0", "IIR0"},
+	{"RX INT8_1 MIX1 INP2", "IIR1", "IIR1"},
+
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"},
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"},
+	{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"},
+	{"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"},
+	{"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"},
+	{"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP0"},
+	{"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP1"},
+	{"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP2"},
+	{"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP0"},
+	{"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP1"},
+	{"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP2"},
+	{"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP0"},
+	{"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP1"},
+	{"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP2"},
+	{"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP0"},
+	{"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP1"},
+	{"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP2"},
+
+	/* Mixing path INT0 */
+	{"RX INT0_2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT0_2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT0_2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT0_2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT0_2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT0_2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT0_2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT0_2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT0_2 INTERP", NULL, "RX INT0_2 MUX"},
+	{"RX INT0 SEC MIX", NULL, "RX INT0_2 INTERP"},
+
+	/* Mixing path INT1 */
+	{"RX INT1_2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT1_2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT1_2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT1_2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT1_2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT1_2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT1_2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT1_2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT1_2 INTERP", NULL, "RX INT1_2 MUX"},
+	{"RX INT1 SEC MIX", NULL, "RX INT1_2 INTERP"},
+
+	/* Mixing path INT2 */
+	{"RX INT2_2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT2_2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT2_2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT2_2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT2_2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT2_2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT2_2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT2_2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT2_2 INTERP", NULL, "RX INT2_2 MUX"},
+	{"RX INT2 SEC MIX", NULL, "RX INT2_2 INTERP"},
+
+	/* Mixing path INT3 */
+	{"RX INT3_2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT3_2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT3_2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT3_2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT3_2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT3_2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT3_2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT3_2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT3_2 INTERP", NULL, "RX INT3_2 MUX"},
+	{"RX INT3 SEC MIX", NULL, "RX INT3_2 INTERP"},
+
+	/* Mixing path INT4 */
+	{"RX INT4_2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT4_2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT4_2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT4_2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT4_2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT4_2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT4_2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT4_2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT4_2 INTERP", NULL, "RX INT4_2 MUX"},
+	{"RX INT4 SEC MIX", NULL, "RX INT4_2 INTERP"},
+
+	/* Mixing path INT7 */
+	{"RX INT7_2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT7_2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT7_2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT7_2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT7_2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT7_2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT7_2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT7_2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT7_2 INTERP", NULL, "RX INT7_2 MUX"},
+	{"RX INT7 SEC MIX", NULL, "RX INT7_2 INTERP"},
+
+	/* Mixing path INT8 */
+	{"RX INT8_2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"RX INT8_2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"RX INT8_2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"RX INT8_2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"RX INT8_2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"RX INT8_2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"RX INT8_2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"RX INT8_2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"RX INT8_2 INTERP", NULL, "RX INT8_2 MUX"},
+	{"RX INT8 SEC MIX", NULL, "RX INT8_2 INTERP"},
+
+	{"RX INT0_1 INTERP", NULL, "RX INT0_1 MIX1"},
+	{"RX INT0 SEC MIX", NULL, "RX INT0_1 INTERP"},
+	{"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"},
+	{"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"},
+	{"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 MIX2"},
+	{"RX INT0 DAC", NULL, "RX INT0 DEM MUX"},
+	{"RX INT0 DAC", NULL, "RX_BIAS"},
+	{"EAR PA", NULL, "RX INT0 DAC"},
+	{"EAR", NULL, "EAR PA"},
+
+	{"RX INT1_1 INTERP", NULL, "RX INT1_1 MIX1"},
+	{"RX INT1 SEC MIX", NULL, "RX INT1_1 INTERP"},
+	{"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"},
+	{"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"},
+	{"RX INT1 MIX3", NULL, "RX INT1 MIX2"},
+	{"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 MIX3"},
+	{"RX INT1 DAC", NULL, "RX INT1 DEM MUX"},
+	{"RX INT1 DAC", NULL, "RX_BIAS"},
+	{"HPHL PA", NULL, "RX INT1 DAC"},
+	{"HPHL", NULL, "HPHL PA"},
+
+	{"RX INT2_1 INTERP", NULL, "RX INT2_1 MIX1"},
+	{"RX INT2 SEC MIX", NULL, "RX INT2_1 INTERP"},
+	{"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"},
+	{"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"},
+	{"RX INT2 MIX3", NULL, "RX INT2 MIX2"},
+	{"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 MIX3"},
+	{"RX INT2 DAC", NULL, "RX INT2 DEM MUX"},
+	{"RX INT2 DAC", NULL, "RX_BIAS"},
+	{"HPHR PA", NULL, "RX INT2 DAC"},
+	{"HPHR", NULL, "HPHR PA"},
+
+	{"RX INT3_1 INTERP", NULL, "RX INT3_1 MIX1"},
+	{"RX INT3 SEC MIX", NULL, "RX INT3_1 INTERP"},
+	{"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"},
+	{"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"},
+	{"RX INT3 MIX3", NULL, "RX INT3 MIX2"},
+	{"RX INT3 DAC", NULL, "RX INT3 MIX3"},
+	{"RX INT3 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT1 PA", NULL, "RX INT3 DAC"},
+	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+
+	{"RX INT4_1 INTERP", NULL, "RX INT4_1 MIX1"},
+	{"RX INT4 SEC MIX", NULL, "RX INT4_1 INTERP"},
+	{"RX INT4 SEC MIX", NULL, "RX INT4_1 MIX1"},
+	{"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"},
+	{"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"},
+	{"RX INT4 MIX3", NULL, "RX INT4 MIX2"},
+	{"RX INT4 DAC", NULL, "RX INT4 MIX3"},
+	{"RX INT4 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT2 PA", NULL, "RX INT4 DAC"},
+	{"LINEOUT2", NULL, "LINEOUT2 PA"},
+
+	{"RX INT7_1 INTERP", NULL, "RX INT7_1 MIX1"},
+	{"RX INT7 SEC MIX", NULL, "RX INT7_1 INTERP"},
+	{"RX INT7 MIX2", NULL, "RX INT7 SEC MIX"},
+	{"RX INT7 MIX2", NULL, "RX INT7 MIX2 INP"},
+	{"RX INT7 CHAIN", NULL, "RX INT7 MIX2"},
+	{"RX INT7 CHAIN", NULL, "RX_BIAS"},
+	{"SPK1 OUT", NULL, "RX INT7 CHAIN"},
+
+	{"RX INT8_1 INTERP", NULL, "RX INT8_1 MIX1"},
+	{"RX INT8 SEC MIX", NULL, "RX INT8_1 INTERP"},
+	{"RX INT8 SEC MIX", NULL, "RX INT8_1 MIX1"},
+	{"RX INT8 CHAIN", NULL, "RX INT8 SEC MIX"},
+	{"RX INT8 CHAIN", NULL, "RX_BIAS"},
+	{"SPK2 OUT", NULL, "RX INT8 CHAIN"},
+
+	/* ANC Routing */
+	{"ANC0 FB MUX", "ANC_IN_EAR", "RX INT0 MIX2"},
+	{"ANC0 FB MUX", "ANC_IN_HPHL", "RX INT1 MIX2"},
+	{"ANC0 FB MUX", "ANC_IN_LO1", "RX INT3 MIX2"},
+	{"ANC0 FB MUX", "ANC_IN_EAR_SPKR", "RX INT7 MIX2"},
+	{"ANC1 FB MUX", "ANC_IN_HPHR", "RX INT2 MIX2"},
+	{"ANC1 FB MUX", "ANC_IN_LO2", "RX INT4 MIX2"},
+
+	{"ANC OUT EAR Enable", "Switch", "ADC MUX10"},
+	{"ANC OUT EAR Enable", "Switch", "ADC MUX11"},
+	{"RX INT0 MIX2", NULL, "ANC OUT EAR Enable"},
+
+	{"ANC OUT HPHL Enable", "Switch", "ADC MUX10"},
+	{"ANC OUT HPHL Enable", "Switch", "ADC MUX11"},
+	{"RX INT1 MIX2", NULL, "ANC OUT HPHL Enable"},
+
+	{"ANC OUT HPHR Enable", "Switch", "ADC MUX12"},
+	{"ANC OUT HPHR Enable", "Switch", "ADC MUX13"},
+	{"RX INT2 MIX2", NULL, "ANC OUT HPHR Enable"},
+
+	{"ANC EAR PA", NULL, "RX INT0 DAC"},
+	{"ANC EAR", NULL, "ANC EAR PA"},
+
+	{"ANC HPHL PA", NULL, "RX INT1 DAC"},
+	{"ANC HPHL", NULL, "ANC HPHL PA"},
+
+	{"ANC HPHR PA", NULL, "RX INT2 DAC"},
+	{"ANC HPHR", NULL, "ANC HPHR PA"},
+
+	{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX10"},
+	{"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX11"},
+	{"RX INT7 MIX2", NULL, "ANC OUT EAR SPKR Enable"},
+
+	{"ANC SPKR PA Enable", "Switch", "RX INT7 CHAIN"},
+	{"ANC SPK1 PA", NULL, "ANC SPKR PA Enable"},
+	{"SPK1 OUT", NULL, "ANC SPK1 PA"},
+
+	/*
+	 * SRC0, SRC1 inputs to Sidetone RX Mixer
+	 * on RX0, RX1, RX2, RX3, RX4 and RX7 chains
+	 */
+	{"IIR0", NULL, "IIR0 INP0 MUX"},
+	{"IIR0 INP0 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP0 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP0 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP0 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP0 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP0 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP0 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP0 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP0 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP0 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR0 INP0 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR0 INP0 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR0 INP0 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR0 INP0 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR0 INP0 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR0 INP0 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR0 INP0 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"IIR0", NULL, "IIR0 INP1 MUX"},
+	{"IIR0 INP1 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP1 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP1 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP1 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP1 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP1 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP1 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP1 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP1 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP1 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR0 INP1 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR0 INP1 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR0 INP1 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR0 INP1 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR0 INP1 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR0 INP1 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR0 INP1 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"IIR0", NULL, "IIR0 INP2 MUX"},
+	{"IIR0 INP2 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP2 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP2 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP2 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP2 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP2 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP2 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP2 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP2 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR0 INP2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR0 INP2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR0 INP2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR0 INP2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR0 INP2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR0 INP2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR0 INP2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"IIR0", NULL, "IIR0 INP3 MUX"},
+	{"IIR0 INP3 MUX", "DEC0", "ADC MUX0"},
+	{"IIR0 INP3 MUX", "DEC1", "ADC MUX1"},
+	{"IIR0 INP3 MUX", "DEC2", "ADC MUX2"},
+	{"IIR0 INP3 MUX", "DEC3", "ADC MUX3"},
+	{"IIR0 INP3 MUX", "DEC4", "ADC MUX4"},
+	{"IIR0 INP3 MUX", "DEC5", "ADC MUX5"},
+	{"IIR0 INP3 MUX", "DEC6", "ADC MUX6"},
+	{"IIR0 INP3 MUX", "DEC7", "ADC MUX7"},
+	{"IIR0 INP3 MUX", "DEC8", "ADC MUX8"},
+	{"IIR0 INP3 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR0 INP3 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR0 INP3 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR0 INP3 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR0 INP3 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR0 INP3 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR0 INP3 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR0 INP3 MUX", "RX7", "CDC_IF RX7 MUX"},
+
+	{"IIR1", NULL, "IIR1 INP0 MUX"},
+	{"IIR1 INP0 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP0 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP0 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP0 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP0 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP0 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP0 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP0 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP0 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP0 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR1 INP0 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR1 INP0 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR1 INP0 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR1 INP0 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR1 INP0 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR1 INP0 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR1 INP0 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"IIR1", NULL, "IIR1 INP1 MUX"},
+	{"IIR1 INP1 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP1 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP1 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP1 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP1 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP1 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP1 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP1 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP1 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP1 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR1 INP1 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR1 INP1 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR1 INP1 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR1 INP1 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR1 INP1 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR1 INP1 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR1 INP1 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"IIR1", NULL, "IIR1 INP2 MUX"},
+	{"IIR1 INP2 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP2 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP2 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP2 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP2 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP2 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP2 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP2 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP2 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP2 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR1 INP2 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR1 INP2 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR1 INP2 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR1 INP2 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR1 INP2 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR1 INP2 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR1 INP2 MUX", "RX7", "CDC_IF RX7 MUX"},
+	{"IIR1", NULL, "IIR1 INP3 MUX"},
+	{"IIR1 INP3 MUX", "DEC0", "ADC MUX0"},
+	{"IIR1 INP3 MUX", "DEC1", "ADC MUX1"},
+	{"IIR1 INP3 MUX", "DEC2", "ADC MUX2"},
+	{"IIR1 INP3 MUX", "DEC3", "ADC MUX3"},
+	{"IIR1 INP3 MUX", "DEC4", "ADC MUX4"},
+	{"IIR1 INP3 MUX", "DEC5", "ADC MUX5"},
+	{"IIR1 INP3 MUX", "DEC6", "ADC MUX6"},
+	{"IIR1 INP3 MUX", "DEC7", "ADC MUX7"},
+	{"IIR1 INP3 MUX", "DEC8", "ADC MUX8"},
+	{"IIR1 INP3 MUX", "RX0", "CDC_IF RX0 MUX"},
+	{"IIR1 INP3 MUX", "RX1", "CDC_IF RX1 MUX"},
+	{"IIR1 INP3 MUX", "RX2", "CDC_IF RX2 MUX"},
+	{"IIR1 INP3 MUX", "RX3", "CDC_IF RX3 MUX"},
+	{"IIR1 INP3 MUX", "RX4", "CDC_IF RX4 MUX"},
+	{"IIR1 INP3 MUX", "RX5", "CDC_IF RX5 MUX"},
+	{"IIR1 INP3 MUX", "RX6", "CDC_IF RX6 MUX"},
+	{"IIR1 INP3 MUX", "RX7", "CDC_IF RX7 MUX"},
+
+	{"SRC0", NULL, "IIR0"},
+	{"SRC1", NULL, "IIR1"},
+	{"RX INT0 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT0 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT1 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT1 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT2 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT2 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT3 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT3 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT4 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT4 MIX2 INP", "SRC1", "SRC1"},
+	{"RX INT7 MIX2 INP", "SRC0", "SRC0"},
+	{"RX INT7 MIX2 INP", "SRC1", "SRC1"},
+
+	/* Native clk main path routing */
+	{"RX INT1_1 NATIVE MUX", "ON", "RX INT1_1 MIX1"},
+	{"RX INT1_1 INTERP", NULL, "RX INT1_1 NATIVE MUX"},
+	{"RX INT1_1 NATIVE MUX", NULL, "RX INT1 NATIVE SUPPLY"},
+
+	{"RX INT2_1 NATIVE MUX", "ON", "RX INT2_1 MIX1"},
+	{"RX INT2_1 INTERP", NULL, "RX INT2_1 NATIVE MUX"},
+	{"RX INT2_1 NATIVE MUX", NULL, "RX INT2 NATIVE SUPPLY"},
+
+	{"RX INT3_1 NATIVE MUX", "ON", "RX INT3_1 MIX1"},
+	{"RX INT3_1 INTERP", NULL, "RX INT3_1 NATIVE MUX"},
+	{"RX INT3_1 NATIVE MUX", NULL, "RX INT3 NATIVE SUPPLY"},
+
+	{"RX INT4_1 NATIVE MUX", "ON", "RX INT4_1 MIX1"},
+	{"RX INT4_1 INTERP", NULL, "RX INT4_1 NATIVE MUX"},
+	{"RX INT4_1 NATIVE MUX", NULL, "RX INT4 NATIVE SUPPLY"},
+
+	/* Native clk mix path routing */
+	{"RX INT1_2 NATIVE MUX", "ON", "RX INT1_2 MUX"},
+	{"RX INT1_2 INTERP", NULL, "RX INT1_2 NATIVE MUX"},
+	{"RX INT1_2 NATIVE MUX", NULL, "RX INT1 NATIVE SUPPLY"},
+
+	{"RX INT2_2 NATIVE MUX", "ON", "RX INT2_2 MUX"},
+	{"RX INT2_2 INTERP", NULL, "RX INT2_2 NATIVE MUX"},
+	{"RX INT2_2 NATIVE MUX", NULL, "RX INT2 NATIVE SUPPLY"},
+
+	{"RX INT3_2 NATIVE MUX", "ON", "RX INT3_2 MUX"},
+	{"RX INT3_2 INTERP", NULL, "RX INT3_2 NATIVE MUX"},
+	{"RX INT3_2 NATIVE MUX", NULL, "RX INT3 NATIVE SUPPLY"},
+
+	{"RX INT4_2 NATIVE MUX", "ON", "RX INT4_2 MUX"},
+	{"RX INT4_2 INTERP", NULL, "RX INT4_2 NATIVE MUX"},
+	{"RX INT4_2 NATIVE MUX", NULL, "RX INT4 NATIVE SUPPLY"},
+
+	{"RX INT7_2 NATIVE MUX", "ON", "RX INT7_2 MUX"},
+	{"RX INT7_2 INTERP", NULL, "RX INT7_2 NATIVE MUX"},
+	{"RX INT7_2 NATIVE MUX", NULL, "RX INT7 NATIVE SUPPLY"},
+
+	{"RX INT8_2 NATIVE MUX", "ON", "RX INT8_2 MUX"},
+	{"RX INT8_2 INTERP", NULL, "RX INT8_2 NATIVE MUX"},
+	{"RX INT8_2 NATIVE MUX", NULL, "RX INT8 NATIVE SUPPLY"},
+
+	/* ASRC Routing */
+	{"ASRC0 MUX", "ASRC_IN_HPHL", "RX INT1_2 INTERP"},
+	{"RX INT1 SEC MIX", "HPHL Switch", "ASRC0 MUX"},
+
+	{"ASRC1 MUX", "ASRC_IN_HPHR", "RX INT2_2 INTERP"},
+	{"RX INT2 SEC MIX", "HPHR Switch", "ASRC1 MUX"},
+
+	{"ASRC0 MUX", "ASRC_IN_LO1", "RX INT3_2 INTERP"},
+	{"RX INT3 SEC MIX", "LO1 Switch", "ASRC0 MUX"},
+
+	{"ASRC1 MUX", "ASRC_IN_LO2", "RX INT4_2 INTERP"},
+	{"RX INT4 SEC MIX", "LO2 Switch", "ASRC1 MUX"},
+
+	{"ASRC2 MUX", "ASRC_IN_SPKR1", "RX INT7_2 INTERP"},
+	{"RX INT7 SEC MIX", NULL, "ASRC2 MUX"},
+
+	{"ASRC3 MUX", "ASRC_IN_SPKR2", "RX INT8_2 INTERP"},
+	{"RX INT8 SEC MIX", NULL, "ASRC3 MUX"},
+};
+
+#endif
diff --git a/asoc/codecs/wcd934x/wcd934x-tables.c b/asoc/codecs/wcd934x/wcd934x-tables.c
new file mode 100644
index 0000000..4e6c2fb
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x-tables.c
@@ -0,0 +1,2155 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <asoc/wcd934x_registers.h>
+
+#define WCD934X_REG(reg)  ((reg) & 0xFF)
+
+const u8 wcd934x_page0_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE0_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_RPM_CLK_BYPASS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_RPM_CLK_GATE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_RPM_CLK_MCLK_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_RPM_CLK_MCLK2_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_RPM_I2S_DSD_CLK_SEL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_RPM_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_TEST0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_TEST1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT4)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT5)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT6)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT7)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT8)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT10)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT11)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT12)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT13)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO)] =
+								WCD934X_READ,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_SLNQ_WAIT_STATE_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_ACTIVE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX0_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX1_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX2_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX3_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX4_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX5_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX6_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_RX7_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX0_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX1_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX2_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX3_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX4_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX5_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX6_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX7_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX8_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX9_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX10_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX11_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX13_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX14_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_SB_TX15_INP_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_TX0_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_TX1_0_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_TX1_1_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_0_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_1_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_2_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_3_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_CLKSRC_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_COMMON_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_0_TDM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DATA_HUB_I2S_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_DMA_RDMA_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_RDMA_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_RDMA_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_RDMA_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_RDMA_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_RDMA4_PRT_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_RDMA_SBTX0_7_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_RDMA_SBTX8_11_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA0_PRT_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA3_PRT_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA4_PRT0_3_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DMA_WDMA4_PRT4_7_CFG)] = WCD934X_READ_WRITE,
+};
+
+const u8 wcd934x_page1_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE1_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_9)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_FLL_MODE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_FLL_STATUS_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CPE_FLL_STATUS_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CPE_FLL_STATUS_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CPE_FLL_STATUS_3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_9)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_FLL_MODE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_I2S_FLL_STATUS_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_I2S_FLL_STATUS_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_I2S_FLL_STATUS_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_I2S_FLL_STATUS_3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_USER_CTL_9)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_FLL_MODE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SB_FLL_STATUS_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SB_FLL_STATUS_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SB_FLL_STATUS_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SB_FLL_STATUS_3)] = WCD934X_READ,
+};
+
+const u8 wcd934x_page2_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE2_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_CPE_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPEFLL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_US_BUF_INT_PERIOD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SVA_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_US_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_MAD_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_CPAR_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_DMIC0_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_DMIC1_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_DMIC2_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_DMIC_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_CPAR_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_WDOG_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_BACKUP_INT)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_STATUS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_CPE_OCD_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1A)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1B)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_MAIN_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_MAIN_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SOC_MAD_INP_SEL)] = WCD934X_READ_WRITE,
+};
+
+const u8 wcd934x_page4_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE4_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CLR_COMMIT)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_MASK0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_MASK1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_MASK2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_MASK3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_STATUS0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_PIN1_STATUS1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_PIN1_STATUS2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_PIN1_STATUS3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_PIN1_CLEAR0)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_CLEAR1)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_CLEAR2)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN1_CLEAR3)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN2_MASK3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_PIN2_STATUS3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_PIN2_CLEAR3)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_MASK2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_MASK3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_STATUS2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_STATUS3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_CLEAR2)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_CLEAR3)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_INTR_LEVEL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_LEVEL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_LEVEL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_LEVEL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_BYPASS0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_BYPASS1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_BYPASS2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_BYPASS3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_SET0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_SET1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_SET2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_SET3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CODEC_MISC_MASK)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_INTR_CODEC_MISC_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_INTR_CODEC_MISC_CLEAR)] = WCD934X_WRITE,
+};
+
+const u8 wcd934x_page5_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE5_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_DEVICE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_REVISION)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_H_COMMAND)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_MASTER_ADDRESS_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_MASTER_ADDRESS_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SLAVE_ADDRESS_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SLAVE_ADDRESS_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_MSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_LSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_MSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_LSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_MSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_LSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_COMM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_FRAME_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH1_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH3_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SW_EVENT_RD)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SW_EVENT_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SAMPLING_FREQ)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_SEL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_RAM_CNTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BANK)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_9)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_A)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_B)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_C)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_D)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_E)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_F)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_10)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_11)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_12)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_13)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_14)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_15)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_16)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_17)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_18)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_19)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1A)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1B)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1C)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1D)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1E)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1F)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_20)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_21)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_22)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_23)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_24)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_25)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_26)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_27)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_28)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_29)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2A)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2B)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2C)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2D)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2E)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2F)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_30)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_31)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_32)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_33)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_34)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_35)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_36)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_37)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_38)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_39)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3A)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3B)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3C)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3D)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3E)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3F)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TOP_CTRL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_TOP_CTRL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_PDM_MUTE_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_STATUS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_FS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_IN_SEL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_GPOUT_ENABLE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_GPOUT_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_MASK)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_CLR)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_IP_TESTING)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS4)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR0)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR1)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR2)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR3)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR4)] = WCD934X_WRITE,
+};
+
+const u8 wcd934x_page6_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_ANA_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_BIAS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_RCO)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_PAGE6_SPARE2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_PAGE6_SPARE3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_BUCK_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_BUCK_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_ANA_RX_SUPPLIES)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_HPH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_EAR)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_LO_1_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MAD_SETUP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_AMIC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_AMIC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_AMIC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_AMIC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_MECH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_ELECT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_ZDET)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_RESULT_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_ANA_MBHC_RESULT_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_ANA_MBHC_RESULT_3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MBHC_BTN7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MICB1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MICB2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MICB2_RAMP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MICB3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_MICB4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_ANA_VBADC)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BIAS_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BIAS_VBG_FINE_ADJ)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RCO_CTRL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RCO_CTRL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RCO_CAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RCO_CAL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RCO_CAL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RCO_TEST_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RCO_CAL_OUT_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_RCO_CAL_OUT_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_RCO_CAL_OUT_3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_RCO_CAL_OUT_4)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_RCO_CAL_OUT_5)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDO_MODE_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_MODE_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_MODE_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_MODE_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_VCL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_VCL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_VCL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_9)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CCL_10)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_FILTER_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_FILTER_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_DRIVER_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_DRIVER_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_DRIVER_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CAL_CODE_EXT_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CAL_CODE_EXT_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_CAL_CODE_OUT_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDO_CAL_CODE_OUT_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDO_TEST_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_TEST_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_CTL_CLK)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_CTL_ANA)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_CTL_SPARE_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_CTL_SPARE_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_CTL_BCS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_STATUS_SPARE_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MBHC_TEST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_SUBBLOCK_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_IBIAS_FE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_BIAS_ADC)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_FE_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_ADC_REF)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_ADC_IO)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_ADC_SAR)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_DEBUG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_LDOH_MODE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_LDOH_BIAS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_LDOH_STB_LOADS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_LDOH_SLOWRAMP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB1_TEST_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB1_TEST_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB1_TEST_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB2_TEST_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB2_TEST_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB2_TEST_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB3_TEST_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB3_TEST_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB3_TEST_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB4_TEST_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB4_TEST_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MICB4_TEST_CTL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_ADC_VCM)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_BIAS_ATEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_ADC_INT1_IB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_ADC_INT2_IB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_START)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_STOP_9P6M)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_STOP_12P288M)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_1_2_TEST_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_1_2_ADC_IB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_1_2_ATEST_REFCTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_1_2_TEST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_1_2_TEST_BLK_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_1_2_TXFE_CLKDIV)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_1_2_SAR1_ERR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_TX_1_2_SAR2_ERR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_TX_3_4_TEST_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_3_4_ADC_IB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_3_4_ATEST_REFCTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_3_4_TEST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_3_4_TEST_BLK_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_3_4_TXFE_CLKDIV)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TX_3_4_SAR1_ERR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_TX_3_4_SAR2_ERR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CLASSH_MODE_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_MODE_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_MODE_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_CTRL_VCL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_CTRL_VCL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_BUCK_TMUX_A_D)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_BUCK_SW_DRV_CNTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLASSH_SPARE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_8)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_9)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_CTRL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_FLYBACK_TEST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_AUX_SW_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_PA_AUX_IN_CONN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_TIMER_DIV)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_OCP_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_OCP_COUNT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_EAR_DAC)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_EAR_AMP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_HPH_LDO)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_HPH_PA)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_HPH_RDACBUFF_CNP2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_HPH_RDAC_LDO)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_HPH_CNP1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_HPH_LOWPOWER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_PA)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_REF)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_LDO)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_SELO_DAC_PA)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_BUCK_RST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_BUCK_VREF_ERRAMP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_FLYB_ERRAMP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_FLYB_BUFF)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_BIAS_FLYB_MID_RST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_L_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_HPH_R_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_HPH_CNP_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_CNP_WG_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_CNP_WG_TIME)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_OCP_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_AUTO_CHOP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_CHOP_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_PA_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_PA_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_L_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_L_TEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_L_ATEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_R_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_R_TEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_R_ATEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_RDAC_CLK_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_RDAC_CLK_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_RDAC_LDO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_REFBUFF_UHQA_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_REFBUFF_LP_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_L_DAC_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_R_DAC_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EAR_EN_REG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EAR_CMBUFF)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EAR_ICTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EAR_EN_DBG_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EAR_CNP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EAR_DAC_CTL_ATEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EAR_STATUS_REG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EAR_EAR_MISC)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_MISC)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_LO2_COMPANDER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_LO1_COMPANDER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_COMMON)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_BYPASS_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_CNP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_CORE_OUT_PROG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_LDO_OUT_PROG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_COM_SWCAP_REFBUF_FREQ)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_COM_PA_FREQ)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_RESERVED_REG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_DIFF_LO_LO1_STATUS_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_DIFF_LO_LO1_STATUS_2)] = WCD934X_READ,
+};
+
+const u8 wcd934x_page7_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_ANA_NEW_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_ANA_HPH2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_ANA_HPH3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_EN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_LDO_CONFIG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_LDO_OCP_CONFIG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_TX_LDO_CONFIG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_TX_DRV_CONFIG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_RX_CONFIG_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_RX_CONFIG_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_PLL_ENABLES)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_PLL_PRESET)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_ANA_PLL_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CLK_SYS_PLL_ENABLES)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_PLL_PRESET)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_PLL_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CLK_SYS_MCLK_PRG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_MCLK2_PRG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_MCLK2_PRG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_XO_PRG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_XO_CAP_XTP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_XO_CAP_XTM)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_BST_EN_DLY)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_CTRL_ILIM)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_VOUT_SETTING)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_VOUT_A_STARTUP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_STARTUP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_FREQ1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_FREQ2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_ELECT_REM_CLAMP_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_CTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_CTL_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_PLUG_DETECT_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_ZDET_ANA_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_ZDET_RAMP_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_FSM_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MBHC_NEW_ADC_RESULT)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_TX_NEW_AMIC_4_5_SEL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_NEW_ADC_MODE)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_VBADC_NEW_ADC_DOUTMSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_VBADC_NEW_ADC_DOUTLSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_HD2_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_VREF_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_MISC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_PA_MISC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_PA_MISC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_LDO_LP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_TEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_TX_LDO_TEST)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_TX_DRV_TEST)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_TEST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_TEST_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_CLK_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RESERVED_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RESERVED_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_L_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_M_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_N_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_PFD_CP_DSM_PROG)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_VCO_PROG)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_LDO_LOCK_CFG)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_DIG_LOCK_DET_CFG)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_POST_DIV_REG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_POST_DIV_REG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_REF_DIV_REG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_REF_DIV_REG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_FILTER_REG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_FILTER_REG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_L_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_M_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_N_VAL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_TEST_REG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_VCO_PROG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_TEST_REG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_LDO_LOCK_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_XO_TEST1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CLK_SYS_INT_XO_TEST2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_VCOMP_HYST)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_VLOOP_FILTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_CTRL_IDELTA)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_CTRL_ILIM_STARTUP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_CTRL_MIN_ONTIME)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_CTRL_MAX_ONTIME)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_CTRL_TIMING)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_TMUX_A_D)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_SW_DRV_CNTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_SPARE1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_BOOST_INT_SPARE2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_SPARE_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_A)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_D)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_INC_WAIT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_IBLEED_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_CPROVR_TEST)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_CTL_A)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_CTL_D)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_TIMEOUT_PERIOD)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_HPF)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_REF)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_COMP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MBHC_NEW_INT_SPARE_2)] = WCD934X_READ_WRITE,
+
+};
+
+const u8 wcd934x_page10_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE10_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_CLK_RESET_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_MODE_1_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_MODE_2_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_FF_SHIFT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_FB_SHIFT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_LPF_FF_A_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_LPF_FF_B_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_LPF_FB_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_SMLPF_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_DCFLT_SHIFT_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_IIR_ADAPT_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_IIR_COEFF_1_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_IIR_COEFF_2_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_FF_A_GAIN_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_FF_B_GAIN_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_FB_GAIN_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_RC_COMMON_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_FIFO_COMMON_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC0_RC0_STATUS_FMIN_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC0_RC1_STATUS_FMIN_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC0_RC0_STATUS_FMAX_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC0_RC1_STATUS_FMAX_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC0_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC1_CLK_RESET_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_MODE_1_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_MODE_2_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_FF_SHIFT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_FB_SHIFT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_LPF_FF_A_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_LPF_FF_B_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_LPF_FB_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_SMLPF_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_DCFLT_SHIFT_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_IIR_ADAPT_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_IIR_COEFF_1_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_IIR_COEFF_2_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_FF_A_GAIN_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_FF_B_GAIN_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_FB_GAIN_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_RC_COMMON_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_FIFO_COMMON_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_ANC1_RC0_STATUS_FMIN_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC1_RC1_STATUS_FMIN_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC1_RC0_STATUS_FMAX_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC1_RC1_STATUS_FMAX_CNTR)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_ANC1_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_192_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_192_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0)] =
+							WCD934X_READ_WRITE,
+};
+
+const u8 wcd934x_page11_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE11_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL6)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL6)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL6)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL6)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL6)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL6)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_VOL_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC6)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE,
+};
+
+const u8 wcd934x_page12_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE12_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_CRC)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_DLY_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_DECAY_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_HPH_V_PA)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_EAR_V_PA)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_HPH_V_HD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_EAR_V_HD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_K1_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_K1_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_K2_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_K2_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_IDLE_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_IDLE_HPH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_IDLE_EAR)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_TEST0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_TEST1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLSH_OVR_VREF)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_RF_PROC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_RF_PROC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_DEBUG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD_MON)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_MON_VAL)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_VBAT_VBAT_BAN)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_ACCESS_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_LSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_MSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_LSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_MSB)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_REF_HQ0_EC_REF_HQ_PATH_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_REF_HQ0_EC_REF_HQ_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_REF_HQ1_EC_REF_HQ_PATH_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_REF_HQ1_EC_REF_HQ_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC0_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC0_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FIFO)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC1_CTL0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC1_CTL1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FIFO)] = WCD934X_READ,
+};
+
+const u8 wcd934x_page13_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE13_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_ANC_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_INP_MUX_EC_REF_HQ_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_CTRL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD)] =
+							WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG7)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_WR_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_WR_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_LUT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_RD_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_RD_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_WR_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_WR_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_LUT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_RD_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_RD_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_WR_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_WR_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_LUT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_RD_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_RD_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_WR_LSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_WR_MSB)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_LUT)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_RD_LSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_RD_MSB)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_DSD0_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD0_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD0_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD0_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD0_CFG3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD0_CFG4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD0_CFG5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD1_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD1_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD1_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD1_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD1_CFG3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD1_CFG4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DSD1_CFG5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_PATH_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG3)] = WCD934X_READ_WRITE,
+};
+
+const u8 wcd934x_page14_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE14_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_CLK_RST_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_PULSE_SUPR_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_TIMER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_BW_SW)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_THRESH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_TIMER2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RMAX_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RMIN_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_PH_DET)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_CLR)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_MB_SW_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_MAST_DIAG_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_7_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_15_8)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_23_16)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_31_24)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_39_32)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_40_43)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_CLK_RST_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_PULSE_SUPR_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_TIMER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_BW_SW)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_THRESH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_TIMER2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RMAX_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RMIN_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_PH_DET)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_CLR)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_MB_SW_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_MAST_DIAG_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_7_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_15_8)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_23_16)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_31_24)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_39_32)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_40_43)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_CLK_RST_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_PULSE_SUPR_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_TIMER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_BW_SW)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_THRESH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_TIMER2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RMAX_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RMIN_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_PH_DET)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_CLR)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_MB_SW_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_MAST_DIAG_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_7_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_15_8)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_23_16)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_31_24)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_39_32)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_40_43)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_CLK_RST_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_PULSE_SUPR_CTL)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_TIMER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_BW_SW)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_THRESH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_TIMER2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW5)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RMAX_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RMIN_DIAG)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_PH_DET)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_CLR)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_MB_SW_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_MAST_DIAG_STATE)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_7_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_15_8)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_23_16)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_31_24)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_39_32)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_40_43)] = WCD934X_READ,
+};
+
+const u8 wcd934x_page15_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE15_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SPLINE_SRC0_CLK_RST_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SPLINE_SRC0_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SPLINE_SRC1_CLK_RST_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SPLINE_SRC1_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SPLINE_SRC2_CLK_RST_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SPLINE_SRC2_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_SPLINE_SRC3_CLK_RST_CTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_SPLINE_SRC3_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_ANC0_RC0_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_ANC0_RC1_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_ANC1_RC0_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_ANC1_RC1_FIFO_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CDC_DEBUG_ANC_RC_RST_DBG_CNTR)] =
+							WCD934X_READ_WRITE,
+};
+
+const u8 wcd934x_page_0x50_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE80_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_NOM_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS2_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_NOM_MX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS_MX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_MAX_SVS2_STEP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_START)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_CPR_STATUS)] = WCD934X_READ_WRITE,
+};
+
+const u8 wcd934x_page_0x80_reg_access[WCD934X_PAGE_SIZE] = {
+	[WCD934X_REG(WCD934X_PAGE80_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_0)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_1)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_2)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_3)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_CFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_NOM_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS2_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_NOM_MX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS_MX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_MAX_SVS2_STEP)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_CTL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_START)] = WCD934X_WRITE,
+	[WCD934X_REG(WCD934X_CODEC_CPR_CPR_STATUS)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_PAGE128_PAGE_REGISTER)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_BIST_MODE_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_RF_PA_ON_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_INTR1_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_INTR2_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SWR_DATA_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SWR_CLK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_2_SCK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SLIMBUS_DATA1_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SLIMBUS_DATA2_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SLIMBUS_CLK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2C_CLK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2C_DATA_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_0_RX_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_0_TX_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_0_SCK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_0_WS_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_1_RX_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_1_TX_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_1_SCK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_1_WS_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_DMIC1_CLK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_DMIC1_DATA_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_DMIC2_CLK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_DMIC2_DATA_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_DMIC3_CLK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_DMIC3_DATA_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_JTCK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_GPIO1_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_GPIO2_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_GPIO3_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_GPIO4_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SPI_S_CSN_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SPI_S_CLK_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SPI_S_DOUT_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_SPI_S_DIN_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_BA_N_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_GPIO0_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_2_RX_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TLMM_I2S_2_WS_PINCFG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PAD_DRVCTL_0)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PAD_DRVCTL_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PIN_STATUS)] = WCD934X_READ,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_NPL_DLY_TEST_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_NPL_DLY_TEST_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_MEM_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_BUS_SEL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_JTAG)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_1)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_2)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_3)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_4)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_5)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_ANA_DTEST_DIR)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_0)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_1)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_2)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_3)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_4)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_SYSMEM_CTRL)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_SOC_SW_PWR_SEQ_DELAY)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_NOM_LOW)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_NOM_HIGH)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH)] =
+							WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_SPI_SLAVE_CHAR)] = WCD934X_READ_WRITE,
+	[WCD934X_REG(WCD934X_TEST_DEBUG_CODEC_DIAGS)] = WCD934X_READ,
+};
+
+const u8 * const wcd934x_reg[WCD934X_NUM_PAGES] = {
+	[WCD934X_PAGE_0] = wcd934x_page0_reg_access,
+	[WCD934X_PAGE_1] = wcd934x_page1_reg_access,
+	[WCD934X_PAGE_2] = wcd934x_page2_reg_access,
+	[WCD934X_PAGE_4] = wcd934x_page4_reg_access,
+	[WCD934X_PAGE_5] = wcd934x_page5_reg_access,
+	[WCD934X_PAGE_6] = wcd934x_page6_reg_access,
+	[WCD934X_PAGE_7] = wcd934x_page7_reg_access,
+	[WCD934X_PAGE_10] = wcd934x_page10_reg_access,
+	[WCD934X_PAGE_11] = wcd934x_page11_reg_access,
+	[WCD934X_PAGE_12] = wcd934x_page12_reg_access,
+	[WCD934X_PAGE_13] = wcd934x_page13_reg_access,
+	[WCD934X_PAGE_14] = wcd934x_page14_reg_access,
+	[WCD934X_PAGE_15] = wcd934x_page15_reg_access,
+	[WCD934X_PAGE_0x50] = wcd934x_page_0x50_reg_access,
+	[WCD934X_PAGE_0X80] = wcd934x_page_0x80_reg_access,
+};
diff --git a/asoc/codecs/wcd934x/wcd934x.c b/asoc/codecs/wcd934x/wcd934x.c
new file mode 100644
index 0000000..1997e04
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x.c
@@ -0,0 +1,10125 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <soc/swr-wcd.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/info.h>
+#include <asoc/wcd934x_registers.h>
+#include "wcd934x.h"
+#include "wcd934x-mbhc.h"
+#include "wcd934x-routing.h"
+#include "wcd934x-dsp-cntl.h"
+#include "wcd934x_irq.h"
+#include "../core.h"
+#include "../pdata.h"
+#include "../wcd9xxx-irq.h"
+#include "../wcd9xxx-common-v2.h"
+#include "../wcd9xxx-resmgr-v2.h"
+#include "../wcdcal-hwdep.h"
+#include "wcd934x-dsd.h"
+
+#define WCD934X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			    SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+			    SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+			    SNDRV_PCM_RATE_384000)
+/* Fractional Rates */
+#define WCD934X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+				 SNDRV_PCM_RATE_176400)
+
+#define WCD934X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+				    SNDRV_PCM_FMTBIT_S24_LE)
+
+#define WCD934X_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+					SNDRV_PCM_FMTBIT_S24_LE | \
+					SNDRV_PCM_FMTBIT_S32_LE)
+
+#define WCD934X_FORMATS_S16_LE (SNDRV_PCM_FMTBIT_S16_LE)
+
+/* Macros for packing register writes into a U32 */
+#define WCD934X_PACKED_REG_SIZE sizeof(u32)
+#define WCD934X_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+	do { \
+		((reg) = ((packed >> 16) & (0xffff))); \
+		((mask) = ((packed >> 8) & (0xff))); \
+		((val) = ((packed) & (0xff))); \
+	} while (0)
+
+#define STRING(name) #name
+#define WCD_DAPM_ENUM(name, reg, offset, text) \
+static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \
+static const struct snd_kcontrol_new name##_mux = \
+		SOC_DAPM_ENUM(STRING(name), name##_enum)
+
+#define WCD_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \
+static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \
+static const struct snd_kcontrol_new name##_mux = \
+		SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname)
+
+#define WCD_DAPM_MUX(name, shift, kctl) \
+		SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux)
+
+/*
+ * Timeout in milli seconds and it is the wait time for
+ * slim channel removal interrupt to receive.
+ */
+#define WCD934X_SLIM_CLOSE_TIMEOUT 1000
+#define WCD934X_SLIM_IRQ_OVERFLOW (1 << 0)
+#define WCD934X_SLIM_IRQ_UNDERFLOW (1 << 1)
+#define WCD934X_SLIM_IRQ_PORT_CLOSED (1 << 2)
+#define WCD934X_MCLK_CLK_12P288MHZ 12288000
+#define WCD934X_MCLK_CLK_9P6MHZ 9600000
+
+#define WCD934X_INTERP_MUX_NUM_INPUTS 3
+#define WCD934X_NUM_INTERPOLATORS 9
+#define WCD934X_NUM_DECIMATORS 9
+#define WCD934X_RX_PATH_CTL_OFFSET 20
+
+#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE))
+
+#define WCD934X_REG_BITS 8
+#define WCD934X_MAX_VALID_ADC_MUX  13
+#define WCD934X_INVALID_ADC_MUX 9
+
+#define WCD934X_AMIC_PWR_LEVEL_LP 0
+#define WCD934X_AMIC_PWR_LEVEL_DEFAULT 1
+#define WCD934X_AMIC_PWR_LEVEL_HP 2
+#define WCD934X_AMIC_PWR_LVL_MASK 0x60
+#define WCD934X_AMIC_PWR_LVL_SHIFT 0x5
+
+#define WCD934X_DEC_PWR_LVL_MASK 0x06
+#define WCD934X_DEC_PWR_LVL_LP 0x02
+#define WCD934X_DEC_PWR_LVL_HP 0x04
+#define WCD934X_DEC_PWR_LVL_DF 0x00
+#define WCD934X_STRING_LEN 100
+
+#define WCD934X_CDC_SIDETONE_IIR_COEFF_MAX 5
+#define WCD934X_DIG_CORE_REG_MIN  WCD934X_CDC_ANC0_CLK_RESET_CTL
+#define WCD934X_DIG_CORE_REG_MAX  0xFFF
+
+#define WCD934X_MAX_MICBIAS 4
+#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone"
+#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone"
+#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone"
+#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone"
+
+#define  TX_HPF_CUT_OFF_FREQ_MASK	0x60
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
+
+#define CPE_ERR_WDOG_BITE BIT(0)
+#define CPE_FATAL_IRQS CPE_ERR_WDOG_BITE
+
+#define WCD934X_MAD_AUDIO_FIRMWARE_PATH "wcd934x/wcd934x_mad_audio.bin"
+
+#define TAVIL_VERSION_ENTRY_SIZE 17
+
+#define WCD934X_DIG_CORE_COLLAPSE_TIMER_MS  (5 * 1000)
+
+enum {
+	POWER_COLLAPSE,
+	POWER_RESUME,
+};
+
+static int dig_core_collapse_enable = 1;
+module_param(dig_core_collapse_enable, int, 0664);
+MODULE_PARM_DESC(dig_core_collapse_enable, "enable/disable power gating");
+
+/* dig_core_collapse timer in seconds */
+static int dig_core_collapse_timer = (WCD934X_DIG_CORE_COLLAPSE_TIMER_MS/1000);
+module_param(dig_core_collapse_timer, int, 0664);
+MODULE_PARM_DESC(dig_core_collapse_timer, "timer for power gating");
+
+#define TAVIL_HPH_REG_RANGE_1  (WCD934X_HPH_R_DAC_CTL - WCD934X_HPH_CNP_EN + 1)
+#define TAVIL_HPH_REG_RANGE_2  (WCD934X_HPH_NEW_ANA_HPH3 -\
+				WCD934X_HPH_NEW_ANA_HPH2 + 1)
+#define TAVIL_HPH_REG_RANGE_3  (WCD934X_HPH_NEW_INT_PA_RDAC_MISC3 -\
+				WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL + 1)
+#define TAVIL_HPH_TOTAL_REG    (TAVIL_HPH_REG_RANGE_1 + TAVIL_HPH_REG_RANGE_2 +\
+				TAVIL_HPH_REG_RANGE_3)
+
+enum {
+	VI_SENSE_1,
+	VI_SENSE_2,
+	AUDIO_NOMINAL,
+	HPH_PA_DELAY,
+	CLSH_Z_CONFIG,
+	ANC_MIC_AMIC1,
+	ANC_MIC_AMIC2,
+	ANC_MIC_AMIC3,
+	ANC_MIC_AMIC4,
+	CLK_INTERNAL,
+	CLK_MODE,
+};
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	AIF2_PB,
+	AIF2_CAP,
+	AIF3_PB,
+	AIF3_CAP,
+	AIF4_PB,
+	AIF4_VIFEED,
+	AIF4_MAD_TX,
+	NUM_CODEC_DAIS,
+};
+
+enum {
+	INTn_1_INP_SEL_ZERO = 0,
+	INTn_1_INP_SEL_DEC0,
+	INTn_1_INP_SEL_DEC1,
+	INTn_1_INP_SEL_IIR0,
+	INTn_1_INP_SEL_IIR1,
+	INTn_1_INP_SEL_RX0,
+	INTn_1_INP_SEL_RX1,
+	INTn_1_INP_SEL_RX2,
+	INTn_1_INP_SEL_RX3,
+	INTn_1_INP_SEL_RX4,
+	INTn_1_INP_SEL_RX5,
+	INTn_1_INP_SEL_RX6,
+	INTn_1_INP_SEL_RX7,
+};
+
+enum {
+	INTn_2_INP_SEL_ZERO = 0,
+	INTn_2_INP_SEL_RX0,
+	INTn_2_INP_SEL_RX1,
+	INTn_2_INP_SEL_RX2,
+	INTn_2_INP_SEL_RX3,
+	INTn_2_INP_SEL_RX4,
+	INTn_2_INP_SEL_RX5,
+	INTn_2_INP_SEL_RX6,
+	INTn_2_INP_SEL_RX7,
+	INTn_2_INP_SEL_PROXIMITY,
+};
+
+enum {
+	INTERP_MAIN_PATH,
+	INTERP_MIX_PATH,
+};
+
+struct tavil_idle_detect_config {
+	u8 hph_idle_thr;
+	u8 hph_idle_detect_en;
+};
+
+struct tavil_cpr_reg_defaults {
+	int wr_data;
+	int wr_addr;
+};
+
+struct interp_sample_rate {
+	int sample_rate;
+	int rate_val;
+};
+
+static struct interp_sample_rate sr_val_tbl[] = {
+	{8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5},
+	{192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA},
+	{176400, 0xB}, {352800, 0xC},
+};
+
+static const struct wcd9xxx_ch tavil_rx_chs[WCD934X_RX_MAX] = {
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER, 0),
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 1, 1),
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 2, 2),
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 3, 3),
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 4, 4),
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 5, 5),
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 6, 6),
+	WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 7, 7),
+};
+
+static const struct wcd9xxx_ch tavil_tx_chs[WCD934X_TX_MAX] = {
+	WCD9XXX_CH(0, 0),
+	WCD9XXX_CH(1, 1),
+	WCD9XXX_CH(2, 2),
+	WCD9XXX_CH(3, 3),
+	WCD9XXX_CH(4, 4),
+	WCD9XXX_CH(5, 5),
+	WCD9XXX_CH(6, 6),
+	WCD9XXX_CH(7, 7),
+	WCD9XXX_CH(8, 8),
+	WCD9XXX_CH(9, 9),
+	WCD9XXX_CH(10, 10),
+	WCD9XXX_CH(11, 11),
+	WCD9XXX_CH(12, 12),
+	WCD9XXX_CH(13, 13),
+	WCD9XXX_CH(14, 14),
+	WCD9XXX_CH(15, 15),
+};
+
+static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = {
+	0,							/* AIF1_PB */
+	BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX),	/* AIF1_CAP */
+	0,							/* AIF2_PB */
+	BIT(AIF1_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX),	/* AIF2_CAP */
+	0,							/* AIF3_PB */
+	BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF4_MAD_TX),	/* AIF3_CAP */
+	0,							/* AIF4_PB */
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+	IIR0 = 0,
+	IIR1,
+	IIR_MAX,
+};
+
+/* Each IIR has 5 Filter Stages */
+enum {
+	BAND1 = 0,
+	BAND2,
+	BAND3,
+	BAND4,
+	BAND5,
+	BAND_MAX,
+};
+
+enum {
+	COMPANDER_1, /* HPH_L */
+	COMPANDER_2, /* HPH_R */
+	COMPANDER_3, /* LO1_DIFF */
+	COMPANDER_4, /* LO2_DIFF */
+	COMPANDER_5, /* LO3_SE - not used in Tavil */
+	COMPANDER_6, /* LO4_SE - not used in Tavil */
+	COMPANDER_7, /* SWR SPK CH1 */
+	COMPANDER_8, /* SWR SPK CH2 */
+	COMPANDER_MAX,
+};
+
+enum {
+	ASRC_IN_HPHL,
+	ASRC_IN_LO1,
+	ASRC_IN_HPHR,
+	ASRC_IN_LO2,
+	ASRC_IN_SPKR1,
+	ASRC_IN_SPKR2,
+	ASRC_INVALID,
+};
+
+enum {
+	ASRC0,
+	ASRC1,
+	ASRC2,
+	ASRC3,
+	ASRC_MAX,
+};
+
+enum {
+	CONV_88P2K_TO_384K,
+	CONV_96K_TO_352P8K,
+	CONV_352P8K_TO_384K,
+	CONV_384K_TO_352P8K,
+	CONV_384K_TO_384K,
+	CONV_96K_TO_384K,
+};
+
+static struct afe_param_slimbus_slave_port_cfg tavil_slimbus_slave_port_cfg = {
+	.minor_version = 1,
+	.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
+	.slave_dev_pgd_la = 0,
+	.slave_dev_intfdev_la = 0,
+	.bit_width = 16,
+	.data_format = 0,
+	.num_channels = 1
+};
+
+static struct afe_param_cdc_reg_page_cfg tavil_cdc_reg_page_cfg = {
+	.minor_version = AFE_API_VERSION_CDC_REG_PAGE_CFG,
+	.enable = 1,
+	.proc_id = AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_1,
+};
+
+static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_MAIN_CTL_1),
+		HW_MAD_AUDIO_ENABLE, 0x1, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_AUDIO_CTL_3),
+		HW_MAD_AUDIO_SLEEP_TIME, 0xF, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_AUDIO_CTL_4),
+		HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_CFG),
+		MAD_AUDIO_INT_DEST_SELECT_REG, 0x2, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_MASK3),
+		MAD_AUDIO_INT_MASK_REG, 0x1, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_STATUS3),
+		MAD_AUDIO_INT_STATUS_REG, 0x1, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_CLEAR3),
+		MAD_AUDIO_INT_CLEAR_REG, 0x1, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_WATERMARK_N, 0x1E, WCD934X_REG_BITS, 0x1
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_ENABLE_N, 0x1, WCD934X_REG_BITS, 0x1
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_WATERMARK_N, 0x1E, WCD934X_REG_BITS, 0x1
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_ENABLE_N, 0x1, WCD934X_REG_BITS, 0x1
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET +
+		 WCD934X_CDC_ANC0_IIR_ADAPT_CTL),
+		AANC_FF_GAIN_ADAPTIVE, 0x4, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET +
+		 WCD934X_CDC_ANC0_IIR_ADAPT_CTL),
+		AANC_FFGAIN_ADAPTIVE_EN, 0x8, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET +
+		 WCD934X_CDC_ANC0_FF_A_GAIN_CTL),
+		AANC_GAIN_CONTROL, 0xFF, WCD934X_REG_BITS, 0
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET +
+		 SB_PGD_TX_PORT_MULTI_CHANNEL_0(0)),
+		SB_PGD_TX_PORTn_MULTI_CHNL_0, 0xFF, WCD934X_REG_BITS, 0x4
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET +
+		 SB_PGD_TX_PORT_MULTI_CHANNEL_1(0)),
+		SB_PGD_TX_PORTn_MULTI_CHNL_1, 0xFF, WCD934X_REG_BITS, 0x4
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET +
+		 SB_PGD_RX_PORT_MULTI_CHANNEL_0(0x180, 0)),
+		SB_PGD_RX_PORTn_MULTI_CHNL_0, 0xFF, WCD934X_REG_BITS, 0x4
+	},
+	{
+		1,
+		(WCD934X_REGISTER_START_OFFSET +
+		 SB_PGD_RX_PORT_MULTI_CHANNEL_0(0x181, 0)),
+		SB_PGD_RX_PORTn_MULTI_CHNL_1, 0xFF, WCD934X_REG_BITS, 0x4
+	},
+};
+
+static struct afe_param_cdc_reg_cfg_data tavil_audio_reg_cfg = {
+	.num_registers = ARRAY_SIZE(audio_reg_cfg),
+	.reg_data = audio_reg_cfg,
+};
+
+static struct afe_param_id_cdc_aanc_version tavil_cdc_aanc_version = {
+	.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
+	.aanc_hw_version        = AANC_HW_BLOCK_VERSION_2,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+#define WCD934X_TX_UNMUTE_DELAY_MS 40
+
+static int tx_unmute_delay = WCD934X_TX_UNMUTE_DELAY_MS;
+module_param(tx_unmute_delay, int, 0664);
+MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path");
+
+static void tavil_codec_set_tx_hold(struct snd_soc_codec *, u16, bool);
+
+/* Hold instance to soundwire platform device */
+struct tavil_swr_ctrl_data {
+	struct platform_device *swr_pdev;
+};
+
+struct wcd_swr_ctrl_platform_data {
+	void *handle; /* holds codec private data */
+	int (*read)(void *handle, int reg);
+	int (*write)(void *handle, int reg, int val);
+	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
+	int (*clk)(void *handle, bool enable);
+	int (*handle_irq)(void *handle,
+			  irqreturn_t (*swrm_irq_handler)(int irq, void *data),
+			  void *swrm_handle, int action);
+};
+
+/* Holds all Soundwire and speaker related information */
+struct wcd934x_swr {
+	struct tavil_swr_ctrl_data *ctrl_data;
+	struct wcd_swr_ctrl_platform_data plat_data;
+	struct mutex read_mutex;
+	struct mutex write_mutex;
+	struct mutex clk_mutex;
+	int spkr_gain_offset;
+	int spkr_mode;
+	int clk_users;
+	int rx_7_count;
+	int rx_8_count;
+};
+
+struct tx_mute_work {
+	struct tavil_priv *tavil;
+	u8 decimator;
+	struct delayed_work dwork;
+};
+
+#define WCD934X_SPK_ANC_EN_DELAY_MS 350
+static int spk_anc_en_delay = WCD934X_SPK_ANC_EN_DELAY_MS;
+module_param(spk_anc_en_delay, int, 0664);
+MODULE_PARM_DESC(spk_anc_en_delay, "delay to enable anc in speaker path");
+
+struct spk_anc_work {
+	struct tavil_priv *tavil;
+	struct delayed_work dwork;
+};
+
+struct hpf_work {
+	struct tavil_priv *tavil;
+	u8 decimator;
+	u8 hpf_cut_off_freq;
+	struct delayed_work dwork;
+};
+
+struct tavil_priv {
+	struct device *dev;
+	struct wcd9xxx *wcd9xxx;
+	struct snd_soc_codec *codec;
+	u32 rx_bias_count;
+	s32 dmic_0_1_clk_cnt;
+	s32 dmic_2_3_clk_cnt;
+	s32 dmic_4_5_clk_cnt;
+	s32 micb_ref[TAVIL_MAX_MICBIAS];
+	s32 pullup_ref[TAVIL_MAX_MICBIAS];
+
+	/* ANC related */
+	u32 anc_slot;
+	bool anc_func;
+
+	/* compander */
+	int comp_enabled[COMPANDER_MAX];
+	int ear_spkr_gain;
+
+	/* class h specific data */
+	struct wcd_clsh_cdc_data clsh_d;
+	/* Tavil Interpolator Mode Select for EAR, HPH_L and HPH_R */
+	u32 hph_mode;
+
+	/* Mad switch reference count */
+	int mad_switch_cnt;
+
+	/* track tavil interface type */
+	u8 intf_type;
+
+	/* to track the status */
+	unsigned long status_mask;
+
+	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
+	/* num of slim ports required */
+	struct wcd9xxx_codec_dai_data  dai[NUM_CODEC_DAIS];
+	/* Port values for Rx and Tx codec_dai */
+	unsigned int rx_port_value[WCD934X_RX_MAX];
+	unsigned int tx_port_value;
+
+	struct wcd9xxx_resmgr_v2 *resmgr;
+	struct wcd934x_swr swr;
+	struct mutex micb_lock;
+
+	struct delayed_work power_gate_work;
+	struct mutex power_lock;
+
+	struct clk *wcd_ext_clk;
+
+	/* mbhc module */
+	struct wcd934x_mbhc *mbhc;
+
+	struct mutex codec_mutex;
+	struct work_struct tavil_add_child_devices_work;
+	struct hpf_work tx_hpf_work[WCD934X_NUM_DECIMATORS];
+	struct tx_mute_work tx_mute_dwork[WCD934X_NUM_DECIMATORS];
+	struct spk_anc_work spk_anc_dwork;
+
+	unsigned int vi_feed_value;
+
+	/* DSP control */
+	struct wcd_dsp_cntl *wdsp_cntl;
+
+	/* cal info for codec */
+	struct fw_info *fw_data;
+
+	/* Entry for version info */
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+
+	/* SVS voting related */
+	struct mutex svs_mutex;
+	int svs_ref_cnt;
+
+	int native_clk_users;
+	/* ASRC users count */
+	int asrc_users[ASRC_MAX];
+	int asrc_output_mode[ASRC_MAX];
+	/* Main path clock users count */
+	int main_clk_users[WCD934X_NUM_INTERPOLATORS];
+	struct tavil_dsd_config *dsd_config;
+	struct tavil_idle_detect_config idle_det_cfg;
+
+	int power_active_ref;
+	int sidetone_coeff_array[IIR_MAX][BAND_MAX]
+		[WCD934X_CDC_SIDETONE_IIR_COEFF_MAX];
+};
+
+static const struct tavil_reg_mask_val tavil_spkr_default[] = {
+	{WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+	{WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+	{WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+	{WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+	{WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x50},
+	{WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x50},
+};
+
+static const struct tavil_reg_mask_val tavil_spkr_mode1[] = {
+	{WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x00},
+	{WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x00},
+	{WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x00},
+	{WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x00},
+	{WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x44},
+	{WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
+};
+
+static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil);
+
+/**
+ * tavil_set_spkr_gain_offset - offset the speaker path
+ * gain with the given offset value.
+ *
+ * @codec: codec instance
+ * @offset: Indicates speaker path gain offset value.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int tavil_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset)
+{
+	struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	if (!priv)
+		return -EINVAL;
+
+	priv->swr.spkr_gain_offset = offset;
+	return 0;
+}
+EXPORT_SYMBOL(tavil_set_spkr_gain_offset);
+
+/**
+ * tavil_set_spkr_mode - Configures speaker compander and smartboost
+ * settings based on speaker mode.
+ *
+ * @codec: codec instance
+ * @mode: Indicates speaker configuration mode.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int tavil_set_spkr_mode(struct snd_soc_codec *codec, int mode)
+{
+	struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int i;
+	const struct tavil_reg_mask_val *regs;
+	int size;
+
+	if (!priv)
+		return -EINVAL;
+
+	switch (mode) {
+	case WCD934X_SPKR_MODE_1:
+		regs = tavil_spkr_mode1;
+		size = ARRAY_SIZE(tavil_spkr_mode1);
+		break;
+	default:
+		regs = tavil_spkr_default;
+		size = ARRAY_SIZE(tavil_spkr_default);
+		break;
+	}
+
+	priv->swr.spkr_mode = mode;
+	for (i = 0; i < size; i++)
+		snd_soc_update_bits(codec, regs[i].reg,
+				    regs[i].mask, regs[i].val);
+	return 0;
+}
+EXPORT_SYMBOL(tavil_set_spkr_mode);
+
+/**
+ * tavil_get_afe_config - returns specific codec configuration to afe to write
+ *
+ * @codec: codec instance
+ * @config_type: Indicates type of configuration to write.
+ */
+void *tavil_get_afe_config(struct snd_soc_codec *codec,
+			   enum afe_config_type config_type)
+{
+	struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		return &priv->slimbus_slave_cfg;
+	case AFE_CDC_REGISTERS_CONFIG:
+		return &tavil_audio_reg_cfg;
+	case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+		return &tavil_slimbus_slave_port_cfg;
+	case AFE_AANC_VERSION:
+		return &tavil_cdc_aanc_version;
+	case AFE_CDC_REGISTER_PAGE_CONFIG:
+		return &tavil_cdc_reg_page_cfg;
+	default:
+		dev_info(codec->dev, "%s: Unknown config_type 0x%x\n",
+			__func__, config_type);
+		return NULL;
+	}
+}
+EXPORT_SYMBOL(tavil_get_afe_config);
+
+static bool is_tavil_playback_dai(int dai_id)
+{
+	if ((dai_id == AIF1_PB) || (dai_id == AIF2_PB) ||
+	    (dai_id == AIF3_PB) || (dai_id == AIF4_PB))
+		return true;
+
+	return false;
+}
+
+static int tavil_find_playback_dai_id_for_port(int port_id,
+					       struct tavil_priv *tavil)
+{
+	struct wcd9xxx_codec_dai_data *dai;
+	struct wcd9xxx_ch *ch;
+	int i, slv_port_id;
+
+	for (i = AIF1_PB; i < NUM_CODEC_DAIS; i++) {
+		if (!is_tavil_playback_dai(i))
+			continue;
+
+		dai = &tavil->dai[i];
+		list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+			slv_port_id = wcd9xxx_get_slave_port(ch->ch_num);
+			if ((slv_port_id > 0) && (slv_port_id == port_id))
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static void tavil_vote_svs(struct tavil_priv *tavil, bool vote)
+{
+	struct wcd9xxx *wcd9xxx;
+
+	wcd9xxx = tavil->wcd9xxx;
+
+	mutex_lock(&tavil->svs_mutex);
+	if (vote) {
+		tavil->svs_ref_cnt++;
+		if (tavil->svs_ref_cnt == 1)
+			regmap_update_bits(wcd9xxx->regmap,
+					   WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0,
+					   0x01, 0x01);
+	} else {
+		/* Do not decrement ref count if it is already 0 */
+		if (tavil->svs_ref_cnt == 0)
+			goto done;
+
+		tavil->svs_ref_cnt--;
+		if (tavil->svs_ref_cnt == 0)
+			regmap_update_bits(wcd9xxx->regmap,
+					   WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0,
+					   0x01, 0x00);
+	}
+done:
+	dev_dbg(tavil->dev, "%s: vote = %s, updated ref cnt = %u\n", __func__,
+		vote ? "vote" : "Unvote", tavil->svs_ref_cnt);
+	mutex_unlock(&tavil->svs_mutex);
+}
+
+static int tavil_get_anc_slot(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tavil->anc_slot;
+	return 0;
+}
+
+static int tavil_put_anc_slot(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	tavil->anc_slot = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int tavil_get_anc_func(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = (tavil->anc_func == true ? 1 : 0);
+	return 0;
+}
+
+static int tavil_put_anc_func(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	mutex_lock(&tavil->codec_mutex);
+	tavil->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
+	dev_dbg(codec->dev, "%s: anc_func %x", __func__, tavil->anc_func);
+
+	if (tavil->anc_func == true) {
+		snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC EAR");
+		snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR PA");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_disable_pin(dapm, "EAR PA");
+		snd_soc_dapm_disable_pin(dapm, "EAR");
+		snd_soc_dapm_disable_pin(dapm, "HPHL PA");
+		snd_soc_dapm_disable_pin(dapm, "HPHR PA");
+		snd_soc_dapm_disable_pin(dapm, "HPHL");
+		snd_soc_dapm_disable_pin(dapm, "HPHR");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+		snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_enable_pin(dapm, "EAR PA");
+		snd_soc_dapm_enable_pin(dapm, "EAR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL");
+		snd_soc_dapm_enable_pin(dapm, "HPHR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL PA");
+		snd_soc_dapm_enable_pin(dapm, "HPHR PA");
+	}
+	mutex_unlock(&tavil->codec_mutex);
+
+	snd_soc_dapm_sync(dapm);
+	return 0;
+}
+
+static int tavil_codec_enable_anc(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	const char *filename;
+	const struct firmware *fw;
+	int i;
+	int ret = 0;
+	int num_anc_slots;
+	struct wcd9xxx_anc_header *anc_head;
+	struct firmware_cal *hwdep_cal = NULL;
+	u32 anc_writes_size = 0;
+	u32 anc_cal_size = 0;
+	int anc_size_remaining;
+	u32 *anc_ptr;
+	u16 reg;
+	u8 mask, val;
+	size_t cal_size;
+	const void *data;
+
+	if (!tavil->anc_func)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		hwdep_cal = wcdcal_get_fw_cal(tavil->fw_data, WCD9XXX_ANC_CAL);
+		if (hwdep_cal) {
+			data = hwdep_cal->data;
+			cal_size = hwdep_cal->size;
+			dev_dbg(codec->dev, "%s: using hwdep calibration, cal_size %zd",
+				__func__, cal_size);
+		} else {
+			filename = "WCD934X/WCD934X_anc.bin";
+			ret = request_firmware(&fw, filename, codec->dev);
+			if (ret < 0) {
+				dev_err(codec->dev, "%s: Failed to acquire ANC data: %d\n",
+					__func__, ret);
+				return ret;
+			}
+			if (!fw) {
+				dev_err(codec->dev, "%s: Failed to get anc fw\n",
+					__func__);
+				return -ENODEV;
+			}
+			data = fw->data;
+			cal_size = fw->size;
+			dev_dbg(codec->dev, "%s: using request_firmware calibration\n",
+				__func__);
+		}
+		if (cal_size < sizeof(struct wcd9xxx_anc_header)) {
+			dev_err(codec->dev, "%s: Invalid cal_size %zd\n",
+				__func__, cal_size);
+			ret = -EINVAL;
+			goto err;
+		}
+		/* First number is the number of register writes */
+		anc_head = (struct wcd9xxx_anc_header *)(data);
+		anc_ptr = (u32 *)(data + sizeof(struct wcd9xxx_anc_header));
+		anc_size_remaining = cal_size -
+				     sizeof(struct wcd9xxx_anc_header);
+		num_anc_slots = anc_head->num_anc_slots;
+
+		if (tavil->anc_slot >= num_anc_slots) {
+			dev_err(codec->dev, "%s: Invalid ANC slot selected\n",
+				__func__);
+			ret = -EINVAL;
+			goto err;
+		}
+		for (i = 0; i < num_anc_slots; i++) {
+			if (anc_size_remaining < WCD934X_PACKED_REG_SIZE) {
+				dev_err(codec->dev, "%s: Invalid register format\n",
+					__func__);
+				ret = -EINVAL;
+				goto err;
+			}
+			anc_writes_size = (u32)(*anc_ptr);
+			anc_size_remaining -= sizeof(u32);
+			anc_ptr += 1;
+
+			if ((anc_writes_size * WCD934X_PACKED_REG_SIZE) >
+			    anc_size_remaining) {
+				dev_err(codec->dev, "%s: Invalid register format\n",
+					__func__);
+				ret = -EINVAL;
+				goto err;
+			}
+
+			if (tavil->anc_slot == i)
+				break;
+
+			anc_size_remaining -= (anc_writes_size *
+				WCD934X_PACKED_REG_SIZE);
+			anc_ptr += anc_writes_size;
+		}
+		if (i == num_anc_slots) {
+			dev_err(codec->dev, "%s: Selected ANC slot not present\n",
+				__func__);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		anc_cal_size = anc_writes_size;
+		for (i = 0; i < anc_writes_size; i++) {
+			WCD934X_CODEC_UNPACK_ENTRY(anc_ptr[i], reg, mask, val);
+			snd_soc_write(codec, reg, (val & mask));
+		}
+
+		/* Rate converter clk enable and set bypass mode */
+		if (!strcmp(w->name, "RX INT0 DAC") ||
+		    !strcmp(w->name, "RX INT1 DAC") ||
+		    !strcmp(w->name, "ANC SPK1 PA")) {
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC0_RC_COMMON_CTL,
+					    0x05, 0x05);
+			if (!strcmp(w->name, "RX INT1 DAC")) {
+				snd_soc_update_bits(codec,
+					WCD934X_CDC_ANC0_FIFO_COMMON_CTL,
+					0x66, 0x66);
+			}
+		} else if (!strcmp(w->name, "RX INT2 DAC")) {
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_RC_COMMON_CTL,
+					    0x05, 0x05);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_FIFO_COMMON_CTL,
+					    0x66, 0x66);
+		}
+		if (!strcmp(w->name, "RX INT1 DAC"))
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08);
+		else if (!strcmp(w->name, "RX INT2 DAC"))
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08);
+
+		if (!hwdep_cal)
+			release_firmware(fw);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		if (!strcmp(w->name, "ANC HPHL PA") ||
+		    !strcmp(w->name, "ANC HPHR PA")) {
+			/* Remove ANC Rx from reset */
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC0_CLK_RESET_CTL,
+					    0x08, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x08, 0x00);
+		}
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, WCD934X_CDC_ANC0_RC_COMMON_CTL,
+				    0x05, 0x00);
+		if (!strcmp(w->name, "ANC EAR PA") ||
+		    !strcmp(w->name, "ANC SPK1 PA") ||
+		    !strcmp(w->name, "ANC HPHL PA")) {
+			snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_1_CTL,
+					    0x30, 0x00);
+			msleep(50);
+			snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_1_CTL,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC0_CLK_RESET_CTL,
+					    0x38, 0x38);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC0_CLK_RESET_CTL,
+					    0x07, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC0_CLK_RESET_CTL,
+					    0x38, 0x00);
+		} else if (!strcmp(w->name, "ANC HPHR PA")) {
+			snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_1_CTL,
+					    0x30, 0x00);
+			msleep(50);
+			snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_1_CTL,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x38, 0x38);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x07, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_ANC1_CLK_RESET_CTL,
+					    0x38, 0x00);
+		}
+		break;
+	}
+
+	return 0;
+err:
+	if (!hwdep_cal)
+		release_firmware(fw);
+	return ret;
+}
+
+static int tavil_get_clkmode(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+
+	if (test_bit(CLK_MODE, &tavil_p->status_mask))
+		ucontrol->value.enumerated.item[0] = 1;
+	else
+		ucontrol->value.enumerated.item[0] = 0;
+
+	dev_dbg(codec->dev, "%s: is_low_power_clock: %s\n", __func__,
+		test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false");
+
+	return 0;
+}
+
+static int tavil_put_clkmode(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+
+	if (ucontrol->value.enumerated.item[0])
+		set_bit(CLK_MODE, &tavil_p->status_mask);
+	else
+		clear_bit(CLK_MODE, &tavil_p->status_mask);
+
+	dev_dbg(codec->dev, "%s: is_low_power_clock: %s\n", __func__,
+		test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false");
+
+	return 0;
+}
+
+static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tavil_p->vi_feed_value;
+
+	return 0;
+}
+
+static int tavil_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct soc_multi_mixer_control *mixer =
+		((struct soc_multi_mixer_control *)kcontrol->private_value);
+	u32 dai_id = widget->shift;
+	u32 port_id = mixer->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n",
+		__func__, enable, port_id, dai_id);
+
+	tavil_p->vi_feed_value = ucontrol->value.integer.value[0];
+
+	mutex_lock(&tavil_p->codec_mutex);
+	if (enable) {
+		if (port_id == WCD934X_TX14 && !test_bit(VI_SENSE_1,
+						&tavil_p->status_mask)) {
+			list_add_tail(&core->tx_chs[WCD934X_TX14].list,
+					&tavil_p->dai[dai_id].wcd9xxx_ch_list);
+			set_bit(VI_SENSE_1, &tavil_p->status_mask);
+		}
+		if (port_id == WCD934X_TX15 && !test_bit(VI_SENSE_2,
+						&tavil_p->status_mask)) {
+			list_add_tail(&core->tx_chs[WCD934X_TX15].list,
+					&tavil_p->dai[dai_id].wcd9xxx_ch_list);
+			set_bit(VI_SENSE_2, &tavil_p->status_mask);
+		}
+	} else {
+		if (port_id == WCD934X_TX14 && test_bit(VI_SENSE_1,
+					&tavil_p->status_mask)) {
+			list_del_init(&core->tx_chs[WCD934X_TX14].list);
+			clear_bit(VI_SENSE_1, &tavil_p->status_mask);
+		}
+		if (port_id == WCD934X_TX15 && test_bit(VI_SENSE_2,
+					&tavil_p->status_mask)) {
+			list_del_init(&core->tx_chs[WCD934X_TX15].list);
+			clear_bit(VI_SENSE_2, &tavil_p->status_mask);
+		}
+	}
+	mutex_unlock(&tavil_p->codec_mutex);
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
+
+	return 0;
+}
+
+static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tavil_p->tx_port_value;
+	return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_dapm_update *update = NULL;
+	struct soc_multi_mixer_control *mixer =
+		((struct soc_multi_mixer_control *)kcontrol->private_value);
+	u32 dai_id = widget->shift;
+	u32 port_id = mixer->shift;
+	u32 enable = ucontrol->value.integer.value[0];
+	u32 vtable;
+
+	dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
+		  __func__,
+		widget->name, ucontrol->id.name, tavil_p->tx_port_value,
+		widget->shift, ucontrol->value.integer.value[0]);
+
+	mutex_lock(&tavil_p->codec_mutex);
+	if (dai_id >= ARRAY_SIZE(vport_slim_check_table)) {
+		dev_err(codec->dev, "%s: dai_id: %d, out of bounds\n",
+			__func__, dai_id);
+		mutex_unlock(&tavil_p->codec_mutex);
+		return -EINVAL;
+	}
+	vtable = vport_slim_check_table[dai_id];
+
+	switch (dai_id) {
+	case AIF1_CAP:
+	case AIF2_CAP:
+	case AIF3_CAP:
+		/* only add to the list if value not set */
+		if (enable && !(tavil_p->tx_port_value & 1 << port_id)) {
+			if (wcd9xxx_tx_vport_validation(vtable, port_id,
+			    tavil_p->dai, NUM_CODEC_DAIS)) {
+				dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
+					__func__, port_id);
+				mutex_unlock(&tavil_p->codec_mutex);
+				return 0;
+			}
+			tavil_p->tx_port_value |= 1 << port_id;
+			list_add_tail(&core->tx_chs[port_id].list,
+				      &tavil_p->dai[dai_id].wcd9xxx_ch_list);
+		} else if (!enable && (tavil_p->tx_port_value &
+			   1 << port_id)) {
+			tavil_p->tx_port_value &= ~(1 << port_id);
+			list_del_init(&core->tx_chs[port_id].list);
+		} else {
+			if (enable)
+				dev_dbg(codec->dev, "%s: TX%u port is used by\n"
+					"this virtual port\n",
+					__func__, port_id);
+			else
+				dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
+					"this virtual port\n",
+					__func__, port_id);
+			/* avoid update power function */
+			mutex_unlock(&tavil_p->codec_mutex);
+			return 0;
+		}
+		break;
+	case AIF4_MAD_TX:
+		break;
+	default:
+		dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
+		mutex_unlock(&tavil_p->codec_mutex);
+		return -EINVAL;
+	}
+	dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
+		__func__, widget->name, widget->sname, tavil_p->tx_port_value,
+		widget->shift);
+
+	mutex_unlock(&tavil_p->codec_mutex);
+	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
+
+	return 0;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] =
+				tavil_p->rx_port_value[widget->shift];
+	return 0;
+}
+
+static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_dapm_update *update = NULL;
+	unsigned int rx_port_value;
+	u32 port_id = widget->shift;
+
+	tavil_p->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
+	rx_port_value = tavil_p->rx_port_value[port_id];
+
+	mutex_lock(&tavil_p->codec_mutex);
+	dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
+		__func__, widget->name, ucontrol->id.name,
+		rx_port_value, widget->shift,
+		ucontrol->value.integer.value[0]);
+
+	/* value need to match the Virtual port and AIF number */
+	switch (rx_port_value) {
+	case 0:
+		list_del_init(&core->rx_chs[port_id].list);
+		break;
+	case 1:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			WCD934X_RX_PORT_START_NUMBER,
+			&tavil_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tavil_p->dai[AIF1_PB].wcd9xxx_ch_list);
+		break;
+	case 2:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			WCD934X_RX_PORT_START_NUMBER,
+			&tavil_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tavil_p->dai[AIF2_PB].wcd9xxx_ch_list);
+		break;
+	case 3:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			WCD934X_RX_PORT_START_NUMBER,
+			&tavil_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tavil_p->dai[AIF3_PB].wcd9xxx_ch_list);
+		break;
+	case 4:
+		if (wcd9xxx_rx_vport_validation(port_id +
+			WCD934X_RX_PORT_START_NUMBER,
+			&tavil_p->dai[AIF4_PB].wcd9xxx_ch_list)) {
+			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+				__func__, port_id);
+			goto rtn;
+		}
+		list_add_tail(&core->rx_chs[port_id].list,
+			      &tavil_p->dai[AIF4_PB].wcd9xxx_ch_list);
+		break;
+	default:
+		dev_err(codec->dev, "Unknown AIF %d\n", rx_port_value);
+		goto err;
+	}
+rtn:
+	mutex_unlock(&tavil_p->codec_mutex);
+	snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+				      rx_port_value, e, update);
+
+	return 0;
+err:
+	mutex_unlock(&tavil_p->codec_mutex);
+	return -EINVAL;
+}
+
+static void tavil_codec_enable_slim_port_intr(
+					struct wcd9xxx_codec_dai_data *dai,
+					struct snd_soc_codec *codec)
+{
+	struct wcd9xxx_ch *ch;
+	int port_num = 0;
+	unsigned short reg = 0;
+	u8 val = 0;
+	struct tavil_priv *tavil_p;
+
+	if (!dai || !codec) {
+		pr_err("%s: Invalid params\n", __func__);
+		return;
+	}
+
+	tavil_p = snd_soc_codec_get_drvdata(codec);
+	list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+		if (ch->port >= WCD934X_RX_PORT_START_NUMBER) {
+			port_num = ch->port - WCD934X_RX_PORT_START_NUMBER;
+			reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + (port_num / 8);
+			val = wcd9xxx_interface_reg_read(tavil_p->wcd9xxx,
+				reg);
+			if (!(val & BYTE_BIT_MASK(port_num))) {
+				val |= BYTE_BIT_MASK(port_num);
+				wcd9xxx_interface_reg_write(
+					tavil_p->wcd9xxx, reg, val);
+				val = wcd9xxx_interface_reg_read(
+					tavil_p->wcd9xxx, reg);
+			}
+		} else {
+			port_num = ch->port;
+			reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
+			val = wcd9xxx_interface_reg_read(tavil_p->wcd9xxx,
+				reg);
+			if (!(val & BYTE_BIT_MASK(port_num))) {
+				val |= BYTE_BIT_MASK(port_num);
+				wcd9xxx_interface_reg_write(tavil_p->wcd9xxx,
+					reg, val);
+				val = wcd9xxx_interface_reg_read(
+					tavil_p->wcd9xxx, reg);
+			}
+		}
+	}
+}
+
+static int tavil_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
+					  bool up)
+{
+	int ret = 0;
+	struct wcd9xxx_ch *ch;
+
+	if (up) {
+		list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+			ret = wcd9xxx_get_slave_port(ch->ch_num);
+			if (ret < 0) {
+				pr_err("%s: Invalid slave port ID: %d\n",
+				       __func__, ret);
+				ret = -EINVAL;
+			} else {
+				set_bit(ret, &dai->ch_mask);
+			}
+		}
+	} else {
+		ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
+					 msecs_to_jiffies(
+						WCD934X_SLIM_CLOSE_TIMEOUT));
+		if (!ret) {
+			pr_err("%s: Slim close tx/rx wait timeout, ch_mask:0x%lx\n",
+				__func__, dai->ch_mask);
+			ret = -ETIMEDOUT;
+		} else {
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static void tavil_codec_mute_dsd(struct snd_soc_codec *codec,
+				 struct list_head *ch_list)
+{
+	u8 dsd0_in;
+	u8 dsd1_in;
+	struct wcd9xxx_ch *ch;
+
+	/* Read DSD Input Ports */
+	dsd0_in = (snd_soc_read(codec, WCD934X_CDC_DSD0_CFG0) & 0x3C) >> 2;
+	dsd1_in = (snd_soc_read(codec, WCD934X_CDC_DSD1_CFG0) & 0x3C) >> 2;
+
+	if ((dsd0_in == 0) && (dsd1_in == 0))
+		return;
+
+	/*
+	 * Check if the ports getting disabled are connected to DSD inputs.
+	 * If connected, enable DSD mute to avoid DC entering into DSD Filter
+	 */
+	list_for_each_entry(ch, ch_list, list) {
+		if (ch->port == (dsd0_in + WCD934X_RX_PORT_START_NUMBER - 1))
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2,
+					    0x04, 0x04);
+		if (ch->port == (dsd1_in + WCD934X_RX_PORT_START_NUMBER - 1))
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2,
+					    0x04, 0x04);
+	}
+}
+
+static int tavil_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct wcd9xxx *core;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+	struct wcd9xxx_codec_dai_data *dai;
+	struct tavil_dsd_config *dsd_conf = tavil_p->dsd_config;
+
+	core = dev_get_drvdata(codec->dev->parent);
+
+	dev_dbg(codec->dev, "%s: event called! codec name %s num_dai %d\n"
+		"stream name %s event %d\n",
+		__func__, codec->component.name,
+		codec->component.num_dai, w->sname, event);
+
+	dai = &tavil_p->dai[w->shift];
+	dev_dbg(codec->dev, "%s: w->name %s w->shift %d event %d\n",
+		 __func__, w->name, w->shift, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		dai->bus_down_in_recovery = false;
+		tavil_codec_enable_slim_port_intr(dai, codec);
+		(void) tavil_codec_enable_slim_chmask(dai, true);
+		ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+					      dai->rate, dai->bit_width,
+					      &dai->grph);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (dsd_conf)
+			tavil_codec_mute_dsd(codec, &dai->wcd9xxx_ch_list);
+
+		ret = wcd9xxx_disconnect_port(core, &dai->wcd9xxx_ch_list,
+					      dai->grph);
+		dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
+			__func__, ret);
+
+		if (!dai->bus_down_in_recovery)
+			ret = tavil_codec_enable_slim_chmask(dai, false);
+		else
+			dev_dbg(codec->dev,
+				"%s: bus in recovery skip enable slim_chmask",
+				__func__);
+		ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+						dai->grph);
+		break;
+	}
+	return ret;
+}
+
+static int tavil_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_codec_dai_data *dai;
+	struct wcd9xxx *core;
+	int ret = 0;
+
+	dev_dbg(codec->dev,
+		"%s: w->name %s, w->shift = %d, num_dai %d stream name %s\n",
+		__func__, w->name, w->shift,
+		codec->component.num_dai, w->sname);
+
+	dai = &tavil_p->dai[w->shift];
+	core = dev_get_drvdata(codec->dev->parent);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		dai->bus_down_in_recovery = false;
+		tavil_codec_enable_slim_port_intr(dai, codec);
+		(void) tavil_codec_enable_slim_chmask(dai, true);
+		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+					      dai->rate, dai->bit_width,
+					      &dai->grph);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+						dai->grph);
+		if (!dai->bus_down_in_recovery)
+			ret = tavil_codec_enable_slim_chmask(dai, false);
+		if (ret < 0) {
+			ret = wcd9xxx_disconnect_port(core,
+						      &dai->wcd9xxx_ch_list,
+						      dai->grph);
+			dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
+				 __func__, ret);
+		}
+		break;
+	}
+	return ret;
+}
+
+static int tavil_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w,
+					      struct snd_kcontrol *kcontrol,
+					      int event)
+{
+	struct wcd9xxx *core = NULL;
+	struct snd_soc_codec *codec = NULL;
+	struct tavil_priv *tavil_p = NULL;
+	int ret = 0;
+	struct wcd9xxx_codec_dai_data *dai = NULL;
+
+	codec = snd_soc_dapm_to_codec(w->dapm);
+	tavil_p = snd_soc_codec_get_drvdata(codec);
+	core = dev_get_drvdata(codec->dev->parent);
+
+	dev_dbg(codec->dev,
+		"%s: num_dai %d stream name %s w->name %s event %d shift %d\n",
+		__func__, codec->component.num_dai, w->sname,
+		w->name, event, w->shift);
+
+	if (w->shift != AIF4_VIFEED) {
+		pr_err("%s Error in enabling the tx path\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	dai = &tavil_p->dai[w->shift];
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (test_bit(VI_SENSE_1, &tavil_p->status_mask)) {
+			dev_dbg(codec->dev, "%s: spkr1 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x0F,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &tavil_p->status_mask)) {
+			pr_debug("%s: spkr2 enabled\n", __func__);
+			/* Enable V&I sensing */
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x0F,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x0F,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x10);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x00);
+		}
+		dai->bus_down_in_recovery = false;
+		tavil_codec_enable_slim_port_intr(dai, codec);
+		(void) tavil_codec_enable_slim_chmask(dai, true);
+		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+					      dai->rate, dai->bit_width,
+					      &dai->grph);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+						dai->grph);
+		if (ret)
+			dev_err(codec->dev, "%s error in close_slim_sch_tx %d\n",
+				__func__, ret);
+		if (!dai->bus_down_in_recovery)
+			ret = tavil_codec_enable_slim_chmask(dai, false);
+		if (ret < 0) {
+			ret = wcd9xxx_disconnect_port(core,
+				&dai->wcd9xxx_ch_list,
+				dai->grph);
+			dev_dbg(codec->dev, "%s: Disconnect TX port, ret = %d\n",
+				__func__, ret);
+		}
+		if (test_bit(VI_SENSE_1, &tavil_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr1 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		if (test_bit(VI_SENSE_2, &tavil_p->status_mask)) {
+			/* Disable V&I sensing */
+			dev_dbg(codec->dev, "%s: spkr2 disabled\n", __func__);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20,
+				0x20);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10,
+				0x00);
+		}
+		break;
+	}
+done:
+	return ret;
+}
+
+static int tavil_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tavil->rx_bias_count++;
+		if (tavil->rx_bias_count == 1) {
+			snd_soc_update_bits(codec, WCD934X_ANA_RX_SUPPLIES,
+					    0x01, 0x01);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tavil->rx_bias_count--;
+		if (!tavil->rx_bias_count)
+			snd_soc_update_bits(codec, WCD934X_ANA_RX_SUPPLIES,
+					    0x01, 0x00);
+		break;
+	};
+	dev_dbg(codec->dev, "%s: Current RX BIAS user count: %d\n", __func__,
+		tavil->rx_bias_count);
+
+	return 0;
+}
+
+static void tavil_spk_anc_update_callback(struct work_struct *work)
+{
+	struct spk_anc_work *spk_anc_dwork;
+	struct tavil_priv *tavil;
+	struct delayed_work *delayed_work;
+	struct snd_soc_codec *codec;
+
+	delayed_work = to_delayed_work(work);
+	spk_anc_dwork = container_of(delayed_work, struct spk_anc_work, dwork);
+	tavil = spk_anc_dwork->tavil;
+	codec = tavil->codec;
+
+	snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_CFG0, 0x10, 0x10);
+}
+
+static int tavil_codec_enable_spkr_anc(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	if (!tavil->anc_func)
+		return 0;
+
+	dev_dbg(codec->dev, "%s: w: %s event: %d anc: %d\n", __func__,
+		w->name, event, tavil->anc_func);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = tavil_codec_enable_anc(w, kcontrol, event);
+		schedule_delayed_work(&tavil->spk_anc_dwork.dwork,
+				      msecs_to_jiffies(spk_anc_en_delay));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		cancel_delayed_work_sync(&tavil->spk_anc_dwork.dwork);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_CFG0,
+				    0x10, 0x00);
+		ret = tavil_codec_enable_anc(w, kcontrol, event);
+		break;
+	}
+	return ret;
+}
+
+static int tavil_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * 5ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX0_RX_PATH_CTL,
+				    0x10, 0x00);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, WCD934X_CDC_RX0_RX_PATH_MIX_CTL)) &
+		     0x10)
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX0_RX_PATH_MIX_CTL,
+					    0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+
+		if (!(strcmp(w->name, "ANC EAR PA"))) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec, WCD934X_CDC_RX0_RX_PATH_CFG0,
+					    0x10, 0x00);
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static void tavil_codec_override(struct snd_soc_codec *codec, int mode,
+				 int event)
+{
+	if (mode == CLS_AB || mode == CLS_AB_HIFI) {
+		switch (event) {
+		case SND_SOC_DAPM_PRE_PMU:
+		case SND_SOC_DAPM_POST_PMU:
+			snd_soc_update_bits(codec,
+				WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02);
+		break;
+		case SND_SOC_DAPM_POST_PMD:
+			snd_soc_update_bits(codec,
+				WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x00);
+		break;
+		}
+	}
+}
+
+static void tavil_codec_clear_anc_tx_hold(struct tavil_priv *tavil)
+{
+	if (test_and_clear_bit(ANC_MIC_AMIC1, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC1, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC2, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC2, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC3, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC3, false);
+	if (test_and_clear_bit(ANC_MIC_AMIC4, &tavil->status_mask))
+		tavil_codec_set_tx_hold(tavil->codec, WCD934X_ANA_AMIC4, false);
+}
+
+static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
+					    0x06, (0x03 << 1));
+
+		if ((!(strcmp(w->name, "ANC HPHR PA"))) &&
+		    (test_bit(HPH_PA_DELAY, &tavil->status_mask)))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH, 0xC0, 0xC0);
+
+		set_bit(HPH_PA_DELAY, &tavil->status_mask);
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) {
+			/* Set regulator mode to AB if DSD is enabled */
+			snd_soc_update_bits(codec, WCD934X_ANA_RX_SUPPLIES,
+					    0x02, 0x02);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if ((!(strcmp(w->name, "ANC HPHR PA")))) {
+			if ((snd_soc_read(codec, WCD934X_ANA_HPH) & 0xC0)
+					!= 0xC0)
+				/*
+				 * If PA_EN is not set (potentially in ANC case)
+				 * then do nothing for POST_PMU and let left
+				 * channel handle everything.
+				 */
+				break;
+		}
+		/*
+		 * 7ms sleep is required after PA is enabled as per
+		 * HW requirement. If compander is disabled, then
+		 * 20ms delay is needed.
+		 */
+		if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) {
+			if (!tavil->comp_enabled[COMPANDER_2])
+				usleep_range(20000, 20100);
+			else
+				usleep_range(7000, 7100);
+			clear_bit(HPH_PA_DELAY, &tavil->status_mask);
+		}
+		if (tavil->anc_func) {
+			/* Clear Tx FE HOLD if both PAs are enabled */
+			if ((snd_soc_read(tavil->codec, WCD934X_ANA_HPH) &
+					0xC0) == 0xC0)
+				tavil_codec_clear_anc_tx_hold(tavil);
+		}
+
+		snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x01);
+
+		/* Remove mute */
+		snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
+				    0x10, 0x00);
+		/* Enable GM3 boost */
+		snd_soc_update_bits(codec, WCD934X_HPH_CNP_WG_CTL,
+				    0x80, 0x80);
+		/* Enable AutoChop timer at the end of power up */
+		snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x02);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) &
+				  0x10)
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+					    0x10, 0x00);
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2,
+					    0x04, 0x00);
+		if (!(strcmp(w->name, "ANC HPHR PA"))) {
+			pr_debug("%s:Do everything needed for left channel\n",
+				__func__);
+			/* Do everything needed for left channel */
+			snd_soc_update_bits(codec, WCD934X_HPH_L_TEST,
+					    0x01, 0x01);
+
+			/* Remove mute */
+			snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
+					    0x10, 0x00);
+
+			/* Remove mix path mute if it is enabled */
+			if ((snd_soc_read(codec,
+					WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) &
+					0x10)
+				snd_soc_update_bits(codec,
+					WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+					0x10, 0x00);
+
+			if (dsd_conf && (snd_soc_read(codec,
+						WCD934X_CDC_DSD0_PATH_CTL) &
+						0x01))
+				snd_soc_update_bits(codec,
+						    WCD934X_CDC_DSD0_CFG2,
+						    0x04, 0x00);
+			/* Remove ANC Rx from reset */
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+		}
+		tavil_codec_override(codec, tavil->hph_mode, event);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		blocking_notifier_call_chain(&tavil->mbhc->notifier,
+					     WCD_EVENT_PRE_HPHR_PA_OFF,
+					     &tavil->mbhc->wcd_mbhc);
+		/* Enable DSD Mute before PA disable */
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2,
+					    0x04, 0x04);
+		snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
+				    0x10, 0x10);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+				    0x10, 0x10);
+		if (!(strcmp(w->name, "ANC HPHR PA")))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH, 0x40, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * 5ms sleep is required after PA disable. If compander is
+		 * disabled, then 20ms delay is needed after PA disable.
+		 */
+		if (!tavil->comp_enabled[COMPANDER_2])
+			usleep_range(20000, 20100);
+		else
+			usleep_range(5000, 5100);
+		tavil_codec_override(codec, tavil->hph_mode, event);
+		blocking_notifier_call_chain(&tavil->mbhc->notifier,
+					     WCD_EVENT_POST_HPHR_PA_OFF,
+					     &tavil->mbhc->wcd_mbhc);
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
+					    0x06, 0x0);
+		if (!(strcmp(w->name, "ANC HPHR PA"))) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX2_RX_PATH_CFG0,
+					    0x10, 0x00);
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
+					    0x06, (0x03 << 1));
+		if ((!(strcmp(w->name, "ANC HPHL PA"))) &&
+		    (test_bit(HPH_PA_DELAY, &tavil->status_mask)))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH,
+					    0xC0, 0xC0);
+		set_bit(HPH_PA_DELAY, &tavil->status_mask);
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) {
+			/* Set regulator mode to AB if DSD is enabled */
+			snd_soc_update_bits(codec, WCD934X_ANA_RX_SUPPLIES,
+					    0x02, 0x02);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			if ((snd_soc_read(codec, WCD934X_ANA_HPH) & 0xC0)
+								!= 0xC0)
+				/*
+				 * If PA_EN is not set (potentially in ANC
+				 * case) then do nothing for POST_PMU and
+				 * let right channel handle everything.
+				 */
+				break;
+		}
+		/*
+		 * 7ms sleep is required after PA is enabled as per
+		 * HW requirement. If compander is disabled, then
+		 * 20ms delay is needed.
+		 */
+		if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) {
+			if (!tavil->comp_enabled[COMPANDER_1])
+				usleep_range(20000, 20100);
+			else
+				usleep_range(7000, 7100);
+			clear_bit(HPH_PA_DELAY, &tavil->status_mask);
+		}
+		if (tavil->anc_func) {
+			/* Clear Tx FE HOLD if both PAs are enabled */
+			if ((snd_soc_read(tavil->codec, WCD934X_ANA_HPH) &
+					0xC0) == 0xC0)
+				tavil_codec_clear_anc_tx_hold(tavil);
+		}
+
+		snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x01);
+		/* Remove Mute on primary path */
+		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
+				    0x10, 0x00);
+		/* Enable GM3 boost */
+		snd_soc_update_bits(codec, WCD934X_HPH_CNP_WG_CTL,
+				    0x80, 0x80);
+		/* Enable AutoChop timer at the end of power up */
+		snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x02);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) &
+				  0x10)
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+					    0x10, 0x00);
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01))
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2,
+					    0x04, 0x00);
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			pr_debug("%s:Do everything needed for right channel\n",
+				__func__);
+
+			/* Do everything needed for right channel */
+			snd_soc_update_bits(codec, WCD934X_HPH_R_TEST,
+					    0x01, 0x01);
+
+			/* Remove mute */
+			snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL,
+						0x10, 0x00);
+
+			/* Remove mix path mute if it is enabled */
+			if ((snd_soc_read(codec,
+					WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) &
+					0x10)
+				snd_soc_update_bits(codec,
+						WCD934X_CDC_RX2_RX_PATH_MIX_CTL,
+						0x10, 0x00);
+			if (dsd_conf && (snd_soc_read(codec,
+					WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
+				snd_soc_update_bits(codec,
+						    WCD934X_CDC_DSD1_CFG2,
+						    0x04, 0x00);
+			/* Remove ANC Rx from reset */
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+		}
+		tavil_codec_override(codec, tavil->hph_mode, event);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		blocking_notifier_call_chain(&tavil->mbhc->notifier,
+					     WCD_EVENT_PRE_HPHL_PA_OFF,
+					     &tavil->mbhc->wcd_mbhc);
+		/* Enable DSD Mute before PA disable */
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01))
+			snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2,
+					    0x04, 0x04);
+
+		snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL,
+				    0x10, 0x10);
+		snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_MIX_CTL,
+				    0x10, 0x10);
+		if (!(strcmp(w->name, "ANC HPHL PA")))
+			snd_soc_update_bits(codec, WCD934X_ANA_HPH,
+					    0x80, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * 5ms sleep is required after PA disable. If compander is
+		 * disabled, then 20ms delay is needed after PA disable.
+		 */
+		if (!tavil->comp_enabled[COMPANDER_1])
+			usleep_range(20000, 20100);
+		else
+			usleep_range(5000, 5100);
+		tavil_codec_override(codec, tavil->hph_mode, event);
+		blocking_notifier_call_chain(&tavil->mbhc->notifier,
+					     WCD_EVENT_POST_HPHL_PA_OFF,
+					     &tavil->mbhc->wcd_mbhc);
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL,
+					    0x06, 0x0);
+		if (!(strcmp(w->name, "ANC HPHL PA"))) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			snd_soc_update_bits(codec,
+				WCD934X_CDC_RX1_RX_PATH_CFG0, 0x10, 0x00);
+		}
+		break;
+	};
+
+	return ret;
+}
+
+static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0;
+	u16 dsd_mute_reg = 0, dsd_clk_reg = 0;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	if (w->reg == WCD934X_ANA_LO_1_2) {
+		if (w->shift == 7) {
+			lineout_vol_reg = WCD934X_CDC_RX3_RX_PATH_CTL;
+			lineout_mix_vol_reg = WCD934X_CDC_RX3_RX_PATH_MIX_CTL;
+			dsd_mute_reg = WCD934X_CDC_DSD0_CFG2;
+			dsd_clk_reg = WCD934X_CDC_DSD0_PATH_CTL;
+		} else if (w->shift == 6) {
+			lineout_vol_reg = WCD934X_CDC_RX4_RX_PATH_CTL;
+			lineout_mix_vol_reg = WCD934X_CDC_RX4_RX_PATH_MIX_CTL;
+			dsd_mute_reg = WCD934X_CDC_DSD1_CFG2;
+			dsd_clk_reg = WCD934X_CDC_DSD1_PATH_CTL;
+		}
+	} else {
+		dev_err(codec->dev, "%s: Error enabling lineout PA\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tavil_codec_override(codec, CLS_AB, event);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * 5ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		snd_soc_update_bits(codec, lineout_vol_reg,
+				    0x10, 0x00);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_read(codec, lineout_mix_vol_reg)) & 0x10)
+			snd_soc_update_bits(codec,
+					    lineout_mix_vol_reg,
+					    0x10, 0x00);
+		if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+			snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x00);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+			snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x04);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		tavil_codec_override(codec, CLS_AB, event);
+	default:
+		break;
+	};
+
+	return 0;
+}
+
+static int tavil_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kcontrol,
+				     int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Disable AutoChop timer during power up */
+		snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x00);
+
+		if (tavil->anc_func)
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_EAR,
+			     CLS_H_NORMAL);
+		if (tavil->anc_func)
+			snd_soc_update_bits(codec, WCD934X_CDC_RX0_RX_PATH_CFG0,
+					    0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_EAR,
+			     CLS_H_NORMAL);
+		break;
+	default:
+		break;
+	};
+
+	return ret;
+}
+
+static int tavil_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int hph_mode = tavil->hph_mode;
+	u8 dem_inp;
+	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__,
+		w->name, event, hph_mode);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tavil->anc_func) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			/* 40 msec delay is needed to avoid click and pop */
+			msleep(40);
+		}
+		/* Read DEM INP Select */
+		dem_inp = snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_SEC0) &
+			  0x03;
+		if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+		     (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+			dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n",
+					__func__, hph_mode);
+			return -EINVAL;
+		}
+		if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP))
+			/* Ripple freq control enable */
+			snd_soc_update_bits(codec,
+					     WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+					     0x01, 0x01);
+		/* Disable AutoChop timer during power up */
+		snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x00);
+		/* Set RDAC gain */
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec,
+					    WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,
+					    0xF0, 0x40);
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01))
+			hph_mode = CLS_H_HIFI;
+
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_HPHR,
+			     hph_mode);
+		if (tavil->anc_func)
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX2_RX_PATH_CFG0,
+					    0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_HPHR,
+			     hph_mode);
+		if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP))
+			/* Ripple freq control disable */
+			snd_soc_update_bits(codec,
+					    WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+					    0x01, 0x0);
+		/* Re-set RDAC gain */
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec,
+					    WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,
+					    0xF0, 0x0);
+		break;
+	default:
+		break;
+	};
+
+	return 0;
+}
+
+static int tavil_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int hph_mode = tavil->hph_mode;
+	u8 dem_inp;
+	int ret = 0;
+	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+	uint32_t impedl = 0, impedr = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__,
+		w->name, event, hph_mode);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tavil->anc_func) {
+			ret = tavil_codec_enable_anc(w, kcontrol, event);
+			/* 40 msec delay is needed to avoid click and pop */
+			msleep(40);
+		}
+		/* Read DEM INP Select */
+		dem_inp = snd_soc_read(codec, WCD934X_CDC_RX1_RX_PATH_SEC0) &
+			  0x03;
+		if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+		     (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+			dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n",
+					__func__, hph_mode);
+			return -EINVAL;
+		}
+		if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP))
+			/* Ripple freq control enable */
+			snd_soc_update_bits(codec,
+					     WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+					     0x01, 0x01);
+		/* Disable AutoChop timer during power up */
+		snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x00);
+		/* Set RDAC gain */
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec,
+					    WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,
+					    0xF0, 0x40);
+		if (dsd_conf &&
+		    (snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01))
+			hph_mode = CLS_H_HIFI;
+
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_HPHL,
+			     hph_mode);
+
+		if (tavil->anc_func)
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX1_RX_PATH_CFG0,
+					    0x10, 0x10);
+
+		ret = tavil_mbhc_get_impedance(tavil->mbhc,
+					       &impedl, &impedr);
+		if (!ret) {
+			wcd_clsh_imped_config(codec, impedl, false);
+			set_bit(CLSH_Z_CONFIG, &tavil->status_mask);
+		} else {
+			dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n",
+				__func__, ret);
+			ret = 0;
+		}
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_HPHL,
+			     hph_mode);
+		if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP))
+			/* Ripple freq control disable */
+			snd_soc_update_bits(codec,
+					    WCD934X_SIDO_NEW_VOUT_D_FREQ2,
+					    0x01, 0x0);
+		/* Re-set RDAC gain */
+		if (TAVIL_IS_1_0(tavil->wcd9xxx))
+			snd_soc_update_bits(codec,
+					    WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,
+					    0xF0, 0x0);
+
+		if (test_bit(CLSH_Z_CONFIG, &tavil->status_mask)) {
+			wcd_clsh_imped_config(codec, impedl, true);
+			clear_bit(CLSH_Z_CONFIG, &tavil->status_mask);
+		}
+		break;
+	default:
+		break;
+	};
+
+	return ret;
+}
+
+static int tavil_codec_lineout_dac_event(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_LO,
+			     CLS_AB);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_clsh_fsm(codec, &tavil->clsh_d,
+			     WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_LO,
+			     CLS_AB);
+		break;
+	}
+
+	return 0;
+}
+
+static int tavil_codec_spk_boost_event(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 boost_path_ctl, boost_path_cfg1;
+	u16 reg, reg_mix;
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	if (!strcmp(w->name, "RX INT7 CHAIN")) {
+		boost_path_ctl = WCD934X_CDC_BOOST0_BOOST_PATH_CTL;
+		boost_path_cfg1 = WCD934X_CDC_RX7_RX_PATH_CFG1;
+		reg = WCD934X_CDC_RX7_RX_PATH_CTL;
+		reg_mix = WCD934X_CDC_RX7_RX_PATH_MIX_CTL;
+	} else if (!strcmp(w->name, "RX INT8 CHAIN")) {
+		boost_path_ctl = WCD934X_CDC_BOOST1_BOOST_PATH_CTL;
+		boost_path_cfg1 = WCD934X_CDC_RX8_RX_PATH_CFG1;
+		reg = WCD934X_CDC_RX8_RX_PATH_CTL;
+		reg_mix = WCD934X_CDC_RX8_RX_PATH_MIX_CTL;
+	} else {
+		dev_err(codec->dev, "%s: unknown widget: %s\n",
+			__func__, w->name);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x01);
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x10);
+		snd_soc_update_bits(codec, reg, 0x10, 0x00);
+		if ((snd_soc_read(codec, reg_mix)) & 0x10)
+			snd_soc_update_bits(codec, reg_mix, 0x10, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x00);
+		snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x00);
+		break;
+	};
+
+	return 0;
+}
+
+static int __tavil_codec_enable_swr(struct snd_soc_dapm_widget *w, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil;
+	int ch_cnt = 0;
+
+	tavil = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) ||
+			(strnstr(w->name, "INT7 MIX2",
+						sizeof("RX INT7 MIX2")))))
+			tavil->swr.rx_7_count++;
+		if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) &&
+		    !tavil->swr.rx_8_count)
+			tavil->swr.rx_8_count++;
+		ch_cnt = !!(tavil->swr.rx_7_count) + tavil->swr.rx_8_count;
+
+		swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev,
+				SWR_DEVICE_UP, NULL);
+		swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev,
+				SWR_SET_NUM_RX_CH, &ch_cnt);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if ((strnstr(w->name, "INT7_", sizeof("RX INT7_")))  ||
+			(strnstr(w->name, "INT7 MIX2",
+			sizeof("RX INT7 MIX2"))))
+			tavil->swr.rx_7_count--;
+		if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) &&
+		    tavil->swr.rx_8_count)
+			tavil->swr.rx_8_count--;
+		ch_cnt = !!(tavil->swr.rx_7_count) + tavil->swr.rx_8_count;
+
+		swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev,
+				SWR_SET_NUM_RX_CH, &ch_cnt);
+
+		break;
+	}
+	dev_dbg(tavil->dev, "%s: %s: current swr ch cnt: %d\n",
+		__func__, w->name, ch_cnt);
+
+	return 0;
+}
+
+static int tavil_codec_enable_swr(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	return __tavil_codec_enable_swr(w, event);
+}
+
+static int tavil_codec_config_mad(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+	int idx;
+	const struct firmware *fw;
+	struct firmware_cal *hwdep_cal = NULL;
+	struct wcd_mad_audio_cal *mad_cal = NULL;
+	const void *data;
+	const char *filename = WCD934X_MAD_AUDIO_FIRMWARE_PATH;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	size_t cal_size;
+
+	hwdep_cal = wcdcal_get_fw_cal(tavil->fw_data, WCD9XXX_MAD_CAL);
+	if (hwdep_cal) {
+		data = hwdep_cal->data;
+		cal_size = hwdep_cal->size;
+		dev_dbg(codec->dev, "%s: using hwdep calibration\n",
+			__func__);
+	} else {
+		ret = request_firmware(&fw, filename, codec->dev);
+		if (ret || !fw) {
+			dev_err(codec->dev,
+				"%s: MAD firmware acquire failed, err = %d\n",
+				__func__, ret);
+			return -ENODEV;
+		}
+		data = fw->data;
+		cal_size = fw->size;
+		dev_dbg(codec->dev, "%s: using request_firmware calibration\n",
+			__func__);
+	}
+
+	if (cal_size < sizeof(*mad_cal)) {
+		dev_err(codec->dev,
+			"%s: Incorrect size %zd for MAD Cal, expected %zd\n",
+			__func__, cal_size, sizeof(*mad_cal));
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	mad_cal = (struct wcd_mad_audio_cal *) (data);
+	if (!mad_cal) {
+		dev_err(codec->dev,
+			"%s: Invalid calibration data\n",
+			__func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	snd_soc_write(codec, WCD934X_SOC_MAD_MAIN_CTL_2,
+		      mad_cal->microphone_info.cycle_time);
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_MAIN_CTL_1, 0xFF << 3,
+			    ((uint16_t)mad_cal->microphone_info.settle_time)
+			    << 3);
+
+	/* Audio */
+	snd_soc_write(codec, WCD934X_SOC_MAD_AUDIO_CTL_8,
+		      mad_cal->audio_info.rms_omit_samples);
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_CTL_1,
+			    0x07 << 4, mad_cal->audio_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_CTL_2, 0x03 << 2,
+			    mad_cal->audio_info.detection_mechanism << 2);
+	snd_soc_write(codec, WCD934X_SOC_MAD_AUDIO_CTL_7,
+		      mad_cal->audio_info.rms_diff_threshold & 0x3F);
+	snd_soc_write(codec, WCD934X_SOC_MAD_AUDIO_CTL_5,
+		      mad_cal->audio_info.rms_threshold_lsb);
+	snd_soc_write(codec, WCD934X_SOC_MAD_AUDIO_CTL_6,
+		      mad_cal->audio_info.rms_threshold_msb);
+
+	for (idx = 0; idx < ARRAY_SIZE(mad_cal->audio_info.iir_coefficients);
+	     idx++) {
+		snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR,
+				    0x3F, idx);
+		snd_soc_write(codec, WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL,
+			      mad_cal->audio_info.iir_coefficients[idx]);
+		dev_dbg(codec->dev, "%s:MAD Audio IIR Coef[%d] = 0X%x",
+			__func__, idx,
+			mad_cal->audio_info.iir_coefficients[idx]);
+	}
+
+	/* Beacon */
+	snd_soc_write(codec, WCD934X_SOC_MAD_BEACON_CTL_8,
+		      mad_cal->beacon_info.rms_omit_samples);
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_BEACON_CTL_1,
+			    0x07 << 4, mad_cal->beacon_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_BEACON_CTL_2, 0x03 << 2,
+			    mad_cal->beacon_info.detection_mechanism << 2);
+	snd_soc_write(codec, WCD934X_SOC_MAD_BEACON_CTL_7,
+		      mad_cal->beacon_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, WCD934X_SOC_MAD_BEACON_CTL_5,
+		      mad_cal->beacon_info.rms_threshold_lsb);
+	snd_soc_write(codec, WCD934X_SOC_MAD_BEACON_CTL_6,
+		      mad_cal->beacon_info.rms_threshold_msb);
+
+	for (idx = 0; idx < ARRAY_SIZE(mad_cal->beacon_info.iir_coefficients);
+	     idx++) {
+		snd_soc_update_bits(codec, WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR,
+				    0x3F, idx);
+		snd_soc_write(codec, WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL,
+			      mad_cal->beacon_info.iir_coefficients[idx]);
+		dev_dbg(codec->dev, "%s:MAD Beacon IIR Coef[%d] = 0X%x",
+			__func__, idx,
+			mad_cal->beacon_info.iir_coefficients[idx]);
+	}
+
+	/* Ultrasound */
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_ULTR_CTL_1,
+			    0x07 << 4,
+			    mad_cal->ultrasound_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_ULTR_CTL_2, 0x03 << 2,
+			    mad_cal->ultrasound_info.detection_mechanism << 2);
+	snd_soc_write(codec, WCD934X_SOC_MAD_ULTR_CTL_7,
+		      mad_cal->ultrasound_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, WCD934X_SOC_MAD_ULTR_CTL_5,
+		      mad_cal->ultrasound_info.rms_threshold_lsb);
+	snd_soc_write(codec, WCD934X_SOC_MAD_ULTR_CTL_6,
+		      mad_cal->ultrasound_info.rms_threshold_msb);
+
+done:
+	if (!hwdep_cal)
+		release_firmware(fw);
+
+	return ret;
+}
+
+static int __tavil_codec_enable_mad(struct snd_soc_codec *codec, bool enable)
+{
+	int rc = 0;
+
+	/* Return if CPE INPUT is DEC1 */
+	if (snd_soc_read(codec, WCD934X_CPE_SS_SVA_CFG) & 0x04) {
+		dev_dbg(codec->dev, "%s: MAD is bypassed, skip mad %s\n",
+			__func__, enable ? "enable" : "disable");
+		return rc;
+	}
+
+	dev_dbg(codec->dev, "%s: enable = %s\n", __func__,
+		enable ? "enable" : "disable");
+
+	if (enable) {
+		snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_CTL_2,
+				    0x03, 0x03);
+		rc = tavil_codec_config_mad(codec);
+		if (rc < 0) {
+			snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_CTL_2,
+					    0x03, 0x00);
+			goto done;
+		}
+
+		/* Turn on MAD clk */
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
+				    0x01, 0x01);
+
+		/* Undo reset for MAD */
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
+				    0x02, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+					0x04, 0x04);
+	} else {
+		snd_soc_update_bits(codec, WCD934X_SOC_MAD_AUDIO_CTL_2,
+				    0x03, 0x00);
+		/* Reset the MAD block */
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
+				    0x02, 0x02);
+		/* Turn off MAD clk */
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_MAD_CTL,
+				    0x01, 0x00);
+		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+					0x04, 0x00);
+	}
+done:
+	return rc;
+}
+
+static int tavil_codec_ape_enable_mad(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol,
+				      int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int rc = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x40, 0x40);
+		rc = __tavil_codec_enable_mad(codec, true);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x40, 0x00);
+		__tavil_codec_enable_mad(codec, false);
+		break;
+	}
+
+	dev_dbg(tavil->dev, "%s: event = %d\n", __func__, event);
+	return rc;
+}
+
+static int tavil_codec_cpe_mad_ctl(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int rc = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tavil->mad_switch_cnt++;
+		if (tavil->mad_switch_cnt != 1)
+			goto done;
+
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x20, 0x20);
+		rc = __tavil_codec_enable_mad(codec, true);
+		if (rc < 0) {
+			tavil->mad_switch_cnt--;
+			goto done;
+		}
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		tavil->mad_switch_cnt--;
+		if (tavil->mad_switch_cnt != 0)
+			goto done;
+
+		snd_soc_update_bits(codec, WCD934X_CPE_SS_SVA_CFG, 0x20, 0x00);
+		__tavil_codec_enable_mad(codec, false);
+		break;
+	}
+done:
+	dev_dbg(tavil->dev, "%s: event = %d, mad_switch_cnt = %d\n",
+		__func__, event, tavil->mad_switch_cnt);
+	return rc;
+}
+
+static int tavil_get_asrc_mode(struct tavil_priv *tavil, int asrc,
+			       u8 main_sr, u8 mix_sr)
+{
+	u8 asrc_output_mode;
+	int asrc_mode = CONV_88P2K_TO_384K;
+
+	if ((asrc < 0) || (asrc >= ASRC_MAX))
+		return 0;
+
+	asrc_output_mode = tavil->asrc_output_mode[asrc];
+
+	if (asrc_output_mode) {
+		/*
+		 * If Mix sample rate is < 96KHz, use 96K to 352.8K
+		 * conversion, or else use 384K to 352.8K conversion
+		 */
+		if (mix_sr < 5)
+			asrc_mode = CONV_96K_TO_352P8K;
+		else
+			asrc_mode = CONV_384K_TO_352P8K;
+	} else {
+		/* Integer main and Fractional mix path */
+		if (main_sr < 8 && mix_sr > 9) {
+			asrc_mode = CONV_352P8K_TO_384K;
+		} else if (main_sr > 8 && mix_sr < 8) {
+			/* Fractional main and Integer mix path */
+			if (mix_sr < 5)
+				asrc_mode = CONV_96K_TO_352P8K;
+			else
+				asrc_mode = CONV_384K_TO_352P8K;
+		} else if (main_sr < 8 && mix_sr < 8) {
+			/* Integer main and Integer mix path */
+			asrc_mode = CONV_96K_TO_384K;
+		}
+	}
+
+	return asrc_mode;
+}
+
+static int tavil_codec_wdma3_ctl(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Fix to 16KHz */
+		snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+				    0xF0, 0x10);
+		/* Select mclk_1 */
+		snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+				    0x02, 0x00);
+		/* Enable DMA */
+		snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+				    0x01, 0x01);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable DMA */
+		snd_soc_update_bits(codec, WCD934X_DMA_WDMA_CTL_3,
+				    0x01, 0x00);
+		break;
+
+	};
+
+	return 0;
+}
+
+static int tavil_codec_enable_asrc(struct snd_soc_codec *codec,
+				   int asrc_in, int event)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	u16 cfg_reg, ctl_reg, clk_reg, asrc_ctl, mix_ctl_reg;
+	int asrc, ret = 0;
+	u8 main_sr, mix_sr, asrc_mode = 0;
+
+	switch (asrc_in) {
+	case ASRC_IN_HPHL:
+		cfg_reg = WCD934X_CDC_RX1_RX_PATH_CFG0;
+		ctl_reg = WCD934X_CDC_RX1_RX_PATH_CTL;
+		clk_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL;
+		asrc_ctl = WCD934X_MIXING_ASRC0_CTL1;
+		asrc = ASRC0;
+		break;
+	case ASRC_IN_LO1:
+		cfg_reg = WCD934X_CDC_RX3_RX_PATH_CFG0;
+		ctl_reg = WCD934X_CDC_RX3_RX_PATH_CTL;
+		clk_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL;
+		asrc_ctl = WCD934X_MIXING_ASRC0_CTL1;
+		asrc = ASRC0;
+		break;
+	case ASRC_IN_HPHR:
+		cfg_reg = WCD934X_CDC_RX2_RX_PATH_CFG0;
+		ctl_reg = WCD934X_CDC_RX2_RX_PATH_CTL;
+		clk_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL;
+		asrc_ctl = WCD934X_MIXING_ASRC1_CTL1;
+		asrc = ASRC1;
+		break;
+	case ASRC_IN_LO2:
+		cfg_reg = WCD934X_CDC_RX4_RX_PATH_CFG0;
+		ctl_reg = WCD934X_CDC_RX4_RX_PATH_CTL;
+		clk_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL;
+		asrc_ctl = WCD934X_MIXING_ASRC1_CTL1;
+		asrc = ASRC1;
+		break;
+	case ASRC_IN_SPKR1:
+		cfg_reg = WCD934X_CDC_RX7_RX_PATH_CFG0;
+		ctl_reg = WCD934X_CDC_RX7_RX_PATH_CTL;
+		clk_reg = WCD934X_MIXING_ASRC2_CLK_RST_CTL;
+		asrc_ctl = WCD934X_MIXING_ASRC2_CTL1;
+		asrc = ASRC2;
+		break;
+	case ASRC_IN_SPKR2:
+		cfg_reg = WCD934X_CDC_RX8_RX_PATH_CFG0;
+		ctl_reg = WCD934X_CDC_RX8_RX_PATH_CTL;
+		clk_reg = WCD934X_MIXING_ASRC3_CLK_RST_CTL;
+		asrc_ctl = WCD934X_MIXING_ASRC3_CTL1;
+		asrc = ASRC3;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid asrc input :%d\n", __func__,
+			asrc_in);
+		ret = -EINVAL;
+		goto done;
+	};
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tavil->asrc_users[asrc] == 0) {
+			snd_soc_update_bits(codec, cfg_reg, 0x80, 0x80);
+			snd_soc_update_bits(codec, clk_reg, 0x01, 0x01);
+			main_sr = snd_soc_read(codec, ctl_reg) & 0x0F;
+			mix_ctl_reg = ctl_reg + 5;
+			mix_sr = snd_soc_read(codec, mix_ctl_reg) & 0x0F;
+			asrc_mode = tavil_get_asrc_mode(tavil, asrc,
+							main_sr, mix_sr);
+			dev_dbg(codec->dev, "%s: main_sr:%d mix_sr:%d asrc_mode %d\n",
+				__func__, main_sr, mix_sr, asrc_mode);
+			snd_soc_update_bits(codec, asrc_ctl, 0x07, asrc_mode);
+		}
+		tavil->asrc_users[asrc]++;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tavil->asrc_users[asrc]--;
+		if (tavil->asrc_users[asrc] <= 0) {
+			tavil->asrc_users[asrc] = 0;
+			snd_soc_update_bits(codec, asrc_ctl, 0x07, 0x00);
+			snd_soc_update_bits(codec, cfg_reg, 0x80, 0x00);
+			snd_soc_update_bits(codec, clk_reg, 0x01, 0x00);
+		}
+		break;
+	};
+
+	dev_dbg(codec->dev, "%s: ASRC%d, users: %d\n",
+		__func__, asrc, tavil->asrc_users[asrc]);
+
+done:
+	return ret;
+}
+
+static int tavil_codec_enable_asrc_resampler(struct snd_soc_dapm_widget *w,
+					     struct snd_kcontrol *kcontrol,
+					     int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int ret = 0;
+	u8 cfg, asrc_in;
+
+	cfg = snd_soc_read(codec, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0);
+	if (!(cfg & 0xFF)) {
+		dev_err(codec->dev, "%s: ASRC%u input not selected\n",
+			__func__, w->shift);
+		return -EINVAL;
+	}
+
+	switch (w->shift) {
+	case ASRC0:
+		asrc_in = ((cfg & 0x03) == 1) ? ASRC_IN_HPHL : ASRC_IN_LO1;
+		ret = tavil_codec_enable_asrc(codec, asrc_in, event);
+		break;
+	case ASRC1:
+		asrc_in = ((cfg & 0x0C) == 4) ? ASRC_IN_HPHR : ASRC_IN_LO2;
+		ret = tavil_codec_enable_asrc(codec, asrc_in, event);
+		break;
+	case ASRC2:
+		asrc_in = ((cfg & 0x30) == 0x20) ? ASRC_IN_SPKR1 : ASRC_INVALID;
+		ret = tavil_codec_enable_asrc(codec, asrc_in, event);
+		break;
+	case ASRC3:
+		asrc_in = ((cfg & 0xC0) == 0x80) ? ASRC_IN_SPKR2 : ASRC_INVALID;
+		ret = tavil_codec_enable_asrc(codec, asrc_in, event);
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid asrc:%u\n", __func__,
+			w->shift);
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+static int tavil_enable_native_supply(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (++tavil->native_clk_users == 1) {
+			snd_soc_update_bits(codec, WCD934X_CLK_SYS_PLL_ENABLES,
+					    0x01, 0x01);
+			usleep_range(100, 120);
+			snd_soc_update_bits(codec, WCD934X_CLK_SYS_MCLK2_PRG1,
+					    0x06, 0x02);
+			snd_soc_update_bits(codec, WCD934X_CLK_SYS_MCLK2_PRG1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_GATE,
+					    0x04, 0x00);
+			usleep_range(30, 50);
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x02, 0x02);
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x10, 0x10);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (tavil->native_clk_users &&
+		    (--tavil->native_clk_users == 0)) {
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x10, 0x00);
+			snd_soc_update_bits(codec,
+					WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x02, 0x00);
+			snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_GATE,
+					    0x04, 0x04);
+			snd_soc_update_bits(codec, WCD934X_CLK_SYS_MCLK2_PRG1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec, WCD934X_CLK_SYS_MCLK2_PRG1,
+					    0x06, 0x00);
+			snd_soc_update_bits(codec, WCD934X_CLK_SYS_PLL_ENABLES,
+					    0x01, 0x00);
+		}
+		break;
+	}
+
+	dev_dbg(codec->dev, "%s: native_clk_users: %d, event: %d\n",
+		__func__, tavil->native_clk_users, event);
+
+	return 0;
+}
+
+static void tavil_codec_hphdelay_lutbypass(struct snd_soc_codec *codec,
+				    u16 interp_idx, int event)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	u8 hph_dly_mask;
+	u16 hph_lut_bypass_reg = 0;
+	u16 hph_comp_ctrl7 = 0;
+
+
+	switch (interp_idx) {
+	case INTERP_HPHL:
+		hph_dly_mask = 1;
+		hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHL_COMP_LUT;
+		hph_comp_ctrl7 = WCD934X_CDC_COMPANDER1_CTL7;
+		break;
+	case INTERP_HPHR:
+		hph_dly_mask = 2;
+		hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHR_COMP_LUT;
+		hph_comp_ctrl7 = WCD934X_CDC_COMPANDER2_CTL7;
+		break;
+	default:
+		break;
+	}
+
+	if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, WCD934X_CDC_CLSH_TEST0,
+				    hph_dly_mask, 0x0);
+		snd_soc_update_bits(codec, hph_lut_bypass_reg, 0x80, 0x80);
+		if (tavil->hph_mode == CLS_H_ULP)
+			snd_soc_update_bits(codec, hph_comp_ctrl7, 0x20, 0x20);
+	}
+
+	if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, WCD934X_CDC_CLSH_TEST0,
+				    hph_dly_mask, hph_dly_mask);
+		snd_soc_update_bits(codec, hph_lut_bypass_reg, 0x80, 0x00);
+		snd_soc_update_bits(codec, hph_comp_ctrl7, 0x20, 0x0);
+	}
+}
+
+static void tavil_codec_hd2_control(struct tavil_priv *priv,
+				    u16 interp_idx, int event)
+{
+	u16 hd2_scale_reg;
+	u16 hd2_enable_reg = 0;
+	struct snd_soc_codec *codec = priv->codec;
+
+	if (TAVIL_IS_1_1(priv->wcd9xxx))
+		return;
+
+	switch (interp_idx) {
+	case INTERP_HPHL:
+		hd2_scale_reg = WCD934X_CDC_RX1_RX_PATH_SEC3;
+		hd2_enable_reg = WCD934X_CDC_RX1_RX_PATH_CFG0;
+		break;
+	case INTERP_HPHR:
+		hd2_scale_reg = WCD934X_CDC_RX2_RX_PATH_SEC3;
+		hd2_enable_reg = WCD934X_CDC_RX2_RX_PATH_CFG0;
+		break;
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x14);
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04);
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00);
+		snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00);
+	}
+}
+
+static int tavil_codec_config_ear_spkr_gain(struct snd_soc_codec *codec,
+					    int event, int gain_reg)
+{
+	int comp_gain_offset, val;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	switch (tavil->swr.spkr_mode) {
+	/* Compander gain in SPKR_MODE1 case is 12 dB */
+	case WCD934X_SPKR_MODE_1:
+		comp_gain_offset = -12;
+		break;
+	/* Default case compander gain is 15 dB */
+	default:
+		comp_gain_offset = -15;
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Apply ear spkr gain only if compander is enabled */
+		if (tavil->comp_enabled[COMPANDER_7] &&
+		    (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL) &&
+		    (tavil->ear_spkr_gain != 0)) {
+			/* For example, val is -8(-12+5-1) for 4dB of gain */
+			val = comp_gain_offset + tavil->ear_spkr_gain - 1;
+			snd_soc_write(codec, gain_reg, val);
+
+			dev_dbg(codec->dev, "%s: RX7 Volume %d dB\n",
+				__func__, val);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/*
+		 * Reset RX7 volume to 0 dB if compander is enabled and
+		 * ear_spkr_gain is non-zero.
+		 */
+		if (tavil->comp_enabled[COMPANDER_7] &&
+		    (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL) &&
+		    (tavil->ear_spkr_gain != 0)) {
+			snd_soc_write(codec, gain_reg, 0x0);
+
+			dev_dbg(codec->dev, "%s: Reset RX7 Volume to 0 dB\n",
+				__func__);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int tavil_config_compander(struct snd_soc_codec *codec, int interp_n,
+				  int event)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int comp;
+	u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+	/* EAR does not have compander */
+	if (!interp_n)
+		return 0;
+
+	comp = interp_n - 1;
+	dev_dbg(codec->dev, "%s: event %d compander %d, enabled %d\n",
+		__func__, event, comp + 1, tavil->comp_enabled[comp]);
+
+	if (!tavil->comp_enabled[comp])
+		return 0;
+
+	comp_ctl0_reg = WCD934X_CDC_COMPANDER1_CTL0 + (comp * 8);
+	rx_path_cfg0_reg = WCD934X_CDC_RX1_RX_PATH_CFG0 + (comp * 20);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Compander Clock */
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x01);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x02);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00);
+		snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00);
+	}
+
+	return 0;
+}
+
+static void tavil_codec_idle_detect_control(struct snd_soc_codec *codec,
+					    int interp, int event)
+{
+	int reg = 0, mask, val;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	if (!tavil->idle_det_cfg.hph_idle_detect_en)
+		return;
+
+	if (interp == INTERP_HPHL) {
+		reg = WCD934X_CDC_RX_IDLE_DET_PATH_CTL;
+		mask = 0x01;
+		val = 0x01;
+	}
+	if (interp == INTERP_HPHR) {
+		reg = WCD934X_CDC_RX_IDLE_DET_PATH_CTL;
+		mask = 0x02;
+		val = 0x02;
+	}
+
+	if (reg && SND_SOC_DAPM_EVENT_ON(event))
+		snd_soc_update_bits(codec, reg, mask, val);
+
+	if (reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_update_bits(codec, reg, mask, 0x00);
+		tavil->idle_det_cfg.hph_idle_thr = 0;
+		snd_soc_write(codec, WCD934X_CDC_RX_IDLE_DET_CFG3, 0x0);
+	}
+}
+
+/**
+ * tavil_codec_enable_interp_clk - Enable main path Interpolator
+ * clock.
+ *
+ * @codec:    Codec instance
+ * @event:    Indicates speaker path gain offset value
+ * @intp_idx: Interpolator index
+ * Returns number of main clock users
+ */
+int tavil_codec_enable_interp_clk(struct snd_soc_codec *codec,
+				  int event, int interp_idx)
+{
+	struct tavil_priv *tavil;
+	u16 main_reg;
+
+	if (!codec) {
+		pr_err("%s: codec is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	tavil  = snd_soc_codec_get_drvdata(codec);
+	main_reg = WCD934X_CDC_RX0_RX_PATH_CTL + (interp_idx * 20);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (tavil->main_clk_users[interp_idx] == 0) {
+			/* Main path PGA mute enable */
+			snd_soc_update_bits(codec, main_reg, 0x10, 0x10);
+			/* Clk enable */
+			snd_soc_update_bits(codec, main_reg, 0x20, 0x20);
+			tavil_codec_idle_detect_control(codec, interp_idx,
+							event);
+			tavil_codec_hd2_control(tavil, interp_idx, event);
+			tavil_codec_hphdelay_lutbypass(codec, interp_idx,
+						       event);
+			tavil_config_compander(codec, interp_idx, event);
+		}
+		tavil->main_clk_users[interp_idx]++;
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		tavil->main_clk_users[interp_idx]--;
+		if (tavil->main_clk_users[interp_idx] <= 0) {
+			tavil->main_clk_users[interp_idx] = 0;
+			tavil_config_compander(codec, interp_idx, event);
+			tavil_codec_hphdelay_lutbypass(codec, interp_idx,
+						       event);
+			tavil_codec_hd2_control(tavil, interp_idx, event);
+			tavil_codec_idle_detect_control(codec, interp_idx,
+							event);
+			/* Clk Disable */
+			snd_soc_update_bits(codec, main_reg, 0x20, 0x00);
+			/* Reset enable and disable */
+			snd_soc_update_bits(codec, main_reg, 0x40, 0x40);
+			snd_soc_update_bits(codec, main_reg, 0x40, 0x00);
+			/* Reset rate to 48K*/
+			snd_soc_update_bits(codec, main_reg, 0x0F, 0x04);
+		}
+	}
+
+	dev_dbg(codec->dev, "%s event %d main_clk_users %d\n",
+		__func__,  event, tavil->main_clk_users[interp_idx]);
+
+	return tavil->main_clk_users[interp_idx];
+}
+EXPORT_SYMBOL(tavil_codec_enable_interp_clk);
+
+static int tavil_anc_out_switch_cb(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	tavil_codec_enable_interp_clk(codec, event, w->shift);
+
+	return 0;
+}
+static int tavil_codec_set_idle_detect_thr(struct snd_soc_codec *codec,
+					   int interp, int path_type)
+{
+	int port_id[4] = { 0, 0, 0, 0 };
+	int *port_ptr, num_ports;
+	int bit_width = 0, i;
+	int mux_reg, mux_reg_val;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int dai_id, idle_thr;
+
+	if ((interp != INTERP_HPHL) && (interp != INTERP_HPHR))
+		return 0;
+
+	if (!tavil->idle_det_cfg.hph_idle_detect_en)
+		return 0;
+
+	port_ptr = &port_id[0];
+	num_ports = 0;
+
+	/*
+	 * Read interpolator MUX input registers and find
+	 * which slimbus port is connected and store the port
+	 * numbers in port_id array.
+	 */
+	if (path_type == INTERP_MIX_PATH) {
+		mux_reg = WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1 +
+			  2 * (interp - 1);
+		mux_reg_val = snd_soc_read(codec, mux_reg) & 0x0f;
+
+		if ((mux_reg_val >= INTn_2_INP_SEL_RX0) &&
+		   (mux_reg_val < INTn_2_INP_SEL_PROXIMITY)) {
+			*port_ptr++ = mux_reg_val +
+				      WCD934X_RX_PORT_START_NUMBER - 1;
+			num_ports++;
+		}
+	}
+
+	if (path_type == INTERP_MAIN_PATH) {
+		mux_reg = WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0 +
+			  2 * (interp - 1);
+		mux_reg_val = snd_soc_read(codec, mux_reg) & 0x0f;
+		i = WCD934X_INTERP_MUX_NUM_INPUTS;
+
+		while (i) {
+			if ((mux_reg_val >= INTn_1_INP_SEL_RX0) &&
+			    (mux_reg_val <= INTn_1_INP_SEL_RX7)) {
+				*port_ptr++ = mux_reg_val +
+					WCD934X_RX_PORT_START_NUMBER -
+					INTn_1_INP_SEL_RX0;
+				num_ports++;
+			}
+			mux_reg_val = (snd_soc_read(codec, mux_reg) &
+						    0xf0) >> 4;
+			mux_reg += 1;
+			i--;
+		}
+	}
+
+	dev_dbg(codec->dev, "%s: num_ports: %d, ports[%d %d %d %d]\n",
+		__func__, num_ports, port_id[0], port_id[1],
+		port_id[2], port_id[3]);
+
+	i = 0;
+	while (num_ports) {
+		dai_id = tavil_find_playback_dai_id_for_port(port_id[i++],
+							     tavil);
+
+		if ((dai_id >= 0) && (dai_id < NUM_CODEC_DAIS)) {
+			dev_dbg(codec->dev, "%s: dai_id: %d bit_width: %d\n",
+				__func__, dai_id,
+				tavil->dai[dai_id].bit_width);
+
+			if (tavil->dai[dai_id].bit_width > bit_width)
+				bit_width = tavil->dai[dai_id].bit_width;
+		}
+
+		num_ports--;
+	}
+
+	switch (bit_width) {
+	case 16:
+		idle_thr = 0xff; /* F16 */
+		break;
+	case 24:
+	case 32:
+		idle_thr = 0x03; /* F22 */
+		break;
+	default:
+		idle_thr = 0x00;
+		break;
+	}
+
+	dev_dbg(codec->dev, "%s: (new) idle_thr: %d, (cur) idle_thr: %d\n",
+		__func__, idle_thr, tavil->idle_det_cfg.hph_idle_thr);
+
+	if ((tavil->idle_det_cfg.hph_idle_thr == 0) ||
+	    (idle_thr < tavil->idle_det_cfg.hph_idle_thr)) {
+		snd_soc_write(codec, WCD934X_CDC_RX_IDLE_DET_CFG3, idle_thr);
+		tavil->idle_det_cfg.hph_idle_thr = idle_thr;
+	}
+
+	return 0;
+}
+
+static int tavil_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol,
+				       int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	u16 gain_reg, mix_reg;
+	int offset_val = 0;
+	int val = 0;
+
+	if (w->shift >= WCD934X_NUM_INTERPOLATORS ||
+	    w->shift == INTERP_LO3_NA || w->shift == INTERP_LO4_NA) {
+		dev_err(codec->dev, "%s: Invalid Interpolator value %d for name %s\n",
+			__func__, w->shift, w->name);
+		return -EINVAL;
+	};
+
+	gain_reg = WCD934X_CDC_RX0_RX_VOL_MIX_CTL +
+					(w->shift * WCD934X_RX_PATH_CTL_OFFSET);
+	mix_reg = WCD934X_CDC_RX0_RX_PATH_MIX_CTL +
+					(w->shift * WCD934X_RX_PATH_CTL_OFFSET);
+
+	if (w->shift == INTERP_SPKR1 ||  w->shift == INTERP_SPKR2)
+		__tavil_codec_enable_swr(w, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tavil_codec_set_idle_detect_thr(codec, w->shift,
+						INTERP_MIX_PATH);
+		tavil_codec_enable_interp_clk(codec, event, w->shift);
+		/* Clk enable */
+		snd_soc_update_bits(codec, mix_reg, 0x20, 0x20);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if ((tavil->swr.spkr_gain_offset ==
+		     WCD934X_RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tavil->comp_enabled[COMPANDER_7] ||
+		     tavil->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL ||
+		     gain_reg == WCD934X_CDC_RX8_RX_VOL_MIX_CTL)) {
+			snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			offset_val = -2;
+		}
+		val = snd_soc_read(codec, gain_reg);
+		val += offset_val;
+		snd_soc_write(codec, gain_reg, val);
+		tavil_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Clk Disable */
+		snd_soc_update_bits(codec, mix_reg, 0x20, 0x00);
+		tavil_codec_enable_interp_clk(codec, event, w->shift);
+		/* Reset enable and disable */
+		snd_soc_update_bits(codec, mix_reg, 0x40, 0x40);
+		snd_soc_update_bits(codec, mix_reg, 0x40, 0x00);
+
+		if ((tavil->swr.spkr_gain_offset ==
+		     WCD934X_RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tavil->comp_enabled[COMPANDER_7] ||
+		     tavil->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL ||
+		     gain_reg == WCD934X_CDC_RX8_RX_VOL_MIX_CTL)) {
+			snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			offset_val = 2;
+			val = snd_soc_read(codec, gain_reg);
+			val += offset_val;
+			snd_soc_write(codec, gain_reg, val);
+		}
+		tavil_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	};
+	dev_dbg(codec->dev, "%s event %d name %s\n", __func__, event, w->name);
+
+	return 0;
+}
+
+/**
+ * tavil_get_dsd_config - Get pointer to dsd config structure
+ *
+ * @codec: pointer to snd_soc_codec structure
+ *
+ * Returns pointer to tavil_dsd_config structure
+ */
+struct tavil_dsd_config *tavil_get_dsd_config(struct snd_soc_codec *codec)
+{
+	struct tavil_priv *tavil;
+
+	if (!codec)
+		return NULL;
+
+	tavil = snd_soc_codec_get_drvdata(codec);
+
+	if (!tavil)
+		return NULL;
+
+	return tavil->dsd_config;
+}
+EXPORT_SYMBOL(tavil_get_dsd_config);
+
+static int tavil_codec_enable_main_path(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	u16 gain_reg;
+	u16 reg;
+	int val;
+	int offset_val = 0;
+
+	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
+
+	if (w->shift >= WCD934X_NUM_INTERPOLATORS ||
+	    w->shift == INTERP_LO3_NA || w->shift == INTERP_LO4_NA) {
+		dev_err(codec->dev, "%s: Invalid Interpolator value %d for name %s\n",
+			__func__, w->shift, w->name);
+		return -EINVAL;
+	};
+
+	reg = WCD934X_CDC_RX0_RX_PATH_CTL + (w->shift *
+					     WCD934X_RX_PATH_CTL_OFFSET);
+	gain_reg = WCD934X_CDC_RX0_RX_VOL_CTL + (w->shift *
+						 WCD934X_RX_PATH_CTL_OFFSET);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tavil_codec_set_idle_detect_thr(codec, w->shift,
+						INTERP_MAIN_PATH);
+		tavil_codec_enable_interp_clk(codec, event, w->shift);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* apply gain after int clk is enabled */
+		if ((tavil->swr.spkr_gain_offset ==
+					WCD934X_RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tavil->comp_enabled[COMPANDER_7] ||
+		     tavil->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD934X_CDC_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x01);
+			offset_val = -2;
+		}
+		val = snd_soc_read(codec, gain_reg);
+		val += offset_val;
+		snd_soc_write(codec, gain_reg, val);
+		tavil_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tavil_codec_enable_interp_clk(codec, event, w->shift);
+
+		if ((tavil->swr.spkr_gain_offset ==
+					WCD934X_RX_GAIN_OFFSET_M1P5_DB) &&
+		    (tavil->comp_enabled[COMPANDER_7] ||
+		     tavil->comp_enabled[COMPANDER_8]) &&
+		    (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL ||
+		     gain_reg == WCD934X_CDC_RX8_RX_VOL_CTL)) {
+			snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX7_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1,
+					    0x01, 0x00);
+			snd_soc_update_bits(codec,
+					    WCD934X_CDC_RX8_RX_PATH_MIX_SEC0,
+					    0x01, 0x00);
+			offset_val = 2;
+			val = snd_soc_read(codec, gain_reg);
+			val += offset_val;
+			snd_soc_write(codec, gain_reg, val);
+		}
+		tavil_codec_config_ear_spkr_gain(codec, event, gain_reg);
+		break;
+	};
+
+	return 0;
+}
+
+static int tavil_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
+				    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU: /* fall through */
+	case SND_SOC_DAPM_PRE_PMD:
+		if (strnstr(w->name, "IIR0", sizeof("IIR0"))) {
+			snd_soc_write(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL,
+			snd_soc_read(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL));
+			snd_soc_write(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL,
+			snd_soc_read(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL));
+			snd_soc_write(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL,
+			snd_soc_read(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL));
+			snd_soc_write(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL,
+			snd_soc_read(codec,
+				WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL));
+		} else {
+			snd_soc_write(codec,
+				WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL,
+			snd_soc_read(codec,
+				WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL));
+			snd_soc_write(codec,
+				WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL,
+			snd_soc_read(codec,
+				WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL));
+			snd_soc_write(codec,
+				WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL,
+			snd_soc_read(codec,
+				WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL));
+		}
+		break;
+	}
+	return 0;
+}
+
+static int tavil_codec_find_amic_input(struct snd_soc_codec *codec,
+				       int adc_mux_n)
+{
+	u16 mask, shift, adc_mux_in_reg;
+	u16 amic_mux_sel_reg;
+	bool is_amic;
+
+	if (adc_mux_n < 0 || adc_mux_n > WCD934X_MAX_VALID_ADC_MUX ||
+	    adc_mux_n == WCD934X_INVALID_ADC_MUX)
+		return 0;
+
+	if (adc_mux_n < 3) {
+		adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+				 adc_mux_n;
+		mask = 0x03;
+		shift = 0;
+		amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+				   2 * adc_mux_n;
+	} else if (adc_mux_n < 4) {
+		adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1;
+		mask = 0x03;
+		shift = 0;
+		amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+				   2 * adc_mux_n;
+	} else if (adc_mux_n < 7) {
+		adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+				 (adc_mux_n - 4);
+		mask = 0x0C;
+		shift = 2;
+		amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+				   adc_mux_n - 4;
+	} else if (adc_mux_n < 8) {
+		adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1;
+		mask = 0x0C;
+		shift = 2;
+		amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+				   adc_mux_n - 4;
+	} else if (adc_mux_n < 12) {
+		adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+				 ((adc_mux_n == 8) ? (adc_mux_n - 8) :
+				  (adc_mux_n - 9));
+		mask = 0x30;
+		shift = 4;
+		amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+				   adc_mux_n - 4;
+	} else if (adc_mux_n < 13) {
+		adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1;
+		mask = 0x30;
+		shift = 4;
+		amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+				   adc_mux_n - 4;
+	} else {
+		adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1;
+		mask = 0xC0;
+		shift = 6;
+		amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+				   adc_mux_n - 4;
+	}
+
+	is_amic = (((snd_soc_read(codec, adc_mux_in_reg) & mask) >> shift)
+		    == 1);
+	if (!is_amic)
+		return 0;
+
+	return snd_soc_read(codec, amic_mux_sel_reg) & 0x07;
+}
+
+static void tavil_codec_set_tx_hold(struct snd_soc_codec *codec,
+				    u16 amic_reg, bool set)
+{
+	u8 mask = 0x20;
+	u8 val;
+
+	if (amic_reg == WCD934X_ANA_AMIC1 ||
+	    amic_reg == WCD934X_ANA_AMIC3)
+		mask = 0x40;
+
+	val = set ? mask : 0x00;
+
+	switch (amic_reg) {
+	case WCD934X_ANA_AMIC1:
+	case WCD934X_ANA_AMIC2:
+		snd_soc_update_bits(codec, WCD934X_ANA_AMIC2, mask, val);
+		break;
+	case WCD934X_ANA_AMIC3:
+	case WCD934X_ANA_AMIC4:
+		snd_soc_update_bits(codec, WCD934X_ANA_AMIC4, mask, val);
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: invalid amic: %d\n",
+			__func__, amic_reg);
+		break;
+	}
+}
+
+static int tavil_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	int adc_mux_n = w->shift;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int amic_n;
+
+	dev_dbg(codec->dev, "%s: event: %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		amic_n = tavil_codec_find_amic_input(codec, adc_mux_n);
+		if (amic_n) {
+			/*
+			 * Prevent ANC Rx pop by leaving Tx FE in HOLD
+			 * state until PA is up. Track AMIC being used
+			 * so we can release the HOLD later.
+			 */
+			set_bit(ANC_MIC_AMIC1 + amic_n - 1,
+				&tavil->status_mask);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static u16 tavil_codec_get_amic_pwlvl_reg(struct snd_soc_codec *codec, int amic)
+{
+	u16 pwr_level_reg = 0;
+
+	switch (amic) {
+	case 1:
+	case 2:
+		pwr_level_reg = WCD934X_ANA_AMIC1;
+		break;
+
+	case 3:
+	case 4:
+		pwr_level_reg = WCD934X_ANA_AMIC3;
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: invalid amic: %d\n",
+			__func__, amic);
+		break;
+	}
+
+	return pwr_level_reg;
+}
+
+#define  TX_HPF_CUT_OFF_FREQ_MASK 0x60
+#define  CF_MIN_3DB_4HZ     0x0
+#define  CF_MIN_3DB_75HZ    0x1
+#define  CF_MIN_3DB_150HZ   0x2
+
+static void tavil_tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+	struct delayed_work *hpf_delayed_work;
+	struct hpf_work *hpf_work;
+	struct tavil_priv *tavil;
+	struct snd_soc_codec *codec;
+	u16 dec_cfg_reg, amic_reg, go_bit_reg;
+	u8 hpf_cut_off_freq;
+	int amic_n;
+
+	hpf_delayed_work = to_delayed_work(work);
+	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+	tavil = hpf_work->tavil;
+	codec = tavil->codec;
+	hpf_cut_off_freq = hpf_work->hpf_cut_off_freq;
+
+	dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * hpf_work->decimator;
+	go_bit_reg = dec_cfg_reg + 7;
+
+	dev_dbg(codec->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n",
+		__func__, hpf_work->decimator, hpf_cut_off_freq);
+
+	amic_n = tavil_codec_find_amic_input(codec, hpf_work->decimator);
+	if (amic_n) {
+		amic_reg = WCD934X_ANA_AMIC1 + amic_n - 1;
+		tavil_codec_set_tx_hold(codec, amic_reg, false);
+	}
+	snd_soc_update_bits(codec, dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
+			    hpf_cut_off_freq << 5);
+	snd_soc_update_bits(codec, go_bit_reg, 0x02, 0x02);
+	/* Minimum 1 clk cycle delay is required as per HW spec */
+	usleep_range(1000, 1010);
+	snd_soc_update_bits(codec, go_bit_reg, 0x02, 0x00);
+}
+
+static void tavil_tx_mute_update_callback(struct work_struct *work)
+{
+	struct tx_mute_work *tx_mute_dwork;
+	struct tavil_priv *tavil;
+	struct delayed_work *delayed_work;
+	struct snd_soc_codec *codec;
+	u16 tx_vol_ctl_reg, hpf_gate_reg;
+
+	delayed_work = to_delayed_work(work);
+	tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork);
+	tavil = tx_mute_dwork->tavil;
+	codec = tavil->codec;
+
+	tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL +
+			 16 * tx_mute_dwork->decimator;
+	hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 +
+		       16 * tx_mute_dwork->decimator;
+	snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00);
+}
+
+static int tavil_codec_enable_rx_path_clk(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	u16 sidetone_reg;
+
+	dev_dbg(codec->dev, "%s %d %d\n", __func__, event, w->shift);
+	sidetone_reg = WCD934X_CDC_RX0_RX_PATH_CFG1 + 0x14*(w->shift);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (!strcmp(w->name, "RX INT7 MIX2 INP"))
+			__tavil_codec_enable_swr(w, event);
+		tavil_codec_enable_interp_clk(codec, event, w->shift);
+		snd_soc_update_bits(codec, sidetone_reg, 0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, sidetone_reg, 0x10, 0x00);
+		tavil_codec_enable_interp_clk(codec, event, w->shift);
+		if (!strcmp(w->name, "RX INT7 MIX2 INP"))
+			__tavil_codec_enable_swr(w, event);
+		break;
+	default:
+		break;
+	};
+	return 0;
+}
+
+static int tavil_codec_enable_dec(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	unsigned int decimator;
+	char *dec_adc_mux_name = NULL;
+	char *widget_name = NULL;
+	char *wname;
+	int ret = 0, amic_n;
+	u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
+	u16 tx_gain_ctl_reg;
+	char *dec;
+	u8 hpf_cut_off_freq;
+
+	dev_dbg(codec->dev, "%s %d\n", __func__, event);
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+
+	wname = widget_name;
+	dec_adc_mux_name = strsep(&widget_name, " ");
+	if (!dec_adc_mux_name) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, w->name);
+		ret =  -EINVAL;
+		goto out;
+	}
+	dec_adc_mux_name = widget_name;
+
+	dec = strpbrk(dec_adc_mux_name, "012345678");
+	if (!dec) {
+		dev_err(codec->dev, "%s: decimator index not found\n",
+			__func__);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(dec, 10, &decimator);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+			__func__, wname);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(codec->dev, "%s(): widget = %s decimator = %u\n", __func__,
+			w->name, decimator);
+
+	tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator;
+	hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 + 16 * decimator;
+	dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * decimator;
+	tx_gain_ctl_reg = WCD934X_CDC_TX0_TX_VOL_CTL + 16 * decimator;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		amic_n = tavil_codec_find_amic_input(codec, decimator);
+		if (amic_n)
+			pwr_level_reg = tavil_codec_get_amic_pwlvl_reg(codec,
+								       amic_n);
+
+		if (pwr_level_reg) {
+			switch ((snd_soc_read(codec, pwr_level_reg) &
+					      WCD934X_AMIC_PWR_LVL_MASK) >>
+					      WCD934X_AMIC_PWR_LVL_SHIFT) {
+			case WCD934X_AMIC_PWR_LEVEL_LP:
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    WCD934X_DEC_PWR_LVL_MASK,
+						    WCD934X_DEC_PWR_LVL_LP);
+				break;
+
+			case WCD934X_AMIC_PWR_LEVEL_HP:
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    WCD934X_DEC_PWR_LVL_MASK,
+						    WCD934X_DEC_PWR_LVL_HP);
+				break;
+			case WCD934X_AMIC_PWR_LEVEL_DEFAULT:
+			default:
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    WCD934X_DEC_PWR_LVL_MASK,
+						    WCD934X_DEC_PWR_LVL_DF);
+				break;
+			}
+		}
+		/* Enable TX PGA Mute */
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		hpf_cut_off_freq = (snd_soc_read(codec, dec_cfg_reg) &
+				   TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+
+		tavil->tx_hpf_work[decimator].hpf_cut_off_freq =
+							hpf_cut_off_freq;
+		if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+			snd_soc_update_bits(codec, dec_cfg_reg,
+					    TX_HPF_CUT_OFF_FREQ_MASK,
+					    CF_MIN_3DB_150HZ << 5);
+			snd_soc_update_bits(codec, hpf_gate_reg, 0x02, 0x02);
+			/*
+			 * Minimum 1 clk cycle delay is required as per
+			 * HW spec.
+			 */
+			usleep_range(1000, 1010);
+			snd_soc_update_bits(codec, hpf_gate_reg, 0x02, 0x00);
+		}
+		/* schedule work queue to Remove Mute */
+		schedule_delayed_work(&tavil->tx_mute_dwork[decimator].dwork,
+				      msecs_to_jiffies(tx_unmute_delay));
+		if (tavil->tx_hpf_work[decimator].hpf_cut_off_freq !=
+							CF_MIN_3DB_150HZ)
+			schedule_delayed_work(
+					&tavil->tx_hpf_work[decimator].dwork,
+					msecs_to_jiffies(300));
+		/* apply gain after decimator is enabled */
+		snd_soc_write(codec, tx_gain_ctl_reg,
+			      snd_soc_read(codec, tx_gain_ctl_reg));
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		hpf_cut_off_freq =
+			tavil->tx_hpf_work[decimator].hpf_cut_off_freq;
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
+		if (cancel_delayed_work_sync(
+		    &tavil->tx_hpf_work[decimator].dwork)) {
+			if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
+				snd_soc_update_bits(codec, dec_cfg_reg,
+						    TX_HPF_CUT_OFF_FREQ_MASK,
+						    hpf_cut_off_freq << 5);
+				snd_soc_update_bits(codec, hpf_gate_reg,
+						    0x02, 0x02);
+				/*
+				 * Minimum 1 clk cycle delay is required as per
+				 * HW spec.
+				 */
+				usleep_range(1000, 1010);
+				snd_soc_update_bits(codec, hpf_gate_reg,
+						    0x02, 0x00);
+			}
+		}
+		cancel_delayed_work_sync(
+				&tavil->tx_mute_dwork[decimator].dwork);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00);
+		snd_soc_update_bits(codec, dec_cfg_reg,
+				    WCD934X_DEC_PWR_LVL_MASK,
+				    WCD934X_DEC_PWR_LVL_DF);
+		break;
+	};
+out:
+	kfree(wname);
+	return ret;
+}
+
+static u32 tavil_get_dmic_sample_rate(struct snd_soc_codec *codec,
+				      unsigned int dmic,
+				      struct wcd9xxx_pdata *pdata)
+{
+	u8 tx_stream_fs;
+	u8 adc_mux_index = 0, adc_mux_sel = 0;
+	bool dec_found = false;
+	u16 adc_mux_ctl_reg, tx_fs_reg;
+	u32 dmic_fs;
+
+	while (dec_found == 0 && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) {
+		if (adc_mux_index < 4) {
+			adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+						(adc_mux_index * 2);
+		} else if (adc_mux_index < WCD934X_INVALID_ADC_MUX) {
+			adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 +
+						adc_mux_index - 4;
+		} else if (adc_mux_index == WCD934X_INVALID_ADC_MUX) {
+			++adc_mux_index;
+			continue;
+		}
+		adc_mux_sel = ((snd_soc_read(codec, adc_mux_ctl_reg) &
+					0xF8) >> 3) - 1;
+
+		if (adc_mux_sel == dmic) {
+			dec_found = true;
+			break;
+		}
+
+		++adc_mux_index;
+	}
+
+	if (dec_found && adc_mux_index <= 8) {
+		tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL + (16 * adc_mux_index);
+		tx_stream_fs = snd_soc_read(codec, tx_fs_reg) & 0x0F;
+		if (tx_stream_fs <= 4)  {
+			if (pdata->dmic_sample_rate <=
+					WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ)
+				dmic_fs = pdata->dmic_sample_rate;
+			else
+				dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ;
+		} else
+			dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
+	} else {
+		dmic_fs = pdata->dmic_sample_rate;
+	}
+
+	return dmic_fs;
+}
+
+static u8 tavil_get_dmic_clk_val(struct snd_soc_codec *codec,
+				 u32 mclk_rate, u32 dmic_clk_rate)
+{
+	u32 div_factor;
+	u8 dmic_ctl_val;
+
+	dev_dbg(codec->dev,
+		"%s: mclk_rate = %d, dmic_sample_rate = %d\n",
+		__func__, mclk_rate, dmic_clk_rate);
+
+	/* Default value to return in case of error */
+	if (mclk_rate == WCD934X_MCLK_CLK_9P6MHZ)
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2;
+	else
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3;
+
+	if (dmic_clk_rate == 0) {
+		dev_err(codec->dev,
+			"%s: dmic_sample_rate cannot be 0\n",
+			__func__);
+		goto done;
+	}
+
+	div_factor = mclk_rate / dmic_clk_rate;
+	switch (div_factor) {
+	case 2:
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2;
+		break;
+	case 3:
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3;
+		break;
+	case 4:
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_4;
+		break;
+	case 6:
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_6;
+		break;
+	case 8:
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_8;
+		break;
+	case 16:
+		dmic_ctl_val = WCD934X_DMIC_CLK_DIV_16;
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
+			__func__, div_factor, mclk_rate, dmic_clk_rate);
+		break;
+	}
+
+done:
+	return dmic_ctl_val;
+}
+
+static int tavil_codec_enable_adc(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+	dev_dbg(codec->dev, "%s: event:%d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tavil_codec_set_tx_hold(codec, w->reg, true);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int tavil_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent);
+	u8  dmic_clk_en = 0x01;
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	u8 dmic_rate_val, dmic_rate_shift = 1;
+	unsigned int dmic;
+	u32 dmic_sample_rate;
+	int ret;
+	char *wname;
+
+	wname = strpbrk(w->name, "012345");
+	if (!wname) {
+		dev_err(codec->dev, "%s: widget not found\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(wname, 10, &dmic);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: Invalid DMIC line on the codec\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 0:
+	case 1:
+		dmic_clk_cnt = &(tavil->dmic_0_1_clk_cnt);
+		dmic_clk_reg = WCD934X_CPE_SS_DMIC0_CTL;
+		break;
+	case 2:
+	case 3:
+		dmic_clk_cnt = &(tavil->dmic_2_3_clk_cnt);
+		dmic_clk_reg = WCD934X_CPE_SS_DMIC1_CTL;
+		break;
+	case 4:
+	case 5:
+		dmic_clk_cnt = &(tavil->dmic_4_5_clk_cnt);
+		dmic_clk_reg = WCD934X_CPE_SS_DMIC2_CTL;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid DMIC Selection\n",
+			__func__);
+		return -EINVAL;
+	};
+	dev_dbg(codec->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
+			__func__, event,  dmic, *dmic_clk_cnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		dmic_sample_rate = tavil_get_dmic_sample_rate(codec, dmic,
+							      pdata);
+		dmic_rate_val =
+			tavil_get_dmic_clk_val(codec,
+					       pdata->mclk_rate,
+					       dmic_sample_rate);
+
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1) {
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					    0x07 << dmic_rate_shift,
+					    dmic_rate_val << dmic_rate_shift);
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					    dmic_clk_en, dmic_clk_en);
+		}
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		dmic_rate_val =
+			tavil_get_dmic_clk_val(codec,
+					       pdata->mclk_rate,
+					       pdata->mad_dmic_sample_rate);
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0) {
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					    dmic_clk_en, 0);
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					    0x07 << dmic_rate_shift,
+					    dmic_rate_val << dmic_rate_shift);
+		}
+		break;
+	};
+
+	return 0;
+}
+
+/*
+ * tavil_mbhc_micb_adjust_voltage: adjust specific micbias voltage
+ * @codec: handle to snd_soc_codec *
+ * @req_volt: micbias voltage to be set
+ * @micb_num: micbias to be set, e.g. micbias1 or micbias2
+ *
+ * return 0 if adjustment is success or error code in case of failure
+ */
+int tavil_mbhc_micb_adjust_voltage(struct snd_soc_codec *codec,
+				   int req_volt, int micb_num)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int cur_vout_ctl, req_vout_ctl;
+	int micb_reg, micb_val, micb_en;
+	int ret = 0;
+
+	switch (micb_num) {
+	case MIC_BIAS_1:
+		micb_reg = WCD934X_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD934X_ANA_MICB2;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD934X_ANA_MICB3;
+		break;
+	case MIC_BIAS_4:
+		micb_reg = WCD934X_ANA_MICB4;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mutex_lock(&tavil->micb_lock);
+
+	/*
+	 * If requested micbias voltage is same as current micbias
+	 * voltage, then just return. Otherwise, adjust voltage as
+	 * per requested value. If micbias is already enabled, then
+	 * to avoid slow micbias ramp-up or down enable pull-up
+	 * momentarily, change the micbias value and then re-enable
+	 * micbias.
+	 */
+	micb_val = snd_soc_read(codec, micb_reg);
+	micb_en = (micb_val & 0xC0) >> 6;
+	cur_vout_ctl = micb_val & 0x3F;
+
+	req_vout_ctl = wcd934x_get_micb_vout_ctl_val(req_volt);
+	if (req_vout_ctl < 0) {
+		ret = -EINVAL;
+		goto exit;
+	}
+	if (cur_vout_ctl == req_vout_ctl) {
+		ret = 0;
+		goto exit;
+	}
+
+	dev_dbg(codec->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n",
+		 __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl),
+		 req_volt, micb_en);
+
+	if (micb_en == 0x1)
+		snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+
+	snd_soc_update_bits(codec, micb_reg, 0x3F, req_vout_ctl);
+
+	if (micb_en == 0x1) {
+		snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40);
+		/*
+		 * Add 2ms delay as per HW requirement after enabling
+		 * micbias
+		 */
+		usleep_range(2000, 2100);
+	}
+exit:
+	mutex_unlock(&tavil->micb_lock);
+	return ret;
+}
+EXPORT_SYMBOL(tavil_mbhc_micb_adjust_voltage);
+
+/*
+ * tavil_micbias_control: enable/disable micbias
+ * @codec: handle to snd_soc_codec *
+ * @micb_num: micbias to be enabled/disabled, e.g. micbias1 or micbias2
+ * @req: control requested, enable/disable or pullup enable/disable
+ * @is_dapm: triggered by dapm or not
+ *
+ * return 0 if control is success or error code in case of failure
+ */
+int tavil_micbias_control(struct snd_soc_codec *codec,
+			  int micb_num, int req, bool is_dapm)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int micb_index = micb_num - 1;
+	u16 micb_reg;
+	int pre_off_event = 0, post_off_event = 0;
+	int post_on_event = 0, post_dapm_off = 0;
+	int post_dapm_on = 0;
+
+	if ((micb_index < 0) || (micb_index > TAVIL_MAX_MICBIAS - 1)) {
+		dev_err(codec->dev, "%s: Invalid micbias index, micb_ind:%d\n",
+			__func__, micb_index);
+		return -EINVAL;
+	}
+
+	switch (micb_num) {
+	case MIC_BIAS_1:
+		micb_reg = WCD934X_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD934X_ANA_MICB2;
+		pre_off_event = WCD_EVENT_PRE_MICBIAS_2_OFF;
+		post_off_event = WCD_EVENT_POST_MICBIAS_2_OFF;
+		post_on_event = WCD_EVENT_POST_MICBIAS_2_ON;
+		post_dapm_on = WCD_EVENT_POST_DAPM_MICBIAS_2_ON;
+		post_dapm_off = WCD_EVENT_POST_DAPM_MICBIAS_2_OFF;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD934X_ANA_MICB3;
+		break;
+	case MIC_BIAS_4:
+		micb_reg = WCD934X_ANA_MICB4;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid micbias number: %d\n",
+			__func__, micb_num);
+		return -EINVAL;
+	}
+	mutex_lock(&tavil->micb_lock);
+
+	switch (req) {
+	case MICB_PULLUP_ENABLE:
+		tavil->pullup_ref[micb_index]++;
+		if ((tavil->pullup_ref[micb_index] == 1) &&
+		    (tavil->micb_ref[micb_index] == 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+		break;
+	case MICB_PULLUP_DISABLE:
+		if (tavil->pullup_ref[micb_index] > 0)
+			tavil->pullup_ref[micb_index]--;
+		if ((tavil->pullup_ref[micb_index] == 0) &&
+		    (tavil->micb_ref[micb_index] == 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
+		break;
+	case MICB_ENABLE:
+		tavil->micb_ref[micb_index]++;
+		if (tavil->micb_ref[micb_index] == 1) {
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40);
+			if (post_on_event && tavil->mbhc)
+				blocking_notifier_call_chain(
+						&tavil->mbhc->notifier,
+						post_on_event,
+						&tavil->mbhc->wcd_mbhc);
+		}
+		if (is_dapm && post_dapm_on && tavil->mbhc)
+			blocking_notifier_call_chain(&tavil->mbhc->notifier,
+					post_dapm_on, &tavil->mbhc->wcd_mbhc);
+		break;
+	case MICB_DISABLE:
+		if (tavil->micb_ref[micb_index] > 0)
+			tavil->micb_ref[micb_index]--;
+		if ((tavil->micb_ref[micb_index] == 0) &&
+		    (tavil->pullup_ref[micb_index] > 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+		else if ((tavil->micb_ref[micb_index] == 0) &&
+			 (tavil->pullup_ref[micb_index] == 0)) {
+			if (pre_off_event && tavil->mbhc)
+				blocking_notifier_call_chain(
+						&tavil->mbhc->notifier,
+						pre_off_event,
+						&tavil->mbhc->wcd_mbhc);
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
+			if (post_off_event && tavil->mbhc)
+				blocking_notifier_call_chain(
+						&tavil->mbhc->notifier,
+						post_off_event,
+						&tavil->mbhc->wcd_mbhc);
+		}
+		if (is_dapm && post_dapm_off && tavil->mbhc)
+			blocking_notifier_call_chain(&tavil->mbhc->notifier,
+					post_dapm_off, &tavil->mbhc->wcd_mbhc);
+		break;
+	};
+
+	dev_dbg(codec->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
+		__func__, micb_num, tavil->micb_ref[micb_index],
+		tavil->pullup_ref[micb_index]);
+
+	mutex_unlock(&tavil->micb_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(tavil_micbias_control);
+
+static int __tavil_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	int micb_num;
+
+	dev_dbg(codec->dev, "%s: wname: %s, event: %d\n",
+		__func__, w->name, event);
+
+	if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1")))
+		micb_num = MIC_BIAS_1;
+	else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2")))
+		micb_num = MIC_BIAS_2;
+	else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3")))
+		micb_num = MIC_BIAS_3;
+	else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4")))
+		micb_num = MIC_BIAS_4;
+	else
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/*
+		 * MIC BIAS can also be requested by MBHC,
+		 * so use ref count to handle micbias pullup
+		 * and enable requests
+		 */
+		tavil_micbias_control(codec, micb_num, MICB_ENABLE, true);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* wait for cnp time */
+		usleep_range(1000, 1100);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tavil_micbias_control(codec, micb_num, MICB_DISABLE, true);
+		break;
+	};
+
+	return 0;
+}
+
+/*
+ * tavil_codec_enable_standalone_micbias - enable micbias standalone
+ * @codec: pointer to codec instance
+ * @micb_num: number of micbias to be enabled
+ * @enable: true to enable micbias or false to disable
+ *
+ * This function is used to enable micbias (1, 2, 3 or 4) during
+ * standalone independent of whether TX use-case is running or not
+ *
+ * Return: error code in case of failure or 0 for success
+ */
+int tavil_codec_enable_standalone_micbias(struct snd_soc_codec *codec,
+					  int micb_num,
+					  bool enable)
+{
+	const char * const micb_names[] = {
+		DAPM_MICBIAS1_STANDALONE, DAPM_MICBIAS2_STANDALONE,
+		DAPM_MICBIAS3_STANDALONE, DAPM_MICBIAS4_STANDALONE
+	};
+	int micb_index = micb_num - 1;
+	int rc;
+
+	if (!codec) {
+		pr_err("%s: Codec memory is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((micb_index < 0) || (micb_index > TAVIL_MAX_MICBIAS - 1)) {
+		dev_err(codec->dev, "%s: Invalid micbias index, micb_ind:%d\n",
+			__func__, micb_index);
+		return -EINVAL;
+	}
+
+	if (enable)
+		rc = snd_soc_dapm_force_enable_pin(
+						snd_soc_codec_get_dapm(codec),
+						micb_names[micb_index]);
+	else
+		rc = snd_soc_dapm_disable_pin(snd_soc_codec_get_dapm(codec),
+					      micb_names[micb_index]);
+
+	if (!rc)
+		snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+	else
+		dev_err(codec->dev, "%s: micbias%d force %s pin failed\n",
+			__func__, micb_num, (enable ? "enable" : "disable"));
+
+	return rc;
+}
+EXPORT_SYMBOL(tavil_codec_enable_standalone_micbias);
+
+static int tavil_codec_force_enable_micbias(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_resmgr_enable_master_bias(tavil->resmgr);
+		tavil_cdc_mclk_enable(codec, true);
+		ret = __tavil_codec_enable_micbias(w, SND_SOC_DAPM_PRE_PMU);
+		/* Wait for 1ms for better cnp */
+		usleep_range(1000, 1100);
+		tavil_cdc_mclk_enable(codec, false);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = __tavil_codec_enable_micbias(w, SND_SOC_DAPM_POST_PMD);
+		wcd_resmgr_disable_master_bias(tavil->resmgr);
+		break;
+	}
+
+	return ret;
+}
+
+static int tavil_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol, int event)
+{
+	return __tavil_codec_enable_micbias(w, event);
+}
+
+
+static const struct reg_sequence tavil_hph_reset_tbl[] = {
+	{ WCD934X_HPH_CNP_EN, 0x80 },
+	{ WCD934X_HPH_CNP_WG_CTL, 0x9A },
+	{ WCD934X_HPH_CNP_WG_TIME, 0x14 },
+	{ WCD934X_HPH_OCP_CTL, 0x28 },
+	{ WCD934X_HPH_AUTO_CHOP, 0x16 },
+	{ WCD934X_HPH_CHOP_CTL, 0x83 },
+	{ WCD934X_HPH_PA_CTL1, 0x46 },
+	{ WCD934X_HPH_PA_CTL2, 0x50 },
+	{ WCD934X_HPH_L_EN, 0x80 },
+	{ WCD934X_HPH_L_TEST, 0xE0 },
+	{ WCD934X_HPH_L_ATEST, 0x50 },
+	{ WCD934X_HPH_R_EN, 0x80 },
+	{ WCD934X_HPH_R_TEST, 0xE0 },
+	{ WCD934X_HPH_R_ATEST, 0x54 },
+	{ WCD934X_HPH_RDAC_CLK_CTL1, 0x99 },
+	{ WCD934X_HPH_RDAC_CLK_CTL2, 0x9B },
+	{ WCD934X_HPH_RDAC_LDO_CTL, 0x33 },
+	{ WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 },
+	{ WCD934X_HPH_REFBUFF_UHQA_CTL, 0xA8 },
+};
+
+static const struct reg_sequence tavil_hph_reset_tbl_1_0[] = {
+	{ WCD934X_HPH_REFBUFF_LP_CTL, 0x0A },
+	{ WCD934X_HPH_L_DAC_CTL, 0x00 },
+	{ WCD934X_HPH_R_DAC_CTL, 0x00 },
+	{ WCD934X_HPH_NEW_ANA_HPH2, 0x00 },
+	{ WCD934X_HPH_NEW_ANA_HPH3, 0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0xA0 },
+	{ WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 },
+	{ WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xFE },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x2 },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e},
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
+};
+
+static const struct reg_sequence tavil_hph_reset_tbl_1_1[] = {
+	{ WCD934X_HPH_REFBUFF_LP_CTL, 0x0E },
+	{ WCD934X_HPH_L_DAC_CTL, 0x00 },
+	{ WCD934X_HPH_R_DAC_CTL, 0x00 },
+	{ WCD934X_HPH_NEW_ANA_HPH2, 0x00 },
+	{ WCD934X_HPH_NEW_ANA_HPH3, 0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 },
+	{ WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0x81 },
+	{ WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 },
+	{ WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
+	{ WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x81 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xFE },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x2 },
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e},
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
+};
+
+static const struct tavil_reg_mask_val tavil_pa_disable[] = {
+	{ WCD934X_CDC_RX1_RX_PATH_CTL, 0x30, 0x10 }, /* RX1 mute enable */
+	{ WCD934X_CDC_RX2_RX_PATH_CTL, 0x30, 0x10 }, /* RX2 mute enable */
+	{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 }, /* GM3 boost disable */
+	{ WCD934X_ANA_HPH, 0x80, 0x00 }, /* HPHL PA disable */
+	{ WCD934X_ANA_HPH, 0x40, 0x00 }, /* HPHR PA disable */
+	{ WCD934X_ANA_HPH, 0x20, 0x00 }, /* HPHL REF dsable */
+	{ WCD934X_ANA_HPH, 0x10, 0x00 }, /* HPHR REF disable */
+};
+
+static const struct tavil_reg_mask_val tavil_ocp_en_seq[] = {
+	{ WCD934X_RX_OCP_CTL, 0x0F, 0x02 }, /* OCP number of attempts is 2 */
+	{ WCD934X_HPH_OCP_CTL, 0xFA, 0x3A }, /* OCP current limit */
+	{ WCD934X_HPH_L_TEST, 0x01, 0x01 }, /* Enable HPHL OCP */
+	{ WCD934X_HPH_R_TEST, 0x01, 0x01 }, /* Enable HPHR OCP */
+};
+
+static const struct tavil_reg_mask_val tavil_ocp_en_seq_1[] = {
+	{ WCD934X_RX_OCP_CTL, 0x0F, 0x02 }, /* OCP number of attempts is 2 */
+	{ WCD934X_HPH_OCP_CTL, 0xFA, 0x3A }, /* OCP current limit */
+};
+
+/* LO-HIFI */
+static const struct tavil_reg_mask_val tavil_pre_pa_en_lohifi[] = {
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00 },
+	{ WCD934X_FLYBACK_VNEG_CTRL_4, 0xf0, 0x80 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x20, 0x20 },
+	{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xf0, 0x40 },
+	{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 },
+	{ WCD934X_RX_BIAS_HPH_LOWPOWER, 0xf0, 0xc0 },
+	{ WCD934X_HPH_PA_CTL1, 0x0e, 0x02 },
+	{ WCD934X_HPH_REFBUFF_LP_CTL, 0x06, 0x06 },
+};
+
+static const struct tavil_reg_mask_val tavil_pre_pa_en[] = {
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00 },
+	{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x20, 0x0 },
+	{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xf0, 0x40 },
+	{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 },
+	{ WCD934X_RX_BIAS_HPH_LOWPOWER, 0xf0, 0x80 },
+	{ WCD934X_HPH_PA_CTL1, 0x0e, 0x06 },
+	{ WCD934X_HPH_REFBUFF_LP_CTL, 0x06, 0x06 },
+};
+
+static const struct tavil_reg_mask_val tavil_post_pa_en[] = {
+	{ WCD934X_HPH_L_TEST, 0x01, 0x01 }, /* Enable HPHL OCP */
+	{ WCD934X_HPH_R_TEST, 0x01, 0x01 }, /* Enable HPHR OCP */
+	{ WCD934X_CDC_RX1_RX_PATH_CTL, 0x30, 0x20 }, /* RX1 mute disable */
+	{ WCD934X_CDC_RX2_RX_PATH_CTL, 0x30, 0x20 }, /* RX2 mute disable */
+	{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x80 }, /* GM3 boost enable */
+	{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02 },
+};
+
+static void tavil_codec_hph_reg_range_read(struct regmap *map, u8 *buf)
+{
+	regmap_bulk_read(map, WCD934X_HPH_CNP_EN, buf, TAVIL_HPH_REG_RANGE_1);
+	regmap_bulk_read(map, WCD934X_HPH_NEW_ANA_HPH2,
+			 buf + TAVIL_HPH_REG_RANGE_1, TAVIL_HPH_REG_RANGE_2);
+	regmap_bulk_read(map, WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL,
+			 buf + TAVIL_HPH_REG_RANGE_1 + TAVIL_HPH_REG_RANGE_2,
+			 TAVIL_HPH_REG_RANGE_3);
+}
+
+static void tavil_codec_hph_reg_recover(struct tavil_priv *tavil,
+					struct regmap *map, int pa_status)
+{
+	int i;
+	unsigned int reg;
+
+	blocking_notifier_call_chain(&tavil->mbhc->notifier,
+				     WCD_EVENT_OCP_OFF,
+				     &tavil->mbhc->wcd_mbhc);
+
+	if (pa_status & 0xC0)
+		goto pa_en_restore;
+
+	dev_dbg(tavil->dev, "%s: HPH PA in disable state (0x%x)\n",
+		__func__, pa_status);
+
+	regmap_write_bits(map, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x10);
+	regmap_write_bits(map, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x10);
+	regmap_write_bits(map, WCD934X_ANA_HPH, 0xC0, 0x00);
+	regmap_write_bits(map, WCD934X_ANA_HPH, 0x30, 0x00);
+	regmap_write_bits(map, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x00);
+	regmap_write_bits(map, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x00);
+
+	/* Restore to HW defaults */
+	regmap_multi_reg_write(map, tavil_hph_reset_tbl,
+			       ARRAY_SIZE(tavil_hph_reset_tbl));
+	if (TAVIL_IS_1_1(tavil->wcd9xxx))
+		regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_1,
+				ARRAY_SIZE(tavil_hph_reset_tbl_1_1));
+	if (TAVIL_IS_1_0(tavil->wcd9xxx))
+		regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_0,
+				ARRAY_SIZE(tavil_hph_reset_tbl_1_0));
+
+	for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq); i++)
+		regmap_write_bits(map, tavil_ocp_en_seq[i].reg,
+				  tavil_ocp_en_seq[i].mask,
+				  tavil_ocp_en_seq[i].val);
+	goto end;
+
+
+pa_en_restore:
+	dev_dbg(tavil->dev, "%s: HPH PA in enable state (0x%x)\n",
+		__func__, pa_status);
+
+	/* Disable PA and other registers before restoring */
+	for (i = 0; i < ARRAY_SIZE(tavil_pa_disable); i++) {
+		if (TAVIL_IS_1_1(tavil->wcd9xxx) &&
+		    (tavil_pa_disable[i].reg == WCD934X_HPH_CNP_WG_CTL))
+			continue;
+		regmap_write_bits(map, tavil_pa_disable[i].reg,
+				  tavil_pa_disable[i].mask,
+				  tavil_pa_disable[i].val);
+	}
+
+	regmap_multi_reg_write(map, tavil_hph_reset_tbl,
+			       ARRAY_SIZE(tavil_hph_reset_tbl));
+	if (TAVIL_IS_1_1(tavil->wcd9xxx))
+		regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_1,
+				ARRAY_SIZE(tavil_hph_reset_tbl_1_1));
+	if (TAVIL_IS_1_0(tavil->wcd9xxx))
+		regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_0,
+				ARRAY_SIZE(tavil_hph_reset_tbl_1_0));
+
+	for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq_1); i++)
+		regmap_write_bits(map, tavil_ocp_en_seq_1[i].reg,
+				  tavil_ocp_en_seq_1[i].mask,
+				  tavil_ocp_en_seq_1[i].val);
+
+	if (tavil->hph_mode == CLS_H_LOHIFI) {
+		for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en_lohifi); i++) {
+			reg = tavil_pre_pa_en_lohifi[i].reg;
+			if ((TAVIL_IS_1_1(tavil->wcd9xxx)) &&
+			    ((reg == WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL) ||
+			     (reg == WCD934X_HPH_CNP_WG_CTL) ||
+			     (reg == WCD934X_HPH_REFBUFF_LP_CTL)))
+				continue;
+			regmap_write_bits(map,
+					  tavil_pre_pa_en_lohifi[i].reg,
+					  tavil_pre_pa_en_lohifi[i].mask,
+					  tavil_pre_pa_en_lohifi[i].val);
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en); i++) {
+			reg = tavil_pre_pa_en[i].reg;
+			if ((TAVIL_IS_1_1(tavil->wcd9xxx)) &&
+			    ((reg == WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL) ||
+			     (reg == WCD934X_HPH_CNP_WG_CTL) ||
+			     (reg == WCD934X_HPH_REFBUFF_LP_CTL)))
+				continue;
+			regmap_write_bits(map, tavil_pre_pa_en[i].reg,
+					  tavil_pre_pa_en[i].mask,
+					  tavil_pre_pa_en[i].val);
+		}
+	}
+
+	if (TAVIL_IS_1_1(tavil->wcd9xxx)) {
+		regmap_write(map, WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x84);
+		regmap_write(map, WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x84);
+	}
+
+	regmap_write_bits(map, WCD934X_ANA_HPH, 0x0C, pa_status & 0x0C);
+	regmap_write_bits(map, WCD934X_ANA_HPH, 0x30, 0x30);
+	/* wait for 100usec after HPH DAC is enabled */
+	usleep_range(100, 110);
+	regmap_write(map, WCD934X_ANA_HPH, pa_status);
+	/* Sleep for 7msec after PA is enabled */
+	usleep_range(7000, 7100);
+
+	for (i = 0; i < ARRAY_SIZE(tavil_post_pa_en); i++) {
+		if ((TAVIL_IS_1_1(tavil->wcd9xxx)) &&
+		    (tavil_post_pa_en[i].reg == WCD934X_HPH_CNP_WG_CTL))
+			continue;
+		regmap_write_bits(map, tavil_post_pa_en[i].reg,
+				  tavil_post_pa_en[i].mask,
+				  tavil_post_pa_en[i].val);
+	}
+
+end:
+	tavil->mbhc->is_hph_recover = true;
+	blocking_notifier_call_chain(
+			&tavil->mbhc->notifier,
+			WCD_EVENT_OCP_ON,
+			&tavil->mbhc->wcd_mbhc);
+}
+
+static int tavil_codec_reset_hph_registers(struct snd_soc_dapm_widget *w,
+					   struct snd_kcontrol *kcontrol,
+					   int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	u8 cache_val[TAVIL_HPH_TOTAL_REG];
+	u8 hw_val[TAVIL_HPH_TOTAL_REG];
+	int pa_status;
+	int ret;
+
+	dev_dbg(wcd9xxx->dev, "%s: event: %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		memset(cache_val, 0, TAVIL_HPH_TOTAL_REG);
+		memset(hw_val, 0, TAVIL_HPH_TOTAL_REG);
+
+		regmap_read(wcd9xxx->regmap, WCD934X_ANA_HPH, &pa_status);
+
+		tavil_codec_hph_reg_range_read(wcd9xxx->regmap, cache_val);
+
+		/* Read register values from HW directly */
+		regcache_cache_bypass(wcd9xxx->regmap, true);
+		tavil_codec_hph_reg_range_read(wcd9xxx->regmap, hw_val);
+		regcache_cache_bypass(wcd9xxx->regmap, false);
+
+		/* compare both the registers to know if there is corruption */
+		ret = memcmp(cache_val, hw_val, TAVIL_HPH_TOTAL_REG);
+
+		/* If both the values are same, it means no corruption */
+		if (ret) {
+			dev_dbg(codec->dev, "%s: cache and hw reg are not same\n",
+				__func__);
+			tavil_codec_hph_reg_recover(tavil, wcd9xxx->regmap,
+						    pa_status);
+		} else {
+			dev_dbg(codec->dev, "%s: cache and hw reg are same\n",
+				__func__);
+			tavil->mbhc->is_hph_recover = false;
+		}
+		break;
+	default:
+		break;
+	};
+
+	return 0;
+}
+
+static int tavil_iir_enable_audio_mixer_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	/* IIR filter band registers are at integer multiples of 16 */
+	u16 iir_reg = WCD934X_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx;
+
+	ucontrol->value.integer.value[0] = (snd_soc_read(codec, iir_reg) &
+					    (1 << band_idx)) != 0;
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int tavil_iir_enable_audio_mixer_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	bool iir_band_en_status;
+	int value = ucontrol->value.integer.value[0];
+	u16 iir_reg = WCD934X_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx;
+
+	/* Mask first 5 bits, 6-8 are reserved */
+	snd_soc_update_bits(codec, iir_reg, (1 << band_idx),
+			    (value << band_idx));
+
+	iir_band_en_status = ((snd_soc_read(codec, iir_reg) &
+			      (1 << band_idx)) != 0);
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
+		iir_idx, band_idx, iir_band_en_status);
+	return 0;
+}
+
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+				   int iir_idx, int band_idx,
+				   int coeff_idx)
+{
+	uint32_t value = 0;
+
+	/* Address does not automatically update if reading */
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t)) & 0x7F);
+
+	value |= snd_soc_read(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx));
+
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 1) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+			       (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL +
+				16 * iir_idx)) << 8);
+
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 2) & 0x7F);
+
+	value |= (snd_soc_read(codec,
+			       (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL +
+				16 * iir_idx)) << 16);
+
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		((band_idx * BAND_MAX + coeff_idx)
+		* sizeof(uint32_t) + 3) & 0x7F);
+
+	/* Mask bits top 2 bits since they are reserved */
+	value |= ((snd_soc_read(codec,
+				(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL +
+				 16 * iir_idx)) & 0x3F) << 24);
+
+	return value;
+}
+
+static int tavil_iir_band_audio_mixer_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	ucontrol->value.integer.value[0] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+	ucontrol->value.integer.value[1] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+	ucontrol->value.integer.value[2] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+	ucontrol->value.integer.value[3] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+	ucontrol->value.integer.value[4] =
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+	dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[0],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[1],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[2],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[3],
+		__func__, iir_idx, band_idx,
+		(uint32_t)ucontrol->value.integer.value[4]);
+	return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+			       int iir_idx, int band_idx,
+			       uint32_t value)
+{
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value & 0xFF));
+
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 8) & 0xFF);
+
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 16) & 0xFF);
+
+	/* Mask top 2 bits, 7-8 are reserved */
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx),
+		(value >> 24) & 0x3F);
+}
+
+static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int iir_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->reg;
+	int band_idx = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+	int coeff_idx;
+
+	/*
+	 * Mask top bit it is reserved
+	 * Updates addr automatically for each B2 write
+	 */
+	snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+	/* Store the coefficients in sidetone coeff array */
+	for (coeff_idx = 0; coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX;
+		coeff_idx++) {
+		tavil->sidetone_coeff_array[iir_idx][band_idx][coeff_idx] =
+			ucontrol->value.integer.value[coeff_idx];
+		set_iir_band_coeff(codec, iir_idx, band_idx,
+			tavil->sidetone_coeff_array[iir_idx][band_idx]
+							[coeff_idx]);
+	}
+
+	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+		"%s: IIR #%d band #%d b1 = 0x%x\n"
+		"%s: IIR #%d band #%d b2 = 0x%x\n"
+		"%s: IIR #%d band #%d a1 = 0x%x\n"
+		"%s: IIR #%d band #%d a2 = 0x%x\n",
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+		__func__, iir_idx, band_idx,
+		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+	return 0;
+}
+
+static void tavil_restore_iir_coeff(struct tavil_priv *tavil, int iir_idx)
+{
+	int band_idx = 0, coeff_idx = 0;
+	struct snd_soc_codec *codec = tavil->codec;
+
+	for (band_idx = 0; band_idx < BAND_MAX; band_idx++) {
+		snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+		for (coeff_idx = 0;
+			coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX;
+			coeff_idx++) {
+			set_iir_band_coeff(codec, iir_idx, band_idx,
+				tavil->sidetone_coeff_array[iir_idx][band_idx]
+								[coeff_idx]);
+		}
+	}
+}
+
+static int tavil_compander_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tavil->comp_enabled[comp];
+	return 0;
+}
+
+static int tavil_compander_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
+		 __func__, comp + 1, tavil->comp_enabled[comp], value);
+	tavil->comp_enabled[comp] = value;
+
+	/* Any specific register configuration for compander */
+	switch (comp) {
+	case COMPANDER_1:
+		/* Set Gain Source Select based on compander enable/disable */
+		snd_soc_update_bits(codec, WCD934X_HPH_L_EN, 0x20,
+				(value ? 0x00:0x20));
+		break;
+	case COMPANDER_2:
+		snd_soc_update_bits(codec, WCD934X_HPH_R_EN, 0x20,
+				(value ? 0x00:0x20));
+		break;
+	case COMPANDER_3:
+	case COMPANDER_4:
+	case COMPANDER_7:
+	case COMPANDER_8:
+		break;
+	default:
+		/*
+		 * if compander is not enabled for any interpolator,
+		 * it does not cause any audio failure, so do not
+		 * return error in this case, but just print a log
+		 */
+		dev_warn(codec->dev, "%s: unknown compander: %d\n",
+			__func__, comp);
+	};
+	return 0;
+}
+
+static int tavil_hph_asrc_mode_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int index = -EINVAL;
+
+	if (!strcmp(kcontrol->id.name, "ASRC0 Output Mode"))
+		index = ASRC0;
+	if (!strcmp(kcontrol->id.name, "ASRC1 Output Mode"))
+		index = ASRC1;
+
+	if (tavil && (index >= 0) && (index < ASRC_MAX))
+		tavil->asrc_output_mode[index] =
+			ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int tavil_hph_asrc_mode_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int val = 0;
+	int index = -EINVAL;
+
+	if (!strcmp(kcontrol->id.name, "ASRC0 Output Mode"))
+		index = ASRC0;
+	if (!strcmp(kcontrol->id.name, "ASRC1 Output Mode"))
+		index = ASRC1;
+
+	if (tavil && (index >= 0) && (index < ASRC_MAX))
+		val = tavil->asrc_output_mode[index];
+
+	ucontrol->value.integer.value[0] = val;
+
+	return 0;
+}
+
+static int tavil_hph_idle_detect_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int val = 0;
+
+	if (tavil)
+		val = tavil->idle_det_cfg.hph_idle_detect_en;
+
+	ucontrol->value.integer.value[0] = val;
+
+	return 0;
+}
+
+static int tavil_hph_idle_detect_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	if (tavil)
+		tavil->idle_det_cfg.hph_idle_detect_en =
+			ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int tavil_dmic_pin_mode_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u16 dmic_pin;
+	u8 reg_val, pinctl_position;
+
+	pinctl_position = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	dmic_pin = pinctl_position & 0x07;
+	reg_val = snd_soc_read(codec,
+			WCD934X_TLMM_DMIC1_CLK_PINCFG + dmic_pin - 1);
+
+	ucontrol->value.integer.value[0] = !!reg_val;
+
+	return 0;
+}
+
+static int tavil_dmic_pin_mode_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	u16 ctl_reg, cfg_reg, dmic_pin;
+	u8 ctl_val, cfg_val, pinctl_position, pinctl_mode, mask;
+
+	/* 0- high or low; 1- high Z */
+	pinctl_mode = ucontrol->value.integer.value[0];
+	pinctl_position = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->shift;
+
+	switch (pinctl_position >> 3) {
+	case 0:
+		ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_0;
+		break;
+	case 1:
+		ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_1;
+		break;
+	case 2:
+		ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_2;
+		break;
+	case 3:
+		ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_3;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid pinctl position = %d\n",
+			__func__, pinctl_position);
+		return -EINVAL;
+	}
+
+	ctl_val = ~(pinctl_mode << (pinctl_position & 0x07));
+	mask = 1 << (pinctl_position & 0x07);
+	snd_soc_update_bits(codec, ctl_reg, mask, ctl_val);
+
+	dmic_pin = pinctl_position & 0x07;
+	cfg_reg = WCD934X_TLMM_DMIC1_CLK_PINCFG + dmic_pin - 1;
+	if (pinctl_mode) {
+		if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+			cfg_val = 0x6;
+		else
+			cfg_val = 0xD;
+	} else
+		cfg_val = 0;
+	snd_soc_update_bits(codec, cfg_reg, 0x1F, cfg_val);
+
+	dev_dbg(codec->dev, "%s: reg=0x%x mask=0x%x val=%d reg=0x%x val=%d\n",
+			__func__, ctl_reg, mask, ctl_val, cfg_reg, cfg_val);
+
+	return 0;
+}
+
+static int tavil_amic_pwr_lvl_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u16 amic_reg = 0;
+
+	if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE"))
+		amic_reg = WCD934X_ANA_AMIC1;
+	if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
+		amic_reg = WCD934X_ANA_AMIC3;
+
+	if (amic_reg)
+		ucontrol->value.integer.value[0] =
+			(snd_soc_read(codec, amic_reg) &
+			 WCD934X_AMIC_PWR_LVL_MASK) >>
+			  WCD934X_AMIC_PWR_LVL_SHIFT;
+	return 0;
+}
+
+static int tavil_amic_pwr_lvl_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u32 mode_val;
+	u16 amic_reg = 0;
+
+	mode_val = ucontrol->value.enumerated.item[0];
+
+	dev_dbg(codec->dev, "%s: mode: %d\n", __func__, mode_val);
+
+	if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE"))
+		amic_reg = WCD934X_ANA_AMIC1;
+	if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE"))
+		amic_reg = WCD934X_ANA_AMIC3;
+
+	if (amic_reg)
+		snd_soc_update_bits(codec, amic_reg, WCD934X_AMIC_PWR_LVL_MASK,
+				    mode_val << WCD934X_AMIC_PWR_LVL_SHIFT);
+	return 0;
+}
+
+static const char *const tavil_conn_mad_text[] = {
+	"NOTUSED1", "ADC1", "ADC2", "ADC3", "ADC4", "NOTUSED5",
+	"NOTUSED6", "NOTUSED2", "DMIC0", "DMIC1", "DMIC2", "DMIC3",
+	"DMIC4", "DMIC5", "NOTUSED3", "NOTUSED4"
+};
+
+static const struct soc_enum tavil_conn_mad_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tavil_conn_mad_text),
+			    tavil_conn_mad_text);
+
+static int tavil_mad_input_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	u8 tavil_mad_input;
+
+	tavil_mad_input = snd_soc_read(codec, WCD934X_SOC_MAD_INP_SEL) & 0x0F;
+	ucontrol->value.integer.value[0] = tavil_mad_input;
+
+	dev_dbg(codec->dev, "%s: tavil_mad_input = %s\n", __func__,
+		tavil_conn_mad_text[tavil_mad_input]);
+
+	return 0;
+}
+
+static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_card *card = codec->component.card;
+	u8 tavil_mad_input;
+	char mad_amic_input_widget[6];
+	const char *mad_input_widget;
+	const char *source_widget = NULL;
+	u32 adc, i, mic_bias_found = 0;
+	int ret = 0;
+	char *mad_input;
+	bool is_adc_input = false;
+
+	tavil_mad_input = ucontrol->value.integer.value[0];
+
+	if (tavil_mad_input >= sizeof(tavil_conn_mad_text)/
+	    sizeof(tavil_conn_mad_text[0])) {
+		dev_err(codec->dev,
+			"%s: tavil_mad_input = %d out of bounds\n",
+			__func__, tavil_mad_input);
+		return -EINVAL;
+	}
+
+	if (strnstr(tavil_conn_mad_text[tavil_mad_input], "NOTUSED",
+				sizeof("NOTUSED"))) {
+		dev_dbg(codec->dev,
+			"%s: Unsupported tavil_mad_input = %s\n",
+			__func__, tavil_conn_mad_text[tavil_mad_input]);
+		/* Make sure the MAD register is updated */
+		snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
+				    0x88, 0x00);
+		return -EINVAL;
+	}
+
+	if (strnstr(tavil_conn_mad_text[tavil_mad_input],
+		    "ADC", sizeof("ADC"))) {
+		mad_input = strpbrk(tavil_conn_mad_text[tavil_mad_input],
+				    "1234");
+		if (!mad_input) {
+			dev_err(codec->dev, "%s: Invalid MAD input %s\n",
+				__func__, tavil_conn_mad_text[tavil_mad_input]);
+			return -EINVAL;
+		}
+
+		ret = kstrtouint(mad_input, 10, &adc);
+		if ((ret < 0) || (adc > 4)) {
+			dev_err(codec->dev, "%s: Invalid ADC = %s\n", __func__,
+				tavil_conn_mad_text[tavil_mad_input]);
+			return -EINVAL;
+		}
+
+		/*AMIC4 and AMIC5 share ADC4*/
+		if ((adc == 4) &&
+		    (snd_soc_read(codec, WCD934X_TX_NEW_AMIC_4_5_SEL) & 0x10))
+			adc = 5;
+
+		snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
+
+		mad_input_widget = mad_amic_input_widget;
+		is_adc_input = true;
+	} else {
+		/* DMIC type input widget*/
+		mad_input_widget = tavil_conn_mad_text[tavil_mad_input];
+	}
+
+	dev_dbg(codec->dev,
+		"%s: tavil input widget = %s, adc_input = %s\n", __func__,
+		mad_input_widget, is_adc_input ? "true" : "false");
+
+	for (i = 0; i < card->num_of_dapm_routes; i++) {
+		if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) {
+			source_widget = card->of_dapm_routes[i].source;
+			if (!source_widget) {
+				dev_err(codec->dev,
+					"%s: invalid source widget\n",
+					__func__);
+				return -EINVAL;
+			}
+
+			if (strnstr(source_widget,
+				"MIC BIAS1", sizeof("MIC BIAS1"))) {
+				mic_bias_found = 1;
+				break;
+			} else if (strnstr(source_widget,
+				"MIC BIAS2", sizeof("MIC BIAS2"))) {
+				mic_bias_found = 2;
+				break;
+			} else if (strnstr(source_widget,
+				"MIC BIAS3", sizeof("MIC BIAS3"))) {
+				mic_bias_found = 3;
+				break;
+			} else if (strnstr(source_widget,
+				"MIC BIAS4", sizeof("MIC BIAS4"))) {
+				mic_bias_found = 4;
+				break;
+			}
+		}
+	}
+
+	if (!mic_bias_found) {
+		dev_err(codec->dev, "%s: mic bias not found for input %s\n",
+			__func__, mad_input_widget);
+		return -EINVAL;
+	}
+
+	dev_dbg(codec->dev, "%s: mic_bias found = %d\n", __func__,
+		mic_bias_found);
+
+	snd_soc_update_bits(codec, WCD934X_SOC_MAD_INP_SEL,
+			    0x0F, tavil_mad_input);
+	snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
+			    0x07, mic_bias_found);
+	/* for all adc inputs, mad should be in micbias mode with BG enabled */
+	if (is_adc_input)
+		snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
+				    0x88, 0x88);
+	else
+		snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
+				    0x88, 0x00);
+	return 0;
+}
+
+static int tavil_ear_pa_gain_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	ear_pa_gain = snd_soc_read(codec, WCD934X_ANA_EAR);
+
+	ear_pa_gain = (ear_pa_gain & 0x70) >> 4;
+
+	ucontrol->value.integer.value[0] = ear_pa_gain;
+
+	dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__,
+		ear_pa_gain);
+
+	return 0;
+}
+
+static int tavil_ear_pa_gain_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	u8 ear_pa_gain;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0]  = %ld\n",
+			__func__, ucontrol->value.integer.value[0]);
+
+	ear_pa_gain =  ucontrol->value.integer.value[0] << 4;
+
+	snd_soc_update_bits(codec, WCD934X_ANA_EAR, 0x70, ear_pa_gain);
+	return 0;
+}
+
+static int tavil_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tavil->ear_spkr_gain;
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int tavil_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	tavil->ear_spkr_gain =  ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: gain = %d\n", __func__, tavil->ear_spkr_gain);
+
+	return 0;
+}
+
+static int tavil_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tavil->hph_mode;
+	return 0;
+}
+
+static int tavil_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	u32 mode_val;
+
+	mode_val = ucontrol->value.enumerated.item[0];
+
+	dev_dbg(codec->dev, "%s: mode: %d\n", __func__, mode_val);
+
+	if (mode_val == 0) {
+		dev_warn(codec->dev, "%s:Invalid HPH Mode, default to Cls-H LOHiFi\n",
+			__func__);
+		mode_val = CLS_H_LOHIFI;
+	}
+	tavil->hph_mode = mode_val;
+	return 0;
+}
+
+static const char * const rx_hph_mode_mux_text[] = {
+	"CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI",
+	"CLS_H_ULP", "CLS_AB_HIFI",
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text),
+			    rx_hph_mode_mux_text);
+
+static const char *const tavil_anc_func_text[] = {"OFF", "ON"};
+static const struct soc_enum tavil_anc_func_enum =
+	SOC_ENUM_SINGLE_EXT(2, tavil_anc_func_text);
+
+static const char *const tavil_clkmode_text[] = {"EXTERNAL", "INTERNAL"};
+static SOC_ENUM_SINGLE_EXT_DECL(tavil_clkmode_enum, tavil_clkmode_text);
+
+/* Cutoff frequency for high pass filter */
+static const char * const cf_text[] = {
+	"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ"
+};
+
+static const char * const rx_cf_text[] = {
+	"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ",
+	"CF_NEG_3DB_0P48HZ"
+};
+
+static const char * const amic_pwr_lvl_text[] = {
+	"LOW_PWR", "DEFAULT", "HIGH_PERF"
+};
+
+static const char * const hph_idle_detect_text[] = {
+	"OFF", "ON"
+};
+
+static const char * const asrc_mode_text[] = {
+	"INT", "FRAC"
+};
+
+static const char * const tavil_ear_pa_gain_text[] = {
+	"G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
+	"G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB"
+};
+
+static const char * const tavil_ear_spkr_pa_gain_text[] = {
+	"G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB",
+	"G_4_DB", "G_5_DB", "G_6_DB"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(tavil_ear_pa_gain_enum, tavil_ear_pa_gain_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tavil_ear_spkr_pa_gain_enum,
+				tavil_ear_spkr_pa_gain_text);
+static SOC_ENUM_SINGLE_EXT_DECL(amic_pwr_lvl_enum, amic_pwr_lvl_text);
+static SOC_ENUM_SINGLE_EXT_DECL(hph_idle_detect_enum, hph_idle_detect_text);
+static SOC_ENUM_SINGLE_EXT_DECL(asrc_mode_enum, asrc_mode_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, WCD934X_CDC_TX0_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, WCD934X_CDC_TX1_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec2_enum, WCD934X_CDC_TX2_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec3_enum, WCD934X_CDC_TX3_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec4_enum, WCD934X_CDC_TX4_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec5_enum, WCD934X_CDC_TX5_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec6_enum, WCD934X_CDC_TX6_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec7_enum, WCD934X_CDC_TX7_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_dec8_enum, WCD934X_CDC_TX8_TX_PATH_CFG0, 5,
+							cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int0_1_enum, WCD934X_CDC_RX0_RX_PATH_CFG2, 0,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 2,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int1_1_enum, WCD934X_CDC_RX1_RX_PATH_CFG2, 0,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 2,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int2_1_enum, WCD934X_CDC_RX2_RX_PATH_CFG2, 0,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 2,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int3_1_enum, WCD934X_CDC_RX3_RX_PATH_CFG2, 0,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 2,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int4_1_enum, WCD934X_CDC_RX4_RX_PATH_CFG2, 0,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 2,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int7_1_enum, WCD934X_CDC_RX7_RX_PATH_CFG2, 0,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 2,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int8_1_enum, WCD934X_CDC_RX8_RX_PATH_CFG2, 0,
+							rx_cf_text);
+static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 2,
+							rx_cf_text);
+
+static const struct snd_kcontrol_new tavil_snd_controls[] = {
+	SOC_ENUM_EXT("EAR PA Gain", tavil_ear_pa_gain_enum,
+		tavil_ear_pa_gain_get, tavil_ear_pa_gain_put),
+	SOC_ENUM_EXT("EAR SPKR PA Gain", tavil_ear_spkr_pa_gain_enum,
+		     tavil_ear_spkr_pa_gain_get, tavil_ear_spkr_pa_gain_put),
+	SOC_SINGLE_TLV("HPHL Volume", WCD934X_HPH_L_EN, 0, 20, 1, line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", WCD934X_HPH_R_EN, 0, 20, 1, line_gain),
+	SOC_SINGLE_TLV("LINEOUT1 Volume", WCD934X_DIFF_LO_LO1_COMPANDER,
+		3, 16, 1, line_gain),
+	SOC_SINGLE_TLV("LINEOUT2 Volume", WCD934X_DIFF_LO_LO2_COMPANDER,
+		3, 16, 1, line_gain),
+	SOC_SINGLE_TLV("ADC1 Volume", WCD934X_ANA_AMIC1, 0, 20, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", WCD934X_ANA_AMIC2, 0, 20, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", WCD934X_ANA_AMIC3, 0, 20, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC4 Volume", WCD934X_ANA_AMIC4, 0, 20, 0, analog_gain),
+
+	SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL,
+		0, -84, 40, digital_gain), /* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
+		WCD934X_CDC_RX0_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
+		WCD934X_CDC_RX1_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
+		WCD934X_CDC_RX2_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
+		WCD934X_CDC_RX3_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
+		WCD934X_CDC_RX4_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
+		WCD934X_CDC_RX7_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
+		WCD934X_CDC_RX8_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC5 Volume", WCD934X_CDC_TX5_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC6 Volume", WCD934X_CDC_TX6_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL, 0,
+		-84, 40, digital_gain),
+
+	SOC_SINGLE_SX_TLV("IIR0 INP0 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, 40,
+		digital_gain),
+	SOC_SINGLE_SX_TLV("IIR0 INP1 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, 40,
+		digital_gain),
+	SOC_SINGLE_SX_TLV("IIR0 INP2 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, 40,
+		digital_gain),
+	SOC_SINGLE_SX_TLV("IIR0 INP3 Volume",
+		WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, 40,
+		digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP0 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84, 40,
+		digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84, 40,
+		digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84, 40,
+		digital_gain),
+	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
+		WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, 40,
+		digital_gain),
+
+	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tavil_get_anc_slot,
+		tavil_put_anc_slot),
+	SOC_ENUM_EXT("ANC Function", tavil_anc_func_enum, tavil_get_anc_func,
+		tavil_put_anc_func),
+
+	SOC_ENUM_EXT("CLK MODE", tavil_clkmode_enum, tavil_get_clkmode,
+		     tavil_put_clkmode),
+
+	SOC_ENUM("TX0 HPF cut off", cf_dec0_enum),
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+	SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+	SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
+	SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
+	SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
+	SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
+
+	SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum),
+	SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum),
+	SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum),
+	SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum),
+	SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum),
+	SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum),
+	SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum),
+	SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum),
+	SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum),
+	SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum),
+	SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum),
+	SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum),
+	SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum),
+	SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum),
+
+	SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+		tavil_rx_hph_mode_get, tavil_rx_hph_mode_put),
+
+	SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR0 Enable Band2", IIR0, BAND2, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR0 Enable Band3", IIR0, BAND3, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR0 Enable Band4", IIR0, BAND4, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR0 Enable Band5", IIR0, BAND5, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+		tavil_iir_enable_audio_mixer_get,
+		tavil_iir_enable_audio_mixer_put),
+
+	SOC_SINGLE_MULTI_EXT("IIR0 Band1", IIR0, BAND1, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band2", IIR0, BAND2, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band3", IIR0, BAND3, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band4", IIR0, BAND4, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR0 Band5", IIR0, BAND5, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+		tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put),
+
+	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+		tavil_compander_get, tavil_compander_put),
+	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+		tavil_compander_get, tavil_compander_put),
+	SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0,
+		tavil_compander_get, tavil_compander_put),
+	SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0,
+		tavil_compander_get, tavil_compander_put),
+	SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0,
+		tavil_compander_get, tavil_compander_put),
+	SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0,
+		tavil_compander_get, tavil_compander_put),
+
+	SOC_ENUM_EXT("ASRC0 Output Mode", asrc_mode_enum,
+		tavil_hph_asrc_mode_get, tavil_hph_asrc_mode_put),
+	SOC_ENUM_EXT("ASRC1 Output Mode", asrc_mode_enum,
+		tavil_hph_asrc_mode_get, tavil_hph_asrc_mode_put),
+
+	SOC_ENUM_EXT("HPH Idle Detect", hph_idle_detect_enum,
+		tavil_hph_idle_detect_get, tavil_hph_idle_detect_put),
+
+	SOC_ENUM_EXT("MAD Input", tavil_conn_mad_enum,
+		     tavil_mad_input_get, tavil_mad_input_put),
+
+	SOC_SINGLE_EXT("DMIC1_CLK_PIN_MODE", SND_SOC_NOPM, 17, 1, 0,
+		tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put),
+
+	SOC_SINGLE_EXT("DMIC1_DATA_PIN_MODE", SND_SOC_NOPM, 18, 1, 0,
+		tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put),
+
+	SOC_SINGLE_EXT("DMIC2_CLK_PIN_MODE", SND_SOC_NOPM, 19, 1, 0,
+		tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put),
+
+	SOC_SINGLE_EXT("DMIC2_DATA_PIN_MODE", SND_SOC_NOPM, 20, 1, 0,
+		tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put),
+
+	SOC_SINGLE_EXT("DMIC3_CLK_PIN_MODE", SND_SOC_NOPM, 21, 1, 0,
+		tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put),
+
+	SOC_SINGLE_EXT("DMIC3_DATA_PIN_MODE", SND_SOC_NOPM, 22, 1, 0,
+		tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put),
+	SOC_ENUM_EXT("AMIC_1_2 PWR MODE", amic_pwr_lvl_enum,
+		tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put),
+	SOC_ENUM_EXT("AMIC_3_4 PWR MODE", amic_pwr_lvl_enum,
+		tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put),
+	SOC_ENUM_EXT("AMIC_5_6 PWR MODE", amic_pwr_lvl_enum,
+		tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put),
+};
+
+static int tavil_dec_enum_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+	u16 mic_sel_reg = 0;
+	u8 mic_sel;
+
+	val = ucontrol->value.enumerated.item[0];
+	if (val > e->items - 1)
+		return -EINVAL;
+
+	dev_dbg(codec->dev, "%s: wname: %s, val: 0x%x\n", __func__,
+		widget->name, val);
+
+	switch (e->reg) {
+	case WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1:
+		if (e->shift_l == 0)
+			mic_sel_reg = WCD934X_CDC_TX0_TX_PATH_CFG0;
+		else if (e->shift_l == 2)
+			mic_sel_reg = WCD934X_CDC_TX4_TX_PATH_CFG0;
+		else if (e->shift_l == 4)
+			mic_sel_reg = WCD934X_CDC_TX8_TX_PATH_CFG0;
+		break;
+	case WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1:
+		if (e->shift_l == 0)
+			mic_sel_reg = WCD934X_CDC_TX1_TX_PATH_CFG0;
+		else if (e->shift_l == 2)
+			mic_sel_reg = WCD934X_CDC_TX5_TX_PATH_CFG0;
+		break;
+	case WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1:
+		if (e->shift_l == 0)
+			mic_sel_reg = WCD934X_CDC_TX2_TX_PATH_CFG0;
+		else if (e->shift_l == 2)
+			mic_sel_reg = WCD934X_CDC_TX6_TX_PATH_CFG0;
+		break;
+	case WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1:
+		if (e->shift_l == 0)
+			mic_sel_reg = WCD934X_CDC_TX3_TX_PATH_CFG0;
+		else if (e->shift_l == 2)
+			mic_sel_reg = WCD934X_CDC_TX7_TX_PATH_CFG0;
+		break;
+	default:
+		dev_err(codec->dev, "%s: e->reg: 0x%x not expected\n",
+			__func__, e->reg);
+		return -EINVAL;
+	}
+
+	/* ADC: 0, DMIC: 1 */
+	mic_sel = val ? 0x0 : 0x1;
+	if (mic_sel_reg)
+		snd_soc_update_bits(codec, mic_sel_reg, 1 << 7, mic_sel << 7);
+
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int tavil_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist =
+					dapm_kcontrol_get_wlist(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+	unsigned short look_ahead_dly_reg = WCD934X_CDC_RX0_RX_PATH_CFG0;
+
+	val = ucontrol->value.enumerated.item[0];
+	if (val >= e->items)
+		return -EINVAL;
+
+	dev_dbg(codec->dev, "%s: wname: %s, val: 0x%x\n", __func__,
+		widget->name, val);
+
+	if (e->reg == WCD934X_CDC_RX0_RX_PATH_SEC0)
+		look_ahead_dly_reg = WCD934X_CDC_RX0_RX_PATH_CFG0;
+	else if (e->reg == WCD934X_CDC_RX1_RX_PATH_SEC0)
+		look_ahead_dly_reg = WCD934X_CDC_RX1_RX_PATH_CFG0;
+	else if (e->reg == WCD934X_CDC_RX2_RX_PATH_SEC0)
+		look_ahead_dly_reg = WCD934X_CDC_RX2_RX_PATH_CFG0;
+
+	/* Set Look Ahead Delay */
+	snd_soc_update_bits(codec, look_ahead_dly_reg,
+			    0x08, (val ? 0x08 : 0x00));
+	/* Set DEM INP Select */
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static const char * const rx_int0_7_mix_mux_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+	"RX6", "RX7", "PROXIMITY"
+};
+
+static const char * const rx_int_mix_mux_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+	"RX6", "RX7"
+};
+
+static const char * const rx_prim_mix_text[] = {
+	"ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2",
+	"RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_sidetone_mix_text[] = {
+	"ZERO", "SRC0", "SRC1", "SRC_SUM"
+};
+
+static const char * const cdc_if_tx0_mux_text[] = {
+	"ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192"
+};
+static const char * const cdc_if_tx1_mux_text[] = {
+	"ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192"
+};
+static const char * const cdc_if_tx2_mux_text[] = {
+	"ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192"
+};
+static const char * const cdc_if_tx3_mux_text[] = {
+	"ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192"
+};
+static const char * const cdc_if_tx4_mux_text[] = {
+	"ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192"
+};
+static const char * const cdc_if_tx5_mux_text[] = {
+	"ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192"
+};
+static const char * const cdc_if_tx6_mux_text[] = {
+	"ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192"
+};
+static const char * const cdc_if_tx7_mux_text[] = {
+	"ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192"
+};
+static const char * const cdc_if_tx8_mux_text[] = {
+	"ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192"
+};
+static const char * const cdc_if_tx9_mux_text[] = {
+	"ZERO", "DEC7", "DEC7_192"
+};
+static const char * const cdc_if_tx10_mux_text[] = {
+	"ZERO", "DEC6", "DEC6_192"
+};
+static const char * const cdc_if_tx11_mux_text[] = {
+	"DEC_0_5", "DEC_9_12", "MAD_AUDIO", "MAD_BRDCST"
+};
+static const char * const cdc_if_tx11_inp1_mux_text[] = {
+	"ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4",
+	"DEC5", "RX_MIX_TX5", "DEC9_10", "DEC11_12"
+};
+static const char * const cdc_if_tx13_mux_text[] = {
+	"CDC_DEC_5", "MAD_BRDCST"
+};
+static const char * const cdc_if_tx13_inp1_mux_text[] = {
+	"ZERO", "DEC5", "DEC5_192"
+};
+
+static const char * const iir_inp_mux_text[] = {
+	"ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6",
+	"DEC7", "DEC8", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_int_dem_inp_mux_text[] = {
+	"NORMAL_DSM_OUT", "CLSH_DSM_OUT",
+};
+
+static const char * const rx_int0_1_interp_mux_text[] = {
+	"ZERO", "RX INT0_1 MIX1",
+};
+
+static const char * const rx_int1_1_interp_mux_text[] = {
+	"ZERO", "RX INT1_1 MIX1",
+};
+
+static const char * const rx_int2_1_interp_mux_text[] = {
+	"ZERO", "RX INT2_1 MIX1",
+};
+
+static const char * const rx_int3_1_interp_mux_text[] = {
+	"ZERO", "RX INT3_1 MIX1",
+};
+
+static const char * const rx_int4_1_interp_mux_text[] = {
+	"ZERO", "RX INT4_1 MIX1",
+};
+
+static const char * const rx_int7_1_interp_mux_text[] = {
+	"ZERO", "RX INT7_1 MIX1",
+};
+
+static const char * const rx_int8_1_interp_mux_text[] = {
+	"ZERO", "RX INT8_1 MIX1",
+};
+
+static const char * const rx_int0_2_interp_mux_text[] = {
+	"ZERO", "RX INT0_2 MUX",
+};
+
+static const char * const rx_int1_2_interp_mux_text[] = {
+	"ZERO", "RX INT1_2 MUX",
+};
+
+static const char * const rx_int2_2_interp_mux_text[] = {
+	"ZERO", "RX INT2_2 MUX",
+};
+
+static const char * const rx_int3_2_interp_mux_text[] = {
+	"ZERO", "RX INT3_2 MUX",
+};
+
+static const char * const rx_int4_2_interp_mux_text[] = {
+	"ZERO", "RX INT4_2 MUX",
+};
+
+static const char * const rx_int7_2_interp_mux_text[] = {
+	"ZERO", "RX INT7_2 MUX",
+};
+
+static const char * const rx_int8_2_interp_mux_text[] = {
+	"ZERO", "RX INT8_2 MUX",
+};
+
+static const char * const mad_sel_txt[] = {
+	"SPE", "MSM"
+};
+
+static const char * const mad_inp_mux_txt[] = {
+	"MAD", "DEC1"
+};
+
+static const char * const adc_mux_text[] = {
+	"DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2"
+};
+
+static const char * const dmic_mux_text[] = {
+	"ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5"
+};
+
+static const char * const amic_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4"
+};
+
+static const char * const amic4_5_sel_text[] = {
+	"AMIC4", "AMIC5"
+};
+
+static const char * const anc0_fb_mux_text[] = {
+	"ZERO", "ANC_IN_HPHL", "ANC_IN_EAR", "ANC_IN_EAR_SPKR",
+	"ANC_IN_LO1"
+};
+
+static const char * const anc1_fb_mux_text[] = {
+	"ZERO", "ANC_IN_HPHR", "ANC_IN_LO2"
+};
+
+static const char * const rx_echo_mux_text[] = {
+	"ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2", "RX_MIX3", "RX_MIX4",
+	"RX_MIX5", "RX_MIX6", "RX_MIX7", "RX_MIX8"
+};
+
+static const char *const slim_rx_mux_text[] = {
+	"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB"
+};
+
+static const char *const cdc_if_rx0_mux_text[] = {
+	"SLIM RX0", "I2S_0 RX0"
+};
+static const char *const cdc_if_rx1_mux_text[] = {
+	"SLIM RX1", "I2S_0 RX1"
+};
+static const char *const cdc_if_rx2_mux_text[] = {
+	"SLIM RX2", "I2S_0 RX2"
+};
+static const char *const cdc_if_rx3_mux_text[] = {
+	"SLIM RX3", "I2S_0 RX3"
+};
+static const char *const cdc_if_rx4_mux_text[] = {
+	"SLIM RX4", "I2S_0 RX4"
+};
+static const char *const cdc_if_rx5_mux_text[] = {
+	"SLIM RX5", "I2S_0 RX5"
+};
+static const char *const cdc_if_rx6_mux_text[] = {
+	"SLIM RX6", "I2S_0 RX6"
+};
+static const char *const cdc_if_rx7_mux_text[] = {
+	"SLIM RX7", "I2S_0 RX7"
+};
+
+static const char * const asrc0_mux_text[] = {
+	"ZERO", "ASRC_IN_HPHL", "ASRC_IN_LO1",
+};
+
+static const char * const asrc1_mux_text[] = {
+	"ZERO", "ASRC_IN_HPHR", "ASRC_IN_LO2",
+};
+
+static const char * const asrc2_mux_text[] = {
+	"ZERO", "ASRC_IN_SPKR1",
+};
+
+static const char * const asrc3_mux_text[] = {
+	"ZERO", "ASRC_IN_SPKR2",
+};
+
+static const char * const native_mux_text[] = {
+	"OFF", "ON",
+};
+
+static const char *const wdma3_port0_text[] = {
+	"RX_MIX_TX0", "DEC0"
+};
+
+static const char *const wdma3_port1_text[] = {
+	"RX_MIX_TX1", "DEC1"
+};
+
+static const char *const wdma3_port2_text[] = {
+	"RX_MIX_TX2", "DEC2"
+};
+
+static const char *const wdma3_port3_text[] = {
+	"RX_MIX_TX3", "DEC3"
+};
+
+static const char *const wdma3_port4_text[] = {
+	"RX_MIX_TX4", "DEC4"
+};
+
+static const char *const wdma3_port5_text[] = {
+	"RX_MIX_TX5", "DEC5"
+};
+
+static const char *const wdma3_port6_text[] = {
+	"RX_MIX_TX6", "DEC6"
+};
+
+static const char *const wdma3_ch_text[] = {
+	"PORT_0", "PORT_1", "PORT_2", "PORT_3", "PORT_4",
+	"PORT_5", "PORT_6", "PORT_7", "PORT_8",
+};
+
+static const struct snd_kcontrol_new aif4_vi_mixer[] = {
+	SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, WCD934X_TX14, 1, 0,
+			tavil_vi_feed_mixer_get, tavil_vi_feed_mixer_put),
+	SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, WCD934X_TX15, 1, 0,
+			tavil_vi_feed_mixer_get, tavil_vi_feed_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif1_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif2_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif3_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif4_mad_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+WCD_DAPM_ENUM_EXT(slim_rx0, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+WCD_DAPM_ENUM_EXT(slim_rx1, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+WCD_DAPM_ENUM_EXT(slim_rx2, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+WCD_DAPM_ENUM_EXT(slim_rx3, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+WCD_DAPM_ENUM_EXT(slim_rx4, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+WCD_DAPM_ENUM_EXT(slim_rx5, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+WCD_DAPM_ENUM_EXT(slim_rx6, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+WCD_DAPM_ENUM_EXT(slim_rx7, SND_SOC_NOPM, 0, slim_rx_mux_text,
+	slim_rx_mux_get, slim_rx_mux_put);
+
+WCD_DAPM_ENUM(cdc_if_rx0, SND_SOC_NOPM, 0, cdc_if_rx0_mux_text);
+WCD_DAPM_ENUM(cdc_if_rx1, SND_SOC_NOPM, 0, cdc_if_rx1_mux_text);
+WCD_DAPM_ENUM(cdc_if_rx2, SND_SOC_NOPM, 0, cdc_if_rx2_mux_text);
+WCD_DAPM_ENUM(cdc_if_rx3, SND_SOC_NOPM, 0, cdc_if_rx3_mux_text);
+WCD_DAPM_ENUM(cdc_if_rx4, SND_SOC_NOPM, 0, cdc_if_rx4_mux_text);
+WCD_DAPM_ENUM(cdc_if_rx5, SND_SOC_NOPM, 0, cdc_if_rx5_mux_text);
+WCD_DAPM_ENUM(cdc_if_rx6, SND_SOC_NOPM, 0, cdc_if_rx6_mux_text);
+WCD_DAPM_ENUM(cdc_if_rx7, SND_SOC_NOPM, 0, cdc_if_rx7_mux_text);
+
+WCD_DAPM_ENUM(rx_int0_2, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 0,
+	rx_int0_7_mix_mux_text);
+WCD_DAPM_ENUM(rx_int1_2, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 0,
+	rx_int_mix_mux_text);
+WCD_DAPM_ENUM(rx_int2_2, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 0,
+	rx_int_mix_mux_text);
+WCD_DAPM_ENUM(rx_int3_2, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 0,
+	rx_int_mix_mux_text);
+WCD_DAPM_ENUM(rx_int4_2, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 0,
+	rx_int_mix_mux_text);
+WCD_DAPM_ENUM(rx_int7_2, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 0,
+	rx_int0_7_mix_mux_text);
+WCD_DAPM_ENUM(rx_int8_2, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 0,
+	rx_int_mix_mux_text);
+
+WCD_DAPM_ENUM(rx_int0_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 0,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int0_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int0_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int1_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 0,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int1_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int1_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int2_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 0,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int2_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int2_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int3_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 0,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int3_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int3_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int4_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 0,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int4_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int4_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int7_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 0,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int7_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int7_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int8_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 0,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int8_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 4,
+	rx_prim_mix_text);
+WCD_DAPM_ENUM(rx_int8_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 4,
+	rx_prim_mix_text);
+
+WCD_DAPM_ENUM(rx_int0_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0,
+	rx_sidetone_mix_text);
+WCD_DAPM_ENUM(rx_int1_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2,
+	rx_sidetone_mix_text);
+WCD_DAPM_ENUM(rx_int2_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4,
+	rx_sidetone_mix_text);
+WCD_DAPM_ENUM(rx_int3_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6,
+	rx_sidetone_mix_text);
+WCD_DAPM_ENUM(rx_int4_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0,
+	rx_sidetone_mix_text);
+WCD_DAPM_ENUM(rx_int7_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 2,
+	rx_sidetone_mix_text);
+
+WCD_DAPM_ENUM(tx_adc_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 4,
+	adc_mux_text);
+WCD_DAPM_ENUM(tx_adc_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 4,
+	adc_mux_text);
+WCD_DAPM_ENUM(tx_adc_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 4,
+	adc_mux_text);
+WCD_DAPM_ENUM(tx_adc_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 6,
+	adc_mux_text);
+
+
+WCD_DAPM_ENUM(tx_dmic_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 3,
+	dmic_mux_text);
+WCD_DAPM_ENUM(tx_dmic_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 3,
+	dmic_mux_text);
+
+
+WCD_DAPM_ENUM(tx_amic_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0,
+	amic_mux_text);
+WCD_DAPM_ENUM(tx_amic_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0,
+	amic_mux_text);
+
+WCD_DAPM_ENUM(tx_amic4_5, WCD934X_TX_NEW_AMIC_4_5_SEL, 7, amic4_5_sel_text);
+
+WCD_DAPM_ENUM(cdc_if_tx0, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 0,
+	cdc_if_tx0_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 2,
+	cdc_if_tx1_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx2, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 4,
+	cdc_if_tx2_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx3, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 6,
+	cdc_if_tx3_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx4, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 0,
+	cdc_if_tx4_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx5, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 2,
+	cdc_if_tx5_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx6, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 4,
+	cdc_if_tx6_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx7, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 6,
+	cdc_if_tx7_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx8, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 0,
+	cdc_if_tx8_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx9, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 2,
+	cdc_if_tx9_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx10, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 4,
+	cdc_if_tx10_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx11_inp1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 0,
+	cdc_if_tx11_inp1_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx11, WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0,
+	cdc_if_tx11_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx13_inp1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 4,
+	cdc_if_tx13_inp1_mux_text);
+WCD_DAPM_ENUM(cdc_if_tx13, WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0,
+	cdc_if_tx13_mux_text);
+
+WCD_DAPM_ENUM(rx_mix_tx0, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 0,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx1, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 4,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx2, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 0,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx3, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 4,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx4, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 0,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx5, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 4,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx6, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 0,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx7, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 4,
+	rx_echo_mux_text);
+WCD_DAPM_ENUM(rx_mix_tx8, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4, 0,
+	rx_echo_mux_text);
+
+WCD_DAPM_ENUM(iir0_inp0, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0,
+	iir_inp_mux_text);
+WCD_DAPM_ENUM(iir0_inp1, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0,
+	iir_inp_mux_text);
+WCD_DAPM_ENUM(iir0_inp2, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0,
+	iir_inp_mux_text);
+WCD_DAPM_ENUM(iir0_inp3, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0,
+	iir_inp_mux_text);
+WCD_DAPM_ENUM(iir1_inp0, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0,
+	iir_inp_mux_text);
+WCD_DAPM_ENUM(iir1_inp1, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0,
+	iir_inp_mux_text);
+WCD_DAPM_ENUM(iir1_inp2, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0,
+	iir_inp_mux_text);
+WCD_DAPM_ENUM(iir1_inp3, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0,
+	iir_inp_mux_text);
+
+WCD_DAPM_ENUM(rx_int0_1_interp, SND_SOC_NOPM, 0, rx_int0_1_interp_mux_text);
+WCD_DAPM_ENUM(rx_int1_1_interp, SND_SOC_NOPM, 0, rx_int1_1_interp_mux_text);
+WCD_DAPM_ENUM(rx_int2_1_interp, SND_SOC_NOPM, 0, rx_int2_1_interp_mux_text);
+WCD_DAPM_ENUM(rx_int3_1_interp, SND_SOC_NOPM, 0, rx_int3_1_interp_mux_text);
+WCD_DAPM_ENUM(rx_int4_1_interp, SND_SOC_NOPM, 0, rx_int4_1_interp_mux_text);
+WCD_DAPM_ENUM(rx_int7_1_interp, SND_SOC_NOPM, 0, rx_int7_1_interp_mux_text);
+WCD_DAPM_ENUM(rx_int8_1_interp, SND_SOC_NOPM, 0, rx_int8_1_interp_mux_text);
+
+WCD_DAPM_ENUM(rx_int0_2_interp, SND_SOC_NOPM, 0, rx_int0_2_interp_mux_text);
+WCD_DAPM_ENUM(rx_int1_2_interp, SND_SOC_NOPM, 0, rx_int1_2_interp_mux_text);
+WCD_DAPM_ENUM(rx_int2_2_interp, SND_SOC_NOPM, 0, rx_int2_2_interp_mux_text);
+WCD_DAPM_ENUM(rx_int3_2_interp, SND_SOC_NOPM, 0, rx_int3_2_interp_mux_text);
+WCD_DAPM_ENUM(rx_int4_2_interp, SND_SOC_NOPM, 0, rx_int4_2_interp_mux_text);
+WCD_DAPM_ENUM(rx_int7_2_interp, SND_SOC_NOPM, 0, rx_int7_2_interp_mux_text);
+WCD_DAPM_ENUM(rx_int8_2_interp, SND_SOC_NOPM, 0, rx_int8_2_interp_mux_text);
+
+WCD_DAPM_ENUM(mad_sel, WCD934X_CPE_SS_SVA_CFG, 0,
+	mad_sel_txt);
+
+WCD_DAPM_ENUM(mad_inp_mux, WCD934X_CPE_SS_SVA_CFG, 2,
+	mad_inp_mux_txt);
+
+WCD_DAPM_ENUM_EXT(rx_int0_dem_inp, WCD934X_CDC_RX0_RX_PATH_SEC0, 0,
+	rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double,
+	tavil_int_dem_inp_mux_put);
+WCD_DAPM_ENUM_EXT(rx_int1_dem_inp, WCD934X_CDC_RX1_RX_PATH_SEC0, 0,
+	rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double,
+	tavil_int_dem_inp_mux_put);
+WCD_DAPM_ENUM_EXT(rx_int2_dem_inp, WCD934X_CDC_RX2_RX_PATH_SEC0, 0,
+	rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double,
+	tavil_int_dem_inp_mux_put);
+
+WCD_DAPM_ENUM_EXT(tx_adc_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 2,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 2,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 2,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 2,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+WCD_DAPM_ENUM_EXT(tx_adc_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 4,
+	adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put);
+
+WCD_DAPM_ENUM(asrc0, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 0,
+	asrc0_mux_text);
+WCD_DAPM_ENUM(asrc1, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 2,
+	asrc1_mux_text);
+WCD_DAPM_ENUM(asrc2, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 4,
+	asrc2_mux_text);
+WCD_DAPM_ENUM(asrc3, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 6,
+	asrc3_mux_text);
+
+WCD_DAPM_ENUM(int1_1_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int2_1_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int3_1_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int4_1_native, SND_SOC_NOPM, 0, native_mux_text);
+
+WCD_DAPM_ENUM(int1_2_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int2_2_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int3_2_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int4_2_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int7_2_native, SND_SOC_NOPM, 0, native_mux_text);
+WCD_DAPM_ENUM(int8_2_native, SND_SOC_NOPM, 0, native_mux_text);
+
+WCD_DAPM_ENUM(anc0_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 0, anc0_fb_mux_text);
+WCD_DAPM_ENUM(anc1_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 3, anc1_fb_mux_text);
+
+
+WCD_DAPM_ENUM(wdma3_port0, WCD934X_DMA_WDMA3_PRT_CFG, 0, wdma3_port0_text);
+WCD_DAPM_ENUM(wdma3_port1, WCD934X_DMA_WDMA3_PRT_CFG, 1, wdma3_port1_text);
+WCD_DAPM_ENUM(wdma3_port2, WCD934X_DMA_WDMA3_PRT_CFG, 2, wdma3_port2_text);
+WCD_DAPM_ENUM(wdma3_port3, WCD934X_DMA_WDMA3_PRT_CFG, 3, wdma3_port3_text);
+WCD_DAPM_ENUM(wdma3_port4, WCD934X_DMA_WDMA3_PRT_CFG, 4, wdma3_port4_text);
+WCD_DAPM_ENUM(wdma3_port5, WCD934X_DMA_WDMA3_PRT_CFG, 5, wdma3_port5_text);
+WCD_DAPM_ENUM(wdma3_port6, WCD934X_DMA_WDMA3_PRT_CFG, 6, wdma3_port6_text);
+
+WCD_DAPM_ENUM(wdma3_ch0, WCD934X_DMA_CH_0_1_CFG_WDMA_3, 0, wdma3_ch_text);
+WCD_DAPM_ENUM(wdma3_ch1, WCD934X_DMA_CH_0_1_CFG_WDMA_3, 4, wdma3_ch_text);
+WCD_DAPM_ENUM(wdma3_ch2, WCD934X_DMA_CH_2_3_CFG_WDMA_3, 0, wdma3_ch_text);
+WCD_DAPM_ENUM(wdma3_ch3, WCD934X_DMA_CH_2_3_CFG_WDMA_3, 4, wdma3_ch_text);
+
+static const struct snd_kcontrol_new anc_ear_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_ear_spkr_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_spkr_pa_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_hphl_pa_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_hphr_pa_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new mad_cpe1_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new mad_cpe2_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new mad_brdcst_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux0_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux1_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux2_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux3_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux4_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux5_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux6_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux7_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux8_switch =
+	SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new rx_int1_asrc_switch[] = {
+	SOC_DAPM_SINGLE("HPHL Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new rx_int2_asrc_switch[] = {
+	SOC_DAPM_SINGLE("HPHR Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new rx_int3_asrc_switch[] = {
+	SOC_DAPM_SINGLE("LO1 Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new rx_int4_asrc_switch[] = {
+	SOC_DAPM_SINGLE("LO2 Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wdma3_onoff_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static int tavil_dsd_mixer_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm =
+				snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct tavil_dsd_config *dsd_conf = tavil_p->dsd_config;
+	int val;
+
+	val = tavil_dsd_get_current_mixer_value(dsd_conf, mc->shift);
+
+	ucontrol->value.integer.value[0] = ((val < 0) ? 0 : val);
+
+	return 0;
+}
+
+static int tavil_dsd_mixer_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
+	struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec);
+	unsigned int wval = ucontrol->value.integer.value[0];
+	struct tavil_dsd_config *dsd_conf = tavil_p->dsd_config;
+
+	if (!dsd_conf)
+		return 0;
+
+	mutex_lock(&tavil_p->codec_mutex);
+
+	tavil_dsd_set_out_select(dsd_conf, mc->shift);
+	tavil_dsd_set_mixer_value(dsd_conf, mc->shift, wval);
+
+	mutex_unlock(&tavil_p->codec_mutex);
+	snd_soc_dapm_mixer_update_power(dapm, kcontrol, wval, NULL);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new hphl_mixer[] = {
+	SOC_SINGLE_EXT("DSD HPHL Switch", SND_SOC_NOPM, INTERP_HPHL, 1, 0,
+			tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
+static const struct snd_kcontrol_new hphr_mixer[] = {
+	SOC_SINGLE_EXT("DSD HPHR Switch", SND_SOC_NOPM, INTERP_HPHR, 1, 0,
+			tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
+static const struct snd_kcontrol_new lo1_mixer[] = {
+	SOC_SINGLE_EXT("DSD LO1 Switch", SND_SOC_NOPM, INTERP_LO1, 1, 0,
+			tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
+static const struct snd_kcontrol_new lo2_mixer[] = {
+	SOC_SINGLE_EXT("DSD LO2 Switch", SND_SOC_NOPM, INTERP_LO2, 1, 0,
+			tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+		AIF1_PB, 0, tavil_codec_enable_slimrx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
+		AIF2_PB, 0, tavil_codec_enable_slimrx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
+		AIF3_PB, 0, tavil_codec_enable_slimrx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM,
+		AIF4_PB, 0, tavil_codec_enable_slimrx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	WCD_DAPM_MUX("SLIM RX0 MUX", WCD934X_RX0, slim_rx0),
+	WCD_DAPM_MUX("SLIM RX1 MUX", WCD934X_RX1, slim_rx1),
+	WCD_DAPM_MUX("SLIM RX2 MUX", WCD934X_RX2, slim_rx2),
+	WCD_DAPM_MUX("SLIM RX3 MUX", WCD934X_RX3, slim_rx3),
+	WCD_DAPM_MUX("SLIM RX4 MUX", WCD934X_RX4, slim_rx4),
+	WCD_DAPM_MUX("SLIM RX5 MUX", WCD934X_RX5, slim_rx5),
+	WCD_DAPM_MUX("SLIM RX6 MUX", WCD934X_RX6, slim_rx6),
+	WCD_DAPM_MUX("SLIM RX7 MUX", WCD934X_RX7, slim_rx7),
+
+	SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	WCD_DAPM_MUX("CDC_IF RX0 MUX", WCD934X_RX0, cdc_if_rx0),
+	WCD_DAPM_MUX("CDC_IF RX1 MUX", WCD934X_RX1, cdc_if_rx1),
+	WCD_DAPM_MUX("CDC_IF RX2 MUX", WCD934X_RX2, cdc_if_rx2),
+	WCD_DAPM_MUX("CDC_IF RX3 MUX", WCD934X_RX3, cdc_if_rx3),
+	WCD_DAPM_MUX("CDC_IF RX4 MUX", WCD934X_RX4, cdc_if_rx4),
+	WCD_DAPM_MUX("CDC_IF RX5 MUX", WCD934X_RX5, cdc_if_rx5),
+	WCD_DAPM_MUX("CDC_IF RX6 MUX", WCD934X_RX6, cdc_if_rx6),
+	WCD_DAPM_MUX("CDC_IF RX7 MUX", WCD934X_RX7, cdc_if_rx7),
+
+	SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_EAR, 0,
+		&rx_int0_2_mux, tavil_codec_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0,
+		&rx_int1_2_mux, tavil_codec_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0,
+		&rx_int2_2_mux, tavil_codec_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", SND_SOC_NOPM, INTERP_LO1, 0,
+		&rx_int3_2_mux, tavil_codec_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", SND_SOC_NOPM, INTERP_LO2, 0,
+		&rx_int4_2_mux, tavil_codec_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", SND_SOC_NOPM, INTERP_SPKR1, 0,
+		&rx_int7_2_mux, tavil_codec_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", SND_SOC_NOPM, INTERP_SPKR2, 0,
+		&rx_int8_2_mux, tavil_codec_enable_mix_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	WCD_DAPM_MUX("RX INT0_1 MIX1 INP0", 0, rx_int0_1_mix_inp0),
+	WCD_DAPM_MUX("RX INT0_1 MIX1 INP1", 0, rx_int0_1_mix_inp1),
+	WCD_DAPM_MUX("RX INT0_1 MIX1 INP2", 0, rx_int0_1_mix_inp2),
+	WCD_DAPM_MUX("RX INT1_1 MIX1 INP0", 0, rx_int1_1_mix_inp0),
+	WCD_DAPM_MUX("RX INT1_1 MIX1 INP1", 0, rx_int1_1_mix_inp1),
+	WCD_DAPM_MUX("RX INT1_1 MIX1 INP2", 0, rx_int1_1_mix_inp2),
+	WCD_DAPM_MUX("RX INT2_1 MIX1 INP0", 0, rx_int2_1_mix_inp0),
+	WCD_DAPM_MUX("RX INT2_1 MIX1 INP1", 0, rx_int2_1_mix_inp1),
+	WCD_DAPM_MUX("RX INT2_1 MIX1 INP2", 0, rx_int2_1_mix_inp2),
+	WCD_DAPM_MUX("RX INT3_1 MIX1 INP0", 0, rx_int3_1_mix_inp0),
+	WCD_DAPM_MUX("RX INT3_1 MIX1 INP1", 0, rx_int3_1_mix_inp1),
+	WCD_DAPM_MUX("RX INT3_1 MIX1 INP2", 0, rx_int3_1_mix_inp2),
+	WCD_DAPM_MUX("RX INT4_1 MIX1 INP0", 0, rx_int4_1_mix_inp0),
+	WCD_DAPM_MUX("RX INT4_1 MIX1 INP1", 0, rx_int4_1_mix_inp1),
+	WCD_DAPM_MUX("RX INT4_1 MIX1 INP2", 0, rx_int4_1_mix_inp2),
+
+	SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp0_mux, tavil_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp1_mux, tavil_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp2_mux, tavil_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp0_mux, tavil_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp1_mux, tavil_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp2_mux, tavil_codec_enable_swr,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0,
+		rx_int1_asrc_switch, ARRAY_SIZE(rx_int1_asrc_switch)),
+	SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0,
+		rx_int2_asrc_switch, ARRAY_SIZE(rx_int2_asrc_switch)),
+	SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0,
+		rx_int3_asrc_switch, ARRAY_SIZE(rx_int3_asrc_switch)),
+	SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0,
+		rx_int4_asrc_switch, ARRAY_SIZE(rx_int4_asrc_switch)),
+	SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 MIX3", SND_SOC_NOPM, 0, 0, hphl_mixer,
+			   ARRAY_SIZE(hphl_mixer)),
+	SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 MIX3", SND_SOC_NOPM, 0, 0, hphr_mixer,
+			   ARRAY_SIZE(hphr_mixer)),
+	SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3 MIX3", SND_SOC_NOPM, 0, 0, lo1_mixer,
+			   ARRAY_SIZE(lo1_mixer)),
+	SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4 MIX3", SND_SOC_NOPM, 0, 0, lo2_mixer,
+			   ARRAY_SIZE(lo2_mixer)),
+	SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0,
+		NULL, 0, tavil_codec_spk_boost_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX INT8 CHAIN", SND_SOC_NOPM, 0, 0,
+		NULL, 0, tavil_codec_spk_boost_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", SND_SOC_NOPM, INTERP_EAR,
+		0, &rx_int0_mix2_inp_mux, tavil_codec_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", SND_SOC_NOPM, INTERP_HPHL,
+		0, &rx_int1_mix2_inp_mux, tavil_codec_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", SND_SOC_NOPM, INTERP_HPHR,
+		0, &rx_int2_mix2_inp_mux, tavil_codec_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT3 MIX2 INP", SND_SOC_NOPM, INTERP_LO1,
+		0, &rx_int3_mix2_inp_mux, tavil_codec_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT4 MIX2 INP", SND_SOC_NOPM, INTERP_LO2,
+		0, &rx_int4_mix2_inp_mux, tavil_codec_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7 MIX2 INP", SND_SOC_NOPM, INTERP_SPKR1,
+		0, &rx_int7_mix2_inp_mux, tavil_codec_enable_rx_path_clk,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	WCD_DAPM_MUX("CDC_IF TX0 MUX", WCD934X_TX0, cdc_if_tx0),
+	WCD_DAPM_MUX("CDC_IF TX1 MUX", WCD934X_TX1, cdc_if_tx1),
+	WCD_DAPM_MUX("CDC_IF TX2 MUX", WCD934X_TX2, cdc_if_tx2),
+	WCD_DAPM_MUX("CDC_IF TX3 MUX", WCD934X_TX3, cdc_if_tx3),
+	WCD_DAPM_MUX("CDC_IF TX4 MUX", WCD934X_TX4, cdc_if_tx4),
+	WCD_DAPM_MUX("CDC_IF TX5 MUX", WCD934X_TX5, cdc_if_tx5),
+	WCD_DAPM_MUX("CDC_IF TX6 MUX", WCD934X_TX6, cdc_if_tx6),
+	WCD_DAPM_MUX("CDC_IF TX7 MUX", WCD934X_TX7, cdc_if_tx7),
+	WCD_DAPM_MUX("CDC_IF TX8 MUX", WCD934X_TX8, cdc_if_tx8),
+	WCD_DAPM_MUX("CDC_IF TX9 MUX", WCD934X_TX9, cdc_if_tx9),
+	WCD_DAPM_MUX("CDC_IF TX10 MUX", WCD934X_TX10, cdc_if_tx10),
+	WCD_DAPM_MUX("CDC_IF TX11 MUX", WCD934X_TX11, cdc_if_tx11),
+	WCD_DAPM_MUX("CDC_IF TX11 INP1 MUX", WCD934X_TX11, cdc_if_tx11_inp1),
+	WCD_DAPM_MUX("CDC_IF TX13 MUX", WCD934X_TX13, cdc_if_tx13),
+	WCD_DAPM_MUX("CDC_IF TX13 INP1 MUX", WCD934X_TX13, cdc_if_tx13_inp1),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX0", WCD934X_CDC_TX0_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux0_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX1", WCD934X_CDC_TX1_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux1_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX2", WCD934X_CDC_TX2_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux2_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX3", WCD934X_CDC_TX3_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux3_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX4", WCD934X_CDC_TX4_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux4_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX5", WCD934X_CDC_TX5_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux5_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX6", WCD934X_CDC_TX6_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux6_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX7", WCD934X_CDC_TX7_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux7_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX8", WCD934X_CDC_TX8_TX_PATH_CTL, 5, 0,
+		&tx_adc_mux8_mux, tavil_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX10", SND_SOC_NOPM, 10, 0, &tx_adc_mux10_mux,
+		tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX11", SND_SOC_NOPM, 11, 0, &tx_adc_mux11_mux,
+		tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX12", SND_SOC_NOPM, 12, 0, &tx_adc_mux12_mux,
+		tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX13", SND_SOC_NOPM, 13, 0, &tx_adc_mux13_mux,
+		tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU),
+
+	WCD_DAPM_MUX("DMIC MUX0", 0, tx_dmic_mux0),
+	WCD_DAPM_MUX("DMIC MUX1", 0, tx_dmic_mux1),
+	WCD_DAPM_MUX("DMIC MUX2", 0, tx_dmic_mux2),
+	WCD_DAPM_MUX("DMIC MUX3", 0, tx_dmic_mux3),
+	WCD_DAPM_MUX("DMIC MUX4", 0, tx_dmic_mux4),
+	WCD_DAPM_MUX("DMIC MUX5", 0, tx_dmic_mux5),
+	WCD_DAPM_MUX("DMIC MUX6", 0, tx_dmic_mux6),
+	WCD_DAPM_MUX("DMIC MUX7", 0, tx_dmic_mux7),
+	WCD_DAPM_MUX("DMIC MUX8", 0, tx_dmic_mux8),
+	WCD_DAPM_MUX("DMIC MUX10", 0, tx_dmic_mux10),
+	WCD_DAPM_MUX("DMIC MUX11", 0, tx_dmic_mux11),
+	WCD_DAPM_MUX("DMIC MUX12", 0, tx_dmic_mux12),
+	WCD_DAPM_MUX("DMIC MUX13", 0, tx_dmic_mux13),
+
+	WCD_DAPM_MUX("AMIC MUX0", 0, tx_amic_mux0),
+	WCD_DAPM_MUX("AMIC MUX1", 0, tx_amic_mux1),
+	WCD_DAPM_MUX("AMIC MUX2", 0, tx_amic_mux2),
+	WCD_DAPM_MUX("AMIC MUX3", 0, tx_amic_mux3),
+	WCD_DAPM_MUX("AMIC MUX4", 0, tx_amic_mux4),
+	WCD_DAPM_MUX("AMIC MUX5", 0, tx_amic_mux5),
+	WCD_DAPM_MUX("AMIC MUX6", 0, tx_amic_mux6),
+	WCD_DAPM_MUX("AMIC MUX7", 0, tx_amic_mux7),
+	WCD_DAPM_MUX("AMIC MUX8", 0, tx_amic_mux8),
+	WCD_DAPM_MUX("AMIC MUX10", 0, tx_amic_mux10),
+	WCD_DAPM_MUX("AMIC MUX11", 0, tx_amic_mux11),
+	WCD_DAPM_MUX("AMIC MUX12", 0, tx_amic_mux12),
+	WCD_DAPM_MUX("AMIC MUX13", 0, tx_amic_mux13),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD934X_ANA_AMIC1, 7, 0,
+		tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD934X_ANA_AMIC2, 7, 0,
+		tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD934X_ANA_AMIC3, 7, 0,
+		tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD934X_ANA_AMIC4, 7, 0,
+		tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+
+	WCD_DAPM_MUX("AMIC4_5 SEL", 0, tx_amic4_5),
+
+	WCD_DAPM_MUX("ANC0 FB MUX", 0, anc0_fb),
+	WCD_DAPM_MUX("ANC1 FB MUX", 0, anc1_fb),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_INPUT("AMIC4"),
+	SND_SOC_DAPM_INPUT("AMIC5"),
+
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2", SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3", SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4", SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/*
+	 * Not supply widget, this is used to recover HPH registers.
+	 * It is not connected to any other widgets
+	 */
+	SND_SOC_DAPM_SUPPLY("RESET_HPH_REGISTERS", SND_SOC_NOPM,
+		0, 0, tavil_codec_reset_hph_registers,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0,
+		tavil_codec_force_enable_micbias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_STANDALONE, SND_SOC_NOPM, 0, 0,
+		tavil_codec_force_enable_micbias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS3_STANDALONE, SND_SOC_NOPM, 0, 0,
+		tavil_codec_force_enable_micbias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0,
+		tavil_codec_force_enable_micbias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+		AIF1_CAP, 0, tavil_codec_enable_slimtx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
+		AIF2_CAP, 0, tavil_codec_enable_slimtx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
+		AIF3_CAP, 0, tavil_codec_enable_slimtx,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+		aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)),
+	SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+		aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)),
+	SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+		aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)),
+	SND_SOC_DAPM_MIXER("AIF4_MAD Mixer", SND_SOC_NOPM, AIF4_MAD_TX, 0,
+		aif4_mad_mixer, ARRAY_SIZE(aif4_mad_mixer)),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
+		AIF4_VIFEED, 0, tavil_codec_enable_slimvi_feedback,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT("AIF4 MAD", "AIF4 MAD TX", 0,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MIXER("AIF4_VI Mixer", SND_SOC_NOPM, AIF4_VIFEED, 0,
+		aif4_vi_mixer, ARRAY_SIZE(aif4_vi_mixer)),
+	SND_SOC_DAPM_INPUT("VIINPUT"),
+
+	SND_SOC_DAPM_MIXER("SLIM TX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX7", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX8", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX9", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX10", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX11", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM TX13", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_dmic,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_dmic,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_dmic,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_dmic,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_dmic,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_dmic,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	WCD_DAPM_MUX("IIR0 INP0 MUX", 0, iir0_inp0),
+	WCD_DAPM_MUX("IIR0 INP1 MUX", 0, iir0_inp1),
+	WCD_DAPM_MUX("IIR0 INP2 MUX", 0, iir0_inp2),
+	WCD_DAPM_MUX("IIR0 INP3 MUX", 0, iir0_inp3),
+	WCD_DAPM_MUX("IIR1 INP0 MUX", 0, iir1_inp0),
+	WCD_DAPM_MUX("IIR1 INP1 MUX", 0, iir1_inp1),
+	WCD_DAPM_MUX("IIR1 INP2 MUX", 0, iir1_inp2),
+	WCD_DAPM_MUX("IIR1 INP3 MUX", 0, iir1_inp3),
+
+	SND_SOC_DAPM_MIXER_E("IIR0", WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL,
+		4, 0, NULL, 0, tavil_codec_set_iir_gain,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER_E("IIR1", WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL,
+		4, 0, NULL, 0, tavil_codec_set_iir_gain,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER("SRC0", WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL,
+		4, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SRC1", WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL,
+		4, 0, NULL, 0),
+
+	WCD_DAPM_MUX("RX MIX TX0 MUX", 0, rx_mix_tx0),
+	WCD_DAPM_MUX("RX MIX TX1 MUX", 0, rx_mix_tx1),
+	WCD_DAPM_MUX("RX MIX TX2 MUX", 0, rx_mix_tx2),
+	WCD_DAPM_MUX("RX MIX TX3 MUX", 0, rx_mix_tx3),
+	WCD_DAPM_MUX("RX MIX TX4 MUX", 0, rx_mix_tx4),
+	WCD_DAPM_MUX("RX MIX TX5 MUX", 0, rx_mix_tx5),
+	WCD_DAPM_MUX("RX MIX TX6 MUX", 0, rx_mix_tx6),
+	WCD_DAPM_MUX("RX MIX TX7 MUX", 0, rx_mix_tx7),
+	WCD_DAPM_MUX("RX MIX TX8 MUX", 0, rx_mix_tx8),
+	WCD_DAPM_MUX("RX INT0 DEM MUX", 0, rx_int0_dem_inp),
+	WCD_DAPM_MUX("RX INT1 DEM MUX", 0, rx_int1_dem_inp),
+	WCD_DAPM_MUX("RX INT2 DEM MUX", 0, rx_int2_dem_inp),
+
+	SND_SOC_DAPM_MUX_E("RX INT0_1 INTERP", SND_SOC_NOPM, INTERP_EAR, 0,
+		&rx_int0_1_interp_mux, tavil_codec_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1_1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0,
+		&rx_int1_1_interp_mux, tavil_codec_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2_1 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0,
+		&rx_int2_1_interp_mux, tavil_codec_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT3_1 INTERP", SND_SOC_NOPM, INTERP_LO1, 0,
+		&rx_int3_1_interp_mux, tavil_codec_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT4_1 INTERP", SND_SOC_NOPM, INTERP_LO2, 0,
+		&rx_int4_1_interp_mux, tavil_codec_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7_1 INTERP", SND_SOC_NOPM, INTERP_SPKR1, 0,
+		&rx_int7_1_interp_mux, tavil_codec_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8_1 INTERP", SND_SOC_NOPM, INTERP_SPKR2, 0,
+		&rx_int8_1_interp_mux, tavil_codec_enable_main_path,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	WCD_DAPM_MUX("RX INT0_2 INTERP", 0, rx_int0_2_interp),
+	WCD_DAPM_MUX("RX INT1_2 INTERP", 0, rx_int1_2_interp),
+	WCD_DAPM_MUX("RX INT2_2 INTERP", 0, rx_int2_2_interp),
+	WCD_DAPM_MUX("RX INT3_2 INTERP", 0, rx_int3_2_interp),
+	WCD_DAPM_MUX("RX INT4_2 INTERP", 0, rx_int4_2_interp),
+	WCD_DAPM_MUX("RX INT7_2 INTERP", 0, rx_int7_2_interp),
+	WCD_DAPM_MUX("RX INT8_2 INTERP", 0, rx_int8_2_interp),
+
+	SND_SOC_DAPM_SWITCH("ADC US MUX0", WCD934X_CDC_TX0_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux0_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX1", WCD934X_CDC_TX1_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux1_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX2", WCD934X_CDC_TX2_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux2_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX3", WCD934X_CDC_TX3_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux3_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX4", WCD934X_CDC_TX4_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux4_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX5", WCD934X_CDC_TX5_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux5_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX6", WCD934X_CDC_TX6_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux6_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX7", WCD934X_CDC_TX7_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux7_switch),
+	SND_SOC_DAPM_SWITCH("ADC US MUX8", WCD934X_CDC_TX8_TX_PATH_192_CTL, 0,
+		0, &adc_us_mux8_switch),
+
+	/* MAD related widgets */
+	SND_SOC_DAPM_INPUT("MAD_CPE_INPUT"),
+	SND_SOC_DAPM_INPUT("MADINPUT"),
+
+	WCD_DAPM_MUX("MAD_SEL MUX", 0, mad_sel),
+	WCD_DAPM_MUX("MAD_INP MUX", 0, mad_inp_mux),
+
+	SND_SOC_DAPM_SWITCH_E("MAD_BROADCAST", SND_SOC_NOPM, 0, 0,
+			      &mad_brdcst_switch, tavil_codec_ape_enable_mad,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SWITCH_E("MAD_CPE1", SND_SOC_NOPM, 0, 0,
+			      &mad_cpe1_switch, tavil_codec_cpe_mad_ctl,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SWITCH_E("MAD_CPE2", SND_SOC_NOPM, 0, 0,
+			      &mad_cpe2_switch, tavil_codec_cpe_mad_ctl,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_OUTPUT("MAD_CPE_OUT1"),
+	SND_SOC_DAPM_OUTPUT("MAD_CPE_OUT2"),
+
+	SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tavil_codec_ear_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD934X_ANA_HPH,
+		5, 0, tavil_codec_hphl_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD934X_ANA_HPH,
+		4, 0, tavil_codec_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tavil_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM,
+		0, 0, tavil_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0,
+		tavil_codec_enable_ear_pa,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHL PA", WCD934X_ANA_HPH, 7, 0, NULL, 0,
+		tavil_codec_enable_hphl_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHR PA", WCD934X_ANA_HPH, 6, 0, NULL, 0,
+		tavil_codec_enable_hphr_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0,
+		tavil_codec_enable_lineout_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0,
+		tavil_codec_enable_lineout_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0,
+		tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC SPK1 PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tavil_codec_enable_spkr_anc,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tavil_codec_enable_hphl_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tavil_codec_enable_hphr_pa,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("HPHL"),
+	SND_SOC_DAPM_OUTPUT("HPHR"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+	SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
+	SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
+	SND_SOC_DAPM_OUTPUT("ANC EAR"),
+	SND_SOC_DAPM_OUTPUT("ANC HPHL"),
+	SND_SOC_DAPM_OUTPUT("ANC HPHR"),
+
+	SND_SOC_DAPM_SWITCH("ANC OUT EAR Enable", SND_SOC_NOPM, 0, 0,
+		&anc_ear_switch),
+	SND_SOC_DAPM_SWITCH("ANC OUT EAR SPKR Enable", SND_SOC_NOPM, 0, 0,
+		&anc_ear_spkr_switch),
+	SND_SOC_DAPM_SWITCH("ANC SPKR PA Enable", SND_SOC_NOPM, 0, 0,
+		&anc_spkr_pa_switch),
+
+	SND_SOC_DAPM_SWITCH_E("ANC OUT HPHL Enable", SND_SOC_NOPM, INTERP_HPHL,
+		0, &anc_hphl_pa_switch, tavil_anc_out_switch_cb,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	 SND_SOC_DAPM_SWITCH_E("ANC OUT HPHR Enable", SND_SOC_NOPM, INTERP_HPHR,
+		0, &anc_hphr_pa_switch, tavil_anc_out_switch_cb,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+		tavil_codec_enable_rx_bias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("RX INT1 NATIVE SUPPLY", SND_SOC_NOPM,
+		INTERP_HPHL, 0, tavil_enable_native_supply,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("RX INT2 NATIVE SUPPLY", SND_SOC_NOPM,
+		INTERP_HPHR, 0, tavil_enable_native_supply,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("RX INT3 NATIVE SUPPLY", SND_SOC_NOPM,
+		INTERP_LO1, 0, tavil_enable_native_supply,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("RX INT4 NATIVE SUPPLY", SND_SOC_NOPM,
+		INTERP_LO2, 0, tavil_enable_native_supply,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("RX INT7 NATIVE SUPPLY", SND_SOC_NOPM,
+		INTERP_SPKR1, 0, tavil_enable_native_supply,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("RX INT8 NATIVE SUPPLY", SND_SOC_NOPM,
+		INTERP_SPKR2, 0, tavil_enable_native_supply,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	WCD_DAPM_MUX("RX INT1_1 NATIVE MUX", 0, int1_1_native),
+	WCD_DAPM_MUX("RX INT2_1 NATIVE MUX", 0, int2_1_native),
+	WCD_DAPM_MUX("RX INT3_1 NATIVE MUX", 0, int3_1_native),
+	WCD_DAPM_MUX("RX INT4_1 NATIVE MUX", 0, int4_1_native),
+
+	WCD_DAPM_MUX("RX INT1_2 NATIVE MUX", 0, int1_2_native),
+	WCD_DAPM_MUX("RX INT2_2 NATIVE MUX", 0, int2_2_native),
+	WCD_DAPM_MUX("RX INT3_2 NATIVE MUX", 0, int3_2_native),
+	WCD_DAPM_MUX("RX INT4_2 NATIVE MUX", 0, int4_2_native),
+	WCD_DAPM_MUX("RX INT7_2 NATIVE MUX", 0, int7_2_native),
+	WCD_DAPM_MUX("RX INT8_2 NATIVE MUX", 0, int8_2_native),
+
+	SND_SOC_DAPM_MUX_E("ASRC0 MUX", SND_SOC_NOPM, ASRC0, 0,
+		&asrc0_mux, tavil_codec_enable_asrc_resampler,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("ASRC1 MUX", SND_SOC_NOPM, ASRC1, 0,
+		&asrc1_mux, tavil_codec_enable_asrc_resampler,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("ASRC2 MUX", SND_SOC_NOPM, ASRC2, 0,
+		&asrc2_mux, tavil_codec_enable_asrc_resampler,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("ASRC3 MUX", SND_SOC_NOPM, ASRC3, 0,
+		&asrc3_mux, tavil_codec_enable_asrc_resampler,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* WDMA3 widgets */
+	WCD_DAPM_MUX("WDMA3 PORT0 MUX", 0, wdma3_port0),
+	WCD_DAPM_MUX("WDMA3 PORT1 MUX", 1, wdma3_port1),
+	WCD_DAPM_MUX("WDMA3 PORT2 MUX", 2, wdma3_port2),
+	WCD_DAPM_MUX("WDMA3 PORT3 MUX", 3, wdma3_port3),
+	WCD_DAPM_MUX("WDMA3 PORT4 MUX", 4, wdma3_port4),
+	WCD_DAPM_MUX("WDMA3 PORT5 MUX", 5, wdma3_port5),
+	WCD_DAPM_MUX("WDMA3 PORT6 MUX", 6, wdma3_port6),
+
+	WCD_DAPM_MUX("WDMA3 CH0 MUX", 0, wdma3_ch0),
+	WCD_DAPM_MUX("WDMA3 CH1 MUX", 4, wdma3_ch1),
+	WCD_DAPM_MUX("WDMA3 CH2 MUX", 0, wdma3_ch2),
+	WCD_DAPM_MUX("WDMA3 CH3 MUX", 4, wdma3_ch3),
+
+	SND_SOC_DAPM_MIXER("WDMA3_CH_MIXER", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH_E("WDMA3_ON_OFF", SND_SOC_NOPM, 0, 0,
+			      &wdma3_onoff_switch, tavil_codec_wdma3_ctl,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("WDMA3_OUT"),
+};
+
+static int tavil_get_channel_map(struct snd_soc_dai *dai,
+				 unsigned int *tx_num, unsigned int *tx_slot,
+				 unsigned int *rx_num, unsigned int *rx_slot)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(dai->codec);
+	u32 i = 0;
+	struct wcd9xxx_ch *ch;
+	int ret = 0;
+
+	switch (dai->id) {
+	case AIF1_PB:
+	case AIF2_PB:
+	case AIF3_PB:
+	case AIF4_PB:
+		if (!rx_slot || !rx_num) {
+			dev_err(tavil->dev, "%s: Invalid rx_slot 0x%pK or rx_num 0x%pK\n",
+				 __func__, rx_slot, rx_num);
+			ret = -EINVAL;
+			break;
+		}
+		list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list,
+				    list) {
+			dev_dbg(tavil->dev, "%s: slot_num %u ch->ch_num %d\n",
+				 __func__, i, ch->ch_num);
+			rx_slot[i++] = ch->ch_num;
+		}
+		*rx_num = i;
+		dev_dbg(tavil->dev, "%s: dai_name = %s dai_id = %x  rx_num = %d\n",
+			__func__, dai->name, dai->id, i);
+		if (*rx_num == 0) {
+			dev_err(tavil->dev, "%s: Channel list empty for dai_name = %s dai_id = %x\n",
+				__func__, dai->name, dai->id);
+			ret = -EINVAL;
+		}
+		break;
+	case AIF1_CAP:
+	case AIF2_CAP:
+	case AIF3_CAP:
+	case AIF4_MAD_TX:
+	case AIF4_VIFEED:
+		if (!tx_slot || !tx_num) {
+			dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK or tx_num 0x%pK\n",
+				 __func__, tx_slot, tx_num);
+			ret = -EINVAL;
+			break;
+		}
+		list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list,
+				    list) {
+			dev_dbg(tavil->dev, "%s: slot_num %u ch->ch_num %d\n",
+				 __func__, i,  ch->ch_num);
+			tx_slot[i++] = ch->ch_num;
+		}
+		*tx_num = i;
+		dev_dbg(tavil->dev, "%s: dai_name = %s dai_id = %x  tx_num = %d\n",
+			 __func__, dai->name, dai->id, i);
+		if (*tx_num == 0) {
+			dev_err(tavil->dev, "%s: Channel list empty for dai_name = %s dai_id = %x\n",
+				 __func__, dai->name, dai->id);
+			ret = -EINVAL;
+		}
+		break;
+	default:
+		dev_err(tavil->dev, "%s: Invalid DAI ID %x\n",
+			__func__, dai->id);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int tavil_set_channel_map(struct snd_soc_dai *dai,
+				 unsigned int tx_num, unsigned int *tx_slot,
+				 unsigned int rx_num, unsigned int *rx_slot)
+{
+	struct tavil_priv *tavil;
+	struct wcd9xxx *core;
+	struct wcd9xxx_codec_dai_data *dai_data = NULL;
+
+	tavil = snd_soc_codec_get_drvdata(dai->codec);
+	core = dev_get_drvdata(dai->codec->dev->parent);
+
+	if (!tx_slot || !rx_slot) {
+		dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK, rx_slot 0x%pK\n",
+			__func__, tx_slot, rx_slot);
+		return -EINVAL;
+	}
+	dev_dbg(tavil->dev, "%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
+		 __func__, dai->name, dai->id, tx_num, rx_num);
+
+	wcd9xxx_init_slimslave(core, core->slim->laddr,
+				tx_num, tx_slot, rx_num, rx_slot);
+	/* Reserve TX13 for MAD data channel */
+	dai_data = &tavil->dai[AIF4_MAD_TX];
+	if (dai_data)
+		list_add_tail(&core->tx_chs[WCD934X_TX13].list,
+			      &dai_data->wcd9xxx_ch_list);
+
+	return 0;
+}
+
+static int tavil_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	return 0;
+}
+
+static void tavil_shutdown(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+}
+
+static int tavil_set_decimator_rate(struct snd_soc_dai *dai,
+				    u32 sample_rate)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wcd9xxx_ch *ch;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	u32 tx_port = 0, tx_fs_rate = 0;
+	u8 shift = 0, shift_val = 0, tx_mux_sel = 0;
+	int decimator = -1;
+	u16 tx_port_reg = 0, tx_fs_reg = 0;
+
+	switch (sample_rate) {
+	case 8000:
+		tx_fs_rate = 0;
+		break;
+	case 16000:
+		tx_fs_rate = 1;
+		break;
+	case 32000:
+		tx_fs_rate = 3;
+		break;
+	case 48000:
+		tx_fs_rate = 4;
+		break;
+	case 96000:
+		tx_fs_rate = 5;
+		break;
+	case 192000:
+		tx_fs_rate = 6;
+		break;
+	default:
+		dev_err(tavil->dev, "%s: Invalid TX sample rate: %d\n",
+			__func__, sample_rate);
+		return -EINVAL;
+
+	};
+
+	list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) {
+		tx_port = ch->port;
+		dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
+			__func__, dai->id, tx_port);
+
+		if ((tx_port < 0) || (tx_port == 12) || (tx_port >= 14)) {
+			dev_err(codec->dev, "%s: Invalid SLIM TX%u port. DAI ID: %d\n",
+				__func__, tx_port, dai->id);
+			return -EINVAL;
+		}
+		/* Find the SB TX MUX input - which decimator is connected */
+		if (tx_port < 4) {
+			tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0;
+			shift = (tx_port << 1);
+			shift_val = 0x03;
+		} else if ((tx_port >= 4) && (tx_port < 8)) {
+			tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1;
+			shift = ((tx_port - 4) << 1);
+			shift_val = 0x03;
+		} else if ((tx_port >= 8) && (tx_port < 11)) {
+			tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2;
+			shift = ((tx_port - 8) << 1);
+			shift_val = 0x03;
+		} else if (tx_port == 11) {
+			tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3;
+			shift = 0;
+			shift_val = 0x0F;
+		} else if (tx_port == 13) {
+			tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3;
+			shift = 4;
+			shift_val = 0x03;
+		}
+		tx_mux_sel = snd_soc_read(codec, tx_port_reg) &
+					  (shift_val << shift);
+		tx_mux_sel = tx_mux_sel >> shift;
+
+		if (tx_port <= 8) {
+			if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3))
+				decimator = tx_port;
+		} else if (tx_port <= 10) {
+			if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+				decimator = ((tx_port == 9) ? 7 : 6);
+		} else if (tx_port == 11) {
+			if ((tx_mux_sel >= 1) && (tx_mux_sel < 7))
+				decimator = tx_mux_sel - 1;
+		} else if (tx_port == 13) {
+			if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+				decimator = 5;
+		}
+
+		if (decimator >= 0) {
+			tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL +
+				    16 * decimator;
+			dev_dbg(codec->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
+				__func__, decimator, tx_port, sample_rate);
+			snd_soc_update_bits(codec, tx_fs_reg, 0x0F, tx_fs_rate);
+		} else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) {
+			/* Check if the TX Mux input is RX MIX TXn */
+			dev_dbg(codec->dev, "%s: RX_MIX_TX%u going to CDC_IF TX%u\n",
+					__func__, tx_port, tx_port);
+		} else {
+			dev_err(codec->dev, "%s: ERROR: Invalid decimator: %d\n",
+				__func__, decimator);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int tavil_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+					   u8 rate_reg_val,
+					   u32 sample_rate)
+{
+	u8 int_2_inp;
+	u32 j;
+	u16 int_mux_cfg1, int_fs_reg;
+	u8 int_mux_cfg1_val;
+	struct snd_soc_codec *codec = dai->codec;
+	struct wcd9xxx_ch *ch;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) {
+		int_2_inp = INTn_2_INP_SEL_RX0 + ch->port -
+						WCD934X_RX_PORT_START_NUMBER;
+		if ((int_2_inp < INTn_2_INP_SEL_RX0) ||
+		    (int_2_inp > INTn_2_INP_SEL_RX7)) {
+			dev_err(codec->dev, "%s: Invalid RX%u port, Dai ID is %d\n",
+				__func__,
+				(ch->port - WCD934X_RX_PORT_START_NUMBER),
+				dai->id);
+			return -EINVAL;
+		}
+
+		int_mux_cfg1 = WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1;
+		for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) {
+			/* Interpolators 5 and 6 are not aviliable in Tavil */
+			if (j == INTERP_LO3_NA || j == INTERP_LO4_NA) {
+				int_mux_cfg1 += 2;
+				continue;
+			}
+			int_mux_cfg1_val = snd_soc_read(codec, int_mux_cfg1) &
+									0x0F;
+			if (int_mux_cfg1_val == int_2_inp) {
+				/*
+				 * Ear mix path supports only 48, 96, 192,
+				 * 384KHz only
+				 */
+				if ((j == INTERP_EAR) &&
+				    (rate_reg_val < 0x4 ||
+				     rate_reg_val > 0x7)) {
+					dev_err_ratelimited(codec->dev,
+					"%s: Invalid rate for AIF_PB DAI(%d)\n",
+					  __func__, dai->id);
+					return -EINVAL;
+				}
+
+				int_fs_reg = WCD934X_CDC_RX0_RX_PATH_MIX_CTL +
+									20 * j;
+				dev_dbg(codec->dev, "%s: AIF_PB DAI(%d) connected to INT%u_2\n",
+					  __func__, dai->id, j);
+				dev_dbg(codec->dev, "%s: set INT%u_2 sample rate to %u\n",
+					__func__, j, sample_rate);
+				snd_soc_update_bits(codec, int_fs_reg, 0x0F,
+						    rate_reg_val);
+			}
+			int_mux_cfg1 += 2;
+		}
+	}
+	return 0;
+}
+
+static int tavil_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+					    u8 rate_reg_val,
+					    u32 sample_rate)
+{
+	u8 int_1_mix1_inp;
+	u32 j;
+	u16 int_mux_cfg0, int_mux_cfg1;
+	u16 int_fs_reg;
+	u8 int_mux_cfg0_val, int_mux_cfg1_val;
+	u8 inp0_sel, inp1_sel, inp2_sel;
+	struct snd_soc_codec *codec = dai->codec;
+	struct wcd9xxx_ch *ch;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
+
+	list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) {
+		int_1_mix1_inp = INTn_1_INP_SEL_RX0 + ch->port -
+						WCD934X_RX_PORT_START_NUMBER;
+		if ((int_1_mix1_inp < INTn_1_INP_SEL_RX0) ||
+		    (int_1_mix1_inp > INTn_1_INP_SEL_RX7)) {
+			dev_err(codec->dev, "%s: Invalid RX%u port, Dai ID is %d\n",
+				__func__,
+				(ch->port - WCD934X_RX_PORT_START_NUMBER),
+				dai->id);
+			return -EINVAL;
+		}
+
+		int_mux_cfg0 = WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0;
+
+		/*
+		 * Loop through all interpolator MUX inputs and find out
+		 * to which interpolator input, the slim rx port
+		 * is connected
+		 */
+		for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) {
+			/* Interpolators 5 and 6 are not aviliable in Tavil */
+			if (j == INTERP_LO3_NA || j == INTERP_LO4_NA) {
+				int_mux_cfg0 += 2;
+				continue;
+			}
+			int_mux_cfg1 = int_mux_cfg0 + 1;
+
+			int_mux_cfg0_val = snd_soc_read(codec, int_mux_cfg0);
+			int_mux_cfg1_val = snd_soc_read(codec, int_mux_cfg1);
+			inp0_sel = int_mux_cfg0_val & 0x0F;
+			inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F;
+			inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F;
+			if ((inp0_sel == int_1_mix1_inp) ||
+			    (inp1_sel == int_1_mix1_inp) ||
+			    (inp2_sel == int_1_mix1_inp)) {
+				/*
+				 * Ear and speaker primary path does not support
+				 * native sample rates
+				 */
+				if ((j == INTERP_EAR || j == INTERP_SPKR1 ||
+					j == INTERP_SPKR2) &&
+					(rate_reg_val > 0x7)) {
+					dev_err_ratelimited(codec->dev,
+					"%s: Invalid rate for AIF_PB DAI(%d)\n",
+					  __func__, dai->id);
+					return -EINVAL;
+				}
+
+				int_fs_reg = WCD934X_CDC_RX0_RX_PATH_CTL +
+									20 * j;
+				dev_dbg(codec->dev,
+				"%s: AIF_PB DAI(%d) connected to INT%u_1\n",
+				  __func__, dai->id, j);
+				dev_dbg(codec->dev,
+					"%s: set INT%u_1 sample rate to %u\n",
+					__func__, j, sample_rate);
+				snd_soc_update_bits(codec, int_fs_reg, 0x0F,
+						    rate_reg_val);
+			}
+			int_mux_cfg0 += 2;
+		}
+		if (dsd_conf)
+			tavil_dsd_set_interp_rate(dsd_conf, ch->port,
+						  sample_rate, rate_reg_val);
+	}
+
+	return 0;
+}
+
+
+static int tavil_set_interpolator_rate(struct snd_soc_dai *dai,
+				       u32 sample_rate)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int rate_val = 0;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) {
+		if (sample_rate == sr_val_tbl[i].sample_rate) {
+			rate_val = sr_val_tbl[i].rate_val;
+			break;
+		}
+	}
+	if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) {
+		dev_err(codec->dev, "%s: Unsupported sample rate: %d\n",
+			__func__, sample_rate);
+		return -EINVAL;
+	}
+
+	ret = tavil_set_prim_interpolator_rate(dai, (u8)rate_val, sample_rate);
+	if (ret)
+		return ret;
+	ret = tavil_set_mix_interpolator_rate(dai, (u8)rate_val, sample_rate);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int tavil_prepare(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	return 0;
+}
+
+static int tavil_vi_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(dai->codec);
+
+	dev_dbg(tavil->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
+		 __func__, dai->name, dai->id, params_rate(params),
+		 params_channels(params));
+
+	tavil->dai[dai->id].rate = params_rate(params);
+	tavil->dai[dai->id].bit_width = 32;
+
+	return 0;
+}
+
+static int tavil_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(dai->codec);
+	int ret = 0;
+
+	dev_dbg(tavil->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
+		 __func__, dai->name, dai->id, params_rate(params),
+		 params_channels(params));
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = tavil_set_interpolator_rate(dai, params_rate(params));
+		if (ret) {
+			dev_err(tavil->dev, "%s: cannot set sample rate: %u\n",
+				__func__, params_rate(params));
+			return ret;
+		}
+		switch (params_width(params)) {
+		case 16:
+			tavil->dai[dai->id].bit_width = 16;
+			break;
+		case 24:
+			tavil->dai[dai->id].bit_width = 24;
+			break;
+		case 32:
+			tavil->dai[dai->id].bit_width = 32;
+			break;
+		default:
+			return -EINVAL;
+		}
+		tavil->dai[dai->id].rate = params_rate(params);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		if (dai->id != AIF4_MAD_TX)
+			ret = tavil_set_decimator_rate(dai,
+						       params_rate(params));
+		if (ret) {
+			dev_err(tavil->dev, "%s: cannot set TX Decimator rate: %d\n",
+				__func__, ret);
+			return ret;
+		}
+		switch (params_width(params)) {
+		case 16:
+			tavil->dai[dai->id].bit_width = 16;
+			break;
+		case 24:
+			tavil->dai[dai->id].bit_width = 24;
+			break;
+		default:
+			dev_err(tavil->dev, "%s: Invalid format 0x%x\n",
+				__func__, params_width(params));
+			return -EINVAL;
+		};
+		tavil->dai[dai->id].rate = params_rate(params);
+		break;
+	default:
+		dev_err(tavil->dev, "%s: Invalid stream type %d\n", __func__,
+			substream->stream);
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops tavil_dai_ops = {
+	.startup = tavil_startup,
+	.shutdown = tavil_shutdown,
+	.hw_params = tavil_hw_params,
+	.prepare = tavil_prepare,
+	.set_channel_map = tavil_set_channel_map,
+	.get_channel_map = tavil_get_channel_map,
+};
+
+static struct snd_soc_dai_ops tavil_vi_dai_ops = {
+	.hw_params = tavil_vi_hw_params,
+	.set_channel_map = tavil_set_channel_map,
+	.get_channel_map = tavil_get_channel_map,
+};
+
+static struct snd_soc_dai_driver tavil_dai[] = {
+	{
+		.name = "tavil_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_S32_LE,
+			.rate_min = 8000,
+			.rate_max = 384000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tavil_dai_ops,
+	},
+	{
+		.name = "tavil_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD934X_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tavil_dai_ops,
+	},
+	{
+		.name = "tavil_rx2",
+		.id = AIF2_PB,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_S32_LE,
+			.rate_min = 8000,
+			.rate_max = 384000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tavil_dai_ops,
+	},
+	{
+		.name = "tavil_tx2",
+		.id = AIF2_CAP,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.rates = WCD934X_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tavil_dai_ops,
+	},
+	{
+		.name = "tavil_rx3",
+		.id = AIF3_PB,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_S32_LE,
+			.rate_min = 8000,
+			.rate_max = 384000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tavil_dai_ops,
+	},
+	{
+		.name = "tavil_tx3",
+		.id = AIF3_CAP,
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.rates = WCD934X_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tavil_dai_ops,
+	},
+	{
+		.name = "tavil_rx4",
+		.id = AIF4_PB,
+		.playback = {
+			.stream_name = "AIF4 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_S32_LE,
+			.rate_min = 8000,
+			.rate_max = 384000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tavil_dai_ops,
+	},
+	{
+		.name = "tavil_vifeedback",
+		.id = AIF4_VIFEED,
+		.capture = {
+			.stream_name = "VIfeed",
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000,
+			.formats = WCD934X_FORMATS_S16_S24_S32_LE,
+			.rate_min = 8000,
+			.rate_max = 48000,
+			.channels_min = 1,
+			.channels_max = 4,
+		 },
+		.ops = &tavil_vi_dai_ops,
+	},
+	{
+		.name = "tavil_mad1",
+		.id = AIF4_MAD_TX,
+		.capture = {
+			.stream_name = "AIF4 MAD TX",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = WCD934X_FORMATS_S16_LE,
+			.rate_min = 16000,
+			.rate_max = 16000,
+			.channels_min = 1,
+			.channels_max = 1,
+		},
+		.ops = &tavil_dai_ops,
+	},
+};
+
+static void tavil_codec_power_gate_digital_core(struct tavil_priv *tavil)
+{
+	mutex_lock(&tavil->power_lock);
+	dev_dbg(tavil->dev, "%s: Entering power gating function, %d\n",
+		__func__, tavil->power_active_ref);
+
+	if (tavil->power_active_ref > 0)
+		goto exit;
+
+	wcd9xxx_set_power_state(tavil->wcd9xxx,
+			WCD_REGION_POWER_COLLAPSE_BEGIN,
+			WCD9XXX_DIG_CORE_REGION_1);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04, 0x04);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x01, 0x00);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x02, 0x00);
+	wcd9xxx_set_power_state(tavil->wcd9xxx, WCD_REGION_POWER_DOWN,
+				WCD9XXX_DIG_CORE_REGION_1);
+exit:
+	dev_dbg(tavil->dev, "%s: Exiting power gating function, %d\n",
+		__func__, tavil->power_active_ref);
+	mutex_unlock(&tavil->power_lock);
+}
+
+static void tavil_codec_power_gate_work(struct work_struct *work)
+{
+	struct tavil_priv *tavil;
+	struct delayed_work *dwork;
+
+	dwork = to_delayed_work(work);
+	tavil = container_of(dwork, struct tavil_priv, power_gate_work);
+
+	tavil_codec_power_gate_digital_core(tavil);
+}
+
+/* called under power_lock acquisition */
+static int tavil_dig_core_remove_power_collapse(struct tavil_priv *tavil)
+{
+	regmap_write(tavil->wcd9xxx->regmap,
+		     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x05);
+	regmap_write(tavil->wcd9xxx->regmap,
+		     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x07);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+	regmap_write(tavil->wcd9xxx->regmap,
+		     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x03);
+
+	wcd9xxx_set_power_state(tavil->wcd9xxx,
+			WCD_REGION_POWER_COLLAPSE_REMOVE,
+			WCD9XXX_DIG_CORE_REGION_1);
+	regcache_mark_dirty(tavil->wcd9xxx->regmap);
+	regcache_sync_region(tavil->wcd9xxx->regmap,
+			     WCD934X_DIG_CORE_REG_MIN,
+			     WCD934X_DIG_CORE_REG_MAX);
+
+	tavil_restore_iir_coeff(tavil, IIR0);
+	tavil_restore_iir_coeff(tavil, IIR1);
+	return 0;
+}
+
+static int tavil_dig_core_power_collapse(struct tavil_priv *tavil,
+					 int req_state)
+{
+	int cur_state;
+
+	/* Exit if feature is disabled */
+	if (!dig_core_collapse_enable)
+		return 0;
+
+	mutex_lock(&tavil->power_lock);
+	if (req_state == POWER_COLLAPSE)
+		tavil->power_active_ref--;
+	else if (req_state == POWER_RESUME)
+		tavil->power_active_ref++;
+	else
+		goto unlock_mutex;
+
+	if (tavil->power_active_ref < 0) {
+		dev_dbg(tavil->dev, "%s: power_active_ref is negative\n",
+			__func__);
+		goto unlock_mutex;
+	}
+
+	if (req_state == POWER_COLLAPSE) {
+		if (tavil->power_active_ref == 0) {
+			schedule_delayed_work(&tavil->power_gate_work,
+			msecs_to_jiffies(dig_core_collapse_timer * 1000));
+		}
+	} else if (req_state == POWER_RESUME) {
+		if (tavil->power_active_ref == 1) {
+			/*
+			 * At this point, there can be two cases:
+			 * 1. Core already in power collapse state
+			 * 2. Timer kicked in and still did not expire or
+			 * waiting for the power_lock
+			 */
+			cur_state = wcd9xxx_get_current_power_state(
+						tavil->wcd9xxx,
+						WCD9XXX_DIG_CORE_REGION_1);
+			if (cur_state == WCD_REGION_POWER_DOWN) {
+				tavil_dig_core_remove_power_collapse(tavil);
+			} else {
+				mutex_unlock(&tavil->power_lock);
+				cancel_delayed_work_sync(
+						&tavil->power_gate_work);
+				mutex_lock(&tavil->power_lock);
+			}
+		}
+	}
+
+unlock_mutex:
+	mutex_unlock(&tavil->power_lock);
+
+	return 0;
+}
+
+static int tavil_cdc_req_mclk_enable(struct tavil_priv *tavil,
+				     bool enable)
+{
+	int ret = 0;
+
+	if (enable) {
+		ret = clk_prepare_enable(tavil->wcd_ext_clk);
+		if (ret) {
+			dev_err(tavil->dev, "%s: ext clk enable failed\n",
+				__func__);
+			goto done;
+		}
+		/* get BG */
+		wcd_resmgr_enable_master_bias(tavil->resmgr);
+		/* get MCLK */
+		wcd_resmgr_enable_clk_block(tavil->resmgr, WCD_CLK_MCLK);
+	} else {
+		/* put MCLK */
+		wcd_resmgr_disable_clk_block(tavil->resmgr, WCD_CLK_MCLK);
+		/* put BG */
+		wcd_resmgr_disable_master_bias(tavil->resmgr);
+		clk_disable_unprepare(tavil->wcd_ext_clk);
+	}
+
+done:
+	return ret;
+}
+
+static int __tavil_cdc_mclk_enable_locked(struct tavil_priv *tavil,
+					  bool enable)
+{
+	int ret = 0;
+
+	if (!tavil->wcd_ext_clk) {
+		dev_err(tavil->dev, "%s: wcd ext clock is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(tavil->dev, "%s: mclk_enable = %u\n", __func__, enable);
+
+	if (enable) {
+		tavil_dig_core_power_collapse(tavil, POWER_RESUME);
+		tavil_vote_svs(tavil, true);
+		ret = tavil_cdc_req_mclk_enable(tavil, true);
+		if (ret)
+			goto done;
+	} else {
+		tavil_cdc_req_mclk_enable(tavil, false);
+		tavil_vote_svs(tavil, false);
+		tavil_dig_core_power_collapse(tavil, POWER_COLLAPSE);
+	}
+
+done:
+	return ret;
+}
+
+static int __tavil_cdc_mclk_enable(struct tavil_priv *tavil,
+				   bool enable)
+{
+	int ret;
+
+	WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
+	ret = __tavil_cdc_mclk_enable_locked(tavil, enable);
+	if (enable)
+		wcd_resmgr_set_sido_input_src(tavil->resmgr,
+						     SIDO_SOURCE_RCO_BG);
+	WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
+
+	return ret;
+}
+
+static ssize_t tavil_codec_version_read(struct snd_info_entry *entry,
+					void *file_private_data,
+					struct file *file,
+					char __user *buf, size_t count,
+					loff_t pos)
+{
+	struct tavil_priv *tavil;
+	struct wcd9xxx *wcd9xxx;
+	char buffer[TAVIL_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	tavil = (struct tavil_priv *) entry->private_data;
+	if (!tavil) {
+		pr_err("%s: tavil priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd9xxx = tavil->wcd9xxx;
+
+	switch (wcd9xxx->version) {
+	case TAVIL_VERSION_WCD9340_1_0:
+		len = snprintf(buffer, sizeof(buffer), "WCD9340_1_0\n");
+		break;
+	case TAVIL_VERSION_WCD9341_1_0:
+		len = snprintf(buffer, sizeof(buffer), "WCD9341_1_0\n");
+		break;
+	case TAVIL_VERSION_WCD9340_1_1:
+		len = snprintf(buffer, sizeof(buffer), "WCD9340_1_1\n");
+		break;
+	case TAVIL_VERSION_WCD9341_1_1:
+		len = snprintf(buffer, sizeof(buffer), "WCD9341_1_1\n");
+		break;
+	default:
+		len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+	}
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops tavil_codec_info_ops = {
+	.read = tavil_codec_version_read,
+};
+
+/*
+ * tavil_codec_info_create_codec_entry - creates wcd934x module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates wcd934x module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int tavil_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct tavil_priv *tavil;
+	struct snd_soc_card *card;
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	tavil = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	tavil->entry = snd_info_create_subdir(codec_root->module,
+					      "tavil", codec_root);
+	if (!tavil->entry) {
+		dev_dbg(codec->dev, "%s: failed to create wcd934x entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   tavil->entry);
+	if (!version_entry) {
+		dev_dbg(codec->dev, "%s: failed to create wcd934x version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = tavil;
+	version_entry->size = TAVIL_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &tavil_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	tavil->version_entry = version_entry;
+
+	return 0;
+}
+EXPORT_SYMBOL(tavil_codec_info_create_codec_entry);
+
+/**
+ * tavil_cdc_mclk_enable - Enable/disable codec mclk
+ *
+ * @codec: codec instance
+ * @enable: Indicates clk enable or disable
+ *
+ * Returns 0 on Success and error on failure
+ */
+int tavil_cdc_mclk_enable(struct snd_soc_codec *codec, bool enable)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	return __tavil_cdc_mclk_enable(tavil, enable);
+}
+EXPORT_SYMBOL(tavil_cdc_mclk_enable);
+
+static int __tavil_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
+					   bool enable)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	if (enable) {
+		if (wcd_resmgr_get_clk_type(tavil->resmgr) ==
+		    WCD_CLK_RCO) {
+			ret = wcd_resmgr_enable_clk_block(tavil->resmgr,
+							  WCD_CLK_RCO);
+		} else {
+			ret = tavil_cdc_req_mclk_enable(tavil, true);
+			if (ret) {
+				dev_err(codec->dev,
+					"%s: mclk_enable failed, err = %d\n",
+					__func__, ret);
+				goto done;
+			}
+			wcd_resmgr_set_sido_input_src(tavil->resmgr,
+							SIDO_SOURCE_RCO_BG);
+			ret = wcd_resmgr_enable_clk_block(tavil->resmgr,
+							   WCD_CLK_RCO);
+			ret |= tavil_cdc_req_mclk_enable(tavil, false);
+		}
+
+	} else {
+		ret = wcd_resmgr_disable_clk_block(tavil->resmgr,
+						   WCD_CLK_RCO);
+	}
+
+	if (ret) {
+		dev_err(codec->dev, "%s: Error in %s RCO\n",
+			__func__, (enable ? "enabling" : "disabling"));
+		ret = -EINVAL;
+	}
+
+done:
+	return ret;
+}
+
+/*
+ * tavil_codec_internal_rco_ctrl: Enable/Disable codec's RCO clock
+ * @codec: Handle to the codec
+ * @enable: Indicates whether clock should be enabled or disabled
+ */
+static int tavil_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
+					 bool enable)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
+	ret = __tavil_codec_internal_rco_ctrl(codec, enable);
+	WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
+	return ret;
+}
+
+/*
+ * tavil_cdc_mclk_tx_enable: Enable/Disable codec's clock for TX path
+ * @codec: Handle to codec
+ * @enable: Indicates whether clock should be enabled or disabled
+ */
+int tavil_cdc_mclk_tx_enable(struct snd_soc_codec *codec, bool enable)
+{
+	struct tavil_priv *tavil_p;
+	int ret = 0;
+	bool clk_mode;
+	bool clk_internal;
+
+	if (!codec)
+		return -EINVAL;
+
+	tavil_p = snd_soc_codec_get_drvdata(codec);
+	clk_mode = test_bit(CLK_MODE, &tavil_p->status_mask);
+	clk_internal = test_bit(CLK_INTERNAL, &tavil_p->status_mask);
+
+	dev_dbg(codec->dev, "%s: clkmode: %d, enable: %d, clk_internal: %d\n",
+		__func__, clk_mode, enable, clk_internal);
+
+	if (clk_mode || clk_internal) {
+		if (enable) {
+			wcd_resmgr_enable_master_bias(tavil_p->resmgr);
+			tavil_dig_core_power_collapse(tavil_p, POWER_RESUME);
+			tavil_vote_svs(tavil_p, true);
+			ret = tavil_codec_internal_rco_ctrl(codec, enable);
+			set_bit(CLK_INTERNAL, &tavil_p->status_mask);
+		} else {
+			clear_bit(CLK_INTERNAL, &tavil_p->status_mask);
+			tavil_codec_internal_rco_ctrl(codec, enable);
+			tavil_vote_svs(tavil_p, false);
+			tavil_dig_core_power_collapse(tavil_p, POWER_COLLAPSE);
+			wcd_resmgr_disable_master_bias(tavil_p->resmgr);
+		}
+	} else {
+		ret = __tavil_cdc_mclk_enable(tavil_p, enable);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(tavil_cdc_mclk_tx_enable);
+
+static const struct wcd_resmgr_cb tavil_resmgr_cb = {
+	.cdc_rco_ctrl = __tavil_codec_internal_rco_ctrl,
+};
+
+static const struct tavil_reg_mask_val tavil_codec_mclk2_1_1_defaults[] = {
+	{WCD934X_CLK_SYS_MCLK2_PRG1, 0x60, 0x20},
+};
+
+static const struct tavil_reg_mask_val tavil_codec_mclk2_1_0_defaults[] = {
+	/*
+	 * PLL Settings:
+	 * Clock Root: MCLK2,
+	 * Clock Source: EXT_CLK,
+	 * Clock Destination: MCLK2
+	 * Clock Freq In: 19.2MHz,
+	 * Clock Freq Out: 11.2896MHz
+	 */
+	{WCD934X_CLK_SYS_MCLK2_PRG1, 0x60, 0x20},
+	{WCD934X_CLK_SYS_INT_POST_DIV_REG0, 0xFF, 0x5E},
+	{WCD934X_CLK_SYS_INT_POST_DIV_REG1, 0x1F, 0x1F},
+	{WCD934X_CLK_SYS_INT_REF_DIV_REG0, 0xFF, 0x54},
+	{WCD934X_CLK_SYS_INT_REF_DIV_REG1, 0xFF, 0x01},
+	{WCD934X_CLK_SYS_INT_FILTER_REG1, 0x07, 0x04},
+	{WCD934X_CLK_SYS_INT_PLL_L_VAL, 0xFF, 0x93},
+	{WCD934X_CLK_SYS_INT_PLL_N_VAL, 0xFF, 0xFA},
+	{WCD934X_CLK_SYS_INT_TEST_REG0, 0xFF, 0x90},
+	{WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG, 0xFF, 0x7E},
+	{WCD934X_CLK_SYS_INT_VCO_PROG, 0xFF, 0xF8},
+	{WCD934X_CLK_SYS_INT_TEST_REG1, 0xFF, 0x68},
+	{WCD934X_CLK_SYS_INT_LDO_LOCK_CFG, 0xFF, 0x40},
+	{WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG, 0xFF, 0x32},
+};
+
+static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = {
+	{WCD934X_BIAS_VBG_FINE_ADJ, 0xFF, 0x75},
+	{WCD934X_CODEC_CPR_SVS_CX_VDD, 0xFF, 0x7C}, /* value in svs mode */
+	{WCD934X_CODEC_CPR_SVS2_CX_VDD, 0xFF, 0x58}, /* value in svs2 mode */
+	{WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+	{WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+	{WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+	{WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+	{WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+	{WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+	{WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+	{WCD934X_CDC_COMPANDER8_CTL7, 0x1E, 0x18},
+	{WCD934X_CDC_COMPANDER7_CTL7, 0x1E, 0x18},
+	{WCD934X_CDC_RX0_RX_PATH_SEC0, 0x08, 0x0},
+	{WCD934X_CDC_CLSH_DECAY_CTRL, 0x03, 0x0},
+	{WCD934X_MICB1_TEST_CTL_2, 0x07, 0x01},
+	{WCD934X_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+	{WCD934X_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+	{WCD934X_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+	{WCD934X_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+	{WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x1F, 0x09},
+	{WCD934X_CDC_TX0_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX1_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX2_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX3_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX4_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX5_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX6_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX7_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_CDC_TX8_TX_PATH_CFG1, 0x01, 0x00},
+	{WCD934X_RX_OCP_CTL, 0x0F, 0x02}, /* OCP number of attempts is 2 */
+	{WCD934X_HPH_OCP_CTL, 0xFF, 0x3A}, /* OCP current limit */
+	{WCD934X_HPH_L_TEST, 0x01, 0x01},
+	{WCD934X_HPH_R_TEST, 0x01, 0x01},
+	{WCD934X_CPE_FLL_CONFIG_CTL_2, 0xFF, 0x20},
+	{WCD934X_MBHC_NEW_CTL_2, 0x0C, 0x00},
+};
+
+static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = {
+	{WCD934X_CDC_COMPANDER1_CTL7, 0x1E, 0x06},
+	{WCD934X_CDC_COMPANDER2_CTL7, 0x1E, 0x06},
+	{WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xFF, 0x84},
+	{WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xFF, 0x84},
+	{WCD934X_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4},
+	{WCD934X_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4},
+};
+
+static const struct tavil_cpr_reg_defaults cpr_defaults[] = {
+	{ 0x00000820, 0x00000094 },
+	{ 0x00000fC0, 0x00000048 },
+	{ 0x0000f000, 0x00000044 },
+	{ 0x0000bb80, 0xC0000178 },
+	{ 0x00000000, 0x00000160 },
+	{ 0x10854522, 0x00000060 },
+	{ 0x10854509, 0x00000064 },
+	{ 0x108544dd, 0x00000068 },
+	{ 0x108544ad, 0x0000006C },
+	{ 0x0000077E, 0x00000070 },
+	{ 0x000007da, 0x00000074 },
+	{ 0x00000000, 0x00000078 },
+	{ 0x00000000, 0x0000007C },
+	{ 0x00042029, 0x00000080 },
+	{ 0x4002002A, 0x00000090 },
+	{ 0x4002002B, 0x00000090 },
+};
+
+static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = {
+	{WCD934X_CDC_CLSH_K2_MSB, 0x0F, 0x00},
+	{WCD934X_CDC_CLSH_K2_LSB, 0xFF, 0x60},
+	{WCD934X_CPE_SS_DMIC_CFG, 0x80, 0x00},
+	{WCD934X_CDC_BOOST0_BOOST_CTL, 0x70, 0x50},
+	{WCD934X_CDC_BOOST1_BOOST_CTL, 0x70, 0x50},
+	{WCD934X_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD934X_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD934X_CDC_TOP_TOP_CFG1, 0x02, 0x02},
+	{WCD934X_CDC_TOP_TOP_CFG1, 0x01, 0x01},
+	{WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x01, 0x01},
+	{WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01},
+	{WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+	{WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+	{WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+	{WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+	{WCD934X_CODEC_RPM_CLK_GATE, 0x08, 0x00},
+	{WCD934X_TLMM_DMIC3_CLK_PINCFG, 0xFF, 0x0a},
+	{WCD934X_TLMM_DMIC3_DATA_PINCFG, 0xFF, 0x0a},
+	{WCD934X_CPE_SS_SVA_CFG, 0x60, 0x00},
+	{WCD934X_CPE_SS_CPAR_CFG, 0x10, 0x10},
+};
+
+static void tavil_codec_init_reg(struct tavil_priv *priv)
+{
+	struct snd_soc_codec *codec = priv->codec;
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_init_common_val); i++)
+		snd_soc_update_bits(codec,
+				    tavil_codec_reg_init_common_val[i].reg,
+				    tavil_codec_reg_init_common_val[i].mask,
+				    tavil_codec_reg_init_common_val[i].val);
+
+	if (TAVIL_IS_1_1(priv->wcd9xxx)) {
+		for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_init_1_1_val); i++)
+			snd_soc_update_bits(codec,
+					tavil_codec_reg_init_1_1_val[i].reg,
+					tavil_codec_reg_init_1_1_val[i].mask,
+					tavil_codec_reg_init_1_1_val[i].val);
+	}
+}
+
+static void tavil_update_reg_defaults(struct tavil_priv *tavil)
+{
+	u32 i;
+	struct wcd9xxx *wcd9xxx;
+
+	wcd9xxx = tavil->wcd9xxx;
+	for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_defaults); i++)
+		regmap_update_bits(wcd9xxx->regmap,
+				   tavil_codec_reg_defaults[i].reg,
+				   tavil_codec_reg_defaults[i].mask,
+				   tavil_codec_reg_defaults[i].val);
+}
+
+static void tavil_update_cpr_defaults(struct tavil_priv *tavil)
+{
+	int i;
+	struct wcd9xxx *wcd9xxx;
+
+	wcd9xxx = tavil->wcd9xxx;
+	if (!TAVIL_IS_1_1(wcd9xxx))
+		return;
+
+	__tavil_cdc_mclk_enable(tavil, true);
+
+	regmap_write(wcd9xxx->regmap, WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x2C);
+	regmap_update_bits(wcd9xxx->regmap, WCD934X_CODEC_RPM_CLK_GATE,
+			   0x10, 0x00);
+
+	for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) {
+		regmap_bulk_write(wcd9xxx->regmap,
+				WCD934X_CODEC_CPR_WR_DATA_0,
+				(u8 *)&cpr_defaults[i].wr_data, 4);
+		regmap_bulk_write(wcd9xxx->regmap,
+				WCD934X_CODEC_CPR_WR_ADDR_0,
+				(u8 *)&cpr_defaults[i].wr_addr, 4);
+	}
+
+	__tavil_cdc_mclk_enable(tavil, false);
+}
+
+static void tavil_slim_interface_init_reg(struct snd_soc_codec *codec)
+{
+	int i;
+	struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+		wcd9xxx_interface_reg_write(priv->wcd9xxx,
+				    WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + i,
+				    0xFF);
+}
+
+static irqreturn_t tavil_misc_irq(int irq, void *data)
+{
+	struct tavil_priv *tavil = data;
+	int misc_val;
+
+	/* Find source of interrupt */
+	regmap_read(tavil->wcd9xxx->regmap, WCD934X_INTR_CODEC_MISC_STATUS,
+		    &misc_val);
+
+	if (misc_val & 0x08) {
+		dev_info(tavil->dev, "%s: irq: %d, DSD DC detected!\n",
+			 __func__, irq);
+		/* DSD DC interrupt, reset DSD path */
+		tavil_dsd_reset(tavil->dsd_config);
+	} else {
+		dev_err(tavil->dev, "%s: Codec misc irq: %d, val: 0x%x\n",
+			__func__, irq, misc_val);
+	}
+
+	/* Clear interrupt status */
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			   WCD934X_INTR_CODEC_MISC_CLEAR, misc_val, 0x00);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t tavil_slimbus_irq(int irq, void *data)
+{
+	struct tavil_priv *tavil = data;
+	unsigned long status = 0;
+	int i, j, port_id, k;
+	u32 bit;
+	u8 val, int_val = 0;
+	bool tx, cleared;
+	unsigned short reg = 0;
+
+	for (i = WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+	     i <= WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
+		val = wcd9xxx_interface_reg_read(tavil->wcd9xxx, i);
+		status |= ((u32)val << (8 * j));
+	}
+
+	for_each_set_bit(j, &status, 32) {
+		tx = (j >= 16 ? true : false);
+		port_id = (tx ? j - 16 : j);
+		val = wcd9xxx_interface_reg_read(tavil->wcd9xxx,
+				WCD934X_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
+		if (val) {
+			if (!tx)
+				reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 +
+					(port_id / 8);
+			else
+				reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 +
+					(port_id / 8);
+			int_val = wcd9xxx_interface_reg_read(
+				tavil->wcd9xxx, reg);
+			/*
+			 * Ignore interrupts for ports for which the
+			 * interrupts are not specifically enabled.
+			 */
+			if (!(int_val & (1 << (port_id % 8))))
+				continue;
+		}
+		if (val & WCD934X_SLIM_IRQ_OVERFLOW)
+			dev_err_ratelimited(tavil->dev, "%s: overflow error on %s port %d, value %x\n",
+			   __func__, (tx ? "TX" : "RX"), port_id, val);
+		if (val & WCD934X_SLIM_IRQ_UNDERFLOW)
+			dev_err_ratelimited(tavil->dev, "%s: underflow error on %s port %d, value %x\n",
+			   __func__, (tx ? "TX" : "RX"), port_id, val);
+		if ((val & WCD934X_SLIM_IRQ_OVERFLOW) ||
+			(val & WCD934X_SLIM_IRQ_UNDERFLOW)) {
+			if (!tx)
+				reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 +
+					(port_id / 8);
+			else
+				reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 +
+					(port_id / 8);
+			int_val = wcd9xxx_interface_reg_read(
+				tavil->wcd9xxx, reg);
+			if (int_val & (1 << (port_id % 8))) {
+				int_val = int_val ^ (1 << (port_id % 8));
+				wcd9xxx_interface_reg_write(tavil->wcd9xxx,
+					reg, int_val);
+			}
+		}
+		if (val & WCD934X_SLIM_IRQ_PORT_CLOSED) {
+			/*
+			 * INT SOURCE register starts from RX to TX
+			 * but port number in the ch_mask is in opposite way
+			 */
+			bit = (tx ? j - 16 : j + 16);
+			dev_dbg(tavil->dev, "%s: %s port %d closed value %x, bit %u\n",
+				 __func__, (tx ? "TX" : "RX"), port_id, val,
+				 bit);
+			for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
+				dev_dbg(tavil->dev, "%s: tavil->dai[%d].ch_mask = 0x%lx\n",
+					 __func__, k, tavil->dai[k].ch_mask);
+				if (test_and_clear_bit(bit,
+						&tavil->dai[k].ch_mask)) {
+					cleared = true;
+					if (!tavil->dai[k].ch_mask)
+						wake_up(
+						      &tavil->dai[k].dai_wait);
+					/*
+					 * There are cases when multiple DAIs
+					 * might be using the same slimbus
+					 * channel. Hence don't break here.
+					 */
+				}
+			}
+			WARN(!cleared,
+			     "Couldn't find slimbus %s port %d for closing\n",
+			     (tx ? "TX" : "RX"), port_id);
+		}
+		wcd9xxx_interface_reg_write(tavil->wcd9xxx,
+					    WCD934X_SLIM_PGD_PORT_INT_CLR_RX_0 +
+					    (j / 8),
+					    1 << (j % 8));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int tavil_setup_irqs(struct tavil_priv *tavil)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = tavil->codec;
+	struct wcd9xxx *wcd9xxx = tavil->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
+				  tavil_slimbus_irq, "SLIMBUS Slave", tavil);
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to request irq %d\n", __func__,
+		       WCD9XXX_IRQ_SLIMBUS);
+	else
+		tavil_slim_interface_init_reg(codec);
+
+	/* Register for misc interrupts as well */
+	ret = wcd9xxx_request_irq(core_res, WCD934X_IRQ_MISC,
+				  tavil_misc_irq, "CDC MISC Irq", tavil);
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to request cdc misc irq\n",
+			__func__);
+
+	return ret;
+}
+
+static void tavil_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+	struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct afe_param_cdc_slimbus_slave_cfg *cfg;
+	struct wcd9xxx *wcd9xxx = priv->wcd9xxx;
+	uint64_t eaddr = 0;
+
+	cfg = &priv->slimbus_slave_cfg;
+	cfg->minor_version = 1;
+	cfg->tx_slave_port_offset = 0;
+	cfg->rx_slave_port_offset = 16;
+
+	memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+	WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+	cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+	cfg->device_enum_addr_msw = eaddr >> 32;
+
+	dev_dbg(codec->dev, "%s: slimbus logical address 0x%llx\n",
+		__func__, eaddr);
+}
+
+static void tavil_cleanup_irqs(struct tavil_priv *tavil)
+{
+	struct wcd9xxx *wcd9xxx = tavil->wcd9xxx;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
+
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tavil);
+	wcd9xxx_free_irq(core_res, WCD934X_IRQ_MISC, tavil);
+}
+
+/*
+ * wcd934x_get_micb_vout_ctl_val: converts micbias from volts to register value
+ * @micb_mv: micbias in mv
+ *
+ * return register value converted
+ */
+int wcd934x_get_micb_vout_ctl_val(u32 micb_mv)
+{
+	/* min micbias voltage is 1V and maximum is 2.85V */
+	if (micb_mv < 1000 || micb_mv > 2850) {
+		pr_err("%s: unsupported micbias voltage\n", __func__);
+		return -EINVAL;
+	}
+
+	return (micb_mv - 1000) / 50;
+}
+EXPORT_SYMBOL(wcd934x_get_micb_vout_ctl_val);
+
+static int tavil_handle_pdata(struct tavil_priv *tavil,
+			      struct wcd9xxx_pdata *pdata)
+{
+	struct snd_soc_codec *codec = tavil->codec;
+	u8 mad_dmic_ctl_val;
+	u8 anc_ctl_value;
+	u32 def_dmic_rate, dmic_clk_drv;
+	int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
+	int rc = 0;
+
+	if (!pdata) {
+		dev_err(codec->dev, "%s: NULL pdata\n", __func__);
+		return -ENODEV;
+	}
+
+	/* set micbias voltage */
+	vout_ctl_1 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv);
+	vout_ctl_2 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv);
+	vout_ctl_3 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv);
+	vout_ctl_4 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb4_mv);
+	if (vout_ctl_1 < 0 || vout_ctl_2 < 0 ||
+	    vout_ctl_3 < 0 || vout_ctl_4 < 0) {
+		rc = -EINVAL;
+		goto done;
+	}
+	snd_soc_update_bits(codec, WCD934X_ANA_MICB1, 0x3F, vout_ctl_1);
+	snd_soc_update_bits(codec, WCD934X_ANA_MICB2, 0x3F, vout_ctl_2);
+	snd_soc_update_bits(codec, WCD934X_ANA_MICB3, 0x3F, vout_ctl_3);
+	snd_soc_update_bits(codec, WCD934X_ANA_MICB4, 0x3F, vout_ctl_4);
+
+	/* Set the DMIC sample rate */
+	switch (pdata->mclk_rate) {
+	case WCD934X_MCLK_CLK_9P6MHZ:
+		def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
+		break;
+	case WCD934X_MCLK_CLK_12P288MHZ:
+		def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ;
+		break;
+	default:
+		/* should never happen */
+		dev_err(codec->dev, "%s: Invalid mclk_rate %d\n",
+			__func__, pdata->mclk_rate);
+		rc = -EINVAL;
+		goto done;
+	};
+
+	if (pdata->dmic_sample_rate ==
+	    WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) {
+		dev_info(codec->dev, "%s: dmic_rate invalid default = %d\n",
+			__func__, def_dmic_rate);
+		pdata->dmic_sample_rate = def_dmic_rate;
+	}
+	if (pdata->mad_dmic_sample_rate ==
+	    WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) {
+		dev_info(codec->dev, "%s: mad_dmic_rate invalid default = %d\n",
+			__func__, def_dmic_rate);
+		/*
+		 * use dmic_sample_rate as the default for MAD
+		 * if mad dmic sample rate is undefined
+		 */
+		pdata->mad_dmic_sample_rate = pdata->dmic_sample_rate;
+	}
+
+	if (pdata->dmic_clk_drv ==
+	    WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED) {
+		pdata->dmic_clk_drv = WCD934X_DMIC_CLK_DRIVE_DEFAULT;
+		dev_dbg(codec->dev,
+			 "%s: dmic_clk_strength invalid, default = %d\n",
+			 __func__, pdata->dmic_clk_drv);
+	}
+
+	switch (pdata->dmic_clk_drv) {
+	case 2:
+		dmic_clk_drv = 0;
+		break;
+	case 4:
+		dmic_clk_drv = 1;
+		break;
+	case 8:
+		dmic_clk_drv = 2;
+		break;
+	case 16:
+		dmic_clk_drv = 3;
+		break;
+	default:
+		dev_err(codec->dev,
+			"%s: invalid dmic_clk_drv %d, using default\n",
+			__func__, pdata->dmic_clk_drv);
+		dmic_clk_drv = 0;
+		break;
+	}
+
+	snd_soc_update_bits(codec, WCD934X_TEST_DEBUG_PAD_DRVCTL_0,
+			    0x0C, dmic_clk_drv << 2);
+
+	/*
+	 * Default the DMIC clk rates to mad_dmic_sample_rate,
+	 * whereas, the anc/txfe dmic rates to dmic_sample_rate
+	 * since the anc/txfe are independent of mad block.
+	 */
+	mad_dmic_ctl_val = tavil_get_dmic_clk_val(tavil->codec,
+				pdata->mclk_rate,
+				pdata->mad_dmic_sample_rate);
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_DMIC0_CTL,
+		0x0E, mad_dmic_ctl_val << 1);
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_DMIC1_CTL,
+		0x0E, mad_dmic_ctl_val << 1);
+	snd_soc_update_bits(codec, WCD934X_CPE_SS_DMIC2_CTL,
+		0x0E, mad_dmic_ctl_val << 1);
+
+	if (dmic_clk_drv == WCD934X_DMIC_CLK_DIV_2)
+		anc_ctl_value = WCD934X_ANC_DMIC_X2_FULL_RATE;
+	else
+		anc_ctl_value = WCD934X_ANC_DMIC_X2_HALF_RATE;
+
+	snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_2_CTL,
+			    0x40, anc_ctl_value << 6);
+	snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_2_CTL,
+			    0x20, anc_ctl_value << 5);
+	snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_2_CTL,
+			    0x40, anc_ctl_value << 6);
+	snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_2_CTL,
+			    0x20, anc_ctl_value << 5);
+
+done:
+	return rc;
+}
+
+static void tavil_cdc_vote_svs(struct snd_soc_codec *codec, bool vote)
+{
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	return tavil_vote_svs(tavil, vote);
+}
+
+struct wcd_dsp_cdc_cb cdc_cb = {
+	.cdc_clk_en = tavil_codec_internal_rco_ctrl,
+	.cdc_vote_svs = tavil_cdc_vote_svs,
+};
+
+static int tavil_wdsp_initialize(struct snd_soc_codec *codec)
+{
+	struct wcd9xxx *control;
+	struct tavil_priv *tavil;
+	struct wcd_dsp_params params;
+	int ret = 0;
+
+	control = dev_get_drvdata(codec->dev->parent);
+	tavil = snd_soc_codec_get_drvdata(codec);
+
+	params.cb = &cdc_cb;
+	params.irqs.cpe_ipc1_irq = WCD934X_IRQ_CPE1_INTR;
+	params.irqs.cpe_err_irq = WCD934X_IRQ_CPE_ERROR;
+	params.irqs.fatal_irqs = CPE_FATAL_IRQS;
+	params.clk_rate = control->mclk_rate;
+	params.dsp_instance = 0;
+
+	wcd_dsp_cntl_init(codec, &params, &tavil->wdsp_cntl);
+	if (!tavil->wdsp_cntl) {
+		dev_err(tavil->dev, "%s: wcd-dsp-control init failed\n",
+			__func__);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * tavil_soc_get_mbhc: get wcd934x_mbhc handle of corresponding codec
+ * @codec: handle to snd_soc_codec *
+ *
+ * return wcd934x_mbhc handle or error code in case of failure
+ */
+struct wcd934x_mbhc *tavil_soc_get_mbhc(struct snd_soc_codec *codec)
+{
+	struct tavil_priv *tavil;
+
+	if (!codec) {
+		pr_err("%s: Invalid params, NULL codec\n", __func__);
+		return NULL;
+	}
+	tavil = snd_soc_codec_get_drvdata(codec);
+
+	if (!tavil) {
+		pr_err("%s: Invalid params, NULL tavil\n", __func__);
+		return NULL;
+	}
+
+	return tavil->mbhc;
+}
+EXPORT_SYMBOL(tavil_soc_get_mbhc);
+
+static void tavil_mclk2_reg_defaults(struct tavil_priv *tavil)
+{
+	int i;
+	struct snd_soc_codec *codec = tavil->codec;
+
+	if (TAVIL_IS_1_0(tavil->wcd9xxx)) {
+		/* MCLK2 configuration */
+		for (i = 0; i < ARRAY_SIZE(tavil_codec_mclk2_1_0_defaults); i++)
+			snd_soc_update_bits(codec,
+					tavil_codec_mclk2_1_0_defaults[i].reg,
+					tavil_codec_mclk2_1_0_defaults[i].mask,
+					tavil_codec_mclk2_1_0_defaults[i].val);
+	}
+	if (TAVIL_IS_1_1(tavil->wcd9xxx)) {
+		/* MCLK2 configuration */
+		for (i = 0; i < ARRAY_SIZE(tavil_codec_mclk2_1_1_defaults); i++)
+			snd_soc_update_bits(codec,
+					tavil_codec_mclk2_1_1_defaults[i].reg,
+					tavil_codec_mclk2_1_1_defaults[i].mask,
+					tavil_codec_mclk2_1_1_defaults[i].val);
+	}
+}
+
+static int tavil_device_down(struct wcd9xxx *wcd9xxx)
+{
+	struct snd_soc_codec *codec;
+	struct tavil_priv *priv;
+	int count;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	priv = snd_soc_codec_get_drvdata(codec);
+	if (priv->swr.ctrl_data)
+		swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
+				SWR_DEVICE_DOWN, NULL);
+	tavil_dsd_reset(priv->dsd_config);
+	snd_soc_card_change_online_state(codec->component.card, 0);
+	for (count = 0; count < NUM_CODEC_DAIS; count++)
+		priv->dai[count].bus_down_in_recovery = true;
+	wcd_dsp_ssr_event(priv->wdsp_cntl, WCD_CDC_DOWN_EVENT);
+	wcd_resmgr_set_sido_input_src_locked(priv->resmgr,
+					     SIDO_SOURCE_INTERNAL);
+
+	return 0;
+}
+
+static int tavil_post_reset_cb(struct wcd9xxx *wcd9xxx)
+{
+	int i, ret = 0;
+	struct wcd9xxx *control;
+	struct snd_soc_codec *codec;
+	struct tavil_priv *tavil;
+	struct wcd9xxx_pdata *pdata;
+	struct wcd_mbhc *mbhc;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	tavil = snd_soc_codec_get_drvdata(codec);
+	control = dev_get_drvdata(codec->dev->parent);
+
+	wcd9xxx_set_power_state(tavil->wcd9xxx,
+				WCD_REGION_POWER_COLLAPSE_REMOVE,
+				WCD9XXX_DIG_CORE_REGION_1);
+
+	mutex_lock(&tavil->codec_mutex);
+
+	tavil_vote_svs(tavil, true);
+	tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+				control->slim_slave->laddr;
+	tavil_slimbus_slave_port_cfg.slave_dev_pgd_la =
+					control->slim->laddr;
+	tavil_init_slim_slave_cfg(codec);
+	snd_soc_card_change_online_state(codec->component.card, 1);
+
+	for (i = 0; i < TAVIL_MAX_MICBIAS; i++)
+		tavil->micb_ref[i] = 0;
+
+	dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
+		__func__, control->mclk_rate);
+
+	if (control->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ)
+		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+				    0x03, 0x00);
+	else if (control->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ)
+		snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+				    0x03, 0x01);
+	wcd_resmgr_post_ssr_v2(tavil->resmgr);
+	tavil_update_reg_defaults(tavil);
+	tavil_codec_init_reg(tavil);
+	__tavil_enable_efuse_sensing(tavil);
+	tavil_mclk2_reg_defaults(tavil);
+
+	__tavil_cdc_mclk_enable(tavil, true);
+	regcache_mark_dirty(codec->component.regmap);
+	regcache_sync(codec->component.regmap);
+	__tavil_cdc_mclk_enable(tavil, false);
+
+	tavil_update_cpr_defaults(tavil);
+
+	pdata = dev_get_platdata(codec->dev->parent);
+	ret = tavil_handle_pdata(tavil, pdata);
+	if (ret < 0)
+		dev_err(codec->dev, "%s: invalid pdata\n", __func__);
+
+	/* Initialize MBHC module */
+	mbhc = &tavil->mbhc->wcd_mbhc;
+	ret = tavil_mbhc_post_ssr_init(tavil->mbhc, codec);
+	if (ret) {
+		dev_err(codec->dev, "%s: mbhc initialization failed\n",
+			__func__);
+		goto done;
+	} else {
+		tavil_mbhc_hs_detect(codec, mbhc->mbhc_cfg);
+	}
+
+	/* DSD initialization */
+	ret = tavil_dsd_post_ssr_init(tavil->dsd_config);
+	if (ret)
+		dev_dbg(tavil->dev, "%s: DSD init failed\n", __func__);
+
+	tavil_cleanup_irqs(tavil);
+	ret = tavil_setup_irqs(tavil);
+	if (ret) {
+		dev_err(codec->dev, "%s: tavil irq setup failed %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	tavil_set_spkr_mode(codec, tavil->swr.spkr_mode);
+	/*
+	 * Once the codec initialization is completed, the svs vote
+	 * can be released allowing the codec to go to SVS2.
+	 */
+	tavil_vote_svs(tavil, false);
+	wcd_dsp_ssr_event(tavil->wdsp_cntl, WCD_CDC_UP_EVENT);
+
+done:
+	mutex_unlock(&tavil->codec_mutex);
+	return ret;
+}
+
+static int tavil_soc_codec_probe(struct snd_soc_codec *codec)
+{
+	struct wcd9xxx *control;
+	struct tavil_priv *tavil;
+	struct wcd9xxx_pdata *pdata;
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int i, ret;
+	void *ptr = NULL;
+
+	control = dev_get_drvdata(codec->dev->parent);
+
+	dev_info(codec->dev, "%s()\n", __func__);
+	tavil = snd_soc_codec_get_drvdata(codec);
+	tavil->intf_type = wcd9xxx_get_intf_type();
+
+	control->dev_down = tavil_device_down;
+	control->post_reset = tavil_post_reset_cb;
+	control->ssr_priv = (void *)codec;
+
+	/* Resource Manager post Init */
+	ret = wcd_resmgr_post_init(tavil->resmgr, &tavil_resmgr_cb, codec);
+	if (ret) {
+		dev_err(codec->dev, "%s: wcd resmgr post init failed\n",
+			__func__);
+		goto err;
+	}
+	/* Class-H Init */
+	wcd_clsh_init(&tavil->clsh_d);
+	/* Default HPH Mode to Class-H Low HiFi */
+	tavil->hph_mode = CLS_H_LOHIFI;
+
+	tavil->fw_data = devm_kzalloc(codec->dev, sizeof(*(tavil->fw_data)),
+				      GFP_KERNEL);
+	if (!tavil->fw_data)
+		goto err;
+
+	set_bit(WCD9XXX_ANC_CAL, tavil->fw_data->cal_bit);
+	set_bit(WCD9XXX_MBHC_CAL, tavil->fw_data->cal_bit);
+	set_bit(WCD9XXX_MAD_CAL, tavil->fw_data->cal_bit);
+	set_bit(WCD9XXX_VBAT_CAL, tavil->fw_data->cal_bit);
+
+	ret = wcd_cal_create_hwdep(tavil->fw_data,
+				   WCD9XXX_CODEC_HWDEP_NODE, codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
+		goto err_hwdep;
+	}
+
+	/* Initialize MBHC module */
+	ret = tavil_mbhc_init(&tavil->mbhc, codec, tavil->fw_data);
+	if (ret) {
+		pr_err("%s: mbhc initialization failed\n", __func__);
+		goto err_hwdep;
+	}
+
+	tavil->codec = codec;
+	for (i = 0; i < COMPANDER_MAX; i++)
+		tavil->comp_enabled[i] = 0;
+
+	tavil_codec_init_reg(tavil);
+
+	pdata = dev_get_platdata(codec->dev->parent);
+	ret = tavil_handle_pdata(tavil, pdata);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s: bad pdata\n", __func__);
+		goto err_hwdep;
+	}
+
+	ptr = devm_kzalloc(codec->dev, (sizeof(tavil_rx_chs) +
+			   sizeof(tavil_tx_chs)), GFP_KERNEL);
+	if (!ptr) {
+		ret = -ENOMEM;
+		goto err_hwdep;
+	}
+
+	snd_soc_dapm_add_routes(dapm, tavil_slim_audio_map,
+			ARRAY_SIZE(tavil_slim_audio_map));
+	for (i = 0; i < NUM_CODEC_DAIS; i++) {
+		INIT_LIST_HEAD(&tavil->dai[i].wcd9xxx_ch_list);
+		init_waitqueue_head(&tavil->dai[i].dai_wait);
+	}
+	tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+				control->slim_slave->laddr;
+	tavil_slimbus_slave_port_cfg.slave_dev_pgd_la =
+				control->slim->laddr;
+	tavil_slimbus_slave_port_cfg.slave_port_mapping[0] =
+				WCD934X_TX13;
+	tavil_init_slim_slave_cfg(codec);
+
+	control->num_rx_port = WCD934X_RX_MAX;
+	control->rx_chs = ptr;
+	memcpy(control->rx_chs, tavil_rx_chs, sizeof(tavil_rx_chs));
+	control->num_tx_port = WCD934X_TX_MAX;
+	control->tx_chs = ptr + sizeof(tavil_rx_chs);
+	memcpy(control->tx_chs, tavil_tx_chs, sizeof(tavil_tx_chs));
+
+	ret = tavil_setup_irqs(tavil);
+	if (ret) {
+		dev_err(tavil->dev, "%s: tavil irq setup failed %d\n",
+			__func__, ret);
+		goto err_pdata;
+	}
+
+	for (i = 0; i < WCD934X_NUM_DECIMATORS; i++) {
+		tavil->tx_hpf_work[i].tavil = tavil;
+		tavil->tx_hpf_work[i].decimator = i;
+		INIT_DELAYED_WORK(&tavil->tx_hpf_work[i].dwork,
+				  tavil_tx_hpf_corner_freq_callback);
+
+		tavil->tx_mute_dwork[i].tavil = tavil;
+		tavil->tx_mute_dwork[i].decimator = i;
+		INIT_DELAYED_WORK(&tavil->tx_mute_dwork[i].dwork,
+				  tavil_tx_mute_update_callback);
+	}
+
+	tavil->spk_anc_dwork.tavil = tavil;
+	INIT_DELAYED_WORK(&tavil->spk_anc_dwork.dwork,
+			  tavil_spk_anc_update_callback);
+
+	tavil_mclk2_reg_defaults(tavil);
+
+	/* DSD initialization */
+	tavil->dsd_config = tavil_dsd_init(codec);
+	if (IS_ERR_OR_NULL(tavil->dsd_config))
+		dev_dbg(tavil->dev, "%s: DSD init failed\n", __func__);
+
+	mutex_lock(&tavil->codec_mutex);
+	snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC EAR");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+	snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA");
+	mutex_unlock(&tavil->codec_mutex);
+
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF2 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF2 Capture");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF3 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF3 Capture");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF4 Playback");
+	snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX");
+	snd_soc_dapm_ignore_suspend(dapm, "VIfeed");
+
+	snd_soc_dapm_sync(dapm);
+
+	tavil_wdsp_initialize(codec);
+
+	/*
+	 * Once the codec initialization is completed, the svs vote
+	 * can be released allowing the codec to go to SVS2.
+	 */
+	tavil_vote_svs(tavil, false);
+
+	return ret;
+
+err_pdata:
+	devm_kfree(codec->dev, ptr);
+	control->rx_chs = NULL;
+	control->tx_chs = NULL;
+err_hwdep:
+	devm_kfree(codec->dev, tavil->fw_data);
+	tavil->fw_data = NULL;
+err:
+	return ret;
+}
+
+static int tavil_soc_codec_remove(struct snd_soc_codec *codec)
+{
+	struct wcd9xxx *control;
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+
+	control = dev_get_drvdata(codec->dev->parent);
+	devm_kfree(codec->dev, control->rx_chs);
+	control->rx_chs = NULL;
+	control->tx_chs = NULL;
+	tavil_cleanup_irqs(tavil);
+
+	if (tavil->wdsp_cntl)
+		wcd_dsp_cntl_deinit(&tavil->wdsp_cntl);
+
+	/* Deinitialize MBHC module */
+	tavil_mbhc_deinit(codec);
+	tavil->mbhc = NULL;
+
+	return 0;
+}
+
+static struct regmap *tavil_get_regmap(struct device *dev)
+{
+	struct wcd9xxx *control = dev_get_drvdata(dev->parent);
+
+	return control->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_tavil = {
+	.probe = tavil_soc_codec_probe,
+	.remove = tavil_soc_codec_remove,
+	.get_regmap = tavil_get_regmap,
+	.component_driver = {
+		.controls = tavil_snd_controls,
+		.num_controls = ARRAY_SIZE(tavil_snd_controls),
+		.dapm_widgets = tavil_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(tavil_dapm_widgets),
+		.dapm_routes = tavil_audio_map,
+		.num_dapm_routes = ARRAY_SIZE(tavil_audio_map),
+	},
+};
+
+#ifdef CONFIG_PM
+static int tavil_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tavil_priv *tavil = platform_get_drvdata(pdev);
+
+	if (!tavil) {
+		dev_err(dev, "%s: tavil private data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_dbg(dev, "%s: system suspend\n", __func__);
+	if (delayed_work_pending(&tavil->power_gate_work) &&
+	    cancel_delayed_work_sync(&tavil->power_gate_work))
+		tavil_codec_power_gate_digital_core(tavil);
+	return 0;
+}
+
+static int tavil_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tavil_priv *tavil = platform_get_drvdata(pdev);
+
+	if (!tavil) {
+		dev_err(dev, "%s: tavil private data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_dbg(dev, "%s: system resume\n", __func__);
+	return 0;
+}
+
+static const struct dev_pm_ops tavil_pm_ops = {
+	.suspend = tavil_suspend,
+	.resume = tavil_resume,
+};
+#endif
+
+static int tavil_swrm_read(void *handle, int reg)
+{
+	struct tavil_priv *tavil;
+	struct wcd9xxx *wcd9xxx;
+	unsigned short swr_rd_addr_base;
+	unsigned short swr_rd_data_base;
+	int val, ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	tavil = (struct tavil_priv *)handle;
+	wcd9xxx = tavil->wcd9xxx;
+
+	dev_dbg(tavil->dev, "%s: Reading soundwire register, 0x%x\n",
+		__func__, reg);
+	swr_rd_addr_base = WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0;
+	swr_rd_data_base = WCD934X_SWR_AHB_BRIDGE_RD_DATA_0;
+
+	mutex_lock(&tavil->swr.read_mutex);
+	ret = regmap_bulk_write(wcd9xxx->regmap, swr_rd_addr_base,
+				 (u8 *)&reg, 4);
+	if (ret < 0) {
+		dev_err(tavil->dev, "%s: RD Addr Failure\n", __func__);
+		goto done;
+	}
+	ret = regmap_bulk_read(wcd9xxx->regmap, swr_rd_data_base,
+				(u8 *)&val, 4);
+	if (ret < 0) {
+		dev_err(tavil->dev, "%s: RD Data Failure\n", __func__);
+		goto done;
+	}
+	ret = val;
+done:
+	mutex_unlock(&tavil->swr.read_mutex);
+
+	return ret;
+}
+
+static int tavil_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len)
+{
+	struct tavil_priv *tavil;
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_reg_val *bulk_reg;
+	unsigned short swr_wr_addr_base;
+	unsigned short swr_wr_data_base;
+	int i, j, ret;
+
+	if (!handle || !reg || !val) {
+		pr_err("%s: NULL parameter\n", __func__);
+		return -EINVAL;
+	}
+	if (len <= 0) {
+		pr_err("%s: Invalid size: %zu\n", __func__, len);
+		return -EINVAL;
+	}
+	tavil = (struct tavil_priv *)handle;
+	wcd9xxx = tavil->wcd9xxx;
+
+	swr_wr_addr_base = WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0;
+	swr_wr_data_base = WCD934X_SWR_AHB_BRIDGE_WR_DATA_0;
+
+	bulk_reg = kzalloc((2 * len * sizeof(struct wcd9xxx_reg_val)),
+			   GFP_KERNEL);
+	if (!bulk_reg)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < (len * 2); i += 2, j++) {
+		bulk_reg[i].reg = swr_wr_data_base;
+		bulk_reg[i].buf = (u8 *)(&val[j]);
+		bulk_reg[i].bytes = 4;
+		bulk_reg[i+1].reg = swr_wr_addr_base;
+		bulk_reg[i+1].buf = (u8 *)(&reg[j]);
+		bulk_reg[i+1].bytes = 4;
+	}
+
+	mutex_lock(&tavil->swr.write_mutex);
+	ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg,
+			 (len * 2), false);
+	if (ret) {
+		dev_err(tavil->dev, "%s: swrm bulk write failed, ret: %d\n",
+			__func__, ret);
+	}
+	mutex_unlock(&tavil->swr.write_mutex);
+
+	kfree(bulk_reg);
+	return ret;
+}
+
+static int tavil_swrm_write(void *handle, int reg, int val)
+{
+	struct tavil_priv *tavil;
+	struct wcd9xxx *wcd9xxx;
+	unsigned short swr_wr_addr_base;
+	unsigned short swr_wr_data_base;
+	struct wcd9xxx_reg_val bulk_reg[2];
+	int ret;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	tavil = (struct tavil_priv *)handle;
+	wcd9xxx = tavil->wcd9xxx;
+
+	swr_wr_addr_base = WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0;
+	swr_wr_data_base = WCD934X_SWR_AHB_BRIDGE_WR_DATA_0;
+
+	/* First Write the Data to register */
+	bulk_reg[0].reg = swr_wr_data_base;
+	bulk_reg[0].buf = (u8 *)(&val);
+	bulk_reg[0].bytes = 4;
+	bulk_reg[1].reg = swr_wr_addr_base;
+	bulk_reg[1].buf = (u8 *)(&reg);
+	bulk_reg[1].bytes = 4;
+
+	mutex_lock(&tavil->swr.write_mutex);
+	ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2, false);
+	if (ret < 0)
+		dev_err(tavil->dev, "%s: WR Data Failure\n", __func__);
+	mutex_unlock(&tavil->swr.write_mutex);
+
+	return ret;
+}
+
+static int tavil_swrm_clock(void *handle, bool enable)
+{
+	struct tavil_priv *tavil;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	tavil = (struct tavil_priv *)handle;
+
+	mutex_lock(&tavil->swr.clk_mutex);
+	dev_dbg(tavil->dev, "%s: swrm clock %s\n",
+		__func__, (enable?"enable" : "disable"));
+	if (enable) {
+		tavil->swr.clk_users++;
+		if (tavil->swr.clk_users == 1) {
+			regmap_update_bits(tavil->wcd9xxx->regmap,
+					WCD934X_TEST_DEBUG_NPL_DLY_TEST_1,
+					0x10, 0x00);
+			__tavil_cdc_mclk_enable(tavil, true);
+			regmap_update_bits(tavil->wcd9xxx->regmap,
+				WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x01);
+		}
+	} else {
+		tavil->swr.clk_users--;
+		if (tavil->swr.clk_users == 0) {
+			regmap_update_bits(tavil->wcd9xxx->regmap,
+				WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+				0x01, 0x00);
+			__tavil_cdc_mclk_enable(tavil, false);
+			regmap_update_bits(tavil->wcd9xxx->regmap,
+					WCD934X_TEST_DEBUG_NPL_DLY_TEST_1,
+					0x10, 0x10);
+		}
+	}
+	dev_dbg(tavil->dev, "%s: swrm clock users %d\n",
+		__func__, tavil->swr.clk_users);
+	mutex_unlock(&tavil->swr.clk_mutex);
+
+	return 0;
+}
+
+static int tavil_swrm_handle_irq(void *handle,
+				 irqreturn_t (*swrm_irq_handler)(int irq,
+								 void *data),
+				 void *swrm_handle,
+				 int action)
+{
+	struct tavil_priv *tavil;
+	int ret = 0;
+	struct wcd9xxx *wcd9xxx;
+
+	if (!handle) {
+		pr_err("%s: NULL handle\n", __func__);
+		return -EINVAL;
+	}
+	tavil = (struct tavil_priv *) handle;
+	wcd9xxx = tavil->wcd9xxx;
+
+	if (action) {
+		ret = wcd9xxx_request_irq(&wcd9xxx->core_res,
+					  WCD934X_IRQ_SOUNDWIRE,
+					  swrm_irq_handler,
+					  "Tavil SWR Master", swrm_handle);
+		if (ret)
+			dev_err(tavil->dev, "%s: Failed to request irq %d\n",
+				__func__, WCD934X_IRQ_SOUNDWIRE);
+	} else
+		wcd9xxx_free_irq(&wcd9xxx->core_res, WCD934X_IRQ_SOUNDWIRE,
+				 swrm_handle);
+
+	return ret;
+}
+
+static void tavil_codec_add_spi_device(struct tavil_priv *tavil,
+				       struct device_node *node)
+{
+	struct spi_master *master;
+	struct spi_device *spi;
+	u32 prop_value;
+	int rc;
+
+	/* Read the master bus num from DT node */
+	rc = of_property_read_u32(node, "qcom,master-bus-num",
+				  &prop_value);
+	if (rc < 0) {
+		dev_err(tavil->dev, "%s: prop %s not found in node %s",
+			__func__, "qcom,master-bus-num", node->full_name);
+		goto done;
+	}
+
+	/* Get the reference to SPI master */
+	master = spi_busnum_to_master(prop_value);
+	if (!master) {
+		dev_err(tavil->dev, "%s: Invalid spi_master for bus_num %u\n",
+			__func__, prop_value);
+		goto done;
+	}
+
+	/* Allocate the spi device */
+	spi = spi_alloc_device(master);
+	if (!spi) {
+		dev_err(tavil->dev, "%s: spi_alloc_device failed\n",
+			__func__);
+		goto err_spi_alloc_dev;
+	}
+
+	/* Initialize device properties */
+	if (of_modalias_node(node, spi->modalias,
+			     sizeof(spi->modalias)) < 0) {
+		dev_err(tavil->dev, "%s: cannot find modalias for %s\n",
+			__func__, node->full_name);
+		goto err_dt_parse;
+	}
+
+	rc = of_property_read_u32(node, "qcom,chip-select",
+				  &prop_value);
+	if (rc < 0) {
+		dev_err(tavil->dev, "%s: prop %s not found in node %s",
+			__func__, "qcom,chip-select", node->full_name);
+		goto err_dt_parse;
+	}
+	spi->chip_select = prop_value;
+
+	rc = of_property_read_u32(node, "qcom,max-frequency",
+				  &prop_value);
+	if (rc < 0) {
+		dev_err(tavil->dev, "%s: prop %s not found in node %s",
+			__func__, "qcom,max-frequency", node->full_name);
+		goto err_dt_parse;
+	}
+	spi->max_speed_hz = prop_value;
+
+	spi->dev.of_node = node;
+
+	rc = spi_add_device(spi);
+	if (rc < 0) {
+		dev_err(tavil->dev, "%s: spi_add_device failed\n", __func__);
+		goto err_dt_parse;
+	}
+
+	/* Put the reference to SPI master */
+	put_device(&master->dev);
+
+	return;
+
+err_dt_parse:
+	spi_dev_put(spi);
+
+err_spi_alloc_dev:
+	/* Put the reference to SPI master */
+	put_device(&master->dev);
+done:
+	return;
+}
+
+static void tavil_add_child_devices(struct work_struct *work)
+{
+	struct tavil_priv *tavil;
+	struct platform_device *pdev;
+	struct device_node *node;
+	struct wcd9xxx *wcd9xxx;
+	struct tavil_swr_ctrl_data *swr_ctrl_data = NULL, *temp;
+	int ret, ctrl_num = 0;
+	struct wcd_swr_ctrl_platform_data *platdata;
+	char plat_dev_name[WCD934X_STRING_LEN];
+
+	tavil = container_of(work, struct tavil_priv,
+			     tavil_add_child_devices_work);
+	if (!tavil) {
+		pr_err("%s: Memory for WCD934X does not exist\n",
+			__func__);
+		return;
+	}
+	wcd9xxx = tavil->wcd9xxx;
+	if (!wcd9xxx) {
+		pr_err("%s: Memory for WCD9XXX does not exist\n",
+			__func__);
+		return;
+	}
+	if (!wcd9xxx->dev->of_node) {
+		dev_err(wcd9xxx->dev, "%s: DT node for wcd9xxx does not exist\n",
+			__func__);
+		return;
+	}
+
+	platdata = &tavil->swr.plat_data;
+
+	for_each_child_of_node(wcd9xxx->dev->of_node, node) {
+
+		/* Parse and add the SPI device node */
+		if (!strcmp(node->name, "wcd_spi")) {
+			tavil_codec_add_spi_device(tavil, node);
+			continue;
+		}
+
+		/* Parse other child device nodes and add platform device */
+		if (!strcmp(node->name, "swr_master"))
+			strlcpy(plat_dev_name, "tavil_swr_ctrl",
+				(WCD934X_STRING_LEN - 1));
+		else if (strnstr(node->name, "msm_cdc_pinctrl",
+				 strlen("msm_cdc_pinctrl")) != NULL)
+			strlcpy(plat_dev_name, node->name,
+				(WCD934X_STRING_LEN - 1));
+		else
+			continue;
+
+		pdev = platform_device_alloc(plat_dev_name, -1);
+		if (!pdev) {
+			dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n",
+				__func__);
+			ret = -ENOMEM;
+			goto err_mem;
+		}
+		pdev->dev.parent = tavil->dev;
+		pdev->dev.of_node = node;
+
+		if (strcmp(node->name, "swr_master") == 0) {
+			ret = platform_device_add_data(pdev, platdata,
+						       sizeof(*platdata));
+			if (ret) {
+				dev_err(&pdev->dev,
+					"%s: cannot add plat data ctrl:%d\n",
+					__func__, ctrl_num);
+				goto err_pdev_add;
+			}
+		}
+
+		ret = platform_device_add(pdev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s: Cannot add platform device\n",
+				__func__);
+			goto err_pdev_add;
+		}
+
+		if (strcmp(node->name, "swr_master") == 0) {
+			temp = krealloc(swr_ctrl_data,
+					(ctrl_num + 1) * sizeof(
+					struct tavil_swr_ctrl_data),
+					GFP_KERNEL);
+			if (!temp) {
+				dev_err(wcd9xxx->dev, "out of memory\n");
+				ret = -ENOMEM;
+				goto err_pdev_add;
+			}
+			swr_ctrl_data = temp;
+			swr_ctrl_data[ctrl_num].swr_pdev = pdev;
+			ctrl_num++;
+			dev_dbg(&pdev->dev,
+				"%s: Added soundwire ctrl device(s)\n",
+				__func__);
+			tavil->swr.ctrl_data = swr_ctrl_data;
+		}
+	}
+
+	return;
+
+err_pdev_add:
+	platform_device_put(pdev);
+err_mem:
+	return;
+}
+
+static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
+{
+	int val, rc;
+
+	WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
+	__tavil_cdc_mclk_enable_locked(tavil, true);
+
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10);
+	regmap_update_bits(tavil->wcd9xxx->regmap,
+			WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
+	/*
+	 * 5ms sleep required after enabling efuse control
+	 * before checking the status.
+	 */
+	usleep_range(5000, 5500);
+	wcd_resmgr_set_sido_input_src(tavil->resmgr,
+					     SIDO_SOURCE_RCO_BG);
+
+	WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
+
+	rc = regmap_read(tavil->wcd9xxx->regmap,
+			 WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
+	if (rc || (!(val & 0x01)))
+		WARN(1, "%s: Efuse sense is not complete val=%x, ret=%d\n",
+			__func__, val, rc);
+
+	__tavil_cdc_mclk_enable(tavil, false);
+
+	return rc;
+}
+
+static void ___tavil_get_codec_fine_version(struct tavil_priv *tavil)
+{
+	int val1, val2, version;
+	struct regmap *regmap;
+	u16 id_minor;
+	u32 version_mask = 0;
+
+	regmap = tavil->wcd9xxx->regmap;
+	version = tavil->wcd9xxx->version;
+	id_minor = tavil->wcd9xxx->codec_type->id_minor;
+
+	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val1);
+	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val2);
+
+	dev_dbg(tavil->dev, "%s: chip version :0x%x 0x:%x\n",
+		__func__, val1, val2);
+
+	version_mask |= (!!((u8)val1 & 0x80)) << DSD_DISABLED_MASK;
+	version_mask |= (!!((u8)val2 & 0x01)) << SLNQ_DISABLED_MASK;
+
+	switch (version_mask) {
+	case DSD_DISABLED | SLNQ_DISABLED:
+		if (id_minor == cpu_to_le16(0))
+			version = TAVIL_VERSION_WCD9340_1_0;
+		else if (id_minor == cpu_to_le16(0x01))
+			version = TAVIL_VERSION_WCD9340_1_1;
+		break;
+	case SLNQ_DISABLED:
+		if (id_minor == cpu_to_le16(0))
+			version = TAVIL_VERSION_WCD9341_1_0;
+		else if (id_minor == cpu_to_le16(0x01))
+			version = TAVIL_VERSION_WCD9341_1_1;
+		break;
+	}
+
+	tavil->wcd9xxx->version = version;
+	tavil->wcd9xxx->codec_type->version = version;
+}
+
+/*
+ * tavil_get_wcd_dsp_cntl: Get the reference to wcd_dsp_cntl
+ * @dev: Device pointer for codec device
+ *
+ * This API gets the reference to codec's struct wcd_dsp_cntl
+ */
+struct wcd_dsp_cntl *tavil_get_wcd_dsp_cntl(struct device *dev)
+{
+	struct platform_device *pdev;
+	struct tavil_priv *tavil;
+
+	if (!dev) {
+		pr_err("%s: Invalid device\n", __func__);
+		return NULL;
+	}
+
+	pdev = to_platform_device(dev);
+	tavil = platform_get_drvdata(pdev);
+
+	return tavil->wdsp_cntl;
+}
+EXPORT_SYMBOL(tavil_get_wcd_dsp_cntl);
+
+static int tavil_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct tavil_priv *tavil;
+	struct clk *wcd_ext_clk;
+	struct wcd9xxx_resmgr_v2 *resmgr;
+	struct wcd9xxx_power_region *cdc_pwr;
+
+	tavil = devm_kzalloc(&pdev->dev, sizeof(struct tavil_priv),
+			    GFP_KERNEL);
+	if (!tavil)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, tavil);
+
+	tavil->wcd9xxx = dev_get_drvdata(pdev->dev.parent);
+	tavil->dev = &pdev->dev;
+	INIT_DELAYED_WORK(&tavil->power_gate_work, tavil_codec_power_gate_work);
+	mutex_init(&tavil->power_lock);
+	INIT_WORK(&tavil->tavil_add_child_devices_work,
+		  tavil_add_child_devices);
+	mutex_init(&tavil->micb_lock);
+	mutex_init(&tavil->swr.read_mutex);
+	mutex_init(&tavil->swr.write_mutex);
+	mutex_init(&tavil->swr.clk_mutex);
+	mutex_init(&tavil->codec_mutex);
+	mutex_init(&tavil->svs_mutex);
+
+	/*
+	 * Codec hardware by default comes up in SVS mode.
+	 * Initialize the svs_ref_cnt to 1 to reflect the hardware
+	 * state in the driver.
+	 */
+	tavil->svs_ref_cnt = 1;
+
+	cdc_pwr = devm_kzalloc(&pdev->dev, sizeof(struct wcd9xxx_power_region),
+				GFP_KERNEL);
+	if (!cdc_pwr) {
+		ret = -ENOMEM;
+		goto err_resmgr;
+	}
+	tavil->wcd9xxx->wcd9xxx_pwr[WCD9XXX_DIG_CORE_REGION_1] = cdc_pwr;
+	cdc_pwr->pwr_collapse_reg_min = WCD934X_DIG_CORE_REG_MIN;
+	cdc_pwr->pwr_collapse_reg_max = WCD934X_DIG_CORE_REG_MAX;
+	wcd9xxx_set_power_state(tavil->wcd9xxx,
+				WCD_REGION_POWER_COLLAPSE_REMOVE,
+				WCD9XXX_DIG_CORE_REGION_1);
+	/*
+	 * Init resource manager so that if child nodes such as SoundWire
+	 * requests for clock, resource manager can honor the request
+	 */
+	resmgr = wcd_resmgr_init(&tavil->wcd9xxx->core_res, NULL);
+	if (IS_ERR(resmgr)) {
+		ret = PTR_ERR(resmgr);
+		dev_err(&pdev->dev, "%s: Failed to initialize wcd resmgr\n",
+			__func__);
+		goto err_resmgr;
+	}
+	tavil->resmgr = resmgr;
+	tavil->swr.plat_data.handle = (void *) tavil;
+	tavil->swr.plat_data.read = tavil_swrm_read;
+	tavil->swr.plat_data.write = tavil_swrm_write;
+	tavil->swr.plat_data.bulk_write = tavil_swrm_bulk_write;
+	tavil->swr.plat_data.clk = tavil_swrm_clock;
+	tavil->swr.plat_data.handle_irq = tavil_swrm_handle_irq;
+	tavil->swr.spkr_gain_offset = WCD934X_RX_GAIN_OFFSET_0_DB;
+
+	/* Register for Clock */
+	wcd_ext_clk = clk_get(tavil->wcd9xxx->dev, "wcd_clk");
+	if (IS_ERR(wcd_ext_clk)) {
+		dev_err(tavil->wcd9xxx->dev, "%s: clk get %s failed\n",
+			__func__, "wcd_ext_clk");
+		goto err_clk;
+	}
+	tavil->wcd_ext_clk = wcd_ext_clk;
+	set_bit(AUDIO_NOMINAL, &tavil->status_mask);
+	/* Update codec register default values */
+	dev_dbg(&pdev->dev, "%s: MCLK Rate = %x\n", __func__,
+		tavil->wcd9xxx->mclk_rate);
+	if (tavil->wcd9xxx->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ)
+		regmap_update_bits(tavil->wcd9xxx->regmap,
+				   WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+				   0x03, 0x00);
+	else if (tavil->wcd9xxx->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ)
+		regmap_update_bits(tavil->wcd9xxx->regmap,
+				   WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+				   0x03, 0x01);
+	tavil_update_reg_defaults(tavil);
+	__tavil_enable_efuse_sensing(tavil);
+	___tavil_get_codec_fine_version(tavil);
+	tavil_update_cpr_defaults(tavil);
+
+	/* Register with soc framework */
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tavil,
+				  tavil_dai, ARRAY_SIZE(tavil_dai));
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Codec registration failed\n",
+		 __func__);
+		goto err_cdc_reg;
+	}
+	schedule_work(&tavil->tavil_add_child_devices_work);
+
+	return ret;
+
+err_cdc_reg:
+	clk_put(tavil->wcd_ext_clk);
+err_clk:
+	wcd_resmgr_remove(tavil->resmgr);
+err_resmgr:
+	mutex_destroy(&tavil->micb_lock);
+	mutex_destroy(&tavil->svs_mutex);
+	mutex_destroy(&tavil->codec_mutex);
+	mutex_destroy(&tavil->swr.read_mutex);
+	mutex_destroy(&tavil->swr.write_mutex);
+	mutex_destroy(&tavil->swr.clk_mutex);
+	devm_kfree(&pdev->dev, tavil);
+
+	return ret;
+}
+
+static int tavil_remove(struct platform_device *pdev)
+{
+	struct tavil_priv *tavil;
+
+	tavil = platform_get_drvdata(pdev);
+	if (!tavil)
+		return -EINVAL;
+
+	mutex_destroy(&tavil->micb_lock);
+	mutex_destroy(&tavil->svs_mutex);
+	mutex_destroy(&tavil->codec_mutex);
+	mutex_destroy(&tavil->swr.read_mutex);
+	mutex_destroy(&tavil->swr.write_mutex);
+	mutex_destroy(&tavil->swr.clk_mutex);
+
+	snd_soc_unregister_codec(&pdev->dev);
+	clk_put(tavil->wcd_ext_clk);
+	wcd_resmgr_remove(tavil->resmgr);
+	if (tavil->dsd_config) {
+		tavil_dsd_deinit(tavil->dsd_config);
+		tavil->dsd_config = NULL;
+	}
+	devm_kfree(&pdev->dev, tavil);
+	return 0;
+}
+
+static struct platform_driver tavil_codec_driver = {
+	.probe = tavil_probe,
+	.remove = tavil_remove,
+	.driver = {
+		.name = "tavil_codec",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &tavil_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(tavil_codec_driver);
+
+MODULE_DESCRIPTION("Tavil Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd934x/wcd934x.h b/asoc/codecs/wcd934x/wcd934x.h
new file mode 100644
index 0000000..ccd48ff
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef WCD934X_H
+#define WCD934X_H
+
+#include <dsp/apr_audio-v2.h>
+#include "wcd934x-dsp-cntl.h"
+#include "../wcd9xxx-slimslave.h"
+#include "../wcd9xxx-common-v2.h"
+#include "../wcd-mbhc-v2.h"
+
+#define WCD934X_REGISTER_START_OFFSET  0x800
+#define WCD934X_SB_PGD_PORT_RX_BASE   0x40
+#define WCD934X_SB_PGD_PORT_TX_BASE   0x50
+#define WCD934X_RX_PORT_START_NUMBER  16
+
+#define WCD934X_DMIC_CLK_DIV_2  0x0
+#define WCD934X_DMIC_CLK_DIV_3  0x1
+#define WCD934X_DMIC_CLK_DIV_4  0x2
+#define WCD934X_DMIC_CLK_DIV_6  0x3
+#define WCD934X_DMIC_CLK_DIV_8  0x4
+#define WCD934X_DMIC_CLK_DIV_16  0x5
+#define WCD934X_DMIC_CLK_DRIVE_DEFAULT 0x02
+
+#define WCD934X_ANC_DMIC_X2_FULL_RATE 1
+#define WCD934X_ANC_DMIC_X2_HALF_RATE 0
+
+#define TAVIL_MAX_MICBIAS 4
+#define TAVIL_NUM_INTERPOLATORS 9
+#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH    64
+
+/* Convert from vout ctl to micbias voltage in mV */
+#define  WCD_VOUT_CTL_TO_MICB(v)  (1000 + v * 50)
+
+/* Feature masks to distinguish codec version */
+#define DSD_DISABLED_MASK   0
+#define SLNQ_DISABLED_MASK  1
+
+#define DSD_DISABLED   (1 << DSD_DISABLED_MASK)
+#define SLNQ_DISABLED  (1 << SLNQ_DISABLED_MASK)
+
+/* Number of input and output Slimbus port */
+enum {
+	WCD934X_RX0 = 0,
+	WCD934X_RX1,
+	WCD934X_RX2,
+	WCD934X_RX3,
+	WCD934X_RX4,
+	WCD934X_RX5,
+	WCD934X_RX6,
+	WCD934X_RX7,
+	WCD934X_RX_MAX,
+};
+
+enum {
+	WCD934X_TX0 = 0,
+	WCD934X_TX1,
+	WCD934X_TX2,
+	WCD934X_TX3,
+	WCD934X_TX4,
+	WCD934X_TX5,
+	WCD934X_TX6,
+	WCD934X_TX7,
+	WCD934X_TX8,
+	WCD934X_TX9,
+	WCD934X_TX10,
+	WCD934X_TX11,
+	WCD934X_TX12,
+	WCD934X_TX13,
+	WCD934X_TX14,
+	WCD934X_TX15,
+	WCD934X_TX_MAX,
+};
+
+enum {
+	INTERP_EAR = 0,
+	INTERP_HPHL,
+	INTERP_HPHR,
+	INTERP_LO1,
+	INTERP_LO2,
+	INTERP_LO3_NA, /* LO3 not avalible in Tavil*/
+	INTERP_LO4_NA,
+	INTERP_SPKR1,
+	INTERP_SPKR2,
+	INTERP_MAX,
+};
+
+/*
+ * Selects compander and smart boost settings
+ * for a given speaker mode
+ */
+enum {
+	WCD934X_SPKR_MODE_DEFAULT,
+	WCD934X_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
+};
+
+/*
+ * Rx path gain offsets
+ */
+enum {
+	WCD934X_RX_GAIN_OFFSET_M1P5_DB,
+	WCD934X_RX_GAIN_OFFSET_0_DB,
+};
+
+/*
+ * Dai data structure holds the
+ * dai specific info like rate,
+ * channel number etc.
+ */
+struct tavil_codec_dai_data {
+	u32 rate;
+	u32 *ch_num;
+	u32 ch_act;
+	u32 ch_tot;
+};
+
+/*
+ * Structure used to update codec
+ * register defaults after reset
+ */
+struct tavil_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+extern void *tavil_get_afe_config(struct snd_soc_codec *codec,
+				  enum afe_config_type config_type);
+extern int tavil_cdc_mclk_enable(struct snd_soc_codec *codec, bool enable);
+extern int tavil_cdc_mclk_tx_enable(struct snd_soc_codec *codec, bool enable);
+extern int tavil_set_spkr_mode(struct snd_soc_codec *codec, int mode);
+extern int tavil_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset);
+extern struct wcd_dsp_cntl *tavil_get_wcd_dsp_cntl(struct device *dev);
+extern int wcd934x_get_micb_vout_ctl_val(u32 micb_mv);
+extern int tavil_micbias_control(struct snd_soc_codec *codec,
+				 int micb_num,
+				 int req, bool is_dapm);
+extern int tavil_mbhc_micb_adjust_voltage(struct snd_soc_codec *codec,
+					  int req_volt,
+					  int micb_num);
+extern struct wcd934x_mbhc *tavil_soc_get_mbhc(struct snd_soc_codec *codec);
+extern int tavil_codec_enable_interp_clk(struct snd_soc_codec *codec,
+					 int event, int intp_idx);
+extern struct tavil_dsd_config *tavil_get_dsd_config(
+				struct snd_soc_codec *codec);
+extern int tavil_codec_info_create_codec_entry(
+				struct snd_info_entry *codec_root,
+				struct snd_soc_codec *codec);
+#endif
diff --git a/asoc/codecs/wcd934x/wcd934x_irq.h b/asoc/codecs/wcd934x/wcd934x_irq.h
new file mode 100644
index 0000000..1a18be3
--- /dev/null
+++ b/asoc/codecs/wcd934x/wcd934x_irq.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD934X_IRQ_H_
+#define __WCD934X_IRQ_H_
+
+enum {
+	/* INTR_REG 0 */
+	WCD934X_IRQ_MISC = 1,
+	WCD934X_IRQ_HPH_PA_OCPL_FAULT,
+	WCD934X_IRQ_HPH_PA_OCPR_FAULT,
+	WCD934X_IRQ_EAR_PA_OCP_FAULT,
+	WCD934X_IRQ_HPH_PA_CNPL_COMPLETE,
+	WCD934X_IRQ_HPH_PA_CNPR_COMPLETE,
+	WCD934X_IRQ_EAR_PA_CNP_COMPLETE,
+	/* INTR_REG 1 */
+	WCD934X_IRQ_MBHC_SW_DET,
+	WCD934X_IRQ_MBHC_ELECT_INS_REM_DET,
+	WCD934X_IRQ_MBHC_BUTTON_PRESS_DET,
+	WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET,
+	WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	WCD934X_IRQ_RESERVED_0,
+	WCD934X_IRQ_RESERVED_1,
+	WCD934X_IRQ_RESERVED_2,
+	/* INTR_REG 2 */
+	WCD934X_IRQ_LINE_PA1_CNP_COMPLETE,
+	WCD934X_IRQ_LINE_PA2_CNP_COMPLETE,
+	WCD934X_IRQ_SLNQ_ANALOG_ERROR,
+	WCD934X_IRQ_RESERVED_3,
+	WCD934X_IRQ_SOUNDWIRE,
+	WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE,
+	WCD934X_IRQ_RCO_ERROR,
+	WCD934X_IRQ_CPE_ERROR,
+	/* INTR_REG 3 */
+	WCD934X_IRQ_MAD_AUDIO,
+	WCD934X_IRQ_MAD_BEACON,
+	WCD934X_IRQ_MAD_ULTRASOUND,
+	WCD934X_IRQ_VBAT_ATTACK,
+	WCD934X_IRQ_VBAT_RESTORE,
+	WCD934X_IRQ_CPE1_INTR,
+	WCD934X_IRQ_RESERVED_4,
+	WCD934X_IRQ_SLNQ_DIGITAL,
+	WCD934X_NUM_IRQS,
+};
+
+#endif
diff --git a/asoc/codecs/wcd9xxx-common-v2.c b/asoc/codecs/wcd9xxx-common-v2.c
new file mode 100644
index 0000000..478c0c6
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-common-v2.c
@@ -0,0 +1,1367 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "core.h"
+#include "wcd9xxx-common-v2.h"
+
+#define WCD_USLEEP_RANGE 50
+#define MAX_IMPED_PARAMS 6
+
+enum {
+	DAC_GAIN_0DB = 0,
+	DAC_GAIN_0P2DB,
+	DAC_GAIN_0P4DB,
+	DAC_GAIN_0P6DB,
+	DAC_GAIN_0P8DB,
+	DAC_GAIN_M0P2DB,
+	DAC_GAIN_M0P4DB,
+	DAC_GAIN_M0P6DB,
+};
+
+enum {
+	VREF_FILT_R_0OHM = 0,
+	VREF_FILT_R_25KOHM,
+	VREF_FILT_R_50KOHM,
+	VREF_FILT_R_100KOHM,
+};
+
+enum {
+	DELTA_I_0MA,
+	DELTA_I_10MA,
+	DELTA_I_20MA,
+	DELTA_I_30MA,
+	DELTA_I_40MA,
+	DELTA_I_50MA,
+};
+
+struct wcd_imped_val {
+	u32 imped_val;
+	u8 index;
+};
+
+static const struct wcd_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = {
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf5},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf5},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf5},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf5},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x0},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x0},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfe},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfe},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfe},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfe},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xff},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xff},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xff},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xff},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+};
+
+static const struct wcd_reg_mask_val imped_table_tavil[][MAX_IMPED_PARAMS] = {
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf2},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf4},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+	},
+	{
+		{WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+		{WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+		{WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+	},
+};
+
+static const struct wcd_imped_val imped_index[] = {
+	{4, 0},
+	{5, 1},
+	{6, 2},
+	{7, 3},
+	{8, 4},
+	{9, 5},
+	{10, 6},
+	{11, 7},
+	{12, 8},
+	{13, 9},
+};
+
+static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_codec *,
+					      struct wcd_clsh_cdc_data *,
+					      u8 req_state, bool en, int mode);
+
+static int get_impedance_index(int imped)
+{
+	int i = 0;
+
+	if (imped < imped_index[i].imped_val) {
+		pr_debug("%s, detected impedance is less than 4 Ohm\n",
+				__func__);
+		i = 0;
+		goto ret;
+	}
+	if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) {
+		pr_debug("%s, detected impedance is greater than 12 Ohm\n",
+				__func__);
+		i = ARRAY_SIZE(imped_index) - 1;
+		goto ret;
+	}
+	for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) {
+		if (imped >= imped_index[i].imped_val &&
+			imped < imped_index[i + 1].imped_val)
+			break;
+	}
+ret:
+	pr_debug("%s: selected impedance index = %d\n",
+			__func__, imped_index[i].index);
+	return imped_index[i].index;
+}
+
+/*
+ * Function: wcd_clsh_imped_config
+ * Params: codec, imped, reset
+ * Description:
+ * This function updates HPHL and HPHR gain settings
+ * according to the impedance value.
+ */
+void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, bool reset)
+{
+	int i;
+	int index = 0;
+	int table_size;
+
+	static const struct wcd_reg_mask_val
+				(*imped_table_ptr)[MAX_IMPED_PARAMS];
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (IS_CODEC_TYPE(wcd9xxx, WCD934X)) {
+		table_size = ARRAY_SIZE(imped_table_tavil);
+		imped_table_ptr = imped_table_tavil;
+	} else {
+		table_size = ARRAY_SIZE(imped_table);
+		imped_table_ptr = imped_table;
+	}
+
+	/* reset = 1, which means request is to reset the register values */
+	if (reset) {
+		for (i = 0; i < MAX_IMPED_PARAMS; i++)
+			snd_soc_update_bits(codec,
+				imped_table_ptr[index][i].reg,
+				imped_table_ptr[index][i].mask, 0);
+		return;
+	}
+	index = get_impedance_index(imped);
+	if (index >= (ARRAY_SIZE(imped_index) - 1)) {
+		pr_debug("%s, impedance not in range = %d\n", __func__, imped);
+		return;
+	}
+	if (index >= table_size) {
+		pr_debug("%s, impedance index not in range = %d\n", __func__,
+			index);
+		return;
+	}
+	for (i = 0; i < MAX_IMPED_PARAMS; i++)
+		snd_soc_update_bits(codec,
+				imped_table_ptr[index][i].reg,
+				imped_table_ptr[index][i].mask,
+				imped_table_ptr[index][i].val);
+}
+EXPORT_SYMBOL(wcd_clsh_imped_config);
+
+static bool is_native_44_1_active(struct snd_soc_codec *codec)
+{
+	bool native_active = false;
+	u8 native_clk, rx1_rate, rx2_rate;
+
+	native_clk = snd_soc_read(codec,
+				 WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL);
+	rx1_rate = snd_soc_read(codec, WCD9XXX_CDC_RX1_RX_PATH_CTL);
+	rx2_rate = snd_soc_read(codec, WCD9XXX_CDC_RX2_RX_PATH_CTL);
+
+	dev_dbg(codec->dev, "%s: native_clk %x rx1_rate= %x rx2_rate= %x",
+		__func__, native_clk, rx1_rate, rx2_rate);
+
+	if ((native_clk & 0x2) &&
+	    ((rx1_rate & 0x0F) == 0x9 || (rx2_rate & 0x0F) == 0x9))
+		native_active = true;
+
+	return native_active;
+}
+
+static const char *mode_to_str(int mode)
+{
+	switch (mode) {
+	case CLS_H_NORMAL:
+		return "CLS_H_NORMAL";
+	case CLS_H_HIFI:
+		return "CLS_H_HIFI";
+	case CLS_H_LOHIFI:
+		return "CLS_H_LOHIFI";
+	case CLS_H_LP:
+		return "CLS_H_LP";
+	case CLS_H_ULP:
+		return "CLS_H_ULP";
+	case CLS_AB:
+		return "CLS_AB";
+	case CLS_AB_HIFI:
+		return "CLS_AB_HIFI";
+	default:
+		return "CLS_H_INVALID";
+	};
+}
+
+static const char *state_to_str(u8 state, char *buf, size_t buflen)
+{
+	int i;
+	int cnt = 0;
+	/*
+	 * This array of strings should match with enum wcd_clsh_state_bit.
+	 */
+	static const char *const states[] = {
+		"STATE_EAR",
+		"STATE_HPH_L",
+		"STATE_HPH_R",
+		"STATE_LO",
+	};
+
+	if (state == WCD_CLSH_STATE_IDLE) {
+		snprintf(buf, buflen, "[STATE_IDLE]");
+		goto done;
+	}
+
+	buf[0] = '\0';
+	for (i = 0; i < ARRAY_SIZE(states); i++) {
+		if (!(state & (1 << i)))
+			continue;
+		cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
+			       buf[0] == '\0' ? "[" : "|",
+			       states[i]);
+	}
+	if (cnt > 0)
+		strlcat(buf + cnt, "]", buflen);
+
+done:
+	if (buf[0] == '\0')
+		snprintf(buf, buflen, "[STATE_UNKNOWN]");
+	return buf;
+}
+
+static inline void
+wcd_enable_clsh_block(struct snd_soc_codec *codec,
+		      struct wcd_clsh_cdc_data *clsh_d, bool enable)
+{
+	if ((enable && ++clsh_d->clsh_users == 1) ||
+	    (!enable && --clsh_d->clsh_users == 0))
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_CRC, 0x01,
+				    (u8) enable);
+	if (clsh_d->clsh_users < 0)
+		clsh_d->clsh_users = 0;
+	dev_dbg(codec->dev, "%s: clsh_users %d, enable %d", __func__,
+		clsh_d->clsh_users, enable);
+}
+
+static inline bool wcd_clsh_enable_status(struct snd_soc_codec *codec)
+{
+	return snd_soc_read(codec, WCD9XXX_A_CDC_CLSH_CRC) & 0x01;
+}
+
+static inline int wcd_clsh_get_int_mode(struct wcd_clsh_cdc_data *clsh_d,
+					int clsh_state)
+{
+	int mode;
+
+	if ((clsh_state != WCD_CLSH_STATE_EAR) &&
+	    (clsh_state != WCD_CLSH_STATE_HPHL) &&
+	    (clsh_state != WCD_CLSH_STATE_HPHR) &&
+	    (clsh_state != WCD_CLSH_STATE_LO))
+		mode = CLS_NONE;
+	else
+		mode = clsh_d->interpolator_modes[ffs(clsh_state)];
+
+	return mode;
+}
+
+static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_data *clsh_d,
+					int clsh_state, int mode)
+{
+	if ((clsh_state != WCD_CLSH_STATE_EAR) &&
+	    (clsh_state != WCD_CLSH_STATE_HPHL) &&
+	    (clsh_state != WCD_CLSH_STATE_HPHR) &&
+	    (clsh_state != WCD_CLSH_STATE_LO))
+		return;
+
+	clsh_d->interpolator_modes[ffs(clsh_state)] = mode;
+}
+
+static inline void wcd_clsh_set_buck_mode(struct snd_soc_codec *codec,
+					  int mode)
+{
+	if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
+	    mode == CLS_AB_HIFI || mode == CLS_AB)
+		snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
+				    0x08, 0x08); /* set to HIFI */
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
+				    0x08, 0x00); /* set to default */
+}
+
+static inline void wcd_clsh_set_flyback_mode(struct snd_soc_codec *codec,
+					     int mode)
+{
+	if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
+	    mode == CLS_AB_HIFI || mode == CLS_AB)
+		snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
+				    0x04, 0x04); /* set to HIFI */
+	else
+		snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
+				    0x04, 0x00); /* set to Default */
+}
+
+static inline void wcd_clsh_gm3_boost_disable(struct snd_soc_codec *codec,
+					      int mode)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!IS_CODEC_TYPE(wcd9xxx, WCD934X))
+		return;
+
+	if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
+	    mode == CLS_AB_HIFI || mode == CLS_AB) {
+		if (TAVIL_IS_1_0(wcd9xxx))
+			snd_soc_update_bits(codec, WCD9XXX_HPH_CNP_WG_CTL,
+					    0x80, 0x0); /* disable GM3 Boost */
+		snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4,
+				    0xF0, 0x80);
+	} else {
+		snd_soc_update_bits(codec, WCD9XXX_HPH_CNP_WG_CTL,
+				    0x80, 0x80); /* set to Default */
+		snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4,
+				    0xF0, 0x70);
+	}
+}
+
+
+static inline void wcd_clsh_force_iq_ctl(struct snd_soc_codec *codec,
+					 int mode)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!IS_CODEC_TYPE(wcd9xxx, WCD934X))
+		return;
+
+	if (mode == CLS_H_LOHIFI || mode == CLS_AB) {
+		snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2,
+				    0x20, 0x20);
+		snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER,
+				    0xF0, 0xC0);
+		snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1,
+				    0x0E, 0x02);
+	} else {
+
+		snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2,
+				    0x20, 0x0);
+		snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER,
+				    0xF0, 0x80);
+		snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1,
+				    0x0E, 0x06);
+	}
+}
+
+static void wcd_clsh_buck_ctrl(struct snd_soc_codec *codec,
+			       struct wcd_clsh_cdc_data *clsh_d,
+			       int mode,
+			       bool enable)
+{
+	/* enable/disable buck */
+	if ((enable && (++clsh_d->buck_users == 1)) ||
+	   (!enable && (--clsh_d->buck_users == 0)))
+		snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
+				    (1 << 7), (enable << 7));
+	dev_dbg(codec->dev, "%s: buck_users %d, enable %d, mode: %s",
+		__func__, clsh_d->buck_users, enable, mode_to_str(mode));
+	/*
+	 * 500us sleep is required after buck enable/disable
+	 * as per HW requirement
+	 */
+	usleep_range(500, 500 + WCD_USLEEP_RANGE);
+}
+
+static void wcd_clsh_flyback_ctrl(struct snd_soc_codec *codec,
+				  struct wcd_clsh_cdc_data *clsh_d,
+				  int mode,
+				  bool enable)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_reg_val bulk_reg[2];
+	u8 vneg[] = {0x00, 0x40};
+
+	/* enable/disable flyback */
+	if ((enable && (++clsh_d->flyback_users == 1)) ||
+	   (!enable && (--clsh_d->flyback_users == 0))) {
+		snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
+				    (1 << 6), (enable << 6));
+		/* 100usec delay is needed as per HW requirement */
+		usleep_range(100, 110);
+		if (enable && (TASHA_IS_1_1(wcd9xxx))) {
+			wcd_clsh_set_flyback_mode(codec, CLS_H_HIFI);
+			snd_soc_update_bits(codec, WCD9XXX_FLYBACK_EN,
+					    0x60, 0x40);
+			snd_soc_update_bits(codec, WCD9XXX_FLYBACK_EN,
+					    0x10, 0x10);
+			vneg[0] = snd_soc_read(codec,
+					       WCD9XXX_A_ANA_RX_SUPPLIES);
+			vneg[0] &= ~(0x40);
+			vneg[1] = vneg[0] | 0x40;
+			bulk_reg[0].reg = WCD9XXX_A_ANA_RX_SUPPLIES;
+			bulk_reg[0].buf = &vneg[0];
+			bulk_reg[0].bytes = 1;
+			bulk_reg[1].reg = WCD9XXX_A_ANA_RX_SUPPLIES;
+			bulk_reg[1].buf = &vneg[1];
+			bulk_reg[1].bytes = 1;
+			/* 500usec delay is needed as per HW requirement */
+			usleep_range(500, 510);
+			wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2,
+						false);
+			snd_soc_update_bits(codec, WCD9XXX_FLYBACK_EN,
+					    0x10, 0x00);
+			wcd_clsh_set_flyback_mode(codec, mode);
+		}
+
+	}
+	dev_dbg(codec->dev, "%s: flyback_users %d, enable %d, mode: %s",
+		__func__, clsh_d->flyback_users, enable, mode_to_str(mode));
+	/*
+	 * 500us sleep is required after flyback enable/disable
+	 * as per HW requirement
+	 */
+	usleep_range(500, 500 + WCD_USLEEP_RANGE);
+}
+
+static void wcd_clsh_set_gain_path(struct snd_soc_codec *codec,
+				   int mode)
+{
+	u8 val = 0;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!TASHA_IS_2_0(wcd9xxx))
+		return;
+
+	switch (mode) {
+	case CLS_H_NORMAL:
+	case CLS_AB:
+		val = 0x00;
+		break;
+	case CLS_H_HIFI:
+		val = 0x02;
+		break;
+	case CLS_H_LP:
+		val = 0x01;
+		break;
+	default:
+		return;
+	};
+	snd_soc_update_bits(codec, WCD9XXX_HPH_L_EN, 0xC0, (val << 6));
+	snd_soc_update_bits(codec, WCD9XXX_HPH_R_EN, 0xC0, (val << 6));
+}
+
+static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
+				  int mode)
+{
+	u8 val = 0;
+	u8 gain = 0;
+	u8 res_val = VREF_FILT_R_0OHM;
+	u8 ipeak = DELTA_I_50MA;
+
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	switch (mode) {
+	case CLS_H_NORMAL:
+		res_val = VREF_FILT_R_50KOHM;
+		val = 0x00;
+		gain = DAC_GAIN_0DB;
+		ipeak = DELTA_I_50MA;
+		break;
+	case CLS_AB:
+		val = 0x00;
+		gain = DAC_GAIN_0DB;
+		ipeak = DELTA_I_50MA;
+		break;
+	case CLS_AB_HIFI:
+		val = 0x08;
+		break;
+	case CLS_H_HIFI:
+		val = 0x08;
+		gain = DAC_GAIN_M0P2DB;
+		ipeak = DELTA_I_50MA;
+		break;
+	case CLS_H_LOHIFI:
+		val = 0x00;
+		if ((IS_CODEC_TYPE(wcd9xxx, WCD9335)) ||
+		    (IS_CODEC_TYPE(wcd9xxx, WCD9326))) {
+			val = 0x08;
+			gain = DAC_GAIN_M0P2DB;
+			ipeak = DELTA_I_50MA;
+		}
+		break;
+	case CLS_H_ULP:
+		val = 0x0C;
+		break;
+	case CLS_H_LP:
+		val = 0x04;
+		ipeak = DELTA_I_30MA;
+		break;
+	default:
+		return;
+	};
+
+	/*
+	 * For tavil set mode to Lower_power for
+	 * CLS_H_LOHIFI and CLS_AB
+	 */
+	if ((IS_CODEC_TYPE(wcd9xxx, WCD934X)) &&
+	    (mode == CLS_H_LOHIFI || mode == CLS_AB))
+		val = 0x04;
+
+	snd_soc_update_bits(codec, WCD9XXX_A_ANA_HPH, 0x0C, val);
+	if (TASHA_IS_2_0(wcd9xxx)) {
+		snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_VCL_2,
+				    0x30, (res_val << 4));
+		if (mode != CLS_H_LP)
+			snd_soc_update_bits(codec, WCD9XXX_HPH_REFBUFF_UHQA_CTL,
+					    0x07, gain);
+		snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_CCL_1,
+				    0xF0, (ipeak << 4));
+	}
+}
+
+static void wcd_clsh_set_flyback_vneg_ctl(struct snd_soc_codec *codec,
+					  bool enable)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!TASHA_IS_2_0(wcd9xxx))
+		return;
+
+	if (enable) {
+		snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0,
+				    0x00);
+		snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
+				    0xE0, (0x07 << 5));
+	} else {
+		snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0,
+				    (0x07 << 5));
+		snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
+				    0xE0, (0x02 << 5));
+	}
+}
+
+static void wcd_clsh_set_flyback_current(struct snd_soc_codec *codec, int mode)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+
+	if (!TASHA_IS_2_0(wcd9xxx))
+		return;
+
+	snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0x0F, 0x0A);
+	snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0xF0, 0xA0);
+	/* Sleep needed to avoid click and pop as per HW requirement */
+	usleep_range(100, 110);
+}
+
+static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_codec *codec,
+					     int mode)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
+			    0x02, 0x00);
+}
+
+static void wcd_clsh_state_lo(struct snd_soc_codec *codec,
+			      struct wcd_clsh_cdc_data *clsh_d,
+			      u8 req_state, bool is_enable, int mode)
+{
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (mode != CLS_AB && mode != CLS_AB_HIFI) {
+		dev_err(codec->dev, "%s: LO cannot be in this mode: %d\n",
+			__func__, mode);
+		return;
+	}
+
+	if (is_enable) {
+		wcd_clsh_set_buck_regulator_mode(codec, mode);
+		wcd_clsh_set_flyback_vneg_ctl(codec, true);
+		wcd_clsh_set_buck_mode(codec, mode);
+		wcd_clsh_set_flyback_mode(codec, mode);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
+		wcd_clsh_set_flyback_current(codec, mode);
+		wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
+	} else {
+		wcd_clsh_buck_ctrl(codec, clsh_d, mode, false);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, mode, false);
+		wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+		wcd_clsh_set_flyback_vneg_ctl(codec, false);
+		wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL);
+	}
+}
+
+static void wcd_clsh_state_hph_ear(struct snd_soc_codec *codec,
+				   struct wcd_clsh_cdc_data *clsh_d,
+				   u8 req_state, bool is_enable, int mode)
+{
+	int hph_mode = 0;
+
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (is_enable) {
+		if (req_state == WCD_CLSH_STATE_EAR) {
+			/* If HPH is running in CLS-AB when
+			 * EAR comes, let it continue to run
+			 * in Class-AB, no need to enable Class-H
+			 * for EAR.
+			 */
+			if (clsh_d->state & WCD_CLSH_STATE_HPHL)
+				hph_mode = wcd_clsh_get_int_mode(clsh_d,
+						WCD_CLSH_STATE_HPHL);
+			else if (clsh_d->state & WCD_CLSH_STATE_HPHR)
+				hph_mode = wcd_clsh_get_int_mode(clsh_d,
+						WCD_CLSH_STATE_HPHR);
+			else
+				return;
+			if (hph_mode != CLS_AB && hph_mode != CLS_AB_HIFI
+			    && !is_native_44_1_active(codec))
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+						0x40, 0x40);
+		}
+
+		if (is_native_44_1_active(codec)) {
+			snd_soc_write(codec, WCD9XXX_CDC_CLSH_HPH_V_PA, 0x39);
+			snd_soc_update_bits(codec,
+					WCD9XXX_CDC_RX0_RX_PATH_SEC0,
+					0x03, 0x00);
+			if ((req_state == WCD_CLSH_STATE_HPHL) ||
+			    (req_state == WCD_CLSH_STATE_HPHR))
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+						0x40, 0x00);
+		}
+
+		if (req_state == WCD_CLSH_STATE_HPHL)
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    0x40, 0x40);
+		if (req_state == WCD_CLSH_STATE_HPHR)
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    0x40, 0x40);
+		if ((req_state == WCD_CLSH_STATE_HPHL) ||
+		    (req_state == WCD_CLSH_STATE_HPHR)) {
+			wcd_clsh_set_gain_path(codec, mode);
+			wcd_clsh_set_flyback_mode(codec, mode);
+			wcd_clsh_set_buck_mode(codec, mode);
+		}
+	} else {
+		if (req_state == WCD_CLSH_STATE_EAR) {
+			/*
+			 * If EAR goes away, disable EAR Channel Enable
+			 * if HPH running in Class-H otherwise
+			 * and if HPH requested mode is CLS_AB then
+			 * no need to disable EAR channel enable bit.
+			 */
+			if (wcd_clsh_enable_status(codec))
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+						0x40, 0x00);
+		}
+
+		if (is_native_44_1_active(codec)) {
+			snd_soc_write(codec, WCD9XXX_CDC_CLSH_HPH_V_PA, 0x1C);
+			snd_soc_update_bits(codec,
+					WCD9XXX_CDC_RX0_RX_PATH_SEC0,
+					0x03, 0x01);
+			if (((clsh_d->state & WCD_CLSH_STATE_HPH_ST)
+				  != WCD_CLSH_STATE_HPH_ST) &&
+			    ((req_state == WCD_CLSH_STATE_HPHL) ||
+			     (req_state == WCD_CLSH_STATE_HPHR)))
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+						0x40, 0x40);
+		}
+
+		if (req_state == WCD_CLSH_STATE_HPHL)
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					0x40, 0x00);
+		if (req_state == WCD_CLSH_STATE_HPHR)
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					0x40, 0x00);
+		if ((req_state & WCD_CLSH_STATE_HPH_ST) &&
+		    !wcd_clsh_enable_status(codec)) {
+			/* If Class-H is not enabled when HPH is turned
+			 * off, enable it as EAR is in progress
+			 */
+			wcd_enable_clsh_block(codec, clsh_d, true);
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+					0x40, 0x40);
+			wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+			wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+		}
+	}
+}
+
+static void wcd_clsh_state_ear_lo(struct snd_soc_codec *codec,
+				  struct wcd_clsh_cdc_data *clsh_d,
+				  u8 req_state, bool is_enable, int mode)
+{
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (is_enable) {
+		/* LO powerup is taken care in PA sequence.
+		 * No need to change to class AB here.
+		 */
+		if (req_state == WCD_CLSH_STATE_EAR) {
+			/* EAR powerup.*/
+			if (!wcd_clsh_enable_status(codec)) {
+				wcd_enable_clsh_block(codec, clsh_d, true);
+				wcd_clsh_set_buck_mode(codec, mode);
+				wcd_clsh_set_flyback_mode(codec, mode);
+			}
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+					0x40, 0x40);
+		}
+	} else {
+		if (req_state == WCD_CLSH_STATE_EAR) {
+			/* EAR powerdown.*/
+			wcd_enable_clsh_block(codec, clsh_d, false);
+			wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+			wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+					0x40, 0x00);
+		}
+		/* LO powerdown is taken care in PA sequence.
+		 * No need to change to class H here.
+		 */
+	}
+}
+
+static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec,
+				  struct wcd_clsh_cdc_data *clsh_d,
+				  u8 req_state, bool is_enable, int mode)
+{
+	int hph_mode = 0;
+
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (is_enable) {
+		/*
+		 * If requested state is LO, put regulator
+		 * in class-AB or if requested state is HPH,
+		 * which means LO is already enabled, keep
+		 * the regulator config the same at class-AB
+		 * and just set the power modes for flyback
+		 * and buck.
+		 */
+		if (req_state == WCD_CLSH_STATE_LO)
+			wcd_clsh_set_buck_regulator_mode(codec, CLS_AB);
+		else {
+			if (!wcd_clsh_enable_status(codec)) {
+				wcd_enable_clsh_block(codec, clsh_d, true);
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_CLSH_K1_MSB,
+						0x0F, 0x00);
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_CLSH_K1_LSB,
+						0xFF, 0xC0);
+				wcd_clsh_set_flyback_mode(codec, mode);
+				wcd_clsh_set_flyback_vneg_ctl(codec, false);
+				wcd_clsh_set_buck_mode(codec, mode);
+				wcd_clsh_set_hph_mode(codec, mode);
+				wcd_clsh_set_gain_path(codec, mode);
+			} else {
+				dev_dbg(codec->dev, "%s:clsh is already enabled\n",
+					__func__);
+			}
+			if (req_state == WCD_CLSH_STATE_HPHL)
+				snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					0x40, 0x40);
+			if (req_state == WCD_CLSH_STATE_HPHR)
+				snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					0x40, 0x40);
+		}
+	} else {
+		if ((req_state == WCD_CLSH_STATE_HPHL) ||
+		    (req_state == WCD_CLSH_STATE_HPHR)) {
+			if (req_state == WCD_CLSH_STATE_HPHL)
+				snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    0x40, 0x00);
+			if (req_state == WCD_CLSH_STATE_HPHR)
+				snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    0x40, 0x00);
+			/*
+			 * If HPH is powering down first, then disable clsh,
+			 * set the buck/flyback mode to default and keep the
+			 * regulator at Class-AB
+			 */
+			if ((clsh_d->state & WCD_CLSH_STATE_HPH_ST)
+				!= WCD_CLSH_STATE_HPH_ST) {
+				wcd_enable_clsh_block(codec, clsh_d, false);
+				wcd_clsh_set_flyback_vneg_ctl(codec, true);
+				wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+				wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+			}
+		} else {
+			/* LO powerdown.
+			 * If HPH mode also is CLS-AB, no need
+			 * to turn-on class-H, otherwise enable
+			 * Class-H configuration.
+			 */
+			if (clsh_d->state & WCD_CLSH_STATE_HPHL)
+				hph_mode = wcd_clsh_get_int_mode(clsh_d,
+						WCD_CLSH_STATE_HPHL);
+			else if (clsh_d->state & WCD_CLSH_STATE_HPHR)
+				hph_mode = wcd_clsh_get_int_mode(clsh_d,
+						WCD_CLSH_STATE_HPHR);
+			else
+				return;
+			dev_dbg(codec->dev, "%s: hph_mode = %d\n", __func__,
+				hph_mode);
+
+			if ((hph_mode == CLS_AB) ||
+			   (hph_mode == CLS_AB_HIFI) ||
+			   (hph_mode == CLS_NONE))
+				goto end;
+
+			/*
+			 * If Class-H is already enabled (HPH ON and then
+			 * LO ON), no need to turn on again, just set the
+			 * regulator mode.
+			 */
+			if (wcd_clsh_enable_status(codec)) {
+				wcd_clsh_set_buck_regulator_mode(codec,
+								 hph_mode);
+				goto end;
+			} else {
+				dev_dbg(codec->dev, "%s: clsh is not enabled\n",
+					__func__);
+			}
+
+			wcd_enable_clsh_block(codec, clsh_d, true);
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_CLSH_K1_MSB,
+					0x0F, 0x00);
+			snd_soc_update_bits(codec,
+					WCD9XXX_A_CDC_CLSH_K1_LSB,
+					0xFF, 0xC0);
+			wcd_clsh_set_buck_regulator_mode(codec,
+							 hph_mode);
+			if (clsh_d->state & WCD_CLSH_STATE_HPHL)
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+						0x40, 0x40);
+			if (clsh_d->state & WCD_CLSH_STATE_HPHR)
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+						0x40, 0x40);
+			wcd_clsh_set_hph_mode(codec, hph_mode);
+		}
+	}
+end:
+	return;
+}
+
+static void wcd_clsh_state_hph_st(struct snd_soc_codec *codec,
+				  struct wcd_clsh_cdc_data *clsh_d,
+				  u8 req_state, bool is_enable, int mode)
+{
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (mode == CLS_AB || mode == CLS_AB_HIFI)
+		return;
+
+	if (is_enable) {
+		if (req_state == WCD_CLSH_STATE_HPHL)
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    0x40, 0x40);
+		if (req_state == WCD_CLSH_STATE_HPHR)
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    0x40, 0x40);
+	} else {
+		if (req_state == WCD_CLSH_STATE_HPHL)
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    0x40, 0x00);
+		if (req_state == WCD_CLSH_STATE_HPHR)
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    0x40, 0x00);
+	}
+}
+
+static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec,
+				 struct wcd_clsh_cdc_data *clsh_d,
+				 u8 req_state, bool is_enable, int mode)
+{
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (mode == CLS_H_NORMAL) {
+		dev_err(codec->dev, "%s: Normal mode not applicable for hph_r\n",
+			__func__);
+		return;
+	}
+
+	if (is_enable) {
+		if (mode != CLS_AB && mode != CLS_AB_HIFI) {
+			wcd_enable_clsh_block(codec, clsh_d, true);
+			/*
+			 * These K1 values depend on the Headphone Impedance
+			 * For now it is assumed to be 16 ohm
+			 */
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_MSB,
+					    0x0F, 0x00);
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_LSB,
+					    0xFF, 0xC0);
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    0x40, 0x40);
+		}
+		wcd_clsh_set_buck_regulator_mode(codec, mode);
+		wcd_clsh_set_flyback_mode(codec, mode);
+		wcd_clsh_gm3_boost_disable(codec, mode);
+		wcd_clsh_force_iq_ctl(codec, mode);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
+		wcd_clsh_set_flyback_current(codec, mode);
+		wcd_clsh_set_buck_mode(codec, mode);
+		wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
+		wcd_clsh_set_hph_mode(codec, mode);
+		wcd_clsh_set_gain_path(codec, mode);
+	} else {
+		wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
+
+		if (mode != CLS_AB && mode != CLS_AB_HIFI) {
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    0x40, 0x00);
+			wcd_enable_clsh_block(codec, clsh_d, false);
+		}
+		/* buck and flyback set to default mode and disable */
+		wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
+		wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL);
+		wcd_clsh_gm3_boost_disable(codec, CLS_H_NORMAL);
+		wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+		wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL);
+	}
+}
+
+static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec,
+				 struct wcd_clsh_cdc_data *clsh_d,
+				 u8 req_state, bool is_enable, int mode)
+{
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (mode == CLS_H_NORMAL) {
+		dev_err(codec->dev, "%s: Normal mode not applicable for hph_l\n",
+			__func__);
+		return;
+	}
+
+	if (is_enable) {
+		if (mode != CLS_AB && mode != CLS_AB_HIFI) {
+			wcd_enable_clsh_block(codec, clsh_d, true);
+			/*
+			 * These K1 values depend on the Headphone Impedance
+			 * For now it is assumed to be 16 ohm
+			 */
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_MSB,
+					    0x0F, 0x00);
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_LSB,
+					    0xFF, 0xC0);
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    0x40, 0x40);
+		}
+		wcd_clsh_set_buck_regulator_mode(codec, mode);
+		wcd_clsh_set_flyback_mode(codec, mode);
+		wcd_clsh_gm3_boost_disable(codec, mode);
+		wcd_clsh_force_iq_ctl(codec, mode);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
+		wcd_clsh_set_flyback_current(codec, mode);
+		wcd_clsh_set_buck_mode(codec, mode);
+		wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
+		wcd_clsh_set_hph_mode(codec, mode);
+		wcd_clsh_set_gain_path(codec, mode);
+	} else {
+		wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
+
+		if (mode != CLS_AB && mode != CLS_AB_HIFI) {
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    0x40, 0x00);
+			wcd_enable_clsh_block(codec, clsh_d, false);
+		}
+		/* set buck and flyback to Default Mode */
+		wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
+		wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL);
+		wcd_clsh_gm3_boost_disable(codec, CLS_H_NORMAL);
+		wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+		wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL);
+	}
+}
+
+static void wcd_clsh_state_ear(struct snd_soc_codec *codec,
+		struct wcd_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable, int mode)
+{
+	dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
+		is_enable ? "enable" : "disable");
+
+	if (mode != CLS_H_NORMAL) {
+		dev_err(codec->dev, "%s: mode: %s cannot be used for EAR\n",
+			__func__, mode_to_str(mode));
+		return;
+	}
+
+	if (is_enable) {
+		wcd_enable_clsh_block(codec, clsh_d, true);
+		snd_soc_update_bits(codec,
+				    WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+				    0x40, 0x40);
+		wcd_clsh_set_buck_mode(codec, mode);
+		wcd_clsh_set_flyback_mode(codec, mode);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
+		wcd_clsh_set_flyback_current(codec, mode);
+		wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
+	} else {
+		snd_soc_update_bits(codec,
+				    WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+				    0x40, 0x00);
+		wcd_enable_clsh_block(codec, clsh_d, false);
+		wcd_clsh_buck_ctrl(codec, clsh_d, mode, false);
+		wcd_clsh_flyback_ctrl(codec, clsh_d, mode, false);
+		wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
+	}
+}
+
+static void wcd_clsh_state_err(struct snd_soc_codec *codec,
+		struct wcd_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable, int mode)
+{
+	char msg[128];
+
+	dev_err(codec->dev,
+		"%s Wrong request for class H state machine requested to %s %s",
+		__func__, is_enable ? "enable" : "disable",
+		state_to_str(req_state, msg, sizeof(msg)));
+	WARN_ON(1);
+}
+
+/*
+ * Function: wcd_clsh_is_state_valid
+ * Params: state
+ * Description:
+ * Provides information on valid states of Class H configuration
+ */
+static bool wcd_clsh_is_state_valid(u8 state)
+{
+	switch (state) {
+	case WCD_CLSH_STATE_IDLE:
+	case WCD_CLSH_STATE_EAR:
+	case WCD_CLSH_STATE_HPHL:
+	case WCD_CLSH_STATE_HPHR:
+	case WCD_CLSH_STATE_HPH_ST:
+	case WCD_CLSH_STATE_LO:
+	case WCD_CLSH_STATE_HPHL_EAR:
+	case WCD_CLSH_STATE_HPHR_EAR:
+	case WCD_CLSH_STATE_HPH_ST_EAR:
+	case WCD_CLSH_STATE_HPHL_LO:
+	case WCD_CLSH_STATE_HPHR_LO:
+	case WCD_CLSH_STATE_HPH_ST_LO:
+	case WCD_CLSH_STATE_EAR_LO:
+		return true;
+	default:
+		return false;
+	};
+}
+
+/*
+ * Function: wcd_clsh_fsm
+ * Params: codec, cdc_clsh_d, req_state, req_type, clsh_event
+ * Description:
+ * This function handles PRE DAC and POST DAC conditions of different devices
+ * and updates class H configuration of different combination of devices
+ * based on validity of their states. cdc_clsh_d will contain current
+ * class h state information
+ */
+void wcd_clsh_fsm(struct snd_soc_codec *codec,
+		struct wcd_clsh_cdc_data *cdc_clsh_d,
+		u8 clsh_event, u8 req_state,
+		int int_mode)
+{
+	u8 old_state, new_state;
+	char msg0[128], msg1[128];
+
+	switch (clsh_event) {
+	case WCD_CLSH_EVENT_PRE_DAC:
+		old_state = cdc_clsh_d->state;
+		new_state = old_state | req_state;
+
+		if (!wcd_clsh_is_state_valid(new_state)) {
+			dev_err(codec->dev,
+				"%s: Class-H not a valid new state: %s\n",
+				__func__,
+				state_to_str(new_state, msg0, sizeof(msg0)));
+			return;
+		}
+		if (new_state == old_state) {
+			dev_err(codec->dev,
+				"%s: Class-H already in requested state: %s\n",
+				__func__,
+				state_to_str(new_state, msg0, sizeof(msg0)));
+			return;
+		}
+		cdc_clsh_d->state = new_state;
+		wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode);
+		(*clsh_state_fp[new_state]) (codec, cdc_clsh_d, req_state,
+					     CLSH_REQ_ENABLE, int_mode);
+		dev_dbg(codec->dev,
+			"%s: ClassH state transition from %s to %s\n",
+			__func__, state_to_str(old_state, msg0, sizeof(msg0)),
+			state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
+		break;
+	case WCD_CLSH_EVENT_POST_PA:
+		old_state = cdc_clsh_d->state;
+		new_state = old_state & (~req_state);
+		if (new_state < NUM_CLSH_STATES_V2) {
+			if (!wcd_clsh_is_state_valid(old_state)) {
+				dev_err(codec->dev,
+					"%s:Invalid old state:%s\n",
+					__func__,
+					state_to_str(old_state, msg0,
+						     sizeof(msg0)));
+				return;
+			}
+			if (new_state == old_state) {
+				dev_err(codec->dev,
+					"%s: Class-H already in requested state: %s\n",
+					__func__,
+					state_to_str(new_state, msg0,
+						     sizeof(msg0)));
+				return;
+			}
+			(*clsh_state_fp[old_state]) (codec, cdc_clsh_d,
+					req_state, CLSH_REQ_DISABLE,
+					int_mode);
+			cdc_clsh_d->state = new_state;
+			wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE);
+			dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
+				__func__, state_to_str(old_state, msg0,
+						       sizeof(msg0)),
+				state_to_str(cdc_clsh_d->state, msg1,
+					     sizeof(msg1)));
+		}
+		break;
+	};
+}
+EXPORT_SYMBOL(wcd_clsh_fsm);
+
+int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh)
+{
+	return clsh->state;
+}
+EXPORT_SYMBOL(wcd_clsh_get_clsh_state);
+
+void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh)
+{
+	int i;
+
+	clsh->state = WCD_CLSH_STATE_IDLE;
+
+	for (i = 0; i < NUM_CLSH_STATES_V2; i++)
+		clsh_state_fp[i] = wcd_clsh_state_err;
+
+	clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear;
+	clsh_state_fp[WCD_CLSH_STATE_HPHL] =
+						wcd_clsh_state_hph_l;
+	clsh_state_fp[WCD_CLSH_STATE_HPHR] =
+						wcd_clsh_state_hph_r;
+	clsh_state_fp[WCD_CLSH_STATE_HPH_ST] =
+						wcd_clsh_state_hph_st;
+	clsh_state_fp[WCD_CLSH_STATE_LO] = wcd_clsh_state_lo;
+	clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] =
+						wcd_clsh_state_hph_ear;
+	clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] =
+						wcd_clsh_state_hph_ear;
+	clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] =
+						wcd_clsh_state_hph_ear;
+	clsh_state_fp[WCD_CLSH_STATE_HPHL_LO] = wcd_clsh_state_hph_lo;
+	clsh_state_fp[WCD_CLSH_STATE_HPHR_LO] = wcd_clsh_state_hph_lo;
+	clsh_state_fp[WCD_CLSH_STATE_HPH_ST_LO] =
+						wcd_clsh_state_hph_lo;
+	clsh_state_fp[WCD_CLSH_STATE_EAR_LO] = wcd_clsh_state_ear_lo;
+	/* Set interpolaotr modes to NONE */
+	wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE);
+	wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE);
+	wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE);
+	wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_LO, CLS_NONE);
+	clsh->flyback_users = 0;
+	clsh->buck_users = 0;
+	clsh->clsh_users = 0;
+}
+EXPORT_SYMBOL(wcd_clsh_init);
+
+MODULE_DESCRIPTION("WCD9XXX Common Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd9xxx-common-v2.h b/asoc/codecs/wcd9xxx-common-v2.h
new file mode 100644
index 0000000..53c9a84
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-common-v2.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WCD9XXX_COMMON_V2
+
+#define _WCD9XXX_COMMON_V2
+
+#define CLSH_REQ_ENABLE true
+#define CLSH_REQ_DISABLE false
+
+#define WCD_CLSH_EVENT_PRE_DAC 0x01
+#define WCD_CLSH_EVENT_POST_PA 0x02
+#define MAX_VBAT_MONITOR_WRITES 17
+/*
+ * Basic states for Class H state machine.
+ * represented as a bit mask within a u8 data type
+ * bit 0: EAR mode
+ * bit 1: HPH Left mode
+ * bit 2: HPH Right mode
+ * bit 3: Lineout mode
+ */
+#define	WCD_CLSH_STATE_IDLE 0x00
+#define	WCD_CLSH_STATE_EAR (0x01 << 0)
+#define	WCD_CLSH_STATE_HPHL (0x01 << 1)
+#define	WCD_CLSH_STATE_HPHR (0x01 << 2)
+#define	WCD_CLSH_STATE_LO (0x01 << 3)
+
+/*
+ * Though number of CLSH states are 4, max state shoulbe be 5
+ * because state array index starts from 1.
+ */
+#define WCD_CLSH_STATE_MAX 5
+#define NUM_CLSH_STATES_V2 (0x01 << WCD_CLSH_STATE_MAX)
+
+
+/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
+#define WCD_CLSH_STATE_HPH_ST (WCD_CLSH_STATE_HPHL | \
+			       WCD_CLSH_STATE_HPHR)
+
+#define WCD_CLSH_STATE_HPHL_LO (WCD_CLSH_STATE_HPHL | \
+				    WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_HPHR_LO (WCD_CLSH_STATE_HPHR | \
+				    WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_HPH_ST_LO (WCD_CLSH_STATE_HPH_ST | \
+				      WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_EAR_LO (WCD_CLSH_STATE_EAR | \
+				   WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_HPHL_EAR (WCD_CLSH_STATE_HPHL | \
+				     WCD_CLSH_STATE_EAR)
+#define WCD_CLSH_STATE_HPHR_EAR (WCD_CLSH_STATE_HPHR | \
+				     WCD_CLSH_STATE_EAR)
+#define WCD_CLSH_STATE_HPH_ST_EAR (WCD_CLSH_STATE_HPH_ST | \
+				       WCD_CLSH_STATE_EAR)
+
+enum {
+	CLS_H_NORMAL = 0, /* Class-H Default */
+	CLS_H_HIFI, /* Class-H HiFi */
+	CLS_H_LP, /* Class-H Low Power */
+	CLS_AB, /* Class-AB Low HIFI*/
+	CLS_H_LOHIFI, /* LoHIFI */
+	CLS_H_ULP, /* Ultra Low power */
+	CLS_AB_HIFI, /* Class-AB */
+	CLS_NONE, /* None of the above modes */
+};
+
+/* Class H data that the codec driver will maintain */
+struct wcd_clsh_cdc_data {
+	u8 state;
+	int flyback_users;
+	int buck_users;
+	int clsh_users;
+	int interpolator_modes[WCD_CLSH_STATE_MAX];
+};
+
+struct wcd_mad_audio_header {
+	u32 reserved[3];
+	u32 num_reg_cfg;
+};
+
+struct wcd_mad_microphone_info {
+	uint8_t input_microphone;
+	uint8_t cycle_time;
+	uint8_t settle_time;
+	uint8_t padding;
+} __packed;
+
+struct wcd_mad_micbias_info {
+	uint8_t micbias;
+	uint8_t k_factor;
+	uint8_t external_bypass_capacitor;
+	uint8_t internal_biasing;
+	uint8_t cfilter;
+	uint8_t padding[3];
+} __packed;
+
+struct wcd_mad_rms_audio_beacon_info {
+	uint8_t rms_omit_samples;
+	uint8_t rms_comp_time;
+	uint8_t detection_mechanism;
+	uint8_t rms_diff_threshold;
+	uint8_t rms_threshold_lsb;
+	uint8_t rms_threshold_msb;
+	uint8_t padding[2];
+	uint8_t iir_coefficients[36];
+} __packed;
+
+struct wcd_mad_rms_ultrasound_info {
+	uint8_t rms_comp_time;
+	uint8_t detection_mechanism;
+	uint8_t rms_diff_threshold;
+	uint8_t rms_threshold_lsb;
+	uint8_t rms_threshold_msb;
+	uint8_t padding[3];
+	uint8_t iir_coefficients[36];
+} __packed;
+
+struct wcd_mad_audio_cal {
+	uint32_t version;
+	struct wcd_mad_microphone_info microphone_info;
+	struct wcd_mad_micbias_info micbias_info;
+	struct wcd_mad_rms_audio_beacon_info audio_info;
+	struct wcd_mad_rms_audio_beacon_info beacon_info;
+	struct wcd_mad_rms_ultrasound_info ultrasound_info;
+} __packed;
+
+struct wcd9xxx_anc_header {
+	u32 reserved[3];
+	u32 num_anc_slots;
+};
+
+struct vbat_monitor_reg {
+	u32 size;
+	u32 writes[MAX_VBAT_MONITOR_WRITES];
+} __packed;
+
+struct wcd_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+extern void wcd_clsh_fsm(struct snd_soc_codec *codec,
+		struct wcd_clsh_cdc_data *cdc_clsh_d,
+		u8 clsh_event, u8 req_state,
+		int int_mode);
+
+extern void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh);
+extern int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh);
+extern void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped,
+		bool reset);
+
+enum {
+	RESERVED = 0,
+	AANC_LPF_FF_FB = 1,
+	AANC_LPF_COEFF_MSB,
+	AANC_LPF_COEFF_LSB,
+	HW_MAD_AUDIO_ENABLE,
+	HW_MAD_ULTR_ENABLE,
+	HW_MAD_BEACON_ENABLE,
+	HW_MAD_AUDIO_SLEEP_TIME,
+	HW_MAD_ULTR_SLEEP_TIME,
+	HW_MAD_BEACON_SLEEP_TIME,
+	HW_MAD_TX_AUDIO_SWITCH_OFF,
+	HW_MAD_TX_ULTR_SWITCH_OFF,
+	HW_MAD_TX_BEACON_SWITCH_OFF,
+	MAD_AUDIO_INT_DEST_SELECT_REG,
+	MAD_ULT_INT_DEST_SELECT_REG,
+	MAD_BEACON_INT_DEST_SELECT_REG,
+	MAD_CLIP_INT_DEST_SELECT_REG,
+	VBAT_INT_DEST_SELECT_REG,
+	MAD_AUDIO_INT_MASK_REG,
+	MAD_ULT_INT_MASK_REG,
+	MAD_BEACON_INT_MASK_REG,
+	MAD_CLIP_INT_MASK_REG,
+	VBAT_INT_MASK_REG,
+	MAD_AUDIO_INT_STATUS_REG,
+	MAD_ULT_INT_STATUS_REG,
+	MAD_BEACON_INT_STATUS_REG,
+	MAD_CLIP_INT_STATUS_REG,
+	VBAT_INT_STATUS_REG,
+	MAD_AUDIO_INT_CLEAR_REG,
+	MAD_ULT_INT_CLEAR_REG,
+	MAD_BEACON_INT_CLEAR_REG,
+	MAD_CLIP_INT_CLEAR_REG,
+	VBAT_INT_CLEAR_REG,
+	SB_PGD_PORT_TX_WATERMARK_N,
+	SB_PGD_PORT_TX_ENABLE_N,
+	SB_PGD_PORT_RX_WATERMARK_N,
+	SB_PGD_PORT_RX_ENABLE_N,
+	SB_PGD_TX_PORTn_MULTI_CHNL_0,
+	SB_PGD_TX_PORTn_MULTI_CHNL_1,
+	SB_PGD_RX_PORTn_MULTI_CHNL_0,
+	SB_PGD_RX_PORTn_MULTI_CHNL_1,
+	AANC_FF_GAIN_ADAPTIVE,
+	AANC_FFGAIN_ADAPTIVE_EN,
+	AANC_GAIN_CONTROL,
+	SPKR_CLIP_PIPE_BANK_SEL,
+	SPKR_CLIPDET_VAL0,
+	SPKR_CLIPDET_VAL1,
+	SPKR_CLIPDET_VAL2,
+	SPKR_CLIPDET_VAL3,
+	SPKR_CLIPDET_VAL4,
+	SPKR_CLIPDET_VAL5,
+	SPKR_CLIPDET_VAL6,
+	SPKR_CLIPDET_VAL7,
+	VBAT_RELEASE_INT_DEST_SELECT_REG,
+	VBAT_RELEASE_INT_MASK_REG,
+	VBAT_RELEASE_INT_STATUS_REG,
+	VBAT_RELEASE_INT_CLEAR_REG,
+	MAD2_CLIP_INT_DEST_SELECT_REG,
+	MAD2_CLIP_INT_MASK_REG,
+	MAD2_CLIP_INT_STATUS_REG,
+	MAD2_CLIP_INT_CLEAR_REG,
+	SPKR2_CLIP_PIPE_BANK_SEL,
+	SPKR2_CLIPDET_VAL0,
+	SPKR2_CLIPDET_VAL1,
+	SPKR2_CLIPDET_VAL2,
+	SPKR2_CLIPDET_VAL3,
+	SPKR2_CLIPDET_VAL4,
+	SPKR2_CLIPDET_VAL5,
+	SPKR2_CLIPDET_VAL6,
+	SPKR2_CLIPDET_VAL7,
+	MAX_CFG_REGISTERS,
+};
+
+#endif
diff --git a/asoc/codecs/wcd9xxx-core-init.c b/asoc/codecs/wcd9xxx-core-init.c
new file mode 100644
index 0000000..e575e0d
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-core-init.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include "msm-cdc-pinctrl.h"
+#include "wcd9xxx-irq.h"
+#include "core.h"
+
+#define NUM_DRIVERS_REG_RET 3
+
+static int __init wcd9xxx_core_init(void)
+{
+	int ret[NUM_DRIVERS_REG_RET] = {0};
+	int i = 0;
+
+	ret[0] = msm_cdc_pinctrl_drv_init();
+	if (ret[0])
+		pr_err("%s: Failed init pinctrl drv: %d\n", __func__, ret[0]);
+
+	ret[1] = wcd9xxx_irq_drv_init();
+	if (ret[1])
+		pr_err("%s: Failed init irq drv: %d\n", __func__, ret[1]);
+
+	ret[2] = wcd9xxx_init();
+	if (ret[2])
+		pr_err("%s: Failed wcd core drv: %d\n", __func__, ret[2]);
+
+	for (i = 0; i < NUM_DRIVERS_REG_RET; i++) {
+		if (ret[i])
+			return ret[i];
+	}
+
+	return 0;
+}
+module_init(wcd9xxx_core_init);
+
+static void __exit wcd9xxx_core_exit(void)
+{
+	wcd9xxx_exit();
+	wcd9xxx_irq_drv_exit();
+	msm_cdc_pinctrl_drv_exit();
+}
+module_exit(wcd9xxx_core_exit);
+
+MODULE_DESCRIPTION("WCD9XXX CODEC core init driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd9xxx-core.c b/asoc/codecs/wcd9xxx-core.c
new file mode 100644
index 0000000..2ab5e89
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-core.c
@@ -0,0 +1,1731 @@
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/ratelimit.h>
+#include <linux/mfd/core.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <sound/soc.h>
+#include "core.h"
+#include "pdata.h"
+#include "msm-cdc-pinctrl.h"
+#include "msm-cdc-supply.h"
+#include "wcd9xxx-irq.h"
+#include "wcd9xxx-utils.h"
+#include "wcd9xxx-regmap.h"
+#include "wcd9xxx-slimslave.h"
+
+#define WCD9XXX_REGISTER_START_OFFSET 0x800
+#define WCD9XXX_SLIM_RW_MAX_TRIES 3
+#define SLIMBUS_PRESENT_TIMEOUT 100
+
+#define MAX_WCD9XXX_DEVICE	4
+#define WCD9XXX_I2C_GSBI_SLAVE_ID "3-000d"
+#define WCD9XXX_I2C_TOP_SLAVE_ADDR	0x0d
+#define WCD9XXX_ANALOG_I2C_SLAVE_ADDR	0x77
+#define WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR	0x66
+#define WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR	0x55
+#define WCD9XXX_I2C_TOP_LEVEL	0
+#define WCD9XXX_I2C_ANALOG	1
+#define WCD9XXX_I2C_DIGITAL_1	2
+#define WCD9XXX_I2C_DIGITAL_2	3
+
+/*
+ * Number of return values needs to be checked for each
+ * registration of Slimbus of I2C bus for each codec
+ */
+#define NUM_WCD9XXX_REG_RET	4
+
+#define SLIM_USR_MC_REPEAT_CHANGE_VALUE 0x0
+#define SLIM_REPEAT_WRITE_MAX_SLICE 16
+#define REG_BYTES 2
+#define VAL_BYTES 1
+#define WCD9XXX_PAGE_NUM(reg)    (((reg) >> 8) & 0xff)
+#define WCD9XXX_PAGE_SIZE 256
+
+struct wcd9xxx_i2c {
+	struct i2c_client *client;
+	struct i2c_msg xfer_msg[2];
+	struct mutex xfer_lock;
+	int mod_id;
+};
+
+static struct regmap_config wcd9xxx_base_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.can_multi_write = true,
+};
+
+static struct regmap_config wcd9xxx_i2c_base_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.can_multi_write = false,
+	.use_single_rw = true,
+};
+
+static u8 wcd9xxx_pgd_la;
+static u8 wcd9xxx_inf_la;
+
+static const int wcd9xxx_cdc_types[] = {
+	[WCD9XXX] = WCD9XXX,
+	[WCD9330] = WCD9330,
+	[WCD9335] = WCD9335,
+	[WCD934X] = WCD934X,
+};
+
+static const struct of_device_id wcd9xxx_of_match[] = {
+	{ .compatible = "qcom,tasha-i2c-pgd",
+	  .data = (void *)&wcd9xxx_cdc_types[WCD9335]},
+	{ .compatible = "qcom,wcd9xxx-i2c",
+	  .data = (void *)&wcd9xxx_cdc_types[WCD9330]},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wcd9xxx_of_match);
+
+static int wcd9xxx_slim_device_up(struct slim_device *sldev);
+static int wcd9xxx_slim_device_down(struct slim_device *sldev);
+
+struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
+
+static int wcd9xxx_slim_multi_reg_write(struct wcd9xxx *wcd9xxx,
+					const void *data, size_t count)
+{
+	unsigned int reg;
+	struct device *dev;
+	u8 val[WCD9XXX_PAGE_SIZE];
+	int ret = 0;
+	int i = 0;
+	int n = 0;
+	unsigned int page_num;
+	size_t num_regs = (count / (REG_BYTES + VAL_BYTES));
+	struct wcd9xxx_reg_val *bulk_reg;
+	u8 *buf;
+
+	dev = wcd9xxx->dev;
+	if (!data) {
+		dev_err(dev, "%s: data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (num_regs == 0)
+		return -EINVAL;
+
+	bulk_reg = kzalloc(num_regs * (sizeof(struct wcd9xxx_reg_val)),
+			   GFP_KERNEL);
+	if (!bulk_reg)
+		return -ENOMEM;
+
+	buf = (u8 *)data;
+	reg = *(u16 *)buf;
+	page_num = WCD9XXX_PAGE_NUM(reg);
+	for (i = 0, n = 0; n < num_regs; i++, n++) {
+		reg = *(u16 *)buf;
+		if (page_num != WCD9XXX_PAGE_NUM(reg)) {
+			ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg,
+						      i, false);
+			page_num = WCD9XXX_PAGE_NUM(reg);
+			i = 0;
+		}
+		buf += REG_BYTES;
+		val[i] = *buf;
+		buf += VAL_BYTES;
+		bulk_reg[i].reg = reg;
+		bulk_reg[i].buf = &val[i];
+		bulk_reg[i].bytes = 1;
+	}
+	ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg,
+				      i, false);
+	if (ret)
+		dev_err(dev, "%s: error writing bulk regs\n",
+			__func__);
+
+	kfree(bulk_reg);
+	return ret;
+}
+
+/*
+ * wcd9xxx_interface_reg_read: Read slim interface registers
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ * @reg: register adderss
+ *
+ * Returns register value in success and negative error code in case of failure
+ */
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+{
+	u8 val;
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx->read_dev(wcd9xxx, reg, 1, (void *)&val,
+				true);
+	if (ret < 0)
+		dev_err(wcd9xxx->dev, "%s: Codec read 0x%x failed\n",
+			__func__, reg);
+	else
+		dev_dbg(wcd9xxx->dev, "%s: Read 0x%02x from 0x%x\n",
+			__func__, val, reg);
+
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	if (ret < 0)
+		return ret;
+	else
+		return val;
+}
+EXPORT_SYMBOL(wcd9xxx_interface_reg_read);
+
+/*
+ * wcd9xxx_interface_reg_write: Write slim interface registers
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ * @reg: register adderss
+ * @val: value of the register to be written
+ *
+ * Returns 0 for success and negative error code in case of failure
+ */
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+		     u8 val)
+{
+	int ret;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	ret = wcd9xxx->write_dev(wcd9xxx, reg, 1, (void *)&val, true);
+	dev_dbg(wcd9xxx->dev, "%s: Write %02x to 0x%x ret(%d)\n",
+		__func__, val, reg, ret);
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_interface_reg_write);
+
+static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
+				int bytes, void *dest, bool interface)
+{
+	int ret;
+	struct slim_ele_access msg;
+	int slim_read_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+
+	msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+	msg.num_bytes = bytes;
+	msg.comp = NULL;
+
+	if (!wcd9xxx->dev_up) {
+		dev_dbg_ratelimited(
+			wcd9xxx->dev, "%s: No read allowed. dev_up = %lu\n",
+			__func__, wcd9xxx->dev_up);
+		return 0;
+	}
+
+	while (1) {
+		mutex_lock(&wcd9xxx->xfer_lock);
+		ret = slim_request_val_element(interface ?
+			       wcd9xxx->slim_slave : wcd9xxx->slim,
+			       &msg, dest, bytes);
+		mutex_unlock(&wcd9xxx->xfer_lock);
+		if (likely(ret == 0) || (--slim_read_tries == 0))
+			break;
+		usleep_range(5000, 5100);
+	}
+
+	if (ret)
+		dev_err(wcd9xxx->dev, "%s: Error, Codec read failed (%d)\n",
+			__func__, ret);
+
+	return ret;
+}
+
+/*
+ * Interface specifies whether the write is to the interface or general
+ * registers.
+ */
+static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx,
+		unsigned short reg, int bytes, void *src, bool interface)
+{
+	int ret;
+	struct slim_ele_access msg;
+	int slim_write_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+
+	msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+	msg.num_bytes = bytes;
+	msg.comp = NULL;
+
+	if (!wcd9xxx->dev_up) {
+		dev_dbg_ratelimited(
+			wcd9xxx->dev, "%s: No write allowed. dev_up = %lu\n",
+			__func__, wcd9xxx->dev_up);
+		return 0;
+	}
+
+	while (1) {
+		mutex_lock(&wcd9xxx->xfer_lock);
+		ret = slim_change_val_element(interface ?
+			      wcd9xxx->slim_slave : wcd9xxx->slim,
+			      &msg, src, bytes);
+		mutex_unlock(&wcd9xxx->xfer_lock);
+		if (likely(ret == 0) || (--slim_write_tries == 0))
+			break;
+		usleep_range(5000, 5100);
+	}
+
+	if (ret)
+		pr_err("%s: Error, Codec write failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_get_allowed_slice(struct wcd9xxx *wcd9xxx,
+					  int bytes)
+{
+	int allowed_sz = bytes;
+
+	if (likely(bytes == SLIM_REPEAT_WRITE_MAX_SLICE))
+		allowed_sz = 16;
+	else if (bytes >= 12)
+		allowed_sz = 12;
+	else if (bytes >= 8)
+		allowed_sz = 8;
+	else if (bytes >= 6)
+		allowed_sz = 6;
+	else if (bytes >= 4)
+		allowed_sz = 4;
+	else
+		allowed_sz = bytes;
+
+	return allowed_sz;
+}
+
+/*
+ * wcd9xxx_slim_write_repeat: Write the same register with multiple values
+ * @wcd9xxx: handle to wcd core
+ * @reg: register to be written
+ * @bytes: number of bytes to be written to reg
+ * @src: buffer with data content to be written to reg
+ * This API will write reg with bytes from src in a single slimbus
+ * transaction. All values from 1 to 16 are supported by this API.
+ */
+int wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			      int bytes, void *src)
+{
+	int ret = 0, bytes_to_write = bytes, bytes_allowed;
+	struct slim_ele_access slim_msg;
+
+	mutex_lock(&wcd9xxx->io_lock);
+	if (wcd9xxx->type == WCD9335 || wcd9xxx->type == WCD934X) {
+		ret = wcd9xxx_page_write(wcd9xxx, &reg);
+		if (ret)
+			goto done;
+	}
+
+	slim_msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+	slim_msg.comp = NULL;
+
+	if (unlikely(bytes > SLIM_REPEAT_WRITE_MAX_SLICE)) {
+		dev_err(wcd9xxx->dev, "%s: size %d not supported\n",
+			__func__, bytes);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (!wcd9xxx->dev_up) {
+		dev_dbg_ratelimited(
+			wcd9xxx->dev, "%s: No write allowed. dev_up = %lu\n",
+			__func__, wcd9xxx->dev_up);
+		ret = 0;
+		goto done;
+	}
+
+	while (bytes_to_write > 0) {
+		bytes_allowed = wcd9xxx_slim_get_allowed_slice(wcd9xxx,
+				       bytes_to_write);
+
+		slim_msg.num_bytes = bytes_allowed;
+		mutex_lock(&wcd9xxx->xfer_lock);
+		ret = slim_user_msg(wcd9xxx->slim, wcd9xxx->slim->laddr,
+				    SLIM_MSG_MT_DEST_REFERRED_USER,
+				    SLIM_USR_MC_REPEAT_CHANGE_VALUE,
+				    &slim_msg, src, bytes_allowed);
+		mutex_unlock(&wcd9xxx->xfer_lock);
+
+		if (ret) {
+			dev_err(wcd9xxx->dev, "%s: failed, ret = %d\n",
+				__func__, ret);
+			break;
+		}
+
+		bytes_to_write = bytes_to_write - bytes_allowed;
+		src = ((u8 *)src) + bytes_allowed;
+	}
+
+done:
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_slim_write_repeat);
+
+/*
+ * wcd9xxx_slim_reserve_bw: API to reserve the slimbus bandwidth
+ * @wcd9xxx: Handle to the wcd9xxx core
+ * @bw_ops: value of the bandwidth that is requested
+ * @commit: Flag to indicate if bandwidth change is to be committed
+ *	    right away
+ */
+int wcd9xxx_slim_reserve_bw(struct wcd9xxx *wcd9xxx,
+		u32 bw_ops, bool commit)
+{
+	if (!wcd9xxx || !wcd9xxx->slim) {
+		pr_err("%s: Invalid handle to %s\n",
+			__func__,
+			(!wcd9xxx) ? "wcd9xxx" : "slim_device");
+		return -EINVAL;
+	}
+
+	return slim_reservemsg_bw(wcd9xxx->slim, bw_ops, commit);
+}
+EXPORT_SYMBOL(wcd9xxx_slim_reserve_bw);
+
+/*
+ * wcd9xxx_slim_bulk_write: API to write multiple registers with one descriptor
+ * @wcd9xxx: Handle to the wcd9xxx core
+ * @wcd9xxx_reg_val: structure holding register and values to be written
+ * @size: Indicates number of messages to be written with one descriptor
+ * @is_interface: Indicates whether the register is for slim interface or for
+ *	       general registers.
+ * @return: returns 0 if success or error information to the caller in case
+ *	    of failure.
+ */
+int wcd9xxx_slim_bulk_write(struct wcd9xxx *wcd9xxx,
+			    struct wcd9xxx_reg_val *bulk_reg,
+			    unsigned int size, bool is_interface)
+{
+	int ret, i;
+	struct slim_val_inf *msgs;
+	unsigned short reg;
+
+	if (!bulk_reg || !size || !wcd9xxx) {
+		pr_err("%s: Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!wcd9xxx->dev_up) {
+		dev_dbg_ratelimited(
+			wcd9xxx->dev, "%s: No write allowed. dev_up = %lu\n",
+			__func__, wcd9xxx->dev_up);
+		return 0;
+	}
+
+	msgs = kzalloc(size * (sizeof(struct slim_val_inf)), GFP_KERNEL);
+	if (!msgs) {
+		ret = -ENOMEM;
+		goto mem_fail;
+	}
+
+	mutex_lock(&wcd9xxx->io_lock);
+	reg = bulk_reg->reg;
+	for (i = 0; i < size; i++) {
+		msgs[i].start_offset = WCD9XXX_REGISTER_START_OFFSET +
+					(bulk_reg->reg & 0xFF);
+		msgs[i].num_bytes = bulk_reg->bytes;
+		msgs[i].wbuf = bulk_reg->buf;
+		bulk_reg++;
+	}
+	ret = wcd9xxx_page_write(wcd9xxx, &reg);
+	if (ret) {
+		pr_err("%s: Page write error for reg: 0x%x\n",
+			__func__, reg);
+		goto err;
+	}
+
+	ret = slim_bulk_msg_write(is_interface ?
+				  wcd9xxx->slim_slave : wcd9xxx->slim,
+				  SLIM_MSG_MT_CORE,
+				  SLIM_MSG_MC_CHANGE_VALUE, msgs, size,
+				  NULL, NULL);
+	if (ret)
+		pr_err("%s: Error, Codec bulk write failed (%d)\n",
+			__func__, ret);
+	/* 100 usec sleep is needed as per HW requirement */
+	usleep_range(100, 110);
+err:
+	mutex_unlock(&wcd9xxx->io_lock);
+	kfree(msgs);
+mem_fail:
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_slim_bulk_write);
+
+static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
+{
+	return (wcd9xxx->codec_type->num_irqs / 8) +
+		((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
+}
+
+static int wcd9xxx_regmap_init_cache(struct wcd9xxx *wcd9xxx)
+{
+	struct regmap_config *regmap_config;
+	int rc;
+
+	regmap_config = wcd9xxx_get_regmap_config(wcd9xxx->type);
+	if (!regmap_config) {
+		dev_err(wcd9xxx->dev, "regmap config is not defined\n");
+		return -EINVAL;
+	}
+
+	rc = regmap_reinit_cache(wcd9xxx->regmap, regmap_config);
+	if (rc != 0) {
+		dev_err(wcd9xxx->dev, "%s:Failed to reinit register cache: %d\n",
+			__func__, rc);
+	}
+
+	return rc;
+}
+
+static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0, i;
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+	regmap_patch_fptr regmap_apply_patch = NULL;
+
+	mutex_init(&wcd9xxx->io_lock);
+	mutex_init(&wcd9xxx->xfer_lock);
+	mutex_init(&wcd9xxx->reset_lock);
+
+	ret = wcd9xxx_bringup(wcd9xxx->dev);
+	if (ret) {
+		ret = -EPROBE_DEFER;
+		goto err_bring_up;
+	}
+
+	wcd9xxx->codec_type = devm_kzalloc(wcd9xxx->dev,
+			sizeof(struct wcd9xxx_codec_type), GFP_KERNEL);
+	if (!wcd9xxx->codec_type) {
+		ret = -ENOMEM;
+		goto err_bring_up;
+	}
+	ret = wcd9xxx_get_codec_info(wcd9xxx->dev);
+	if (ret) {
+		ret = -EPROBE_DEFER;
+		goto fail_cdc_fill;
+	}
+	wcd9xxx->version = wcd9xxx->codec_type->version;
+	if (!wcd9xxx->codec_type->dev || !wcd9xxx->codec_type->size)
+		goto fail_cdc_fill;
+
+	core_res->parent = wcd9xxx;
+	core_res->dev = wcd9xxx->dev;
+	core_res->intr_table = wcd9xxx->codec_type->intr_tbl;
+	core_res->intr_table_size = wcd9xxx->codec_type->intr_tbl_size;
+
+	for (i = 0; i < WCD9XXX_INTR_REG_MAX; i++)
+		wcd9xxx->core_res.intr_reg[i] =
+			wcd9xxx->codec_type->intr_reg[i];
+
+	wcd9xxx_core_res_init(&wcd9xxx->core_res,
+			      wcd9xxx->codec_type->num_irqs,
+			      wcd9xxx_num_irq_regs(wcd9xxx),
+			      wcd9xxx->regmap);
+
+	if (wcd9xxx_core_irq_init(&wcd9xxx->core_res))
+		goto err;
+
+	ret = wcd9xxx_regmap_init_cache(wcd9xxx);
+	if (ret)
+		goto err_irq;
+
+	regmap_apply_patch = wcd9xxx_get_regmap_reg_patch(
+			wcd9xxx->type);
+	if (regmap_apply_patch) {
+		ret = regmap_apply_patch(wcd9xxx->regmap,
+				wcd9xxx->version);
+		if (ret)
+			dev_err(wcd9xxx->dev,
+					"Failed to register patch: %d\n", ret);
+	}
+
+	ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx->codec_type->dev,
+			      wcd9xxx->codec_type->size, NULL, 0, NULL);
+	if (ret != 0) {
+		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
+		goto err_irq;
+	}
+
+	ret = device_init_wakeup(wcd9xxx->dev, true);
+	if (ret) {
+		dev_err(wcd9xxx->dev, "Device wakeup init failed: %d\n", ret);
+		goto err_irq;
+	}
+
+	return ret;
+err_irq:
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
+fail_cdc_fill:
+	devm_kfree(wcd9xxx->dev, wcd9xxx->codec_type);
+	wcd9xxx->codec_type = NULL;
+err:
+	wcd9xxx_bringdown(wcd9xxx->dev);
+	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
+err_bring_up:
+	mutex_destroy(&wcd9xxx->io_lock);
+	mutex_destroy(&wcd9xxx->xfer_lock);
+	mutex_destroy(&wcd9xxx->reset_lock);
+	return ret;
+}
+
+static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
+{
+	device_init_wakeup(wcd9xxx->dev, false);
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
+	wcd9xxx_bringdown(wcd9xxx->dev);
+	wcd9xxx_reset_low(wcd9xxx->dev);
+	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
+	mutex_destroy(&wcd9xxx->io_lock);
+	mutex_destroy(&wcd9xxx->xfer_lock);
+	mutex_destroy(&wcd9xxx->reset_lock);
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		slim_remove_device(wcd9xxx->slim_slave);
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+struct wcd9xxx *debugCodec;
+
+static struct dentry *debugfs_wcd9xxx_dent;
+static struct dentry *debugfs_peek;
+static struct dentry *debugfs_poke;
+static struct dentry *debugfs_power_state;
+static struct dentry *debugfs_reg_dump;
+
+static unsigned char read_data;
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token != NULL) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (kstrtoul(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t wcd9xxx_slimslave_reg_show(char __user *ubuf, size_t count,
+					  loff_t *ppos)
+{
+	int i, reg_val, len;
+	ssize_t total = 0;
+	char tmp_buf[25]; /* each line is 12 bytes but 25 for margin of error */
+
+	for (i = (int) *ppos / 12; i <= SLIM_MAX_REG_ADDR; i++) {
+		reg_val = wcd9xxx_interface_reg_read(debugCodec, i);
+		len = snprintf(tmp_buf, sizeof(tmp_buf),
+			"0x%.3x: 0x%.2x\n", i, reg_val);
+
+		if ((total + len) >= count - 1)
+			break;
+		if (copy_to_user((ubuf + total), tmp_buf, len)) {
+			pr_err("%s: fail to copy reg dump\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
+		*ppos += len;
+		total += len;
+	}
+
+copy_err:
+	return total;
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[8];
+	char *access_str = file->private_data;
+	ssize_t ret_cnt;
+
+	if (*ppos < 0 || !count)
+		return -EINVAL;
+
+	if (!strcmp(access_str, "slimslave_peek")) {
+		snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
+		ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf,
+					       strnlen(lbuf, 7));
+	} else if (!strcmp(access_str, "slimslave_reg_dump")) {
+		ret_cnt = wcd9xxx_slimslave_reg_show(ubuf, count, ppos);
+	} else {
+		pr_err("%s: %s not permitted to read\n", __func__, access_str);
+		ret_cnt = -EPERM;
+	}
+
+	return ret_cnt;
+}
+
+static void wcd9xxx_set_reset_pin_state(struct wcd9xxx *wcd9xxx,
+					struct wcd9xxx_pdata *pdata,
+					bool active)
+{
+	if (wcd9xxx->wcd_rst_np) {
+		if (active)
+			msm_cdc_pinctrl_select_active_state(
+						wcd9xxx->wcd_rst_np);
+		else
+			msm_cdc_pinctrl_select_sleep_state(
+						wcd9xxx->wcd_rst_np);
+
+		return;
+	} else if (gpio_is_valid(wcd9xxx->reset_gpio)) {
+		gpio_direction_output(wcd9xxx->reset_gpio,
+				      (active == true ? 1 : 0));
+	}
+}
+
+static int codec_debug_process_cdc_power(char *lbuf)
+{
+	long int param;
+	int rc;
+	struct wcd9xxx_pdata *pdata;
+
+	if (wcd9xxx_get_intf_type() != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		pr_err("%s: CODEC is not in SLIMBUS mode\n", __func__);
+		rc = -EPERM;
+		goto error_intf;
+	}
+
+	rc = get_parameters(lbuf, &param, 1);
+
+	if (likely(!rc)) {
+		pdata = debugCodec->slim->dev.platform_data;
+		if (param == 0) {
+			wcd9xxx_slim_device_down(debugCodec->slim);
+			msm_cdc_disable_static_supplies(debugCodec->dev,
+							debugCodec->supplies,
+							pdata->regulator,
+							pdata->num_supplies);
+			wcd9xxx_set_reset_pin_state(debugCodec, pdata, false);
+		} else if (param == 1) {
+			msm_cdc_enable_static_supplies(debugCodec->dev,
+						       debugCodec->supplies,
+						       pdata->regulator,
+						       pdata->num_supplies);
+			usleep_range(1000, 2000);
+			wcd9xxx_set_reset_pin_state(debugCodec, pdata, false);
+			usleep_range(1000, 2000);
+			wcd9xxx_set_reset_pin_state(debugCodec, pdata, true);
+			usleep_range(1000, 2000);
+			wcd9xxx_slim_device_up(debugCodec->slim);
+		} else {
+			pr_err("%s: invalid command %ld\n", __func__, param);
+		}
+	}
+
+error_intf:
+	return rc;
+}
+
+static ssize_t codec_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *access_str = filp->private_data;
+	char lbuf[32];
+	int rc;
+	long int param[5];
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+
+	if (!strcmp(access_str, "slimslave_poke")) {
+		/* write */
+		rc = get_parameters(lbuf, param, 2);
+		if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) &&
+			(rc == 0))
+			wcd9xxx_interface_reg_write(debugCodec, param[0],
+				param[1]);
+		else
+			rc = -EINVAL;
+	} else if (!strcmp(access_str, "slimslave_peek")) {
+		/* read */
+		rc = get_parameters(lbuf, param, 1);
+		if ((param[0] <= 0x3FF) && (rc == 0))
+			read_data = wcd9xxx_interface_reg_read(debugCodec,
+				param[0]);
+		else
+			rc = -EINVAL;
+	} else if (!strcmp(access_str, "power_state")) {
+		rc = codec_debug_process_cdc_power(lbuf);
+	}
+
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+	.read = codec_debug_read
+};
+#endif
+
+static struct wcd9xxx_i2c *wcd9xxx_i2c_get_device_info(struct wcd9xxx *wcd9xxx,
+						u16 reg)
+{
+	u16 mask = 0x0f00;
+	int value = 0;
+	struct wcd9xxx_i2c *wcd9xxx_i2c = NULL;
+
+	if (wcd9xxx->type == WCD9335) {
+		wcd9xxx_i2c = &wcd9xxx_modules[0];
+	} else {
+		value = ((reg & mask) >> 8) & 0x000f;
+		switch (value) {
+		case 0:
+			wcd9xxx_i2c = &wcd9xxx_modules[0];
+			break;
+		case 1:
+			wcd9xxx_i2c = &wcd9xxx_modules[1];
+			break;
+		case 2:
+			wcd9xxx_i2c = &wcd9xxx_modules[2];
+			break;
+		case 3:
+			wcd9xxx_i2c = &wcd9xxx_modules[3];
+			break;
+
+		default:
+			break;
+		}
+	}
+	return wcd9xxx_i2c;
+}
+
+static int wcd9xxx_i2c_write_device(struct wcd9xxx *wcd9xxx, u16 reg, u8 *value,
+				u32 bytes)
+{
+
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	u8 data[bytes + 1];
+	struct wcd9xxx_i2c *wcd9xxx_i2c;
+
+	wcd9xxx_i2c = wcd9xxx_i2c_get_device_info(wcd9xxx, reg);
+	if (wcd9xxx_i2c == NULL || wcd9xxx_i2c->client == NULL) {
+		pr_err("failed to get device info\n");
+		return -ENODEV;
+	}
+	reg_addr = (u8)reg;
+	msg = &wcd9xxx_i2c->xfer_msg[0];
+	msg->addr = wcd9xxx_i2c->client->addr;
+	msg->len = bytes + 1;
+	msg->flags = 0;
+	data[0] = reg;
+	data[1] = *value;
+	msg->buf = data;
+	ret = i2c_transfer(wcd9xxx_i2c->client->adapter,
+			   wcd9xxx_i2c->xfer_msg, 1);
+	/* Try again if the write fails */
+	if (ret != 1) {
+		ret = i2c_transfer(wcd9xxx_i2c->client->adapter,
+						wcd9xxx_i2c->xfer_msg, 1);
+		if (ret != 1) {
+			pr_err("failed to write the device\n");
+			return ret;
+		}
+	}
+	pr_debug("write success register = %x val = %x\n", reg, data[1]);
+	return 0;
+}
+
+
+static int wcd9xxx_i2c_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
+				  int bytes, unsigned char *dest)
+{
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	struct wcd9xxx_i2c *wcd9xxx_i2c;
+	u8 i = 0;
+
+	wcd9xxx_i2c = wcd9xxx_i2c_get_device_info(wcd9xxx, reg);
+	if (wcd9xxx_i2c == NULL || wcd9xxx_i2c->client == NULL) {
+		pr_err("failed to get device info\n");
+		return -ENODEV;
+	}
+	for (i = 0; i < bytes; i++) {
+		reg_addr = (u8)reg++;
+		msg = &wcd9xxx_i2c->xfer_msg[0];
+		msg->addr = wcd9xxx_i2c->client->addr;
+		msg->len = 1;
+		msg->flags = 0;
+		msg->buf = &reg_addr;
+
+		msg = &wcd9xxx_i2c->xfer_msg[1];
+		msg->addr = wcd9xxx_i2c->client->addr;
+		msg->len = 1;
+		msg->flags = I2C_M_RD;
+		msg->buf = dest++;
+		ret = i2c_transfer(wcd9xxx_i2c->client->adapter,
+				wcd9xxx_i2c->xfer_msg, 2);
+
+		/* Try again if read fails first time */
+		if (ret != 2) {
+			ret = i2c_transfer(wcd9xxx_i2c->client->adapter,
+					   wcd9xxx_i2c->xfer_msg, 2);
+			if (ret != 2) {
+				pr_err("failed to read wcd9xxx register\n");
+				return ret;
+			}
+		}
+	}
+	return 0;
+}
+
+int wcd9xxx_i2c_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			int bytes, void *dest, bool interface_reg)
+{
+	return wcd9xxx_i2c_read_device(wcd9xxx, reg, bytes, dest);
+}
+
+int wcd9xxx_i2c_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+			 int bytes, void *src, bool interface_reg)
+{
+	return wcd9xxx_i2c_write_device(wcd9xxx, reg, src, bytes);
+}
+
+static int wcd9xxx_i2c_get_client_index(struct i2c_client *client,
+					int *wcd9xx_index)
+{
+	int ret = 0;
+
+	switch (client->addr) {
+	case WCD9XXX_I2C_TOP_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_TOP_LEVEL;
+	break;
+	case WCD9XXX_ANALOG_I2C_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_ANALOG;
+	break;
+	case WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_DIGITAL_1;
+	break;
+	case WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_DIGITAL_2;
+	break;
+	default:
+		ret = -EINVAL;
+	break;
+	}
+	return ret;
+}
+
+static int wcd9xxx_i2c_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct wcd9xxx *wcd9xxx = NULL;
+	struct wcd9xxx_pdata *pdata = NULL;
+	int val = 0;
+	int ret = 0;
+	int wcd9xx_index = 0;
+	struct device *dev;
+	int intf_type;
+	const struct of_device_id *of_id;
+
+	intf_type = wcd9xxx_get_intf_type();
+
+	pr_debug("%s: interface status %d\n", __func__, intf_type);
+	if (intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n",
+			__func__);
+		return -ENODEV;
+	} else if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
+		if (ret != 0)
+			dev_err(&client->dev, "%s: I2C set codec I2C\n"
+				"client failed\n", __func__);
+		else {
+			dev_err(&client->dev, "%s:probe for other slaves\n"
+				"devices of codec I2C slave Addr = %x\n",
+				__func__, client->addr);
+			wcd9xxx_modules[wcd9xx_index].client = client;
+		}
+		return ret;
+	} else if (intf_type == WCD9XXX_INTERFACE_TYPE_PROBING) {
+		dev = &client->dev;
+		if (client->dev.of_node) {
+			dev_dbg(&client->dev, "%s:Platform data\n"
+				"from device tree\n", __func__);
+			pdata = wcd9xxx_populate_dt_data(&client->dev);
+			if (!pdata) {
+				dev_err(&client->dev,
+					"%s: Fail to obtain pdata from device tree\n",
+					__func__);
+				ret = -EINVAL;
+				goto fail;
+			}
+			client->dev.platform_data = pdata;
+		} else {
+			dev_dbg(&client->dev, "%s:Platform data from\n"
+				"board file\n", __func__);
+			pdata = client->dev.platform_data;
+		}
+		wcd9xxx = devm_kzalloc(&client->dev, sizeof(struct wcd9xxx),
+				       GFP_KERNEL);
+		if (!wcd9xxx) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		if (!pdata) {
+			dev_dbg(&client->dev, "no platform data?\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		wcd9xxx->type = WCD9XXX;
+		if (client->dev.of_node) {
+			of_id = of_match_device(wcd9xxx_of_match, &client->dev);
+			if (of_id) {
+				wcd9xxx->type = *((int *)of_id->data);
+				dev_info(&client->dev, "%s: codec type is %d\n",
+					 __func__, wcd9xxx->type);
+			}
+		} else {
+			dev_info(&client->dev, "%s: dev.of_node is NULL, default to WCD9XXX\n",
+				 __func__);
+			wcd9xxx->type = WCD9XXX;
+		}
+		wcd9xxx->regmap = wcd9xxx_regmap_init(&client->dev,
+				&wcd9xxx_i2c_base_regmap_config);
+		if (IS_ERR(wcd9xxx->regmap)) {
+			ret = PTR_ERR(wcd9xxx->regmap);
+			dev_err(&client->dev, "%s: Failed to allocate register map: %d\n",
+					__func__, ret);
+			goto err_codec;
+		}
+		wcd9xxx->reset_gpio = pdata->reset_gpio;
+		wcd9xxx->wcd_rst_np = pdata->wcd_rst_np;
+
+		if (!wcd9xxx->wcd_rst_np) {
+			pdata->use_pinctrl = false;
+			dev_err(&client->dev, "%s: pinctrl not used for rst_n\n",
+				__func__);
+			goto err_codec;
+		}
+
+		if (i2c_check_functionality(client->adapter,
+					    I2C_FUNC_I2C) == 0) {
+			dev_dbg(&client->dev, "can't talk I2C?\n");
+			ret = -EIO;
+			goto fail;
+		}
+		dev_set_drvdata(&client->dev, wcd9xxx);
+		wcd9xxx->dev = &client->dev;
+		wcd9xxx->dev_up = true;
+		if (client->dev.of_node)
+			wcd9xxx->mclk_rate = pdata->mclk_rate;
+
+		wcd9xxx->num_of_supplies = pdata->num_supplies;
+		ret = msm_cdc_init_supplies(wcd9xxx->dev, &wcd9xxx->supplies,
+					    pdata->regulator,
+					    pdata->num_supplies);
+		if (!wcd9xxx->supplies) {
+			dev_err(wcd9xxx->dev, "%s: Cannot init wcd supplies\n",
+				__func__);
+			goto err_codec;
+		}
+		ret = msm_cdc_enable_static_supplies(wcd9xxx->dev,
+						     wcd9xxx->supplies,
+						     pdata->regulator,
+						     pdata->num_supplies);
+		if (ret) {
+			dev_err(wcd9xxx->dev, "%s: wcd static supply enable failed!\n",
+				__func__);
+			goto err_codec;
+		}
+		/* For WCD9335, it takes about 600us for the Vout_A and
+		 * Vout_D to be ready after BUCK_SIDO is powered up\
+		 * SYS_RST_N shouldn't be pulled high during this time
+		 */
+		if (wcd9xxx->type == WCD9335)
+			usleep_range(600, 650);
+		else
+			usleep_range(5, 10);
+
+		ret = wcd9xxx_reset(wcd9xxx->dev);
+		if (ret) {
+			pr_err("%s: Resetting Codec failed\n", __func__);
+			goto err_supplies;
+		}
+
+		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
+		if (ret != 0) {
+			pr_err("%s:Set codec I2C client failed\n", __func__);
+			goto err_supplies;
+		}
+
+		wcd9xxx_modules[wcd9xx_index].client = client;
+		wcd9xxx->read_dev = wcd9xxx_i2c_read;
+		wcd9xxx->write_dev = wcd9xxx_i2c_write;
+		if (!wcd9xxx->dev->of_node)
+			wcd9xxx_assign_irq(&wcd9xxx->core_res,
+					pdata->irq, pdata->irq_base);
+
+		ret = wcd9xxx_device_init(wcd9xxx);
+		if (ret) {
+			pr_err("%s: error, initializing device failed (%d)\n",
+			       __func__, ret);
+			goto err_device_init;
+		}
+
+		ret = wcd9xxx_i2c_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1,
+				       &val, 0);
+		if (ret < 0)
+			pr_err("%s: failed to read the wcd9xxx status (%d)\n",
+			       __func__, ret);
+		if (val != wcd9xxx->codec_type->i2c_chip_status)
+			pr_err("%s: unknown chip status 0x%x\n", __func__, val);
+
+		wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
+
+		return ret;
+	}
+
+	pr_err("%s: I2C probe in wrong state\n", __func__);
+
+
+err_device_init:
+	wcd9xxx_reset_low(wcd9xxx->dev);
+err_supplies:
+	msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+				 pdata->regulator,
+				 pdata->num_supplies);
+	pdata->regulator = NULL;
+	pdata->num_supplies = 0;
+err_codec:
+	devm_kfree(&client->dev, wcd9xxx);
+	dev_set_drvdata(&client->dev, NULL);
+fail:
+	return ret;
+}
+
+static int wcd9xxx_i2c_remove(struct i2c_client *client)
+{
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata = client->dev.platform_data;
+
+	wcd9xxx = dev_get_drvdata(&client->dev);
+	msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+				 pdata->regulator,
+				 pdata->num_supplies);
+	wcd9xxx_device_exit(wcd9xxx);
+	dev_set_drvdata(&client->dev, NULL);
+	return 0;
+}
+
+static int wcd9xxx_dt_parse_slim_interface_dev_info(struct device *dev,
+						struct slim_device *slim_ifd)
+{
+	int ret = 0;
+	struct property *prop;
+
+	ret = of_property_read_string(dev->of_node, "qcom,cdc-slim-ifd",
+				      &slim_ifd->name);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			"qcom,cdc-slim-ifd-dev", dev->of_node->full_name);
+		return -ENODEV;
+	}
+	prop = of_find_property(dev->of_node,
+			"qcom,cdc-slim-ifd-elemental-addr", NULL);
+	if (!prop) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			"qcom,cdc-slim-ifd-elemental-addr",
+			dev->of_node->full_name);
+		return -ENODEV;
+	} else if (prop->length != 6) {
+		dev_err(dev, "invalid codec slim ifd addr. addr length = %d\n",
+			      prop->length);
+		return -ENODEV;
+	}
+	memcpy(slim_ifd->e_addr, prop->value, 6);
+
+	return 0;
+}
+
+static int wcd9xxx_slim_get_laddr(struct slim_device *sb,
+				  const u8 *e_addr, u8 e_len, u8 *laddr)
+{
+	int ret;
+	const unsigned long timeout = jiffies +
+				      msecs_to_jiffies(SLIMBUS_PRESENT_TIMEOUT);
+
+	do {
+		ret = slim_get_logical_addr(sb, e_addr, e_len, laddr);
+		if (!ret)
+			break;
+		/* Give SLIMBUS time to report present and be ready. */
+		usleep_range(1000, 1100);
+		pr_debug_ratelimited("%s: retyring get logical addr\n",
+				     __func__);
+	} while time_before(jiffies, timeout);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_probe(struct slim_device *slim)
+{
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata;
+	const struct slim_device_id *device_id;
+	int ret = 0;
+	int intf_type;
+
+	intf_type = wcd9xxx_get_intf_type();
+
+	wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx),
+				GFP_KERNEL);
+	if (!wcd9xxx) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (!slim) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+		dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
+			__func__);
+		ret = -ENODEV;
+		goto err;
+	}
+	if (slim->dev.of_node) {
+		dev_info(&slim->dev, "Platform data from device tree\n");
+		pdata = wcd9xxx_populate_dt_data(&slim->dev);
+		if (!pdata) {
+			dev_err(&slim->dev,
+				"%s: Fail to obtain pdata from device tree\n",
+				__func__);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ret = wcd9xxx_dt_parse_slim_interface_dev_info(&slim->dev,
+				&pdata->slimbus_slave_device);
+		if (ret) {
+			dev_err(&slim->dev, "Error, parsing slim interface\n");
+			devm_kfree(&slim->dev, pdata);
+			ret = -EINVAL;
+			goto err;
+		}
+		slim->dev.platform_data = pdata;
+
+	} else {
+		dev_info(&slim->dev, "Platform data from board file\n");
+		pdata = slim->dev.platform_data;
+	}
+
+	if (!pdata) {
+		dev_err(&slim->dev, "Error, no platform data\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (!slim->ctrl) {
+		dev_err(&slim->dev, "%s: Error, no SLIMBUS control data\n",
+			__func__);
+		ret = -EINVAL;
+		goto err_codec;
+	}
+	device_id = slim_get_device_id(slim);
+	if (!device_id) {
+		dev_err(&slim->dev, "%s: Error, no device id\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	wcd9xxx->type = device_id->driver_data;
+	dev_info(&slim->dev, "%s: probing for wcd type: %d, name: %s\n",
+		 __func__, wcd9xxx->type, device_id->name);
+
+	/* wcd9xxx members init */
+	wcd9xxx->multi_reg_write = wcd9xxx_slim_multi_reg_write;
+	wcd9xxx->slim = slim;
+	slim_set_clientdata(slim, wcd9xxx);
+	wcd9xxx->reset_gpio = pdata->reset_gpio;
+	wcd9xxx->dev = &slim->dev;
+	wcd9xxx->mclk_rate = pdata->mclk_rate;
+	wcd9xxx->dev_up = true;
+	wcd9xxx->wcd_rst_np = pdata->wcd_rst_np;
+
+	wcd9xxx->regmap = wcd9xxx_regmap_init(&slim->dev,
+					      &wcd9xxx_base_regmap_config);
+	if (IS_ERR(wcd9xxx->regmap)) {
+		ret = PTR_ERR(wcd9xxx->regmap);
+		dev_err(&slim->dev, "%s: Failed to allocate register map: %d\n",
+			__func__, ret);
+		goto err_codec;
+	}
+
+	if (!wcd9xxx->wcd_rst_np) {
+		pdata->use_pinctrl = false;
+		dev_err(&slim->dev, "%s: pinctrl not used for rst_n\n",
+			__func__);
+		goto err_codec;
+	}
+
+	wcd9xxx->num_of_supplies = pdata->num_supplies;
+	ret = msm_cdc_init_supplies(&slim->dev, &wcd9xxx->supplies,
+				    pdata->regulator,
+				    pdata->num_supplies);
+	if (!wcd9xxx->supplies) {
+		dev_err(wcd9xxx->dev, "%s: Cannot init wcd supplies\n",
+			__func__);
+		goto err_codec;
+	}
+	ret = msm_cdc_enable_static_supplies(wcd9xxx->dev,
+					     wcd9xxx->supplies,
+					     pdata->regulator,
+					     pdata->num_supplies);
+	if (ret) {
+		dev_err(wcd9xxx->dev, "%s: wcd static supply enable failed!\n",
+			__func__);
+		goto err_codec;
+	}
+
+	/*
+	 * For WCD9335, it takes about 600us for the Vout_A and
+	 * Vout_D to be ready after BUCK_SIDO is powered up.
+	 * SYS_RST_N shouldn't be pulled high during this time
+	 */
+	if (wcd9xxx->type == WCD9335 || wcd9xxx->type == WCD934X)
+		usleep_range(600, 650);
+	else
+		usleep_range(5, 10);
+
+	ret = wcd9xxx_reset(&slim->dev);
+	if (ret) {
+		dev_err(&slim->dev, "%s: Resetting Codec failed\n", __func__);
+		goto err_supplies;
+	}
+
+	ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
+				     ARRAY_SIZE(wcd9xxx->slim->e_addr),
+				     &wcd9xxx->slim->laddr);
+	if (ret) {
+		dev_err(&slim->dev, "%s: failed to get slimbus %s logical address: %d\n",
+		       __func__, wcd9xxx->slim->name, ret);
+		goto err_reset;
+	}
+	wcd9xxx->read_dev = wcd9xxx_slim_read_device;
+	wcd9xxx->write_dev = wcd9xxx_slim_write_device;
+	wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
+	wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
+	if (!wcd9xxx->dev->of_node)
+		wcd9xxx_assign_irq(&wcd9xxx->core_res,
+					pdata->irq, pdata->irq_base);
+
+	ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
+	if (ret) {
+		dev_err(&slim->dev, "%s: error, adding SLIMBUS device failed\n",
+			__func__);
+		goto err_reset;
+	}
+
+	ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim_slave,
+				     wcd9xxx->slim_slave->e_addr,
+				     ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
+				     &wcd9xxx->slim_slave->laddr);
+	if (ret) {
+		dev_err(&slim->dev, "%s: failed to get slimbus %s logical address: %d\n",
+		       __func__, wcd9xxx->slim->name, ret);
+		goto err_slim_add;
+	}
+	wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_SLIMBUS);
+
+	ret = wcd9xxx_device_init(wcd9xxx);
+	if (ret) {
+		dev_err(&slim->dev, "%s: error, initializing device failed (%d)\n",
+			__func__, ret);
+		goto err_slim_add;
+	}
+#ifdef CONFIG_DEBUG_FS
+	debugCodec = wcd9xxx;
+
+	debugfs_wcd9xxx_dent = debugfs_create_dir
+		("wcd9xxx_core", 0);
+	if (!IS_ERR(debugfs_wcd9xxx_dent)) {
+		debugfs_peek = debugfs_create_file("slimslave_peek",
+		S_IFREG | 0444, debugfs_wcd9xxx_dent,
+		(void *) "slimslave_peek", &codec_debug_ops);
+
+		debugfs_poke = debugfs_create_file("slimslave_poke",
+		S_IFREG | 0444, debugfs_wcd9xxx_dent,
+		(void *) "slimslave_poke", &codec_debug_ops);
+
+		debugfs_power_state = debugfs_create_file("power_state",
+		S_IFREG | 0444, debugfs_wcd9xxx_dent,
+		(void *) "power_state", &codec_debug_ops);
+
+		debugfs_reg_dump = debugfs_create_file("slimslave_reg_dump",
+		S_IFREG | 0444, debugfs_wcd9xxx_dent,
+		(void *) "slimslave_reg_dump", &codec_debug_ops);
+	}
+#endif
+
+	return ret;
+
+err_slim_add:
+	slim_remove_device(wcd9xxx->slim_slave);
+err_reset:
+	wcd9xxx_reset_low(wcd9xxx->dev);
+err_supplies:
+	msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+				 pdata->regulator,
+				 pdata->num_supplies);
+err_codec:
+	slim_set_clientdata(slim, NULL);
+err:
+	devm_kfree(&slim->dev, wcd9xxx);
+	return ret;
+}
+static int wcd9xxx_slim_remove(struct slim_device *pdev)
+{
+	struct wcd9xxx *wcd9xxx;
+	struct wcd9xxx_pdata *pdata = pdev->dev.platform_data;
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove_recursive(debugfs_wcd9xxx_dent);
+#endif
+	wcd9xxx = slim_get_devicedata(pdev);
+	wcd9xxx_deinit_slimslave(wcd9xxx);
+	slim_remove_device(wcd9xxx->slim_slave);
+	msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+				 pdata->regulator,
+				 pdata->num_supplies);
+	wcd9xxx_device_exit(wcd9xxx);
+	slim_set_clientdata(pdev, NULL);
+	return 0;
+}
+
+static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0;
+	struct wcd9xxx_core_resource *wcd9xxx_res = &wcd9xxx->core_res;
+
+	dev_info(wcd9xxx->dev, "%s: codec bring up\n", __func__);
+	wcd9xxx_bringup(wcd9xxx->dev);
+	ret = wcd9xxx_irq_init(wcd9xxx_res);
+	if (ret) {
+		pr_err("%s: wcd9xx_irq_init failed : %d\n", __func__, ret);
+	} else {
+		if (wcd9xxx->post_reset)
+			ret = wcd9xxx->post_reset(wcd9xxx);
+	}
+	return ret;
+}
+
+static int wcd9xxx_slim_device_reset(struct slim_device *sldev)
+{
+	int ret;
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Wait for 500 ms for device down to complete. Observed delay
+	 *  of ~200ms for device down to complete after being called,
+	 * due to context switch issue.
+	 */
+	ret = wait_on_bit_timeout(&wcd9xxx->dev_up, 0,
+				  TASK_INTERRUPTIBLE,
+				  msecs_to_jiffies(500));
+	if (ret)
+		pr_err("%s: slim device down not complete in 500 msec\n",
+				__func__);
+
+	mutex_lock(&wcd9xxx->reset_lock);
+
+	dev_info(wcd9xxx->dev, "%s: device reset, dev_up = %lu\n",
+			__func__, wcd9xxx->dev_up);
+	if (wcd9xxx->dev_up) {
+		mutex_unlock(&wcd9xxx->reset_lock);
+		return 0;
+	}
+
+	ret = wcd9xxx_reset(wcd9xxx->dev);
+	if (ret)
+		dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__);
+	mutex_unlock(&wcd9xxx->reset_lock);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_device_up(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	int ret = 0;
+
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_info(wcd9xxx->dev, "%s: slim device up, dev_up = %lu\n",
+			__func__, wcd9xxx->dev_up);
+	if (wcd9xxx->dev_up)
+		return 0;
+
+	wcd9xxx->dev_up = true;
+
+	mutex_lock(&wcd9xxx->reset_lock);
+	ret = wcd9xxx_device_up(wcd9xxx);
+	mutex_unlock(&wcd9xxx->reset_lock);
+
+	return ret;
+}
+
+static int wcd9xxx_slim_device_down(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&wcd9xxx->reset_lock);
+
+	dev_info(wcd9xxx->dev, "%s: device down, dev_up = %lu\n",
+			__func__, wcd9xxx->dev_up);
+	if (!wcd9xxx->dev_up) {
+		mutex_unlock(&wcd9xxx->reset_lock);
+		return 0;
+	}
+
+	if (wcd9xxx->dev_down)
+		wcd9xxx->dev_down(wcd9xxx);
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
+	wcd9xxx_reset_low(wcd9xxx->dev);
+	wcd9xxx->dev_up = false;
+	mutex_unlock(&wcd9xxx->reset_lock);
+
+	return 0;
+}
+
+static int wcd9xxx_slim_resume(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
+	return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
+}
+
+static int wcd9xxx_i2c_resume(struct device *dev)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+
+	if (wcd9xxx)
+		return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
+	else
+		return 0;
+}
+
+static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
+	return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
+}
+
+static int wcd9xxx_i2c_suspend(struct device *dev)
+{
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+	pm_message_t pmesg = {0};
+
+	if (wcd9xxx)
+		return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
+	else
+		return 0;
+}
+
+static const struct slim_device_id wcd_slim_device_id[] = {
+	{"sitar-slim", 0},
+	{"sitar1p1-slim", 0},
+	{"tabla-slim", 0},
+	{"tabla2x-slim", 0},
+	{"taiko-slim-pgd", 0},
+	{"tapan-slim-pgd", 0},
+	{"tomtom-slim-pgd", WCD9330},
+	{"tasha-slim-pgd", WCD9335},
+	{"tavil-slim-pgd", WCD934X},
+	{}
+};
+
+static struct slim_driver wcd_slim_driver = {
+	.driver = {
+		.name = "wcd-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = wcd_slim_device_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+	.device_up = wcd9xxx_slim_device_up,
+	.reset_device = wcd9xxx_slim_device_reset,
+	.device_down = wcd9xxx_slim_device_down,
+};
+
+static struct i2c_device_id wcd9xxx_id_table[] = {
+	{"wcd9xxx-i2c", WCD9XXX_I2C_TOP_LEVEL},
+	{"wcd9xxx-i2c", WCD9XXX_I2C_ANALOG},
+	{"wcd9xxx-i2c", WCD9XXX_I2C_DIGITAL_1},
+	{"wcd9xxx-i2c", WCD9XXX_I2C_DIGITAL_2},
+	{}
+};
+
+static struct i2c_device_id tasha_id_table[] = {
+	{"tasha-i2c-pgd", WCD9XXX_I2C_TOP_LEVEL},
+	{}
+};
+
+static struct i2c_device_id tabla_id_table[] = {
+	{"tabla top level", WCD9XXX_I2C_TOP_LEVEL},
+	{"tabla analog", WCD9XXX_I2C_ANALOG},
+	{"tabla digital1", WCD9XXX_I2C_DIGITAL_1},
+	{"tabla digital2", WCD9XXX_I2C_DIGITAL_2},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static const struct dev_pm_ops wcd9xxx_i2c_pm_ops = {
+	.suspend = wcd9xxx_i2c_suspend,
+	.resume	= wcd9xxx_i2c_resume,
+};
+
+static struct i2c_driver tabla_i2c_driver = {
+	.driver                 = {
+		.owner          =       THIS_MODULE,
+		.name           =       "tabla-i2c-core",
+		.pm		=	&wcd9xxx_i2c_pm_ops,
+	},
+	.id_table               =       tabla_id_table,
+	.probe                  =       wcd9xxx_i2c_probe,
+	.remove                 =       wcd9xxx_i2c_remove,
+};
+
+static struct i2c_driver wcd9xxx_i2c_driver = {
+	.driver                 = {
+		.owner          =       THIS_MODULE,
+		.name           =       "wcd9xxx-i2c-core",
+		.pm		=	&wcd9xxx_i2c_pm_ops,
+	},
+	.id_table               =       wcd9xxx_id_table,
+	.probe                  =       wcd9xxx_i2c_probe,
+	.remove                 =       wcd9xxx_i2c_remove,
+};
+
+static struct i2c_driver wcd9335_i2c_driver = {
+	.driver	                = {
+		.owner	        =       THIS_MODULE,
+		.name           =       "tasha-i2c-core",
+		.pm		=	&wcd9xxx_i2c_pm_ops,
+	},
+	.id_table               =       tasha_id_table,
+	.probe                  =       wcd9xxx_i2c_probe,
+	.remove                 =       wcd9xxx_i2c_remove,
+};
+
+int wcd9xxx_init(void)
+{
+	int ret[NUM_WCD9XXX_REG_RET] = {0};
+	int i = 0;
+
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
+
+	ret[0] = i2c_add_driver(&tabla_i2c_driver);
+	if (ret[0])
+		pr_err("%s: Failed to add the tabla2x I2C driver: %d\n",
+			__func__, ret[0]);
+
+	ret[1] = i2c_add_driver(&wcd9xxx_i2c_driver);
+	if (ret[1])
+		pr_err("%s: Failed to add the wcd9xxx I2C driver: %d\n",
+			__func__, ret[1]);
+
+	ret[2] = i2c_add_driver(&wcd9335_i2c_driver);
+	if (ret[2])
+		pr_err("%s: Failed to add the wcd9335 I2C driver: %d\n",
+			__func__, ret[2]);
+
+	ret[3] = slim_driver_register(&wcd_slim_driver);
+	if (ret[3])
+		pr_err("%s: Failed to register wcd SB driver: %d\n",
+			__func__, ret[3]);
+
+	for (i = 0; i < NUM_WCD9XXX_REG_RET; i++) {
+		if (ret[i])
+			return ret[i];
+	}
+
+	return 0;
+}
+
+void wcd9xxx_exit(void)
+{
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
+
+	i2c_del_driver(&tabla_i2c_driver);
+	i2c_del_driver(&wcd9xxx_i2c_driver);
+	i2c_del_driver(&wcd9335_i2c_driver);
+	slim_driver_unregister(&wcd_slim_driver);
+}
+
+MODULE_DESCRIPTION("Codec core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd9xxx-irq.c b/asoc/codecs/wcd9xxx-irq.c
new file mode 100644
index 0000000..65100c9
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-irq.c
@@ -0,0 +1,853 @@
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/ratelimit.h>
+#include <soc/qcom/pm.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "core.h"
+#include "wcd9xxx-irq.h"
+
+#define BYTE_BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_BYTE))
+#define BIT_BYTE(nr)			((nr) / BITS_PER_BYTE)
+
+#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 100
+
+#ifndef NO_IRQ
+#define NO_IRQ	(-1)
+#endif
+
+#ifdef CONFIG_OF
+struct wcd9xxx_irq_drv_data {
+	struct irq_domain *domain;
+	int irq;
+};
+#endif
+
+static int virq_to_phyirq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int virq);
+static int phyirq_to_virq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res);
+static void wcd9xxx_irq_put_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res);
+static int wcd9xxx_map_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
+
+static void wcd9xxx_irq_lock(struct irq_data *data)
+{
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	mutex_lock(&wcd9xxx_res->irq_lock);
+}
+
+static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
+{
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	int i;
+
+	if ((ARRAY_SIZE(wcd9xxx_res->irq_masks_cur) >
+	     WCD9XXX_MAX_IRQ_REGS) ||
+	     (ARRAY_SIZE(wcd9xxx_res->irq_masks_cache) >
+	      WCD9XXX_MAX_IRQ_REGS)) {
+		pr_err("%s: Array Size out of bound\n", __func__);
+		return;
+	}
+	if (!wcd9xxx_res->wcd_core_regmap) {
+		pr_err("%s: Codec core regmap not defined\n",
+			__func__);
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wcd9xxx_res->irq_masks_cur); i++) {
+		/* If there's been a change in the mask write it back
+		 * to the hardware.
+		 */
+		if (wcd9xxx_res->irq_masks_cur[i] !=
+					wcd9xxx_res->irq_masks_cache[i]) {
+
+			wcd9xxx_res->irq_masks_cache[i] =
+					wcd9xxx_res->irq_masks_cur[i];
+			regmap_write(wcd9xxx_res->wcd_core_regmap,
+			wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i,
+			wcd9xxx_res->irq_masks_cur[i]);
+		}
+	}
+
+	mutex_unlock(&wcd9xxx_res->irq_lock);
+}
+
+static void wcd9xxx_irq_enable(struct irq_data *data)
+{
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+	int byte = BIT_BYTE(wcd9xxx_irq);
+	int size = ARRAY_SIZE(wcd9xxx_res->irq_masks_cur);
+
+	if ((byte < size) && (byte >= 0)) {
+		wcd9xxx_res->irq_masks_cur[byte] &=
+			~(BYTE_BIT_MASK(wcd9xxx_irq));
+	} else {
+		pr_err("%s: Array size is %d but index is %d: Out of range\n",
+			__func__, size, byte);
+	}
+}
+
+static void wcd9xxx_irq_disable(struct irq_data *data)
+{
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+	int byte = BIT_BYTE(wcd9xxx_irq);
+	int size = ARRAY_SIZE(wcd9xxx_res->irq_masks_cur);
+
+	if ((byte < size) && (byte >= 0)) {
+		wcd9xxx_res->irq_masks_cur[byte]
+			|= BYTE_BIT_MASK(wcd9xxx_irq);
+	} else {
+		pr_err("%s: Array size is %d but index is %d: Out of range\n",
+			__func__, size, byte);
+	}
+}
+
+static void wcd9xxx_irq_ack(struct irq_data *data)
+{
+	int wcd9xxx_irq = 0;
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+
+	if (wcd9xxx_res == NULL) {
+		pr_err("%s: wcd9xxx_res is NULL\n", __func__);
+		return;
+	}
+	wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+	pr_debug("%s: IRQ_ACK called for WCD9XXX IRQ: %d\n",
+				__func__, wcd9xxx_irq);
+}
+
+static void wcd9xxx_irq_mask(struct irq_data *d)
+{
+	/* do nothing but required as linux calls irq_mask without NULL check */
+}
+
+static struct irq_chip wcd9xxx_irq_chip = {
+	.name = "wcd9xxx",
+	.irq_bus_lock = wcd9xxx_irq_lock,
+	.irq_bus_sync_unlock = wcd9xxx_irq_sync_unlock,
+	.irq_disable = wcd9xxx_irq_disable,
+	.irq_enable = wcd9xxx_irq_enable,
+	.irq_mask = wcd9xxx_irq_mask,
+	.irq_ack = wcd9xxx_irq_ack,
+};
+
+bool wcd9xxx_lock_sleep(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	enum wcd9xxx_pm_state os;
+
+	/*
+	 * wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+	 * and its subroutines only motly.
+	 * but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
+	 * It can race with wcd9xxx_irq_thread.
+	 * So need to embrace wlock_holders with mutex.
+	 *
+	 * If system didn't resume, we can simply return false so codec driver's
+	 * IRQ handler can return without handling IRQ.
+	 * As interrupt line is still active, codec will have another IRQ to
+	 * retry shortly.
+	 */
+	mutex_lock(&wcd9xxx_res->pm_lock);
+	if (wcd9xxx_res->wlock_holders++ == 0) {
+		pr_debug("%s: holding wake lock\n", __func__);
+		pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
+				      msm_cpuidle_get_deep_idle_latency());
+		pm_stay_awake(wcd9xxx_res->dev);
+	}
+	mutex_unlock(&wcd9xxx_res->pm_lock);
+
+	if (!wait_event_timeout(wcd9xxx_res->pm_wq,
+				((os =  wcd9xxx_pm_cmpxchg(wcd9xxx_res,
+						  WCD9XXX_PM_SLEEPABLE,
+						  WCD9XXX_PM_AWAKE)) ==
+							WCD9XXX_PM_SLEEPABLE ||
+					(os == WCD9XXX_PM_AWAKE)),
+				msecs_to_jiffies(
+					WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
+		pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
+			__func__,
+			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx_res->pm_state,
+			wcd9xxx_res->wlock_holders);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
+		return false;
+	}
+	wake_up_all(&wcd9xxx_res->pm_wq);
+	return true;
+}
+EXPORT_SYMBOL(wcd9xxx_lock_sleep);
+
+void wcd9xxx_unlock_sleep(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	mutex_lock(&wcd9xxx_res->pm_lock);
+	if (--wcd9xxx_res->wlock_holders == 0) {
+		pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
+			 __func__, wcd9xxx_res->pm_state, WCD9XXX_PM_SLEEPABLE);
+		/*
+		 * if wcd9xxx_lock_sleep failed, pm_state would be still
+		 * WCD9XXX_PM_ASLEEP, don't overwrite
+		 */
+		if (likely(wcd9xxx_res->pm_state == WCD9XXX_PM_AWAKE))
+			wcd9xxx_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+		pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
+				PM_QOS_DEFAULT_VALUE);
+		pm_relax(wcd9xxx_res->dev);
+	}
+	mutex_unlock(&wcd9xxx_res->pm_lock);
+	wake_up_all(&wcd9xxx_res->pm_wq);
+}
+EXPORT_SYMBOL(wcd9xxx_unlock_sleep);
+
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	mutex_lock(&wcd9xxx_res->nested_irq_lock);
+}
+
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	mutex_unlock(&wcd9xxx_res->nested_irq_lock);
+}
+
+
+static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res,
+			struct intr_data *irqdata)
+{
+	int irqbit = irqdata->intr_num;
+
+	if (!wcd9xxx_res->wcd_core_regmap) {
+		pr_err("%s: codec core regmap not defined\n",
+			__func__);
+		return;
+	}
+
+	if (irqdata->clear_first) {
+		wcd9xxx_nested_irq_lock(wcd9xxx_res);
+		regmap_write(wcd9xxx_res->wcd_core_regmap,
+			wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] +
+					      BIT_BYTE(irqbit),
+			BYTE_BIT_MASK(irqbit));
+
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			regmap_write(wcd9xxx_res->wcd_core_regmap,
+				wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
+				0x02);
+		handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+		wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+	} else {
+		wcd9xxx_nested_irq_lock(wcd9xxx_res);
+		handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+		regmap_write(wcd9xxx_res->wcd_core_regmap,
+			wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] +
+					      BIT_BYTE(irqbit),
+			BYTE_BIT_MASK(irqbit));
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			regmap_write(wcd9xxx_res->wcd_core_regmap,
+				wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
+				0x02);
+
+		wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+	}
+}
+
+static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
+{
+	int ret;
+	int i;
+	struct intr_data irqdata;
+	char linebuf[128];
+	static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1);
+	struct wcd9xxx_core_resource *wcd9xxx_res = data;
+	int num_irq_regs = wcd9xxx_res->num_irq_regs;
+	u8 status[4], status1[4] = {0}, unmask_status[4] = {0};
+
+	if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) {
+		dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n");
+		return IRQ_NONE;
+	}
+
+	if (!wcd9xxx_res->wcd_core_regmap) {
+		dev_err(wcd9xxx_res->dev,
+			"%s: Codec core regmap not supplied\n",
+			   __func__);
+		goto err_disable_irq;
+	}
+
+	memset(status, 0, sizeof(status));
+	ret = regmap_bulk_read(wcd9xxx_res->wcd_core_regmap,
+		wcd9xxx_res->intr_reg[WCD9XXX_INTR_STATUS_BASE],
+		status, num_irq_regs);
+
+	if (ret < 0) {
+		dev_err(wcd9xxx_res->dev,
+				"Failed to read interrupt status: %d\n", ret);
+		goto err_disable_irq;
+	}
+	/*
+	 * If status is 0 return without clearing.
+	 * status contains: HW status - masked interrupts
+	 * status1 contains: unhandled interrupts - masked interrupts
+	 * unmasked_status contains: unhandled interrupts
+	 */
+	if (unlikely(!memcmp(status, status1, sizeof(status)))) {
+		pr_debug("%s: status is 0\n", __func__);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
+		return IRQ_HANDLED;
+	}
+
+	/*
+	 * Copy status to unmask_status before masking, otherwise SW may miss
+	 * to clear masked interrupt in corner case.
+	 */
+	memcpy(unmask_status, status, sizeof(unmask_status));
+
+	/* Apply masking */
+	for (i = 0; i < num_irq_regs; i++)
+		status[i] &= ~wcd9xxx_res->irq_masks_cur[i];
+
+	memcpy(status1, status, sizeof(status1));
+
+	/* Find out which interrupt was triggered and call that interrupt's
+	 * handler function
+	 *
+	 * Since codec has only one hardware irq line which is shared by
+	 * codec's different internal interrupts, so it's possible master irq
+	 * handler dispatches multiple nested irq handlers after breaking
+	 * order.  Dispatch interrupts in the order that is maintained by
+	 * the interrupt table.
+	 */
+	for (i = 0; i < wcd9xxx_res->intr_table_size; i++) {
+		irqdata = wcd9xxx_res->intr_table[i];
+		if (status[BIT_BYTE(irqdata.intr_num)] &
+			BYTE_BIT_MASK(irqdata.intr_num)) {
+			wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata);
+			status1[BIT_BYTE(irqdata.intr_num)] &=
+					~BYTE_BIT_MASK(irqdata.intr_num);
+			unmask_status[BIT_BYTE(irqdata.intr_num)] &=
+					~BYTE_BIT_MASK(irqdata.intr_num);
+		}
+	}
+
+	/*
+	 * As a failsafe if unhandled irq is found, clear it to prevent
+	 * interrupt storm.
+	 * Note that we can say there was an unhandled irq only when no irq
+	 * handled by nested irq handler since Taiko supports qdsp as irqs'
+	 * destination for few irqs.  Therefore driver shouldn't clear pending
+	 * irqs when few handled while few others not.
+	 */
+	if (unlikely(!memcmp(status, status1, sizeof(status)))) {
+		if (__ratelimit(&ratelimit)) {
+			pr_warn("%s: Unhandled irq found\n", __func__);
+			hex_dump_to_buffer(status, sizeof(status), 16, 1,
+					   linebuf, sizeof(linebuf), false);
+			pr_warn("%s: status0 : %s\n", __func__, linebuf);
+			hex_dump_to_buffer(status1, sizeof(status1), 16, 1,
+					   linebuf, sizeof(linebuf), false);
+			pr_warn("%s: status1 : %s\n", __func__, linebuf);
+		}
+		/*
+		 * unmask_status contains unhandled interrupts, hence clear all
+		 * unhandled interrupts.
+		 */
+		ret = regmap_bulk_write(wcd9xxx_res->wcd_core_regmap,
+			wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE],
+			unmask_status, num_irq_regs);
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			regmap_write(wcd9xxx_res->wcd_core_regmap,
+				wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
+				0x02);
+	}
+	wcd9xxx_unlock_sleep(wcd9xxx_res);
+
+	return IRQ_HANDLED;
+
+err_disable_irq:
+		dev_err(wcd9xxx_res->dev,
+				"Disable irq %d\n", wcd9xxx_res->irq);
+
+		disable_irq_wake(wcd9xxx_res->irq);
+		disable_irq_nosync(wcd9xxx_res->irq);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
+		return IRQ_NONE;
+}
+
+/**
+ * wcd9xxx_free_irq
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ * @data: data pointer
+ *
+ */
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq, void *data)
+{
+	free_irq(phyirq_to_virq(wcd9xxx_res, irq), data);
+}
+EXPORT_SYMBOL(wcd9xxx_free_irq);
+
+/**
+ * wcd9xxx_enable_irq
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ *
+ */
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
+{
+	if (wcd9xxx_res->irq)
+		enable_irq(phyirq_to_virq(wcd9xxx_res, irq));
+}
+EXPORT_SYMBOL(wcd9xxx_enable_irq);
+
+/**
+ * wcd9xxx_disable_irq
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ *
+ */
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
+{
+	if (wcd9xxx_res->irq)
+		disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq));
+}
+EXPORT_SYMBOL(wcd9xxx_disable_irq);
+
+/**
+ * wcd9xxx_disable_irq_sync
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ *
+ */
+void wcd9xxx_disable_irq_sync(
+			struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
+{
+	if (wcd9xxx_res->irq)
+		disable_irq(phyirq_to_virq(wcd9xxx_res, irq));
+}
+EXPORT_SYMBOL(wcd9xxx_disable_irq_sync);
+
+static int wcd9xxx_irq_setup_downstream_irq(
+			struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	int irq, virq, ret;
+
+	pr_debug("%s: enter\n", __func__);
+
+	for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) {
+		/* Map OF irq */
+		virq = wcd9xxx_map_irq(wcd9xxx_res, irq);
+		pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
+		if (virq == NO_IRQ) {
+			pr_err("%s, No interrupt specifier for irq %d\n",
+			       __func__, irq);
+			return NO_IRQ;
+		}
+
+		ret = irq_set_chip_data(virq, wcd9xxx_res);
+		if (ret) {
+			pr_err("%s: Failed to configure irq %d (%d)\n",
+			       __func__, irq, ret);
+			return ret;
+		}
+
+		if (wcd9xxx_res->irq_level_high[irq])
+			irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
+						 handle_level_irq);
+		else
+			irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
+						 handle_edge_irq);
+
+		irq_set_nested_thread(virq, 1);
+	}
+
+	pr_debug("%s: leave\n", __func__);
+
+	return 0;
+}
+
+/**
+ * wcd9xxx_irq_init
+ *
+ * @wcd9xxx_res: pointer to core resource
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	int i, ret;
+	u8 irq_level[wcd9xxx_res->num_irq_regs];
+	struct irq_domain *domain;
+	struct device_node *pnode;
+
+	mutex_init(&wcd9xxx_res->irq_lock);
+	mutex_init(&wcd9xxx_res->nested_irq_lock);
+
+	pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node);
+	if (unlikely(!pnode))
+		return -EINVAL;
+
+	domain = irq_find_host(pnode);
+	if (unlikely(!domain))
+		return -EINVAL;
+
+	wcd9xxx_res->domain = domain;
+
+	wcd9xxx_res->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx_res);
+	if (!wcd9xxx_res->irq) {
+		pr_warn("%s: irq driver is not yet initialized\n", __func__);
+		mutex_destroy(&wcd9xxx_res->irq_lock);
+		mutex_destroy(&wcd9xxx_res->nested_irq_lock);
+		return -EPROBE_DEFER;
+	}
+	pr_debug("%s: probed irq %d\n", __func__, wcd9xxx_res->irq);
+
+	/* Setup downstream IRQs */
+	ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx_res);
+	if (ret) {
+		pr_err("%s: Failed to setup downstream IRQ\n", __func__);
+		wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+		mutex_destroy(&wcd9xxx_res->irq_lock);
+		mutex_destroy(&wcd9xxx_res->nested_irq_lock);
+		return ret;
+	}
+
+	/* All other wcd9xxx interrupts are edge triggered */
+	wcd9xxx_res->irq_level_high[0] = true;
+
+	/* mask all the interrupts */
+	memset(irq_level, 0, wcd9xxx_res->num_irq_regs);
+	for (i = 0; i < wcd9xxx_res->num_irqs; i++) {
+		wcd9xxx_res->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		wcd9xxx_res->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		irq_level[BIT_BYTE(i)] |=
+		    wcd9xxx_res->irq_level_high[i] << (i % BITS_PER_BYTE);
+	}
+
+	if (!wcd9xxx_res->wcd_core_regmap) {
+		dev_err(wcd9xxx_res->dev,
+			"%s: Codec core regmap not defined\n",
+			   __func__);
+		ret = -EINVAL;
+		goto fail_irq_init;
+	}
+
+	for (i = 0; i < wcd9xxx_res->num_irq_regs; i++) {
+		/* Initialize interrupt mask and level registers */
+		regmap_write(wcd9xxx_res->wcd_core_regmap,
+			wcd9xxx_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] + i,
+					irq_level[i]);
+		regmap_write(wcd9xxx_res->wcd_core_regmap,
+			wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i,
+			wcd9xxx_res->irq_masks_cur[i]);
+	}
+
+	ret = request_threaded_irq(wcd9xxx_res->irq, NULL, wcd9xxx_irq_thread,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   "wcd9xxx", wcd9xxx_res);
+	if (ret != 0)
+		dev_err(wcd9xxx_res->dev, "Failed to request IRQ %d: %d\n",
+			wcd9xxx_res->irq, ret);
+	else {
+		ret = enable_irq_wake(wcd9xxx_res->irq);
+		if (ret)
+			dev_err(wcd9xxx_res->dev,
+				"Failed to set wake interrupt on IRQ %d: %d\n",
+				wcd9xxx_res->irq, ret);
+		if (ret)
+			free_irq(wcd9xxx_res->irq, wcd9xxx_res);
+	}
+
+	if (ret)
+		goto fail_irq_init;
+
+	return ret;
+
+fail_irq_init:
+	dev_err(wcd9xxx_res->dev,
+			"%s: Failed to init wcd9xxx irq\n", __func__);
+	wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+	mutex_destroy(&wcd9xxx_res->irq_lock);
+	mutex_destroy(&wcd9xxx_res->nested_irq_lock);
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_irq_init);
+
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq, irq_handler_t handler,
+			const char *name, void *data)
+{
+	int virq;
+
+	virq = phyirq_to_virq(wcd9xxx_res, irq);
+
+	return request_threaded_irq(virq, NULL, handler, IRQF_TRIGGER_RISING,
+				    name, data);
+}
+EXPORT_SYMBOL(wcd9xxx_request_irq);
+
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	dev_dbg(wcd9xxx_res->dev, "%s: Cleaning up irq %d\n", __func__,
+		wcd9xxx_res->irq);
+
+	if (wcd9xxx_res->irq) {
+		disable_irq_wake(wcd9xxx_res->irq);
+		free_irq(wcd9xxx_res->irq, wcd9xxx_res);
+		wcd9xxx_res->irq = 0;
+		wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+	}
+	mutex_destroy(&wcd9xxx_res->irq_lock);
+	mutex_destroy(&wcd9xxx_res->nested_irq_lock);
+}
+
+#ifndef CONFIG_OF
+static int phyirq_to_virq(
+	struct wcd9xxx_core_resource *wcd9xxx_res,
+	int offset)
+{
+	return wcd9xxx_res->irq_base + offset;
+}
+
+static int virq_to_phyirq(
+	struct wcd9xxx_core_resource *wcd9xxx_res,
+	int virq)
+{
+	return virq - wcd9xxx_res->irq_base;
+}
+
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	return wcd9xxx_res->irq;
+}
+
+static void wcd9xxx_irq_put_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	/* Do nothing */
+}
+
+static int wcd9xxx_map_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res, int irq)
+{
+	return phyirq_to_virq(wcd9xxx_core_res, irq);
+}
+#else
+static struct wcd9xxx_irq_drv_data *
+wcd9xxx_irq_add_domain(struct device_node *node,
+			       struct device_node *parent)
+{
+	struct wcd9xxx_irq_drv_data *data = NULL;
+
+	pr_debug("%s: node %s, node parent %s\n", __func__,
+		 node->name, node->parent->name);
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	/*
+	 * wcd9xxx_intc interrupt controller supports N to N irq mapping with
+	 * single cell binding with irq numbers(offsets) only.
+	 * Use irq_domain_simple_ops that has irq_domain_simple_map and
+	 * irq_domain_xlate_onetwocell.
+	 */
+	data->domain = irq_domain_add_linear(node, WCD9XXX_MAX_NUM_IRQS,
+					     &irq_domain_simple_ops, data);
+	if (!data->domain) {
+		kfree(data);
+		return NULL;
+	}
+
+	return data;
+}
+
+static struct wcd9xxx_irq_drv_data *
+wcd9xxx_get_irq_drv_d(const struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	struct irq_domain *domain;
+
+	domain = wcd9xxx_res->domain;
+
+	if (domain)
+		return domain->host_data;
+	else
+		return NULL;
+}
+
+static int phyirq_to_virq(struct wcd9xxx_core_resource *wcd9xxx_res, int offset)
+{
+	struct wcd9xxx_irq_drv_data *data;
+
+	data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
+	if (!data) {
+		pr_warn("%s: not registered to interrupt controller\n",
+			__func__);
+		return -EINVAL;
+	}
+	return irq_linear_revmap(data->domain, offset);
+}
+
+static int virq_to_phyirq(struct wcd9xxx_core_resource *wcd9xxx_res, int virq)
+{
+	struct irq_data *irq_data = irq_get_irq_data(virq);
+
+	if (unlikely(!irq_data)) {
+		pr_err("%s: irq_data is NULL", __func__);
+		return -EINVAL;
+	}
+	return irq_data->hwirq;
+}
+
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+				struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	struct wcd9xxx_irq_drv_data *data;
+
+	data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
+	if (!data) {
+		pr_err("%s: interrupt controller is not registered\n",
+			__func__);
+		return 0;
+	}
+
+	/* Make sure data is updated before return. */
+	rmb();
+	return data->irq;
+}
+
+static void wcd9xxx_irq_put_upstream_irq(
+			struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	wcd9xxx_res->domain = NULL;
+}
+
+static int wcd9xxx_map_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
+{
+	return of_irq_to_resource(wcd9xxx_res->dev->of_node, irq, NULL);
+}
+
+static int wcd9xxx_irq_probe(struct platform_device *pdev)
+{
+	int irq, dir_apps_irq = -EINVAL;
+	struct wcd9xxx_irq_drv_data *data;
+	struct device_node *node = pdev->dev.of_node;
+	int ret = -EINVAL;
+
+	irq = of_get_named_gpio(node, "qcom,gpio-connect", 0);
+	if (!gpio_is_valid(irq))
+		dir_apps_irq = platform_get_irq_byname(pdev, "wcd_irq");
+
+	if (!gpio_is_valid(irq) && dir_apps_irq < 0) {
+		dev_err(&pdev->dev, "TLMM connect gpio not found\n");
+		return -EPROBE_DEFER;
+	}
+	if (dir_apps_irq > 0) {
+		irq = dir_apps_irq;
+	} else {
+		irq = gpio_to_irq(irq);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "Unable to configure irq\n");
+			return irq;
+		}
+	}
+	dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
+	data = wcd9xxx_irq_add_domain(node, node->parent);
+	if (!data) {
+		pr_err("%s: irq_add_domain failed\n", __func__);
+		return -EINVAL;
+	}
+	data->irq = irq;
+
+	/* Make sure irq is saved before return. */
+	wmb();
+	ret = 0;
+
+	return ret;
+}
+
+static int wcd9xxx_irq_remove(struct platform_device *pdev)
+{
+	struct irq_domain *domain;
+	struct wcd9xxx_irq_drv_data *data;
+
+	domain = irq_find_host(pdev->dev.of_node);
+	if (unlikely(!domain)) {
+		pr_err("%s: domain is NULL", __func__);
+		return -EINVAL;
+	}
+	data = (struct wcd9xxx_irq_drv_data *)domain->host_data;
+	data->irq = 0;
+
+	/* Make sure irq variable is updated in data, before irq removal. */
+	wmb();
+	irq_domain_remove(data->domain);
+	kfree(data);
+	domain->host_data = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id of_match[] = {
+	{ .compatible = "qcom,wcd9xxx-irq" },
+	{ }
+};
+
+static struct platform_driver wcd9xxx_irq_driver = {
+	.probe = wcd9xxx_irq_probe,
+	.remove = wcd9xxx_irq_remove,
+	.driver = {
+		.name = "wcd9xxx_intc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(of_match),
+	},
+};
+
+int wcd9xxx_irq_drv_init(void)
+{
+	return platform_driver_register(&wcd9xxx_irq_driver);
+}
+
+void wcd9xxx_irq_drv_exit(void)
+{
+	platform_driver_unregister(&wcd9xxx_irq_driver);
+}
+#endif /* CONFIG_OF */
diff --git a/asoc/codecs/wcd9xxx-irq.h b/asoc/codecs/wcd9xxx-irq.h
new file mode 100644
index 0000000..dfe0b92
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-irq.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include "core.h"
+
+#ifndef __MFD_WCD9XXX_IRQ_H
+#define __MFD_WCD9XXX_IRQ_H
+bool wcd9xxx_lock_sleep(struct wcd9xxx_core_resource *wcd9xxx_res);
+void wcd9xxx_unlock_sleep(struct wcd9xxx_core_resource *wcd9xxx_res);
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *wcd9xxx_res);
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *wcd9xxx_res);
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq,
+			irq_handler_t handler, const char *name, void *data);
+
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq, void *data);
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq);
+void wcd9xxx_disable_irq_sync(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq);
+
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res);
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res);
+int wcd9xxx_irq_drv_init(void);
+void wcd9xxx_irq_drv_exit(void);
+#endif
diff --git a/asoc/codecs/wcd9xxx-regmap.h b/asoc/codecs/wcd9xxx-regmap.h
new file mode 100644
index 0000000..b7604ff
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-regmap.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WCD9XXX_REGMAP_
+#define _WCD9XXX_REGMAP_
+
+#include <linux/regmap.h>
+#include "core.h"
+
+typedef int (*regmap_patch_fptr)(struct regmap *, int);
+
+extern struct regmap_config wcd934x_regmap_config;
+extern int wcd934x_regmap_register_patch(struct regmap *regmap,
+					 int version);
+
+extern struct regmap_config wcd9335_regmap_config;
+extern int wcd9335_regmap_register_patch(struct regmap *regmap,
+					 int version);
+
+static inline struct regmap_config *wcd9xxx_get_regmap_config(int type)
+{
+	struct regmap_config *regmap_config;
+
+	switch (type) {
+	case WCD934X:
+		regmap_config = &wcd934x_regmap_config;
+		break;
+	case WCD9335:
+		regmap_config = &wcd9335_regmap_config;
+		break;
+	default:
+		regmap_config = NULL;
+		break;
+	};
+
+	return regmap_config;
+}
+
+static inline regmap_patch_fptr wcd9xxx_get_regmap_reg_patch(int type)
+{
+	regmap_patch_fptr apply_patch;
+
+	switch (type) {
+	case WCD9335:
+		apply_patch = wcd9335_regmap_register_patch;
+		break;
+	case WCD934X:
+		apply_patch = wcd934x_regmap_register_patch;
+		break;
+	default:
+		apply_patch = NULL;
+		break;
+	}
+
+	return apply_patch;
+}
+
+#endif
diff --git a/asoc/codecs/wcd9xxx-resmgr-v2.c b/asoc/codecs/wcd9xxx-resmgr-v2.c
new file mode 100644
index 0000000..1b7610f
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-resmgr-v2.c
@@ -0,0 +1,693 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+#include "wcd9xxx-resmgr-v2.h"
+#include "core.h"
+#include "wcd9335_registers.h"
+#include <asoc/wcd934x_registers.h>
+
+#define WCD9XXX_RCO_CALIBRATION_DELAY_INC_US 5000
+#define WCD93XX_ANA_BIAS 0x0601
+#define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41
+#define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42
+
+
+static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type)
+{
+	if (clk_type == WCD_CLK_OFF)
+		return "WCD_CLK_OFF";
+	else if (clk_type == WCD_CLK_RCO)
+		return "WCD_CLK_RCO";
+	else if (clk_type == WCD_CLK_MCLK)
+		return "WCD_CLK_MCLK";
+	else
+		return "WCD_CLK_UNDEFINED";
+}
+
+static int wcd_resmgr_codec_reg_update_bits(struct wcd9xxx_resmgr_v2 *resmgr,
+					    u16 reg, u8 mask, u8 val)
+{
+	bool change;
+	int ret;
+
+	if (resmgr->codec_type == WCD934X) {
+		/* Tavil does not support ANA_CLK_TOP register */
+		if (reg == WCD9335_ANA_CLK_TOP)
+			return 0;
+	} else {
+		/* Tasha does not support CLK_SYS_MCLK_PRG register */
+		if (reg == WCD934X_CLK_SYS_MCLK_PRG)
+			return 0;
+	}
+	if (resmgr->codec) {
+		ret = snd_soc_update_bits(resmgr->codec, reg, mask, val);
+	} else if (resmgr->core_res->wcd_core_regmap) {
+		ret = regmap_update_bits_check(
+				resmgr->core_res->wcd_core_regmap,
+				reg, mask, val, &change);
+		if (!ret)
+			ret = change;
+	} else {
+		pr_err("%s: codec/regmap not defined\n", __func__);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int wcd_resmgr_codec_reg_read(struct wcd9xxx_resmgr_v2 *resmgr,
+				     unsigned int reg)
+{
+	int val, ret;
+
+	if (resmgr->codec_type == WCD934X) {
+		if (reg == WCD9335_ANA_CLK_TOP)
+			return 0;
+	} else {
+		if (reg == WCD934X_CLK_SYS_MCLK_PRG)
+			return 0;
+	}
+	if (resmgr->codec) {
+		val = snd_soc_read(resmgr->codec, reg);
+	} else if (resmgr->core_res->wcd_core_regmap) {
+		ret = regmap_read(resmgr->core_res->wcd_core_regmap,
+				  reg, &val);
+		if (ret)
+			val = ret;
+	} else {
+		pr_err("%s: wcd regmap is null\n", __func__);
+		return -EINVAL;
+	}
+
+	return val;
+}
+
+/*
+ * wcd_resmgr_get_clk_type()
+ * Returns clk type that is currently enabled
+ */
+int wcd_resmgr_get_clk_type(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	if (!resmgr) {
+		pr_err("%s: resmgr not initialized\n", __func__);
+		return -EINVAL;
+	}
+	return resmgr->clk_type;
+}
+EXPORT_SYMBOL(wcd_resmgr_get_clk_type);
+
+static void wcd_resmgr_cdc_specific_get_clk(struct wcd9xxx_resmgr_v2 *resmgr,
+						int clk_users)
+{
+	/* Caller of this function should have acquired BG_CLK lock */
+	if (clk_users) {
+		if (resmgr->resmgr_cb &&
+		    resmgr->resmgr_cb->cdc_rco_ctrl) {
+			while (clk_users--)
+				resmgr->resmgr_cb->cdc_rco_ctrl(resmgr->codec,
+								true);
+		}
+	}
+}
+
+/*
+ * wcd_resmgr_post_ssr_v2
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ */
+void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	int old_bg_audio_users;
+	int old_clk_rco_users, old_clk_mclk_users;
+
+	WCD9XXX_V2_BG_CLK_LOCK(resmgr);
+
+	old_bg_audio_users = resmgr->master_bias_users;
+	old_clk_mclk_users = resmgr->clk_mclk_users;
+	old_clk_rco_users = resmgr->clk_rco_users;
+	resmgr->master_bias_users = 0;
+	resmgr->clk_mclk_users = 0;
+	resmgr->clk_rco_users = 0;
+	resmgr->clk_type = WCD_CLK_OFF;
+
+	pr_debug("%s: old_bg_audio_users=%d old_clk_mclk_users=%d old_clk_rco_users=%d\n",
+		 __func__, old_bg_audio_users,
+		 old_clk_mclk_users, old_clk_rco_users);
+
+	if (old_bg_audio_users) {
+		while (old_bg_audio_users--)
+			wcd_resmgr_enable_master_bias(resmgr);
+	}
+
+	if (old_clk_mclk_users) {
+		while (old_clk_mclk_users--)
+			wcd_resmgr_enable_clk_block(resmgr, WCD_CLK_MCLK);
+	}
+
+	if (old_clk_rco_users)
+		wcd_resmgr_cdc_specific_get_clk(resmgr, old_clk_rco_users);
+
+	WCD9XXX_V2_BG_CLK_UNLOCK(resmgr);
+}
+EXPORT_SYMBOL(wcd_resmgr_post_ssr_v2);
+
+/*
+ * wcd_resmgr_enable_master_bias: enable codec master bias
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ */
+int wcd_resmgr_enable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	mutex_lock(&resmgr->master_bias_lock);
+
+	resmgr->master_bias_users++;
+	if (resmgr->master_bias_users == 1) {
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS,
+						 0x80, 0x80);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS,
+						 0x40, 0x40);
+		/*
+		 * 1ms delay is required after pre-charge is enabled
+		 * as per HW requirement
+		 */
+		usleep_range(1000, 1100);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS,
+						 0x40, 0x00);
+		wcd_resmgr_codec_reg_update_bits(resmgr,
+						WCD93XX_ANA_BIAS, 0x20, 0x00);
+	}
+
+	pr_debug("%s: current master bias users: %d\n", __func__,
+		 resmgr->master_bias_users);
+
+	mutex_unlock(&resmgr->master_bias_lock);
+	return 0;
+}
+EXPORT_SYMBOL(wcd_resmgr_enable_master_bias);
+
+/*
+ * wcd_resmgr_disable_master_bias: disable codec master bias
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ */
+int wcd_resmgr_disable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	mutex_lock(&resmgr->master_bias_lock);
+	if (resmgr->master_bias_users <= 0) {
+		mutex_unlock(&resmgr->master_bias_lock);
+		return -EINVAL;
+	}
+
+	resmgr->master_bias_users--;
+	if (resmgr->master_bias_users == 0) {
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS,
+						 0x80, 0x00);
+		wcd_resmgr_codec_reg_update_bits(resmgr,
+						WCD93XX_ANA_BIAS, 0x20, 0x00);
+	}
+	mutex_unlock(&resmgr->master_bias_lock);
+	return 0;
+}
+EXPORT_SYMBOL(wcd_resmgr_disable_master_bias);
+
+static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	/* Enable mclk requires master bias to be enabled first */
+	if (resmgr->master_bias_users <= 0) {
+		pr_err("%s: Cannot turn on MCLK, BG is not enabled\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (((resmgr->clk_mclk_users == 0) &&
+	     (resmgr->clk_type == WCD_CLK_MCLK)) ||
+	    ((resmgr->clk_mclk_users > 0) &&
+	    (resmgr->clk_type != WCD_CLK_MCLK))) {
+		pr_err("%s: Error enabling MCLK, clk_type: %s\n",
+			__func__,
+			wcd_resmgr_clk_type_to_str(resmgr->clk_type));
+		return -EINVAL;
+	}
+
+	if (++resmgr->clk_mclk_users == 1) {
+		wcd_resmgr_codec_reg_update_bits(resmgr,
+				WCD9335_ANA_CLK_TOP, 0x80, 0x80);
+		wcd_resmgr_codec_reg_update_bits(resmgr,
+				WCD9335_ANA_CLK_TOP, 0x08, 0x00);
+		wcd_resmgr_codec_reg_update_bits(resmgr,
+				WCD9335_ANA_CLK_TOP, 0x04, 0x04);
+		if (resmgr->codec_type == WCD934X) {
+			/*
+			 * In tavil clock contrl register is changed
+			 * to CLK_SYS_MCLK_PRG
+			 */
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x80);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x30, 0x10);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x01, 0x01);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x01, 0x01);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x01, 0x01);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x01, 0x01);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x00);
+		} else {
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+					0x01, 0x01);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+					0x01, 0x01);
+		}
+		/*
+		 * 10us sleep is required after clock is enabled
+		 * as per HW requirement
+		 */
+		usleep_range(10, 15);
+	}
+
+	resmgr->clk_type = WCD_CLK_MCLK;
+
+	pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
+		 resmgr->clk_mclk_users,
+		 wcd_resmgr_clk_type_to_str(resmgr->clk_type));
+
+	return 0;
+}
+
+static int wcd_resmgr_disable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	if (resmgr->clk_mclk_users <= 0) {
+		pr_err("%s: No mclk users, cannot disable mclk\n", __func__);
+		return -EINVAL;
+	}
+
+	if (--resmgr->clk_mclk_users == 0) {
+		if (resmgr->clk_rco_users > 0) {
+			/* MCLK to RCO switch */
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD9335_ANA_CLK_TOP,
+					0x08, 0x08);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x02);
+			/* Disable clock buffer */
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x00);
+			resmgr->clk_type = WCD_CLK_RCO;
+		} else {
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD9335_ANA_CLK_TOP,
+					0x04, 0x00);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+					WCD934X_CLK_SYS_MCLK_PRG, 0x81, 0x00);
+			resmgr->clk_type = WCD_CLK_OFF;
+		}
+
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
+						 0x80, 0x00);
+	}
+
+	if ((resmgr->codec_type == WCD934X) &&
+	    (resmgr->clk_type == WCD_CLK_OFF))
+		wcd_resmgr_set_sido_input_src(resmgr, SIDO_SOURCE_INTERNAL);
+
+	pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
+		 resmgr->clk_mclk_users,
+		 wcd_resmgr_clk_type_to_str(resmgr->clk_type));
+
+	return 0;
+}
+
+static void wcd_resmgr_set_buck_accuracy(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+					 0x02, 0x02);
+	/* 100us sleep needed after HIGH_ACCURACY_PRE_EN1 */
+	usleep_range(100, 110);
+	wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+					 0x01, 0x01);
+	/* 100us sleep needed after HIGH_ACCURACY_PRE_EN2 */
+	usleep_range(100, 110);
+	wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+					 0x04, 0x04);
+	/* 100us sleep needed after HIGH_ACCURACY_EN */
+	usleep_range(100, 110);
+}
+
+static int wcd_resmgr_enable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	bool rco_cal_done = true;
+
+	resmgr->clk_rco_users++;
+	if ((resmgr->clk_rco_users == 1) &&
+	    ((resmgr->clk_type == WCD_CLK_OFF) ||
+	     (resmgr->clk_mclk_users == 0))) {
+		pr_warn("%s: RCO enable requires MCLK to be ON first\n",
+			__func__);
+		resmgr->clk_rco_users--;
+		return -EINVAL;
+	} else if ((resmgr->clk_rco_users == 1) &&
+		   (resmgr->clk_mclk_users)) {
+		/* RCO Enable */
+		if (resmgr->sido_input_src == SIDO_SOURCE_INTERNAL) {
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+							 WCD9335_ANA_RCO,
+							 0x80, 0x80);
+			if (resmgr->codec_type == WCD934X)
+				wcd_resmgr_set_buck_accuracy(resmgr);
+		}
+
+		/*
+		 * 20us required after RCO BG is enabled as per HW
+		 * requirements
+		 */
+		usleep_range(20, 25);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
+						 0x40, 0x40);
+		/*
+		 * 20us required after RCO is enabled as per HW
+		 * requirements
+		 */
+		usleep_range(20, 25);
+		/* RCO Calibration */
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
+						 0x04, 0x04);
+		if (resmgr->codec_type == WCD934X)
+			/*
+			 * For wcd934x codec, 20us sleep is needed
+			 * after enabling RCO calibration
+			 */
+			usleep_range(20, 25);
+
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
+						 0x04, 0x00);
+		if (resmgr->codec_type == WCD934X)
+			/*
+			 * For wcd934x codec, 20us sleep is needed
+			 * after disabling RCO calibration
+			 */
+			usleep_range(20, 25);
+
+		/* RCO calibration takes app. 5ms to complete */
+		usleep_range(WCD9XXX_RCO_CALIBRATION_DELAY_INC_US,
+		       WCD9XXX_RCO_CALIBRATION_DELAY_INC_US + 100);
+		if (wcd_resmgr_codec_reg_read(resmgr, WCD9335_ANA_RCO) & 0x02)
+			rco_cal_done = false;
+
+		WARN((!rco_cal_done), "RCO Calibration failed\n");
+
+		/* Switch MUX to RCO */
+		if (resmgr->clk_mclk_users == 1) {
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+							WCD9335_ANA_CLK_TOP,
+							0x08, 0x08);
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+						 WCD934X_CLK_SYS_MCLK_PRG,
+						 0x02, 0x02);
+			resmgr->clk_type = WCD_CLK_RCO;
+		}
+	}
+	pr_debug("%s: rco clk users: %d, clk_type: %s\n", __func__,
+		 resmgr->clk_rco_users,
+		 wcd_resmgr_clk_type_to_str(resmgr->clk_type));
+
+	return 0;
+}
+
+static int wcd_resmgr_disable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	if ((resmgr->clk_rco_users <= 0) ||
+	    (resmgr->clk_type == WCD_CLK_OFF)) {
+		pr_err("%s: rco_clk_users = %d, clk_type = %d, cannot disable\n",
+			__func__, resmgr->clk_rco_users, resmgr->clk_type);
+		return -EINVAL;
+	}
+
+	resmgr->clk_rco_users--;
+
+	if ((resmgr->clk_rco_users == 0) &&
+	    (resmgr->clk_type == WCD_CLK_RCO)) {
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
+						 0x08, 0x00);
+		wcd_resmgr_codec_reg_update_bits(resmgr,
+						 WCD934X_CLK_SYS_MCLK_PRG,
+						 0x02, 0x00);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP,
+						 0x04, 0x00);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
+						 0x40, 0x00);
+		if (resmgr->sido_input_src == SIDO_SOURCE_INTERNAL)
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+							 WCD9335_ANA_RCO,
+							 0x80, 0x00);
+		wcd_resmgr_codec_reg_update_bits(resmgr,
+						 WCD934X_CLK_SYS_MCLK_PRG,
+						 0x01, 0x00);
+		resmgr->clk_type = WCD_CLK_OFF;
+	} else if ((resmgr->clk_rco_users == 0) &&
+	      (resmgr->clk_mclk_users)) {
+		/* Disable RCO while MCLK is ON */
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_RCO,
+						 0x40, 0x00);
+		if (resmgr->sido_input_src == SIDO_SOURCE_INTERNAL)
+			wcd_resmgr_codec_reg_update_bits(resmgr,
+							 WCD9335_ANA_RCO,
+							 0x80, 0x00);
+	}
+
+	if ((resmgr->codec_type == WCD934X) &&
+	    (resmgr->clk_type == WCD_CLK_OFF))
+		wcd_resmgr_set_sido_input_src(resmgr, SIDO_SOURCE_INTERNAL);
+
+	pr_debug("%s: rco clk users: %d, clk_type: %s\n", __func__,
+		 resmgr->clk_rco_users,
+		 wcd_resmgr_clk_type_to_str(resmgr->clk_type));
+
+	return 0;
+}
+
+/*
+ * wcd_resmgr_enable_clk_block: enable MCLK or RCO
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ * @type: Clock type to enable
+ */
+int wcd_resmgr_enable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr,
+				enum wcd_clock_type type)
+{
+	int ret;
+
+	switch (type) {
+	case WCD_CLK_MCLK:
+		ret = wcd_resmgr_enable_clk_mclk(resmgr);
+		break;
+	case WCD_CLK_RCO:
+		ret = wcd_resmgr_enable_clk_rco(resmgr);
+		break;
+	default:
+		pr_err("%s: Unknown Clock type: %s\n", __func__,
+			wcd_resmgr_clk_type_to_str(type));
+		ret = -EINVAL;
+		break;
+	};
+
+	if (ret)
+		pr_err("%s: Enable clock %s failed\n", __func__,
+			wcd_resmgr_clk_type_to_str(type));
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd_resmgr_enable_clk_block);
+
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+					  int sido_src)
+{
+	if (!resmgr)
+		return;
+
+	if (sido_src == resmgr->sido_input_src)
+		return;
+
+	if (sido_src == SIDO_SOURCE_INTERNAL) {
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+						 0x04, 0x00);
+		usleep_range(100, 110);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+						 0x03, 0x00);
+		usleep_range(100, 110);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_RCO,
+						 0x80, 0x00);
+		usleep_range(100, 110);
+		resmgr->sido_input_src = SIDO_SOURCE_INTERNAL;
+		pr_debug("%s: sido input src to internal\n", __func__);
+	} else if (sido_src == SIDO_SOURCE_RCO_BG) {
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_RCO,
+						 0x80, 0x80);
+		usleep_range(100, 110);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+						 0x02, 0x02);
+		usleep_range(100, 110);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+						 0x01, 0x01);
+		usleep_range(100, 110);
+		wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+						 0x04, 0x04);
+		usleep_range(100, 110);
+		resmgr->sido_input_src = SIDO_SOURCE_RCO_BG;
+		pr_debug("%s: sido input src to external\n", __func__);
+	}
+}
+EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src);
+
+/*
+ * wcd_resmgr_set_sido_input_src_locked:
+ *   Set SIDO input in BG_CLK locked context
+ *
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ * @sido_src: Select the SIDO input source
+ */
+void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr,
+					  int sido_src)
+{
+	if (!resmgr)
+		return;
+
+	WCD9XXX_V2_BG_CLK_LOCK(resmgr);
+	wcd_resmgr_set_sido_input_src(resmgr, sido_src);
+	WCD9XXX_V2_BG_CLK_UNLOCK(resmgr);
+}
+EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src_locked);
+
+/*
+ * wcd_resmgr_disable_clk_block: disable MCLK or RCO
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ * @type: Clock type to disable
+ */
+int wcd_resmgr_disable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr,
+				enum wcd_clock_type type)
+{
+	int ret;
+
+	switch (type) {
+	case WCD_CLK_MCLK:
+		ret = wcd_resmgr_disable_clk_mclk(resmgr);
+		break;
+	case WCD_CLK_RCO:
+		ret = wcd_resmgr_disable_clk_rco(resmgr);
+		break;
+	default:
+		pr_err("%s: Unknown Clock type: %s\n", __func__,
+			wcd_resmgr_clk_type_to_str(type));
+		ret = -EINVAL;
+		break;
+	};
+
+	if (ret)
+		pr_err("%s: Disable clock %s failed\n", __func__,
+			wcd_resmgr_clk_type_to_str(type));
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd_resmgr_disable_clk_block);
+
+/*
+ * wcd_resmgr_init: initialize wcd resource manager
+ * @core_res: handle to struct wcd9xxx_core_resource
+ *
+ * Early init call without a handle to snd_soc_codec *
+ */
+struct wcd9xxx_resmgr_v2 *wcd_resmgr_init(
+		struct wcd9xxx_core_resource *core_res,
+		struct snd_soc_codec *codec)
+{
+	struct wcd9xxx_resmgr_v2 *resmgr;
+	struct wcd9xxx *wcd9xxx;
+
+	resmgr = kzalloc(sizeof(struct wcd9xxx_resmgr_v2), GFP_KERNEL);
+	if (!resmgr)
+		return ERR_PTR(-ENOMEM);
+
+	wcd9xxx = container_of(core_res, struct wcd9xxx, core_res);
+	if (!wcd9xxx) {
+		kfree(resmgr);
+		pr_err("%s: Cannot get wcd9xx pointer\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	mutex_init(&resmgr->codec_bg_clk_lock);
+	mutex_init(&resmgr->master_bias_lock);
+	resmgr->master_bias_users = 0;
+	resmgr->clk_mclk_users = 0;
+	resmgr->clk_rco_users = 0;
+	resmgr->master_bias_users = 0;
+	resmgr->codec = codec;
+	resmgr->core_res = core_res;
+	resmgr->sido_input_src = SIDO_SOURCE_INTERNAL;
+	resmgr->codec_type = wcd9xxx->type;
+
+	return resmgr;
+}
+EXPORT_SYMBOL(wcd_resmgr_init);
+
+/*
+ * wcd_resmgr_remove: Clean-up wcd resource manager
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ */
+void wcd_resmgr_remove(struct wcd9xxx_resmgr_v2 *resmgr)
+{
+	mutex_destroy(&resmgr->master_bias_lock);
+	kfree(resmgr);
+}
+EXPORT_SYMBOL(wcd_resmgr_remove);
+
+/*
+ * wcd_resmgr_post_init: post init call to assign codec handle
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2 created during early init
+ * @resmgr_cb: codec callback function for resmgr
+ * @codec: handle to struct snd_soc_codec
+ */
+int wcd_resmgr_post_init(struct wcd9xxx_resmgr_v2 *resmgr,
+			 const struct wcd_resmgr_cb *resmgr_cb,
+			 struct snd_soc_codec *codec)
+{
+	if (!resmgr) {
+		pr_err("%s: resmgr not allocated\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!codec) {
+		pr_err("%s: Codec memory is NULL, nothing to post init\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	resmgr->codec = codec;
+	resmgr->resmgr_cb = resmgr_cb;
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd_resmgr_post_init);
+
+MODULE_DESCRIPTION("wcd9xxx resmgr v2 module");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd9xxx-resmgr-v2.h b/asoc/codecs/wcd9xxx-resmgr-v2.h
new file mode 100644
index 0000000..e9d3531
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-resmgr-v2.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD9XXX_COMMON_V2_H__
+#define __WCD9XXX_COMMON_V2_H__
+
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "core.h"
+
+enum wcd_clock_type {
+	WCD_CLK_OFF,
+	WCD_CLK_RCO,
+	WCD_CLK_MCLK,
+};
+
+enum {
+	SIDO_SOURCE_INTERNAL,
+	SIDO_SOURCE_RCO_BG,
+};
+
+struct wcd_resmgr_cb {
+	int (*cdc_rco_ctrl)(struct snd_soc_codec *, bool);
+};
+
+struct wcd9xxx_resmgr_v2 {
+	struct snd_soc_codec *codec;
+	struct wcd9xxx_core_resource *core_res;
+
+	int master_bias_users;
+	int clk_mclk_users;
+	int clk_rco_users;
+
+	struct mutex codec_bg_clk_lock;
+	struct mutex master_bias_lock;
+
+	enum codec_variant codec_type;
+	enum wcd_clock_type clk_type;
+
+	const struct wcd_resmgr_cb *resmgr_cb;
+	int sido_input_src;
+};
+
+#define WCD9XXX_V2_BG_CLK_LOCK(resmgr)			\
+{							\
+	struct wcd9xxx_resmgr_v2 *__resmgr = resmgr;	\
+	pr_debug("%s: Acquiring BG_CLK\n", __func__);	\
+	mutex_lock(&__resmgr->codec_bg_clk_lock);	\
+	pr_debug("%s: Acquiring BG_CLK done\n", __func__);	\
+}
+
+#define WCD9XXX_V2_BG_CLK_UNLOCK(resmgr)			\
+{							\
+	struct wcd9xxx_resmgr_v2 *__resmgr = resmgr;	\
+	pr_debug("%s: Releasing BG_CLK\n", __func__);	\
+	mutex_unlock(&__resmgr->codec_bg_clk_lock);	\
+}
+
+#define WCD9XXX_V2_BG_CLK_ASSERT_LOCKED(resmgr)		\
+{							\
+	WARN_ONCE(!mutex_is_locked(&resmgr->codec_bg_clk_lock), \
+		  "%s: BG_CLK lock should have acquired\n", __func__); \
+}
+
+int wcd_resmgr_enable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr);
+int wcd_resmgr_disable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr);
+struct wcd9xxx_resmgr_v2 *wcd_resmgr_init(
+		struct wcd9xxx_core_resource *core_res,
+		struct snd_soc_codec *codec);
+void wcd_resmgr_remove(struct wcd9xxx_resmgr_v2 *resmgr);
+int wcd_resmgr_post_init(struct wcd9xxx_resmgr_v2 *resmgr,
+			 const struct wcd_resmgr_cb *resmgr_cb,
+			 struct snd_soc_codec *codec);
+int wcd_resmgr_enable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr,
+				enum wcd_clock_type type);
+int wcd_resmgr_disable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr,
+				enum wcd_clock_type type);
+int wcd_resmgr_get_clk_type(struct wcd9xxx_resmgr_v2 *resmgr);
+void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr);
+void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr,
+					  int sido_src);
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+					  int sido_src);
+
+#endif
diff --git a/asoc/codecs/wcd9xxx-rst.c b/asoc/codecs/wcd9xxx-rst.c
new file mode 100644
index 0000000..3df95d5
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-rst.c
@@ -0,0 +1,443 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "core.h"
+#include "pdata.h"
+#include "wcd9xxx-utils.h"
+#include "wcd9335_registers.h"
+#include "wcd9335_irq.h"
+#include <asoc/wcd934x_registers.h>
+#include "wcd934x/wcd934x_irq.h"
+
+/* wcd9335 interrupt table  */
+static const struct intr_data wcd9335_intr_table[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD9335_IRQ_MBHC_SW_DET, true},
+	{WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true},
+	{WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true},
+	{WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true},
+	{WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
+	{WCD9335_IRQ_FLL_LOCK_LOSS, false},
+	{WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false},
+	{WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false},
+	{WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false},
+	{WCD9335_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD9335_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD9335_IRQ_EAR_PA_OCP_FAULT, false},
+	{WCD9335_IRQ_SOUNDWIRE, false},
+	{WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false},
+	{WCD9335_IRQ_RCO_ERROR, false},
+	{WCD9335_IRQ_SVA_ERROR, false},
+	{WCD9335_IRQ_MAD_AUDIO, false},
+	{WCD9335_IRQ_MAD_BEACON, false},
+	{WCD9335_IRQ_SVA_OUTBOX1, true},
+	{WCD9335_IRQ_SVA_OUTBOX2, true},
+	{WCD9335_IRQ_MAD_ULTRASOUND, false},
+	{WCD9335_IRQ_VBAT_ATTACK, false},
+	{WCD9335_IRQ_VBAT_RESTORE, false},
+};
+
+static const struct intr_data wcd934x_intr_table[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD934X_IRQ_MBHC_SW_DET, true},
+	{WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, true},
+	{WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, true},
+	{WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, true},
+	{WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
+	{WCD934X_IRQ_MISC, false},
+	{WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, false},
+	{WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, false},
+	{WCD934X_IRQ_EAR_PA_CNP_COMPLETE, false},
+	{WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, false},
+	{WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, false},
+	{WCD934X_IRQ_SLNQ_ANALOG_ERROR, false},
+	{WCD934X_IRQ_RESERVED_3, false},
+	{WCD934X_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD934X_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD934X_IRQ_EAR_PA_OCP_FAULT, false},
+	{WCD934X_IRQ_SOUNDWIRE, false},
+	{WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, false},
+	{WCD934X_IRQ_RCO_ERROR, false},
+	{WCD934X_IRQ_CPE_ERROR, false},
+	{WCD934X_IRQ_MAD_AUDIO, false},
+	{WCD934X_IRQ_MAD_BEACON, false},
+	{WCD934X_IRQ_CPE1_INTR, true},
+	{WCD934X_IRQ_RESERVED_4, false},
+	{WCD934X_IRQ_MAD_ULTRASOUND, false},
+	{WCD934X_IRQ_VBAT_ATTACK, false},
+	{WCD934X_IRQ_VBAT_RESTORE, false},
+};
+
+/*
+ * wcd9335_bring_down: Bringdown WCD Codec
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd9335_bring_down(struct wcd9xxx *wcd9xxx)
+{
+	if (!wcd9xxx || !wcd9xxx->regmap)
+		return -EINVAL;
+
+	regmap_write(wcd9xxx->regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+		     0x04);
+
+	return 0;
+}
+
+/*
+ * wcd9335_bring_up: Bringup WCD Codec
+ *
+ * @wcd9xxx: Pointer to the wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd9335_bring_up(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0;
+	int val, byte0;
+	struct regmap *wcd_regmap;
+
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+			__func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val);
+	regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0);
+
+	if ((val < 0) || (byte0 < 0)) {
+		dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n",
+			__func__);
+		return -EINVAL;
+	}
+	if ((val & 0x80) && (byte0 == 0x0)) {
+		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n",
+			 __func__);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x5);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x7);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x3);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+	} else if (byte0 == 0x1) {
+		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n",
+			 __func__);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
+		regmap_write(wcd_regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x5);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x7);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x3);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+	} else if ((byte0 == 0) && (!(val & 0x80))) {
+		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n",
+			 __func__);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x3);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+	} else {
+		dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n",
+			__func__);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * wcd9335_get_cdc_info: Get codec specific information
+ *
+ * @wcd9xxx: pointer to wcd9xxx structure
+ * @wcd_type: pointer to wcd9xxx_codec_type structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd9335_get_cdc_info(struct wcd9xxx *wcd9xxx,
+			   struct wcd9xxx_codec_type *wcd_type)
+{
+	u16 id_minor, id_major;
+	struct regmap *wcd_regmap;
+	int rc, val, version = 0;
+
+	if (!wcd9xxx || !wcd_type)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+			__func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+			(u8 *)&id_minor, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
+			      (u8 *)&id_major, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+		 __func__, id_major, id_minor);
+
+	/* Version detection */
+	if (id_major == TASHA_MAJOR) {
+		regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,
+			    &val);
+		version = ((u8)val & 0x80) >> 7;
+	} else if (id_major == TASHA2P0_MAJOR)
+		version = 2;
+	else
+		dev_err(wcd9xxx->dev, "%s: wcd9335 version unknown (major 0x%x, minor 0x%x)\n",
+			__func__, id_major, id_minor);
+
+	/* Fill codec type info */
+	wcd_type->id_major = id_major;
+	wcd_type->id_minor = id_minor;
+	wcd_type->num_irqs = WCD9335_NUM_IRQS;
+	wcd_type->version = version;
+	wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
+	wcd_type->i2c_chip_status = 0x01;
+	wcd_type->intr_tbl = wcd9335_intr_table;
+	wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9335_intr_table);
+
+	wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
+						WCD9335_INTR_PIN1_STATUS0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
+						WCD9335_INTR_PIN1_CLEAR0;
+	wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
+						WCD9335_INTR_PIN1_MASK0;
+	wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
+						WCD9335_INTR_LEVEL0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
+						WCD9335_INTR_CLR_COMMIT;
+
+	return rc;
+}
+
+/*
+ * wcd934x_bring_down: Bringdown WCD Codec
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd934x_bring_down(struct wcd9xxx *wcd9xxx)
+{
+	if (!wcd9xxx || !wcd9xxx->regmap)
+		return -EINVAL;
+
+	regmap_write(wcd9xxx->regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+		     0x04);
+
+	return 0;
+}
+
+/*
+ * wcd934x_bring_up: Bringup WCD Codec
+ *
+ * @wcd9xxx: Pointer to the wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd934x_bring_up(struct wcd9xxx *wcd9xxx)
+{
+	struct regmap *wcd_regmap;
+
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+			__func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
+	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
+	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
+	/* Add 1msec delay for VOUT to settle */
+	usleep_range(1000, 1100);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+
+	return 0;
+}
+
+/*
+ * wcd934x_get_cdc_info: Get codec specific information
+ *
+ * @wcd9xxx: pointer to wcd9xxx structure
+ * @wcd_type: pointer to wcd9xxx_codec_type structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd934x_get_cdc_info(struct wcd9xxx *wcd9xxx,
+			   struct wcd9xxx_codec_type *wcd_type)
+{
+	u16 id_minor, id_major;
+	struct regmap *wcd_regmap;
+	int rc, version = -1;
+
+	if (!wcd9xxx || !wcd_type)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null\n", __func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+			      (u8 *)&id_minor, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
+			      (u8 *)&id_major, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+		 __func__, id_major, id_minor);
+
+	if (id_major != TAVIL_MAJOR)
+		goto version_unknown;
+
+	/*
+	 * As fine version info cannot be retrieved before tavil probe.
+	 * Assign coarse versions for possible future use before tavil probe.
+	 */
+	if (id_minor == cpu_to_le16(0))
+		version = TAVIL_VERSION_1_0;
+	else if (id_minor == cpu_to_le16(0x01))
+		version = TAVIL_VERSION_1_1;
+
+version_unknown:
+	if (version < 0)
+		dev_err(wcd9xxx->dev, "%s: wcd934x version unknown\n",
+			__func__);
+
+	/* Fill codec type info */
+	wcd_type->id_major = id_major;
+	wcd_type->id_minor = id_minor;
+	wcd_type->num_irqs = WCD934X_NUM_IRQS;
+	wcd_type->version = version;
+	wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
+	wcd_type->i2c_chip_status = 0x01;
+	wcd_type->intr_tbl = wcd934x_intr_table;
+	wcd_type->intr_tbl_size = ARRAY_SIZE(wcd934x_intr_table);
+
+	wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
+						WCD934X_INTR_PIN1_STATUS0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
+						WCD934X_INTR_PIN1_CLEAR0;
+	wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
+						WCD934X_INTR_PIN1_MASK0;
+	wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
+						WCD934X_INTR_LEVEL0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
+						WCD934X_INTR_CLR_COMMIT;
+
+	return rc;
+}
+
+codec_bringdown_fn wcd9xxx_bringdown_fn(int type)
+{
+	codec_bringdown_fn cdc_bdown_fn;
+
+	switch (type) {
+	case WCD934X:
+		cdc_bdown_fn = wcd934x_bring_down;
+		break;
+	case WCD9335:
+		cdc_bdown_fn = wcd9335_bring_down;
+		break;
+	default:
+		cdc_bdown_fn = NULL;
+		break;
+	}
+
+	return cdc_bdown_fn;
+}
+
+codec_bringup_fn wcd9xxx_bringup_fn(int type)
+{
+	codec_bringup_fn cdc_bup_fn;
+
+	switch (type) {
+	case WCD934X:
+		cdc_bup_fn = wcd934x_bring_up;
+		break;
+	case WCD9335:
+		cdc_bup_fn = wcd9335_bring_up;
+		break;
+	default:
+		cdc_bup_fn = NULL;
+		break;
+	}
+
+	return cdc_bup_fn;
+}
+
+codec_type_fn wcd9xxx_get_codec_info_fn(int type)
+{
+	codec_type_fn cdc_type_fn;
+
+	switch (type) {
+	case WCD934X:
+		cdc_type_fn = wcd934x_get_cdc_info;
+		break;
+	case WCD9335:
+		cdc_type_fn = wcd9335_get_cdc_info;
+		break;
+	default:
+		cdc_type_fn = NULL;
+		break;
+	}
+
+	return cdc_type_fn;
+}
+
diff --git a/asoc/codecs/wcd9xxx-slimslave.c b/asoc/codecs/wcd9xxx-slimslave.c
new file mode 100644
index 0000000..66a8332
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-slimslave.c
@@ -0,0 +1,584 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "wcd9xxx-slimslave.h"
+
+struct wcd9xxx_slim_sch {
+	u16 rx_port_ch_reg_base;
+	u16 port_tx_cfg_reg_base;
+	u16 port_rx_cfg_reg_base;
+};
+
+static struct wcd9xxx_slim_sch sh_ch;
+
+static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx,
+				    u8 wcd9xxx_pgd_la, u32 cnt,
+				    struct wcd9xxx_ch *channels, u32 path);
+
+static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
+				      u32 cnt, struct wcd9xxx_ch *channels);
+
+static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
+{
+	if (wcd9xxx->codec_type->slim_slave_type ==
+	    WCD9XXX_SLIM_SLAVE_ADDR_TYPE_0) {
+		sh_ch.rx_port_ch_reg_base = 0x180;
+		sh_ch.port_rx_cfg_reg_base = 0x040;
+		sh_ch.port_tx_cfg_reg_base = 0x040;
+	} else {
+		sh_ch.rx_port_ch_reg_base =
+			0x180 - (TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
+		sh_ch.port_rx_cfg_reg_base =
+			0x040 - TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.port_tx_cfg_reg_base = 0x050;
+	}
+
+	return 0;
+}
+
+/**
+ * wcd9xxx_init_slimslave
+ *
+ * @wcd9xxx: pointer to wcd9xxx struct
+ * @wcd9xxx_pgd_la: pgd_la value
+ * @tx_num: tx number
+ * @rx_num: rx number
+ * @tx_slot: pointer to tx slot
+ * @rx_slot: pointer to rx slot
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la,
+			   unsigned int tx_num, unsigned int *tx_slot,
+			   unsigned int rx_num, unsigned int *rx_slot)
+{
+	int ret = 0;
+	int i;
+
+	ret = wcd9xxx_configure_ports(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Failed to configure register address offset\n",
+		       __func__);
+		goto err;
+	}
+
+	if (!rx_num || rx_num > wcd9xxx->num_rx_port) {
+		pr_err("%s: invalid rx num %d\n", __func__, rx_num);
+		return -EINVAL;
+	}
+	if (wcd9xxx->rx_chs) {
+		wcd9xxx->num_rx_port = rx_num;
+		for (i = 0; i < rx_num; i++) {
+			wcd9xxx->rx_chs[i].ch_num = rx_slot[i];
+			INIT_LIST_HEAD(&wcd9xxx->rx_chs[i].list);
+		}
+		ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
+						wcd9xxx->num_rx_port,
+						wcd9xxx->rx_chs,
+						SLIM_SINK);
+		if (ret) {
+			pr_err("%s: Failed to alloc %d rx slimbus channels\n",
+				__func__, wcd9xxx->num_rx_port);
+			kfree(wcd9xxx->rx_chs);
+			wcd9xxx->rx_chs = NULL;
+			wcd9xxx->num_rx_port = 0;
+		}
+	} else {
+		pr_err("Not able to allocate memory for %d slimbus rx ports\n",
+			wcd9xxx->num_rx_port);
+	}
+
+	if (!tx_num || tx_num > wcd9xxx->num_tx_port) {
+		pr_err("%s: invalid tx num %d\n", __func__, tx_num);
+		return -EINVAL;
+	}
+	if (wcd9xxx->tx_chs) {
+		wcd9xxx->num_tx_port = tx_num;
+		for (i = 0; i < tx_num; i++) {
+			wcd9xxx->tx_chs[i].ch_num = tx_slot[i];
+			INIT_LIST_HEAD(&wcd9xxx->tx_chs[i].list);
+		}
+		ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
+						wcd9xxx->num_tx_port,
+						wcd9xxx->tx_chs,
+						SLIM_SRC);
+		if (ret) {
+			pr_err("%s: Failed to alloc %d tx slimbus channels\n",
+				__func__, wcd9xxx->num_tx_port);
+			kfree(wcd9xxx->tx_chs);
+			wcd9xxx->tx_chs = NULL;
+			wcd9xxx->num_tx_port = 0;
+		}
+	} else {
+		pr_err("Not able to allocate memory for %d slimbus tx ports\n",
+			wcd9xxx->num_tx_port);
+	}
+	return 0;
+err:
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_init_slimslave);
+
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
+{
+	if (wcd9xxx->num_rx_port) {
+		wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
+					wcd9xxx->num_rx_port,
+					wcd9xxx->rx_chs);
+		wcd9xxx->num_rx_port = 0;
+	}
+	if (wcd9xxx->num_tx_port) {
+		wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
+					wcd9xxx->num_tx_port,
+					wcd9xxx->tx_chs);
+		wcd9xxx->num_tx_port = 0;
+	}
+	return 0;
+}
+
+
+static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx,
+				    u8 wcd9xxx_pgd_la, u32 cnt,
+				    struct wcd9xxx_ch *channels, u32 path)
+{
+	int ret = 0;
+	u32 ch_idx;
+
+	/* The slimbus channel allocation seem take longer time
+	 * so do the allocation up front to avoid delay in start of
+	 * playback
+	 */
+	pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
+	for (ch_idx = 0; ch_idx < cnt; ch_idx++) {
+		ret = slim_get_slaveport(wcd9xxx_pgd_la,
+					channels[ch_idx].port,
+					&channels[ch_idx].sph, path);
+		pr_debug("%s: pgd_la[%d] channels[%d].port[%d]\n"
+			"channels[%d].sph[%d] path[%d]\n",
+			__func__, wcd9xxx_pgd_la, ch_idx,
+			channels[ch_idx].port,
+			ch_idx, channels[ch_idx].sph, path);
+		if (ret < 0) {
+			pr_err("%s: slave port failure id[%d] ret[%d]\n",
+				__func__, channels[ch_idx].ch_num, ret);
+			goto err;
+		}
+
+		ret = slim_query_ch(wcd9xxx->slim,
+				    channels[ch_idx].ch_num,
+				    &channels[ch_idx].ch_h);
+		if (ret < 0) {
+			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
+				__func__, channels[ch_idx].ch_num, ret);
+			goto err;
+		}
+	}
+err:
+	return ret;
+}
+
+static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
+			u32 cnt, struct wcd9xxx_ch *channels)
+{
+	int idx = 0;
+	int ret = 0;
+	/* slim_dealloc_ch */
+	for (idx = 0; idx < cnt; idx++) {
+		ret = slim_dealloc_ch(slim, channels[idx].ch_h);
+		if (ret < 0) {
+			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
+				__func__, ret, channels[idx].ch_h);
+		}
+	}
+	return ret;
+}
+
+/* Enable slimbus slave device for RX path */
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+			    struct list_head *wcd9xxx_ch_list,
+			    unsigned int rate, unsigned int bit_width,
+			    u16 *grph)
+{
+	u8 ch_cnt = 0;
+	u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
+	u8  payload = 0;
+	u16 codec_port = 0;
+	int ret;
+	struct slim_ch prop;
+	struct wcd9xxx_ch *rx;
+	int size = ARRAY_SIZE(ch_h);
+
+	/* Configure slave interface device */
+
+	list_for_each_entry(rx, wcd9xxx_ch_list, list) {
+		payload |= 1 << rx->shift;
+		if (ch_cnt < size) {
+			ch_h[ch_cnt] = rx->ch_h;
+			ch_cnt++;
+			pr_debug("list ch->ch_h %d ch->sph %d\n",
+				 rx->ch_h, rx->sph);
+		} else {
+			pr_err("%s: allocated channel number %u is out of max rangae %d\n",
+			       __func__, ch_cnt,
+			       size);
+			ret = EINVAL;
+			goto err;
+		}
+	}
+	pr_debug("%s: ch_cnt[%d] rate=%d WATER_MARK_VAL %d\n",
+		 __func__, ch_cnt, rate, WATER_MARK_VAL);
+	/* slim_define_ch api */
+	prop.prot = SLIM_AUTO_ISO;
+	if ((rate == 44100) || (rate == 88200) || (rate == 176400) ||
+	    (rate == 352800)) {
+		prop.baser = SLIM_RATE_11025HZ;
+		prop.ratem = (rate/11025);
+	} else {
+		prop.baser = SLIM_RATE_4000HZ;
+		prop.ratem = (rate/4000);
+	}
+	prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
+	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
+	prop.sampleszbits = bit_width;
+
+	pr_debug("Before slim_define_ch:\n"
+		 "ch_cnt %d,ch_h[0] %d ch_h[1] %d, grph %d\n",
+		 ch_cnt, ch_h[0], ch_h[1], *grph);
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
+			     true, grph);
+	if (ret < 0) {
+		pr_err("%s: slim_define_ch failed ret[%d]\n",
+		       __func__, ret);
+		goto err;
+	}
+
+	list_for_each_entry(rx, wcd9xxx_ch_list, list) {
+		codec_port = rx->port;
+		pr_debug("%s: codec_port %d rx 0x%p, payload %d\n"
+			 "sh_ch.rx_port_ch_reg_base0 0x%x\n"
+			 "sh_ch.port_rx_cfg_reg_base 0x%x\n",
+			 __func__, codec_port, rx, payload,
+			 sh_ch.rx_port_ch_reg_base,
+			sh_ch.port_rx_cfg_reg_base);
+
+		/* look for the valid port range and chose the
+		 * payload accordingly
+		 */
+		/* write to interface device */
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+				sh_ch.rx_port_ch_reg_base, codec_port),
+				payload);
+
+		if (ret < 0) {
+			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+				__func__,
+				SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+				sh_ch.rx_port_ch_reg_base, codec_port),
+				payload, ret);
+			goto err;
+		}
+		/* configure the slave port for water mark and enable*/
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				SB_PGD_PORT_CFG_BYTE_ADDR(
+				sh_ch.port_rx_cfg_reg_base, codec_port),
+				WATER_MARK_VAL);
+		if (ret < 0) {
+			pr_err("%s:watermark set failure for port[%d] ret[%d]",
+				__func__, codec_port, ret);
+		}
+
+		ret = slim_connect_sink(wcd9xxx->slim, &rx->sph, 1, rx->ch_h);
+		if (ret < 0) {
+			pr_err("%s: slim_connect_sink failed ret[%d]\n",
+				__func__, ret);
+			goto err_close_slim_sch;
+		}
+	}
+	/* slim_control_ch */
+	ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
+			      true);
+	if (ret < 0) {
+		pr_err("%s: slim_control_ch failed ret[%d]\n",
+			__func__, ret);
+		goto err_close_slim_sch;
+	}
+	return 0;
+
+err_close_slim_sch:
+	/*  release all acquired handles */
+	wcd9xxx_close_slim_sch_rx(wcd9xxx, wcd9xxx_ch_list, *grph);
+err:
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_cfg_slim_sch_rx);
+
+/* Enable slimbus slave device for RX path */
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+			    struct list_head *wcd9xxx_ch_list,
+			    unsigned int rate, unsigned int bit_width,
+			    u16 *grph)
+{
+	u16 ch_cnt = 0;
+	u16 payload = 0;
+	u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
+	u16 codec_port;
+	int ret = 0;
+	struct wcd9xxx_ch *tx;
+	int size = ARRAY_SIZE(ch_h);
+
+	struct slim_ch prop;
+
+	list_for_each_entry(tx, wcd9xxx_ch_list, list) {
+		payload |= 1 << tx->shift;
+		if (ch_cnt < size) {
+			ch_h[ch_cnt] = tx->ch_h;
+			ch_cnt++;
+		} else {
+			pr_err("%s: allocated channel number %u is out of max rangae %d\n",
+			       __func__, ch_cnt,
+			       size);
+			ret = EINVAL;
+			goto err;
+		}
+	}
+
+	/* slim_define_ch api */
+	prop.prot = SLIM_AUTO_ISO;
+	prop.baser = SLIM_RATE_4000HZ;
+	prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
+	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
+	prop.ratem = (rate/4000);
+	prop.sampleszbits = bit_width;
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
+			     true, grph);
+	if (ret < 0) {
+		pr_err("%s: slim_define_ch failed ret[%d]\n",
+		       __func__, ret);
+		goto err;
+	}
+
+	pr_debug("%s: ch_cnt[%d] rate[%d] bitwidth[%u]\n", __func__, ch_cnt,
+		 rate, bit_width);
+	list_for_each_entry(tx, wcd9xxx_ch_list, list) {
+		codec_port = tx->port;
+		pr_debug("%s: codec_port %d tx 0x%p, payload 0x%x\n",
+			 __func__, codec_port, tx, payload);
+		/* write to interface device */
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
+				payload & 0x00FF);
+		if (ret < 0) {
+			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+				__func__,
+				SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
+				payload, ret);
+			goto err;
+		}
+		/* ports 8,9 */
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
+				(payload & 0xFF00)>>8);
+		if (ret < 0) {
+			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+				__func__,
+				SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
+				payload, ret);
+			goto err;
+		}
+		/* configure the slave port for water mark and enable*/
+		ret = wcd9xxx_interface_reg_write(wcd9xxx,
+				SB_PGD_PORT_CFG_BYTE_ADDR(
+				sh_ch.port_tx_cfg_reg_base, codec_port),
+				WATER_MARK_VAL);
+		if (ret < 0) {
+			pr_err("%s:watermark set failure for port[%d] ret[%d]",
+				__func__, codec_port, ret);
+		}
+
+		ret = slim_connect_src(wcd9xxx->slim, tx->sph, tx->ch_h);
+
+		if (ret < 0) {
+			pr_err("%s: slim_connect_src failed ret[%d]\n",
+			       __func__, ret);
+			goto err;
+		}
+	}
+	/* slim_control_ch */
+	ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
+			      true);
+	if (ret < 0) {
+		pr_err("%s: slim_control_ch failed ret[%d]\n",
+			__func__, ret);
+		goto err;
+	}
+	return 0;
+err:
+	/* release all acquired handles */
+	wcd9xxx_close_slim_sch_tx(wcd9xxx, wcd9xxx_ch_list, *grph);
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_cfg_slim_sch_tx);
+
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+			      struct list_head *wcd9xxx_ch_list, u16 grph)
+{
+	u32 sph[SLIM_MAX_RX_PORTS] = {0};
+	int ch_cnt = 0;
+	int ret = 0;
+	struct wcd9xxx_ch *rx;
+
+	list_for_each_entry(rx, wcd9xxx_ch_list, list)
+		sph[ch_cnt++] = rx->sph;
+
+	pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n", __func__, ch_cnt,
+		sph[0], sph[1]);
+
+	/* slim_control_ch (REMOVE) */
+	pr_debug("%s before slim_control_ch grph %d\n", __func__, grph);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
+	if (ret < 0) {
+		pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
+		goto err;
+	}
+err:
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_close_slim_sch_rx);
+
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+			      struct list_head *wcd9xxx_ch_list,
+			      u16 grph)
+{
+	u32 sph[SLIM_MAX_TX_PORTS] = {0};
+	int ret = 0;
+	int ch_cnt = 0;
+	struct wcd9xxx_ch *tx;
+
+	pr_debug("%s\n", __func__);
+	list_for_each_entry(tx, wcd9xxx_ch_list, list)
+		sph[ch_cnt++] = tx->sph;
+
+	pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n",
+		__func__, ch_cnt, sph[0], sph[1]);
+	/* slim_control_ch (REMOVE) */
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
+	if (ret < 0) {
+		pr_err("%s: slim_control_ch failed ret[%d]\n",
+			__func__, ret);
+		goto err;
+	}
+err:
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_close_slim_sch_tx);
+
+int wcd9xxx_get_slave_port(unsigned int ch_num)
+{
+	int ret = 0;
+
+	ret = (ch_num - BASE_CH_NUM);
+	pr_debug("%s: ch_num[%d] slave port[%d]\n", __func__, ch_num, ret);
+	if (ret < 0) {
+		pr_err("%s: Error:- Invalid slave port found = %d\n",
+			__func__, ret);
+		return -EINVAL;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_get_slave_port);
+
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx,
+			    struct list_head *wcd9xxx_ch_list, u16 grph)
+{
+	u32 sph[SLIM_MAX_TX_PORTS + SLIM_MAX_RX_PORTS] = {0};
+	int ch_cnt = 0;
+	int ret = 0;
+	struct wcd9xxx_ch *slim_ch;
+
+	list_for_each_entry(slim_ch, wcd9xxx_ch_list, list)
+		sph[ch_cnt++] = slim_ch->sph;
+
+	/* slim_disconnect_port */
+	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
+	if (ret < 0) {
+		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
+			__func__, ret);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_disconnect_port);
+
+/* This function is called with mutex acquired */
+int wcd9xxx_rx_vport_validation(u32 port_id,
+				struct list_head *codec_dai_list)
+{
+	struct wcd9xxx_ch *ch;
+	int ret = 0;
+
+	pr_debug("%s: port_id %u\n", __func__, port_id);
+
+	list_for_each_entry(ch,
+		codec_dai_list, list) {
+		pr_debug("%s: ch->port %u\n", __func__, ch->port);
+		if (ch->port == port_id) {
+			ret = -EINVAL;
+			break;
+		}
+	}
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_rx_vport_validation);
+
+
+/* This function is called with mutex acquired */
+int wcd9xxx_tx_vport_validation(u32 table, u32 port_id,
+				struct wcd9xxx_codec_dai_data *codec_dai,
+				u32 num_codec_dais)
+{
+	struct wcd9xxx_ch *ch;
+	int ret = 0;
+	u32 index;
+	unsigned long vtable = table;
+	u32 size = sizeof(table) * BITS_PER_BYTE;
+
+	pr_debug("%s: vtable 0x%lx port_id %u size %d\n", __func__,
+		 vtable, port_id, size);
+	for_each_set_bit(index, &vtable, size) {
+		if (index < num_codec_dais) {
+			list_for_each_entry(ch,
+					&codec_dai[index].wcd9xxx_ch_list,
+					list) {
+				pr_debug("%s: index %u ch->port %u vtable 0x%lx\n",
+						__func__, index, ch->port,
+						vtable);
+				if (ch->port == port_id) {
+					pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
+							__func__, port_id + 1,
+							(index + 1)/2);
+					ret = -EINVAL;
+					break;
+				}
+			}
+		} else {
+			pr_err("%s: Invalid index %d of codec dai",
+					__func__, index);
+			ret = -EINVAL;
+		}
+		if (ret)
+			break;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_tx_vport_validation);
diff --git a/asoc/codecs/wcd9xxx-slimslave.h b/asoc/codecs/wcd9xxx-slimslave.h
new file mode 100644
index 0000000..5132e43
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-slimslave.h
@@ -0,0 +1,119 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD9XXX_SLIMSLAVE_H_
+#define __WCD9XXX_SLIMSLAVE_H_
+
+#include <linux/slimbus/slimbus.h>
+#include "core.h"
+
+
+/*
+ *  client is expected to give port ids in the range of
+ *  1-10 for pre Taiko Tx ports and 1-16 for Taiko
+ *  1-7 for pre Taiko Rx ports and 1-16 for Tako,
+ *  we need to add offset for getting the absolute slave
+ *  port id before configuring the HW
+ */
+#define TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 10
+#define TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 16
+
+#define SLIM_MAX_TX_PORTS TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS \
+	TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+#define TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS \
+	TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 7
+#define TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 13
+
+#define SLIM_MAX_RX_PORTS TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS
+
+#define SLIM_MAX_REG_ADDR (0x180 + 4 * (SLIM_MAX_RX_PORTS))
+
+#define TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID \
+	TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS
+#define TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID \
+	TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID 16
+#define TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID 31
+
+#define TABLA_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID 9
+#define TAIKO_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID 15
+
+/* below details are taken from SLIMBUS slave SWI */
+#define SB_PGD_PORT_BASE 0x000
+
+#define SB_PGD_PORT_CFG_BYTE_ADDR(offset, port_num) \
+		(SB_PGD_PORT_BASE + offset + (1 * port_num))
+
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0(port_num) \
+		(SB_PGD_PORT_BASE + 0x100 + 4*port_num)
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0_START_PORT_ID   0
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID     7
+
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_1(port_num) \
+		(SB_PGD_PORT_BASE + 0x101 + 4*port_num)
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID   8
+
+#define SB_PGD_RX_PORT_MULTI_CHANNEL_0(offset, port_num) \
+		(SB_PGD_PORT_BASE + offset + (4 * port_num))
+
+/* slave port water mark level
+ *   (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes)
+ */
+#define SLAVE_PORT_WATER_MARK_6BYTES  0
+#define SLAVE_PORT_WATER_MARK_9BYTES  1
+#define SLAVE_PORT_WATER_MARK_12BYTES 2
+#define SLAVE_PORT_WATER_MARK_15BYTES 3
+#define SLAVE_PORT_WATER_MARK_SHIFT 1
+#define SLAVE_PORT_ENABLE           1
+#define SLAVE_PORT_DISABLE          0
+#define WATER_MARK_VAL \
+	((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \
+	 (SLAVE_PORT_ENABLE))
+#define BASE_CH_NUM 128
+
+
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx,
+			   u8 wcd9xxx_pgd_la,
+			   unsigned int tx_num, unsigned int *tx_slot,
+			   unsigned int rx_num, unsigned int *rx_slot);
+
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx);
+
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+			    struct list_head *wcd9xxx_ch_list,
+			    unsigned int rate, unsigned int bit_width,
+			    u16 *grph);
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+			    struct list_head *wcd9xxx_ch_list,
+			    unsigned int rate, unsigned int bit_width,
+				u16 *grph);
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+			      struct list_head *wcd9xxx_ch_list, u16 grph);
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+			      struct list_head *wcd9xxx_ch_list, u16 grph);
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
+			unsigned int *rx_ch,
+			unsigned int *tx_ch);
+int wcd9xxx_get_slave_port(unsigned int ch_num);
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx,
+			    struct list_head *wcd9xxx_ch_list, u16 grph);
+int wcd9xxx_rx_vport_validation(u32 port_id,
+				struct list_head *codec_dai_list);
+int wcd9xxx_tx_vport_validation(u32 vtable, u32 port_id,
+				struct wcd9xxx_codec_dai_data *codec_dai,
+				u32 num_codec_dais);
+#endif /* __WCD9XXX_SLIMSLAVE_H_ */
diff --git a/asoc/codecs/wcd9xxx-soc-init.c b/asoc/codecs/wcd9xxx-soc-init.c
new file mode 100644
index 0000000..fa8abb7
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-soc-init.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <sound/wcd-dsp-mgr.h>
+#include "audio-ext-clk-up.h"
+
+static int __init wcd9xxx_soc_init(void)
+{
+	int ret = 0;
+
+	ret = wcd_dsp_mgr_init();
+	if (!ret) {
+		ret = audio_ref_clk_platform_init();
+		if (ret) {
+			pr_err("%s: init extclk fail: %d\n", __func__, ret);
+			wcd_dsp_mgr_exit();
+		}
+	} else {
+		pr_err("%s: init dsp mgr fail: %d\n", __func__, ret);
+	}
+
+	return ret;
+}
+module_init(wcd9xxx_soc_init);
+
+static void __exit wcd9xxx_soc_exit(void)
+{
+	audio_ref_clk_platform_exit();
+	wcd_dsp_mgr_exit();
+}
+module_exit(wcd9xxx_soc_exit);
+
+MODULE_DESCRIPTION("WCD9XXX CODEC soc init driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd9xxx-utils.c b/asoc/codecs/wcd9xxx-utils.c
new file mode 100644
index 0000000..a1ea938
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-utils.c
@@ -0,0 +1,1198 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/mfd/core.h>
+#include "core.h"
+#include "msm-cdc-supply.h"
+#include "msm-cdc-pinctrl.h"
+#include "pdata.h"
+#include "wcd9xxx-irq.h"
+#include "wcd9xxx-utils.h"
+
+#define REG_BYTES 2
+#define VAL_BYTES 1
+/*
+ * Page Register Address that APP Proc uses to
+ * access WCD9335 Codec registers is identified
+ * as 0x00
+ */
+#define PAGE_REG_ADDR 0x00
+
+static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
+
+static struct mfd_cell tavil_devs[] = {
+	{
+		.name = "qcom-wcd-pinctrl",
+		.of_compatible = "qcom,wcd-pinctrl",
+	},
+	{
+		.name = "tavil_codec",
+	},
+};
+
+static struct mfd_cell tasha_devs[] = {
+	{
+		.name = "tasha_codec",
+	},
+};
+
+static struct mfd_cell tomtom_devs[] = {
+	{
+		.name = "tomtom_codec",
+	},
+};
+
+static int wcd9xxx_read_of_property_u32(struct device *dev, const char *name,
+					u32 *val)
+{
+	int rc = 0;
+
+	rc = of_property_read_u32(dev->of_node, name, val);
+	if (rc)
+		dev_err(dev, "%s: Looking up %s property in node %s failed",
+			__func__, name, dev->of_node->full_name);
+
+	return rc;
+}
+
+static void wcd9xxx_dt_parse_micbias_info(struct device *dev,
+					  struct wcd9xxx_micbias_setting *mb)
+{
+	u32 prop_val;
+	int rc;
+
+	if (of_find_property(dev->of_node, "qcom,cdc-micbias-ldoh-v", NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias-ldoh-v",
+						  &prop_val);
+		if (!rc)
+			mb->ldoh_v  =  (u8)prop_val;
+	}
+
+	/* MB1 */
+	if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt1-mv",
+			     NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias-cfilt1-mv",
+						   &prop_val);
+		if (!rc)
+			mb->cfilt1_mv = prop_val;
+
+		rc = wcd9xxx_read_of_property_u32(dev,
+						"qcom,cdc-micbias1-cfilt-sel",
+						&prop_val);
+		if (!rc)
+			mb->bias1_cfilt_sel = (u8)prop_val;
+
+	} else if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv",
+				    NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias1-mv",
+						  &prop_val);
+		if (!rc)
+			mb->micb1_mv = prop_val;
+	} else {
+		dev_info(dev, "%s: Micbias1 DT property not found\n",
+			__func__);
+	}
+
+	/* MB2 */
+	if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt2-mv",
+			     NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias-cfilt2-mv",
+						   &prop_val);
+		if (!rc)
+			mb->cfilt2_mv = prop_val;
+
+		rc = wcd9xxx_read_of_property_u32(dev,
+						"qcom,cdc-micbias2-cfilt-sel",
+						&prop_val);
+		if (!rc)
+			mb->bias2_cfilt_sel = (u8)prop_val;
+
+	} else if (of_find_property(dev->of_node, "qcom,cdc-micbias2-mv",
+				    NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias2-mv",
+						  &prop_val);
+		if (!rc)
+			mb->micb2_mv = prop_val;
+	} else {
+		dev_info(dev, "%s: Micbias2 DT property not found\n",
+			__func__);
+	}
+
+	/* MB3 */
+	if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt3-mv",
+			     NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias-cfilt3-mv",
+						   &prop_val);
+		if (!rc)
+			mb->cfilt3_mv = prop_val;
+
+		rc = wcd9xxx_read_of_property_u32(dev,
+						"qcom,cdc-micbias3-cfilt-sel",
+						&prop_val);
+		if (!rc)
+			mb->bias3_cfilt_sel = (u8)prop_val;
+
+	} else if (of_find_property(dev->of_node, "qcom,cdc-micbias3-mv",
+				    NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias3-mv",
+						  &prop_val);
+		if (!rc)
+			mb->micb3_mv = prop_val;
+	} else {
+		dev_info(dev, "%s: Micbias3 DT property not found\n",
+			__func__);
+	}
+
+	/* MB4 */
+	if (of_find_property(dev->of_node, "qcom,cdc-micbias4-cfilt-sel",
+			     NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						"qcom,cdc-micbias4-cfilt-sel",
+						&prop_val);
+		if (!rc)
+			mb->bias4_cfilt_sel = (u8)prop_val;
+
+	} else if (of_find_property(dev->of_node, "qcom,cdc-micbias4-mv",
+				    NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-micbias4-mv",
+						  &prop_val);
+		if (!rc)
+			mb->micb4_mv = prop_val;
+	} else {
+		dev_info(dev, "%s: Micbias4 DT property not found\n",
+			__func__);
+	}
+
+	mb->bias1_cap_mode =
+	   (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
+	 MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+	mb->bias2_cap_mode =
+	   (of_property_read_bool(dev->of_node, "qcom,cdc-micbias2-ext-cap") ?
+	    MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+	mb->bias3_cap_mode =
+	   (of_property_read_bool(dev->of_node, "qcom,cdc-micbias3-ext-cap") ?
+	    MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+	mb->bias4_cap_mode =
+	   (of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ?
+	    MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+
+	mb->bias2_is_headset_only =
+		of_property_read_bool(dev->of_node,
+				      "qcom,cdc-micbias2-headset-only");
+
+	/* Print micbias info */
+	dev_dbg(dev, "%s: ldoh_v  %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
+		__func__, (u32)mb->ldoh_v, (u32)mb->cfilt1_mv,
+		(u32)mb->cfilt2_mv, (u32)mb->cfilt3_mv);
+
+	dev_dbg(dev, "%s: micb1_mv %u micb2_mv %u micb3_mv %u micb4_mv %u",
+		__func__, mb->micb1_mv, mb->micb2_mv,
+		mb->micb3_mv, mb->micb4_mv);
+
+	dev_dbg(dev, "%s: bias1_cfilt_sel %u bias2_cfilt_sel %u\n",
+		__func__, (u32)mb->bias1_cfilt_sel, (u32)mb->bias2_cfilt_sel);
+
+	dev_dbg(dev, "%s: bias3_cfilt_sel %u bias4_cfilt_sel %u\n",
+		__func__, (u32)mb->bias3_cfilt_sel, (u32)mb->bias4_cfilt_sel);
+
+	dev_dbg(dev, "%s: bias1_ext_cap %d bias2_ext_cap %d\n",
+		__func__, mb->bias1_cap_mode, mb->bias2_cap_mode);
+
+	dev_dbg(dev, "%s: bias3_ext_cap %d bias4_ext_cap %d\n",
+		__func__, mb->bias3_cap_mode, mb->bias4_cap_mode);
+
+	dev_dbg(dev, "%s: bias2_is_headset_only %d\n",
+		__func__, mb->bias2_is_headset_only);
+}
+
+/*
+ * wcd9xxx_validate_dmic_sample_rate:
+ *	Given the dmic_sample_rate and mclk rate, validate the
+ *	dmic_sample_rate. If dmic rate is found to be invalid,
+ *	assign the dmic rate as undefined, so individual codec
+ *	drivers can use their own defaults
+ * @dev: the device for which the dmic is to be configured
+ * @dmic_sample_rate: The input dmic_sample_rate
+ * @mclk_rate: The input codec mclk rate
+ * @dmic_rate_type: String to indicate the type of dmic sample
+ *		    rate, used for debug/error logging.
+ */
+static u32 wcd9xxx_validate_dmic_sample_rate(struct device *dev,
+		u32 dmic_sample_rate, u32 mclk_rate,
+		const char *dmic_rate_type)
+{
+	u32 div_factor;
+
+	if (dmic_sample_rate == WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED ||
+	    mclk_rate % dmic_sample_rate != 0)
+		goto undefined_rate;
+
+	div_factor = mclk_rate / dmic_sample_rate;
+
+	switch (div_factor) {
+	case 2:
+	case 3:
+	case 4:
+	case 8:
+	case 16:
+		/* Valid dmic DIV factors */
+		dev_dbg(dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n",
+			__func__, div_factor, mclk_rate);
+		break;
+	case 6:
+		/*
+		 * DIV 6 is valid for both 9.6MHz and 12.288MHz
+		 * MCLK on Tavil. Older codecs support DIV6 only
+		 * for 12.288MHz MCLK.
+		 */
+		if ((mclk_rate == WCD9XXX_MCLK_CLK_9P6HZ) &&
+		    (of_device_is_compatible(dev->of_node,
+					     "qcom,tavil-slim-pgd")))
+			dev_dbg(dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n",
+				__func__, div_factor, mclk_rate);
+		else if (mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ)
+			goto undefined_rate;
+		break;
+	default:
+		/* Any other DIV factor is invalid */
+		goto undefined_rate;
+	}
+
+	return dmic_sample_rate;
+
+undefined_rate:
+	dev_dbg(dev, "%s: Invalid %s = %d, for mclk %d\n",
+		 __func__, dmic_rate_type, dmic_sample_rate, mclk_rate);
+	dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
+
+	return dmic_sample_rate;
+}
+
+/*
+ * wcd9xxx_populate_dt_data:
+ *	Parse device tree properties for the given codec device
+ *
+ * @dev: pointer to codec device
+ *
+ * Returns pointer to the platform data resulting from parsing
+ * device tree.
+ */
+struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev)
+{
+	struct wcd9xxx_pdata *pdata;
+	u32 dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
+	u32 mad_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
+	u32 ecpp_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
+	u32 dmic_clk_drive = WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED;
+	u32 prop_val;
+	int rc = 0;
+
+	if (!dev || !dev->of_node)
+		return NULL;
+
+	pdata = devm_kzalloc(dev, sizeof(struct wcd9xxx_pdata),
+			     GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	/* Parse power supplies */
+	msm_cdc_get_power_supplies(dev, &pdata->regulator,
+				   &pdata->num_supplies);
+	if (!pdata->regulator || (pdata->num_supplies <= 0)) {
+		dev_err(dev, "%s: no power supplies defined for codec\n",
+			__func__);
+		goto err_power_sup;
+	}
+
+	/* Parse micbias info */
+	wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias);
+
+	pdata->wcd_rst_np = of_parse_phandle(dev->of_node,
+					     "qcom,wcd-rst-gpio-node", 0);
+	if (!pdata->wcd_rst_np) {
+		dev_err(dev, "%s: Looking up %s property in node %s failed\n",
+			__func__, "qcom,wcd-rst-gpio-node",
+			dev->of_node->full_name);
+		goto err_parse_dt_prop;
+	}
+
+	if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-mclk-clk-rate",
+					   &prop_val)))
+		pdata->mclk_rate = prop_val;
+
+	if (pdata->mclk_rate != WCD9XXX_MCLK_CLK_9P6HZ &&
+	    pdata->mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) {
+		dev_err(dev, "%s: Invalid mclk_rate = %u\n", __func__,
+			pdata->mclk_rate);
+		goto err_parse_dt_prop;
+	}
+
+	if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-dmic-sample-rate",
+					   &prop_val)))
+		dmic_sample_rate = prop_val;
+
+	pdata->dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev,
+							dmic_sample_rate,
+							pdata->mclk_rate,
+							"audio_dmic_rate");
+	if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-mad-dmic-rate",
+					   &prop_val)))
+		mad_dmic_sample_rate = prop_val;
+
+	pdata->mad_dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev,
+							mad_dmic_sample_rate,
+							pdata->mclk_rate,
+							"mad_dmic_rate");
+
+	if (of_find_property(dev->of_node, "qcom,cdc-ecpp-dmic-rate", NULL)) {
+		rc = wcd9xxx_read_of_property_u32(dev,
+						  "qcom,cdc-ecpp-dmic-rate",
+						  &prop_val);
+		if (!rc)
+			ecpp_dmic_sample_rate = prop_val;
+	}
+
+	pdata->ecpp_dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev,
+							ecpp_dmic_sample_rate,
+							pdata->mclk_rate,
+							"ecpp_dmic_rate");
+
+	if (!(of_property_read_u32(dev->of_node,
+				   "qcom,cdc-dmic-clk-drv-strength",
+				   &prop_val))) {
+		dmic_clk_drive = prop_val;
+
+		if (dmic_clk_drive != 2 && dmic_clk_drive != 4 &&
+		    dmic_clk_drive != 8 && dmic_clk_drive != 16)
+			dev_err(dev, "Invalid cdc-dmic-clk-drv-strength %d\n",
+				dmic_clk_drive);
+	}
+
+	pdata->dmic_clk_drv = dmic_clk_drive;
+
+	return pdata;
+
+err_parse_dt_prop:
+	devm_kfree(dev, pdata->regulator);
+	pdata->regulator = NULL;
+	pdata->num_supplies = 0;
+err_power_sup:
+	devm_kfree(dev, pdata);
+	return NULL;
+}
+EXPORT_SYMBOL(wcd9xxx_populate_dt_data);
+
+static bool is_wcd9xxx_reg_power_down(struct wcd9xxx *wcd9xxx, u16 rreg)
+{
+	bool ret = false;
+	int i;
+	struct wcd9xxx_power_region *wcd9xxx_pwr;
+
+	if (!wcd9xxx)
+		return ret;
+
+	for (i = 0; i < WCD9XXX_MAX_PWR_REGIONS; i++) {
+		wcd9xxx_pwr = wcd9xxx->wcd9xxx_pwr[i];
+		if (!wcd9xxx_pwr)
+			continue;
+		if (((wcd9xxx_pwr->pwr_collapse_reg_min == 0) &&
+		     (wcd9xxx_pwr->pwr_collapse_reg_max == 0)) ||
+		    (wcd9xxx_pwr->power_state ==
+		     WCD_REGION_POWER_COLLAPSE_REMOVE))
+			ret = false;
+		else if (((wcd9xxx_pwr->power_state ==
+			   WCD_REGION_POWER_DOWN) ||
+			  (wcd9xxx_pwr->power_state ==
+			   WCD_REGION_POWER_COLLAPSE_BEGIN)) &&
+			 (rreg >= wcd9xxx_pwr->pwr_collapse_reg_min) &&
+			 (rreg <= wcd9xxx_pwr->pwr_collapse_reg_max))
+			ret = true;
+	}
+	return ret;
+}
+
+/*
+ * wcd9xxx_page_write:
+ *	Retrieve page number from register and
+ *	write that page number to the page address.
+ *	Called under io_lock acquisition.
+ *
+ * @wcd9xxx: pointer to wcd9xxx
+ * @reg: Register address from which page number is retrieved
+ *
+ * Returns 0 for success and negative error code for failure.
+ */
+int wcd9xxx_page_write(struct wcd9xxx *wcd9xxx, unsigned short *reg)
+{
+	int ret = 0;
+	unsigned short c_reg, reg_addr;
+	u8 pg_num, prev_pg_num;
+
+	if (wcd9xxx->type != WCD9335 && wcd9xxx->type != WCD934X)
+		return ret;
+
+	c_reg = *reg;
+	pg_num = c_reg >> 8;
+	reg_addr = c_reg & 0xff;
+	if (wcd9xxx->prev_pg_valid) {
+		prev_pg_num = wcd9xxx->prev_pg;
+		if (prev_pg_num != pg_num) {
+			ret = wcd9xxx->write_dev(
+					wcd9xxx, PAGE_REG_ADDR, 1,
+					(void *) &pg_num, false);
+			if (ret < 0)
+				pr_err("page write error, pg_num: 0x%x\n",
+					pg_num);
+			else {
+				wcd9xxx->prev_pg = pg_num;
+				dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n",
+					__func__, pg_num);
+			}
+		}
+	} else {
+		ret = wcd9xxx->write_dev(
+				wcd9xxx, PAGE_REG_ADDR, 1, (void *) &pg_num,
+				false);
+		if (ret < 0)
+			pr_err("page write error, pg_num: 0x%x\n", pg_num);
+		else {
+			wcd9xxx->prev_pg = pg_num;
+			wcd9xxx->prev_pg_valid = true;
+			dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n",
+				__func__, pg_num);
+		}
+	}
+	*reg = reg_addr;
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_page_write);
+
+static int regmap_bus_read(void *context, const void *reg, size_t reg_size,
+			   void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+	unsigned short c_reg, rreg;
+	int ret, i;
+
+	if (!wcd9xxx) {
+		dev_err(dev, "%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (!reg || !val) {
+		dev_err(dev, "%s: reg or val is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (reg_size != REG_BYTES) {
+		dev_err(dev, "%s: register size %zd bytes, not supported\n",
+			__func__, reg_size);
+		return -EINVAL;
+	}
+
+	mutex_lock(&wcd9xxx->io_lock);
+	c_reg = *(u16 *)reg;
+	rreg = c_reg;
+
+	if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) {
+		ret = 0;
+		for (i = 0; i < val_size; i++)
+			((u8 *)val)[i] = 0;
+		goto err;
+	}
+	ret = wcd9xxx_page_write(wcd9xxx, &c_reg);
+	if (ret)
+		goto err;
+	ret = wcd9xxx->read_dev(wcd9xxx, c_reg, val_size, val, false);
+	if (ret < 0)
+		dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n",
+			__func__, ret, rreg, val_size);
+	else {
+		for (i = 0; i < val_size; i++)
+			dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n",
+				__func__, ((u8 *)val)[i], rreg + i);
+	}
+err:
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return ret;
+}
+
+static int regmap_bus_gather_write(void *context,
+				   const void *reg, size_t reg_size,
+				   const void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+	unsigned short c_reg, rreg;
+	int ret, i;
+
+	if (!wcd9xxx) {
+		dev_err(dev, "%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (!reg || !val) {
+		dev_err(dev, "%s: reg or val is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (reg_size != REG_BYTES) {
+		dev_err(dev, "%s: register size %zd bytes, not supported\n",
+			__func__, reg_size);
+		return -EINVAL;
+	}
+	mutex_lock(&wcd9xxx->io_lock);
+	c_reg = *(u16 *)reg;
+	rreg = c_reg;
+
+	if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) {
+		ret = 0;
+		goto err;
+	}
+	ret = wcd9xxx_page_write(wcd9xxx, &c_reg);
+	if (ret)
+		goto err;
+
+	for (i = 0; i < val_size; i++)
+		dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i],
+			rreg + i);
+
+	ret = wcd9xxx->write_dev(wcd9xxx, c_reg, val_size, (void *) val,
+				 false);
+	if (ret < 0)
+		dev_err(dev, "%s: Codec write failed (%d), reg:0x%x, size:%zd\n",
+			__func__, ret, rreg, val_size);
+
+err:
+	mutex_unlock(&wcd9xxx->io_lock);
+	return ret;
+}
+
+static int regmap_bus_write(void *context, const void *data, size_t count)
+{
+	struct device *dev = context;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	WARN_ON(count < REG_BYTES);
+
+	if (count > (REG_BYTES + VAL_BYTES)) {
+		if (wcd9xxx->multi_reg_write)
+			return wcd9xxx->multi_reg_write(wcd9xxx,
+							data, count);
+	} else
+		return regmap_bus_gather_write(context, data, REG_BYTES,
+					       data + REG_BYTES,
+					       count - REG_BYTES);
+
+	dev_err(dev, "%s: bus multi reg write failure\n", __func__);
+
+	return -EINVAL;
+}
+
+static struct regmap_bus regmap_bus_config = {
+	.write = regmap_bus_write,
+	.gather_write = regmap_bus_gather_write,
+	.read = regmap_bus_read,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/*
+ * wcd9xxx_regmap_init:
+ *	Initialize wcd9xxx register map
+ *
+ * @dev: pointer to wcd device
+ * @config: pointer to register map config
+ *
+ * Returns pointer to regmap structure for success
+ * or NULL in case of failure.
+ */
+struct regmap *wcd9xxx_regmap_init(struct device *dev,
+				   const struct regmap_config *config)
+{
+	return devm_regmap_init(dev, &regmap_bus_config, dev, config);
+}
+EXPORT_SYMBOL(wcd9xxx_regmap_init);
+
+/*
+ * wcd9xxx_reset:
+ *	Reset wcd9xxx codec
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_reset(struct device *dev)
+{
+	struct wcd9xxx *wcd9xxx;
+	int rc;
+	int value;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd9xxx = dev_get_drvdata(dev);
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	if (!wcd9xxx->wcd_rst_np) {
+		dev_err(dev, "%s: reset gpio device node not specified\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	value = msm_cdc_pinctrl_get_state(wcd9xxx->wcd_rst_np);
+	if (value > 0) {
+		wcd9xxx->avoid_cdc_rstlow = 1;
+		return 0;
+	}
+
+	rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np);
+	if (rc) {
+		dev_err(dev, "%s: wcd sleep state request fail!\n",
+			__func__);
+		return rc;
+	}
+
+	/* 20ms sleep required after pulling the reset gpio to LOW */
+	msleep(20);
+
+	rc = msm_cdc_pinctrl_select_active_state(wcd9xxx->wcd_rst_np);
+	if (rc) {
+		dev_err(dev, "%s: wcd active state request fail!\n",
+			__func__);
+		return rc;
+	}
+	msleep(20);
+
+	return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_reset);
+
+/*
+ * wcd9xxx_reset_low:
+ *	Pull the wcd9xxx codec reset_n to low
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_reset_low(struct device *dev)
+{
+	struct wcd9xxx *wcd9xxx;
+	int rc;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd9xxx = dev_get_drvdata(dev);
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	if (!wcd9xxx->wcd_rst_np) {
+		dev_err(dev, "%s: reset gpio device node not specified\n",
+			__func__);
+		return -EINVAL;
+	}
+	if (wcd9xxx->avoid_cdc_rstlow) {
+		wcd9xxx->avoid_cdc_rstlow = 0;
+		dev_dbg(dev, "%s: avoid pull down of reset GPIO\n", __func__);
+		return 0;
+	}
+
+	rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np);
+	if (rc)
+		dev_err(dev, "%s: wcd sleep state request fail!\n",
+			__func__);
+
+	return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_reset_low);
+
+/*
+ * wcd9xxx_bringup:
+ *	Toggle reset analog and digital cores of wcd9xxx codec
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_bringup(struct device *dev)
+{
+	struct wcd9xxx *wcd9xxx;
+	int rc;
+	codec_bringup_fn cdc_bup_fn;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd9xxx = dev_get_drvdata(dev);
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	cdc_bup_fn = wcd9xxx_bringup_fn(wcd9xxx->type);
+	if (!cdc_bup_fn) {
+		dev_err(dev, "%s: Codec bringup fn NULL!\n",
+			__func__);
+		return -EINVAL;
+	}
+	rc = cdc_bup_fn(wcd9xxx);
+	if (rc)
+		dev_err(dev, "%s: Codec bringup error, rc: %d\n",
+			__func__, rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_bringup);
+
+/*
+ * wcd9xxx_bringup:
+ *	Set analog and digital cores of wcd9xxx codec in reset state
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_bringdown(struct device *dev)
+{
+	struct wcd9xxx *wcd9xxx;
+	int rc;
+	codec_bringdown_fn cdc_bdown_fn;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd9xxx = dev_get_drvdata(dev);
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	cdc_bdown_fn = wcd9xxx_bringdown_fn(wcd9xxx->type);
+	if (!cdc_bdown_fn) {
+		dev_err(dev, "%s: Codec bring down fn NULL!\n",
+			__func__);
+		return -EINVAL;
+	}
+	rc = cdc_bdown_fn(wcd9xxx);
+	if (rc)
+		dev_err(dev, "%s: Codec bring down error, rc: %d\n",
+			__func__, rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_bringdown);
+
+/*
+ * wcd9xxx_get_codec_info:
+ *	Fill codec specific information like interrupts, version
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_get_codec_info(struct device *dev)
+{
+	struct wcd9xxx *wcd9xxx;
+	int rc;
+	codec_type_fn cdc_type_fn;
+	struct wcd9xxx_codec_type *cinfo;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd9xxx = dev_get_drvdata(dev);
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	cdc_type_fn = wcd9xxx_get_codec_info_fn(wcd9xxx->type);
+	if (!cdc_type_fn) {
+		dev_err(dev, "%s: Codec fill type fn NULL!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	cinfo = wcd9xxx->codec_type;
+	if (!cinfo)
+		return -EINVAL;
+
+	rc = cdc_type_fn(wcd9xxx, cinfo);
+	if (rc) {
+		dev_err(dev, "%s: Codec type fill failed, rc:%d\n",
+			__func__, rc);
+		return rc;
+
+	}
+
+	switch (wcd9xxx->type) {
+	case WCD934X:
+		cinfo->dev = tavil_devs;
+		cinfo->size = ARRAY_SIZE(tavil_devs);
+		break;
+	case WCD9335:
+		cinfo->dev = tasha_devs;
+		cinfo->size = ARRAY_SIZE(tasha_devs);
+		break;
+	case WCD9330:
+		cinfo->dev = tomtom_devs;
+		cinfo->size = ARRAY_SIZE(tomtom_devs);
+		break;
+	default:
+		cinfo->dev = NULL;
+		cinfo->size = 0;
+		break;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_get_codec_info);
+
+/*
+ * wcd9xxx_core_irq_init:
+ *	Initialize wcd9xxx codec irq instance
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_core_irq_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	int ret = 0;
+
+	if (!wcd9xxx_core_res)
+		return -EINVAL;
+
+	if (wcd9xxx_core_res->irq != 1) {
+		ret = wcd9xxx_irq_init(wcd9xxx_core_res);
+		if (ret)
+			pr_err("IRQ initialization failed\n");
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_irq_init);
+
+/*
+ * wcd9xxx_assign_irq:
+ *	Assign irq and irq_base to wcd9xxx core resource
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @irq: irq number
+ * @irq_base: base irq number
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_assign_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	unsigned int irq,
+	unsigned int irq_base)
+{
+	if (!wcd9xxx_core_res)
+		return -EINVAL;
+
+	wcd9xxx_core_res->irq = irq;
+	wcd9xxx_core_res->irq_base = irq_base;
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_assign_irq);
+
+/*
+ * wcd9xxx_core_res_init:
+ *	Initialize wcd core resource instance
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @num_irqs: number of irqs for wcd9xxx core
+ * @num_irq_regs: number of irq registers
+ * @wcd_regmap: pointer to the wcd register map
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_core_res_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	int num_irqs, int num_irq_regs, struct regmap *wcd_regmap)
+{
+	if (!wcd9xxx_core_res || !wcd_regmap)
+		return -EINVAL;
+
+	mutex_init(&wcd9xxx_core_res->pm_lock);
+	wcd9xxx_core_res->wlock_holders = 0;
+	wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+	init_waitqueue_head(&wcd9xxx_core_res->pm_wq);
+	pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req,
+				PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
+	wcd9xxx_core_res->num_irqs = num_irqs;
+	wcd9xxx_core_res->num_irq_regs = num_irq_regs;
+	wcd9xxx_core_res->wcd_core_regmap = wcd_regmap;
+
+	pr_info("%s: num_irqs = %d, num_irq_regs = %d\n",
+			__func__, wcd9xxx_core_res->num_irqs,
+			wcd9xxx_core_res->num_irq_regs);
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_init);
+
+/*
+ * wcd9xxx_core_res_deinit:
+ *	Deinit wcd core resource instance
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ */
+void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	if (!wcd9xxx_core_res)
+		return;
+
+	pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req);
+	mutex_destroy(&wcd9xxx_core_res->pm_lock);
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_deinit);
+
+/*
+ * wcd9xxx_pm_cmpxchg:
+ *	Check old state and exchange with pm new state
+ *	if old state matches with current state
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @o: pm old state
+ * @n: pm new state
+ *
+ * Returns old state
+ */
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+		struct wcd9xxx_core_resource *wcd9xxx_core_res,
+		enum wcd9xxx_pm_state o,
+		enum wcd9xxx_pm_state n)
+{
+	enum wcd9xxx_pm_state old;
+
+	if (!wcd9xxx_core_res)
+		return o;
+
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	old = wcd9xxx_core_res->pm_state;
+	if (old == o)
+		wcd9xxx_core_res->pm_state = n;
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+
+	return old;
+}
+EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg);
+
+/*
+ * wcd9xxx_core_res_suspend:
+ *	Suspend callback function for wcd9xxx core
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @pm_message_t: pm message
+ *
+ * Returns 0 for success or negative error code for failure/busy
+ */
+int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	pm_message_t pmesg)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	/*
+	 * pm_qos_update_request() can be called after this suspend chain call
+	 * started. thus suspend can be called while lock is being held
+	 */
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) {
+		pr_debug("%s: suspending system, state %d, wlock %d\n",
+			 __func__, wcd9xxx_core_res->pm_state,
+			 wcd9xxx_core_res->wlock_holders);
+		wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP;
+	} else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) {
+		/*
+		 * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+		 * then set to WCD9XXX_PM_ASLEEP
+		 */
+		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+			 __func__, wcd9xxx_core_res->pm_state,
+			 wcd9xxx_core_res->wlock_holders);
+		mutex_unlock(&wcd9xxx_core_res->pm_lock);
+		if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq,
+					 wcd9xxx_pm_cmpxchg(wcd9xxx_core_res,
+						  WCD9XXX_PM_SLEEPABLE,
+						  WCD9XXX_PM_ASLEEP) ==
+							WCD9XXX_PM_SLEEPABLE,
+					 HZ))) {
+			pr_debug("%s: suspend failed state %d, wlock %d\n",
+				 __func__, wcd9xxx_core_res->pm_state,
+				 wcd9xxx_core_res->wlock_holders);
+			ret = -EBUSY;
+		} else {
+			pr_debug("%s: done, state %d, wlock %d\n", __func__,
+				 wcd9xxx_core_res->pm_state,
+				 wcd9xxx_core_res->wlock_holders);
+		}
+		mutex_lock(&wcd9xxx_core_res->pm_lock);
+	} else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_warn("%s: system is already suspended, state %d, wlock %dn",
+			__func__, wcd9xxx_core_res->pm_state,
+			wcd9xxx_core_res->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_suspend);
+
+/*
+ * wcd9xxx_core_res_resume:
+ *	Resume callback function for wcd9xxx core
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ *
+ * Returns 0 for success or negative error code for failure/busy
+ */
+int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+				wcd9xxx_core_res->pm_state,
+				wcd9xxx_core_res->wlock_holders);
+		wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+	} else {
+		pr_warn("%s: system is already awake, state %d wlock %d\n",
+				__func__, wcd9xxx_core_res->pm_state,
+				wcd9xxx_core_res->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+	wake_up_all(&wcd9xxx_core_res->pm_wq);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_resume);
+
+/*
+ * wcd9xxx_get_intf_type:
+ *	Get interface type of wcd9xxx core
+ *
+ * Returns interface type
+ */
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
+{
+	return wcd9xxx_intf;
+}
+EXPORT_SYMBOL(wcd9xxx_get_intf_type);
+
+/*
+ * wcd9xxx_set_intf_type:
+ *	Set interface type of wcd9xxx core
+ *
+ */
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status)
+{
+	wcd9xxx_intf = intf_status;
+}
+EXPORT_SYMBOL(wcd9xxx_set_intf_type);
+
+/*
+ * wcd9xxx_set_power_state: set power state for the region
+ * @wcd9xxx: handle to wcd core
+ * @state: power state to be set
+ * @region: region index
+ *
+ * Returns error code in case of failure or 0 for success
+ */
+int wcd9xxx_set_power_state(struct wcd9xxx *wcd9xxx,
+			    enum codec_power_states state,
+			    enum wcd_power_regions region)
+{
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) {
+		dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n",
+			__func__, region);
+		return -EINVAL;
+	}
+	if (!wcd9xxx->wcd9xxx_pwr[region]) {
+		dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n",
+			__func__, region);
+		return -EINVAL;
+	}
+	mutex_lock(&wcd9xxx->io_lock);
+	wcd9xxx->wcd9xxx_pwr[region]->power_state = state;
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_set_power_state);
+
+/*
+ * wcd9xxx_get_current_power_state: Get power state of the region
+ * @wcd9xxx: handle to wcd core
+ * @region: region index
+ *
+ * Returns current power state of the region or error code for failure
+ */
+int wcd9xxx_get_current_power_state(struct wcd9xxx *wcd9xxx,
+				    enum wcd_power_regions region)
+{
+	int state;
+
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) {
+		dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n",
+			__func__, region);
+		return -EINVAL;
+	}
+	if (!wcd9xxx->wcd9xxx_pwr[region]) {
+		dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n",
+			__func__, region);
+		return -EINVAL;
+	}
+
+	mutex_lock(&wcd9xxx->io_lock);
+	state = wcd9xxx->wcd9xxx_pwr[region]->power_state;
+	mutex_unlock(&wcd9xxx->io_lock);
+
+	return state;
+}
+EXPORT_SYMBOL(wcd9xxx_get_current_power_state);
diff --git a/asoc/codecs/wcd9xxx-utils.h b/asoc/codecs/wcd9xxx-utils.h
new file mode 100644
index 0000000..a7ec56c
--- /dev/null
+++ b/asoc/codecs/wcd9xxx-utils.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD9XXX_UTILS_H__
+#define __WCD9XXX_UTILS_H__
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include "pdata.h"
+#include "core.h"
+
+struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev);
+int wcd9xxx_bringup(struct device *dev);
+int wcd9xxx_bringdown(struct device *dev);
+struct regmap *wcd9xxx_regmap_init(struct device *dev,
+				   const struct regmap_config *config);
+int wcd9xxx_reset(struct device *dev);
+int wcd9xxx_reset_low(struct device *dev);
+int wcd9xxx_get_codec_info(struct device *dev);
+
+typedef int (*codec_bringup_fn)(struct wcd9xxx *);
+typedef int (*codec_bringdown_fn)(struct wcd9xxx *);
+typedef int (*codec_type_fn)(struct wcd9xxx *,
+			     struct wcd9xxx_codec_type *);
+
+codec_bringdown_fn wcd9xxx_bringdown_fn(int type);
+codec_bringup_fn wcd9xxx_bringup_fn(int type);
+codec_type_fn wcd9xxx_get_codec_info_fn(int type);
+
+#endif
diff --git a/asoc/codecs/wcd_cmi_api.h b/asoc/codecs/wcd_cmi_api.h
new file mode 100644
index 0000000..39be641
--- /dev/null
+++ b/asoc/codecs/wcd_cmi_api.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CMI_API__
+#define __CMI_API__
+
+enum cmi_api_result {
+	CMI_API_FAILED = 1,
+	CMI_API_BUSY,
+	CMI_API_NO_MEMORY,
+	CMI_API_NOT_READY,
+};
+
+enum cmi_api_event {
+	CMI_API_MSG = 1,
+	CMI_API_OFFLINE,
+	CMI_API_ONLINE,
+	CMI_API_DEINITIALIZED,
+};
+
+struct cmi_api_notification {
+	enum cmi_api_event event;
+	enum cmi_api_result result;
+	void *message;
+};
+
+void *cmi_register(
+	void notification_callback
+		(const struct cmi_api_notification *parameter),
+	u32 service);
+enum cmi_api_result cmi_deregister(void *reg_handle);
+enum cmi_api_result cmi_send_msg(void *message);
+
+#endif /*__CMI_API__*/
diff --git a/asoc/codecs/wcd_cpe_core.c b/asoc/codecs/wcd_cpe_core.c
new file mode 100644
index 0000000..7748ace
--- /dev/null
+++ b/asoc/codecs/wcd_cpe_core.c
@@ -0,0 +1,4579 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/elf.h>
+#include <linux/wait.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/pm_qos.h>
+#include <linux/dma-mapping.h>
+#include <sound/soc.h>
+#include <sound/info.h>
+#include <sound/lsm_params.h>
+#include <sound/cpe_cmi.h>
+#include <soc/qcom/pm.h>
+#include <dsp/audio_cal_utils.h>
+#include "core.h"
+#include "cpe_core.h"
+#include "cpe_err.h"
+#include "wcd_cpe_core.h"
+#include "wcd_cpe_services.h"
+#include "wcd_cmi_api.h"
+#include "wcd9xxx-irq.h"
+
+#define CMI_CMD_TIMEOUT (10 * HZ)
+#define WCD_CPE_LSM_MAX_SESSIONS 2
+#define WCD_CPE_AFE_MAX_PORTS 4
+#define AFE_SVC_EXPLICIT_PORT_START 1
+#define WCD_CPE_EC_PP_BUF_SIZE	480 /* 5 msec buffer */
+
+#define ELF_FLAG_EXECUTE (1 << 0)
+#define ELF_FLAG_WRITE (1 << 1)
+#define ELF_FLAG_READ (1 << 2)
+
+#define ELF_FLAG_RW (ELF_FLAG_READ | ELF_FLAG_WRITE)
+
+#define WCD_CPE_GRAB_LOCK(lock, name)		\
+{						\
+	pr_debug("%s: %s lock acquire\n",	\
+		 __func__, name);		\
+	mutex_lock(lock);			\
+}
+
+#define WCD_CPE_REL_LOCK(lock, name)		\
+{						\
+	pr_debug("%s: %s lock release\n",	\
+		 __func__, name);		\
+	mutex_unlock(lock);			\
+}
+
+#define WCD_CPE_STATE_MAX_LEN 11
+#define CPE_OFFLINE_WAIT_TIMEOUT (2 * HZ)
+#define CPE_READY_WAIT_TIMEOUT (3 * HZ)
+#define WCD_CPE_SYSFS_DIR_MAX_LENGTH 32
+
+#define CPE_ERR_IRQ_CB(core) \
+	(core->cpe_cdc_cb->cpe_err_irq_control)
+
+/*
+ * AFE output buffer size is always
+ * (sample_rate * number of bytes per sample/2*1000)
+ */
+#define AFE_OUT_BUF_SIZE(bit_width, sample_rate) \
+	(((sample_rate) * (bit_width / BITS_PER_BYTE))/(2*1000))
+
+enum afe_port_state {
+	AFE_PORT_STATE_DEINIT = 0,
+	AFE_PORT_STATE_INIT,
+	AFE_PORT_STATE_CONFIG,
+	AFE_PORT_STATE_STARTED,
+	AFE_PORT_STATE_SUSPENDED,
+};
+
+struct wcd_cmi_afe_port_data {
+	u8 port_id;
+	struct mutex afe_lock;
+	struct completion afe_cmd_complete;
+	enum afe_port_state port_state;
+	u8 cmd_result;
+	u32 mem_handle;
+};
+
+struct cpe_lsm_ids {
+	u32 module_id;
+	u32 param_id;
+};
+
+static struct wcd_cpe_core *core_d;
+static struct cpe_lsm_session
+		*lsm_sessions[WCD_CPE_LSM_MAX_SESSIONS + 1];
+struct wcd_cpe_core * (*wcd_get_cpe_core)(struct snd_soc_codec *);
+static struct wcd_cmi_afe_port_data afe_ports[WCD_CPE_AFE_MAX_PORTS + 1];
+static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param);
+static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core);
+static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core);
+static ssize_t cpe_ftm_test_trigger(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos);
+static u32 ramdump_enable;
+static u32 cpe_ftm_test_status;
+static const struct file_operations cpe_ftm_test_trigger_fops = {
+	.open = simple_open,
+	.write = cpe_ftm_test_trigger,
+};
+
+static int wcd_cpe_afe_svc_cmd_mode(void *core_handle,
+				    u8 mode);
+struct wcd_cpe_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct wcd_cpe_core *core, char *buf);
+	ssize_t (*store)(struct wcd_cpe_core *core, const char *buf,
+			 ssize_t count);
+};
+
+#define WCD_CPE_ATTR(_name, _mode, _show, _store) \
+static struct wcd_cpe_attribute cpe_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = _mode}, \
+	.show = _show, \
+	.store = _store, \
+}
+
+#define to_wcd_cpe_attr(a) \
+	container_of((a), struct wcd_cpe_attribute, attr)
+
+#define kobj_to_cpe_core(kobj) \
+	container_of((kobj), struct wcd_cpe_core, cpe_kobj)
+
+/* wcd_cpe_lsm_session_active: check if any session is active
+ * return true if any session is active.
+ */
+static bool wcd_cpe_lsm_session_active(void)
+{
+	int index = 1;
+	bool lsm_active = false;
+
+	/* session starts from index 1 */
+	for (; index <= WCD_CPE_LSM_MAX_SESSIONS; index++) {
+		if (lsm_sessions[index] != NULL) {
+			lsm_active = true;
+			break;
+		} else {
+			lsm_active = false;
+		}
+	}
+	return lsm_active;
+}
+
+static int wcd_cpe_get_sfr_dump(struct wcd_cpe_core *core)
+{
+	struct cpe_svc_mem_segment dump_seg;
+	int rc;
+	u8 *sfr_dump;
+
+	sfr_dump = kzalloc(core->sfr_buf_size, GFP_KERNEL);
+	if (!sfr_dump)
+		goto done;
+
+	dump_seg.type = CPE_SVC_DATA_MEM;
+	dump_seg.cpe_addr = core->sfr_buf_addr;
+	dump_seg.size = core->sfr_buf_size;
+	dump_seg.data = sfr_dump;
+	dev_dbg(core->dev,
+		"%s: reading SFR from CPE, size = %zu\n",
+		__func__, core->sfr_buf_size);
+
+	rc = cpe_svc_ramdump(core->cpe_handle, &dump_seg);
+	if (rc < 0) {
+		dev_err(core->dev,
+			"%s: Failed to read cpe sfr_dump, err = %d\n",
+			__func__, rc);
+		goto free_sfr_dump;
+	}
+
+	dev_info(core->dev,
+		 "%s: cpe_sfr = %s\n", __func__, sfr_dump);
+
+free_sfr_dump:
+	kfree(sfr_dump);
+done:
+	/* Even if SFR dump failed, do not return error */
+	return 0;
+}
+
+static int wcd_cpe_collect_ramdump(struct wcd_cpe_core *core)
+{
+	struct cpe_svc_mem_segment dump_seg;
+	int rc;
+
+	if (!core->cpe_ramdump_dev || !core->cpe_dump_v_addr ||
+	    core->hw_info.dram_size == 0) {
+		dev_err(core->dev,
+			"%s: Ramdump devices not set up, size = %zu\n",
+			__func__, core->hw_info.dram_size);
+		return -EINVAL;
+	}
+
+	dump_seg.type = CPE_SVC_DATA_MEM;
+	dump_seg.cpe_addr = core->hw_info.dram_offset;
+	dump_seg.size = core->hw_info.dram_size;
+	dump_seg.data = core->cpe_dump_v_addr;
+
+	dev_dbg(core->dev,
+		"%s: Reading ramdump from CPE\n",
+		__func__);
+
+	rc = cpe_svc_ramdump(core->cpe_handle, &dump_seg);
+	if (rc < 0) {
+		dev_err(core->dev,
+			"%s: Failed to read CPE ramdump, err = %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	dev_dbg(core->dev,
+		"%s: completed reading ramdump from CPE\n",
+		__func__);
+
+	core->cpe_ramdump_seg.address = (unsigned long) core->cpe_dump_addr;
+	core->cpe_ramdump_seg.size = core->hw_info.dram_size;
+	core->cpe_ramdump_seg.v_address = core->cpe_dump_v_addr;
+
+	rc = do_ramdump(core->cpe_ramdump_dev,
+			&core->cpe_ramdump_seg, 1);
+	if (rc)
+		dev_err(core->dev,
+			"%s: fail to dump cpe ram to device, err = %d\n",
+			__func__, rc);
+	return rc;
+}
+
+/* wcd_cpe_is_valid_elf_hdr: check if the ELF header is valid
+ * @core: handle to wcd_cpe_core
+ * @fw_size: size of firmware from request_firmware
+ * @ehdr: the elf header to be checked for
+ * return true if all checks pass, true if any elf check fails
+ */
+static bool wcd_cpe_is_valid_elf_hdr(struct wcd_cpe_core *core, size_t fw_size,
+				     const struct elf32_hdr *ehdr)
+{
+	if (fw_size < sizeof(*ehdr)) {
+		dev_err(core->dev, "%s:Firmware too small\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+		dev_err(core->dev, "%s: Not an ELF file\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
+		dev_err(core->dev, "%s: Not a executable image\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		dev_err(core->dev, "%s: no segments to load\n", __func__);
+		goto elf_check_fail;
+	}
+
+	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
+	    sizeof(struct elf32_hdr) > fw_size) {
+		dev_err(core->dev, "%s: Too small MDT file\n", __func__);
+		goto elf_check_fail;
+	}
+
+	return true;
+
+elf_check_fail:
+	return false;
+}
+
+/*
+ * wcd_cpe_load_each_segment: download segment to CPE
+ * @core: handle to struct wcd_cpe_core
+ * @file_idx: index of split firmware image file name
+ * @phdr: program header from metadata
+ */
+static int wcd_cpe_load_each_segment(struct wcd_cpe_core *core,
+			  int file_idx, const struct elf32_phdr *phdr)
+{
+	const struct firmware *split_fw;
+	char split_fname[32];
+	int ret = 0;
+	struct cpe_svc_mem_segment *segment;
+
+	if (!core || !phdr) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* file size can be 0 for bss segments */
+	if (phdr->p_filesz == 0 || phdr->p_memsz == 0)
+		return 0;
+
+	segment = kzalloc(sizeof(struct cpe_svc_mem_segment), GFP_KERNEL);
+	if (!segment)
+		return -ENOMEM;
+
+	snprintf(split_fname, sizeof(split_fname), "%s.b%02d",
+		 core->fname, file_idx);
+
+	ret = request_firmware(&split_fw, split_fname, core->dev);
+	if (ret) {
+		dev_err(core->dev, "firmware %s not found\n",
+			split_fname);
+		ret = -EIO;
+		goto fw_req_fail;
+	}
+
+	if (phdr->p_flags & ELF_FLAG_EXECUTE)
+		segment->type = CPE_SVC_INSTRUCTION_MEM;
+	else if (phdr->p_flags & ELF_FLAG_RW)
+		segment->type = CPE_SVC_DATA_MEM;
+	else {
+		dev_err(core->dev, "%s invalid flags 0x%x\n",
+			__func__, phdr->p_flags);
+		goto done;
+	}
+
+	segment->cpe_addr = phdr->p_paddr;
+	segment->size = phdr->p_filesz;
+	segment->data = (u8 *) split_fw->data;
+
+	dev_dbg(core->dev,
+		"%s: cpe segment type %s read from firmware\n", __func__,
+		(segment->type == CPE_SVC_INSTRUCTION_MEM) ?
+			"INSTRUCTION" : "DATA");
+
+	ret = cpe_svc_download_segment(core->cpe_handle, segment);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: Failed to download %s, error = %d\n",
+			__func__, split_fname, ret);
+		goto done;
+	}
+
+done:
+	release_firmware(split_fw);
+
+fw_req_fail:
+	kfree(segment);
+	return ret;
+}
+
+/*
+ * wcd_cpe_enable_cpe_clks: enable the clocks for CPE
+ * @core: handle to wcd_cpe_core
+ * @enable: flag indicating whether to enable/disable cpe clocks
+ */
+static int wcd_cpe_enable_cpe_clks(struct wcd_cpe_core *core, bool enable)
+{
+	int ret, ret1;
+
+	if (!core || !core->cpe_cdc_cb ||
+	    !core->cpe_cdc_cb->cpe_clk_en) {
+		pr_err("%s: invalid handle\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	ret = core->cpe_cdc_cb->cdc_clk_en(core->codec, enable);
+	if (ret) {
+		dev_err(core->dev, "%s: Failed to enable RCO\n",
+			__func__);
+		return ret;
+	}
+
+	if (!enable && core->cpe_clk_ref > 0)
+		core->cpe_clk_ref--;
+
+	/*
+	 * CPE clk will be enabled at the first time
+	 * and be disabled at the last time.
+	 */
+	if (core->cpe_clk_ref == 0) {
+		ret = core->cpe_cdc_cb->cpe_clk_en(core->codec, enable);
+		if (ret) {
+			dev_err(core->dev,
+				"%s: cpe_clk_en() failed, err = %d\n",
+				__func__, ret);
+			goto cpe_clk_fail;
+		}
+	}
+
+	if (enable)
+		core->cpe_clk_ref++;
+
+	return 0;
+
+cpe_clk_fail:
+	/* Release the codec clk if CPE clk enable failed */
+	if (enable) {
+		ret1 = core->cpe_cdc_cb->cdc_clk_en(core->codec, !enable);
+		if (ret1)
+			dev_err(core->dev,
+				"%s: Fail to release codec clk, err = %d\n",
+				__func__, ret1);
+	}
+
+	return ret;
+}
+
+/*
+ * wcd_cpe_bus_vote_max_bw: Function to vote for max bandwidth on codec bus
+ * @core: handle to core for cpe
+ * @vote: flag to indicate enable/disable of vote
+ *
+ * This function will try to use the codec provided callback to
+ * vote/unvote for the max bandwidth of the bus that is used by
+ * the codec for register reads/writes.
+ */
+static int wcd_cpe_bus_vote_max_bw(struct wcd_cpe_core *core,
+		bool vote)
+{
+	if (!core || !core->cpe_cdc_cb) {
+		pr_err("%s: Invalid handle to %s\n",
+			__func__,
+			(!core) ? "core" : "codec callbacks");
+		return -EINVAL;
+	}
+
+	if (core->cpe_cdc_cb->bus_vote_bw) {
+		dev_dbg(core->dev, "%s: %s cdc bus max bandwidth\n",
+			 __func__, vote ? "Vote" : "Unvote");
+		core->cpe_cdc_cb->bus_vote_bw(core->codec, vote);
+	}
+
+	return 0;
+}
+
+/*
+ * wcd_cpe_load_fw: Function to load the fw image
+ * @core: cpe core pointer
+ * @load_type: indicates whether to load to data section
+ *	       or the instruction section
+ *
+ * Parse the mdt file to look for program headers, load each
+ * split file corresponding to the program headers.
+ */
+static int wcd_cpe_load_fw(struct wcd_cpe_core *core,
+	unsigned int load_type)
+{
+
+	int ret, phdr_idx;
+	struct snd_soc_codec *codec = NULL;
+	struct wcd9xxx *wcd9xxx = NULL;
+	const struct elf32_hdr *ehdr;
+	const struct elf32_phdr *phdr;
+	const struct firmware *fw;
+	const u8 *elf_ptr;
+	char mdt_name[64];
+	bool img_dload_fail = false;
+	bool load_segment;
+
+	if (!core || !core->cpe_handle) {
+		pr_err("%s: Error CPE core %pK\n", __func__,
+		       core);
+		return -EINVAL;
+	}
+	codec = core->codec;
+	wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	snprintf(mdt_name, sizeof(mdt_name), "%s.mdt", core->fname);
+	ret = request_firmware(&fw, mdt_name, core->dev);
+	if (ret < 0) {
+		dev_err(core->dev, "firmware %s not found\n", mdt_name);
+		return ret;
+	}
+
+	ehdr = (struct elf32_hdr *) fw->data;
+	if (!wcd_cpe_is_valid_elf_hdr(core, fw->size, ehdr)) {
+		dev_err(core->dev, "%s: fw mdt %s is invalid\n",
+			__func__, mdt_name);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	elf_ptr = fw->data + sizeof(*ehdr);
+
+	if (load_type == ELF_FLAG_EXECUTE) {
+		/* Reset CPE first */
+		ret = cpe_svc_reset(core->cpe_handle);
+		if (ret < 0) {
+			dev_err(core->dev,
+				"%s: Failed to reset CPE with error %d\n",
+				__func__, ret);
+			goto done;
+		}
+	}
+
+	dev_dbg(core->dev, "%s: start image dload, name = %s, load_type = 0x%x\n",
+		__func__, core->fname, load_type);
+
+	wcd_cpe_bus_vote_max_bw(core, true);
+
+	/* parse every program header and request corresponding firmware */
+	for (phdr_idx = 0; phdr_idx < ehdr->e_phnum; phdr_idx++) {
+		phdr = (struct elf32_phdr *)elf_ptr;
+		load_segment = false;
+
+		dev_dbg(core->dev,
+			"index = %d, vaddr = 0x%x, paddr = 0x%x, filesz = 0x%x, memsz = 0x%x, flags = 0x%x\n"
+			, phdr_idx, phdr->p_vaddr, phdr->p_paddr,
+			phdr->p_filesz, phdr->p_memsz, phdr->p_flags);
+
+		switch (load_type) {
+		case ELF_FLAG_EXECUTE:
+			if (phdr->p_flags & load_type)
+				load_segment = true;
+			break;
+		case ELF_FLAG_RW:
+			if (!(phdr->p_flags & ELF_FLAG_EXECUTE) &&
+			    (phdr->p_flags & load_type))
+				load_segment = true;
+			break;
+		default:
+			pr_err("%s: Invalid load_type 0x%x\n",
+				__func__, load_type);
+			ret = -EINVAL;
+			goto rel_bus_vote;
+		}
+
+		if (load_segment) {
+			ret = wcd_cpe_load_each_segment(core,
+						phdr_idx, phdr);
+			if (ret < 0) {
+				dev_err(core->dev,
+					"Failed to load segment %d, aborting img dload\n",
+					phdr_idx);
+				img_dload_fail = true;
+				goto rel_bus_vote;
+			}
+		} else {
+			dev_dbg(core->dev,
+				"%s: skipped segment with index %d\n",
+				__func__, phdr_idx);
+		}
+
+		elf_ptr = elf_ptr + sizeof(*phdr);
+	}
+	if (load_type == ELF_FLAG_EXECUTE)
+		core->ssr_type = WCD_CPE_IMEM_DOWNLOADED;
+
+rel_bus_vote:
+	wcd_cpe_bus_vote_max_bw(core, false);
+
+done:
+	release_firmware(fw);
+	return ret;
+}
+
+/*
+ * wcd_cpe_change_online_state - mark cpe online/offline state
+ * @core: core session to mark
+ * @online: whether online of offline
+ *
+ */
+static void wcd_cpe_change_online_state(struct wcd_cpe_core *core,
+			int online)
+{
+	struct wcd_cpe_ssr_entry *ssr_entry = NULL;
+	unsigned long ret;
+
+	if (!core) {
+		pr_err("%s: Invalid core handle\n",
+			__func__);
+		return;
+	}
+
+	ssr_entry = &core->ssr_entry;
+	WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR");
+	ssr_entry->offline = !online;
+
+	/* Make sure write to offline state is completed. */
+	wmb();
+	ret = xchg(&ssr_entry->offline_change, 1);
+	wake_up_interruptible(&ssr_entry->offline_poll_wait);
+	WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR");
+	pr_debug("%s: change state 0x%x offline_change 0x%x\n"
+		 " core->offline 0x%x, ret = %ld\n",
+		 __func__, online,
+		 ssr_entry->offline_change,
+		 core->ssr_entry.offline, ret);
+}
+
+/*
+ * wcd_cpe_load_fw_image: work function to load the fw image
+ * @work: work that is scheduled to perform the image loading
+ *
+ * Parse the mdt file to look for program headers, load each
+ * split file corresponding to the program headers.
+ */
+static void wcd_cpe_load_fw_image(struct work_struct *work)
+{
+	struct wcd_cpe_core *core;
+	int ret = 0;
+
+	core = container_of(work, struct wcd_cpe_core, load_fw_work);
+	ret = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE);
+	if (!ret)
+		wcd_cpe_change_online_state(core, 1);
+	else
+		pr_err("%s: failed to load instruction section, err = %d\n",
+			__func__, ret);
+}
+
+/*
+ * wcd_cpe_get_core_handle: get the handle to wcd_cpe_core
+ * @codec: codec from which this handle is to be obtained
+ * Codec driver should provide a callback function to obtain
+ * handle to wcd_cpe_core during initialization of wcd_cpe_core
+ */
+void *wcd_cpe_get_core_handle(
+	struct snd_soc_codec *codec)
+{
+	struct wcd_cpe_core *core = NULL;
+
+	if (!codec) {
+		pr_err("%s: Invalid codec handle\n",
+			__func__);
+		goto done;
+	}
+
+	if (!wcd_get_cpe_core) {
+		dev_err(codec->dev,
+			"%s: codec callback not available\n",
+			__func__);
+		goto done;
+	}
+
+	core = wcd_get_cpe_core(codec);
+
+	if (!core)
+		dev_err(codec->dev,
+			"%s: handle to core not available\n",
+			__func__);
+done:
+	return core;
+}
+EXPORT_SYMBOL(wcd_cpe_get_core_handle);
+
+/*
+ * svass_engine_irq: threaded interrupt handler for svass engine irq
+ * @irq: interrupt number
+ * @data: data pointer passed during irq registration
+ */
+static irqreturn_t svass_engine_irq(int irq, void *data)
+{
+	struct wcd_cpe_core *core = data;
+	int ret = 0;
+
+	if (!core) {
+		pr_err("%s: Invalid data for interrupt handler\n",
+			__func__);
+		goto done;
+	}
+
+	ret = cpe_svc_process_irq(core->cpe_handle, CPE_IRQ_OUTBOX_IRQ);
+	if (ret < 0)
+		dev_err(core->dev,
+			"%s: Error processing irq from cpe_Services\n",
+			__func__);
+done:
+	return IRQ_HANDLED;
+}
+
+/*
+ * wcd_cpe_state_read - update read status in procfs
+ * @entry: snd_info_entry
+ * @buf: buffer where the read status is updated.
+ *
+ */
+static ssize_t wcd_cpe_state_read(struct snd_info_entry *entry,
+			       void *file_private_data, struct file *file,
+			       char __user *buf, size_t count, loff_t pos)
+{
+	int len = 0;
+	char buffer[WCD_CPE_STATE_MAX_LEN];
+	struct wcd_cpe_core *core = NULL;
+	struct wcd_cpe_ssr_entry *ssr_entry = NULL;
+
+	core = (struct wcd_cpe_core *) entry->private_data;
+	if (!core) {
+		pr_err("%s: CPE core NULL\n", __func__);
+		return -EINVAL;
+	}
+	ssr_entry = &core->ssr_entry;
+
+	/* Make sure read from ssr_entry is completed. */
+	rmb();
+	dev_dbg(core->dev,
+		"%s: Offline 0x%x\n", __func__,
+		 ssr_entry->offline);
+
+	WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR");
+	len = snprintf(buffer, sizeof(buffer), "%s\n",
+		       ssr_entry->offline ? "OFFLINE" : "ONLINE");
+	WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR");
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+/*
+ * wcd_cpe_state_poll - polls for change state
+ * @entry: snd_info_entry
+ * @wait: wait for duration for poll wait
+ *
+ */
+static unsigned int wcd_cpe_state_poll(struct snd_info_entry *entry,
+					void *private_data, struct file *file,
+					poll_table *wait)
+{
+	struct wcd_cpe_core *core = NULL;
+	struct wcd_cpe_ssr_entry *ssr_entry = NULL;
+	int ret = 0;
+
+	core = (struct wcd_cpe_core *) entry->private_data;
+	if (!core) {
+		pr_err("%s: CPE core NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	ssr_entry = &core->ssr_entry;
+
+	dev_dbg(core->dev, "%s: CPE Poll wait\n",
+	       __func__);
+	poll_wait(file, &ssr_entry->offline_poll_wait, wait);
+	dev_dbg(core->dev, "%s: Wake-up Poll wait\n",
+	       __func__);
+	WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR");
+
+	if (xchg(&ssr_entry->offline_change, 0))
+		ret = POLLIN | POLLPRI | POLLRDNORM;
+
+	WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR");
+
+	dev_dbg(core->dev, "%s: ret (%d) from poll_wait\n",
+		__func__, ret);
+	return ret;
+}
+
+/*
+ * wcd_cpe_is_online_state - return true if card is online state
+ * @core: core offline to query
+ */
+static bool wcd_cpe_is_online_state(void *core_handle)
+{
+	struct wcd_cpe_core *core = core_handle;
+
+	if (core_handle) {
+		return !core->ssr_entry.offline;
+	} else {
+		pr_err("%s: Core handle NULL\n", __func__);
+		/* still return 1- offline if core ptr null */
+		return false;
+	}
+}
+
+static struct snd_info_entry_ops wcd_cpe_state_proc_ops = {
+	.read = wcd_cpe_state_read,
+	.poll = wcd_cpe_state_poll,
+};
+
+static int wcd_cpe_check_new_image(struct wcd_cpe_core *core)
+{
+	int rc = 0;
+	char temp_img_name[WCD_CPE_IMAGE_FNAME_MAX];
+
+	if (!strcmp(core->fname, core->dyn_fname) &&
+	    core->ssr_type != WCD_CPE_INITIALIZED) {
+		dev_dbg(core->dev,
+			"%s: Firmware unchanged, fname = %s, ssr_type 0x%x\n",
+			__func__, core->fname, core->ssr_type);
+		goto done;
+	}
+
+	/*
+	 * Different firmware name requested,
+	 * Re-load the instruction section
+	 */
+	strlcpy(temp_img_name, core->fname,
+		WCD_CPE_IMAGE_FNAME_MAX);
+	strlcpy(core->fname, core->dyn_fname,
+		WCD_CPE_IMAGE_FNAME_MAX);
+
+	rc = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE);
+	if (rc) {
+		dev_err(core->dev,
+			"%s: Failed to dload new image %s, err = %d\n",
+			__func__, core->fname, rc);
+		/* If new image download failed, revert back to old image */
+		strlcpy(core->fname, temp_img_name,
+			WCD_CPE_IMAGE_FNAME_MAX);
+		rc = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE);
+		if (rc)
+			dev_err(core->dev,
+				"%s: Failed to re-dload image %s, err = %d\n",
+				__func__, core->fname, rc);
+	} else {
+		dev_info(core->dev, "%s: fw changed to %s\n",
+			 __func__, core->fname);
+	}
+done:
+	return rc;
+}
+
+static int wcd_cpe_enable(struct wcd_cpe_core *core,
+		bool enable)
+{
+	int ret = 0;
+
+	if (enable) {
+		/* Reset CPE first */
+		ret = cpe_svc_reset(core->cpe_handle);
+		if (ret < 0) {
+			dev_err(core->dev,
+				"%s: CPE Reset failed, error = %d\n",
+				__func__, ret);
+			goto done;
+		}
+
+		ret = wcd_cpe_setup_irqs(core);
+		if (ret) {
+			dev_err(core->dev,
+				"%s: CPE IRQs setup failed, error = %d\n",
+				__func__, ret);
+			goto done;
+		}
+		ret = wcd_cpe_check_new_image(core);
+		if (ret)
+			goto fail_boot;
+
+		/* Dload data section */
+		ret = wcd_cpe_load_fw(core, ELF_FLAG_RW);
+		if (ret) {
+			dev_err(core->dev,
+				"%s: Failed to dload data section, err = %d\n",
+				__func__, ret);
+			goto fail_boot;
+		}
+
+		ret = wcd_cpe_enable_cpe_clks(core, true);
+		if (ret < 0) {
+			dev_err(core->dev,
+				"%s: CPE clk enable failed, err = %d\n",
+				__func__, ret);
+			goto fail_boot;
+		}
+
+		ret = cpe_svc_boot(core->cpe_handle,
+				   core->cpe_debug_mode);
+		if (ret < 0) {
+			dev_err(core->dev,
+				"%s: Failed to boot CPE\n",
+				__func__);
+			goto fail_boot;
+		}
+
+		/* wait for CPE to be online */
+		dev_dbg(core->dev,
+			"%s: waiting for CPE bootup\n",
+			__func__);
+
+		wait_for_completion(&core->online_compl);
+
+		dev_dbg(core->dev,
+			"%s: CPE bootup done\n",
+			__func__);
+
+		core->ssr_type = WCD_CPE_ENABLED;
+	} else {
+		if (core->ssr_type == WCD_CPE_BUS_DOWN_EVENT ||
+		    core->ssr_type == WCD_CPE_SSR_EVENT) {
+			/*
+			 * If this disable vote is when
+			 * SSR is in progress, do not disable CPE here,
+			 * instead SSR handler will control CPE.
+			 */
+			wcd_cpe_enable_cpe_clks(core, false);
+			wcd_cpe_cleanup_irqs(core);
+			goto done;
+		}
+
+		ret = cpe_svc_shutdown(core->cpe_handle);
+		if (ret < 0) {
+			dev_err(core->dev,
+				"%s: CPE shutdown failed, error %d\n",
+				__func__, ret);
+			goto done;
+		}
+
+		wcd_cpe_enable_cpe_clks(core, false);
+		wcd_cpe_cleanup_irqs(core);
+		core->ssr_type = WCD_CPE_IMEM_DOWNLOADED;
+	}
+
+	return ret;
+
+fail_boot:
+	wcd_cpe_cleanup_irqs(core);
+
+done:
+	return ret;
+}
+
+/*
+ * wcd_cpe_boot_ssr: Load the images to CPE after ssr and bootup cpe
+ * @core: handle to the core
+ */
+static int wcd_cpe_boot_ssr(struct wcd_cpe_core *core)
+{
+	int rc = 0;
+
+	if (!core || !core->cpe_handle) {
+		pr_err("%s: Invalid handle\n", __func__);
+		rc = -EINVAL;
+		goto fail;
+	}
+	/* Load the instruction section and mark CPE as online */
+	rc = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE);
+	if (rc) {
+		dev_err(core->dev,
+			"%s: Failed to load instruction, err = %d\n",
+			__func__, rc);
+		goto fail;
+	} else {
+		wcd_cpe_change_online_state(core, 1);
+	}
+
+fail:
+	return rc;
+}
+
+/*
+ * wcd_cpe_clr_ready_status:
+ *	Clear the value from the ready status for CPE
+ * @core: handle to the core
+ * @value: flag/bitmask that is to be cleared
+ *
+ * This function should not be invoked with ssr_lock acquired
+ */
+static void wcd_cpe_clr_ready_status(struct wcd_cpe_core *core,
+			       u8 value)
+{
+	WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR");
+	core->ready_status &= ~(value);
+	dev_dbg(core->dev,
+		"%s: ready_status = 0x%x\n",
+		__func__, core->ready_status);
+	WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR");
+}
+
+/*
+ * wcd_cpe_set_and_complete:
+ *	Set the ready status with the provided value and
+ *	flag the completion object if ready status moves
+ *	to ready to download
+ * @core: handle to the core
+ * @value: flag/bitmask that is to be set
+ */
+static void wcd_cpe_set_and_complete(struct wcd_cpe_core *core,
+				u8 value)
+{
+	WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR");
+	core->ready_status |= value;
+	if ((core->ready_status & WCD_CPE_READY_TO_DLOAD) ==
+	    WCD_CPE_READY_TO_DLOAD) {
+		dev_dbg(core->dev,
+			"%s: marking ready, status = 0x%x\n",
+			__func__, core->ready_status);
+		complete(&core->ready_compl);
+	}
+	WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR");
+}
+
+
+/*
+ * wcd_cpe_ssr_work: work function to handle CPE SSR
+ * @work: work that is scheduled to perform CPE shutdown
+ *	and restart
+ */
+static void wcd_cpe_ssr_work(struct work_struct *work)
+{
+
+	int rc = 0;
+	u32 irq = 0;
+	struct wcd_cpe_core *core = NULL;
+	u8 status = 0;
+
+	core = container_of(work, struct wcd_cpe_core, ssr_work);
+	if (!core) {
+		pr_err("%s: Core handle NULL\n", __func__);
+		return;
+	}
+
+	/* Obtain pm request up in case of suspend mode */
+	pm_qos_add_request(&core->pm_qos_req,
+			   PM_QOS_CPU_DMA_LATENCY,
+			   PM_QOS_DEFAULT_VALUE);
+	pm_qos_update_request(&core->pm_qos_req,
+			msm_cpuidle_get_deep_idle_latency());
+
+	dev_dbg(core->dev,
+		"%s: CPE SSR with event %d\n",
+		__func__, core->ssr_type);
+
+	if (core->ssr_type == WCD_CPE_SSR_EVENT) {
+		if (CPE_ERR_IRQ_CB(core))
+			core->cpe_cdc_cb->cpe_err_irq_control(
+					core->codec,
+					CPE_ERR_IRQ_STATUS,
+					&status);
+		if (status & core->irq_info.cpe_fatal_irqs)
+			irq = CPE_IRQ_WDOG_BITE;
+	} else {
+		/* If bus is down, cdc reg cannot be read */
+		irq = CPE_IRQ_WDOG_BITE;
+	}
+
+	if (core->cpe_users > 0) {
+		rc = cpe_svc_process_irq(core->cpe_handle, irq);
+		if (rc < 0)
+			/*
+			 * Even if process_irq fails,
+			 * wait for cpe to move to offline state
+			 */
+			dev_err(core->dev,
+				"%s: irq processing failed, error = %d\n",
+				__func__, rc);
+
+		rc = wait_for_completion_timeout(&core->offline_compl,
+						 CPE_OFFLINE_WAIT_TIMEOUT);
+		if (!rc) {
+			dev_err(core->dev,
+				"%s: wait for cpe offline timed out\n",
+				__func__);
+			goto err_ret;
+		}
+		if (core->ssr_type != WCD_CPE_BUS_DOWN_EVENT) {
+			wcd_cpe_get_sfr_dump(core);
+
+			/*
+			 * Ramdump has to be explicitly enabled
+			 * through debugfs and cannot be collected
+			 * when bus is down.
+			 */
+			if (ramdump_enable)
+				wcd_cpe_collect_ramdump(core);
+		}
+	} else {
+		pr_err("%s: no cpe users, mark as offline\n", __func__);
+		wcd_cpe_change_online_state(core, 0);
+		wcd_cpe_set_and_complete(core,
+					 WCD_CPE_BLK_READY);
+	}
+
+	rc = wait_for_completion_timeout(&core->ready_compl,
+					 CPE_READY_WAIT_TIMEOUT);
+	if (!rc) {
+		dev_err(core->dev,
+			"%s: ready to online timed out, status = %u\n",
+			__func__, core->ready_status);
+		goto err_ret;
+	}
+
+	rc = wcd_cpe_boot_ssr(core);
+
+	/* Once image are downloaded make sure all
+	 * error interrupts are cleared
+	 */
+	if (CPE_ERR_IRQ_CB(core))
+		core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
+					CPE_ERR_IRQ_CLEAR, NULL);
+
+err_ret:
+	/* remove after default pm qos */
+	pm_qos_update_request(&core->pm_qos_req,
+			      PM_QOS_DEFAULT_VALUE);
+	pm_qos_remove_request(&core->pm_qos_req);
+}
+
+/*
+ * wcd_cpe_ssr_handle: handle SSR events here.
+ * @core_handle: handle to the cpe core
+ * @event: indicates ADSP or CDSP SSR.
+ */
+int wcd_cpe_ssr_event(void *core_handle,
+		      enum wcd_cpe_ssr_state_event event)
+{
+	struct wcd_cpe_core *core = core_handle;
+
+	if (!core) {
+		pr_err("%s: Invalid handle to core\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * If CPE is not even enabled, the SSR event for
+	 * CPE needs to be ignored
+	 */
+	if (core->ssr_type == WCD_CPE_INITIALIZED) {
+		dev_info(core->dev,
+			"%s: CPE initialized but not enabled, skip CPE ssr\n",
+			 __func__);
+		return 0;
+	}
+
+	dev_dbg(core->dev,
+		"%s: Schedule ssr work, event = %d\n",
+		__func__, core->ssr_type);
+
+	switch (event) {
+	case WCD_CPE_BUS_DOWN_EVENT:
+		/*
+		 * If bus down, then CPE block is also
+		 * treated to be down
+		 */
+		wcd_cpe_clr_ready_status(core, WCD_CPE_READY_TO_DLOAD);
+		core->ssr_type = event;
+		schedule_work(&core->ssr_work);
+		break;
+
+	case WCD_CPE_SSR_EVENT:
+		wcd_cpe_clr_ready_status(core, WCD_CPE_BLK_READY);
+		core->ssr_type = event;
+		schedule_work(&core->ssr_work);
+		break;
+
+	case WCD_CPE_BUS_UP_EVENT:
+		wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY);
+		/*
+		 * In case of bus up event ssr_type will be changed
+		 * to WCD_CPE_ACTIVE once CPE is online
+		 */
+		break;
+
+	default:
+		dev_err(core->dev,
+			"%s: unhandled SSR event %d\n",
+			__func__, event);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd_cpe_ssr_event);
+
+/*
+ * svass_exception_irq: threaded irq handler for sva error interrupts
+ * @irq: interrupt number
+ * @data: data pointer passed during irq registration
+ *
+ * Once a error interrupt is received, it is not cleared, since
+ * clearing this interrupt will raise spurious interrupts unless
+ * CPE is reset.
+ */
+static irqreturn_t svass_exception_irq(int irq, void *data)
+{
+	struct wcd_cpe_core *core = data;
+	u8 status = 0;
+
+	if (!core || !CPE_ERR_IRQ_CB(core)) {
+		pr_err("%s: Invalid %s\n",
+		       __func__,
+		       (!core) ? "core" : "cdc control");
+		return IRQ_HANDLED;
+	}
+
+	core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
+			CPE_ERR_IRQ_STATUS, &status);
+
+	while (status != 0) {
+		if (status & core->irq_info.cpe_fatal_irqs) {
+			dev_err(core->dev,
+				"%s: CPE SSR event,err_status = 0x%02x\n",
+				__func__, status);
+			wcd_cpe_ssr_event(core, WCD_CPE_SSR_EVENT);
+			/*
+			 * If fatal interrupt is received,
+			 * trigger SSR and stop processing
+			 * further interrupts
+			 */
+			break;
+		}
+		/*
+		 * Mask the interrupt that was raised to
+		 * avoid spurious interrupts
+		 */
+		core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
+					CPE_ERR_IRQ_MASK, &status);
+
+		/* Clear only the interrupt that was raised */
+		core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
+					CPE_ERR_IRQ_CLEAR, &status);
+		dev_err(core->dev,
+			"%s: err_interrupt status = 0x%x\n",
+			__func__, status);
+
+		/* Read status for pending interrupts */
+		core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
+					CPE_ERR_IRQ_STATUS, &status);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * wcd_cpe_cmi_afe_cb: callback called on response to afe commands
+ * @param: parameter containing the response code, etc
+ *
+ * Process the request to the command sent to CPE and wakeup the
+ * command send wait.
+ */
+static void wcd_cpe_cmi_afe_cb(const struct cmi_api_notification *param)
+{
+	struct cmi_hdr *hdr;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	u8 port_id;
+
+	if (!param) {
+		pr_err("%s: param is null\n", __func__);
+		return;
+	}
+
+	if (param->event != CMI_API_MSG) {
+		pr_err("%s: unhandled event 0x%x\n",
+			__func__, param->event);
+		return;
+	}
+
+	pr_debug("%s: param->result = %d\n",
+		 __func__, param->result);
+
+	hdr = (struct cmi_hdr *) param->message;
+
+	/*
+	 * for AFE cmd response, port id is
+	 * stored at session id field of header
+	 */
+	port_id = CMI_HDR_GET_SESSION_ID(hdr);
+	if (port_id > WCD_CPE_AFE_MAX_PORTS) {
+		pr_err("%s: invalid port_id %d\n",
+			__func__, port_id);
+		return;
+	}
+
+	afe_port_d = &(afe_ports[port_id]);
+
+	if (hdr->opcode == CPE_CMI_BASIC_RSP_OPCODE) {
+
+		u8 *payload = ((u8 *)param->message) + (sizeof(struct cmi_hdr));
+		u8 result = payload[0];
+
+		afe_port_d->cmd_result = result;
+		complete(&afe_port_d->afe_cmd_complete);
+
+	} else if (hdr->opcode == CPE_AFE_PORT_CMDRSP_SHARED_MEM_ALLOC) {
+
+		struct cpe_cmdrsp_shmem_alloc *cmdrsp_shmem_alloc =
+			(struct cpe_cmdrsp_shmem_alloc *) param->message;
+
+		if (cmdrsp_shmem_alloc->addr == 0) {
+			pr_err("%s: Failed AFE shared mem alloc\n", __func__);
+			afe_port_d->cmd_result = CMI_SHMEM_ALLOC_FAILED;
+		} else {
+			pr_debug("%s AFE shared mem addr = 0x%x\n",
+				 __func__, cmdrsp_shmem_alloc->addr);
+			afe_port_d->mem_handle = cmdrsp_shmem_alloc->addr;
+			afe_port_d->cmd_result = 0;
+		}
+		complete(&afe_port_d->afe_cmd_complete);
+	}
+}
+
+/*
+ * wcd_cpe_initialize_afe_port_data: Initialize all AFE ports
+ *
+ * Initialize the data for all the afe ports. Assign the
+ * afe port state to INIT state.
+ */
+static void wcd_cpe_initialize_afe_port_data(void)
+{
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int i;
+
+	for (i = 0; i <= WCD_CPE_AFE_MAX_PORTS; i++) {
+		afe_port_d = &afe_ports[i];
+		afe_port_d->port_id = i;
+		init_completion(&afe_port_d->afe_cmd_complete);
+		afe_port_d->port_state = AFE_PORT_STATE_INIT;
+		mutex_init(&afe_port_d->afe_lock);
+	}
+}
+
+/*
+ * wcd_cpe_deinitialize_afe_port_data: De-initialize all AFE ports
+ *
+ * De-Initialize the data for all the afe ports. Assign the
+ * afe port state to DEINIT state.
+ */
+static void wcd_cpe_deinitialize_afe_port_data(void)
+{
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int i;
+
+	for (i = 0; i <= WCD_CPE_AFE_MAX_PORTS; i++) {
+		afe_port_d = &afe_ports[i];
+		afe_port_d->port_state = AFE_PORT_STATE_DEINIT;
+		mutex_destroy(&afe_port_d->afe_lock);
+	}
+}
+
+/*
+ * wcd_cpe_svc_event_cb: callback from cpe services, indicating
+ * CPE is online or offline.
+ * @param: parameter / payload for event to be notified
+ */
+static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param)
+{
+	struct snd_soc_codec *codec;
+	struct wcd_cpe_core *core;
+	struct cpe_svc_boot_event *boot_data;
+	bool active_sessions;
+
+	if (!param) {
+		pr_err("%s: Invalid event\n", __func__);
+		return;
+	}
+
+	codec = param->private_data;
+	if (!codec) {
+		pr_err("%s: Invalid handle to codec\n",
+			__func__);
+		return;
+	}
+
+	core = wcd_cpe_get_core_handle(codec);
+	if (!core) {
+		pr_err("%s: Invalid handle to core\n",
+			__func__);
+		return;
+	}
+
+	dev_dbg(core->dev,
+		"%s: event = 0x%x, ssr_type = 0x%x\n",
+		__func__, param->event, core->ssr_type);
+
+	switch (param->event) {
+	case CPE_SVC_BOOT:
+		boot_data = (struct cpe_svc_boot_event *)
+				param->payload;
+		core->sfr_buf_addr = boot_data->debug_address;
+		core->sfr_buf_size = boot_data->debug_buffer_size;
+		dev_dbg(core->dev,
+			"%s: CPE booted, sfr_addr = %d, sfr_size = %zu\n",
+			__func__, core->sfr_buf_addr,
+			core->sfr_buf_size);
+		break;
+	case CPE_SVC_ONLINE:
+		core->ssr_type = WCD_CPE_ACTIVE;
+		dev_dbg(core->dev, "%s CPE is now online\n",
+			 __func__);
+		complete(&core->online_compl);
+		break;
+	case CPE_SVC_OFFLINE:
+		/*
+		 * offline can happen during normal shutdown,
+		 * but we are interested in offline only during
+		 * SSR.
+		 */
+		if (core->ssr_type != WCD_CPE_SSR_EVENT &&
+		    core->ssr_type != WCD_CPE_BUS_DOWN_EVENT)
+			break;
+
+		active_sessions = wcd_cpe_lsm_session_active();
+		wcd_cpe_change_online_state(core, 0);
+		complete(&core->offline_compl);
+		dev_err(core->dev, "%s: CPE is now offline\n",
+			 __func__);
+		break;
+	case CPE_SVC_CMI_CLIENTS_DEREG:
+
+		/*
+		 * Only when either CPE SSR is in progress,
+		 * or the bus is down, we need to mark the CPE
+		 * as ready. In all other cases, this event is
+		 * ignored
+		 */
+		if (core->ssr_type == WCD_CPE_SSR_EVENT ||
+		    core->ssr_type == WCD_CPE_BUS_DOWN_EVENT)
+			wcd_cpe_set_and_complete(core,
+						 WCD_CPE_BLK_READY);
+		break;
+	default:
+		dev_err(core->dev,
+			"%s: unhandled notification\n",
+			__func__);
+		break;
+	}
+}
+
+/*
+ * wcd_cpe_cleanup_irqs: free the irq resources required by cpe
+ * @core: handle the cpe core
+ *
+ * This API will free the IRQs for CPE but does not mask the
+ * CPE interrupts. If masking is needed, it has to be done
+ * explicity by caller.
+ */
+static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core)
+{
+
+	struct snd_soc_codec *codec = core->codec;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+
+	wcd9xxx_free_irq(core_res,
+			 core->irq_info.cpe_engine_irq,
+			 core);
+	wcd9xxx_free_irq(core_res,
+			 core->irq_info.cpe_err_irq,
+			 core);
+
+}
+
+/*
+ * wcd_cpe_setup_sva_err_intr: setup the irqs for CPE
+ * @core: handle to wcd_cpe_core
+ * All interrupts needed for CPE are acquired. If any
+ * request_irq fails, then all irqs are free'd
+ */
+static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core)
+{
+	int ret;
+	struct snd_soc_codec *codec = core->codec;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+
+	ret = wcd9xxx_request_irq(core_res,
+				  core->irq_info.cpe_engine_irq,
+				  svass_engine_irq, "SVASS_Engine", core);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: Failed to request svass engine irq\n",
+			__func__);
+		goto fail_engine_irq;
+	}
+
+	/* Make sure all error interrupts are cleared */
+	if (CPE_ERR_IRQ_CB(core))
+		core->cpe_cdc_cb->cpe_err_irq_control(
+					core->codec,
+					CPE_ERR_IRQ_CLEAR,
+					NULL);
+
+	/* Enable required error interrupts */
+	if (CPE_ERR_IRQ_CB(core))
+		core->cpe_cdc_cb->cpe_err_irq_control(
+					core->codec,
+					CPE_ERR_IRQ_UNMASK,
+					NULL);
+
+	ret = wcd9xxx_request_irq(core_res,
+				  core->irq_info.cpe_err_irq,
+				  svass_exception_irq, "SVASS_Exception", core);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: Failed to request svass err irq\n",
+			__func__);
+		goto fail_exception_irq;
+	}
+
+	return 0;
+
+fail_exception_irq:
+	wcd9xxx_free_irq(core_res,
+			 core->irq_info.cpe_engine_irq, core);
+
+fail_engine_irq:
+	return ret;
+}
+
+static int wcd_cpe_get_cal_index(int32_t cal_type)
+{
+	int cal_index = -EINVAL;
+
+	if (cal_type == ULP_AFE_CAL_TYPE)
+		cal_index = WCD_CPE_LSM_CAL_AFE;
+	else if (cal_type == ULP_LSM_CAL_TYPE)
+		cal_index = WCD_CPE_LSM_CAL_LSM;
+	else if (cal_type == ULP_LSM_TOPOLOGY_ID_CAL_TYPE)
+		cal_index = WCD_CPE_LSM_CAL_TOPOLOGY_ID;
+	else
+		pr_err("%s: invalid cal_type %d\n",
+			__func__, cal_type);
+
+	return cal_index;
+}
+
+static int wcd_cpe_alloc_cal(int32_t cal_type, size_t data_size, void *data)
+{
+	int ret = 0;
+	int cal_index;
+
+	cal_index = wcd_cpe_get_cal_index(cal_type);
+	if (cal_index < 0) {
+		pr_err("%s: invalid caltype %d\n",
+			__func__, cal_type);
+		return -EINVAL;
+	}
+
+	ret = cal_utils_alloc_cal(data_size, data,
+				  core_d->cal_data[cal_index],
+				  0, NULL);
+	if (ret < 0)
+		pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
+			__func__, ret, cal_type);
+	return ret;
+}
+
+static int wcd_cpe_dealloc_cal(int32_t cal_type, size_t data_size,
+			   void *data)
+{
+	int ret = 0;
+	int cal_index;
+
+	cal_index = wcd_cpe_get_cal_index(cal_type);
+	if (cal_index < 0) {
+		pr_err("%s: invalid caltype %d\n",
+			__func__, cal_type);
+		return -EINVAL;
+	}
+
+	ret = cal_utils_dealloc_cal(data_size, data,
+				    core_d->cal_data[cal_index]);
+	if (ret < 0)
+		pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
+			__func__, ret, cal_type);
+	return ret;
+}
+
+static int wcd_cpe_set_cal(int32_t cal_type, size_t data_size, void *data)
+{
+	int ret = 0;
+	int cal_index;
+
+	cal_index = wcd_cpe_get_cal_index(cal_type);
+	if (cal_index < 0) {
+		pr_err("%s: invalid caltype %d\n",
+			__func__, cal_type);
+		return -EINVAL;
+	}
+
+	ret = cal_utils_set_cal(data_size, data,
+				core_d->cal_data[cal_index],
+				0, NULL);
+	if (ret < 0)
+		pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
+			__func__, ret, cal_type);
+	return ret;
+}
+
+static int wcd_cpe_cal_init(struct wcd_cpe_core *core)
+{
+	int ret = 0;
+
+	struct cal_type_info cal_type_info[] = {
+		{{ULP_AFE_CAL_TYPE,
+		 {wcd_cpe_alloc_cal, wcd_cpe_dealloc_cal, NULL,
+		  wcd_cpe_set_cal, NULL, NULL} },
+		{NULL, NULL, cal_utils_match_buf_num} },
+
+		{{ULP_LSM_CAL_TYPE,
+		 {wcd_cpe_alloc_cal, wcd_cpe_dealloc_cal, NULL,
+		  wcd_cpe_set_cal, NULL, NULL} },
+		 {NULL, NULL, cal_utils_match_buf_num} },
+
+		{{ULP_LSM_TOPOLOGY_ID_CAL_TYPE,
+		 {wcd_cpe_alloc_cal, wcd_cpe_dealloc_cal, NULL,
+		  wcd_cpe_set_cal, NULL, NULL} },
+		 {NULL, NULL, cal_utils_match_buf_num} },
+	};
+
+	ret = cal_utils_create_cal_types(WCD_CPE_LSM_CAL_MAX,
+					 core->cal_data,
+					 cal_type_info);
+	if (ret < 0)
+		pr_err("%s: could not create cal type!\n",
+		       __func__);
+	return ret;
+}
+
+/*
+ * wcd_cpe_enable: setup the cpe interrupts and schedule
+ *	the work to download image and bootup the CPE.
+ * core: handle to cpe core structure
+ */
+static int wcd_cpe_vote(struct wcd_cpe_core *core,
+		bool enable)
+{
+	int ret = 0;
+
+	if (!core) {
+		pr_err("%s: Invalid handle to core\n",
+			__func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	dev_dbg(core->dev,
+		"%s: enter, enable = %s, cpe_users = %u\n",
+		__func__, (enable ? "true" : "false"),
+		core->cpe_users);
+
+	if (enable) {
+		core->cpe_users++;
+		if (core->cpe_users == 1) {
+			ret = wcd_cpe_enable(core, enable);
+			if (ret) {
+				dev_err(core->dev,
+					"%s: CPE enable failed, err = %d\n",
+					__func__, ret);
+				goto done;
+			}
+		} else {
+			dev_dbg(core->dev,
+				"%s: cpe already enabled, users = %u\n",
+				__func__, core->cpe_users);
+			goto done;
+		}
+	} else {
+		core->cpe_users--;
+		if (core->cpe_users == 0) {
+			ret = wcd_cpe_enable(core, enable);
+			if (ret) {
+				dev_err(core->dev,
+					"%s: CPE disable failed, err = %d\n",
+					__func__, ret);
+				goto done;
+			}
+		} else {
+			dev_dbg(core->dev,
+				"%s: %u valid users on cpe\n",
+				__func__, core->cpe_users);
+			goto done;
+		}
+	}
+
+	dev_dbg(core->dev,
+		"%s: leave, enable = %s, cpe_users = %u\n",
+		__func__, (enable ? "true" : "false"),
+		core->cpe_users);
+
+done:
+	return ret;
+}
+
+static int wcd_cpe_debugfs_init(struct wcd_cpe_core *core)
+{
+	int rc = 0;
+
+	struct dentry *dir = debugfs_create_dir("wcd_cpe", NULL);
+
+	if (IS_ERR_OR_NULL(dir)) {
+		dir = NULL;
+		rc = -ENODEV;
+		goto err_create_dir;
+	}
+
+	if (!debugfs_create_u32("ramdump_enable", 0644,
+				dir, &ramdump_enable)) {
+		dev_err(core->dev, "%s: Failed to create debugfs node %s\n",
+			__func__, "ramdump_enable");
+		rc = -ENODEV;
+		goto err_create_entry;
+	}
+
+	if (!debugfs_create_file("cpe_ftm_test_trigger", 0200,
+				dir, core, &cpe_ftm_test_trigger_fops)) {
+		dev_err(core->dev, "%s: Failed to create debugfs node %s\n",
+			__func__, "cpe_ftm_test_trigger");
+		rc = -ENODEV;
+		goto err_create_entry;
+	}
+
+	if (!debugfs_create_u32("cpe_ftm_test_status", 0444,
+				dir, &cpe_ftm_test_status)) {
+		dev_err(core->dev, "%s: Failed to create debugfs node %s\n",
+			__func__, "cpe_ftm_test_status");
+		rc = -ENODEV;
+		goto err_create_entry;
+	}
+
+err_create_entry:
+	debugfs_remove(dir);
+
+err_create_dir:
+	return rc;
+}
+
+static ssize_t fw_name_show(struct wcd_cpe_core *core, char *buf)
+{
+	return snprintf(buf, WCD_CPE_IMAGE_FNAME_MAX, "%s",
+			core->dyn_fname);
+}
+
+static ssize_t fw_name_store(struct wcd_cpe_core *core,
+		const char *buf, ssize_t count)
+{
+	int copy_count = count;
+	const char *pos;
+
+	pos = memchr(buf, '\n', count);
+	if (pos)
+		copy_count = pos - buf;
+
+	if (copy_count > (WCD_CPE_IMAGE_FNAME_MAX - 1)) {
+		dev_err(core->dev,
+			"%s: Invalid length %d, max allowed %d\n",
+			__func__, copy_count, WCD_CPE_IMAGE_FNAME_MAX - 1);
+		return -EINVAL;
+	}
+
+	strlcpy(core->dyn_fname, buf, copy_count + 1);
+
+	return count;
+}
+
+WCD_CPE_ATTR(fw_name, 0660, fw_name_show, fw_name_store);
+
+static ssize_t wcd_cpe_sysfs_show(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	struct wcd_cpe_attribute *cpe_attr = to_wcd_cpe_attr(attr);
+	struct wcd_cpe_core *core = kobj_to_cpe_core(kobj);
+	ssize_t ret = -EINVAL;
+
+	if (core && cpe_attr->show)
+		ret = cpe_attr->show(core, buf);
+
+	return ret;
+}
+
+static ssize_t wcd_cpe_sysfs_store(struct kobject *kobj,
+		struct attribute *attr, const char *buf,
+		size_t count)
+{
+	struct wcd_cpe_attribute *cpe_attr = to_wcd_cpe_attr(attr);
+	struct wcd_cpe_core *core = kobj_to_cpe_core(kobj);
+	ssize_t ret = -EINVAL;
+
+	if (core && cpe_attr->store)
+		ret = cpe_attr->store(core, buf, count);
+
+	return ret;
+}
+
+static const struct sysfs_ops wcd_cpe_sysfs_ops = {
+	.show = wcd_cpe_sysfs_show,
+	.store = wcd_cpe_sysfs_store,
+};
+
+static struct kobj_type wcd_cpe_ktype = {
+	.sysfs_ops = &wcd_cpe_sysfs_ops,
+};
+
+static int wcd_cpe_sysfs_init(struct wcd_cpe_core *core, int id)
+{
+	char sysfs_dir_name[WCD_CPE_SYSFS_DIR_MAX_LENGTH];
+	int rc = 0;
+
+	snprintf(sysfs_dir_name, WCD_CPE_SYSFS_DIR_MAX_LENGTH,
+		 "%s%d", "wcd_cpe", id);
+
+	rc = kobject_init_and_add(&core->cpe_kobj, &wcd_cpe_ktype,
+				  kernel_kobj,
+				  sysfs_dir_name);
+	if (unlikely(rc)) {
+		dev_err(core->dev,
+			"%s: Failed to add kobject %s, err = %d\n",
+			__func__, sysfs_dir_name, rc);
+		goto done;
+	}
+
+	rc = sysfs_create_file(&core->cpe_kobj, &cpe_attr_fw_name.attr);
+	if (rc) {
+		dev_err(core->dev,
+			"%s: Failed to fw_name sysfs entry to %s\n",
+			__func__, sysfs_dir_name);
+		goto fail_create_file;
+	}
+
+	return 0;
+
+fail_create_file:
+	kobject_put(&core->cpe_kobj);
+done:
+	return rc;
+}
+
+static ssize_t cpe_ftm_test_trigger(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct wcd_cpe_core *core = file->private_data;
+	int ret = 0;
+
+	/* Enable the clks for cpe */
+	ret = wcd_cpe_enable_cpe_clks(core, true);
+	if (ret < 0) {
+		dev_err(core->dev,
+			"%s: CPE clk enable failed, err = %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	/* Get the CPE_STATUS */
+	ret = cpe_svc_ftm_test(core->cpe_handle, &cpe_ftm_test_status);
+	if (ret < 0) {
+		dev_err(core->dev,
+			"%s: CPE FTM test failed, err = %d\n",
+			__func__, ret);
+		if (ret == CPE_SVC_BUSY) {
+			cpe_ftm_test_status = 1;
+			ret = 0;
+		}
+	}
+
+	/* Disable the clks for cpe */
+	ret = wcd_cpe_enable_cpe_clks(core, false);
+	if (ret < 0) {
+		dev_err(core->dev,
+			"%s: CPE clk disable failed, err = %d\n",
+			__func__, ret);
+	}
+
+done:
+	if (ret < 0)
+		return ret;
+	else
+		return count;
+}
+
+static int wcd_cpe_validate_params(
+	struct snd_soc_codec *codec,
+	struct wcd_cpe_params *params)
+{
+
+	if (!codec) {
+		pr_err("%s: Invalid codec\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!params) {
+		dev_err(codec->dev,
+			"%s: No params supplied for codec %s\n",
+			__func__, codec->component.name);
+		return -EINVAL;
+	}
+
+	if (!params->codec || !params->get_cpe_core ||
+	    !params->cdc_cb) {
+		dev_err(codec->dev,
+			"%s: Invalid params for codec %s\n",
+			__func__, codec->component.name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * wcd_cpe_init: Initialize CPE related structures
+ * @img_fname: filename for firmware image
+ * @codec: handle to codec requesting for image download
+ * @params: parameter structure passed from caller
+ *
+ * This API will initialize the cpe core but will not
+ * download the image or boot the cpe core.
+ */
+struct wcd_cpe_core *wcd_cpe_init(const char *img_fname,
+	struct snd_soc_codec *codec,
+	struct wcd_cpe_params *params)
+{
+	struct wcd_cpe_core *core;
+	int ret = 0;
+	struct snd_card *card = NULL;
+	struct snd_info_entry *entry = NULL;
+	char proc_name[WCD_CPE_STATE_MAX_LEN];
+	const char *cpe_name = "cpe";
+	const char *state_name = "_state";
+	const struct cpe_svc_hw_cfg *hw_info;
+	int id = 0;
+
+	if (wcd_cpe_validate_params(codec, params))
+		return NULL;
+
+	core = kzalloc(sizeof(struct wcd_cpe_core), GFP_KERNEL);
+	if (!core)
+		return NULL;
+
+	snprintf(core->fname, sizeof(core->fname), "%s", img_fname);
+	strlcpy(core->dyn_fname, core->fname, WCD_CPE_IMAGE_FNAME_MAX);
+
+	wcd_get_cpe_core = params->get_cpe_core;
+
+	core->codec = params->codec;
+	core->dev = params->codec->dev;
+	core->cpe_debug_mode = params->dbg_mode;
+
+	core->cdc_info.major_version = params->cdc_major_ver;
+	core->cdc_info.minor_version = params->cdc_minor_ver;
+	core->cdc_info.id = params->cdc_id;
+
+	core->cpe_cdc_cb = params->cdc_cb;
+
+	memcpy(&core->irq_info, &params->cdc_irq_info,
+	       sizeof(core->irq_info));
+
+	INIT_WORK(&core->load_fw_work, wcd_cpe_load_fw_image);
+	INIT_WORK(&core->ssr_work, wcd_cpe_ssr_work);
+	init_completion(&core->offline_compl);
+	init_completion(&core->ready_compl);
+	init_completion(&core->online_compl);
+	init_waitqueue_head(&core->ssr_entry.offline_poll_wait);
+	mutex_init(&core->ssr_lock);
+	core->cpe_users = 0;
+	core->cpe_clk_ref = 0;
+
+	/*
+	 * By default, during probe, it is assumed that
+	 * both CPE hardware block and underlying bus to codec
+	 * are ready
+	 */
+	core->ready_status = WCD_CPE_READY_TO_DLOAD;
+
+	core->cpe_handle = cpe_svc_initialize(NULL, &core->cdc_info,
+					      params->cpe_svc_params);
+	if (!core->cpe_handle) {
+		dev_err(core->dev,
+			"%s: failed to initialize cpe services\n",
+			__func__);
+		goto fail_cpe_initialize;
+	}
+
+	core->cpe_reg_handle = cpe_svc_register(core->cpe_handle,
+					wcd_cpe_svc_event_cb,
+					CPE_SVC_ONLINE | CPE_SVC_OFFLINE |
+					CPE_SVC_BOOT |
+					CPE_SVC_CMI_CLIENTS_DEREG,
+					"codec cpe handler");
+	if (!core->cpe_reg_handle) {
+		dev_err(core->dev,
+			"%s: failed to register cpe service\n",
+			__func__);
+		goto fail_cpe_register;
+	}
+
+	card = codec->component.card->snd_card;
+	snprintf(proc_name, (sizeof("cpe") + sizeof("_state") +
+		 sizeof(id) - 2), "%s%d%s", cpe_name, id, state_name);
+	entry = snd_info_create_card_entry(card, proc_name,
+					   card->proc_root);
+	if (entry) {
+		core->ssr_entry.entry = entry;
+		core->ssr_entry.offline = 1;
+		entry->size = WCD_CPE_STATE_MAX_LEN;
+		entry->content = SNDRV_INFO_CONTENT_DATA;
+		entry->c.ops = &wcd_cpe_state_proc_ops;
+		entry->private_data = core;
+		ret = snd_info_register(entry);
+		if (ret < 0) {
+			dev_err(core->dev,
+				"%s: snd_info_register failed (%d)\n",
+				 __func__, ret);
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	} else {
+		dev_err(core->dev,
+			"%s: Failed to create CPE SSR status entry\n",
+			__func__);
+		/*
+		 * Even if SSR entry creation fails, continue
+		 * with image download
+		 */
+	}
+
+	core_d = core;
+	ret = wcd_cpe_cal_init(core);
+	if (ret < 0) {
+		dev_err(core->dev,
+			"%s: CPE calibration init failed, err = %d\n",
+			__func__, ret);
+		goto fail_cpe_reset;
+	}
+
+	wcd_cpe_debugfs_init(core);
+
+	wcd_cpe_sysfs_init(core, id);
+
+	hw_info = cpe_svc_get_hw_cfg(core->cpe_handle);
+	if (!hw_info) {
+		dev_err(core->dev,
+			"%s: hw info not available\n",
+			__func__);
+		goto schedule_dload_work;
+	} else {
+		core->hw_info.dram_offset = hw_info->DRAM_offset;
+		core->hw_info.dram_size = hw_info->DRAM_size;
+		core->hw_info.iram_offset = hw_info->IRAM_offset;
+		core->hw_info.iram_size = hw_info->IRAM_size;
+	}
+
+	/* Setup the ramdump device and buffer */
+	core->cpe_ramdump_dev = create_ramdump_device("cpe",
+						      core->dev);
+	if (!core->cpe_ramdump_dev) {
+		dev_err(core->dev,
+			"%s: Failed to create ramdump device\n",
+			__func__);
+		goto schedule_dload_work;
+	}
+
+	arch_setup_dma_ops(core->dev, 0, 0, NULL, 0);
+	core->cpe_dump_v_addr = dma_alloc_coherent(core->dev,
+						   core->hw_info.dram_size,
+						   &core->cpe_dump_addr,
+						   GFP_KERNEL);
+	if (!core->cpe_dump_v_addr) {
+		dev_err(core->dev,
+			"%s: Failed to alloc memory for cpe dump, size = %zd\n",
+			__func__, core->hw_info.dram_size);
+		goto schedule_dload_work;
+	} else {
+		memset(core->cpe_dump_v_addr, 0, core->hw_info.dram_size);
+	}
+
+schedule_dload_work:
+	core->ssr_type = WCD_CPE_INITIALIZED;
+	schedule_work(&core->load_fw_work);
+	return core;
+
+fail_cpe_reset:
+	cpe_svc_deregister(core->cpe_handle, core->cpe_reg_handle);
+
+fail_cpe_register:
+	cpe_svc_deinitialize(core->cpe_handle);
+
+fail_cpe_initialize:
+	kfree(core);
+	return NULL;
+}
+EXPORT_SYMBOL(wcd_cpe_init);
+
+/*
+ * wcd_cpe_cmi_lsm_callback: callback called from cpe services
+ *			     to notify command response for lsm
+ *			     service
+ * @param: param containing the response code and status
+ *
+ * This callback is registered with cpe services while registering
+ * the LSM service
+ */
+static void wcd_cpe_cmi_lsm_callback(const struct cmi_api_notification *param)
+{
+	struct cmi_hdr *hdr;
+	struct cpe_lsm_session *lsm_session;
+	u8 session_id;
+
+	if (!param) {
+		pr_err("%s: param is null\n", __func__);
+		return;
+	}
+
+	if (param->event != CMI_API_MSG) {
+		pr_err("%s: unhandled event 0x%x\n", __func__, param->event);
+		return;
+	}
+
+	hdr = (struct cmi_hdr *) param->message;
+	session_id = CMI_HDR_GET_SESSION_ID(hdr);
+
+	if (session_id > WCD_CPE_LSM_MAX_SESSIONS) {
+		pr_err("%s: invalid lsm session id = %d\n",
+			__func__, session_id);
+		return;
+	}
+
+	lsm_session = lsm_sessions[session_id];
+
+	if (hdr->opcode == CPE_CMI_BASIC_RSP_OPCODE) {
+
+		u8 *payload = ((u8 *)param->message) + (sizeof(struct cmi_hdr));
+		u8 result = payload[0];
+
+		lsm_session->cmd_err_code = result;
+		complete(&lsm_session->cmd_comp);
+
+	} else if (hdr->opcode == CPE_LSM_SESSION_CMDRSP_SHARED_MEM_ALLOC) {
+
+		struct cpe_cmdrsp_shmem_alloc *cmdrsp_shmem_alloc =
+			(struct cpe_cmdrsp_shmem_alloc *) param->message;
+
+		if (cmdrsp_shmem_alloc->addr == 0) {
+			pr_err("%s: Failed LSM shared mem alloc\n", __func__);
+			lsm_session->cmd_err_code = CMI_SHMEM_ALLOC_FAILED;
+
+		} else {
+
+			pr_debug("%s LSM shared mem addr = 0x%x\n",
+				__func__, cmdrsp_shmem_alloc->addr);
+			lsm_session->lsm_mem_handle = cmdrsp_shmem_alloc->addr;
+			lsm_session->cmd_err_code = 0;
+		}
+
+		complete(&lsm_session->cmd_comp);
+
+	} else if (hdr->opcode == CPE_LSM_SESSION_EVENT_DETECTION_STATUS_V2) {
+
+		struct cpe_lsm_event_detect_v2 *event_detect_v2 =
+			(struct cpe_lsm_event_detect_v2 *) param->message;
+
+		if (!lsm_session->priv_d) {
+			pr_err("%s: private data is not present\n",
+				__func__);
+			return;
+		}
+
+		pr_debug("%s: event payload, status = %u, size = %u\n",
+			__func__, event_detect_v2->detection_status,
+			event_detect_v2->size);
+
+		if (lsm_session->event_cb)
+			lsm_session->event_cb(
+				lsm_session->priv_d,
+				event_detect_v2->detection_status,
+				event_detect_v2->size,
+				event_detect_v2->payload);
+	}
+}
+
+/*
+ * wcd_cpe_cmi_send_lsm_msg: send a message to lsm service
+ * @core: handle to cpe core
+ * @session: session on which to send the message
+ * @message: actual message containing header and payload
+ *
+ * Sends message to lsm service for specified session and wait
+ * for response back on the message.
+ * should be called after acquiring session specific mutex
+ */
+static int wcd_cpe_cmi_send_lsm_msg(
+			struct wcd_cpe_core *core,
+			struct cpe_lsm_session *session,
+			void *message)
+{
+	int ret = 0;
+	struct cmi_hdr *hdr = message;
+
+	pr_debug("%s: sending message with opcode 0x%x\n",
+		 __func__, hdr->opcode);
+
+	if (unlikely(!wcd_cpe_is_online_state(core))) {
+		dev_err(core->dev,
+			"%s: MSG not sent, CPE offline\n",
+			 __func__);
+		goto done;
+	}
+
+	if (CMI_HDR_GET_OBM_FLAG(hdr))
+		wcd_cpe_bus_vote_max_bw(core, true);
+
+	reinit_completion(&session->cmd_comp);
+	ret = cmi_send_msg(message);
+	if (ret) {
+		pr_err("%s: msg opcode (0x%x) send failed (%d)\n",
+			__func__, hdr->opcode, ret);
+		goto rel_bus_vote;
+	}
+
+	ret = wait_for_completion_timeout(&session->cmd_comp,
+					  CMI_CMD_TIMEOUT);
+	if (ret > 0) {
+		pr_debug("%s: command 0x%x, received response 0x%x\n",
+			__func__, hdr->opcode, session->cmd_err_code);
+		if (session->cmd_err_code == CMI_SHMEM_ALLOC_FAILED)
+			session->cmd_err_code = CPE_ENOMEMORY;
+		if (session->cmd_err_code > 0)
+			pr_err("%s: CPE returned error[%s]\n",
+				__func__, cpe_err_get_err_str(
+				session->cmd_err_code));
+		ret = cpe_err_get_lnx_err_code(session->cmd_err_code);
+		goto rel_bus_vote;
+	} else {
+		pr_err("%s: command (0x%x) send timed out\n",
+			__func__, hdr->opcode);
+		ret = -ETIMEDOUT;
+		goto rel_bus_vote;
+	}
+
+
+rel_bus_vote:
+
+	if (CMI_HDR_GET_OBM_FLAG(hdr))
+		wcd_cpe_bus_vote_max_bw(core, false);
+
+done:
+	return ret;
+}
+
+
+/*
+ * fill_cmi_header: fill the cmi header with specified values
+ *
+ * @hdr: header to be updated with values
+ * @session_id: session id of the header,
+ *		in case of AFE service it is port_id
+ * @service_id: afe/lsm, etc
+ * @version: update the version field in header
+ * @payload_size: size of the payload following after header
+ * @opcode: opcode of the message
+ * @obm_flag: indicates if this header is for obm message
+ *
+ */
+static int fill_cmi_header(struct cmi_hdr *hdr,
+			   u8 session_id, u8 service_id,
+			   bool version, u8 payload_size,
+			   u16 opcode, bool obm_flag)
+{
+	/* sanitize the data */
+	if (!IS_VALID_SESSION_ID(session_id) ||
+	    !IS_VALID_SERVICE_ID(service_id) ||
+	    !IS_VALID_PLD_SIZE(payload_size)) {
+		pr_err("Invalid header creation request\n");
+		return -EINVAL;
+	}
+
+	CMI_HDR_SET_SESSION(hdr, session_id);
+	CMI_HDR_SET_SERVICE(hdr, service_id);
+	if (version)
+		CMI_HDR_SET_VERSION(hdr, 1);
+	else
+		CMI_HDR_SET_VERSION(hdr, 0);
+
+	CMI_HDR_SET_PAYLOAD_SIZE(hdr, payload_size);
+
+	hdr->opcode = opcode;
+
+	if (obm_flag)
+		CMI_HDR_SET_OBM(hdr, CMI_OBM_FLAG_OUT_BAND);
+	else
+		CMI_HDR_SET_OBM(hdr, CMI_OBM_FLAG_IN_BAND);
+
+	return 0;
+}
+
+/*
+ * fill_lsm_cmd_header_v0_inband:
+ *	Given the header, fill the header with information
+ *	for lsm service, version 0 and inband message
+ * @hdr: the cmi header to be filled.
+ * @session_id: ID for the lsm session
+ * @payload_size: size for cmi message payload
+ * @opcode: opcode for cmi message
+ */
+static int fill_lsm_cmd_header_v0_inband(struct cmi_hdr *hdr,
+		u8 session_id, u8 payload_size, u16 opcode)
+{
+	return fill_cmi_header(hdr, session_id,
+			       CMI_CPE_LSM_SERVICE_ID, false,
+			       payload_size, opcode, false);
+}
+
+/*
+ * wcd_cpe_is_valid_lsm_session:
+ *	Check session parameters to identify validity for the sesion
+ * @core: handle to cpe core
+ * @session: handle to the lsm session
+ * @func: invoking function to be printed in error logs
+ */
+static int wcd_cpe_is_valid_lsm_session(struct wcd_cpe_core *core,
+		struct cpe_lsm_session *session,
+		const char *func)
+{
+	if (unlikely(IS_ERR_OR_NULL(core))) {
+		pr_err("%s: invalid handle to core\n",
+			func);
+		return -EINVAL;
+	}
+
+	if (unlikely(IS_ERR_OR_NULL(session))) {
+		dev_err(core->dev, "%s: invalid session\n",
+			func);
+		return -EINVAL;
+	}
+
+	if (session->id > WCD_CPE_LSM_MAX_SESSIONS) {
+		dev_err(core->dev, "%s: invalid session id (%u)\n",
+			func, session->id);
+		return -EINVAL;
+	}
+
+	dev_dbg(core->dev, "%s: session_id = %u\n",
+		func, session->id);
+	return 0;
+}
+
+static int wcd_cpe_cmd_lsm_open_tx_v2(
+	struct wcd_cpe_core *core,
+	struct cpe_lsm_session *session)
+{
+	struct cpe_lsm_cmd_open_tx_v2 cmd_open_tx_v2;
+	struct cal_block_data *top_cal = NULL;
+	struct audio_cal_info_lsm_top *lsm_top;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	if (core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID] == NULL) {
+		dev_err(core->dev,
+			"%s: LSM_TOPOLOGY cal not allocated!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID]->lock);
+	top_cal = cal_utils_get_only_cal_block(
+			core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID]);
+	if (!top_cal) {
+		dev_err(core->dev,
+			"%s: Failed to get LSM TOPOLOGY cal block\n",
+			__func__);
+		ret = -EINVAL;
+		goto unlock_cal_mutex;
+	}
+
+	lsm_top = (struct audio_cal_info_lsm_top *)
+			top_cal->cal_info;
+
+	if (!lsm_top) {
+		dev_err(core->dev,
+			"%s: cal_info for LSM_TOPOLOGY not found\n",
+			__func__);
+		ret = -EINVAL;
+		goto unlock_cal_mutex;
+	}
+
+	dev_dbg(core->dev,
+		"%s: topology_id = 0x%x, acdb_id = 0x%x, app_type = 0x%x\n",
+		__func__, lsm_top->topology, lsm_top->acdb_id,
+		lsm_top->app_type);
+
+	if (lsm_top->topology == 0) {
+		dev_err(core->dev,
+			"%s: topology id not sent for app_type 0x%x\n",
+			__func__, lsm_top->app_type);
+		ret = -EINVAL;
+		goto unlock_cal_mutex;
+	}
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_open_tx_v2, 0, sizeof(struct cpe_lsm_cmd_open_tx_v2));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_open_tx_v2.hdr,
+				session->id, OPEN_V2_CMD_PAYLOAD_SIZE,
+				CPE_LSM_SESSION_CMD_OPEN_TX_V2)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	cmd_open_tx_v2.topology_id = lsm_top->topology;
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_open_tx_v2);
+	if (ret)
+		dev_err(core->dev,
+			"%s: failed to send open_tx_v2 cmd, err = %d\n",
+			__func__, ret);
+	else
+		session->is_topology_used = true;
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+
+unlock_cal_mutex:
+	mutex_unlock(&core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID]->lock);
+	return ret;
+}
+
+/*
+ * wcd_cpe_cmd_lsm_open_tx: compose and send lsm open command
+ * @core_handle: handle to cpe core
+ * @session: session for which the command needs to be sent
+ * @app_id: application id part of the command
+ * @sample_rate: sample rate for this session
+ */
+static int wcd_cpe_cmd_lsm_open_tx(void *core_handle,
+		struct cpe_lsm_session *session,
+		u16 app_id, u16 sample_rate)
+{
+	struct cpe_lsm_cmd_open_tx cmd_open_tx;
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	/* Try to open with topology first */
+	ret = wcd_cpe_cmd_lsm_open_tx_v2(core, session);
+	if (!ret)
+		goto done;
+
+	dev_dbg(core->dev, "%s: Try open_tx without topology\n",
+		__func__);
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_open_tx, 0, sizeof(struct cpe_lsm_cmd_open_tx));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_open_tx.hdr,
+				session->id, OPEN_CMD_PAYLOAD_SIZE,
+				CPE_LSM_SESSION_CMD_OPEN_TX)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	cmd_open_tx.app_id = app_id;
+	cmd_open_tx.sampling_rate = sample_rate;
+
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_open_tx);
+	if (ret)
+		dev_err(core->dev,
+			"%s: failed to send open_tx cmd, err = %d\n",
+			__func__, ret);
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+done:
+	return ret;
+}
+
+/*
+ * wcd_cpe_cmd_close_tx: compose and send lsm close command
+ * @core_handle: handle to cpe core
+ * @session: session for which the command needs to be sent
+ */
+static int wcd_cpe_cmd_lsm_close_tx(void *core_handle,
+			struct cpe_lsm_session *session)
+{
+	struct cmi_hdr cmd_close_tx;
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_close_tx, 0, sizeof(cmd_close_tx));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_close_tx, session->id,
+			    0, CPE_LSM_SESSION_CMD_CLOSE_TX)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_close_tx);
+	if (ret)
+		dev_err(core->dev,
+			"%s: lsm close_tx cmd failed, err = %d\n",
+			__func__, ret);
+	else
+		session->is_topology_used = false;
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+/*
+ * wcd_cpe_cmd_shmem_alloc: compose and send lsm shared
+ *			    memory allocation command
+ * @core_handle: handle to cpe core
+ * @session: session for which the command needs to be sent
+ * @size: size of memory to be allocated
+ */
+static int wcd_cpe_cmd_lsm_shmem_alloc(void *core_handle,
+			struct cpe_lsm_session *session,
+			u32 size)
+{
+	struct cpe_cmd_shmem_alloc cmd_shmem_alloc;
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_shmem_alloc, 0, sizeof(cmd_shmem_alloc));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_shmem_alloc.hdr, session->id,
+			    SHMEM_ALLOC_CMD_PLD_SIZE,
+			    CPE_LSM_SESSION_CMD_SHARED_MEM_ALLOC)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	cmd_shmem_alloc.size = size;
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_shmem_alloc);
+	if (ret)
+		dev_err(core->dev,
+			"%s: lsm_shmem_alloc cmd send fail, %d\n",
+			__func__, ret);
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+/*
+ * wcd_cpe_cmd_lsm_shmem_dealloc: deallocate the shared memory
+ *				  for the specified session
+ * @core_handle: handle to cpe core
+ * @session: session for which memory needs to be deallocated.
+ */
+static int wcd_cpe_cmd_lsm_shmem_dealloc(void *core_handle,
+		struct cpe_lsm_session *session)
+{
+	struct cpe_cmd_shmem_dealloc cmd_dealloc;
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_dealloc, 0, sizeof(cmd_dealloc));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_dealloc.hdr, session->id,
+			    SHMEM_DEALLOC_CMD_PLD_SIZE,
+			    CPE_LSM_SESSION_CMD_SHARED_MEM_DEALLOC)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	cmd_dealloc.addr = session->lsm_mem_handle;
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_dealloc);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: lsm_shmem_dealloc cmd failed, rc %d\n",
+			__func__, ret);
+		goto end_ret;
+	}
+
+	memset(&session->lsm_mem_handle, 0,
+	       sizeof(session->lsm_mem_handle));
+
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+/*
+ * wcd_cpe_send_lsm_cal: send the calibration for lsm service
+ *			      from acdb to the cpe
+ * @core: handle to cpe core
+ * @session: session for which the calibration needs to be set.
+ */
+static int wcd_cpe_send_lsm_cal(
+			struct wcd_cpe_core *core,
+			struct cpe_lsm_session *session)
+{
+
+	u8 *msg_pld;
+	struct cmi_hdr *hdr;
+	struct cal_block_data *lsm_cal = NULL;
+	void *inb_msg;
+	int rc = 0;
+
+	if (core->cal_data[WCD_CPE_LSM_CAL_LSM] == NULL) {
+		pr_err("%s: LSM cal not allocated!\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->cal_data[WCD_CPE_LSM_CAL_LSM]->lock);
+	lsm_cal = cal_utils_get_only_cal_block(
+			core->cal_data[WCD_CPE_LSM_CAL_LSM]);
+	if (!lsm_cal) {
+		pr_err("%s: failed to get lsm cal block\n", __func__);
+		rc = -EINVAL;
+		goto unlock_cal_mutex;
+	}
+
+	if (lsm_cal->cal_data.size == 0) {
+		dev_dbg(core->dev, "%s: No LSM cal to send\n",
+			__func__);
+		rc = 0;
+		goto unlock_cal_mutex;
+	}
+
+	inb_msg = kzalloc(sizeof(struct cmi_hdr) + lsm_cal->cal_data.size,
+			  GFP_KERNEL);
+	if (!inb_msg) {
+		rc = -ENOMEM;
+		goto unlock_cal_mutex;
+	}
+
+	hdr = (struct cmi_hdr *) inb_msg;
+
+	rc = fill_lsm_cmd_header_v0_inband(hdr, session->id,
+			lsm_cal->cal_data.size,
+			CPE_LSM_SESSION_CMD_SET_PARAMS);
+	if (rc) {
+		pr_err("%s: invalid params for header, err = %d\n",
+			__func__, rc);
+		goto free_msg;
+	}
+
+	msg_pld = ((u8 *) inb_msg) + sizeof(struct cmi_hdr);
+	memcpy(msg_pld, lsm_cal->cal_data.kvaddr,
+	       lsm_cal->cal_data.size);
+
+	rc = wcd_cpe_cmi_send_lsm_msg(core, session, inb_msg);
+	if (rc)
+		pr_err("%s: acdb lsm_params send failed, err = %d\n",
+			__func__, rc);
+
+free_msg:
+	kfree(inb_msg);
+
+unlock_cal_mutex:
+	mutex_unlock(&core->cal_data[WCD_CPE_LSM_CAL_LSM]->lock);
+	return rc;
+
+}
+
+static void wcd_cpe_set_param_data(struct cpe_param_data *param_d,
+		struct cpe_lsm_ids *ids, u32 p_size,
+		u32 set_param_cmd)
+{
+	param_d->module_id = ids->module_id;
+	param_d->param_id = ids->param_id;
+
+	switch (set_param_cmd) {
+	case CPE_LSM_SESSION_CMD_SET_PARAMS_V2:
+		param_d->p_size.param_size = p_size;
+		break;
+	case CPE_LSM_SESSION_CMD_SET_PARAMS:
+	default:
+		param_d->p_size.sr.param_size =
+			(u16) p_size;
+		param_d->p_size.sr.reserved = 0;
+		break;
+	}
+}
+
+static int wcd_cpe_send_param_epd_thres(struct wcd_cpe_core *core,
+		struct cpe_lsm_session *session,
+		void *data, struct cpe_lsm_ids *ids)
+{
+	struct snd_lsm_ep_det_thres *ep_det_data;
+	struct cpe_lsm_param_epd_thres epd_cmd;
+	struct cmi_hdr *msg_hdr = &epd_cmd.hdr;
+	struct cpe_param_data *param_d =
+				&epd_cmd.param;
+	int rc;
+
+	memset(&epd_cmd, 0, sizeof(epd_cmd));
+	ep_det_data = (struct snd_lsm_ep_det_thres *) data;
+	if (fill_lsm_cmd_header_v0_inband(msg_hdr,
+				session->id,
+				CPE_CMD_EPD_THRES_PLD_SIZE,
+				CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		rc = -EINVAL;
+		goto err_ret;
+	}
+
+	wcd_cpe_set_param_data(param_d, ids,
+			       CPE_EPD_THRES_PARAM_SIZE,
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	epd_cmd.minor_version = 1;
+	epd_cmd.epd_begin = ep_det_data->epd_begin;
+	epd_cmd.epd_end = ep_det_data->epd_end;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	rc = wcd_cpe_cmi_send_lsm_msg(core, session, &epd_cmd);
+	if (unlikely(rc))
+		dev_err(core->dev,
+			"%s: set_param(EPD Threshold) failed, rc %dn",
+			__func__, rc);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+err_ret:
+	return rc;
+}
+
+static int wcd_cpe_send_param_opmode(struct wcd_cpe_core *core,
+		struct cpe_lsm_session *session,
+		void *data, struct cpe_lsm_ids *ids)
+{
+	struct snd_lsm_detect_mode *opmode_d;
+	struct cpe_lsm_param_opmode opmode_cmd;
+	struct cmi_hdr *msg_hdr = &opmode_cmd.hdr;
+	struct cpe_param_data *param_d =
+				&opmode_cmd.param;
+	int rc;
+
+	memset(&opmode_cmd, 0, sizeof(opmode_cmd));
+	opmode_d = (struct snd_lsm_detect_mode *) data;
+	if (fill_lsm_cmd_header_v0_inband(msg_hdr,
+				session->id,
+				CPE_CMD_OPMODE_PLD_SIZE,
+				CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		rc = -EINVAL;
+		goto err_ret;
+	}
+
+	wcd_cpe_set_param_data(param_d, ids,
+			       CPE_OPMODE_PARAM_SIZE,
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	opmode_cmd.minor_version = 1;
+	if (opmode_d->mode == LSM_MODE_KEYWORD_ONLY_DETECTION)
+		opmode_cmd.mode = 1;
+	else
+		opmode_cmd.mode = 3;
+
+	if (opmode_d->detect_failure)
+		opmode_cmd.mode |= 0x04;
+
+	opmode_cmd.reserved = 0;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	rc = wcd_cpe_cmi_send_lsm_msg(core, session, &opmode_cmd);
+	if (unlikely(rc))
+		dev_err(core->dev,
+			"%s: set_param(operation_mode) failed, rc %dn",
+			__func__, rc);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+err_ret:
+	return rc;
+}
+
+static int wcd_cpe_send_param_gain(struct wcd_cpe_core *core,
+		struct cpe_lsm_session *session,
+		void *data, struct cpe_lsm_ids *ids)
+{
+	struct snd_lsm_gain *gain_d;
+	struct cpe_lsm_param_gain gain_cmd;
+	struct cmi_hdr *msg_hdr = &gain_cmd.hdr;
+	struct cpe_param_data *param_d =
+				&gain_cmd.param;
+	int rc;
+
+	memset(&gain_cmd, 0, sizeof(gain_cmd));
+	gain_d = (struct snd_lsm_gain *) data;
+	if (fill_lsm_cmd_header_v0_inband(msg_hdr,
+				session->id,
+				CPE_CMD_GAIN_PLD_SIZE,
+				CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		rc = -EINVAL;
+		goto err_ret;
+	}
+
+	wcd_cpe_set_param_data(param_d, ids,
+			       CPE_GAIN_PARAM_SIZE,
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	gain_cmd.minor_version = 1;
+	gain_cmd.gain = gain_d->gain;
+	gain_cmd.reserved = 0;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	rc = wcd_cpe_cmi_send_lsm_msg(core, session, &gain_cmd);
+	if (unlikely(rc))
+		dev_err(core->dev,
+			"%s: set_param(lsm_gain) failed, rc %dn",
+			__func__, rc);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+err_ret:
+	return rc;
+}
+
+static int wcd_cpe_send_param_connectport(struct wcd_cpe_core *core,
+		struct cpe_lsm_session *session,
+		void *data, struct cpe_lsm_ids *ids, u16 port_id)
+{
+	struct cpe_lsm_param_connectport con_port_cmd;
+	struct cmi_hdr *msg_hdr = &con_port_cmd.hdr;
+	struct cpe_param_data *param_d =
+				&con_port_cmd.param;
+	int rc;
+
+	memset(&con_port_cmd, 0, sizeof(con_port_cmd));
+	if (fill_lsm_cmd_header_v0_inband(msg_hdr,
+				session->id,
+				CPE_CMD_CONNECTPORT_PLD_SIZE,
+				CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		rc = -EINVAL;
+		goto err_ret;
+	}
+
+	wcd_cpe_set_param_data(param_d, ids,
+			       CPE_CONNECTPORT_PARAM_SIZE,
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	con_port_cmd.minor_version = 1;
+	con_port_cmd.afe_port_id = port_id;
+	con_port_cmd.reserved = 0;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	rc = wcd_cpe_cmi_send_lsm_msg(core, session, &con_port_cmd);
+	if (unlikely(rc))
+		dev_err(core->dev,
+			"%s: set_param(connect_port) failed, rc %dn",
+			__func__, rc);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+err_ret:
+	return rc;
+}
+
+static int wcd_cpe_send_param_conf_levels(
+		struct wcd_cpe_core *core,
+		struct cpe_lsm_session *session,
+		struct cpe_lsm_ids *ids)
+{
+	struct cpe_lsm_conf_level conf_level_data;
+	struct cmi_hdr *hdr = &(conf_level_data.hdr);
+	struct cpe_param_data *param_d = &(conf_level_data.param);
+	u8 pld_size = 0;
+	u8 pad_bytes = 0;
+	void *message;
+	int ret = 0;
+
+	memset(&conf_level_data, 0, sizeof(conf_level_data));
+
+	pld_size = (sizeof(struct cpe_lsm_conf_level) - sizeof(struct cmi_hdr));
+	pld_size += session->num_confidence_levels;
+	pad_bytes = ((4 - (pld_size % 4)) % 4);
+	pld_size += pad_bytes;
+
+	fill_cmi_header(hdr, session->id, CMI_CPE_LSM_SERVICE_ID,
+			false, pld_size,
+			CPE_LSM_SESSION_CMD_SET_PARAMS_V2, false);
+
+	wcd_cpe_set_param_data(param_d, ids,
+			       pld_size - sizeof(struct cpe_param_data),
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	conf_level_data.num_active_models = session->num_confidence_levels;
+
+	message = kzalloc(sizeof(struct cpe_lsm_conf_level) +
+			   conf_level_data.num_active_models + pad_bytes,
+			   GFP_KERNEL);
+	if (!message) {
+		pr_err("%s: no memory for conf_level\n", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(message, &conf_level_data,
+	       sizeof(struct cpe_lsm_conf_level));
+	memcpy(((u8 *) message) + sizeof(struct cpe_lsm_conf_level),
+		session->conf_levels, conf_level_data.num_active_models);
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, message);
+	if (ret)
+		pr_err("%s: lsm_set_conf_levels failed, err = %d\n",
+			__func__, ret);
+	kfree(message);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+static int wcd_cpe_send_param_snd_model(struct wcd_cpe_core *core,
+	struct cpe_lsm_session *session, struct cpe_lsm_ids *ids)
+{
+	int ret = 0;
+	struct cmi_obm_msg obm_msg;
+	struct cpe_param_data *param_d;
+
+
+	ret = fill_cmi_header(&obm_msg.hdr, session->id,
+			CMI_CPE_LSM_SERVICE_ID, 0, 20,
+			CPE_LSM_SESSION_CMD_SET_PARAMS_V2, true);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: Invalid parameters, rc = %d\n",
+			__func__, ret);
+		goto err_ret;
+	}
+
+	obm_msg.pld.version = 0;
+	obm_msg.pld.size = session->snd_model_size;
+	obm_msg.pld.data_ptr.kvaddr = session->snd_model_data;
+	obm_msg.pld.mem_handle = session->lsm_mem_handle;
+
+	param_d = (struct cpe_param_data *) session->snd_model_data;
+	wcd_cpe_set_param_data(param_d, ids,
+			(session->snd_model_size - sizeof(*param_d)),
+			CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &obm_msg);
+	if (ret)
+		dev_err(core->dev,
+			"%s: snd_model_register failed, %d\n",
+			__func__, ret);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+
+err_ret:
+	return ret;
+}
+
+static int wcd_cpe_send_param_dereg_model(
+	struct wcd_cpe_core *core,
+	struct cpe_lsm_session *session,
+	struct cpe_lsm_ids *ids)
+{
+	struct cmi_hdr *hdr;
+	struct cpe_param_data *param_d;
+	u8 *message;
+	u32 pld_size;
+	int rc = 0;
+
+	pld_size = sizeof(*hdr) + sizeof(*param_d);
+
+	message = kzalloc(pld_size, GFP_KERNEL);
+	if (!message)
+		return -ENOMEM;
+
+	hdr = (struct cmi_hdr *) message;
+	param_d = (struct cpe_param_data *)
+			(((u8 *) message) + sizeof(*hdr));
+
+	if (fill_lsm_cmd_header_v0_inband(hdr,
+				session->id,
+				sizeof(*param_d),
+				CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		rc = -EINVAL;
+		goto err_ret;
+	}
+	wcd_cpe_set_param_data(param_d, ids, 0,
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	rc = wcd_cpe_cmi_send_lsm_msg(core, session, message);
+	if (rc)
+		dev_err(core->dev,
+			"%s: snd_model_deregister failed, %d\n",
+			__func__, rc);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+err_ret:
+	kfree(message);
+	return rc;
+}
+
+static int wcd_cpe_send_custom_param(
+	struct wcd_cpe_core *core,
+	struct cpe_lsm_session *session,
+	void *data, u32 msg_size)
+{
+	u8 *msg;
+	struct cmi_hdr *hdr;
+	u8 *msg_pld;
+	int rc;
+
+	if (msg_size > CMI_INBAND_MESSAGE_SIZE) {
+		dev_err(core->dev,
+			"%s: out of band custom params not supported\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	msg = kzalloc(sizeof(*hdr) + msg_size, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = (struct cmi_hdr *) msg;
+	msg_pld = msg + sizeof(struct cmi_hdr);
+
+	if (fill_lsm_cmd_header_v0_inband(hdr,
+				session->id,
+				msg_size,
+				CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		rc = -EINVAL;
+		goto err_ret;
+	}
+
+	memcpy(msg_pld, data, msg_size);
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	rc = wcd_cpe_cmi_send_lsm_msg(core, session, msg);
+	if (rc)
+		dev_err(core->dev,
+			"%s: custom params send failed, err = %d\n",
+			 __func__, rc);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+err_ret:
+	kfree(msg);
+	return rc;
+}
+
+static int wcd_cpe_set_one_param(void *core_handle,
+	struct cpe_lsm_session *session, struct lsm_params_info *p_info,
+	void *data, uint32_t param_type)
+{
+	struct wcd_cpe_core *core = core_handle;
+	int rc = 0;
+	struct cpe_lsm_ids ids;
+
+	memset(&ids, 0, sizeof(ids));
+	ids.module_id = p_info->module_id;
+	ids.param_id = p_info->param_id;
+
+	switch (param_type) {
+	case LSM_ENDPOINT_DETECT_THRESHOLD:
+		rc = wcd_cpe_send_param_epd_thres(core, session,
+						data, &ids);
+		break;
+	case LSM_OPERATION_MODE:
+		rc = wcd_cpe_send_param_opmode(core, session, data, &ids);
+		break;
+	case LSM_GAIN:
+		rc = wcd_cpe_send_param_gain(core, session, data, &ids);
+		break;
+	case LSM_MIN_CONFIDENCE_LEVELS:
+		rc = wcd_cpe_send_param_conf_levels(core, session, &ids);
+		break;
+	case LSM_REG_SND_MODEL:
+		rc = wcd_cpe_send_param_snd_model(core, session, &ids);
+		break;
+	case LSM_DEREG_SND_MODEL:
+		rc = wcd_cpe_send_param_dereg_model(core, session, &ids);
+		break;
+	case LSM_CUSTOM_PARAMS:
+		rc = wcd_cpe_send_custom_param(core, session,
+					       data, p_info->param_size);
+		break;
+	default:
+		pr_err("%s: wrong param_type 0x%x\n",
+			__func__, param_type);
+	}
+
+	if (rc)
+		dev_err(core->dev,
+			"%s: send_param(%d) failed, err %d\n",
+			 __func__, param_type, rc);
+	return rc;
+}
+
+/*
+ * wcd_cpe_lsm_set_params: set the parameters for lsm service
+ * @core: handle to cpe core
+ * @session: session for which the parameters are to be set
+ * @detect_mode: mode for detection
+ * @detect_failure: flag indicating failure detection enabled/disabled
+ *
+ */
+static int wcd_cpe_lsm_set_params(struct wcd_cpe_core *core,
+	struct cpe_lsm_session *session,
+	enum lsm_detection_mode detect_mode, bool detect_failure)
+{
+	struct cpe_lsm_ids ids;
+	struct snd_lsm_detect_mode det_mode;
+
+	int ret = 0;
+
+	/* Send lsm calibration */
+	ret = wcd_cpe_send_lsm_cal(core, session);
+	if (ret) {
+		pr_err("%s: fail to sent acdb cal, err = %d",
+			__func__, ret);
+		goto err_ret;
+	}
+
+	/* Send operation mode */
+	ids.module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
+	ids.param_id = CPE_LSM_PARAM_ID_OPERATION_MODE;
+	det_mode.mode = detect_mode;
+	det_mode.detect_failure = detect_failure;
+	ret = wcd_cpe_send_param_opmode(core, session,
+					&det_mode, &ids);
+	if (ret)
+		dev_err(core->dev,
+			"%s: Failed to set opmode, err=%d\n",
+			__func__, ret);
+
+err_ret:
+	return ret;
+}
+
+static int wcd_cpe_lsm_set_data(void *core_handle,
+				struct cpe_lsm_session *session,
+				enum lsm_detection_mode detect_mode,
+				bool detect_failure)
+{
+	struct wcd_cpe_core *core = core_handle;
+	struct cpe_lsm_ids ids;
+	int ret = 0;
+
+	if (session->num_confidence_levels > 0) {
+		ret = wcd_cpe_lsm_set_params(core, session, detect_mode,
+				       detect_failure);
+		if (ret) {
+			dev_err(core->dev,
+				"%s: lsm set params failed, rc = %d\n",
+				__func__, ret);
+			goto err_ret;
+		}
+
+		ids.module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
+		ids.param_id = CPE_LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
+		ret = wcd_cpe_send_param_conf_levels(core, session, &ids);
+		if (ret) {
+			dev_err(core->dev,
+				"%s: lsm confidence levels failed, rc = %d\n",
+				__func__, ret);
+			goto err_ret;
+		}
+	} else {
+		dev_dbg(core->dev,
+			"%s: no conf levels to set\n",
+			__func__);
+	}
+
+err_ret:
+	return ret;
+}
+
+/*
+ * wcd_cpe_lsm_reg_snd_model: register the sound model for listen
+ * @session: session for which to register the sound model
+ * @detect_mode: detection mode, user dependent/independent
+ * @detect_failure: flag to indicate if failure detection is enabled
+ *
+ * The memory required for sound model should be pre-allocated on CPE
+ * before this function is invoked.
+ */
+static int wcd_cpe_lsm_reg_snd_model(void *core_handle,
+				 struct cpe_lsm_session *session,
+				 enum lsm_detection_mode detect_mode,
+				 bool detect_failure)
+{
+	int ret = 0;
+	struct cmi_obm_msg obm_msg;
+	struct wcd_cpe_core *core = core_handle;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	ret = wcd_cpe_lsm_set_data(core_handle, session,
+				   detect_mode, detect_failure);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: fail to set lsm data, err = %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	ret = fill_cmi_header(&obm_msg.hdr, session->id,
+			CMI_CPE_LSM_SERVICE_ID, 0, 20,
+			CPE_LSM_SESSION_CMD_REGISTER_SOUND_MODEL, true);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: Invalid parameters, rc = %d\n",
+			__func__, ret);
+		goto err_ret;
+	}
+
+	obm_msg.pld.version = 0;
+	obm_msg.pld.size = session->snd_model_size;
+	obm_msg.pld.data_ptr.kvaddr = session->snd_model_data;
+	obm_msg.pld.mem_handle = session->lsm_mem_handle;
+
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &obm_msg);
+	if (ret)
+		dev_err(core->dev,
+			"%s: snd_model_register failed, %d\n",
+			__func__, ret);
+err_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+/*
+ * wcd_cpe_lsm_dereg_snd_model: deregister the sound model for listen
+ * @core_handle: handle to cpe core
+ * @session: session for which to deregister the sound model
+ *
+ */
+static int wcd_cpe_lsm_dereg_snd_model(void *core_handle,
+				struct cpe_lsm_session *session)
+{
+	struct cmi_hdr cmd_dereg_snd_model;
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_dereg_snd_model, 0, sizeof(cmd_dereg_snd_model));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_dereg_snd_model, session->id,
+			    0, CPE_LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_dereg_snd_model);
+	if (ret)
+		dev_err(core->dev,
+			"%s: failed to send dereg_snd_model cmd\n",
+			__func__);
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+/*
+ * wcd_cpe_lsm_get_afe_out_port_id: get afe output port id
+ * @core_handle: handle to the CPE core
+ * @session: session for which port id needs to get
+ */
+static int wcd_cpe_lsm_get_afe_out_port_id(void *core_handle,
+					   struct cpe_lsm_session *session)
+{
+	struct wcd_cpe_core *core = core_handle;
+	struct snd_soc_codec *codec;
+	int rc = 0;
+
+	if (!core || !core->codec) {
+		pr_err("%s: Invalid handle to %s\n",
+			__func__,
+			(!core) ? "core" : "codec");
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (!session) {
+		dev_err(core->dev, "%s: Invalid session\n",
+			__func__);
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (!core->cpe_cdc_cb ||
+		!core->cpe_cdc_cb->get_afe_out_port_id) {
+		session->afe_out_port_id = WCD_CPE_AFE_OUT_PORT_2;
+		dev_dbg(core->dev,
+			"%s: callback not defined, default port_id = %d\n",
+			__func__, session->afe_out_port_id);
+		goto done;
+	}
+
+	codec = core->codec;
+	rc = core->cpe_cdc_cb->get_afe_out_port_id(codec,
+						   &session->afe_out_port_id);
+	if (rc) {
+		dev_err(core->dev,
+			"%s: failed to get port id, err = %d\n",
+			__func__, rc);
+		goto done;
+	}
+	dev_dbg(core->dev, "%s: port_id: %d\n", __func__,
+		session->afe_out_port_id);
+
+done:
+	return rc;
+}
+
+/*
+ * wcd_cpe_cmd_lsm_start: send the start command to lsm
+ * @core_handle: handle to the CPE core
+ * @session: session for which start command to be sent
+ *
+ */
+static int wcd_cpe_cmd_lsm_start(void *core_handle,
+			struct cpe_lsm_session *session)
+{
+	struct cmi_hdr cmd_lsm_start;
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_lsm_start, 0, sizeof(struct cmi_hdr));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_lsm_start, session->id, 0,
+					  CPE_LSM_SESSION_CMD_START)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_lsm_start);
+	if (ret)
+		dev_err(core->dev, "failed to send lsm_start cmd\n");
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+/*
+ * wcd_cpe_cmd_lsm_stop: send the stop command for LSM service
+ * @core_handle: handle to the cpe core
+ * @session: session for which stop command to be sent
+ *
+ */
+static int wcd_cpe_cmd_lsm_stop(void *core_handle,
+		struct cpe_lsm_session *session)
+{
+	struct cmi_hdr cmd_lsm_stop;
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session,
+					   __func__);
+	if (ret)
+		return ret;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&cmd_lsm_stop, 0, sizeof(struct cmi_hdr));
+	if (fill_lsm_cmd_header_v0_inband(&cmd_lsm_stop, session->id, 0,
+					  CPE_LSM_SESSION_CMD_STOP)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_lsm_stop);
+	if (ret)
+		dev_err(core->dev,
+			"%s: failed to send lsm_stop cmd\n",
+			__func__);
+end_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+
+}
+
+/*
+ * wcd_cpe_alloc_lsm_session: allocate a lsm session
+ * @core: handle to wcd_cpe_core
+ * @lsm_priv_d: lsm private data
+ */
+static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session(
+	void *core_handle, void *client_data,
+	void (*event_cb)(void *, u8, u8, u8 *))
+{
+	struct cpe_lsm_session *session;
+	int i, session_id = -1;
+	struct wcd_cpe_core *core = core_handle;
+	bool afe_register_service = false;
+	int ret = 0;
+
+	/*
+	 * Even if multiple listen sessions can be
+	 * allocated, the AFE service registration
+	 * should be done only once as CPE can only
+	 * have one instance of AFE service.
+	 *
+	 * If this is the first session to be allocated,
+	 * only then register the afe service.
+	 */
+	if (!wcd_cpe_lsm_session_active())
+		afe_register_service = true;
+
+	for (i = 1; i <= WCD_CPE_LSM_MAX_SESSIONS; i++) {
+		if (!lsm_sessions[i]) {
+			session_id = i;
+			break;
+		}
+	}
+
+	if (session_id < 0) {
+		dev_err(core->dev,
+			"%s: max allowed sessions already allocated\n",
+			__func__);
+		return NULL;
+	}
+
+	ret = wcd_cpe_vote(core, true);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: Failed to enable cpe, err = %d\n",
+			__func__, ret);
+		return NULL;
+	}
+
+	session = kzalloc(sizeof(struct cpe_lsm_session), GFP_KERNEL);
+	if (!session)
+		goto err_session_alloc;
+
+	session->id = session_id;
+	session->event_cb = event_cb;
+	session->cmi_reg_handle = cmi_register(wcd_cpe_cmi_lsm_callback,
+						CMI_CPE_LSM_SERVICE_ID);
+	if (!session->cmi_reg_handle) {
+		dev_err(core->dev,
+			"%s: Failed to register LSM service with CMI\n",
+			__func__);
+		goto err_ret;
+	}
+	session->priv_d = client_data;
+	mutex_init(&session->lsm_lock);
+	if (afe_register_service) {
+		/* Register for AFE Service */
+		core->cmi_afe_handle = cmi_register(wcd_cpe_cmi_afe_cb,
+						CMI_CPE_AFE_SERVICE_ID);
+		wcd_cpe_initialize_afe_port_data();
+		if (!core->cmi_afe_handle) {
+			dev_err(core->dev,
+				"%s: Failed to register AFE service with CMI\n",
+				__func__);
+			goto err_afe_svc_reg;
+		}
+
+		/* Once AFE service is registered, send the mode command */
+		ret = wcd_cpe_afe_svc_cmd_mode(core,
+				AFE_SVC_EXPLICIT_PORT_START);
+		if (ret)
+			goto err_afe_mode_cmd;
+	}
+
+	session->lsm_mem_handle = 0;
+	init_completion(&session->cmd_comp);
+
+	lsm_sessions[session_id] = session;
+	return session;
+
+err_afe_mode_cmd:
+	cmi_deregister(core->cmi_afe_handle);
+
+err_afe_svc_reg:
+	cmi_deregister(session->cmi_reg_handle);
+	mutex_destroy(&session->lsm_lock);
+
+err_ret:
+	kfree(session);
+
+err_session_alloc:
+	wcd_cpe_vote(core, false);
+	return NULL;
+}
+
+/*
+ * wcd_cpe_lsm_config_lab_latency: send lab latency value
+ * @core: handle to wcd_cpe_core
+ * @session: lsm session
+ * @latency: the value of latency for lab setup in msec
+ */
+static int wcd_cpe_lsm_config_lab_latency(
+		struct wcd_cpe_core *core,
+		struct cpe_lsm_session *session,
+		u32 latency)
+{
+	int ret = 0, pld_size = CPE_PARAM_LSM_LAB_LATENCY_SIZE;
+	struct cpe_lsm_lab_latency_config cpe_lab_latency;
+	struct cpe_lsm_lab_config *lab_lat = &cpe_lab_latency.latency_cfg;
+	struct cpe_param_data *param_d = &lab_lat->param;
+	struct cpe_lsm_ids ids;
+
+	if (fill_lsm_cmd_header_v0_inband(&cpe_lab_latency.hdr, session->id,
+		(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		pr_err("%s: Failed to create header\n", __func__);
+		return -EINVAL;
+	}
+	if (latency == 0x00 || latency > WCD_CPE_LAB_MAX_LATENCY) {
+		pr_err("%s: Invalid latency %u\n",
+			__func__, latency);
+		return -EINVAL;
+	}
+
+	lab_lat->latency = latency;
+	lab_lat->minor_ver = 1;
+	ids.module_id = CPE_LSM_MODULE_ID_LAB;
+	ids.param_id = CPE_LSM_PARAM_ID_LAB_CONFIG;
+	wcd_cpe_set_param_data(param_d, &ids,
+			       PARAM_SIZE_LSM_LATENCY_SIZE,
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	pr_debug("%s: Module 0x%x Param 0x%x size %zu pld_size 0x%x\n",
+		  __func__, lab_lat->param.module_id,
+		 lab_lat->param.param_id, PARAM_SIZE_LSM_LATENCY_SIZE,
+		 pld_size);
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cpe_lab_latency);
+	if (ret != 0)
+		pr_err("%s: lsm_set_params failed, error = %d\n",
+		       __func__, ret);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+	return ret;
+}
+
+/*
+ * wcd_cpe_lsm_lab_control: enable/disable lab
+ * @core: handle to wcd_cpe_core
+ * @session: lsm session
+ * @enable: Indicates whether to enable / disable lab
+ */
+static int wcd_cpe_lsm_lab_control(
+		void *core_handle,
+		struct cpe_lsm_session *session,
+		bool enable)
+{
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0, pld_size = CPE_PARAM_SIZE_LSM_LAB_CONTROL;
+	struct cpe_lsm_control_lab cpe_lab_enable;
+	struct cpe_lsm_lab_enable *lab_enable = &cpe_lab_enable.lab_enable;
+	struct cpe_param_data *param_d = &lab_enable->param;
+	struct cpe_lsm_ids ids;
+
+	pr_debug("%s: enter payload_size = %d Enable %d\n",
+		 __func__, pld_size, enable);
+
+	memset(&cpe_lab_enable, 0, sizeof(cpe_lab_enable));
+
+	if (fill_lsm_cmd_header_v0_inband(&cpe_lab_enable.hdr, session->id,
+		(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		return -EINVAL;
+	}
+	if (enable == true)
+		lab_enable->enable = 1;
+	else
+		lab_enable->enable = 0;
+
+	ids.module_id = CPE_LSM_MODULE_ID_LAB;
+	ids.param_id = CPE_LSM_PARAM_ID_LAB_ENABLE;
+	wcd_cpe_set_param_data(param_d, &ids,
+			PARAM_SIZE_LSM_CONTROL_SIZE,
+			CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	pr_debug("%s: Module 0x%x, Param 0x%x size %zu pld_size 0x%x\n",
+		 __func__, lab_enable->param.module_id,
+		 lab_enable->param.param_id, PARAM_SIZE_LSM_CONTROL_SIZE,
+		 pld_size);
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cpe_lab_enable);
+	if (ret != 0) {
+		pr_err("%s: lsm_set_params failed, error = %d\n",
+			__func__, ret);
+		WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+		goto done;
+	}
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+
+	if (lab_enable->enable)
+		ret = wcd_cpe_lsm_config_lab_latency(core, session,
+					       WCD_CPE_LAB_MAX_LATENCY);
+done:
+	return ret;
+}
+
+/*
+ * wcd_cpe_lsm_eob: stop lab
+ * @core: handle to wcd_cpe_core
+ * @session: lsm session to be deallocated
+ */
+static int wcd_cpe_lsm_eob(
+			struct wcd_cpe_core *core,
+			struct cpe_lsm_session *session)
+{
+	int ret = 0;
+	struct cmi_hdr lab_eob;
+
+	if (fill_lsm_cmd_header_v0_inband(&lab_eob, session->id,
+		0, CPE_LSM_SESSION_CMD_EOB)) {
+		return -EINVAL;
+	}
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &lab_eob);
+	if (ret != 0)
+		pr_err("%s: lsm_set_params failed\n", __func__);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+
+	return ret;
+}
+
+/*
+ * wcd_cpe_dealloc_lsm_session: deallocate lsm session
+ * @core: handle to wcd_cpe_core
+ * @session: lsm session to be deallocated
+ */
+static int wcd_cpe_dealloc_lsm_session(void *core_handle,
+			struct cpe_lsm_session *session)
+{
+	struct wcd_cpe_core *core = core_handle;
+	int ret = 0;
+
+	if (!session) {
+		dev_err(core->dev,
+			"%s: Invalid lsm session\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_dbg(core->dev, "%s: session %d being deallocated\n",
+		__func__, session->id);
+	if (session->id > WCD_CPE_LSM_MAX_SESSIONS) {
+		dev_err(core->dev,
+			"%s: Wrong session id %d max allowed = %d\n",
+			__func__, session->id,
+			WCD_CPE_LSM_MAX_SESSIONS);
+		return -EINVAL;
+	}
+
+	cmi_deregister(session->cmi_reg_handle);
+	mutex_destroy(&session->lsm_lock);
+	lsm_sessions[session->id] = NULL;
+	kfree(session);
+
+	if (!wcd_cpe_lsm_session_active()) {
+		cmi_deregister(core->cmi_afe_handle);
+		core->cmi_afe_handle = NULL;
+		wcd_cpe_deinitialize_afe_port_data();
+	}
+
+	ret = wcd_cpe_vote(core, false);
+	if (ret)
+		dev_dbg(core->dev,
+			"%s: Failed to un-vote cpe, err = %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static int wcd_cpe_lab_ch_setup(void *core_handle,
+		struct cpe_lsm_session *session,
+		enum wcd_cpe_event event)
+{
+	struct wcd_cpe_core *core = core_handle;
+	struct snd_soc_codec *codec;
+	int rc = 0;
+	u8 cpe_intr_bits;
+
+	if (!core || !core->codec) {
+		pr_err("%s: Invalid handle to %s\n",
+			__func__,
+			(!core) ? "core" : "codec");
+		rc = EINVAL;
+		goto done;
+	}
+
+	if (!core->cpe_cdc_cb ||
+	    !core->cpe_cdc_cb->cdc_ext_clk ||
+	    !core->cpe_cdc_cb->lab_cdc_ch_ctl) {
+		dev_err(core->dev,
+			"%s: Invalid codec callbacks\n",
+			__func__);
+		rc = -EINVAL;
+		goto done;
+	}
+
+	codec = core->codec;
+	dev_dbg(core->dev,
+		"%s: event = 0x%x\n",
+		__func__, event);
+
+	switch (event) {
+	case WCD_CPE_PRE_ENABLE:
+		rc = core->cpe_cdc_cb->cdc_ext_clk(codec, true, false);
+		if (rc) {
+			dev_err(core->dev,
+				"%s: failed to enable cdc clk, err = %d\n",
+				__func__, rc);
+			goto done;
+		}
+
+		rc = core->cpe_cdc_cb->lab_cdc_ch_ctl(codec,
+						      true);
+		if (rc) {
+			dev_err(core->dev,
+				"%s: failed to enable cdc port, err = %d\n",
+				__func__, rc);
+			rc = core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
+			goto done;
+		}
+
+		break;
+
+	case WCD_CPE_POST_ENABLE:
+		rc = cpe_svc_toggle_lab(core->cpe_handle, true);
+		if (rc)
+			dev_err(core->dev,
+			"%s: Failed to enable lab\n", __func__);
+		break;
+
+	case WCD_CPE_PRE_DISABLE:
+		/*
+		 * Mask the non-fatal interrupts in CPE as they will
+		 * be generated during lab teardown and may flood.
+		 */
+		cpe_intr_bits = ~(core->irq_info.cpe_fatal_irqs & 0xFF);
+		if (CPE_ERR_IRQ_CB(core))
+			core->cpe_cdc_cb->cpe_err_irq_control(
+						core->codec,
+						CPE_ERR_IRQ_MASK,
+						&cpe_intr_bits);
+
+		rc = core->cpe_cdc_cb->lab_cdc_ch_ctl(codec,
+						      false);
+		if (rc)
+			dev_err(core->dev,
+				"%s: failed to disable cdc port, err = %d\n",
+				__func__, rc);
+		break;
+
+	case WCD_CPE_POST_DISABLE:
+		rc = wcd_cpe_lsm_eob(core, session);
+		if (rc)
+			dev_err(core->dev,
+				"%s: eob send failed, err = %d\n",
+				__func__, rc);
+
+		/* Continue teardown even if eob failed */
+		rc = cpe_svc_toggle_lab(core->cpe_handle, false);
+		if (rc)
+			dev_err(core->dev,
+			"%s: Failed to disable lab\n", __func__);
+
+		/* Continue with disabling even if toggle lab fails */
+		rc = core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
+		if (rc)
+			dev_err(core->dev,
+				"%s: failed to disable cdc clk, err = %d\n",
+				__func__, rc);
+
+		/* Unmask non-fatal CPE interrupts */
+		cpe_intr_bits = ~(core->irq_info.cpe_fatal_irqs & 0xFF);
+		if (CPE_ERR_IRQ_CB(core))
+			core->cpe_cdc_cb->cpe_err_irq_control(
+						core->codec,
+						CPE_ERR_IRQ_UNMASK,
+						&cpe_intr_bits);
+		break;
+
+	default:
+		dev_err(core->dev,
+			"%s: Invalid event 0x%x\n",
+			__func__, event);
+		rc = -EINVAL;
+		break;
+	}
+
+done:
+	return rc;
+}
+
+static int wcd_cpe_lsm_set_fmt_cfg(void *core_handle,
+			struct cpe_lsm_session *session)
+{
+	int ret;
+	struct cpe_lsm_output_format_cfg out_fmt_cfg;
+	struct wcd_cpe_core *core = core_handle;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session, __func__);
+	if (ret)
+		goto done;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+
+	memset(&out_fmt_cfg, 0, sizeof(out_fmt_cfg));
+	if (fill_lsm_cmd_header_v0_inband(&out_fmt_cfg.hdr,
+			session->id, OUT_FMT_CFG_CMD_PAYLOAD_SIZE,
+			CPE_LSM_SESSION_CMD_TX_BUFF_OUTPUT_CONFIG)) {
+		ret = -EINVAL;
+		goto err_ret;
+	}
+
+	out_fmt_cfg.format = session->out_fmt_cfg.format;
+	out_fmt_cfg.packing = session->out_fmt_cfg.pack_mode;
+	out_fmt_cfg.data_path_events = session->out_fmt_cfg.data_path_events;
+
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &out_fmt_cfg);
+	if (ret)
+		dev_err(core->dev,
+			"%s: lsm_set_output_format_cfg failed, err = %d\n",
+			__func__, ret);
+
+err_ret:
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+done:
+	return ret;
+}
+
+static void wcd_cpe_snd_model_offset(void *core_handle,
+		struct cpe_lsm_session *session, size_t *offset)
+{
+	*offset = sizeof(struct cpe_param_data);
+}
+
+static int wcd_cpe_lsm_set_media_fmt_params(void *core_handle,
+					  struct cpe_lsm_session *session,
+					  struct lsm_hw_params *param)
+{
+	struct cpe_lsm_media_fmt_param media_fmt;
+	struct cmi_hdr *msg_hdr = &media_fmt.hdr;
+	struct wcd_cpe_core *core = core_handle;
+	struct cpe_param_data *param_d = &media_fmt.param;
+	struct cpe_lsm_ids ids;
+	int ret;
+
+	memset(&media_fmt, 0, sizeof(media_fmt));
+	if (fill_lsm_cmd_header_v0_inband(msg_hdr,
+				session->id,
+				CPE_MEDIA_FMT_PLD_SIZE,
+				CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memset(&ids, 0, sizeof(ids));
+	ids.module_id = CPE_LSM_MODULE_FRAMEWORK;
+	ids.param_id = CPE_LSM_PARAM_ID_MEDIA_FMT;
+
+	wcd_cpe_set_param_data(param_d, &ids, CPE_MEDIA_FMT_PARAM_SIZE,
+			       CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
+
+	media_fmt.minor_version = 1;
+	media_fmt.sample_rate = param->sample_rate;
+	media_fmt.num_channels = param->num_chs;
+	media_fmt.bit_width = param->bit_width;
+
+	WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
+	ret = wcd_cpe_cmi_send_lsm_msg(core, session, &media_fmt);
+	if (ret)
+		dev_err(core->dev,
+			"%s: Set_param(media_format) failed, err=%d\n",
+			__func__, ret);
+	WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
+done:
+	return ret;
+}
+
+static int wcd_cpe_lsm_set_port(void *core_handle,
+				struct cpe_lsm_session *session, void *data)
+{
+	u32 port_id;
+	int ret;
+	struct cpe_lsm_ids ids;
+	struct wcd_cpe_core *core = core_handle;
+
+	ret = wcd_cpe_is_valid_lsm_session(core, session, __func__);
+	if (ret)
+		goto done;
+
+	if (!data) {
+		dev_err(core->dev, "%s: data is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+	port_id = *(u32 *)data;
+	dev_dbg(core->dev, "%s: port_id: %d\n", __func__, port_id);
+
+	memset(&ids, 0, sizeof(ids));
+	ids.module_id = LSM_MODULE_ID_FRAMEWORK;
+	ids.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+
+	ret = wcd_cpe_send_param_connectport(core, session, NULL,
+					     &ids, port_id);
+	if (ret)
+		dev_err(core->dev,
+			"%s: send_param_connectport failed, err %d\n",
+			__func__, ret);
+done:
+	return ret;
+}
+
+/*
+ * wcd_cpe_get_lsm_ops: register lsm driver to codec
+ * @lsm_ops: structure with lsm callbacks
+ * @codec: codec to which this lsm driver is registered to
+ */
+int wcd_cpe_get_lsm_ops(struct wcd_cpe_lsm_ops *lsm_ops)
+{
+	lsm_ops->lsm_alloc_session = wcd_cpe_alloc_lsm_session;
+	lsm_ops->lsm_dealloc_session = wcd_cpe_dealloc_lsm_session;
+	lsm_ops->lsm_open_tx = wcd_cpe_cmd_lsm_open_tx;
+	lsm_ops->lsm_close_tx = wcd_cpe_cmd_lsm_close_tx;
+	lsm_ops->lsm_shmem_alloc = wcd_cpe_cmd_lsm_shmem_alloc;
+	lsm_ops->lsm_shmem_dealloc = wcd_cpe_cmd_lsm_shmem_dealloc;
+	lsm_ops->lsm_register_snd_model = wcd_cpe_lsm_reg_snd_model;
+	lsm_ops->lsm_deregister_snd_model = wcd_cpe_lsm_dereg_snd_model;
+	lsm_ops->lsm_get_afe_out_port_id = wcd_cpe_lsm_get_afe_out_port_id;
+	lsm_ops->lsm_start = wcd_cpe_cmd_lsm_start;
+	lsm_ops->lsm_stop = wcd_cpe_cmd_lsm_stop;
+	lsm_ops->lsm_lab_control = wcd_cpe_lsm_lab_control;
+	lsm_ops->lab_ch_setup = wcd_cpe_lab_ch_setup;
+	lsm_ops->lsm_set_data = wcd_cpe_lsm_set_data;
+	lsm_ops->lsm_set_fmt_cfg = wcd_cpe_lsm_set_fmt_cfg;
+	lsm_ops->lsm_set_one_param = wcd_cpe_set_one_param;
+	lsm_ops->lsm_get_snd_model_offset = wcd_cpe_snd_model_offset;
+	lsm_ops->lsm_set_media_fmt_params = wcd_cpe_lsm_set_media_fmt_params;
+	lsm_ops->lsm_set_port = wcd_cpe_lsm_set_port;
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd_cpe_get_lsm_ops);
+
+static int fill_afe_cmd_header(struct cmi_hdr *hdr, u8 port_id,
+				u16 opcode, u8 pld_size,
+				bool obm_flag)
+{
+	CMI_HDR_SET_SESSION(hdr, port_id);
+	CMI_HDR_SET_SERVICE(hdr, CMI_CPE_AFE_SERVICE_ID);
+
+	CMI_HDR_SET_PAYLOAD_SIZE(hdr, pld_size);
+
+	hdr->opcode = opcode;
+
+	if (obm_flag)
+		CMI_HDR_SET_OBM(hdr, CMI_OBM_FLAG_OUT_BAND);
+	else
+		CMI_HDR_SET_OBM(hdr, CMI_OBM_FLAG_IN_BAND);
+
+	return 0;
+}
+
+/*
+ * wcd_cpe_cmi_send_afe_msg: send message to AFE service
+ * @core: wcd cpe core handle
+ * @port_cfg: configuration data for the afe port
+ *	      for which this message is to be sent
+ * @message: actual message with header and payload
+ *
+ * Port specific lock needs to be acquired before this
+ * function can be invoked
+ */
+static int wcd_cpe_cmi_send_afe_msg(
+	struct wcd_cpe_core *core,
+	struct wcd_cmi_afe_port_data *port_d,
+	void *message)
+{
+	int ret = 0;
+	struct cmi_hdr *hdr = message;
+
+	pr_debug("%s: sending message with opcode 0x%x\n",
+		__func__, hdr->opcode);
+
+	if (unlikely(!wcd_cpe_is_online_state(core))) {
+		dev_err(core->dev, "%s: CPE offline\n", __func__);
+		return 0;
+	}
+
+	if (CMI_HDR_GET_OBM_FLAG(hdr))
+		wcd_cpe_bus_vote_max_bw(core, true);
+
+	ret = cmi_send_msg(message);
+	if (ret) {
+		pr_err("%s: cmd 0x%x send failed, err = %d\n",
+			__func__, hdr->opcode, ret);
+		goto rel_bus_vote;
+	}
+
+	ret = wait_for_completion_timeout(&port_d->afe_cmd_complete,
+					  CMI_CMD_TIMEOUT);
+	if (ret > 0) {
+		pr_debug("%s: command 0x%x, received response 0x%x\n",
+			 __func__, hdr->opcode, port_d->cmd_result);
+		if (port_d->cmd_result == CMI_SHMEM_ALLOC_FAILED)
+			port_d->cmd_result = CPE_ENOMEMORY;
+		if (port_d->cmd_result > 0)
+			pr_err("%s: CPE returned error[%s]\n",
+				__func__, cpe_err_get_err_str(
+				port_d->cmd_result));
+		ret = cpe_err_get_lnx_err_code(port_d->cmd_result);
+		goto rel_bus_vote;
+	} else {
+		pr_err("%s: command 0x%x send timed out\n",
+			__func__, hdr->opcode);
+		ret = -ETIMEDOUT;
+		goto rel_bus_vote;
+	}
+
+rel_bus_vote:
+	reinit_completion(&port_d->afe_cmd_complete);
+
+	if (CMI_HDR_GET_OBM_FLAG(hdr))
+		wcd_cpe_bus_vote_max_bw(core, false);
+
+	return ret;
+}
+
+
+
+/*
+ * wcd_cpe_afe_shmem_alloc: allocate the cpe memory for afe service
+ * @core: handle to cpe core
+ * @port_cfg: configuration data for the port which needs
+ *	      memory to be allocated on CPE
+ * @size: size of the memory to be allocated
+ */
+static int wcd_cpe_afe_shmem_alloc(
+	struct wcd_cpe_core *core,
+	struct wcd_cmi_afe_port_data *port_d,
+	u32 size)
+{
+	struct cpe_cmd_shmem_alloc cmd_shmem_alloc;
+	int ret = 0;
+
+	pr_debug("%s: enter: size = %d\n", __func__, size);
+
+	memset(&cmd_shmem_alloc, 0, sizeof(cmd_shmem_alloc));
+	if (fill_afe_cmd_header(&cmd_shmem_alloc.hdr, port_d->port_id,
+			    CPE_AFE_PORT_CMD_SHARED_MEM_ALLOC,
+			    SHMEM_ALLOC_CMD_PLD_SIZE, false)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	cmd_shmem_alloc.size = size;
+
+	ret = wcd_cpe_cmi_send_afe_msg(core, port_d, &cmd_shmem_alloc);
+	if (ret) {
+		pr_err("%s: afe_shmem_alloc fail,ret = %d\n",
+			__func__, ret);
+		goto end_ret;
+	}
+
+	pr_debug("%s: completed %s, mem_handle = 0x%x\n",
+		__func__, "CPE_AFE_CMD_SHARED_MEM_ALLOC",
+		port_d->mem_handle);
+
+end_ret:
+	return ret;
+}
+
+/*
+ * wcd_cpe_afe_shmem_dealloc: deallocate the cpe memory for
+ *			      afe service
+ * @core: handle to cpe core
+ * @port_d: configuration data for the port which needs
+ *	      memory to be deallocated on CPE
+ * The memory handle to be de-allocated is saved in the
+ * port configuration data
+ */
+static int wcd_cpe_afe_shmem_dealloc(
+	struct wcd_cpe_core *core,
+	struct wcd_cmi_afe_port_data *port_d)
+{
+	struct cpe_cmd_shmem_dealloc cmd_dealloc;
+	int ret = 0;
+
+	pr_debug("%s: enter, port_id = %d\n",
+		 __func__, port_d->port_id);
+
+	memset(&cmd_dealloc, 0, sizeof(cmd_dealloc));
+	if (fill_afe_cmd_header(&cmd_dealloc.hdr, port_d->port_id,
+				CPE_AFE_PORT_CMD_SHARED_MEM_DEALLOC,
+				SHMEM_DEALLOC_CMD_PLD_SIZE, false)) {
+		ret = -EINVAL;
+		goto end_ret;
+	}
+
+	cmd_dealloc.addr = port_d->mem_handle;
+	ret = wcd_cpe_cmi_send_afe_msg(core, port_d, &cmd_dealloc);
+	if (ret) {
+		pr_err("failed to send shmem_dealloc cmd\n");
+		goto end_ret;
+	}
+	memset(&port_d->mem_handle, 0,
+	       sizeof(port_d->mem_handle));
+
+end_ret:
+	return ret;
+}
+
+/*
+ * wcd_cpe_send_afe_cal: send the acdb calibration to AFE port
+ * @core: handle to cpe core
+ * @port_d: configuration data for the port for which the
+ *	      calibration needs to be appplied
+ */
+static int wcd_cpe_send_afe_cal(void *core_handle,
+		struct wcd_cmi_afe_port_data *port_d)
+{
+
+	struct cal_block_data *afe_cal = NULL;
+	struct wcd_cpe_core *core = core_handle;
+	struct cmi_obm_msg obm_msg;
+	void *inb_msg = NULL;
+	void *msg;
+	int rc = 0;
+	bool is_obm_msg;
+
+	if (core->cal_data[WCD_CPE_LSM_CAL_AFE] == NULL) {
+		pr_err("%s: LSM cal not allocated!\n",
+			__func__);
+		rc = -EINVAL;
+		goto rel_cal_mutex;
+	}
+
+	mutex_lock(&core->cal_data[WCD_CPE_LSM_CAL_AFE]->lock);
+	afe_cal = cal_utils_get_only_cal_block(
+			core->cal_data[WCD_CPE_LSM_CAL_AFE]);
+	if (!afe_cal) {
+		pr_err("%s: failed to get afe cal block\n",
+			__func__);
+		rc = -EINVAL;
+		goto rel_cal_mutex;
+	}
+
+	if (afe_cal->cal_data.size == 0) {
+		dev_dbg(core->dev, "%s: No AFE cal to send\n",
+			__func__);
+		rc = 0;
+		goto rel_cal_mutex;
+	}
+
+	is_obm_msg = (afe_cal->cal_data.size >
+		      CMI_INBAND_MESSAGE_SIZE) ? true : false;
+
+	if (is_obm_msg) {
+		struct cmi_hdr *hdr = &(obm_msg.hdr);
+		struct cmi_obm *pld = &(obm_msg.pld);
+
+		rc = wcd_cpe_afe_shmem_alloc(core, port_d,
+					afe_cal->cal_data.size);
+		if (rc) {
+			dev_err(core->dev,
+				"%s: AFE shmem alloc fail %d\n",
+				__func__, rc);
+			goto rel_cal_mutex;
+		}
+
+		rc = fill_afe_cmd_header(hdr, port_d->port_id,
+					 CPE_AFE_CMD_SET_PARAM,
+					 CPE_AFE_PARAM_PAYLOAD_SIZE,
+					 true);
+		if (rc) {
+			dev_err(core->dev,
+				"%s: invalid params for header, err = %d\n",
+				__func__, rc);
+			wcd_cpe_afe_shmem_dealloc(core, port_d);
+			goto rel_cal_mutex;
+		}
+
+		pld->version = 0;
+		pld->size = afe_cal->cal_data.size;
+		pld->data_ptr.kvaddr = afe_cal->cal_data.kvaddr;
+		pld->mem_handle = port_d->mem_handle;
+		msg = &obm_msg;
+
+	} else {
+		u8 *msg_pld;
+		struct cmi_hdr *hdr;
+
+		inb_msg = kzalloc(sizeof(struct cmi_hdr) +
+					afe_cal->cal_data.size,
+				  GFP_KERNEL);
+		if (!inb_msg) {
+			dev_err(core->dev,
+				"%s: no memory for afe cal inband\n",
+				__func__);
+			rc = -ENOMEM;
+			goto rel_cal_mutex;
+		}
+
+		hdr = (struct cmi_hdr *) inb_msg;
+
+		rc = fill_afe_cmd_header(hdr, port_d->port_id,
+					 CPE_AFE_CMD_SET_PARAM,
+					 CPE_AFE_PARAM_PAYLOAD_SIZE,
+					 false);
+		if (rc) {
+			dev_err(core->dev,
+				"%s: invalid params for header, err = %d\n",
+				__func__, rc);
+			kfree(inb_msg);
+			inb_msg = NULL;
+			goto rel_cal_mutex;
+		}
+
+		msg_pld = ((u8 *) inb_msg) + sizeof(struct cmi_hdr);
+		memcpy(msg_pld, afe_cal->cal_data.kvaddr,
+		       afe_cal->cal_data.size);
+
+		msg = inb_msg;
+	}
+
+	rc = wcd_cpe_cmi_send_afe_msg(core, port_d, msg);
+	if (rc)
+		pr_err("%s: afe cal for listen failed, rc = %d\n",
+			__func__, rc);
+
+	if (is_obm_msg) {
+		wcd_cpe_afe_shmem_dealloc(core, port_d);
+		port_d->mem_handle = 0;
+	} else {
+		kfree(inb_msg);
+		inb_msg = NULL;
+	}
+
+rel_cal_mutex:
+	mutex_unlock(&core->cal_data[WCD_CPE_LSM_CAL_AFE]->lock);
+	return rc;
+}
+
+/*
+ * wcd_cpe_is_valid_port: check validity of afe port id
+ * @core: handle to core to check for validity
+ * @afe_cfg: client provided afe configuration
+ * @func: function name invoking this validity check,
+ *	  used for logging purpose only.
+ */
+static int wcd_cpe_is_valid_port(struct wcd_cpe_core *core,
+		struct wcd_cpe_afe_port_cfg *afe_cfg,
+		const char *func)
+{
+	if (unlikely(IS_ERR_OR_NULL(core))) {
+		pr_err("%s: Invalid core handle\n", func);
+		return -EINVAL;
+	}
+
+	if (afe_cfg->port_id > WCD_CPE_AFE_MAX_PORTS) {
+		dev_err(core->dev,
+			"%s: invalid afe port (%u)\n",
+			func, afe_cfg->port_id);
+		return -EINVAL;
+	}
+
+	dev_dbg(core->dev,
+		"%s: port_id = %u\n",
+		func, afe_cfg->port_id);
+
+	return 0;
+}
+
+static int wcd_cpe_afe_svc_cmd_mode(void *core_handle,
+				    u8 mode)
+{
+	struct cpe_afe_svc_cmd_mode afe_mode;
+	struct wcd_cpe_core *core = core_handle;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int ret;
+
+	afe_port_d = &afe_ports[0];
+	/*
+	 * AFE SVC mode command is for the service and not port
+	 * specific, hence use AFE port as 0 so the command will
+	 * be applied to all AFE ports on CPE.
+	 */
+	afe_port_d->port_id = 0;
+
+	WCD_CPE_GRAB_LOCK(&afe_port_d->afe_lock, "afe");
+	memset(&afe_mode, 0, sizeof(afe_mode));
+	if (fill_afe_cmd_header(&afe_mode.hdr, afe_port_d->port_id,
+				CPE_AFE_SVC_CMD_LAB_MODE,
+				CPE_AFE_CMD_MODE_PAYLOAD_SIZE,
+				false)) {
+		ret = -EINVAL;
+		goto err_ret;
+	}
+
+	afe_mode.mode = mode;
+
+	ret = wcd_cpe_cmi_send_afe_msg(core, afe_port_d, &afe_mode);
+	if (ret)
+		dev_err(core->dev,
+			"%s: afe_svc_mode cmd failed, err = %d\n",
+			__func__, ret);
+
+err_ret:
+	WCD_CPE_REL_LOCK(&afe_port_d->afe_lock, "afe");
+	return ret;
+}
+
+static int wcd_cpe_afe_cmd_port_cfg(void *core_handle,
+		struct wcd_cpe_afe_port_cfg *afe_cfg)
+{
+	struct cpe_afe_cmd_port_cfg port_cfg_cmd;
+	struct wcd_cpe_core *core = core_handle;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int ret;
+
+	ret = wcd_cpe_is_valid_port(core, afe_cfg, __func__);
+	if (ret)
+		goto done;
+
+	afe_port_d = &afe_ports[afe_cfg->port_id];
+	afe_port_d->port_id = afe_cfg->port_id;
+
+	WCD_CPE_GRAB_LOCK(&afe_port_d->afe_lock, "afe");
+	memset(&port_cfg_cmd, 0, sizeof(port_cfg_cmd));
+	if (fill_afe_cmd_header(&port_cfg_cmd.hdr,
+			afe_cfg->port_id,
+			CPE_AFE_PORT_CMD_GENERIC_CONFIG,
+			CPE_AFE_CMD_PORT_CFG_PAYLOAD_SIZE,
+			false)) {
+		ret = -EINVAL;
+		goto err_ret;
+	}
+
+	port_cfg_cmd.bit_width = afe_cfg->bit_width;
+	port_cfg_cmd.num_channels = afe_cfg->num_channels;
+	port_cfg_cmd.sample_rate = afe_cfg->sample_rate;
+
+	if (afe_port_d->port_id == CPE_AFE_PORT_3_TX)
+		port_cfg_cmd.buffer_size = WCD_CPE_EC_PP_BUF_SIZE;
+	else
+		port_cfg_cmd.buffer_size = AFE_OUT_BUF_SIZE(afe_cfg->bit_width,
+							afe_cfg->sample_rate);
+
+	ret = wcd_cpe_cmi_send_afe_msg(core, afe_port_d, &port_cfg_cmd);
+	if (ret)
+		dev_err(core->dev,
+			"%s: afe_port_config failed, err = %d\n",
+			__func__, ret);
+
+err_ret:
+	WCD_CPE_REL_LOCK(&afe_port_d->afe_lock, "afe");
+done:
+	return ret;
+}
+
+/*
+ * wcd_cpe_afe_set_params: set the parameters for afe port
+ * @afe_cfg: configuration data for the port for which the
+ *	      parameters are to be set
+ */
+static int wcd_cpe_afe_set_params(void *core_handle,
+		struct wcd_cpe_afe_port_cfg *afe_cfg, bool afe_mad_ctl)
+{
+	struct cpe_afe_params afe_params;
+	struct cpe_afe_hw_mad_ctrl *hw_mad_ctrl = &afe_params.hw_mad_ctrl;
+	struct cpe_afe_port_cfg *port_cfg = &afe_params.port_cfg;
+	struct wcd_cpe_core *core = core_handle;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int ret = 0, pld_size = 0;
+
+	ret = wcd_cpe_is_valid_port(core, afe_cfg, __func__);
+	if (ret)
+		return ret;
+
+	afe_port_d = &afe_ports[afe_cfg->port_id];
+	afe_port_d->port_id = afe_cfg->port_id;
+
+	WCD_CPE_GRAB_LOCK(&afe_port_d->afe_lock, "afe");
+
+	ret = wcd_cpe_send_afe_cal(core, afe_port_d);
+	if (ret) {
+		dev_err(core->dev,
+			"%s: afe acdb cal send failed, err = %d\n",
+			__func__, ret);
+		goto err_ret;
+	}
+
+	pld_size = CPE_AFE_PARAM_PAYLOAD_SIZE;
+	memset(&afe_params, 0, sizeof(afe_params));
+
+	if (fill_afe_cmd_header(&afe_params.hdr,
+				afe_cfg->port_id,
+				CPE_AFE_CMD_SET_PARAM,
+				(u8) pld_size, false)) {
+		ret = -EINVAL;
+		goto err_ret;
+	}
+
+	hw_mad_ctrl->param.module_id = CPE_AFE_MODULE_HW_MAD;
+	hw_mad_ctrl->param.param_id = CPE_AFE_PARAM_ID_HW_MAD_CTL;
+	hw_mad_ctrl->param.p_size.sr.param_size = PARAM_SIZE_AFE_HW_MAD_CTRL;
+	hw_mad_ctrl->param.p_size.sr.reserved = 0;
+	hw_mad_ctrl->minor_version = 1;
+	hw_mad_ctrl->mad_type = MAD_TYPE_AUDIO;
+	hw_mad_ctrl->mad_enable = afe_mad_ctl;
+
+	port_cfg->param.module_id = CPE_AFE_MODULE_AUDIO_DEV_INTERFACE;
+	port_cfg->param.param_id = CPE_AFE_PARAM_ID_GENERIC_PORT_CONFIG;
+	port_cfg->param.p_size.sr.param_size = PARAM_SIZE_AFE_PORT_CFG;
+	port_cfg->param.p_size.sr.reserved = 0;
+	port_cfg->minor_version = 1;
+	port_cfg->bit_width = afe_cfg->bit_width;
+	port_cfg->num_channels = afe_cfg->num_channels;
+	port_cfg->sample_rate = afe_cfg->sample_rate;
+
+	ret = wcd_cpe_cmi_send_afe_msg(core, afe_port_d, &afe_params);
+	if (ret)
+		dev_err(core->dev,
+			"%s: afe_port_config failed, err = %d\n",
+			__func__, ret);
+err_ret:
+	WCD_CPE_REL_LOCK(&afe_port_d->afe_lock, "afe");
+	return ret;
+}
+
+/*
+ * wcd_cpe_afe_port_start: send the start command to afe service
+ * @core_handle: handle to the cpe core
+ * @port_cfg: configuration data for the afe port which needs
+ *	      to be started.
+ */
+static int wcd_cpe_afe_port_start(void *core_handle,
+			struct wcd_cpe_afe_port_cfg *port_cfg)
+{
+
+	struct cmi_hdr hdr;
+	struct wcd_cpe_core *core = core_handle;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_port(core, port_cfg, __func__);
+	if (ret)
+		return ret;
+
+	afe_port_d = &afe_ports[port_cfg->port_id];
+	afe_port_d->port_id = port_cfg->port_id;
+
+	WCD_CPE_GRAB_LOCK(&afe_port_d->afe_lock, "afe");
+
+	memset(&hdr, 0, sizeof(struct cmi_hdr));
+	fill_afe_cmd_header(&hdr, port_cfg->port_id,
+			    CPE_AFE_PORT_CMD_START,
+			    0, false);
+	ret = wcd_cpe_cmi_send_afe_msg(core, afe_port_d, &hdr);
+	if (ret)
+		dev_err(core->dev,
+			"%s: afe_port_start cmd failed, err = %d\n",
+			__func__, ret);
+	WCD_CPE_REL_LOCK(&afe_port_d->afe_lock, "afe");
+	return ret;
+}
+
+/*
+ * wcd_cpe_afe_port_stop: send stop command to afe service
+ * @core_handle: handle to the cpe core
+ * @port_cfg: configuration data for the afe port which needs
+ *	      to be stopped.
+ */
+static int wcd_cpe_afe_port_stop(void *core_handle,
+	struct wcd_cpe_afe_port_cfg *port_cfg)
+{
+	struct cmi_hdr hdr;
+	struct wcd_cpe_core *core = core_handle;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_port(core, port_cfg, __func__);
+	if (ret)
+		return ret;
+
+	afe_port_d = &afe_ports[port_cfg->port_id];
+	afe_port_d->port_id = port_cfg->port_id;
+
+	WCD_CPE_GRAB_LOCK(&afe_port_d->afe_lock, "afe");
+
+	memset(&hdr, 0, sizeof(hdr));
+	fill_afe_cmd_header(&hdr, port_cfg->port_id,
+			    CPE_AFE_PORT_CMD_STOP,
+			    0, false);
+	ret = wcd_cpe_cmi_send_afe_msg(core, afe_port_d, &hdr);
+	if (ret)
+		dev_err(core->dev,
+			"%s: afe_stop cmd failed, err = %d\n",
+			__func__, ret);
+
+	WCD_CPE_REL_LOCK(&afe_port_d->afe_lock, "afe");
+	return ret;
+}
+
+/*
+ * wcd_cpe_afe_port_suspend: send suspend command to afe service
+ * @core_handle: handle to the cpe core
+ * @port_cfg: configuration data for the afe port which needs
+ *	      to be suspended.
+ */
+static int wcd_cpe_afe_port_suspend(void *core_handle,
+		struct wcd_cpe_afe_port_cfg *port_cfg)
+{
+	struct cmi_hdr hdr;
+	struct wcd_cpe_core *core = core_handle;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_port(core, port_cfg, __func__);
+	if (ret)
+		return ret;
+
+	afe_port_d = &afe_ports[port_cfg->port_id];
+	afe_port_d->port_id = port_cfg->port_id;
+
+	WCD_CPE_GRAB_LOCK(&afe_port_d->afe_lock, "afe");
+
+	memset(&hdr, 0, sizeof(struct cmi_hdr));
+	fill_afe_cmd_header(&hdr, port_cfg->port_id,
+			    CPE_AFE_PORT_CMD_SUSPEND,
+			    0, false);
+	ret = wcd_cpe_cmi_send_afe_msg(core, afe_port_d, &hdr);
+	if (ret)
+		dev_err(core->dev,
+			"%s: afe_suspend cmd failed, err = %d\n",
+			__func__, ret);
+	WCD_CPE_REL_LOCK(&afe_port_d->afe_lock, "afe");
+	return ret;
+}
+
+/*
+ * wcd_cpe_afe_port_resume: send the resume command to afe service
+ * @core_handle: handle to the cpe core
+ * @port_cfg: configuration data for the afe port which needs
+ *	      to be resumed.
+ */
+static int wcd_cpe_afe_port_resume(void *core_handle,
+		struct wcd_cpe_afe_port_cfg *port_cfg)
+{
+	struct cmi_hdr hdr;
+	struct wcd_cpe_core *core = core_handle;
+	struct wcd_cmi_afe_port_data *afe_port_d;
+	int ret = 0;
+
+	ret = wcd_cpe_is_valid_port(core, port_cfg, __func__);
+	if (ret)
+		return ret;
+
+	afe_port_d = &afe_ports[port_cfg->port_id];
+	afe_port_d->port_id = port_cfg->port_id;
+
+	WCD_CPE_GRAB_LOCK(&afe_port_d->afe_lock, "afe");
+
+	memset(&hdr, 0, sizeof(hdr));
+	fill_afe_cmd_header(&hdr, port_cfg->port_id,
+			    CPE_AFE_PORT_CMD_RESUME,
+			    0, false);
+	ret = wcd_cpe_cmi_send_afe_msg(core, afe_port_d, &hdr);
+	if (ret)
+		dev_err(core->dev,
+			"%s: afe_resume cmd failed, err = %d\n",
+			__func__, ret);
+	WCD_CPE_REL_LOCK(&afe_port_d->afe_lock, "afe");
+	return ret;
+
+}
+
+/*
+ * wcd_cpe_register_afe_driver: register lsm driver to codec
+ * @cpe_ops: structure with lsm callbacks
+ * @codec: codec to which this lsm driver is registered to
+ */
+int wcd_cpe_get_afe_ops(struct wcd_cpe_afe_ops *afe_ops)
+{
+	afe_ops->afe_set_params = wcd_cpe_afe_set_params;
+	afe_ops->afe_port_start = wcd_cpe_afe_port_start;
+	afe_ops->afe_port_stop = wcd_cpe_afe_port_stop;
+	afe_ops->afe_port_suspend = wcd_cpe_afe_port_suspend;
+	afe_ops->afe_port_resume = wcd_cpe_afe_port_resume;
+	afe_ops->afe_port_cmd_cfg = wcd_cpe_afe_cmd_port_cfg;
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd_cpe_get_afe_ops);
+
+MODULE_DESCRIPTION("WCD CPE Core");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd_cpe_core.h b/asoc/codecs/wcd_cpe_core.h
new file mode 100644
index 0000000..3d672b8
--- /dev/null
+++ b/asoc/codecs/wcd_cpe_core.h
@@ -0,0 +1,226 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef WCD_CPE_CORE_H
+#define WCD_CPE_CORE_H
+
+#include <soc/qcom/ramdump.h>
+#include <linux/dma-mapping.h>
+#include "wcd_cpe_services.h"
+
+#define WCD_CPE_LAB_MAX_LATENCY 250
+#define WCD_CPE_MAD_SLIM_CHANNEL 140
+
+/* Indicates CPE block is ready for image re-download */
+#define WCD_CPE_BLK_READY  (1 << 0)
+/* Indicates the underlying bus is ready */
+#define WCD_CPE_BUS_READY (1 << 1)
+
+/*
+ * only when the underlying bus and CPE block both are ready,
+ * the state will be ready to download
+ */
+#define WCD_CPE_READY_TO_DLOAD	\
+	(WCD_CPE_BLK_READY | WCD_CPE_BUS_READY)
+
+#define WCD_CPE_LOAD_IMEM (1 << 0)
+#define WCD_CPE_LOAD_DATA (1 << 1)
+#define WCD_CPE_LOAD_ALL \
+	(WCD_CPE_LOAD_IMEM | WCD_CPE_LOAD_DATA)
+
+#define WCD_CPE_IMAGE_FNAME_MAX 64
+
+#define WCD_CPE_AFE_OUT_PORT_2 2
+#define WCD_CPE_AFE_OUT_PORT_4 4
+
+enum {
+	WCD_CPE_LSM_CAL_AFE = 0,
+	WCD_CPE_LSM_CAL_LSM,
+	WCD_CPE_LSM_CAL_TOPOLOGY_ID,
+	WCD_CPE_LSM_CAL_MAX,
+};
+
+enum cpe_err_irq_cntl_type {
+	CPE_ERR_IRQ_MASK = 0,
+	CPE_ERR_IRQ_UNMASK,
+	CPE_ERR_IRQ_CLEAR,
+	CPE_ERR_IRQ_STATUS,
+};
+
+struct wcd_cpe_cdc_cb {
+	/* codec provided callback to enable RCO */
+	int (*cdc_clk_en)(struct snd_soc_codec *, bool);
+
+	/* callback for FLL setup for codec */
+	int (*cpe_clk_en)(struct snd_soc_codec *, bool);
+	int (*cdc_ext_clk)(struct snd_soc_codec *codec, int enable, bool dapm);
+	int (*lab_cdc_ch_ctl)(struct snd_soc_codec *codec, u8 event);
+	int (*get_afe_out_port_id)(struct snd_soc_codec *codec, u16 *port_id);
+	int (*bus_vote_bw)(struct snd_soc_codec *codec,
+			   bool vote);
+
+	/* Callback to control the cpe error interrupt mask/status/clear */
+	int (*cpe_err_irq_control)(struct snd_soc_codec *codec,
+				    enum cpe_err_irq_cntl_type cntl_type,
+				    u8 *status);
+};
+
+enum wcd_cpe_ssr_state_event {
+	/* Indicates CPE is initialized */
+	WCD_CPE_INITIALIZED = 0,
+	/* Indicates that IMEM is downloaded to CPE */
+	WCD_CPE_IMEM_DOWNLOADED,
+	/* Indicates CPE is enabled */
+	WCD_CPE_ENABLED,
+	/* Indicates that CPE is currently active */
+	WCD_CPE_ACTIVE,
+	/* Event from underlying bus notifying bus is down */
+	WCD_CPE_BUS_DOWN_EVENT,
+	/* Event from CPE block, notifying CPE is down */
+	WCD_CPE_SSR_EVENT,
+	/* Event from underlying bus notifying bus is up */
+	WCD_CPE_BUS_UP_EVENT,
+};
+
+struct wcd_cpe_ssr_entry {
+	int offline;
+	u32 offline_change;
+	wait_queue_head_t offline_poll_wait;
+	struct snd_info_entry *entry;
+};
+
+struct wcd_cpe_irq_info {
+	int cpe_engine_irq;
+	int cpe_err_irq;
+	u8 cpe_fatal_irqs;
+};
+
+struct wcd_cpe_hw_info {
+	u32 dram_offset;
+	size_t dram_size;
+	u32 iram_offset;
+	size_t iram_size;
+};
+
+struct wcd_cpe_core {
+	/* handle to cpe services */
+	void *cpe_handle;
+
+	/* registration handle to cpe services */
+	void *cpe_reg_handle;
+
+	/* cmi registration handle for afe service */
+	void *cmi_afe_handle;
+
+	/* handle to codec */
+	struct snd_soc_codec *codec;
+
+	/* codec device */
+	struct device *dev;
+
+	/* firmware image file name */
+	char fname[WCD_CPE_IMAGE_FNAME_MAX];
+
+	/* firmware image file name from sysfs */
+	char dyn_fname[WCD_CPE_IMAGE_FNAME_MAX];
+
+	/* codec information needed by cpe services */
+	struct cpe_svc_codec_info_v1 cdc_info;
+
+	/* work to perform image download */
+	struct work_struct load_fw_work;
+
+	/* flag to indicate mode in which cpe needs to be booted */
+	int cpe_debug_mode;
+
+	/* callbacks for codec specific implementation */
+	const struct wcd_cpe_cdc_cb *cpe_cdc_cb;
+
+	/* work to handle CPE SSR*/
+	struct work_struct ssr_work;
+
+	/* PM handle for suspend mode during SSR */
+	struct pm_qos_request pm_qos_req;
+
+	/* completion event indicating CPE OFFLINE */
+	struct completion offline_compl;
+
+	/* entry into snd card procfs indicating cpe status */
+	struct wcd_cpe_ssr_entry ssr_entry;
+
+	/*
+	 * completion event to signal CPE is
+	 * ready for image re-download
+	 */
+	struct completion ready_compl;
+
+	/* maintains the status for cpe ssr */
+	u8 ready_status;
+
+	/* Indicate SSR type */
+	enum wcd_cpe_ssr_state_event ssr_type;
+
+	/* mutex to protect cpe ssr status variables */
+	struct mutex ssr_lock;
+
+	/* Store the calibration data needed for cpe */
+	struct cal_type_data *cal_data[WCD_CPE_LSM_CAL_MAX];
+
+	/* completion event to signal CPE is online */
+	struct completion online_compl;
+
+	/* reference counter for cpe usage */
+	u8 cpe_users;
+
+	/* Ramdump support */
+	void *cpe_ramdump_dev;
+	struct ramdump_segment cpe_ramdump_seg;
+	dma_addr_t cpe_dump_addr;
+	void *cpe_dump_v_addr;
+
+	/* SFR support */
+	u32 sfr_buf_addr;
+	size_t sfr_buf_size;
+
+	/* IRQ information for CPE interrupts */
+	struct wcd_cpe_irq_info irq_info;
+
+	/* Kobject for sysfs entry */
+	struct kobject cpe_kobj;
+
+	/* Reference count for cpe clk*/
+	int cpe_clk_ref;
+
+	/* codec based hardware info */
+	struct wcd_cpe_hw_info hw_info;
+};
+
+struct wcd_cpe_params {
+	struct snd_soc_codec *codec;
+	struct wcd_cpe_core * (*get_cpe_core)(
+				struct snd_soc_codec *);
+	const struct wcd_cpe_cdc_cb *cdc_cb;
+	int dbg_mode;
+	u16 cdc_major_ver;
+	u16 cdc_minor_ver;
+	u32 cdc_id;
+
+	struct wcd_cpe_irq_info cdc_irq_info;
+
+	struct cpe_svc_init_param *cpe_svc_params;
+};
+
+int wcd_cpe_ssr_event(void *core_handle,
+		      enum wcd_cpe_ssr_state_event event);
+struct wcd_cpe_core *wcd_cpe_init(const char *img_fname,
+struct snd_soc_codec *codec, struct wcd_cpe_params *params);
+#endif
diff --git a/asoc/codecs/wcd_cpe_services.c b/asoc/codecs/wcd_cpe_services.c
new file mode 100644
index 0000000..7a0e703
--- /dev/null
+++ b/asoc/codecs/wcd_cpe_services.c
@@ -0,0 +1,2726 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+#include <linux/mfd/wcd9xxx/wcd9330_registers.h>
+#include <linux/mfd/wcd9335/registers.h>
+#include "core.h"
+#include "cpe_cmi.h"
+#include "wcd_cpe_services.h"
+#include "wcd_cmi_api.h"
+
+#define CPE_MSG_BUFFER_SIZE 132
+#define CPE_NO_SERVICE 0
+
+#define CMI_DRIVER_SUPPORTED_VERSION 0
+#define CMI_API_SUCCESS 0
+#define CMI_MSG_TRANSPORT (0x0002)
+#define CPE_SVC_INACTIVE_STATE_RETRIES_MAX 10
+
+#define TOMTOM_A_SVASS_SPE_DRAM_OFFSET				0x50000
+#define TOMTOM_A_SVASS_SPE_DRAM_SIZE				0x30000
+#define TOMTOM_A_SVASS_SPE_IRAM_OFFSET				0x80000
+#define TOMTOM_A_SVASS_SPE_IRAM_SIZE				0xC000
+#define TOMTOM_A_SVASS_SPE_INBOX_SIZE				12
+#define TOMTOM_A_SVASS_SPE_OUTBOX_SIZE				12
+
+#define MEM_ACCESS_NONE_VAL			0x0
+#define MEM_ACCESS_IRAM_VAL			0x1
+#define MEM_ACCESS_DRAM_VAL			0x2
+#define LISTEN_CTL_SPE_VAL			0x0
+#define LISTEN_CTL_MSM_VAL			0x1
+
+#define WCD9335_CPE_SS_SPE_DRAM_OFFSET		0x48000
+#define WCD9335_CPE_SS_SPE_DRAM_SIZE		0x34000
+#define WCD9335_CPE_SS_SPE_IRAM_OFFSET		0x80000
+#define WCD9335_CPE_SS_SPE_IRAM_SIZE		0x20000
+
+#define WCD9335_CPE_SS_SPE_INBOX_SIZE		16
+#define WCD9335_CPE_SS_SPE_OUTBOX_SIZE		16
+#define WCD9335_CPE_SS_SPE_MEM_BANK_SIZ		16
+
+#define WCD9335_CPE_SS_SPE_INBOX1(N)	(WCD9335_CPE_SS_INBOX1_0 + (N))
+#define WCD9335_CPE_SS_SPE_OUTBOX1(N)	(WCD9335_CPE_SS_OUTBOX1_0 + (N))
+#define WCD9335_CPE_SS_MEM_BANK(N)	(WCD9335_CPE_SS_MEM_BANK_0 + (N))
+
+#define CHUNK_SIZE 16
+
+#define CPE_SVC_GRAB_LOCK(lock, name)		\
+{						\
+	pr_debug("%s: %s lock acquire\n",	\
+		 __func__, name);		\
+	mutex_lock(lock);			\
+}
+
+#define CPE_SVC_REL_LOCK(lock, name)		\
+{						\
+	pr_debug("%s: %s lock release\n",	\
+		 __func__, name);		\
+	mutex_unlock(lock);			\
+}
+
+static const struct cpe_svc_hw_cfg cpe_svc_tomtom_info = {
+	TOMTOM_A_SVASS_SPE_DRAM_SIZE,
+	TOMTOM_A_SVASS_SPE_DRAM_OFFSET,
+	TOMTOM_A_SVASS_SPE_IRAM_SIZE,
+	TOMTOM_A_SVASS_SPE_IRAM_OFFSET,
+	TOMTOM_A_SVASS_SPE_INBOX_SIZE,
+	TOMTOM_A_SVASS_SPE_OUTBOX_SIZE
+};
+
+static const struct cpe_svc_hw_cfg cpe_svc_wcd9335_info = {
+	WCD9335_CPE_SS_SPE_DRAM_SIZE,
+	WCD9335_CPE_SS_SPE_DRAM_OFFSET,
+	WCD9335_CPE_SS_SPE_IRAM_SIZE,
+	WCD9335_CPE_SS_SPE_IRAM_OFFSET,
+	WCD9335_CPE_SS_SPE_INBOX_SIZE,
+	WCD9335_CPE_SS_SPE_OUTBOX_SIZE
+};
+
+enum cpe_state {
+	CPE_STATE_UNINITIALIZED = 0,
+	CPE_STATE_INITIALIZED,
+	CPE_STATE_IDLE,
+	CPE_STATE_DOWNLOADING,
+	CPE_STATE_BOOTING,
+	CPE_STATE_SENDING_MSG,
+	CPE_STATE_OFFLINE,
+	CPE_STATE_BUFFERING,
+	CPE_STATE_BUFFERING_CANCELLED
+};
+
+enum cpe_substate {
+	CPE_SS_IDLE = 0,
+	CPE_SS_MSG_REQUEST_ACCESS,
+	CPE_SS_MSG_SEND_INBOX,
+	CPE_SS_MSG_SENT,
+	CPE_SS_DL_DOWNLOADING,
+	CPE_SS_DL_COMPLETED,
+	CPE_SS_BOOT,
+	CPE_SS_BOOT_INIT,
+	CPE_SS_ONLINE
+};
+
+enum cpe_command {
+	CPE_CMD_KILL_THREAD = 0,
+	CPE_CMD_BOOT,
+	CPE_CMD_BOOT_INITIALIZE,
+	CPE_CMD_BOOT_COMPLETE,
+	CPE_CMD_SEND_MSG,
+	CPE_CMD_SEND_TRANS_MSG,
+	CPE_CMD_SEND_MSG_COMPLETE,
+	CPE_CMD_PROCESS_IRQ,
+	CPE_CMD_RAMDUMP,
+	CPE_CMD_DL_SEGMENT,
+	CPE_CMD_SHUTDOWN,
+	CPE_CMD_RESET,
+	CPE_CMD_DEINITIALIZE,
+	CPE_CMD_READ,
+	CPE_CMD_ENABLE_LAB,
+	CPE_CMD_DISABLE_LAB,
+	CPE_CMD_SWAP_BUFFER,
+	CPE_LAB_CFG_SB,
+	CPE_CMD_CANCEL_MEMACCESS,
+	CPE_CMD_PROC_INCOMING_MSG,
+	CPE_CMD_FTM_TEST,
+};
+
+enum cpe_process_result {
+	CPE_PROC_SUCCESS = 0,
+	CPE_PROC_FAILED,
+	CPE_PROC_KILLED,
+	CPE_PROC_QUEUED,
+};
+
+struct cpe_command_node {
+	enum cpe_command command;
+	enum cpe_svc_result result;
+	void *data;
+	struct list_head list;
+};
+
+struct cpe_info {
+	struct list_head main_queue;
+	struct completion cmd_complete;
+	struct completion thread_comp;
+	void *thread_handler;
+	bool stop_thread;
+	struct mutex msg_lock;
+	enum cpe_state state;
+	enum cpe_substate substate;
+	struct list_head client_list;
+	enum cpe_process_result (*cpe_process_command)
+			(struct cpe_command_node *command_node);
+	enum cpe_svc_result (*cpe_cmd_validate)
+				(const struct cpe_info *i,
+				 enum cpe_command command);
+	enum cpe_svc_result (*cpe_start_notification)
+			     (struct cpe_info *i);
+	u32 initialized;
+	struct cpe_svc_tgt_abstraction *tgt;
+	void *pending;
+	void *data;
+	void *client_context;
+	u32 codec_id;
+	struct work_struct clk_plan_work;
+	struct completion core_svc_cmd_compl;
+};
+
+struct cpe_tgt_waiti_info {
+	u8 tgt_waiti_size;
+	u8 *tgt_waiti_data;
+};
+
+struct cpe_svc_tgt_abstraction {
+	enum cpe_svc_result (*tgt_boot)(int debug_mode);
+
+	u32 (*tgt_cpar_init_done)(void);
+
+	u32 (*tgt_is_active)(void);
+
+	enum cpe_svc_result (*tgt_reset)(void);
+
+	enum cpe_svc_result (*tgt_stop)(void);
+
+	enum cpe_svc_result (*tgt_read_mailbox)
+				(u8 *buffer, size_t size);
+
+	enum cpe_svc_result (*tgt_write_mailbox)
+				(u8 *buffer, size_t size);
+
+	enum cpe_svc_result (*tgt_read_ram)
+				(struct cpe_info *c,
+				 struct cpe_svc_mem_segment *data);
+
+	enum cpe_svc_result (*tgt_write_ram)
+				(struct cpe_info *c,
+				const struct cpe_svc_mem_segment *data);
+
+	enum cpe_svc_result (*tgt_route_notification)
+				(enum cpe_svc_module module,
+				 enum cpe_svc_route_dest dest);
+
+	enum cpe_svc_result (*tgt_set_debug_mode)(u32 enable);
+	const struct cpe_svc_hw_cfg *(*tgt_get_cpe_info)(void);
+	enum cpe_svc_result (*tgt_deinit)
+				(struct cpe_svc_tgt_abstraction *param);
+	enum cpe_svc_result (*tgt_voice_tx_lab)
+				(bool);
+	u8 *inbox;
+	u8 *outbox;
+	struct cpe_tgt_waiti_info *tgt_waiti_info;
+};
+
+static enum cpe_svc_result cpe_tgt_tomtom_init(
+	struct cpe_svc_codec_info_v1 *codec_info,
+	struct cpe_svc_tgt_abstraction *param);
+
+static enum cpe_svc_result cpe_tgt_wcd9335_init(
+	struct cpe_svc_codec_info_v1 *codec_info,
+	struct cpe_svc_tgt_abstraction *param);
+
+struct cpe_send_msg {
+	u8 *payload;
+	u32 isobm;
+	u32 address;
+	size_t size;
+};
+
+struct cpe_read_handle {
+	void *registration;
+	struct cpe_info t_info;
+	struct list_head buffers;
+	void *config;
+};
+
+struct generic_notification {
+	void (*notification)
+		(const struct cpe_svc_notification *parameter);
+	void (*cmi_notification)
+		(const struct cmi_api_notification *parameter);
+};
+
+struct cpe_notif_node {
+	struct generic_notification notif;
+	u32 mask;
+	u32 service;
+	const struct cpe_info *context;
+	const char *name;
+	u32 disabled;
+	struct list_head list;
+};
+
+struct cpe_priv {
+	struct cpe_info *cpe_default_handle;
+	void (*cpe_irq_control_callback)(u32 enable);
+	void (*cpe_query_freq_plans_cb)
+		(void *cdc_priv,
+		 struct cpe_svc_cfg_clk_plan *clk_freq);
+	void (*cpe_change_freq_plan_cb)(void *cdc_priv,
+			u32 clk_freq);
+	u32 cpe_msg_buffer;
+	void *cpe_cmi_handle;
+	struct mutex cpe_api_mutex;
+	struct mutex cpe_svc_lock;
+	struct cpe_svc_boot_event cpe_debug_vector;
+	void *cdc_priv;
+};
+
+static struct cpe_priv cpe_d;
+
+static enum cpe_svc_result __cpe_svc_shutdown(void *cpe_handle);
+
+static enum cpe_svc_result cpe_is_command_valid(
+		const struct cpe_info *t_info,
+		enum cpe_command command);
+
+static int cpe_register_read(u32 reg, u8 *val)
+{
+	*(val) = snd_soc_read(cpe_d.cdc_priv, reg);
+	return 0;
+}
+
+static enum cpe_svc_result cpe_update_bits(u32 reg,
+		u32 mask, u32 value)
+{
+	int ret = 0;
+
+	ret = snd_soc_update_bits(cpe_d.cdc_priv, reg,
+				  mask, value);
+	if (ret < 0)
+		return CPE_SVC_FAILED;
+
+	return CPE_SVC_SUCCESS;
+}
+
+static int cpe_register_write(u32 reg, u32 val)
+{
+	int ret = 0;
+
+	if (reg != WCD9335_CPE_SS_MEM_BANK_0)
+		pr_debug("%s: reg = 0x%x, value = 0x%x\n",
+			  __func__, reg, val);
+
+	ret = snd_soc_write(cpe_d.cdc_priv, reg, val);
+	if (ret < 0)
+		return CPE_SVC_FAILED;
+
+	return CPE_SVC_SUCCESS;
+}
+
+static int cpe_register_write_repeat(u32 reg, u8 *ptr, u32 to_write)
+{
+	struct snd_soc_codec *codec = cpe_d.cdc_priv;
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
+	int ret = 0;
+
+	ret = wcd9xxx_slim_write_repeat(wcd9xxx, reg, to_write, ptr);
+	if (ret != 0)
+		pr_err("%s: slim_write_repeat failed\n", __func__);
+
+	if (ret < 0)
+		return CPE_SVC_FAILED;
+
+	return CPE_SVC_SUCCESS;
+}
+
+static bool cpe_register_read_autoinc_supported(void)
+{
+	return true;
+}
+
+
+/* Called under msgq locked context */
+static void cpe_cmd_received(struct cpe_info *t_info)
+{
+	struct cpe_command_node *node = NULL;
+	enum cpe_process_result proc_rc = CPE_PROC_SUCCESS;
+
+	if (!t_info) {
+		pr_err("%s: Invalid thread info\n",
+			__func__);
+		return;
+	}
+
+	while (!list_empty(&t_info->main_queue)) {
+		if (proc_rc != CPE_PROC_SUCCESS)
+			break;
+		node = list_first_entry(&t_info->main_queue,
+					struct cpe_command_node, list);
+		if (!node)
+			break;
+		list_del(&node->list);
+		proc_rc = t_info->cpe_process_command(node);
+		pr_debug("%s: process command return %d\n",
+			 __func__, proc_rc);
+
+		switch (proc_rc) {
+		case CPE_PROC_SUCCESS:
+			kfree(node);
+			break;
+		case CPE_PROC_FAILED:
+			kfree(node);
+			pr_err("%s: cmd failed\n", __func__);
+			break;
+		case CPE_PROC_KILLED:
+			break;
+		default:
+			list_add(&node->list, &(t_info->main_queue));
+
+		}
+	}
+}
+
+static int cpe_worker_thread(void *context)
+{
+	struct cpe_info *t_info = (struct cpe_info *)context;
+
+	/*
+	 * Thread will run until requested to stop explicitly
+	 * by setting the t_info->stop_thread flag
+	 */
+	while (1) {
+		/* Wait for command to be processed */
+		wait_for_completion(&t_info->cmd_complete);
+
+		CPE_SVC_GRAB_LOCK(&t_info->msg_lock, "msg_lock");
+		cpe_cmd_received(t_info);
+		reinit_completion(&t_info->cmd_complete);
+		/* Check if thread needs to be stopped */
+		if (t_info->stop_thread)
+			goto unlock_and_exit;
+		CPE_SVC_REL_LOCK(&t_info->msg_lock, "msg_lock");
+	};
+
+unlock_and_exit:
+	pr_debug("%s: thread stopped\n", __func__);
+	CPE_SVC_REL_LOCK(&t_info->msg_lock, "msg_lock");
+	complete_and_exit(&t_info->thread_comp, 0);
+}
+
+static void cpe_create_worker_thread(struct cpe_info *t_info)
+{
+	INIT_LIST_HEAD(&t_info->main_queue);
+	init_completion(&t_info->cmd_complete);
+	init_completion(&t_info->thread_comp);
+	t_info->stop_thread = false;
+	t_info->thread_handler = kthread_run(cpe_worker_thread,
+		(void *)t_info, "cpe-worker-thread");
+	pr_debug("%s: Created new worker thread\n",
+		 __func__);
+}
+
+static void cpe_cleanup_worker_thread(struct cpe_info *t_info)
+{
+	if (!t_info->thread_handler) {
+		pr_err("%s: thread not created\n", __func__);
+		return;
+	}
+
+	/*
+	 * Wake up the command handler in case
+	 * it is waiting for an command to be processed.
+	 */
+	CPE_SVC_GRAB_LOCK(&t_info->msg_lock, "msg_lock");
+	t_info->stop_thread = true;
+	complete(&t_info->cmd_complete);
+	CPE_SVC_REL_LOCK(&t_info->msg_lock, "msg_lock");
+
+	/* Wait for the thread to exit */
+	wait_for_completion(&t_info->thread_comp);
+	t_info->thread_handler = NULL;
+
+	pr_debug("%s: Thread cleaned up successfully\n",
+		 __func__);
+}
+
+static enum cpe_svc_result
+cpe_send_cmd_to_thread(struct cpe_info *t_info,
+	enum cpe_command command, void *data,
+	bool high_prio)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_command_node *cmd = NULL;
+
+	rc = cpe_is_command_valid(t_info, command);
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: Invalid command %d\n",
+			__func__, command);
+		return rc;
+	}
+
+	cmd = kzalloc(sizeof(struct cpe_command_node),
+		      GFP_ATOMIC);
+	if (!cmd)
+		return CPE_SVC_NO_MEMORY;
+
+	cmd->command = command;
+	cmd->data = data;
+
+	CPE_SVC_GRAB_LOCK(&t_info->msg_lock, "msg_lock");
+	if (high_prio)
+		list_add(&(cmd->list),
+			 &(t_info->main_queue));
+	else
+		list_add_tail(&(cmd->list),
+			      &(t_info->main_queue));
+	complete(&t_info->cmd_complete);
+	CPE_SVC_REL_LOCK(&t_info->msg_lock, "msg_lock");
+
+	return rc;
+}
+
+static enum cpe_svc_result cpe_change_state(
+	struct cpe_info *t_info,
+	enum cpe_state state, enum cpe_substate ss)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	t_info->state = state;
+	t_info->substate = ss;
+
+	pr_debug("%s: current state: %d,%d, new_state: %d,%d\n",
+		 __func__, t_info->state, t_info->substate,
+		 state, ss);
+
+	return rc;
+}
+
+static enum cpe_svc_result
+cpe_is_command_valid(const struct cpe_info *t_info,
+		enum cpe_command command)
+{
+	enum cpe_svc_result rc = CPE_SVC_INVALID_HANDLE;
+
+	if (t_info && t_info->cpe_cmd_validate)
+		rc = t_info->cpe_cmd_validate(t_info, command);
+	else
+		pr_err("%s: invalid handle or callback\n",
+			__func__);
+	return rc;
+}
+
+static void cpe_notify_client(struct cpe_notif_node *client,
+		struct cpe_svc_notification *payload)
+{
+	if (!client || !payload) {
+		pr_err("%s: invalid client or payload\n",
+			__func__);
+		return;
+	}
+
+	if (!(client->mask & payload->event)) {
+		pr_debug("%s: client mask 0x%x not registered for event 0x%x\n",
+			 __func__, client->mask, payload->event);
+		return;
+	}
+
+	if (client->notif.notification && !client->disabled)
+		client->notif.notification(payload);
+
+	if ((client->mask & CPE_SVC_CMI_MSG) &&
+	     client->notif.cmi_notification)
+		client->notif.cmi_notification(
+			(const struct cmi_api_notification *)payload);
+}
+
+static void cpe_broadcast_notification(const struct cpe_info *t_info,
+		struct cpe_svc_notification *payload)
+{
+	struct cpe_notif_node *n = NULL;
+
+	if (!t_info || !payload) {
+		pr_err("%s: invalid handle\n", __func__);
+		return;
+	}
+
+	pr_debug("%s: notify clients, event = %d\n",
+		 __func__, payload->event);
+	payload->private_data = cpe_d.cdc_priv;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+	list_for_each_entry(n, &t_info->client_list, list) {
+		if (!(n->mask & CPE_SVC_CMI_MSG))
+			cpe_notify_client(n, payload);
+	}
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+}
+
+static void *cpe_register_generic(struct cpe_info *t_info,
+		void notification_callback(
+			const struct cpe_svc_notification *parameter),
+		void cmi_callback(
+			const struct cmi_api_notification *parameter),
+		u32 mask, u32 service, const char *name)
+{
+	struct cpe_notif_node *n = NULL;
+
+	n = kzalloc(sizeof(struct cpe_notif_node),
+		    GFP_KERNEL);
+	if (!n)
+		return NULL;
+	n->mask = mask;
+	n->service = service;
+	n->notif.notification = notification_callback;
+	n->notif.cmi_notification = cmi_callback;
+	n->context = t_info;
+	n->disabled = false;
+	n->name = name;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+	/* Make sure CPE core service is first */
+	if (service == CMI_CPE_CORE_SERVICE_ID)
+		list_add(&n->list, &t_info->client_list);
+	else
+		list_add_tail(&n->list, &t_info->client_list);
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+
+	return n;
+}
+
+static enum cpe_svc_result cpe_deregister_generic(struct cpe_info *t_info,
+		void *reg_handle)
+{
+	struct cpe_notif_node *n = (struct cpe_notif_node *)reg_handle;
+
+	if (!t_info || !reg_handle) {
+		pr_err("%s: invalid handle\n", __func__);
+		return CPE_SVC_INVALID_HANDLE;
+	}
+
+	list_del(&(n->list));
+	kfree(reg_handle);
+
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result cpe_svc_tgt_init(struct cpe_svc_codec_info_v1 *i,
+		struct cpe_svc_tgt_abstraction *abs)
+{
+	if (!i || !abs) {
+		pr_err("%s: Incorrect information provided\n",
+			__func__);
+		return CPE_SVC_FAILED;
+	}
+
+	switch (i->id) {
+	case CPE_SVC_CODEC_TOMTOM:
+		return cpe_tgt_tomtom_init(i, abs);
+	case CPE_SVC_CODEC_WCD9335:
+		return cpe_tgt_wcd9335_init(i, abs);
+	default:
+		pr_err("%s: Codec type %d not supported\n",
+			__func__, i->id);
+		return CPE_SVC_FAILED;
+	}
+
+	return CPE_SVC_SUCCESS;
+}
+
+static void cpe_notify_cmi_client(struct cpe_info *t_info, u8 *payload,
+		enum cpe_svc_result result)
+{
+	struct cpe_notif_node *n = NULL;
+	struct cmi_api_notification notif;
+	struct cmi_hdr *hdr;
+	u8 service = 0;
+
+	if (!t_info || !payload) {
+		pr_err("%s: invalid payload/handle\n",
+			__func__);
+		return;
+	}
+
+	hdr = CMI_GET_HEADER(payload);
+	service = CMI_HDR_GET_SERVICE(hdr);
+
+	notif.event = CPE_SVC_CMI_MSG;
+	notif.result = result;
+	notif.message = payload;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+	list_for_each_entry(n, &t_info->client_list, list) {
+
+		if ((n->mask & CPE_SVC_CMI_MSG) &&
+		    n->service == service &&
+		    n->notif.cmi_notification) {
+			n->notif.cmi_notification(&notif);
+			break;
+		}
+	}
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+}
+
+static void cpe_toggle_irq_notification(struct cpe_info *t_info, u32 value)
+{
+	if (cpe_d.cpe_irq_control_callback)
+		cpe_d.cpe_irq_control_callback(value);
+}
+
+static void cpe_command_cleanup(struct cpe_command_node *command_node)
+{
+	switch (command_node->command) {
+	case CPE_CMD_SEND_MSG:
+	case CPE_CMD_SEND_TRANS_MSG:
+	case CPE_CMD_SEND_MSG_COMPLETE:
+	case CPE_CMD_SHUTDOWN:
+	case CPE_CMD_READ:
+		kfree(command_node->data);
+		command_node->data = NULL;
+		break;
+	default:
+		pr_err("%s: unhandled command\n",
+			__func__);
+		break;
+	}
+}
+
+static enum cpe_svc_result cpe_send_msg_to_inbox(
+		struct cpe_info *t_info, u32 opcode,
+		struct cpe_send_msg *msg)
+{
+	size_t bytes = 0;
+	size_t inbox_size =
+		t_info->tgt->tgt_get_cpe_info()->inbox_size;
+	struct cmi_hdr *hdr;
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	memset(t_info->tgt->inbox, 0, inbox_size);
+	hdr = CMI_GET_HEADER(t_info->tgt->inbox);
+	CMI_HDR_SET_SESSION(hdr, 1);
+	CMI_HDR_SET_SERVICE(hdr, CMI_CPE_CORE_SERVICE_ID);
+	CMI_HDR_SET_VERSION(hdr, CMI_DRIVER_SUPPORTED_VERSION);
+	CMI_HDR_SET_OBM(hdr, CMI_OBM_FLAG_IN_BAND);
+
+	switch (opcode) {
+	case CPE_CORE_SVC_CMD_SHARED_MEM_ALLOC: {
+		struct cmi_core_svc_cmd_shared_mem_alloc *m;
+
+		CMI_HDR_SET_OPCODE(hdr,
+			CPE_CORE_SVC_CMD_SHARED_MEM_ALLOC);
+		CMI_HDR_SET_PAYLOAD_SIZE(hdr,
+			sizeof(struct cmi_core_svc_cmd_shared_mem_alloc));
+		m = (struct cmi_core_svc_cmd_shared_mem_alloc *)
+			CMI_GET_PAYLOAD(t_info->tgt->inbox);
+		m->size = CPE_MSG_BUFFER_SIZE;
+		pr_debug("send shared mem alloc msg to cpe inbox\n");
+		}
+		break;
+	case CPE_CORE_SVC_CMD_DRAM_ACCESS_REQ:
+		CMI_HDR_SET_OPCODE(hdr,
+			CPE_CORE_SVC_CMD_DRAM_ACCESS_REQ);
+		CMI_HDR_SET_PAYLOAD_SIZE(hdr, 0);
+		pr_debug("%s: Creating DRAM acces request msg\n",
+			 __func__);
+		break;
+
+	case CPE_CMI_BASIC_RSP_OPCODE: {
+		struct cmi_basic_rsp_result *rsp;
+
+		CMI_HDR_SET_OPCODE(hdr,
+			       CPE_CMI_BASIC_RSP_OPCODE);
+		CMI_HDR_SET_PAYLOAD_SIZE(hdr,
+			sizeof(struct cmi_basic_rsp_result));
+		rsp = (struct cmi_basic_rsp_result *)
+				CMI_GET_PAYLOAD(t_info->tgt->inbox);
+		rsp->status = 0;
+		pr_debug("%s: send basic response\n", __func__);
+		}
+		break;
+
+	default:
+		if (msg->address != 0) {
+			struct cmi_msg_transport *m = NULL;
+			struct cpe_svc_mem_segment mem_seg;
+
+			mem_seg.type = CPE_SVC_DATA_MEM;
+			if (msg->isobm) {
+				struct cmi_obm *obm = (struct cmi_obm *)
+
+				CMI_GET_PAYLOAD(msg->payload);
+				mem_seg.cpe_addr = obm->mem_handle;
+				mem_seg.data = (u8 *)obm->data_ptr.kvaddr;
+				mem_seg.size = obm->size;
+				t_info->tgt->tgt_write_ram(t_info, &mem_seg);
+			}
+
+			mem_seg.cpe_addr = msg->address;
+			mem_seg.data = msg->payload;
+			mem_seg.size = msg->size;
+			t_info->tgt->tgt_write_ram(t_info, &mem_seg);
+
+			hdr = CMI_GET_HEADER(t_info->tgt->inbox);
+			CMI_HDR_SET_OPCODE(hdr, CMI_MSG_TRANSPORT);
+			m = (struct cmi_msg_transport *)
+				CMI_GET_PAYLOAD(t_info->tgt->inbox);
+			m->addr = msg->address;
+			m->size = msg->size;
+			CMI_HDR_SET_PAYLOAD_SIZE(hdr,
+				sizeof(struct cmi_msg_transport));
+		} else {
+			memcpy(t_info->tgt->inbox, msg->payload,
+			       msg->size);
+		}
+
+		break;
+	}
+
+	pr_debug("%s: sending message to cpe inbox\n",
+		  __func__);
+	bytes = sizeof(struct cmi_hdr);
+	hdr = CMI_GET_HEADER(t_info->tgt->inbox);
+	bytes += CMI_HDR_GET_PAYLOAD_SIZE(hdr);
+	rc = t_info->tgt->tgt_write_mailbox(t_info->tgt->inbox, bytes);
+
+	return rc;
+}
+
+static bool cpe_is_cmd_clk_req(void *cmd)
+{
+	struct cmi_hdr *hdr;
+
+	hdr = CMI_GET_HEADER(cmd);
+
+	if ((CMI_HDR_GET_SERVICE(hdr) ==
+	    CMI_CPE_CORE_SERVICE_ID)) {
+		if (CMI_GET_OPCODE(cmd) ==
+		    CPE_CORE_SVC_CMD_CLK_FREQ_REQUEST)
+			return true;
+	}
+
+	return false;
+}
+
+static enum cpe_svc_result cpe_process_clk_change_req(
+		struct cpe_info *t_info)
+{
+	struct cmi_core_svc_cmd_clk_freq_request *req;
+
+	req = (struct cmi_core_svc_cmd_clk_freq_request *)
+			CMI_GET_PAYLOAD(t_info->tgt->outbox);
+
+	if (!cpe_d.cpe_change_freq_plan_cb) {
+		pr_err("%s: No support for clk freq change\n",
+			__func__);
+		return CPE_SVC_FAILED;
+	}
+
+	cpe_d.cpe_change_freq_plan_cb(cpe_d.cdc_priv,
+				      req->clk_freq);
+
+	/*send a basic response*/
+	cpe_send_msg_to_inbox(t_info,
+		CPE_CMI_BASIC_RSP_OPCODE, NULL);
+
+	return CPE_SVC_SUCCESS;
+}
+
+static void cpe_process_irq_int(u32 irq,
+		struct cpe_info *t_info)
+{
+	struct cpe_command_node temp_node;
+	struct cpe_send_msg *m;
+	u8 size = 0;
+	bool err_irq = false;
+	struct cmi_hdr *hdr;
+
+	pr_debug("%s: irq = %u\n", __func__, irq);
+
+	if (!t_info) {
+		pr_err("%s: Invalid handle\n",
+			__func__);
+		return;
+	}
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	switch (irq) {
+	case CPE_IRQ_OUTBOX_IRQ:
+		size = t_info->tgt->tgt_get_cpe_info()->outbox_size;
+		t_info->tgt->tgt_read_mailbox(t_info->tgt->outbox, size);
+		break;
+
+	case CPE_IRQ_MEM_ACCESS_ERROR:
+		err_irq = true;
+		cpe_change_state(t_info, CPE_STATE_OFFLINE, CPE_SS_IDLE);
+		break;
+
+	case CPE_IRQ_WDOG_BITE:
+	case CPE_IRQ_RCO_WDOG_INT:
+		err_irq = true;
+		__cpe_svc_shutdown(t_info);
+		break;
+
+	case CPE_IRQ_FLL_LOCK_LOST:
+	default:
+		err_irq = true;
+		break;
+	}
+
+	if (err_irq) {
+		pr_err("%s: CPE error IRQ %u occurred\n",
+			__func__, irq);
+		CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+		return;
+	}
+
+	switch (t_info->state) {
+	case CPE_STATE_BOOTING:
+
+		switch (t_info->substate) {
+		case CPE_SS_BOOT:
+			temp_node.command = CPE_CMD_BOOT_INITIALIZE;
+			temp_node.result = CPE_SVC_SUCCESS;
+			t_info->substate = CPE_SS_BOOT_INIT;
+			t_info->cpe_process_command(&temp_node);
+			break;
+
+		case CPE_SS_BOOT_INIT:
+			temp_node.command = CPE_CMD_BOOT_COMPLETE;
+			temp_node.result = CPE_SVC_SUCCESS;
+			t_info->substate = CPE_SS_ONLINE;
+			t_info->cpe_process_command(&temp_node);
+			break;
+
+		default:
+			pr_debug("%s: unhandled substate %d for state %d\n",
+				 __func__, t_info->state, t_info->substate);
+			break;
+		}
+		break;
+
+	case CPE_STATE_SENDING_MSG:
+		hdr = CMI_GET_HEADER(t_info->tgt->outbox);
+		if (CMI_GET_OPCODE(t_info->tgt->outbox) ==
+		    CPE_LSM_SESSION_EVENT_DETECTION_STATUS_V2) {
+			pr_debug("%s: session_id: %u, state: %d,%d, event received\n",
+				 __func__, CMI_HDR_GET_SESSION_ID(hdr),
+				t_info->state, t_info->substate);
+			temp_node.command = CPE_CMD_PROC_INCOMING_MSG;
+			temp_node.data = NULL;
+			t_info->cpe_process_command(&temp_node);
+			break;
+		}
+
+		m = (struct cpe_send_msg *)t_info->pending;
+
+		switch (t_info->substate) {
+		case CPE_SS_MSG_REQUEST_ACCESS:
+			cpe_send_cmd_to_thread(t_info,
+				CPE_CMD_SEND_TRANS_MSG, m, true);
+			break;
+
+		case CPE_SS_MSG_SEND_INBOX:
+			if (cpe_is_cmd_clk_req(t_info->tgt->outbox))
+				cpe_process_clk_change_req(t_info);
+			else
+				cpe_send_cmd_to_thread(t_info,
+					CPE_CMD_SEND_MSG_COMPLETE, m, true);
+			break;
+
+		default:
+			pr_debug("%s: unhandled substate %d for state %d\n",
+				 __func__, t_info->state, t_info->substate);
+			break;
+		}
+		break;
+
+	case CPE_STATE_IDLE:
+		pr_debug("%s: Message received, notifying client\n",
+			 __func__);
+		temp_node.command = CPE_CMD_PROC_INCOMING_MSG;
+		temp_node.data = NULL;
+		t_info->cpe_process_command(&temp_node);
+		break;
+
+	default:
+		pr_debug("%s: unhandled state %d\n",
+			 __func__, t_info->state);
+		break;
+	}
+
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+}
+
+
+static void broacast_boot_failed(void)
+{
+	struct cpe_info *t_info = cpe_d.cpe_default_handle;
+	struct cpe_svc_notification payload;
+
+	payload.event = CPE_SVC_BOOT_FAILED;
+	payload.result = CPE_SVC_FAILED;
+	payload.payload = NULL;
+	if (t_info)
+		payload.private_data =
+			t_info->client_context;
+	cpe_broadcast_notification(t_info, &payload);
+}
+
+static enum cpe_svc_result broadcast_boot_event(
+		struct cpe_info *t_info)
+{
+	struct cpe_svc_notification payload;
+
+	payload.event = CPE_SVC_ONLINE;
+	payload.result = CPE_SVC_SUCCESS;
+	payload.payload = NULL;
+	if (t_info)
+		payload.private_data =
+			t_info->client_context;
+	cpe_broadcast_notification(t_info, &payload);
+
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_process_result cpe_boot_initialize(struct cpe_info *t_info,
+	enum cpe_svc_result *cpe_rc)
+{
+	enum cpe_process_result rc = CPE_SVC_FAILED;
+	struct cpe_svc_notification payload;
+	struct cmi_core_svc_event_system_boot *p = NULL;
+
+	if (CMI_GET_OPCODE(t_info->tgt->outbox) !=
+		CPE_CORE_SVC_EVENT_SYSTEM_BOOT) {
+		broacast_boot_failed();
+		return rc;
+	}
+
+	p = (struct cmi_core_svc_event_system_boot *)
+		CMI_GET_PAYLOAD(t_info->tgt->outbox);
+	if (p->status != CPE_BOOT_SUCCESS) {
+		pr_err("%s: cpe boot failed, status = %d\n",
+			__func__, p->status);
+		broacast_boot_failed();
+		return rc;
+	}
+
+	/* boot was successful */
+	if (p->version ==
+	    CPE_CORE_VERSION_SYSTEM_BOOT_EVENT) {
+		cpe_d.cpe_debug_vector.debug_address =
+				p->sfr_buff_address;
+		cpe_d.cpe_debug_vector.debug_buffer_size =
+				p->sfr_buff_size;
+		cpe_d.cpe_debug_vector.status = p->status;
+		payload.event = CPE_SVC_BOOT;
+		payload.result = CPE_SVC_SUCCESS;
+		payload.payload = (void *)&cpe_d.cpe_debug_vector;
+		payload.private_data = t_info->client_context;
+		cpe_broadcast_notification(t_info, &payload);
+	}
+	cpe_change_state(t_info, CPE_STATE_BOOTING,
+			 CPE_SS_BOOT_INIT);
+	(*cpe_rc) = cpe_send_msg_to_inbox(t_info,
+			CPE_CORE_SVC_CMD_SHARED_MEM_ALLOC, NULL);
+	rc = CPE_PROC_SUCCESS;
+	return rc;
+}
+
+static void cpe_svc_core_cmi_handler(
+		const struct cmi_api_notification *parameter)
+{
+	struct cmi_hdr *hdr;
+
+	if (!parameter)
+		return;
+
+	pr_debug("%s: event = %d\n",
+		 __func__, parameter->event);
+
+	if (parameter->event != CMI_API_MSG)
+		return;
+
+	hdr = (struct cmi_hdr *) parameter->message;
+
+	if (hdr->opcode == CPE_CMI_BASIC_RSP_OPCODE) {
+		struct cmi_basic_rsp_result *result;
+
+		result = (struct cmi_basic_rsp_result *)
+			((u8 *)parameter->message) + (sizeof(*hdr));
+		if (result->status)
+			pr_err("%s: error response, error code = %u\n",
+				__func__, result->status);
+		complete(&cpe_d.cpe_default_handle->core_svc_cmd_compl);
+	}
+}
+
+static void cpe_clk_plan_work(struct work_struct *work)
+{
+	struct cpe_info *t_info = NULL;
+	size_t size = 0;
+	struct cpe_svc_cfg_clk_plan plan;
+	u8 *cmi_msg;
+	struct cmi_hdr *hdr;
+	int rc;
+
+	t_info = container_of(work, struct cpe_info, clk_plan_work);
+	if (!t_info) {
+		pr_err("%s: Invalid handle for cpe_info\n",
+			__func__);
+		return;
+	}
+
+	/* Register the core service */
+	cpe_d.cpe_cmi_handle = cmi_register(
+					cpe_svc_core_cmi_handler,
+					CMI_CPE_CORE_SERVICE_ID);
+
+	/* send the clk plan command */
+	if (!cpe_d.cpe_query_freq_plans_cb) {
+		pr_err("%s: No support for querying clk plans\n",
+			__func__);
+		return;
+	}
+
+	cpe_d.cpe_query_freq_plans_cb(cpe_d.cdc_priv, &plan);
+	size = sizeof(plan.current_clk_feq) +
+		sizeof(plan.num_clk_freqs);
+	size += plan.num_clk_freqs *
+		  sizeof(plan.clk_freqs[0]);
+	cmi_msg = kzalloc(size + sizeof(struct cmi_hdr),
+			  GFP_KERNEL);
+	if (!cmi_msg)
+		return;
+
+	hdr = (struct cmi_hdr *) cmi_msg;
+	CMI_HDR_SET_OPCODE(hdr,
+			   CPE_CORE_SVC_CMD_CFG_CLK_PLAN);
+	CMI_HDR_SET_SERVICE(hdr, CMI_CPE_CORE_SERVICE_ID);
+		CMI_HDR_SET_SESSION(hdr, 1);
+	CMI_HDR_SET_VERSION(hdr, CMI_DRIVER_SUPPORTED_VERSION);
+	CMI_HDR_SET_PAYLOAD_SIZE(hdr, size);
+	memcpy(CMI_GET_PAYLOAD(cmi_msg), &plan,
+	       size);
+	cmi_send_msg(cmi_msg);
+
+	/* Wait for clk plan command to complete */
+	rc = wait_for_completion_timeout(&t_info->core_svc_cmd_compl,
+					 (10 * HZ));
+	if (!rc) {
+		pr_err("%s: clk plan cmd timed out\n",
+			__func__);
+		goto cmd_fail;
+	}
+
+	/* clk plan cmd is successful, send start notification */
+	if (t_info->cpe_start_notification)
+		t_info->cpe_start_notification(t_info);
+	else
+		pr_err("%s: no start notification\n",
+			 __func__);
+
+cmd_fail:
+	kfree(cmi_msg);
+	cmi_deregister(cpe_d.cpe_cmi_handle);
+}
+
+static enum cpe_process_result cpe_boot_complete(
+		struct cpe_info *t_info)
+{
+	struct cmi_core_svc_cmdrsp_shared_mem_alloc *p = NULL;
+
+	if (CMI_GET_OPCODE(t_info->tgt->outbox) !=
+		CPE_CORE_SVC_CMDRSP_SHARED_MEM_ALLOC) {
+		broacast_boot_failed();
+		return CPE_PROC_FAILED;
+	}
+
+	p = (struct cmi_core_svc_cmdrsp_shared_mem_alloc *)
+		CMI_GET_PAYLOAD(t_info->tgt->outbox);
+	cpe_d.cpe_msg_buffer = p->addr;
+
+	if (cpe_d.cpe_msg_buffer == 0) {
+		pr_err("%s: Invalid cpe buffer for message\n",
+			__func__);
+		broacast_boot_failed();
+		return CPE_PROC_FAILED;
+	}
+
+	cpe_change_state(t_info, CPE_STATE_IDLE, CPE_SS_IDLE);
+	cpe_create_worker_thread(t_info);
+
+	if (t_info->codec_id != CPE_SVC_CODEC_TOMTOM) {
+		schedule_work(&t_info->clk_plan_work);
+	} else {
+		if (t_info->cpe_start_notification)
+			t_info->cpe_start_notification(t_info);
+		else
+			pr_err("%s: no start notification\n",
+				__func__);
+	}
+
+	pr_debug("%s: boot complete\n", __func__);
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_process_result cpe_process_send_msg(
+	struct cpe_info *t_info,
+	enum cpe_svc_result *cpe_rc,
+	struct cpe_command_node *command_node)
+{
+	enum cpe_process_result rc = CPE_PROC_SUCCESS;
+	struct cpe_send_msg *m =
+		(struct cpe_send_msg *)command_node->data;
+	u32 size = m->size;
+
+	if (t_info->pending) {
+		pr_debug("%s: message queued\n", __func__);
+		*cpe_rc = CPE_SVC_SUCCESS;
+		return CPE_PROC_QUEUED;
+	}
+
+	pr_debug("%s: Send CMI message, size = %u\n",
+		 __func__, size);
+
+	if (size <= t_info->tgt->tgt_get_cpe_info()->inbox_size) {
+		pr_debug("%s: Msg fits mailbox, size %u\n",
+			 __func__, size);
+		cpe_change_state(t_info, CPE_STATE_SENDING_MSG,
+			CPE_SS_MSG_SEND_INBOX);
+		t_info->pending = m;
+		*cpe_rc = cpe_send_msg_to_inbox(t_info, 0, m);
+	} else if (size < CPE_MSG_BUFFER_SIZE) {
+		m->address = cpe_d.cpe_msg_buffer;
+		pr_debug("%s: Message req CMI mem access\n",
+			 __func__);
+		t_info->pending = m;
+		cpe_change_state(t_info, CPE_STATE_SENDING_MSG,
+			CPE_SS_MSG_REQUEST_ACCESS);
+		*cpe_rc = cpe_send_msg_to_inbox(t_info,
+			CPE_CORE_SVC_CMD_DRAM_ACCESS_REQ, m);
+	} else {
+		pr_debug("%s: Invalid msg size %u\n",
+			 __func__, size);
+		cpe_command_cleanup(command_node);
+		rc = CPE_PROC_FAILED;
+		cpe_change_state(t_info, CPE_STATE_IDLE,
+			CPE_SS_IDLE);
+	}
+
+	return rc;
+}
+
+static enum cpe_process_result cpe_process_incoming(
+		struct cpe_info *t_info)
+{
+	enum cpe_process_result rc = CPE_PROC_FAILED;
+	struct cmi_hdr *hdr;
+
+	hdr = CMI_GET_HEADER(t_info->tgt->outbox);
+
+	if (CMI_HDR_GET_SERVICE(hdr) ==
+	    CMI_CPE_CORE_SERVICE_ID) {
+		pr_debug("%s: core service message received\n",
+			 __func__);
+
+		switch (CMI_GET_OPCODE(t_info->tgt->outbox)) {
+		case CPE_CORE_SVC_CMD_CLK_FREQ_REQUEST:
+			cpe_process_clk_change_req(t_info);
+			rc = CPE_PROC_SUCCESS;
+			break;
+		case CMI_MSG_TRANSPORT:
+			pr_debug("%s: transport msg received\n",
+				 __func__);
+			rc = CPE_PROC_SUCCESS;
+			break;
+		case CPE_CMI_BASIC_RSP_OPCODE:
+			pr_debug("%s: received basic rsp\n",
+				 __func__);
+			rc = CPE_PROC_SUCCESS;
+			break;
+		default:
+			pr_debug("%s: unknown message received\n",
+				 __func__);
+			break;
+		}
+	} else {
+		/* if service id if for a CMI client, notify client */
+		pr_debug("%s: Message received, notifying client\n",
+			 __func__);
+		cpe_notify_cmi_client(t_info,
+			t_info->tgt->outbox, CPE_SVC_SUCCESS);
+		rc = CPE_PROC_SUCCESS;
+	}
+
+	return rc;
+}
+
+static enum cpe_process_result cpe_process_kill_thread(
+	struct cpe_info *t_info,
+	struct cpe_command_node *command_node)
+{
+	struct cpe_svc_notification payload;
+
+	cpe_d.cpe_msg_buffer = 0;
+	payload.result = CPE_SVC_SHUTTING_DOWN;
+	payload.event = CPE_SVC_OFFLINE;
+	payload.payload = NULL;
+	payload.private_data = t_info->client_context;
+	/*
+	 * Make state as offline before broadcasting
+	 * the message to clients.
+	 */
+	cpe_change_state(t_info, CPE_STATE_OFFLINE,
+			 CPE_SS_IDLE);
+	cpe_broadcast_notification(t_info, &payload);
+
+	return CPE_PROC_KILLED;
+}
+
+static enum cpe_process_result cpe_mt_process_cmd(
+		struct cpe_command_node *command_node)
+{
+	struct cpe_info *t_info = cpe_d.cpe_default_handle;
+	enum cpe_svc_result cpe_rc = CPE_SVC_SUCCESS;
+	enum cpe_process_result rc = CPE_PROC_SUCCESS;
+	struct cpe_send_msg *m;
+	struct cmi_hdr *hdr;
+	u8 service = 0;
+	u8 retries = 0;
+
+	if (!t_info || !command_node) {
+		pr_err("%s: Invalid handle/command node\n",
+			__func__);
+		return CPE_PROC_FAILED;
+	}
+
+	pr_debug("%s: cmd = %u\n", __func__, command_node->command);
+
+	cpe_rc = cpe_is_command_valid(t_info, command_node->command);
+
+	if (cpe_rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: Invalid command %d, err = %d\n",
+			__func__, command_node->command, cpe_rc);
+		return CPE_PROC_FAILED;
+	}
+
+	switch (command_node->command) {
+
+	case CPE_CMD_BOOT_INITIALIZE:
+		rc = cpe_boot_initialize(t_info, &cpe_rc);
+		break;
+
+	case CPE_CMD_BOOT_COMPLETE:
+		rc = cpe_boot_complete(t_info);
+		break;
+
+	case CPE_CMD_SEND_MSG:
+		rc = cpe_process_send_msg(t_info, &cpe_rc,
+					  command_node);
+		break;
+
+	case CPE_CMD_SEND_TRANS_MSG:
+		m = (struct cpe_send_msg *)command_node->data;
+
+		while (retries < CPE_SVC_INACTIVE_STATE_RETRIES_MAX) {
+			if (t_info->tgt->tgt_is_active()) {
+				++retries;
+				/* Wait for CPE to be inactive */
+				usleep_range(5000, 5100);
+			} else {
+				break;
+			}
+		}
+
+		pr_debug("%s: cpe inactive after %d attempts\n",
+			 __func__, retries);
+
+		cpe_change_state(t_info, CPE_STATE_SENDING_MSG,
+				CPE_SS_MSG_SEND_INBOX);
+		rc = cpe_send_msg_to_inbox(t_info, 0, m);
+		break;
+
+	case CPE_CMD_SEND_MSG_COMPLETE:
+		hdr = CMI_GET_HEADER(t_info->tgt->outbox);
+		service = CMI_HDR_GET_SERVICE(hdr);
+		pr_debug("%s: msg send success, notifying clients\n",
+			 __func__);
+		cpe_command_cleanup(command_node);
+		t_info->pending = NULL;
+		cpe_change_state(t_info,
+				 CPE_STATE_IDLE, CPE_SS_IDLE);
+		cpe_notify_cmi_client(t_info,
+			t_info->tgt->outbox, CPE_SVC_SUCCESS);
+		break;
+
+	case CPE_CMD_PROC_INCOMING_MSG:
+		rc = cpe_process_incoming(t_info);
+		break;
+
+	case CPE_CMD_KILL_THREAD:
+		rc = cpe_process_kill_thread(t_info, command_node);
+		break;
+
+	default:
+		pr_err("%s: unhandled cpe cmd = %d\n",
+			__func__, command_node->command);
+		break;
+	}
+
+	if (cpe_rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: failed to execute command\n", __func__);
+		if (t_info->pending) {
+			m = (struct cpe_send_msg *)t_info->pending;
+			cpe_notify_cmi_client(t_info, m->payload,
+					      CPE_SVC_FAILED);
+			t_info->pending = NULL;
+		}
+
+		cpe_command_cleanup(command_node);
+		rc = CPE_PROC_FAILED;
+		cpe_change_state(t_info, CPE_STATE_IDLE,
+			CPE_SS_IDLE);
+	}
+
+	return rc;
+}
+
+static enum cpe_svc_result cpe_mt_validate_cmd(
+		const struct cpe_info *t_info,
+		enum cpe_command command)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	if ((t_info == NULL) || t_info->initialized == false) {
+		pr_err("%s: cpe service is not ready\n",
+			__func__);
+		return CPE_SVC_NOT_READY;
+	}
+
+	switch (t_info->state) {
+	case CPE_STATE_UNINITIALIZED:
+	case CPE_STATE_INITIALIZED:
+		switch (command) {
+		case CPE_CMD_RESET:
+		case CPE_CMD_DL_SEGMENT:
+		case CPE_CMD_RAMDUMP:
+		case CPE_CMD_PROCESS_IRQ:
+		case CPE_CMD_KILL_THREAD:
+		case CPE_CMD_DEINITIALIZE:
+		case CPE_CMD_FTM_TEST:
+			rc = CPE_SVC_SUCCESS;
+			break;
+		default:
+			rc = CPE_SVC_NOT_READY;
+			break;
+		}
+		break;
+
+	case CPE_STATE_DOWNLOADING:
+		switch (command) {
+		case CPE_CMD_RESET:
+		case CPE_CMD_DL_SEGMENT:
+		case CPE_CMD_BOOT:
+		case CPE_CMD_FTM_TEST:
+			rc = CPE_SVC_SUCCESS;
+			break;
+		default:
+			rc = CPE_SVC_NOT_READY;
+			break;
+		}
+		break;
+
+	case CPE_STATE_BOOTING:
+		switch (command) {
+		case CPE_CMD_PROCESS_IRQ:
+		case CPE_CMD_BOOT_INITIALIZE:
+		case CPE_CMD_BOOT_COMPLETE:
+		case CPE_CMD_SHUTDOWN:
+			rc = CPE_SVC_SUCCESS;
+			break;
+		case CPE_CMD_FTM_TEST:
+			rc = CPE_SVC_BUSY;
+			break;
+		default:
+			rc = CPE_SVC_NOT_READY;
+			break;
+		}
+		break;
+
+	case CPE_STATE_IDLE:
+		switch (command) {
+		case CPE_CMD_SEND_MSG:
+		case CPE_CMD_SEND_TRANS_MSG:
+		case CPE_CMD_SEND_MSG_COMPLETE:
+		case CPE_CMD_PROCESS_IRQ:
+		case CPE_CMD_RESET:
+		case CPE_CMD_SHUTDOWN:
+		case CPE_CMD_KILL_THREAD:
+		case CPE_CMD_PROC_INCOMING_MSG:
+			rc = CPE_SVC_SUCCESS;
+			break;
+		case CPE_CMD_FTM_TEST:
+			rc = CPE_SVC_BUSY;
+			break;
+		default:
+			rc = CPE_SVC_FAILED;
+			break;
+		}
+		break;
+
+	case CPE_STATE_SENDING_MSG:
+		switch (command) {
+		case CPE_CMD_SEND_MSG:
+		case CPE_CMD_SEND_TRANS_MSG:
+		case CPE_CMD_SEND_MSG_COMPLETE:
+		case CPE_CMD_PROCESS_IRQ:
+		case CPE_CMD_SHUTDOWN:
+		case CPE_CMD_KILL_THREAD:
+		case CPE_CMD_PROC_INCOMING_MSG:
+			rc = CPE_SVC_SUCCESS;
+			break;
+		case CPE_CMD_FTM_TEST:
+			rc = CPE_SVC_BUSY;
+			break;
+		default:
+			rc = CPE_SVC_FAILED;
+			break;
+		}
+		break;
+
+	case CPE_STATE_OFFLINE:
+		switch (command) {
+		case CPE_CMD_RESET:
+		case CPE_CMD_RAMDUMP:
+		case CPE_CMD_KILL_THREAD:
+			rc = CPE_SVC_SUCCESS;
+			break;
+		default:
+			rc = CPE_SVC_NOT_READY;
+			break;
+		}
+		break;
+
+	default:
+		pr_debug("%s: unhandled state %d\n",
+			 __func__, t_info->state);
+		break;
+	}
+
+	if (rc != CPE_SVC_SUCCESS)
+		pr_err("%s: invalid command %d, state = %d\n",
+			__func__, command, t_info->state);
+	return rc;
+}
+
+void *cpe_svc_initialize(
+		void irq_control_callback(u32 enable),
+		const void *codec_info, void *context)
+{
+	struct cpe_info *t_info = NULL;
+	const struct cpe_svc_hw_cfg *cap = NULL;
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_svc_init_param *init_context =
+		(struct cpe_svc_init_param *) context;
+	void *client_context = NULL;
+
+	if (cpe_d.cpe_default_handle &&
+	    cpe_d.cpe_default_handle->initialized == true)
+		return (void *)cpe_d.cpe_default_handle;
+	cpe_d.cpe_query_freq_plans_cb = NULL;
+	cpe_d.cpe_change_freq_plan_cb = NULL;
+
+	if (context) {
+		client_context = init_context->context;
+		switch (init_context->version) {
+		case CPE_SVC_INIT_PARAM_V1:
+			cpe_d.cpe_query_freq_plans_cb =
+				init_context->query_freq_plans_cb;
+			cpe_d.cpe_change_freq_plan_cb =
+				init_context->change_freq_plan_cb;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!cpe_d.cpe_default_handle) {
+		cpe_d.cpe_default_handle = kzalloc(sizeof(struct cpe_info),
+					     GFP_KERNEL);
+		if (!cpe_d.cpe_default_handle)
+			goto err_register;
+
+		memset(cpe_d.cpe_default_handle, 0,
+		       sizeof(struct cpe_info));
+	}
+
+	t_info = cpe_d.cpe_default_handle;
+	t_info->client_context = client_context;
+
+	INIT_LIST_HEAD(&t_info->client_list);
+	cpe_d.cdc_priv = client_context;
+	INIT_WORK(&t_info->clk_plan_work, cpe_clk_plan_work);
+	init_completion(&t_info->core_svc_cmd_compl);
+
+	t_info->tgt = kzalloc(sizeof(struct cpe_svc_tgt_abstraction),
+			      GFP_KERNEL);
+	if (!t_info->tgt)
+		goto err_tgt_alloc;
+	t_info->codec_id =
+		((struct cpe_svc_codec_info_v1 *) codec_info)->id;
+
+	rc = cpe_svc_tgt_init((struct cpe_svc_codec_info_v1 *)codec_info,
+			t_info->tgt);
+
+	if (rc != CPE_SVC_SUCCESS)
+		goto err_tgt_init;
+
+	cap = t_info->tgt->tgt_get_cpe_info();
+
+	memset(t_info->tgt->outbox, 0, cap->outbox_size);
+	memset(t_info->tgt->inbox, 0, cap->inbox_size);
+	mutex_init(&t_info->msg_lock);
+	cpe_d.cpe_irq_control_callback = irq_control_callback;
+	t_info->cpe_process_command = cpe_mt_process_cmd;
+	t_info->cpe_cmd_validate = cpe_mt_validate_cmd;
+	t_info->cpe_start_notification = broadcast_boot_event;
+	mutex_init(&cpe_d.cpe_api_mutex);
+	mutex_init(&cpe_d.cpe_svc_lock);
+	pr_debug("%s: cpe services initialized\n", __func__);
+	t_info->state = CPE_STATE_INITIALIZED;
+	t_info->initialized = true;
+
+	return t_info;
+
+err_tgt_init:
+	kfree(t_info->tgt);
+
+err_tgt_alloc:
+	kfree(cpe_d.cpe_default_handle);
+	cpe_d.cpe_default_handle = NULL;
+
+err_register:
+	return NULL;
+}
+
+enum cpe_svc_result cpe_svc_deinitialize(void *cpe_handle)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	rc = cpe_is_command_valid(t_info, CPE_CMD_DEINITIALIZE);
+
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: Invalid command %d\n",
+			__func__, CPE_CMD_DEINITIALIZE);
+		return rc;
+	}
+
+	if (cpe_d.cpe_default_handle == t_info)
+		cpe_d.cpe_default_handle = NULL;
+
+	t_info->tgt->tgt_deinit(t_info->tgt);
+	cpe_change_state(t_info, CPE_STATE_UNINITIALIZED,
+			 CPE_SS_IDLE);
+	mutex_destroy(&t_info->msg_lock);
+	kfree(t_info->tgt);
+	kfree(t_info);
+	mutex_destroy(&cpe_d.cpe_api_mutex);
+	mutex_destroy(&cpe_d.cpe_svc_lock);
+
+	return rc;
+}
+
+void *cpe_svc_register(void *cpe_handle,
+		void (*notification_callback)
+			(const struct cpe_svc_notification *parameter),
+		u32 mask, const char *name)
+{
+	void *reg_handle;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!cpe_d.cpe_default_handle) {
+		cpe_d.cpe_default_handle = kzalloc(sizeof(struct cpe_info),
+					     GFP_KERNEL);
+		if (!cpe_d.cpe_default_handle) {
+			CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+			return NULL;
+		}
+
+		memset(cpe_d.cpe_default_handle, 0,
+			sizeof(struct cpe_info));
+	}
+
+	if (!cpe_handle)
+		cpe_handle = cpe_d.cpe_default_handle;
+
+	reg_handle = cpe_register_generic((struct cpe_info *)cpe_handle,
+					   notification_callback,
+					   NULL,
+					   mask, CPE_NO_SERVICE, name);
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+
+	return reg_handle;
+}
+
+enum cpe_svc_result cpe_svc_deregister(void *cpe_handle, void *reg_handle)
+{
+	enum cpe_svc_result rc;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!cpe_handle)
+		cpe_handle = cpe_d.cpe_default_handle;
+
+	rc = cpe_deregister_generic((struct cpe_info *)cpe_handle,
+				    reg_handle);
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_download_segment(void *cpe_handle,
+	const struct cpe_svc_mem_segment *segment)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	rc = cpe_is_command_valid(t_info, CPE_CMD_DL_SEGMENT);
+
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: cmd validation fail, cmd = %d\n",
+			__func__, CPE_CMD_DL_SEGMENT);
+		CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+		return rc;
+	}
+
+	cpe_toggle_irq_notification(t_info, false);
+	t_info->state = CPE_STATE_DOWNLOADING;
+	t_info->substate = CPE_SS_DL_DOWNLOADING;
+	rc = t_info->tgt->tgt_write_ram(t_info, segment);
+	cpe_toggle_irq_notification(t_info, true);
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_boot(void *cpe_handle, int debug_mode)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	rc = cpe_is_command_valid(t_info, CPE_CMD_BOOT);
+
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: cmd validation fail, cmd = %d\n",
+			__func__, CPE_CMD_BOOT);
+		CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+		return rc;
+	}
+
+	if (rc == CPE_SVC_SUCCESS) {
+		t_info->tgt->tgt_boot(debug_mode);
+		t_info->state = CPE_STATE_BOOTING;
+		t_info->substate = CPE_SS_BOOT;
+		pr_debug("%s: cpe service booting\n",
+			 __func__);
+	}
+
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_process_irq(void *cpe_handle, u32 cpe_irq)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	cpe_toggle_irq_notification(t_info, false);
+	cpe_process_irq_int(cpe_irq, t_info);
+	cpe_toggle_irq_notification(t_info, true);
+
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_route_notification(void *cpe_handle,
+		enum cpe_svc_module module, enum cpe_svc_route_dest dest)
+{
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+	enum cpe_svc_result rc = CPE_SVC_NOT_READY;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	if (t_info->tgt)
+		rc = t_info->tgt->tgt_route_notification(module, dest);
+
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	return rc;
+}
+
+static enum cpe_svc_result __cpe_svc_shutdown(void *cpe_handle)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+	struct cpe_command_node *n = NULL;
+	struct cpe_command_node kill_cmd;
+
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	rc = cpe_is_command_valid(t_info, CPE_CMD_SHUTDOWN);
+
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: cmd validation fail, cmd = %d\n",
+			__func__, CPE_CMD_SHUTDOWN);
+		return rc;
+	}
+
+	while (!list_empty(&t_info->main_queue)) {
+		n = list_first_entry(&t_info->main_queue,
+				     struct cpe_command_node, list);
+
+		if (n->command == CPE_CMD_SEND_MSG) {
+			cpe_notify_cmi_client(t_info, (u8 *)n->data,
+				CPE_SVC_SHUTTING_DOWN);
+		}
+		/*
+		 * Since command cannot be processed,
+		 * delete it from the list and perform cleanup
+		 */
+		list_del(&n->list);
+		cpe_command_cleanup(n);
+		kfree(n);
+	}
+
+	pr_debug("%s: cpe service OFFLINE state\n", __func__);
+
+	t_info->state = CPE_STATE_OFFLINE;
+	t_info->substate = CPE_SS_IDLE;
+
+	memset(&kill_cmd, 0, sizeof(kill_cmd));
+	kill_cmd.command = CPE_CMD_KILL_THREAD;
+
+	if (t_info->pending) {
+		struct cpe_send_msg *m =
+			(struct cpe_send_msg *)t_info->pending;
+		cpe_notify_cmi_client(t_info, m->payload,
+			CPE_SVC_SHUTTING_DOWN);
+		kfree(t_info->pending);
+		t_info->pending = NULL;
+	}
+
+	cpe_cleanup_worker_thread(t_info);
+	t_info->cpe_process_command(&kill_cmd);
+
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_shutdown(void *cpe_handle)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	rc = __cpe_svc_shutdown(cpe_handle);
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_reset(void *cpe_handle)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	rc = cpe_is_command_valid(t_info, CPE_CMD_RESET);
+
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: cmd validation fail, cmd = %d\n",
+			__func__, CPE_CMD_RESET);
+		CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+		return rc;
+	}
+
+	if (t_info && t_info->tgt) {
+		rc = t_info->tgt->tgt_reset();
+		pr_debug("%s: cpe services in INITIALIZED state\n",
+			 __func__);
+		t_info->state = CPE_STATE_INITIALIZED;
+		t_info->substate = CPE_SS_IDLE;
+	}
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_ramdump(void *cpe_handle,
+		struct cpe_svc_mem_segment *buffer)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	rc = cpe_is_command_valid(t_info, CPE_CMD_RAMDUMP);
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: cmd validation fail, cmd = %d\n",
+			__func__, CPE_CMD_RAMDUMP);
+		CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+		return rc;
+	}
+
+	if (t_info->tgt) {
+		rc = t_info->tgt->tgt_read_ram(t_info, buffer);
+	} else {
+		pr_err("%s: cpe service not ready\n", __func__);
+		rc = CPE_SVC_NOT_READY;
+	}
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_set_debug_mode(void *cpe_handle, u32 mode)
+{
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+	enum cpe_svc_result rc = CPE_SVC_INVALID_HANDLE;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	if (t_info->tgt)
+		rc = t_info->tgt->tgt_set_debug_mode(mode);
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+
+	return rc;
+}
+
+const struct cpe_svc_hw_cfg *cpe_svc_get_hw_cfg(void *cpe_handle)
+{
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	if (t_info->tgt)
+		return t_info->tgt->tgt_get_cpe_info();
+
+	return NULL;
+}
+
+void *cmi_register(
+		void notification_callback(
+			const struct cmi_api_notification *parameter),
+		u32 service)
+{
+	void *reg_handle = NULL;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	reg_handle = cpe_register_generic(cpe_d.cpe_default_handle,
+			NULL,
+			notification_callback,
+			(CPE_SVC_CMI_MSG | CPE_SVC_OFFLINE |
+			 CPE_SVC_ONLINE),
+			service,
+			"CMI_CLIENT");
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+
+	return reg_handle;
+}
+
+enum cmi_api_result cmi_deregister(void *reg_handle)
+{
+	u32 clients = 0;
+	struct cpe_notif_node *n = NULL;
+	enum cmi_api_result rc = CMI_API_SUCCESS;
+	struct cpe_svc_notification payload;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	rc = (enum cmi_api_result) cpe_deregister_generic(
+		cpe_d.cpe_default_handle, reg_handle);
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+	list_for_each_entry(n, &cpe_d.cpe_default_handle->client_list, list) {
+		if (n->mask & CPE_SVC_CMI_MSG)
+			clients++;
+	}
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_svc_lock, "cpe_svc");
+
+	if (clients == 0) {
+		payload.event = CPE_SVC_CMI_CLIENTS_DEREG;
+		payload.payload = NULL;
+		payload.result = CPE_SVC_SUCCESS;
+		cpe_broadcast_notification(cpe_d.cpe_default_handle, &payload);
+	}
+
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	return rc;
+}
+
+enum cmi_api_result cmi_send_msg(void *message)
+{
+	enum cmi_api_result rc = CMI_API_SUCCESS;
+	struct cpe_send_msg *msg = NULL;
+	struct cmi_hdr *hdr;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	hdr = CMI_GET_HEADER(message);
+	msg = kzalloc(sizeof(struct cpe_send_msg),
+		      GFP_ATOMIC);
+	if (!msg) {
+		CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+		return CPE_SVC_NO_MEMORY;
+	}
+
+	if (CMI_HDR_GET_OBM_FLAG(hdr) == CMI_OBM_FLAG_OUT_BAND)
+		msg->isobm = 1;
+	else
+		msg->isobm = 0;
+
+	msg->size = sizeof(struct cmi_hdr) +
+			CMI_HDR_GET_PAYLOAD_SIZE(hdr);
+
+	msg->payload = kzalloc(msg->size, GFP_ATOMIC);
+	if (!msg->payload) {
+		kfree(msg);
+		CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+		return CPE_SVC_NO_MEMORY;
+	}
+
+	msg->address = 0;
+	memcpy((void *)msg->payload, message, msg->size);
+
+	rc = (enum cmi_api_result) cpe_send_cmd_to_thread(
+			cpe_d.cpe_default_handle,
+			CPE_CMD_SEND_MSG,
+			(void *)msg, false);
+
+	if (rc != 0) {
+		pr_err("%s: Failed to queue message\n", __func__);
+		kfree(msg->payload);
+		kfree(msg);
+	}
+
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	return rc;
+}
+
+enum cpe_svc_result cpe_svc_ftm_test(void *cpe_handle, u32 *status)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+	struct cpe_svc_mem_segment backup_seg;
+	struct cpe_svc_mem_segment waiti_seg;
+	u8 *backup_data = NULL;
+
+	CPE_SVC_GRAB_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	rc = cpe_is_command_valid(t_info, CPE_CMD_FTM_TEST);
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: cmd validation fail, cmd = %d\n",
+			__func__, CPE_CMD_FTM_TEST);
+		goto fail_cmd;
+	}
+
+	if (t_info && t_info->tgt) {
+		backup_data = kzalloc(
+				t_info->tgt->tgt_waiti_info->tgt_waiti_size,
+				GFP_KERNEL);
+
+		/* CPE reset */
+		rc = t_info->tgt->tgt_reset();
+		if (rc != CPE_SVC_SUCCESS) {
+			pr_err("%s: CPE reset fail! err = %d\n",
+				__func__, rc);
+			goto err_return;
+		}
+
+		/* Back up the 4 byte IRAM data first */
+		backup_seg.type = CPE_SVC_INSTRUCTION_MEM;
+		backup_seg.cpe_addr =
+			t_info->tgt->tgt_get_cpe_info()->IRAM_offset;
+		backup_seg.size = t_info->tgt->tgt_waiti_info->tgt_waiti_size;
+		backup_seg.data = backup_data;
+
+		pr_debug("%s: Backing up IRAM data from CPE\n",
+			__func__);
+
+		rc = t_info->tgt->tgt_read_ram(t_info, &backup_seg);
+		if (rc != CPE_SVC_SUCCESS) {
+			pr_err("%s: Fail to backup CPE IRAM data, err = %d\n",
+				__func__, rc);
+			goto err_return;
+		}
+
+		pr_debug("%s: Complete backing up IRAM data from CPE\n",
+			__func__);
+
+		/* Write the WAITI instruction data */
+		waiti_seg.type = CPE_SVC_INSTRUCTION_MEM;
+		waiti_seg.cpe_addr =
+			t_info->tgt->tgt_get_cpe_info()->IRAM_offset;
+		waiti_seg.size = t_info->tgt->tgt_waiti_info->tgt_waiti_size;
+		waiti_seg.data = t_info->tgt->tgt_waiti_info->tgt_waiti_data;
+
+		rc = t_info->tgt->tgt_write_ram(t_info, &waiti_seg);
+		if (rc != CPE_SVC_SUCCESS) {
+			pr_err("%s: Fail to write the WAITI data, err = %d\n",
+				__func__, rc);
+			goto restore_iram;
+		}
+
+		/* Boot up cpe to execute the WAITI instructions */
+		rc = t_info->tgt->tgt_boot(1);
+		if (rc != CPE_SVC_SUCCESS) {
+			pr_err("%s: Fail to boot CPE, err = %d\n",
+				__func__, rc);
+			goto reset;
+		}
+
+		/*
+		 * 1ms delay is suggested by the hw team to
+		 * wait for cpe to boot up.
+		 */
+		usleep_range(1000, 1100);
+
+		/* Check if the cpe init is done after executing the WAITI */
+		*status = t_info->tgt->tgt_cpar_init_done();
+
+reset:
+		/* Set the cpe back to reset state */
+		rc = t_info->tgt->tgt_reset();
+		if (rc != CPE_SVC_SUCCESS) {
+			pr_err("%s: CPE reset fail! err = %d\n",
+				__func__, rc);
+			goto restore_iram;
+		}
+
+restore_iram:
+		/* Restore the IRAM 4 bytes data */
+		rc = t_info->tgt->tgt_write_ram(t_info, &backup_seg);
+		if (rc != CPE_SVC_SUCCESS) {
+			pr_err("%s: Fail to restore the IRAM data, err = %d\n",
+				__func__, rc);
+			goto err_return;
+		}
+	}
+
+err_return:
+	kfree(backup_data);
+fail_cmd:
+	CPE_SVC_REL_LOCK(&cpe_d.cpe_api_mutex, "cpe_api");
+	return rc;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_boot(int debug_mode)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+static u32 cpe_tgt_tomtom_is_cpar_init_done(void)
+{
+	return 0;
+}
+
+static u32 cpe_tgt_tomtom_is_active(void)
+{
+	return 0;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_reset(void)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+enum cpe_svc_result cpe_tgt_tomtom_voicetx(bool enable)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+enum cpe_svc_result cpe_svc_toggle_lab(void *cpe_handle, bool enable)
+{
+
+	struct cpe_info *t_info = (struct cpe_info *)cpe_handle;
+
+	if (!t_info)
+		t_info = cpe_d.cpe_default_handle;
+
+	if (t_info->tgt)
+		return t_info->tgt->tgt_voice_tx_lab(enable);
+	else
+		return CPE_SVC_INVALID_HANDLE;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_read_mailbox(u8 *buffer,
+	size_t size)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_write_mailbox(u8 *buffer,
+	size_t size)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_read_RAM(struct cpe_info *t_info,
+		struct cpe_svc_mem_segment *mem_seg)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_write_RAM(struct cpe_info *t_info,
+		const struct cpe_svc_mem_segment *mem_seg)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_route_notification(
+		enum cpe_svc_module module,
+		enum cpe_svc_route_dest dest)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_set_debug_mode(u32 enable)
+{
+	return CPE_SVC_SUCCESS;
+}
+
+static const struct cpe_svc_hw_cfg *cpe_tgt_tomtom_get_cpe_info(void)
+{
+	return &cpe_svc_tomtom_info;
+}
+
+static enum cpe_svc_result cpe_tgt_tomtom_deinit(
+		struct cpe_svc_tgt_abstraction *param)
+{
+	kfree(param->inbox);
+	param->inbox = NULL;
+	kfree(param->outbox);
+	param->outbox = NULL;
+	memset(param, 0, sizeof(struct cpe_svc_tgt_abstraction));
+	return CPE_SVC_SUCCESS;
+}
+
+static u8 cpe_tgt_tomtom_waiti_data[] = {0x00, 0x70, 0x00, 0x00};
+
+static struct cpe_tgt_waiti_info cpe_tgt_tomtom_waiti_info = {
+	.tgt_waiti_size = ARRAY_SIZE(cpe_tgt_tomtom_waiti_data),
+	.tgt_waiti_data = cpe_tgt_tomtom_waiti_data,
+};
+
+static enum cpe_svc_result cpe_tgt_tomtom_init(
+		struct cpe_svc_codec_info_v1 *codec_info,
+		struct cpe_svc_tgt_abstraction *param)
+{
+	if (!codec_info)
+		return CPE_SVC_INVALID_HANDLE;
+	if (!param)
+		return CPE_SVC_INVALID_HANDLE;
+
+	if (codec_info->id == CPE_SVC_CODEC_TOMTOM) {
+		param->tgt_boot      = cpe_tgt_tomtom_boot;
+		param->tgt_cpar_init_done = cpe_tgt_tomtom_is_cpar_init_done;
+		param->tgt_is_active = cpe_tgt_tomtom_is_active;
+		param->tgt_reset = cpe_tgt_tomtom_reset;
+		param->tgt_read_mailbox = cpe_tgt_tomtom_read_mailbox;
+		param->tgt_write_mailbox = cpe_tgt_tomtom_write_mailbox;
+		param->tgt_read_ram = cpe_tgt_tomtom_read_RAM;
+		param->tgt_write_ram = cpe_tgt_tomtom_write_RAM;
+		param->tgt_route_notification =
+			cpe_tgt_tomtom_route_notification;
+		param->tgt_set_debug_mode = cpe_tgt_tomtom_set_debug_mode;
+		param->tgt_get_cpe_info = cpe_tgt_tomtom_get_cpe_info;
+		param->tgt_deinit = cpe_tgt_tomtom_deinit;
+		param->tgt_voice_tx_lab = cpe_tgt_tomtom_voicetx;
+		param->tgt_waiti_info = &cpe_tgt_tomtom_waiti_info;
+
+		param->inbox = kzalloc(TOMTOM_A_SVASS_SPE_INBOX_SIZE,
+				       GFP_KERNEL);
+		if (!param->inbox)
+			return CPE_SVC_NO_MEMORY;
+
+		param->outbox = kzalloc(TOMTOM_A_SVASS_SPE_OUTBOX_SIZE,
+					GFP_KERNEL);
+		if (!param->outbox) {
+			kfree(param->inbox);
+			return CPE_SVC_NO_MEMORY;
+		}
+	}
+
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_boot(int debug_mode)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	if (!debug_mode)
+		rc |= cpe_update_bits(
+				WCD9335_CPE_SS_WDOG_CFG,
+				0x3f, 0x31);
+	else
+		pr_info("%s: CPE in debug mode, WDOG disabled\n",
+			__func__);
+
+	rc |= cpe_register_write(WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 19);
+	rc |= cpe_update_bits(WCD9335_CPE_SS_CPAR_CTL, 0x04, 0x00);
+	rc |= cpe_update_bits(WCD9335_CPE_SS_CPAR_CTL, 0x02, 0x02);
+	rc |= cpe_update_bits(WCD9335_CPE_SS_CPAR_CTL, 0x01, 0x01);
+
+	if (unlikely(rc)) {
+		pr_err("%s: Failed to boot, err = %d\n",
+			__func__, rc);
+		rc = CPE_SVC_FAILED;
+	}
+
+	return rc;
+}
+
+static u32 cpe_tgt_wcd9335_is_cpar_init_done(void)
+{
+	u8 temp = 0;
+
+	cpe_register_read(WCD9335_CPE_SS_STATUS, &temp);
+	return temp & 0x1;
+}
+
+static u32 cpe_tgt_wcd9335_is_active(void)
+{
+	u8 temp = 0;
+
+	cpe_register_read(WCD9335_CPE_SS_STATUS, &temp);
+	return temp & 0x4;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_reset(void)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	rc |= cpe_update_bits(WCD9335_CPE_SS_CPAR_CFG, 0x01, 0x00);
+
+	rc |= cpe_register_write(
+		WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN, 0x00);
+	rc |= cpe_register_write(
+		WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN, 0x00);
+	rc |= cpe_register_write(
+		WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1, 0x00);
+	rc |= cpe_register_write(
+		WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2, 0x00);
+
+	rc |= cpe_update_bits(WCD9335_CPE_SS_CPAR_CTL, 0x04, 0x04);
+
+	if (unlikely(rc)) {
+		pr_err("%s: failed to reset cpe, err = %d\n",
+			__func__, rc);
+		rc = CPE_SVC_FAILED;
+	}
+
+	return rc;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_read_mailbox(u8 *buffer,
+	size_t size)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	u32 cnt = 0;
+
+	pr_debug("%s: size=%zd\n", __func__, size);
+
+	if (size > WCD9335_CPE_SS_SPE_OUTBOX_SIZE)
+		size = WCD9335_CPE_SS_SPE_OUTBOX_SIZE;
+
+	for (cnt = 0; (cnt < size) && (rc == CPE_SVC_SUCCESS); cnt++)
+		rc = cpe_register_read(WCD9335_CPE_SS_SPE_OUTBOX1(cnt),
+				       &buffer[cnt]);
+
+	rc = cpe_register_write(WCD9335_CPE_SS_OUTBOX1_ACK, 0x01);
+
+	if (unlikely(rc)) {
+		pr_err("%s: failed to ACK outbox, err = %d\n",
+			__func__, rc);
+		rc = CPE_SVC_FAILED;
+	}
+
+	return rc;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_write_mailbox(u8 *buffer,
+	size_t size)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	u32 cnt = 0;
+
+	pr_debug("%s: size = %zd\n", __func__, size);
+	if (size > WCD9335_CPE_SS_SPE_INBOX_SIZE)
+		size = WCD9335_CPE_SS_SPE_INBOX_SIZE;
+	for (cnt = 0; (cnt < size) && (rc == CPE_SVC_SUCCESS); cnt++) {
+		rc |= cpe_register_write(WCD9335_CPE_SS_SPE_INBOX1(cnt),
+			buffer[cnt]);
+	}
+
+	if (unlikely(rc)) {
+		pr_err("%s: Error %d writing mailbox registers\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = cpe_register_write(WCD9335_CPE_SS_INBOX1_TRG, 1);
+	return rc;
+}
+
+static enum cpe_svc_result cpe_wcd9335_get_mem_addr(struct cpe_info *t_info,
+		const struct cpe_svc_mem_segment *mem_seg,
+		u32 *addr, u8 *mem)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	u32 offset, mem_sz, address;
+	u8 mem_type;
+
+	switch (mem_seg->type) {
+	case CPE_SVC_DATA_MEM:
+		mem_type = MEM_ACCESS_DRAM_VAL;
+		offset = WCD9335_CPE_SS_SPE_DRAM_OFFSET;
+		mem_sz = WCD9335_CPE_SS_SPE_DRAM_SIZE;
+		break;
+
+	case CPE_SVC_INSTRUCTION_MEM:
+		mem_type = MEM_ACCESS_IRAM_VAL;
+		offset = WCD9335_CPE_SS_SPE_IRAM_OFFSET;
+		mem_sz = WCD9335_CPE_SS_SPE_IRAM_SIZE;
+		break;
+
+	default:
+		pr_err("%s: Invalid mem type = %u\n",
+			__func__, mem_seg->type);
+		return CPE_SVC_INVALID_HANDLE;
+	}
+
+	if (mem_seg->cpe_addr < offset) {
+		pr_err("%s: Invalid addr %x for mem type %u\n",
+			__func__, mem_seg->cpe_addr, mem_type);
+		return CPE_SVC_INVALID_HANDLE;
+	}
+
+	address = mem_seg->cpe_addr - offset;
+	if (address + mem_seg->size > mem_sz) {
+		pr_err("%s: wrong size %zu, start address %x, mem_type %u\n",
+			__func__, mem_seg->size, address, mem_type);
+		return CPE_SVC_INVALID_HANDLE;
+	}
+
+	(*addr) = address;
+	(*mem) = mem_type;
+
+	return rc;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_read_RAM(struct cpe_info *t_info,
+		struct cpe_svc_mem_segment *mem_seg)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	u8 temp = 0;
+	u32 cnt = 0;
+	u8 mem = 0x0;
+	u32 addr = 0;
+	u32 lastaddr = 0;
+	u32 ptr_update = true;
+	bool autoinc;
+
+	if (!mem_seg) {
+		pr_err("%s: Invalid buffer\n", __func__);
+		return CPE_SVC_INVALID_HANDLE;
+	}
+
+	rc = cpe_wcd9335_get_mem_addr(t_info, mem_seg, &addr, &mem);
+
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: Cannot obtain address, mem_type %u\n",
+			__func__, mem_seg->type);
+		return rc;
+	}
+
+	rc |= cpe_register_write(WCD9335_CPE_SS_MEM_CTRL, 0);
+	autoinc = cpe_register_read_autoinc_supported();
+
+	if (autoinc)
+		temp = 0x18;
+	else
+		temp = 0x10;
+
+	temp |= mem;
+
+	lastaddr = ~addr;
+	do {
+		if (!autoinc || (ptr_update)) {
+			/* write LSB only if modified */
+			if ((lastaddr & 0xFF) != (addr & 0xFF))
+				rc |= cpe_register_write(
+						WCD9335_CPE_SS_MEM_PTR_0,
+						(addr & 0xFF));
+			/* write middle byte only if modified */
+			if (((lastaddr >> 8) & 0xFF) != ((addr >> 8) & 0xFF))
+				rc |= cpe_register_write(
+						WCD9335_CPE_SS_MEM_PTR_1,
+						((addr>>8) & 0xFF));
+			/* write MSB only if modified */
+			if (((lastaddr >> 16) & 0xFF) != ((addr >> 16) & 0xFF))
+				rc |= cpe_register_write(
+						WCD9335_CPE_SS_MEM_PTR_2,
+						((addr>>16) & 0xFF));
+
+			rc |= cpe_register_write(WCD9335_CPE_SS_MEM_CTRL, temp);
+			lastaddr = addr;
+			addr++;
+			ptr_update = false;
+		}
+
+		rc |= cpe_register_read(WCD9335_CPE_SS_MEM_BANK_0,
+				       &mem_seg->data[cnt]);
+
+		if (!autoinc)
+			rc |= cpe_register_write(WCD9335_CPE_SS_MEM_CTRL, 0);
+	} while ((++cnt < mem_seg->size) ||
+		 (rc != CPE_SVC_SUCCESS));
+
+	rc |= cpe_register_write(WCD9335_CPE_SS_MEM_CTRL, 0);
+
+	if (rc)
+		pr_err("%s: Failed to read registers, err = %d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_write_RAM(struct cpe_info *t_info,
+		const struct cpe_svc_mem_segment *mem_seg)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	u8 mem_reg_val = 0;
+	u8 mem = MEM_ACCESS_NONE_VAL;
+	u32 addr = 0;
+	u8 *temp_ptr = NULL;
+	u32 temp_size = 0;
+	bool autoinc;
+
+	if (!mem_seg) {
+		pr_err("%s: Invalid mem segment\n",
+			__func__);
+		return CPE_SVC_INVALID_HANDLE;
+	}
+
+	rc = cpe_wcd9335_get_mem_addr(t_info, mem_seg, &addr, &mem);
+
+	if (rc != CPE_SVC_SUCCESS) {
+		pr_err("%s: Cannot obtain address, mem_type %u\n",
+			__func__, mem_seg->type);
+		return rc;
+	}
+
+	autoinc = cpe_register_read_autoinc_supported();
+	if (autoinc)
+		mem_reg_val = 0x18;
+	else
+		mem_reg_val = 0x10;
+
+	mem_reg_val |= mem;
+
+	rc = cpe_update_bits(WCD9335_CPE_SS_MEM_CTRL,
+			     0x0F, mem_reg_val);
+
+	rc = cpe_register_write(WCD9335_CPE_SS_MEM_PTR_0,
+				(addr & 0xFF));
+	rc = cpe_register_write(WCD9335_CPE_SS_MEM_PTR_1,
+				((addr >> 8) & 0xFF));
+
+	rc = cpe_register_write(WCD9335_CPE_SS_MEM_PTR_2,
+				((addr >> 16) & 0xFF));
+
+	temp_size = 0;
+	temp_ptr = mem_seg->data;
+
+	while (temp_size <= mem_seg->size) {
+		u32 to_write = (mem_seg->size >= temp_size+CHUNK_SIZE)
+			? CHUNK_SIZE : (mem_seg->size - temp_size);
+
+		if (t_info->state == CPE_STATE_OFFLINE) {
+			pr_err("%s: CPE is offline\n", __func__);
+			return CPE_SVC_FAILED;
+		}
+
+		cpe_register_write_repeat(WCD9335_CPE_SS_MEM_BANK_0,
+			temp_ptr, to_write);
+		temp_size += CHUNK_SIZE;
+		temp_ptr += CHUNK_SIZE;
+	}
+
+	rc = cpe_register_write(WCD9335_CPE_SS_MEM_CTRL, 0);
+
+	if (rc)
+		pr_err("%s: Failed to write registers, err = %d\n",
+			__func__, rc);
+	return rc;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_route_notification(
+		enum cpe_svc_module module,
+		enum cpe_svc_route_dest dest)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	pr_debug("%s: Module = %d, Destination = %d\n",
+		 __func__, module, dest);
+
+	switch (module) {
+	case CPE_SVC_LISTEN_PROC:
+		switch (dest) {
+		case CPE_SVC_EXTERNAL:
+			rc = cpe_update_bits(WCD9335_CPE_SS_CFG, 0x01, 0x01);
+			break;
+		case CPE_SVC_INTERNAL:
+			rc = cpe_update_bits(WCD9335_CPE_SS_CFG, 0x01, 0x00);
+			break;
+		default:
+			pr_err("%s: Invalid destination %d\n",
+				__func__, dest);
+			return CPE_SVC_FAILED;
+		}
+		break;
+	default:
+		pr_err("%s: Invalid module %d\n",
+			__func__, module);
+		rc = CPE_SVC_FAILED;
+		break;
+	}
+	return rc;
+}
+
+static enum cpe_svc_result cpe_tgt_wcd9335_set_debug_mode(u32 enable)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+
+	pr_debug("%s: enable = %s\n", __func__,
+		 (enable) ? "true" : "false");
+
+	return rc;
+}
+
+static const struct cpe_svc_hw_cfg *cpe_tgt_wcd9335_get_cpe_info(void)
+{
+	return &cpe_svc_wcd9335_info;
+}
+
+static enum cpe_svc_result
+cpe_tgt_wcd9335_deinit(struct cpe_svc_tgt_abstraction *param)
+{
+	kfree(param->inbox);
+	param->inbox = NULL;
+	kfree(param->outbox);
+	param->outbox = NULL;
+	memset(param, 0, sizeof(struct cpe_svc_tgt_abstraction));
+
+	return CPE_SVC_SUCCESS;
+}
+
+static enum cpe_svc_result
+	cpe_tgt_wcd9335_voicetx(bool enable)
+{
+	enum cpe_svc_result rc = CPE_SVC_SUCCESS;
+	u8 val = 0;
+
+	pr_debug("%s: enable = %u\n", __func__, enable);
+	if (enable)
+		val = 0x02;
+	else
+		val = 0x00;
+
+	rc = cpe_update_bits(WCD9335_CPE_SS_CFG, 0x02, val);
+	val = 0;
+	cpe_register_read(WCD9335_CPE_SS_CFG, &val);
+
+	return rc;
+}
+
+static u8 cpe_tgt_wcd9335_waiti_data[] = {0x00, 0x70, 0x00, 0x00};
+
+static struct cpe_tgt_waiti_info cpe_tgt_wcd9335_waiti_info = {
+	.tgt_waiti_size = ARRAY_SIZE(cpe_tgt_wcd9335_waiti_data),
+	.tgt_waiti_data = cpe_tgt_wcd9335_waiti_data,
+};
+
+static enum cpe_svc_result cpe_tgt_wcd9335_init(
+		struct cpe_svc_codec_info_v1 *codec_info,
+		struct cpe_svc_tgt_abstraction *param)
+{
+	if (!codec_info)
+		return CPE_SVC_INVALID_HANDLE;
+	if (!param)
+		return CPE_SVC_INVALID_HANDLE;
+
+	if (codec_info->id == CPE_SVC_CODEC_WCD9335) {
+		param->tgt_boot = cpe_tgt_wcd9335_boot;
+		param->tgt_cpar_init_done = cpe_tgt_wcd9335_is_cpar_init_done;
+		param->tgt_is_active = cpe_tgt_wcd9335_is_active;
+		param->tgt_reset = cpe_tgt_wcd9335_reset;
+		param->tgt_read_mailbox = cpe_tgt_wcd9335_read_mailbox;
+		param->tgt_write_mailbox = cpe_tgt_wcd9335_write_mailbox;
+		param->tgt_read_ram = cpe_tgt_wcd9335_read_RAM;
+		param->tgt_write_ram = cpe_tgt_wcd9335_write_RAM;
+		param->tgt_route_notification =
+			cpe_tgt_wcd9335_route_notification;
+		param->tgt_set_debug_mode = cpe_tgt_wcd9335_set_debug_mode;
+		param->tgt_get_cpe_info = cpe_tgt_wcd9335_get_cpe_info;
+		param->tgt_deinit = cpe_tgt_wcd9335_deinit;
+		param->tgt_voice_tx_lab = cpe_tgt_wcd9335_voicetx;
+		param->tgt_waiti_info = &cpe_tgt_wcd9335_waiti_info;
+
+		param->inbox = kzalloc(WCD9335_CPE_SS_SPE_INBOX_SIZE,
+				       GFP_KERNEL);
+		if (!param->inbox)
+			return CPE_SVC_NO_MEMORY;
+
+		param->outbox = kzalloc(WCD9335_CPE_SS_SPE_OUTBOX_SIZE,
+					GFP_KERNEL);
+		if (!param->outbox) {
+			kfree(param->inbox);
+			return CPE_SVC_NO_MEMORY;
+		}
+	}
+
+	return CPE_SVC_SUCCESS;
+}
+
+MODULE_DESCRIPTION("WCD CPE Services");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd_cpe_services.h b/asoc/codecs/wcd_cpe_services.h
new file mode 100644
index 0000000..68eb619
--- /dev/null
+++ b/asoc/codecs/wcd_cpe_services.h
@@ -0,0 +1,179 @@
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CPE_SERVICES__
+#define __CPE_SERVICES__
+
+#define CPE_IRQ_OUTBOX_IRQ		0x01
+#define CPE_IRQ_MEM_ACCESS_ERROR	0x02
+#define CPE_IRQ_WDOG_BITE		0x04
+#define CPE_IRQ_BUFFER_OVERFLOW		0x08
+#define CPE_IRQ_LAB_OVFUNF		0x10
+#define CPE_IRQ_FLL_LOCK_LOST		0x20
+#define CPE_IRQ_RCO_WDOG_INT		0x40
+
+#define EFAILED (MAX_ERRNO - 1)
+#define ENOTREADY (MAX_ERRNO - 2)
+
+#define MAX_SUPPORTED_CLKFREQ 8
+#define CPE_SVC_INIT_PARAM_V1 1
+
+enum cpe_svc_result {
+	CPE_SVC_SUCCESS			= 0,
+	CPE_SVC_FAILED			= -EFAILED,
+	CPE_SVC_NO_MEMORY		= -ENOMEM,
+	CPE_SVC_INVALID_HANDLE		= -EINVAL,
+	CPE_SVC_NOT_READY		= -ENOTREADY,
+	CPE_SVC_SHUTTING_DOWN		= -ESHUTDOWN,
+	CPE_SVC_BUSY			= -EBUSY,
+};
+
+enum cpe_svc_event {
+	CPE_SVC_CMI_MSG			= 0x01,
+	CPE_SVC_OFFLINE			= 0x02,
+	CPE_SVC_ONLINE			= 0x04,
+	CPE_SVC_BOOT_FAILED		= 0x08,
+	CPE_SVC_READ_COMPLETE		= 0x10,
+	CPE_SVC_READ_ERROR		= 0x20,
+	CPE_SVC_BOOT			= 0x40,
+	CPE_SVC_CMI_CLIENTS_DEREG	= 0x100,
+	CPE_SVC_EVENT_ANCHOR		= 0x7FFF
+};
+
+enum cpe_svc_module {
+	CPE_SVC_LISTEN_PROC		= 1,
+	CPE_SVC_MODULE_ANCHOR		= 0x7F
+};
+
+enum cpe_svc_route_dest {
+	CPE_SVC_EXTERNAL		= 1,
+	CPE_SVC_INTERNAL		= 2,
+	CPE_SVC_ROUTE_ANCHOR		= 0x7F
+};
+
+enum cpe_svc_mem_type {
+	CPE_SVC_DATA_MEM		= 1,
+	CPE_SVC_INSTRUCTION_MEM		= 2,
+	CPE_SVC_IPC_MEM			= 3,
+	CPE_SVC_MEM_TYPE_ANCHOR		= 0x7F
+};
+
+enum cpe_svc_codec_id {
+	CPE_SVC_CODEC_TOMTOM		= 5,
+	CPE_SVC_CODEC_WCD9335		= 7,
+	CPE_SVC_CODEC_WCD9326		= 8,
+	CPE_SVC_CODEC_ID_ANCHOR		= 0x7ffffff
+};
+
+enum cpe_svc_codec_version {
+	CPE_SVC_CODEC_V1P0		= 1,
+	CPE_SVC_CODEC_VERSION_ANCHOR	= 0x7fffffff
+};
+
+struct cpe_svc_codec_info_v1 {
+	u16			major_version;/*must be 1*/
+	u16			minor_version;/*must be 0*/
+	u32			id;
+	u32			version;
+	/*Add 1.1 version fields after this line*/
+};
+
+struct cpe_svc_notification {
+	enum cpe_svc_event event;
+	enum cpe_svc_result result;
+	void *payload;
+	void *private_data;
+};
+
+struct cpe_svc_msg_payload {
+	u8    *cmi_msg;
+};
+
+struct cpe_svc_read_complete {
+	u8    *buffer;
+	size_t   size;
+};
+
+struct cpe_svc_boot_event {
+	u32 debug_address;
+	size_t debug_buffer_size;
+	u32 status;
+};
+
+struct cpe_svc_mem_segment {
+	enum cpe_svc_mem_type type;
+	u32 cpe_addr;
+	size_t size;
+	u8 *data;
+};
+
+struct cpe_svc_hw_cfg {
+	size_t DRAM_size;
+	u32 DRAM_offset;
+	size_t IRAM_size;
+	u32 IRAM_offset;
+	u8 inbox_size;
+	u8 outbox_size;
+};
+
+struct cpe_svc_cfg_clk_plan {
+	u32 current_clk_feq;
+	u32 num_clk_freqs;
+	u32 clk_freqs[MAX_SUPPORTED_CLKFREQ];
+};
+
+struct cpe_svc_init_param {
+	void *context;
+	u32 version;
+	void (*query_freq_plans_cb)(void *cdc_priv,
+			struct cpe_svc_cfg_clk_plan *clk_freq);
+	void (*change_freq_plan_cb)(void *cdc_priv,
+			u32 clk_freq);
+};
+
+
+void *cpe_svc_initialize(
+		void irq_control_callback(u32 enable),
+		const void *codec_info, void *context);
+enum cpe_svc_result cpe_svc_deinitialize(void *cpe_handle);
+
+void *cpe_svc_register(void *cpe_handle,
+		void (*notification_callback)(
+			const struct cpe_svc_notification *parameter),
+		u32 mask, const char *name);
+
+enum cpe_svc_result cpe_svc_deregister(void *cpe_handle, void *reg_handle);
+
+enum cpe_svc_result cpe_svc_download_segment(void *cpe_handle,
+		const struct cpe_svc_mem_segment *segment);
+
+enum cpe_svc_result cpe_svc_boot(void *cpe_handle, int debug_mode);
+
+enum cpe_svc_result cpe_svc_shutdown(void *cpe_handle);
+
+enum cpe_svc_result cpe_svc_reset(void *cpe_handle);
+
+enum cpe_svc_result cpe_svc_process_irq(void *cpe_handle, u32 cpe_irq);
+
+enum cpe_svc_result
+cpe_svc_route_notification(void *cpe_handle, enum cpe_svc_module module,
+		enum cpe_svc_route_dest dest);
+
+enum cpe_svc_result cpe_svc_ramdump(void *cpe_handle,
+		struct cpe_svc_mem_segment *buffer);
+
+enum cpe_svc_result cpe_svc_set_debug_mode(void *cpe_handle, u32 mode);
+
+const struct cpe_svc_hw_cfg *cpe_svc_get_hw_cfg(void *cpe_handle);
+enum cpe_svc_result cpe_svc_toggle_lab(void *cpe_handle, bool enable);
+enum cpe_svc_result cpe_svc_ftm_test(void *cpe_handle, u32 *status);
+#endif /*__CPE_SERVICES__*/
diff --git a/asoc/codecs/wcdcal-hwdep.c b/asoc/codecs/wcdcal-hwdep.c
new file mode 100644
index 0000000..31eae69
--- /dev/null
+++ b/asoc/codecs/wcdcal-hwdep.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <linux/bitops.h>
+#include <sound/hwdep.h>
+#include <sound/msmcal-hwdep.h>
+#include <sound/soc.h>
+#include "wcdcal-hwdep.h"
+
+const int cal_size_info[WCD9XXX_MAX_CAL] = {
+	[WCD9XXX_ANC_CAL] = 16384,
+	[WCD9XXX_MBHC_CAL] = 4096,
+	[WCD9XXX_MAD_CAL] = 4096,
+	[WCD9XXX_VBAT_CAL] = 72,
+};
+
+const char *cal_name_info[WCD9XXX_MAX_CAL] = {
+	[WCD9XXX_ANC_CAL] = "anc",
+	[WCD9XXX_MBHC_CAL] = "mbhc",
+	[WCD9XXX_MAD_CAL] = "mad",
+	[WCD9XXX_VBAT_CAL] = "vbat",
+};
+
+struct firmware_cal *wcdcal_get_fw_cal(struct fw_info *fw_data,
+					enum wcd_cal_type type)
+{
+	if (!fw_data) {
+		pr_err("%s: fw_data is NULL\n", __func__);
+		return NULL;
+	}
+	if (type >= WCD9XXX_MAX_CAL ||
+		type < WCD9XXX_MIN_CAL) {
+		pr_err("%s: wrong cal type sent %d\n", __func__, type);
+		return NULL;
+	}
+	mutex_lock(&fw_data->lock);
+	if (!test_bit(WCDCAL_RECIEVED,
+		&fw_data->wcdcal_state[type])) {
+		pr_err("%s: cal not sent by userspace %d\n",
+			__func__, type);
+		mutex_unlock(&fw_data->lock);
+		return NULL;
+	}
+	mutex_unlock(&fw_data->lock);
+	return fw_data->fw[type];
+}
+EXPORT_SYMBOL(wcdcal_get_fw_cal);
+
+static int wcdcal_hwdep_ioctl_shared(struct snd_hwdep *hw,
+			struct wcdcal_ioctl_buffer fw_user)
+{
+	struct fw_info *fw_data = hw->private_data;
+	struct firmware_cal **fw = fw_data->fw;
+	void *data;
+
+	if (!test_bit(fw_user.cal_type, fw_data->cal_bit)) {
+		pr_err("%s: codec didn't set this %d!!\n",
+				__func__, fw_user.cal_type);
+		return -EFAULT;
+	}
+	if (fw_user.cal_type >= WCD9XXX_MAX_CAL ||
+		fw_user.cal_type < WCD9XXX_MIN_CAL) {
+		pr_err("%s: wrong cal type sent %d\n",
+				__func__, fw_user.cal_type);
+		return -EFAULT;
+	}
+	if (fw_user.size > cal_size_info[fw_user.cal_type] ||
+		fw_user.size <= 0) {
+		pr_err("%s: incorrect firmware size %d for %s\n",
+			__func__, fw_user.size,
+			cal_name_info[fw_user.cal_type]);
+		return -EFAULT;
+	}
+	data = fw[fw_user.cal_type]->data;
+	if (copy_from_user(data, fw_user.buffer, fw_user.size))
+		return -EFAULT;
+	fw[fw_user.cal_type]->size = fw_user.size;
+	mutex_lock(&fw_data->lock);
+	set_bit(WCDCAL_RECIEVED, &fw_data->wcdcal_state[fw_user.cal_type]);
+	mutex_unlock(&fw_data->lock);
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct wcdcal_ioctl_buffer32 {
+	u32 size;
+	compat_uptr_t buffer;
+	enum wcd_cal_type cal_type;
+};
+
+enum {
+	SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32 =
+		_IOW('U', 0x1, struct wcdcal_ioctl_buffer32),
+};
+
+static int wcdcal_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct wcdcal_ioctl_buffer __user *argp = (void __user *)arg;
+	struct wcdcal_ioctl_buffer32 fw_user32;
+	struct wcdcal_ioctl_buffer fw_user_compat;
+
+	if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32) {
+		pr_err("%s: wrong ioctl command sent %u!\n", __func__, cmd);
+		return -ENOIOCTLCMD;
+	}
+	if (copy_from_user(&fw_user32, argp, sizeof(fw_user32))) {
+		pr_err("%s: failed to copy\n", __func__);
+		return -EFAULT;
+	}
+	fw_user_compat.size = fw_user32.size;
+	fw_user_compat.buffer = compat_ptr(fw_user32.buffer);
+	fw_user_compat.cal_type = fw_user32.cal_type;
+	return wcdcal_hwdep_ioctl_shared(hw, fw_user_compat);
+}
+#else
+#define wcdcal_hwdep_ioctl_compat NULL
+#endif
+
+static int wcdcal_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct wcdcal_ioctl_buffer __user *argp = (void __user *)arg;
+	struct wcdcal_ioctl_buffer fw_user;
+
+	if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE) {
+		pr_err("%s: wrong ioctl command sent %d!\n", __func__, cmd);
+		return -ENOIOCTLCMD;
+	}
+	if (copy_from_user(&fw_user, argp, sizeof(fw_user))) {
+		pr_err("%s: failed to copy\n", __func__);
+		return -EFAULT;
+	}
+	return wcdcal_hwdep_ioctl_shared(hw, fw_user);
+}
+
+static int wcdcal_hwdep_release(struct snd_hwdep *hw, struct file *file)
+{
+	struct fw_info *fw_data = hw->private_data;
+
+	mutex_lock(&fw_data->lock);
+	/* clear all the calibrations */
+	memset(fw_data->wcdcal_state, 0,
+		sizeof(fw_data->wcdcal_state));
+	mutex_unlock(&fw_data->lock);
+	return 0;
+}
+
+int wcd_cal_create_hwdep(void *data, int node, struct snd_soc_codec *codec)
+{
+	char hwname[40];
+	struct snd_hwdep *hwdep;
+	struct firmware_cal **fw;
+	struct fw_info *fw_data = data;
+	int err, cal_bit;
+
+	if (!fw_data || !codec) {
+		pr_err("%s: wrong arguments passed\n", __func__);
+		return -EINVAL;
+	}
+
+	fw = fw_data->fw;
+	snprintf(hwname, strlen("Codec %s"), "Codec %s",
+		 codec->component.name);
+	err = snd_hwdep_new(codec->component.card->snd_card,
+			    hwname, node, &hwdep);
+	if (err < 0) {
+		dev_err(codec->dev, "%s: new hwdep failed %d\n",
+				__func__, err);
+		return err;
+	}
+	snprintf(hwdep->name, strlen("Codec %s"), "Codec %s",
+		 codec->component.name);
+	hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_CODEC;
+	hwdep->private_data = fw_data;
+	hwdep->ops.ioctl_compat = wcdcal_hwdep_ioctl_compat;
+	hwdep->ops.ioctl = wcdcal_hwdep_ioctl;
+	hwdep->ops.release = wcdcal_hwdep_release;
+	mutex_init(&fw_data->lock);
+
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		set_bit(WCDCAL_UNINITIALISED,
+				&fw_data->wcdcal_state[cal_bit]);
+		fw[cal_bit] = kzalloc(sizeof *(fw[cal_bit]), GFP_KERNEL);
+		if (!fw[cal_bit]) {
+			dev_err(codec->dev, "%s: no memory for %s cal\n",
+				__func__, cal_name_info[cal_bit]);
+			goto end;
+		}
+	}
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		fw[cal_bit]->data = kzalloc(cal_size_info[cal_bit],
+						GFP_KERNEL);
+		if (!fw[cal_bit]->data)
+			goto exit;
+		set_bit(WCDCAL_INITIALISED,
+			&fw_data->wcdcal_state[cal_bit]);
+	}
+	return 0;
+exit:
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		kfree(fw[cal_bit]->data);
+		fw[cal_bit]->data = NULL;
+	}
+end:
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		kfree(fw[cal_bit]);
+		fw[cal_bit] = NULL;
+	}
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(wcd_cal_create_hwdep);
diff --git a/asoc/codecs/wcdcal-hwdep.h b/asoc/codecs/wcdcal-hwdep.h
new file mode 100644
index 0000000..632e2f1
--- /dev/null
+++ b/asoc/codecs/wcdcal-hwdep.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD9XXX_HWDEP_H__
+#define __WCD9XXX_HWDEP_H__
+#include <sound/msmcal-hwdep.h>
+
+enum wcd_cal_states {
+	WCDCAL_UNINITIALISED,
+	WCDCAL_INITIALISED,
+	WCDCAL_RECIEVED
+};
+
+struct fw_info {
+	struct firmware_cal *fw[WCD9XXX_MAX_CAL];
+	DECLARE_BITMAP(cal_bit, WCD9XXX_MAX_CAL);
+	/* for calibration tracking */
+	unsigned long wcdcal_state[WCD9XXX_MAX_CAL];
+	struct mutex lock;
+};
+
+struct firmware_cal {
+	u8 *data;
+	size_t size;
+};
+
+struct snd_soc_codec;
+int wcd_cal_create_hwdep(void *fw, int node, struct snd_soc_codec *codec);
+struct firmware_cal *wcdcal_get_fw_cal(struct fw_info *fw_data,
+					enum wcd_cal_type type);
+#endif /* __WCD9XXX_HWDEP_H__ */
diff --git a/asoc/codecs/wsa881x-analog.c b/asoc/codecs/wsa881x-analog.c
new file mode 100644
index 0000000..4de9624
--- /dev/null
+++ b/asoc/codecs/wsa881x-analog.c
@@ -0,0 +1,1446 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/q6afe-v2.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include "wsa881x-analog.h"
+#include "wsa881x-temp-sensor.h"
+#include "../msm/msm-audio-pinctrl.h"
+
+#define SPK_GAIN_12DB 4
+#define WIDGET_NAME_MAX_SIZE 80
+
+/*
+ * Private data Structure for wsa881x. All parameters related to
+ * WSA881X codec needs to be defined here.
+ */
+struct wsa881x_pdata {
+	struct regmap *regmap[2];
+	struct i2c_client *client[2];
+	struct snd_soc_codec *codec;
+
+	/* track wsa881x status during probe */
+	int status;
+	bool boost_enable;
+	bool visense_enable;
+	int spk_pa_gain;
+	struct i2c_msg xfer_msg[2];
+	struct mutex xfer_lock;
+	bool regmap_flag;
+	bool wsa_active;
+	int index;
+	int (*enable_mclk)(struct snd_soc_card *, bool);
+	struct wsa881x_tz_priv tz_pdata;
+	int bg_cnt;
+	int clk_cnt;
+	int enable_cnt;
+	int version;
+	struct mutex bg_lock;
+	struct mutex res_lock;
+	struct delayed_work ocp_ctl_work;
+};
+
+enum {
+	WSA881X_STATUS_PROBING,
+	WSA881X_STATUS_I2C,
+};
+
+#define WSA881X_OCP_CTL_TIMER_SEC 2
+#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
+#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
+
+static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC;
+module_param(wsa881x_ocp_poll_timer_sec, int, 0664);
+MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling");
+
+static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec,
+						bool enable);
+
+const char *wsa_tz_names[] = {"wsa881x.0e", "wsa881x.0f"};
+
+struct wsa881x_pdata wsa_pdata[MAX_WSA881X_DEVICE];
+
+static bool pinctrl_init;
+
+static int wsa881x_populate_dt_pdata(struct device *dev);
+static int wsa881x_reset(struct wsa881x_pdata *pdata, bool enable);
+static int wsa881x_startup(struct wsa881x_pdata *pdata);
+static int wsa881x_shutdown(struct wsa881x_pdata *pdata);
+
+static int delay_array_msec[] = {10, 20, 30, 40, 50};
+
+static int wsa881x_i2c_addr = -1;
+static int wsa881x_probing_count;
+static int wsa881x_presence_count;
+
+static const char * const wsa881x_spk_pa_gain_text[] = {
+"POS_13P5_DB", "POS_12_DB", "POS_10P5_DB", "POS_9_DB", "POS_7P5_DB",
+"POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB", "POS_0_DB"};
+
+static const struct soc_enum wsa881x_spk_pa_gain_enum[] = {
+		SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa881x_spk_pa_gain_text),
+				    wsa881x_spk_pa_gain_text),
+};
+
+static int wsa881x_spk_pa_gain_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->spk_pa_gain;
+
+	dev_dbg(codec->dev, "%s: spk_pa_gain = %ld\n", __func__,
+				ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int wsa881x_spk_pa_gain_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	if (ucontrol->value.integer.value[0] < 0 ||
+		ucontrol->value.integer.value[0] > 0xC) {
+		dev_err(codec->dev, "%s: Unsupported gain val %ld\n",
+			 __func__, ucontrol->value.integer.value[0]);
+		return -EINVAL;
+	}
+	wsa881x->spk_pa_gain = ucontrol->value.integer.value[0];
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+			 __func__, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int get_i2c_wsa881x_device_index(u16 reg)
+{
+	u16 mask = 0x0f00;
+	int value = 0;
+
+	value = ((reg & mask) >> 8) & 0x000f;
+
+	switch (value) {
+	case 0:
+		return 0;
+	case 1:
+		return 1;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int wsa881x_i2c_write_device(struct wsa881x_pdata *wsa881x,
+			unsigned int reg, unsigned int val)
+{
+	int i = 0, rc = 0;
+	int wsa881x_index;
+	struct i2c_msg *msg;
+	int ret = 0;
+	int bytes = 1;
+	u8 reg_addr = 0;
+	u8 data[bytes + 1];
+
+	wsa881x_index = get_i2c_wsa881x_device_index(reg);
+	if (wsa881x_index < 0) {
+		pr_err("%s:invalid register to write\n", __func__);
+		return -EINVAL;
+	}
+	if (wsa881x->regmap_flag) {
+		rc = regmap_write(wsa881x->regmap[wsa881x_index], reg, val);
+		for (i = 0; rc && i < ARRAY_SIZE(delay_array_msec); i++) {
+			pr_err("Failed writing reg=%u - retry(%d)\n", reg, i);
+			/* retry after delay of increasing order */
+			msleep(delay_array_msec[i]);
+			rc = regmap_write(wsa881x->regmap[wsa881x_index],
+								reg, val);
+		}
+		if (rc)
+			pr_err("Failed writing reg=%u rc=%d\n", reg, rc);
+		else
+			pr_err("write success register = %x val = %x\n",
+							reg, val);
+	} else {
+		reg_addr = (u8)reg;
+		msg = &wsa881x->xfer_msg[0];
+		msg->addr = wsa881x->client[wsa881x_index]->addr;
+		msg->len = bytes + 1;
+		msg->flags = 0;
+		data[0] = reg;
+		data[1] = (u8)val;
+		msg->buf = data;
+		ret = i2c_transfer(wsa881x->client[wsa881x_index]->adapter,
+						wsa881x->xfer_msg, 1);
+		/* Try again if the write fails */
+		if (ret != 1) {
+			ret = i2c_transfer(
+					wsa881x->client[wsa881x_index]->adapter,
+							wsa881x->xfer_msg, 1);
+			if (ret != 1) {
+				pr_err("failed to write the device\n");
+				return ret;
+			}
+		}
+		pr_debug("write success reg = %x val = %x\n", reg, data[1]);
+	}
+	return rc;
+}
+
+static int wsa881x_i2c_read_device(struct wsa881x_pdata *wsa881x,
+				unsigned int reg)
+{
+	int wsa881x_index;
+	int i = 0, rc = 0;
+	unsigned int val;
+	struct i2c_msg *msg;
+	int ret = 0;
+	u8 reg_addr = 0;
+	u8 dest[5];
+
+	wsa881x_index = get_i2c_wsa881x_device_index(reg);
+	if (wsa881x_index < 0) {
+		pr_err("%s:invalid register to read\n", __func__);
+		return -EINVAL;
+	}
+	if (wsa881x->regmap_flag) {
+		rc = regmap_read(wsa881x->regmap[wsa881x_index], reg, &val);
+		for (i = 0; rc && i < ARRAY_SIZE(delay_array_msec); i++) {
+			pr_err("Failed reading reg=%u - retry(%d)\n", reg, i);
+			/* retry after delay of increasing order */
+			msleep(delay_array_msec[i]);
+			rc = regmap_read(wsa881x->regmap[wsa881x_index],
+						reg, &val);
+		}
+		if (rc) {
+			pr_err("Failed reading reg=%u rc=%d\n", reg, rc);
+			return rc;
+		}
+		pr_debug("read success reg = %x val = %x\n",
+						reg, val);
+	} else {
+		reg_addr = (u8)reg;
+		msg = &wsa881x->xfer_msg[0];
+		msg->addr = wsa881x->client[wsa881x_index]->addr;
+		msg->len = 1;
+		msg->flags = 0;
+		msg->buf = &reg_addr;
+
+		msg = &wsa881x->xfer_msg[1];
+		msg->addr = wsa881x->client[wsa881x_index]->addr;
+		msg->len = 1;
+		msg->flags = I2C_M_RD;
+		msg->buf = dest;
+		ret = i2c_transfer(wsa881x->client[wsa881x_index]->adapter,
+					wsa881x->xfer_msg, 2);
+
+		/* Try again if read fails first time */
+		if (ret != 2) {
+			ret = i2c_transfer(
+				wsa881x->client[wsa881x_index]->adapter,
+						wsa881x->xfer_msg, 2);
+			if (ret != 2) {
+				pr_err("failed to read wsa register:%d\n",
+								reg);
+				return ret;
+			}
+		}
+		val = dest[0];
+	}
+	return val;
+}
+
+static unsigned int wsa881x_i2c_read(struct snd_soc_codec *codec,
+				unsigned int reg)
+{
+	struct wsa881x_pdata *wsa881x;
+	unsigned int val;
+	int ret;
+
+	if (codec == NULL) {
+		pr_err("%s: invalid codec\n", __func__);
+		return -EINVAL;
+	}
+	wsa881x = snd_soc_codec_get_drvdata(codec);
+	if (!wsa881x->wsa_active) {
+		ret = snd_soc_cache_read(codec, reg, &val);
+		if (ret >= 0)
+			return val;
+		dev_err(codec->dev,
+			"cache read failed for reg: 0x%x ret: %d\n",
+						 reg, ret);
+		return ret;
+	}
+	return wsa881x_i2c_read_device(wsa881x, reg);
+}
+
+static int wsa881x_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
+			unsigned int val)
+{
+	struct wsa881x_pdata *wsa881x;
+	int ret = 0;
+
+	if (codec == NULL) {
+		pr_err("%s: invalid codec\n", __func__);
+		return -EINVAL;
+	}
+	wsa881x = snd_soc_codec_get_drvdata(codec);
+	if (!wsa881x->wsa_active) {
+		ret = snd_soc_cache_write(codec, reg, val);
+		if (ret != 0)
+			dev_err(codec->dev, "cache write to %x failed: %d\n",
+						reg, ret);
+		return ret;
+	}
+	return wsa881x_i2c_write_device(wsa881x, reg, val);
+}
+
+static int wsa881x_i2c_get_client_index(struct i2c_client *client,
+					int *wsa881x_index)
+{
+	int ret = 0;
+
+	switch (client->addr) {
+	case WSA881X_I2C_SPK0_SLAVE0_ADDR:
+	case WSA881X_I2C_SPK0_SLAVE1_ADDR:
+		*wsa881x_index = WSA881X_I2C_SPK0_SLAVE0;
+	break;
+	case WSA881X_I2C_SPK1_SLAVE0_ADDR:
+	case WSA881X_I2C_SPK1_SLAVE1_ADDR:
+		*wsa881x_index = WSA881X_I2C_SPK1_SLAVE0;
+	break;
+	default:
+		ret = -EINVAL;
+	break;
+	}
+	return ret;
+}
+
+static int wsa881x_boost_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enable:%d\n", __func__, enable);
+	if (enable) {
+		if (!WSA881X_IS_2_0(wsa881x->version)) {
+			snd_soc_update_bits(codec, WSA881X_ANA_CTL,
+								0x01, 0x01);
+			snd_soc_update_bits(codec, WSA881X_ANA_CTL,
+								0x04, 0x04);
+			snd_soc_update_bits(codec, WSA881X_BOOST_PS_CTL,
+								0x40, 0x00);
+			snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT1,
+								0xF0, 0xB0);
+			snd_soc_update_bits(codec, WSA881X_BOOST_ZX_CTL,
+								0x20, 0x00);
+			snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL,
+								0x80, 0x80);
+		} else {
+			snd_soc_update_bits(codec, WSA881X_BOOST_LOOP_STABILITY,
+							0x03, 0x03);
+			snd_soc_update_bits(codec, WSA881X_BOOST_MISC2_CTL,
+							0xFF, 0x14);
+			snd_soc_update_bits(codec, WSA881X_BOOST_START_CTL,
+							0x80, 0x80);
+			snd_soc_update_bits(codec, WSA881X_BOOST_START_CTL,
+							0x03, 0x00);
+			snd_soc_update_bits(codec,
+					WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
+					0x0C, 0x04);
+			snd_soc_update_bits(codec,
+					WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
+					0x03, 0x00);
+			snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT1,
+							0xF0, 0x70);
+			snd_soc_update_bits(codec, WSA881X_ANA_CTL, 0x03, 0x01);
+			snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN,
+								0x08, 0x08);
+			snd_soc_update_bits(codec, WSA881X_ANA_CTL, 0x04, 0x04);
+			snd_soc_update_bits(codec, WSA881X_BOOST_CURRENT_LIMIT,
+								0x0F, 0x08);
+			snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL,
+								0x80, 0x80);
+		}
+		/* For WSA8810, start-up time is 1500us as per qcrg sequence */
+		usleep_range(1500, 1510);
+	} else {
+		/* ENSURE: Class-D amp is shutdown. CLK is still on */
+		snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL, 0x80, 0x00);
+		/* boost settle time is 1500us as per qcrg sequence */
+		usleep_range(1500, 1510);
+	}
+	return 0;
+}
+
+static int wsa881x_visense_txfe_ctrl(struct snd_soc_codec *codec, bool enable,
+				     u8 isense1_gain, u8 isense2_gain,
+				     u8 vsense_gain)
+{
+	u8 value = 0;
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enable:%d\n", __func__, enable);
+
+	if (enable) {
+		if (WSA881X_IS_2_0(wsa881x->version)) {
+			snd_soc_update_bits(codec, WSA881X_OTP_REG_28,
+						0x3F, 0x3A);
+			snd_soc_update_bits(codec, WSA881X_BONGO_RESRV_REG1,
+						0xFF, 0xB2);
+			snd_soc_update_bits(codec, WSA881X_BONGO_RESRV_REG2,
+						0xFF, 0x05);
+		}
+		snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_VSENSE_VCM,
+					0x08, 0x00);
+		if (WSA881X_IS_2_0(wsa881x->version)) {
+			snd_soc_update_bits(codec, WSA881X_SPKR_PROT_ATEST2,
+							0x1C, 0x04);
+		} else {
+			snd_soc_update_bits(codec, WSA881X_SPKR_PROT_ATEST2,
+							0x08, 0x08);
+			snd_soc_update_bits(codec, WSA881X_SPKR_PROT_ATEST2,
+							0x02, 0x02);
+		}
+		value = ((isense2_gain << 6) | (isense1_gain << 4) |
+			(vsense_gain << 3));
+		snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_GAIN,
+					0xF8, value);
+		snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_GAIN,
+					0x01, 0x01);
+	} else {
+		if (WSA881X_IS_2_0(wsa881x->version))
+			snd_soc_update_bits(codec,
+				WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x10, 0x10);
+		else
+			snd_soc_update_bits(codec,
+				WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x08, 0x08);
+		/*
+		 * 200us sleep is needed after visense txfe disable as per
+		 * HW requirement.
+		 */
+		usleep_range(200, 210);
+
+		snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_GAIN,
+					0x01, 0x00);
+	}
+	return 0;
+}
+
+static int wsa881x_visense_adc_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enable:%d\n", __func__, enable);
+	if (enable) {
+		if (!WSA881X_IS_2_0(wsa881x->version))
+			snd_soc_update_bits(codec, WSA881X_ADC_SEL_IBIAS,
+							0x70, 0x40);
+		snd_soc_update_bits(codec, WSA881X_ADC_EN_SEL_IBIAS,
+							0x07, 0x04);
+		snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V, 0x80, 0x80);
+		snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_I, 0x80, 0x80);
+	} else {
+		/* Ensure: Speaker Protection has been stopped */
+		snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V, 0x80, 0x00);
+		snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_I, 0x80, 0x00);
+	}
+
+	return 0;
+}
+
+static void wsa881x_bandgap_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: enable:%d, bg_count:%d\n", __func__,
+		enable, wsa881x->bg_cnt);
+	mutex_lock(&wsa881x->bg_lock);
+	if (enable) {
+		++wsa881x->bg_cnt;
+		if (wsa881x->bg_cnt == 1) {
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP,
+					    0x08, 0x08);
+			/* 400usec sleep is needed as per HW requirement */
+			usleep_range(400, 410);
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x04, 0x04);
+		}
+	} else {
+		--wsa881x->bg_cnt;
+		if (wsa881x->bg_cnt <= 0) {
+			WARN_ON(wsa881x->bg_cnt < 0);
+			wsa881x->bg_cnt = 0;
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x04, 0x00);
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x08, 0x00);
+		}
+	}
+	mutex_unlock(&wsa881x->bg_lock);
+}
+
+static void wsa881x_clk_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s:ss enable:%d, clk_count:%d\n", __func__,
+		enable, wsa881x->clk_cnt);
+	mutex_lock(&wsa881x->res_lock);
+	if (enable) {
+		++wsa881x->clk_cnt;
+		if (wsa881x->clk_cnt == 1) {
+			snd_soc_write(codec, WSA881X_CDC_RST_CTL, 0x02);
+			snd_soc_write(codec, WSA881X_CDC_RST_CTL, 0x03);
+			snd_soc_write(codec, WSA881X_CLOCK_CONFIG, 0x01);
+			snd_soc_write(codec, WSA881X_CDC_DIG_CLK_CTL, 0x01);
+			snd_soc_write(codec, WSA881X_CDC_ANA_CLK_CTL, 0x01);
+		}
+	} else {
+		--wsa881x->clk_cnt;
+		if (wsa881x->clk_cnt <= 0) {
+			WARN_ON(wsa881x->clk_cnt < 0);
+			wsa881x->clk_cnt = 0;
+			snd_soc_write(codec, WSA881X_CDC_ANA_CLK_CTL, 0x00);
+			snd_soc_write(codec, WSA881X_CDC_DIG_CLK_CTL, 0x00);
+			if (WSA881X_IS_2_0(wsa881x->version))
+				snd_soc_update_bits(codec,
+					WSA881X_CDC_TOP_CLK_CTL, 0x01, 0x00);
+		}
+	}
+	mutex_unlock(&wsa881x->res_lock);
+}
+
+static int wsa881x_rdac_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enable:%d\n", __func__, enable);
+	if (enable) {
+		snd_soc_update_bits(codec, WSA881X_ANA_CTL, 0x08, 0x00);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, 0x08, 0x08);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x20, 0x20);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x20, 0x00);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x40, 0x40);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x80, 0x80);
+		if (WSA881X_IS_2_0(wsa881x->version)) {
+			snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
+								0x01, 0x01);
+			snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL,
+								0x30, 0x30);
+			snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL,
+								0x0C, 0x00);
+		}
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, 0xF0, 0x40);
+		snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0x01, 0x01);
+	} else {
+		/* Ensure class-D amp is off */
+		snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x80, 0x00);
+	}
+	return 0;
+}
+
+static int wsa881x_spkr_pa_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	int ret = 0;
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enable:%d\n", __func__, enable);
+	if (enable) {
+		/*
+		 * Ensure: Boost is enabled and stable, Analog input is up
+		 * and outputting silence
+		 */
+		if (!WSA881X_IS_2_0(wsa881x->version)) {
+			snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_I,
+								0xFF, 0x01);
+			snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V,
+								0x02, 0x02);
+			snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_V,
+								0xFF, 0x10);
+			snd_soc_update_bits(codec, WSA881X_SPKR_PWRSTG_DBG,
+								0xA0, 0xA0);
+			snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN,
+								0x80, 0x80);
+			usleep_range(700, 710);
+			snd_soc_update_bits(codec, WSA881X_SPKR_PWRSTG_DBG,
+								0x00, 0x00);
+			snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_V,
+								0xFF, 0x00);
+			snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V,
+								0x02, 0x00);
+			snd_soc_update_bits(codec, WSA881X_ADC_EN_DET_TEST_I,
+								0xFF, 0x00);
+		} else
+			snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN,
+								0x80, 0x80);
+		/* add 1000us delay as per qcrg */
+		usleep_range(1000, 1010);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x01, 0x01);
+		if (WSA881X_IS_2_0(wsa881x->version))
+			snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
+								0x01, 0x00);
+		usleep_range(1000, 1010);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN, 0xF0,
+						(wsa881x->spk_pa_gain << 4));
+		if (wsa881x->visense_enable) {
+			ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1,
+							"wsa_vi");
+			if (ret) {
+				pr_err("%s: gpio set cannot be activated %s\n",
+					__func__, "wsa_vi");
+				return ret;
+			}
+			wsa881x_visense_txfe_ctrl(codec, true,
+						0x00, 0x01, 0x00);
+			wsa881x_visense_adc_ctrl(codec, true);
+		}
+	} else {
+		/*
+		 * Ensure: Boost is still on, Stream from Analog input and
+		 * Speaker Protection has been stopped and input is at 0V
+		 */
+		if (WSA881X_IS_2_0(wsa881x->version)) {
+			snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
+								0x01, 0x01);
+			usleep_range(1000, 1010);
+			snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_CAL,
+								0x01, 0x00);
+			msleep(20);
+			snd_soc_update_bits(codec, WSA881X_ANA_CTL,
+								0x03, 0x00);
+			usleep_range(200, 210);
+		}
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x80, 0x00);
+	}
+	return 0;
+}
+
+static int wsa881x_get_boost(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->boost_enable;
+	return 0;
+}
+
+static int wsa881x_set_boost(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: Boost enable current %d, new %d\n",
+		 __func__, wsa881x->boost_enable, value);
+	wsa881x->boost_enable = value;
+	return 0;
+}
+
+static int wsa881x_get_visense(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->visense_enable;
+	return 0;
+}
+
+static int wsa881x_set_visense(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: VIsense enable current %d, new %d\n",
+		 __func__, wsa881x->visense_enable, value);
+	wsa881x->visense_enable = value;
+	return 0;
+}
+
+static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
+	SOC_SINGLE_EXT("BOOST Switch", SND_SOC_NOPM, 0, 1, 0,
+		wsa881x_get_boost, wsa881x_set_boost),
+
+	SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
+		wsa881x_get_visense, wsa881x_set_visense),
+
+	SOC_ENUM_EXT("WSA_SPK PA Gain", wsa881x_spk_pa_gain_enum[0],
+		wsa881x_spk_pa_gain_get, wsa881x_spk_pa_gain_put),
+};
+
+static const char * const rdac_text[] = {
+	"ZERO", "Switch",
+};
+
+static const struct soc_enum rdac_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(rdac_text), rdac_text);
+
+static const struct snd_kcontrol_new rdac_mux[] = {
+	SOC_DAPM_ENUM("RDAC", rdac_enum)
+};
+
+static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s: %s %d boost %d visense %d\n",
+		 __func__, w->name, event,
+		wsa881x->boost_enable, wsa881x->visense_enable);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = wsa881x_startup(wsa881x);
+		if (ret) {
+			pr_err("%s: wsa startup failed ret: %d", __func__, ret);
+			return ret;
+		}
+		wsa881x_clk_ctrl(codec, true);
+		snd_soc_update_bits(codec, WSA881X_SPKR_DAC_CTL, 0x02, 0x02);
+		if (!WSA881X_IS_2_0(wsa881x->version))
+			snd_soc_update_bits(codec, WSA881X_BIAS_REF_CTRL,
+								0x0F, 0x08);
+		wsa881x_bandgap_ctrl(codec, true);
+		if (!WSA881X_IS_2_0(wsa881x->version))
+			snd_soc_update_bits(codec, WSA881X_SPKR_BBM_CTL,
+								0x02, 0x02);
+		snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0xC0, 0x80);
+		snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0x06, 0x06);
+		if (!WSA881X_IS_2_0(wsa881x->version)) {
+			snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL2,
+								0x04, 0x04);
+			snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_INT,
+								0x09, 0x09);
+		}
+		snd_soc_update_bits(codec, WSA881X_SPKR_PA_INT, 0xF0, 0x20);
+		if (WSA881X_IS_2_0(wsa881x->version))
+			snd_soc_update_bits(codec, WSA881X_SPKR_PA_INT,
+								0x0E, 0x0E);
+		if (wsa881x->boost_enable)
+			wsa881x_boost_ctrl(codec, true);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		wsa881x_rdac_ctrl(codec, true);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		wsa881x_rdac_ctrl(codec, false);
+		if (wsa881x->visense_enable) {
+			wsa881x_visense_adc_ctrl(codec, false);
+			wsa881x_visense_txfe_ctrl(codec, false,
+						0x00, 0x01, 0x00);
+			ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1,
+							"wsa_vi");
+			if (ret) {
+				pr_err("%s: gpio set cannot be suspended %s\n",
+					__func__, "wsa_vi");
+				return ret;
+			}
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (wsa881x->boost_enable)
+			wsa881x_boost_ctrl(codec, false);
+		wsa881x_clk_ctrl(codec, false);
+		wsa881x_bandgap_ctrl(codec, false);
+		ret = wsa881x_shutdown(wsa881x);
+		if (ret < 0) {
+			pr_err("%s: wsa shutdown failed ret: %d",
+					__func__, ret);
+			return ret;
+		}
+		break;
+	default:
+		pr_err("%s: invalid event:%d\n", __func__, event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void wsa881x_ocp_ctl_work(struct work_struct *work)
+{
+	struct wsa881x_pdata *wsa881x;
+	struct delayed_work *dwork;
+	struct snd_soc_codec *codec;
+	unsigned long temp_val;
+
+	dwork = to_delayed_work(work);
+	wsa881x = container_of(dwork, struct wsa881x_pdata, ocp_ctl_work);
+
+	if (!wsa881x)
+		return;
+
+	codec = wsa881x->codec;
+	wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
+	dev_dbg(codec->dev, " temp = %ld\n", temp_val);
+
+	if (temp_val <= WSA881X_OCP_CTL_TEMP_CELSIUS)
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0x00);
+	else
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
+
+		schedule_delayed_work(&wsa881x->ocp_ctl_work,
+			msecs_to_jiffies(wsa881x_ocp_poll_timer_sec * 1000));
+}
+
+static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0x80);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		wsa881x_spkr_pa_ctrl(codec, true);
+		schedule_delayed_work(&wsa881x->ocp_ctl_work,
+			msecs_to_jiffies(WSA881X_OCP_CTL_TIMER_SEC * 1000));
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		wsa881x_spkr_pa_ctrl(codec, false);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
+		break;
+	default:
+		pr_err("%s: invalid event:%d\n", __func__, event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("WSA_IN"),
+
+	SND_SOC_DAPM_DAC_E("RDAC Analog", NULL, SND_SOC_NOPM, 0, 0,
+		wsa881x_rdac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("WSA_RDAC", SND_SOC_NOPM, 0, 0,
+		rdac_mux),
+
+	SND_SOC_DAPM_PGA_S("WSA_SPKR PGA", 1, SND_SOC_NOPM, 0, 0,
+			wsa881x_spkr_pa_event,
+			SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_PRE_PMD |
+			SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("WSA_SPKR"),
+};
+
+static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
+	{"WSA_RDAC", "Switch", "WSA_IN"},
+	{"RDAC Analog", NULL, "WSA_RDAC"},
+	{"WSA_SPKR PGA", NULL, "RDAC Analog"},
+	{"WSA_SPKR", NULL, "WSA_SPKR PGA"},
+};
+
+
+static int wsa881x_startup(struct wsa881x_pdata *pdata)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = pdata->codec;
+	struct snd_soc_card *card = codec->component.card;
+
+	pr_debug("%s(): wsa startup, enable_cnt:%d\n", __func__,
+					pdata->enable_cnt);
+
+	if (pdata->enable_cnt++ > 0)
+		return 0;
+	ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1, "wsa_clk");
+	if (ret) {
+		pr_err("%s: gpio set cannot be activated %s\n",
+			__func__, "wsa_clk");
+		return ret;
+	}
+	if (pdata->enable_mclk) {
+		ret = pdata->enable_mclk(card, true);
+		if (ret < 0) {
+			dev_err_ratelimited(codec->dev,
+				"%s: mclk enable failed %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	ret = wsa881x_reset(pdata, true);
+	return ret;
+}
+
+static int wsa881x_shutdown(struct wsa881x_pdata *pdata)
+{
+	int ret = 0, reg;
+	struct snd_soc_codec *codec = pdata->codec;
+	struct snd_soc_card *card = codec->component.card;
+
+	pr_debug("%s(): wsa shutdown, enable_cnt:%d\n", __func__,
+					pdata->enable_cnt);
+	if (--pdata->enable_cnt > 0)
+		return 0;
+	ret = wsa881x_reset(pdata, false);
+	if (ret) {
+		pr_err("%s: wsa reset failed suspend %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	if (pdata->enable_mclk) {
+		ret = pdata->enable_mclk(card, false);
+		if (ret < 0) {
+			pr_err("%s: mclk disable failed %d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+
+	ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1, "wsa_clk");
+	if (ret) {
+		pr_err("%s: gpio set cannot be suspended %s\n",
+			__func__, "wsa_clk");
+		return ret;
+	}
+	if (pdata->codec) {
+		/* restore defaults to cache */
+		for (reg = 0; reg < ARRAY_SIZE(wsa881x_ana_reg_defaults);
+				reg++) {
+			if (wsa881x_ana_reg_readable[reg])
+				snd_soc_cache_write(pdata->codec,
+					wsa881x_ana_reg_defaults[reg].reg,
+					wsa881x_ana_reg_defaults[reg].def);
+		}
+	}
+	return 0;
+}
+
+static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec,
+						bool enable)
+{
+	int ret = 0;
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		ret = wsa881x_startup(wsa881x);
+		if (ret < 0) {
+			dev_err_ratelimited(codec->dev,
+				"%s: failed to startup\n", __func__);
+			return ret;
+		}
+	}
+	wsa881x_clk_ctrl(codec, enable);
+	wsa881x_bandgap_ctrl(codec, enable);
+	if (!enable) {
+		ret = wsa881x_shutdown(wsa881x);
+		if (ret < 0)
+			dev_err_ratelimited(codec->dev,
+				"%s: failed to shutdown\n", __func__);
+	}
+	return ret;
+}
+
+static int32_t wsa881x_temp_reg_read(struct snd_soc_codec *codec,
+				     struct wsa_temp_register *wsa_temp_reg)
+{
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	if (!wsa881x) {
+		dev_err(codec->dev, "%s: wsa881x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	ret = wsa881x_resource_acquire(codec, true);
+	if (ret) {
+		dev_err_ratelimited(codec->dev,
+			"%s: resource acquire fail\n", __func__);
+		return ret;
+	}
+
+	if (WSA881X_IS_2_0(wsa881x->version)) {
+		snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x00);
+		wsa_temp_reg->dmeas_msb = snd_soc_read(codec, WSA881X_TEMP_MSB);
+		wsa_temp_reg->dmeas_lsb = snd_soc_read(codec, WSA881X_TEMP_LSB);
+		snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x01);
+	} else {
+		wsa_temp_reg->dmeas_msb = snd_soc_read(codec,
+						   WSA881X_TEMP_DOUT_MSB);
+		wsa_temp_reg->dmeas_lsb = snd_soc_read(codec,
+						   WSA881X_TEMP_DOUT_LSB);
+	}
+	wsa_temp_reg->d1_msb = snd_soc_read(codec, WSA881X_OTP_REG_1);
+	wsa_temp_reg->d1_lsb = snd_soc_read(codec, WSA881X_OTP_REG_2);
+	wsa_temp_reg->d2_msb = snd_soc_read(codec, WSA881X_OTP_REG_3);
+	wsa_temp_reg->d2_lsb = snd_soc_read(codec, WSA881X_OTP_REG_4);
+
+	ret = wsa881x_resource_acquire(codec, false);
+	if (ret)
+		dev_err_ratelimited(codec->dev,
+			"%s: resource release fail\n", __func__);
+
+	return ret;
+}
+
+static int wsa881x_probe(struct snd_soc_codec *codec)
+{
+	struct i2c_client *client;
+	int ret = 0;
+	int wsa881x_index = 0;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	char *widget_name = NULL;
+	struct snd_soc_card *card = codec->component.card;
+	struct snd_soc_codec_conf *codec_conf = card->codec_conf;
+
+	client = dev_get_drvdata(codec->dev);
+	ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
+	if (ret != 0) {
+		dev_err(&client->dev, "%s: I2C get codec I2C\n"
+			"client failed\n", __func__);
+		return ret;
+	}
+	mutex_init(&wsa_pdata[wsa881x_index].bg_lock);
+	mutex_init(&wsa_pdata[wsa881x_index].res_lock);
+	snprintf(wsa_pdata[wsa881x_index].tz_pdata.name, 100, "%s",
+			wsa_tz_names[wsa881x_index]);
+	wsa_pdata[wsa881x_index].codec = codec;
+	wsa_pdata[wsa881x_index].spk_pa_gain = SPK_GAIN_12DB;
+	wsa_pdata[wsa881x_index].codec = codec;
+	wsa_pdata[wsa881x_index].tz_pdata.codec = codec;
+	wsa_pdata[wsa881x_index].tz_pdata.wsa_temp_reg_read =
+						wsa881x_temp_reg_read;
+	snd_soc_codec_set_drvdata(codec, &wsa_pdata[wsa881x_index]);
+	wsa881x_init_thermal(&wsa_pdata[wsa881x_index].tz_pdata);
+	INIT_DELAYED_WORK(&wsa_pdata[wsa881x_index].ocp_ctl_work,
+				wsa881x_ocp_ctl_work);
+
+	if (codec_conf->name_prefix) {
+		widget_name = kcalloc(WIDGET_NAME_MAX_SIZE, sizeof(char),
+					GFP_KERNEL);
+		if (!widget_name)
+			return -ENOMEM;
+
+		snprintf(widget_name, WIDGET_NAME_MAX_SIZE,
+			"%s WSA_SPKR", codec_conf->name_prefix);
+		snd_soc_dapm_ignore_suspend(dapm, widget_name);
+		snprintf(widget_name, WIDGET_NAME_MAX_SIZE,
+			"%s WSA_IN", codec_conf->name_prefix);
+		snd_soc_dapm_ignore_suspend(dapm, widget_name);
+		kfree(widget_name);
+	} else {
+		snd_soc_dapm_ignore_suspend(dapm, "WSA_SPKR");
+		snd_soc_dapm_ignore_suspend(dapm, "WSA_IN");
+	}
+
+	snd_soc_dapm_sync(dapm);
+	return 0;
+}
+
+static int wsa881x_remove(struct snd_soc_codec *codec)
+{
+	struct wsa881x_pdata *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	if (wsa881x->tz_pdata.tz_dev)
+		wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
+
+	mutex_destroy(&wsa881x->bg_lock);
+	mutex_destroy(&wsa881x->res_lock);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wsa881x = {
+	.probe	= wsa881x_probe,
+	.remove	= wsa881x_remove,
+
+	.read = wsa881x_i2c_read,
+	.write = wsa881x_i2c_write,
+
+	.reg_cache_size = WSA881X_CACHE_SIZE,
+	.reg_cache_default = wsa881x_ana_reg_defaults,
+	.reg_word_size = 1,
+
+	.component_driver = {
+		.controls = wsa881x_snd_controls,
+		.num_controls = ARRAY_SIZE(wsa881x_snd_controls),
+		.dapm_widgets = wsa881x_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
+		.dapm_routes = wsa881x_audio_map,
+		.num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
+	},
+};
+
+static int wsa881x_reset(struct wsa881x_pdata *pdata, bool enable)
+{
+	int ret = 0;
+
+	/*
+	 * shutdown the GPIOs WSA_EN, WSA_MCLK, regulators
+	 * and restore defaults in soc cache when shutdown.
+	 * Enable regulators, GPIOs WSA_MCLK, WSA_EN when powerup.
+	 */
+	if (enable) {
+		if (pdata->wsa_active)
+			return 0;
+		ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1, "wsa_reset");
+		if (ret) {
+			pr_err("%s: gpio set cannot be activated %s\n",
+				__func__, "wsa_reset");
+			return ret;
+		}
+		ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1, "wsa_reset");
+		if (ret) {
+			pr_err("%s: gpio set cannot be suspended(powerup) %s\n",
+				__func__, "wsa_reset");
+			return ret;
+		}
+		ret = msm_gpioset_activate(CLIENT_WSA_BONGO_1, "wsa_reset");
+		if (ret) {
+			pr_err("%s: gpio set cannot be activated %s\n",
+				__func__, "wsa_reset");
+			return ret;
+		}
+		pdata->wsa_active = true;
+	} else {
+		if (!pdata->wsa_active)
+			return 0;
+		ret = msm_gpioset_suspend(CLIENT_WSA_BONGO_1, "wsa_reset");
+		if (ret) {
+			pr_err("%s: gpio set cannot be suspended %s\n",
+				__func__, "wsa_reset");
+			return ret;
+		}
+		pdata->wsa_active = false;
+	}
+	return ret;
+}
+
+int wsa881x_get_client_index(void)
+{
+	return wsa881x_i2c_addr;
+}
+EXPORT_SYMBOL(wsa881x_get_client_index);
+
+int wsa881x_get_probing_count(void)
+{
+	return wsa881x_probing_count;
+}
+EXPORT_SYMBOL(wsa881x_get_probing_count);
+
+int wsa881x_get_presence_count(void)
+{
+	return wsa881x_presence_count;
+}
+EXPORT_SYMBOL(wsa881x_get_presence_count);
+
+int wsa881x_set_mclk_callback(
+	int (*enable_mclk_callback)(struct snd_soc_card *, bool))
+{
+	int i;
+
+	for (i = 0; i < MAX_WSA881X_DEVICE; i++) {
+		if (wsa_pdata[i].status == WSA881X_STATUS_I2C)
+			wsa_pdata[i].enable_mclk = enable_mclk_callback;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(wsa881x_set_mclk_callback);
+
+static int check_wsa881x_presence(struct i2c_client *client)
+{
+	int ret = 0;
+	int wsa881x_index = 0;
+
+	ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
+	if (ret != 0) {
+		dev_err(&client->dev, "%s: I2C get codec I2C\n"
+			"client failed\n", __func__);
+		return ret;
+	}
+	ret = wsa881x_i2c_read_device(&wsa_pdata[wsa881x_index],
+					WSA881X_CDC_RST_CTL);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to read wsa881x with addr %x\n",
+				client->addr);
+		return ret;
+	}
+	ret = wsa881x_i2c_write_device(&wsa_pdata[wsa881x_index],
+					WSA881X_CDC_RST_CTL, 0x01);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed write addr %x reg:0x5 val:0x1\n",
+					client->addr);
+		return ret;
+	}
+	/* allow 20ms before trigger next write to verify WSA881x presence */
+	msleep(20);
+	ret = wsa881x_i2c_write_device(&wsa_pdata[wsa881x_index],
+					WSA881X_CDC_RST_CTL, 0x00);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed write addr %x reg:0x5 val:0x0\n",
+					client->addr);
+		return ret;
+	}
+	return ret;
+}
+
+static int wsa881x_populate_dt_pdata(struct device *dev)
+{
+	int ret = 0;
+
+	/* reading the gpio configurations from dtsi file */
+	if (!pinctrl_init) {
+		ret = msm_gpioset_initialize(CLIENT_WSA_BONGO_1, dev);
+		if (ret < 0) {
+			dev_err(dev,
+			"%s: error reading dtsi files%d\n", __func__, ret);
+			goto err;
+		}
+		pinctrl_init = true;
+	}
+err:
+	return ret;
+}
+
+static int wsa881x_i2c_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret = 0;
+	int wsa881x_index = 0;
+	struct wsa881x_pdata *pdata = NULL;
+
+	ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
+	if (ret != 0) {
+		dev_err(&client->dev, "%s: I2C get codec I2C\n"
+			"client failed\n", __func__);
+		return ret;
+	}
+
+	pdata = &wsa_pdata[wsa881x_index];
+
+	if ((client->addr == WSA881X_I2C_SPK0_SLAVE1_ADDR ||
+		client->addr == WSA881X_I2C_SPK1_SLAVE1_ADDR) &&
+		(pdata->status == WSA881X_STATUS_PROBING))
+		return ret;
+
+	if (pdata->status == WSA881X_STATUS_I2C) {
+		dev_dbg(&client->dev, "%s:probe for other slaves\n"
+			"devices of codec I2C slave Addr = %x\n",
+			__func__, client->addr);
+
+		dev_dbg(&client->dev, "%s:wsa_idx = %d SLAVE = %d\n",
+				__func__, wsa881x_index, WSA881X_ANALOG_SLAVE);
+		pdata->regmap[WSA881X_ANALOG_SLAVE] =
+			devm_regmap_init_i2c(
+				client,
+			&wsa881x_ana_regmap_config[WSA881X_ANALOG_SLAVE]);
+		regcache_cache_bypass(pdata->regmap[WSA881X_ANALOG_SLAVE],
+					true);
+		if (IS_ERR(pdata->regmap[WSA881X_ANALOG_SLAVE])) {
+			ret = PTR_ERR(pdata->regmap[WSA881X_ANALOG_SLAVE]);
+			dev_err(&client->dev,
+				"%s: regmap_init failed %d\n",
+					__func__, ret);
+		}
+		client->dev.platform_data = pdata;
+		i2c_set_clientdata(client, pdata);
+		pdata->client[WSA881X_ANALOG_SLAVE] = client;
+		if (pdata->version == WSA881X_2_0)
+			wsa881x_update_regmap_2_0(
+					pdata->regmap[WSA881X_ANALOG_SLAVE],
+					WSA881X_ANALOG_SLAVE);
+
+		return ret;
+	} else if (pdata->status == WSA881X_STATUS_PROBING) {
+		pdata->index = wsa881x_index;
+		if (client->dev.of_node) {
+			dev_dbg(&client->dev, "%s:Platform data\n"
+				"from device tree\n", __func__);
+			ret = wsa881x_populate_dt_pdata(&client->dev);
+			if (ret < 0) {
+				dev_err(&client->dev,
+				"%s: Fail to obtain pdata from device tree\n",
+					 __func__);
+				ret = -EINVAL;
+				goto err;
+			}
+			client->dev.platform_data = pdata;
+		} else {
+			dev_dbg(&client->dev, "%s:Platform data from\n"
+				"board file\n", __func__);
+			pdata = client->dev.platform_data;
+		}
+		if (!pdata) {
+			dev_dbg(&client->dev, "no platform data?\n");
+			ret = -EINVAL;
+			goto err;
+		}
+		i2c_set_clientdata(client, pdata);
+		dev_set_drvdata(&client->dev, client);
+
+		pdata->regmap[WSA881X_DIGITAL_SLAVE] =
+			devm_regmap_init_i2c(
+				client,
+			&wsa881x_ana_regmap_config[WSA881X_DIGITAL_SLAVE]);
+		regcache_cache_bypass(pdata->regmap[WSA881X_DIGITAL_SLAVE],
+					true);
+		if (IS_ERR(pdata->regmap[WSA881X_DIGITAL_SLAVE])) {
+			ret = PTR_ERR(pdata->regmap[WSA881X_DIGITAL_SLAVE]);
+			dev_err(&client->dev, "%s: regmap_init failed %d\n",
+				__func__, ret);
+			goto err;
+		}
+		/* bus reset sequence */
+		ret = wsa881x_reset(pdata, true);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: WSA enable Failed %d\n",
+				__func__, ret);
+			goto err;
+		}
+		pdata->client[WSA881X_DIGITAL_SLAVE] = client;
+		pdata->regmap_flag = true;
+		ret = check_wsa881x_presence(client);
+		if (ret < 0) {
+			dev_err(&client->dev,
+				"failed to ping wsa with addr:%x, ret = %d\n",
+						client->addr, ret);
+			wsa881x_probing_count++;
+			goto err1;
+		}
+		pdata->version = wsa881x_i2c_read_device(pdata,
+					WSA881X_CHIP_ID1);
+		pr_debug("%s: wsa881x version: %d\n", __func__, pdata->version);
+		if (pdata->version == WSA881X_2_0) {
+			wsa881x_update_reg_defaults_2_0();
+			wsa881x_update_regmap_2_0(
+					pdata->regmap[WSA881X_DIGITAL_SLAVE],
+					WSA881X_DIGITAL_SLAVE);
+		}
+		wsa881x_presence_count++;
+		wsa881x_probing_count++;
+		ret = snd_soc_register_codec(&client->dev,
+					&soc_codec_dev_wsa881x,
+					     NULL, 0);
+		if (ret < 0)
+			goto err1;
+		pdata->status = WSA881X_STATUS_I2C;
+	}
+err1:
+	wsa881x_reset(pdata, false);
+err:
+	return 0;
+}
+
+static int wsa881x_i2c_remove(struct i2c_client *client)
+{
+	struct wsa881x_pdata *wsa881x = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	i2c_set_clientdata(client, NULL);
+	kfree(wsa881x);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wsa881x_i2c_suspend(struct device *dev)
+{
+	pr_debug("%s: system suspend\n", __func__);
+	return 0;
+}
+
+static int wsa881x_i2c_resume(struct device *dev)
+{
+	pr_debug("%s: system resume\n", __func__);
+	return 0;
+}
+
+static const struct dev_pm_ops wsa881x_i2c_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(wsa881x_i2c_suspend, wsa881x_i2c_resume)
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct i2c_device_id wsa881x_i2c_id[] = {
+	{"wsa881x-i2c-dev", WSA881X_I2C_SPK0_SLAVE0_ADDR},
+	{"wsa881x-i2c-dev", WSA881X_I2C_SPK0_SLAVE1_ADDR},
+	{"wsa881x-i2c-dev", WSA881X_I2C_SPK1_SLAVE0_ADDR},
+	{"wsa881x-i2c-dev", WSA881X_I2C_SPK1_SLAVE1_ADDR},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, wsa881x_i2c_id);
+
+
+static const struct of_device_id msm_match_table[] = {
+	{.compatible = "qcom,wsa881x-i2c-codec"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_match_table);
+
+static struct i2c_driver wsa881x_codec_driver = {
+	.driver = {
+		.name = "wsa881x-i2c-codec",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM_SLEEP
+		.pm = &wsa881x_i2c_pm_ops,
+#endif
+		.of_match_table = msm_match_table,
+	},
+	.id_table = wsa881x_i2c_id,
+	.probe = wsa881x_i2c_probe,
+	.remove = wsa881x_i2c_remove,
+};
+
+static int __init wsa881x_codec_init(void)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_WSA881X_DEVICE; i++)
+		wsa_pdata[i].status = WSA881X_STATUS_PROBING;
+	return i2c_add_driver(&wsa881x_codec_driver);
+}
+module_init(wsa881x_codec_init);
+
+static void __exit wsa881x_codec_exit(void)
+{
+	i2c_del_driver(&wsa881x_codec_driver);
+}
+
+module_exit(wsa881x_codec_exit);
+
+MODULE_DESCRIPTION("WSA881x Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wsa881x-analog.h b/asoc/codecs/wsa881x-analog.h
new file mode 100644
index 0000000..a2ef2a2
--- /dev/null
+++ b/asoc/codecs/wsa881x-analog.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WSA881X_H
+#define _WSA881X_H
+
+#include <linux/regmap.h>
+#include "wsa881x-registers-analog.h"
+#include <sound/soc.h>
+
+#define WSA881X_I2C_SPK0_SLAVE0_ADDR	0x0E
+#define WSA881X_I2C_SPK0_SLAVE1_ADDR	0x44
+#define WSA881X_I2C_SPK1_SLAVE0_ADDR	0x0F
+#define WSA881X_I2C_SPK1_SLAVE1_ADDR	0x45
+
+#define WSA881X_I2C_SPK0_SLAVE0	0
+#define WSA881X_I2C_SPK1_SLAVE0	1
+#define MAX_WSA881X_DEVICE 2
+#define WSA881X_DIGITAL_SLAVE 0
+#define WSA881X_ANALOG_SLAVE 1
+
+enum {
+	WSA881X_1_X = 0,
+	WSA881X_2_0,
+};
+
+#define WSA881X_IS_2_0(ver) \
+	((ver == WSA881X_2_0) ? 1 : 0)
+
+extern const u8 wsa881x_ana_reg_readable[WSA881X_CACHE_SIZE];
+extern struct reg_default wsa881x_ana_reg_defaults[WSA881X_CACHE_SIZE];
+extern struct regmap_config wsa881x_ana_regmap_config[2];
+int wsa881x_get_client_index(void);
+int wsa881x_get_probing_count(void);
+int wsa881x_get_presence_count(void);
+int wsa881x_set_mclk_callback(
+	int (*enable_mclk_callback)(struct snd_soc_card *, bool));
+void wsa881x_update_reg_defaults_2_0(void);
+void wsa881x_update_regmap_2_0(struct regmap *regmap, int flag);
+
+#endif /* _WSA881X_H */
diff --git a/asoc/codecs/wsa881x-irq.c b/asoc/codecs/wsa881x-irq.c
new file mode 100644
index 0000000..9afbd92
--- /dev/null
+++ b/asoc/codecs/wsa881x-irq.c
@@ -0,0 +1,610 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/ratelimit.h>
+#include <linux/pm_qos.h>
+#include <soc/qcom/pm.h>
+#include "wsa881x-irq.h"
+#include "wsa881x-registers-analog.h"
+
+#define BYTE_BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_BYTE))
+#define BIT_BYTE(nr)			((nr) / BITS_PER_BYTE)
+
+
+#define WSA_MAX_NUM_IRQS 8
+
+#ifndef NO_IRQ
+#define NO_IRQ	(-1)
+#endif
+
+static int virq_to_phyirq(
+	struct wsa_resource *wsa_res, int virq);
+static int phyirq_to_virq(
+	struct wsa_resource *wsa_res, int irq);
+static unsigned int wsa_irq_get_upstream_irq(
+	struct wsa_resource *wsa_res);
+static void wsa_irq_put_upstream_irq(
+	struct wsa_resource *wsa_res);
+static int wsa_map_irq(
+	struct wsa_resource *wsa_res, int irq);
+
+static struct snd_soc_codec *ptr_codec;
+
+/**
+ * wsa_set_codec() - to update codec pointer
+ * @codec: codec pointer.
+ *
+ * To update the codec pointer, which is used to read/write
+ * wsa register.
+ *
+ * Return: void.
+ */
+void wsa_set_codec(struct snd_soc_codec *codec)
+{
+	if (codec == NULL) {
+		pr_err("%s: codec pointer is NULL\n", __func__);
+		ptr_codec = NULL;
+		return;
+	}
+	ptr_codec = codec;
+	/* Initialize interrupt mask and level registers */
+	snd_soc_write(codec, WSA881X_INTR_LEVEL, 0x8F);
+	snd_soc_write(codec, WSA881X_INTR_MASK, 0x8F);
+}
+
+static void wsa_irq_lock(struct irq_data *data)
+{
+	struct wsa_resource *wsa_res =
+			irq_data_get_irq_chip_data(data);
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res pointer is NULL\n", __func__);
+		return;
+	}
+	mutex_lock(&wsa_res->irq_lock);
+}
+
+static void wsa_irq_sync_unlock(struct irq_data *data)
+{
+	struct wsa_resource *wsa_res =
+			irq_data_get_irq_chip_data(data);
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res pointer is NULL\n", __func__);
+		return;
+	}
+	if (wsa_res->codec == NULL) {
+		pr_err("%s: codec pointer not registered\n", __func__);
+		if (ptr_codec == NULL) {
+			pr_err("%s: did not receive valid codec pointer\n",
+					__func__);
+			goto unlock;
+		} else {
+			wsa_res->codec = ptr_codec;
+		}
+	}
+
+	/*
+	 * If there's been a change in the mask write it back
+	 * to the hardware.
+	 */
+	if (wsa_res->irq_masks_cur !=
+			wsa_res->irq_masks_cache) {
+
+		wsa_res->irq_masks_cache =
+			wsa_res->irq_masks_cur;
+		snd_soc_write(wsa_res->codec,
+			WSA881X_INTR_MASK,
+			wsa_res->irq_masks_cur);
+	}
+unlock:
+	mutex_unlock(&wsa_res->irq_lock);
+}
+
+static void wsa_irq_enable(struct irq_data *data)
+{
+	struct wsa_resource *wsa_res =
+			irq_data_get_irq_chip_data(data);
+	int wsa_irq;
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res pointer is NULL\n", __func__);
+		return;
+	}
+	wsa_irq = virq_to_phyirq(wsa_res, data->irq);
+	pr_debug("%s: wsa_irq = %d\n", __func__, wsa_irq);
+	wsa_res->irq_masks_cur &=
+			~(BYTE_BIT_MASK(wsa_irq));
+}
+
+static void wsa_irq_disable(struct irq_data *data)
+{
+	struct wsa_resource *wsa_res =
+			irq_data_get_irq_chip_data(data);
+	int wsa_irq;
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res pointer is NULL\n", __func__);
+		return;
+	}
+	wsa_irq = virq_to_phyirq(wsa_res, data->irq);
+	pr_debug("%s: wsa_irq = %d\n", __func__, wsa_irq);
+	wsa_res->irq_masks_cur
+			|= BYTE_BIT_MASK(wsa_irq);
+}
+
+static void wsa_irq_ack(struct irq_data *data)
+{
+	int wsa_irq = 0;
+	struct wsa_resource *wsa_res =
+			irq_data_get_irq_chip_data(data);
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return;
+	}
+	wsa_irq = virq_to_phyirq(wsa_res, data->irq);
+	pr_debug("%s: IRQ_ACK called for WCD9XXX IRQ: %d\n",
+				__func__, wsa_irq);
+}
+
+static void wsa_irq_mask(struct irq_data *d)
+{
+	/* do nothing but required as linux calls irq_mask without NULL check */
+}
+
+static struct irq_chip wsa_irq_chip = {
+	.name = "wsa",
+	.irq_bus_lock = wsa_irq_lock,
+	.irq_bus_sync_unlock = wsa_irq_sync_unlock,
+	.irq_disable = wsa_irq_disable,
+	.irq_enable = wsa_irq_enable,
+	.irq_mask = wsa_irq_mask,
+	.irq_ack = wsa_irq_ack,
+};
+
+static irqreturn_t wsa_irq_thread(int irq, void *data)
+{
+	struct wsa_resource *wsa_res = data;
+	int i;
+	u8 status;
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return IRQ_HANDLED;
+	}
+	if (wsa_res->codec == NULL) {
+		pr_err("%s: codec pointer not registered\n", __func__);
+		if (ptr_codec == NULL) {
+			pr_err("%s: did not receive valid codec pointer\n",
+					__func__);
+			return IRQ_HANDLED;
+		}
+		wsa_res->codec = ptr_codec;
+	}
+	status = snd_soc_read(wsa_res->codec, WSA881X_INTR_STATUS);
+	/* Apply masking */
+	status &= ~wsa_res->irq_masks_cur;
+
+	for (i = 0; i < wsa_res->num_irqs; i++) {
+		if (status & BYTE_BIT_MASK(i)) {
+			mutex_lock(&wsa_res->nested_irq_lock);
+			handle_nested_irq(phyirq_to_virq(wsa_res, i));
+			mutex_unlock(&wsa_res->nested_irq_lock);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * wsa_free_irq() - to free an interrupt
+ * @irq: interrupt number.
+ * @data: pointer to wsa resource.
+ *
+ * To free already requested interrupt.
+ *
+ * Return: void.
+ */
+void wsa_free_irq(int irq, void *data)
+{
+	struct wsa_resource *wsa_res = data;
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return;
+	}
+	free_irq(phyirq_to_virq(wsa_res, irq), data);
+}
+
+/**
+ * wsa_enable_irq() - to enable an interrupt
+ * @wsa_res: pointer to wsa resource.
+ * @irq: interrupt number.
+ *
+ * This function is to enable an interrupt.
+ *
+ * Return: void.
+ */
+void wsa_enable_irq(struct wsa_resource *wsa_res, int irq)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return;
+	}
+	enable_irq(phyirq_to_virq(wsa_res, irq));
+}
+
+/**
+ * wsa_disable_irq() - to disable an interrupt
+ * @wsa_res: pointer to wsa resource.
+ * @irq: interrupt number.
+ *
+ * To disable an interrupt without waiting for executing
+ * handler to complete.
+ *
+ * Return: void.
+ */
+void wsa_disable_irq(struct wsa_resource *wsa_res, int irq)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return;
+	}
+	disable_irq_nosync(phyirq_to_virq(wsa_res, irq));
+}
+
+/**
+ * wsa_disable_irq_sync() - to disable an interrupt
+ * @wsa_res: pointer to wsa resource.
+ * @irq: interrupt number.
+ *
+ * To disable an interrupt, wait for executing IRQ
+ * handler to complete.
+ *
+ * Return: void.
+ */
+void wsa_disable_irq_sync(
+			struct wsa_resource *wsa_res, int irq)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return;
+	}
+	disable_irq(phyirq_to_virq(wsa_res, irq));
+}
+
+static int wsa_irq_setup_downstream_irq(struct wsa_resource *wsa_res)
+{
+	int irq, virq, ret;
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: enter\n", __func__);
+
+	for (irq = 0; irq < wsa_res->num_irqs; irq++) {
+		/* Map OF irq */
+		virq = wsa_map_irq(wsa_res, irq);
+		pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
+		if (virq == NO_IRQ) {
+			pr_err("%s, No interrupt specifier for irq %d\n",
+			       __func__, irq);
+			return NO_IRQ;
+		}
+
+		ret = irq_set_chip_data(virq, wsa_res);
+		if (ret) {
+			pr_err("%s: Failed to configure irq %d (%d)\n",
+			       __func__, irq, ret);
+			return ret;
+		}
+
+		if (wsa_res->irq_level_high[irq])
+			irq_set_chip_and_handler(virq, &wsa_irq_chip,
+						 handle_level_irq);
+		else
+			irq_set_chip_and_handler(virq, &wsa_irq_chip,
+						 handle_edge_irq);
+
+		irq_set_nested_thread(virq, 1);
+	}
+
+	pr_debug("%s: leave\n", __func__);
+
+	return 0;
+}
+
+static int wsa_irq_init(struct wsa_resource *wsa_res)
+{
+	int i, ret;
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return -EINVAL;
+	}
+	mutex_init(&wsa_res->irq_lock);
+	mutex_init(&wsa_res->nested_irq_lock);
+
+	wsa_res->irq = wsa_irq_get_upstream_irq(wsa_res);
+	if (!wsa_res->irq) {
+		pr_warn("%s: irq driver is not yet initialized\n", __func__);
+		mutex_destroy(&wsa_res->irq_lock);
+		mutex_destroy(&wsa_res->nested_irq_lock);
+		return -EPROBE_DEFER;
+	}
+	pr_debug("%s: probed irq %d\n", __func__, wsa_res->irq);
+
+	/* Setup downstream IRQs */
+	ret = wsa_irq_setup_downstream_irq(wsa_res);
+	if (ret) {
+		pr_err("%s: Failed to setup downstream IRQ\n", __func__);
+		goto fail_irq_init;
+	}
+
+	/* mask all the interrupts */
+	for (i = 0; i < wsa_res->num_irqs; i++) {
+		wsa_res->irq_masks_cur |= BYTE_BIT_MASK(i);
+		wsa_res->irq_masks_cache |= BYTE_BIT_MASK(i);
+	}
+
+	ret = request_threaded_irq(wsa_res->irq, NULL, wsa_irq_thread,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   "wsa", wsa_res);
+	if (ret != 0) {
+		dev_err(wsa_res->dev, "Failed to request IRQ %d: %d\n",
+			wsa_res->irq, ret);
+	} else {
+		ret = enable_irq_wake(wsa_res->irq);
+		if (ret) {
+			dev_err(wsa_res->dev,
+				"Failed to set wake interrupt on IRQ %d: %d\n",
+				wsa_res->irq, ret);
+			free_irq(wsa_res->irq, wsa_res);
+		}
+	}
+
+	if (ret)
+		goto fail_irq_init;
+
+	return ret;
+
+fail_irq_init:
+	dev_err(wsa_res->dev,
+			"%s: Failed to init wsa irq\n", __func__);
+	wsa_irq_put_upstream_irq(wsa_res);
+	mutex_destroy(&wsa_res->irq_lock);
+	mutex_destroy(&wsa_res->nested_irq_lock);
+	return ret;
+}
+
+/**
+ * wsa_request_irq() - to request/register an interrupt
+ * @wsa_res: pointer to wsa_resource.
+ * @irq: interrupt number.
+ * @handler: interrupt handler function pointer.
+ * @name: interrupt name.
+ * @data: device info.
+ *
+ * Convert physical irq to virtual irq and then
+ * reguest for threaded handler.
+ *
+ * Return: Retuns success/failure.
+ */
+int wsa_request_irq(struct wsa_resource *wsa_res,
+			int irq, irq_handler_t handler,
+			const char *name, void *data)
+{
+	int virq;
+
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return -EINVAL;
+	}
+	virq = phyirq_to_virq(wsa_res, irq);
+
+	/*
+	 * ARM needs us to explicitly flag the IRQ as valid
+	 * and will set them noprobe when we do so.
+	 */
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+	set_irq_flags(virq, IRQF_VALID);
+#else
+	set_irq_noprobe(virq);
+#endif
+
+	return request_threaded_irq(virq, NULL, handler, IRQF_TRIGGER_RISING,
+				    name, data);
+}
+
+/**
+ * wsa_irq_exit() - to disable/clear interrupt/resources
+ * @wsa_res: pointer to wsa_resource
+ *
+ * Disable and free the interrupts and then release resources.
+ *
+ * Return: void.
+ */
+void wsa_irq_exit(struct wsa_resource *wsa_res)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return;
+	}
+	dev_dbg(wsa_res->dev, "%s: Cleaning up irq %d\n", __func__,
+		wsa_res->irq);
+
+	if (wsa_res->irq) {
+		disable_irq_wake(wsa_res->irq);
+		free_irq(wsa_res->irq, wsa_res);
+		/* Release parent's of node */
+		wsa_irq_put_upstream_irq(wsa_res);
+	}
+	mutex_destroy(&wsa_res->irq_lock);
+	mutex_destroy(&wsa_res->nested_irq_lock);
+}
+
+static int phyirq_to_virq(struct wsa_resource *wsa_res, int offset)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return -EINVAL;
+	}
+	return irq_linear_revmap(wsa_res->domain, offset);
+}
+
+static int virq_to_phyirq(struct wsa_resource *wsa_res, int virq)
+{
+	struct irq_data *irq_data = irq_get_irq_data(virq);
+
+	if (unlikely(!irq_data)) {
+		pr_err("%s: irq_data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	return irq_data->hwirq;
+}
+
+static unsigned int wsa_irq_get_upstream_irq(struct wsa_resource *wsa_res)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return -EINVAL;
+	}
+	return wsa_res->irq;
+}
+
+static void wsa_irq_put_upstream_irq(struct wsa_resource *wsa_res)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return;
+	}
+	/* Hold parent's of node */
+	of_node_put(wsa_res->dev->of_node);
+}
+
+static int wsa_map_irq(struct wsa_resource *wsa_res, int irq)
+{
+	if (wsa_res == NULL) {
+		pr_err("%s: wsa_res is NULL\n", __func__);
+		return -EINVAL;
+	}
+	return of_irq_to_resource(wsa_res->dev->of_node, irq, NULL);
+}
+
+static int wsa_irq_probe(struct platform_device *pdev)
+{
+	int irq;
+	struct wsa_resource *wsa_res = NULL;
+	int ret = -EINVAL;
+
+	irq = platform_get_irq_byname(pdev, "wsa-int");
+	if (irq < 0) {
+		dev_err(&pdev->dev, "%s: Couldn't find wsa-int node(%d)\n",
+			__func__, irq);
+		return -EINVAL;
+	}
+	pr_debug("%s: node %s\n", __func__, pdev->name);
+	wsa_res = kzalloc(sizeof(*wsa_res), GFP_KERNEL);
+	if (!wsa_res) {
+		pr_err("%s: could not allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+	/*
+	 * wsa interrupt controller supports N to N irq mapping with
+	 * single cell binding with irq numbers(offsets) only.
+	 * Use irq_domain_simple_ops that has irq_domain_simple_map and
+	 * irq_domain_xlate_onetwocell.
+	 */
+	wsa_res->dev = &pdev->dev;
+	wsa_res->domain = irq_domain_add_linear(wsa_res->dev->of_node,
+			WSA_MAX_NUM_IRQS, &irq_domain_simple_ops,
+			wsa_res);
+	if (!wsa_res->domain) {
+		dev_err(&pdev->dev, "%s: domain is NULL\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+	wsa_res->dev = &pdev->dev;
+
+	dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
+	wsa_res->irq = irq;
+	wsa_res->num_irq_regs = 1;
+	wsa_res->num_irqs = WSA_NUM_IRQS;
+	ret = wsa_irq_init(wsa_res);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "%s: failed to do irq init %d\n",
+				__func__, ret);
+		goto err;
+	}
+
+	return ret;
+err:
+	kfree(wsa_res);
+	return ret;
+}
+
+static int wsa_irq_remove(struct platform_device *pdev)
+{
+	struct irq_domain *domain;
+	struct wsa_resource *data;
+
+	domain = irq_find_host(pdev->dev.of_node);
+	if (unlikely(!domain)) {
+		pr_err("%s: domain is NULL\n", __func__);
+		return -EINVAL;
+	}
+	data = (struct wsa_resource *)domain->host_data;
+	data->irq = 0;
+
+	return 0;
+}
+
+static const struct of_device_id of_match[] = {
+	{ .compatible = "qcom,wsa-irq" },
+	{ }
+};
+
+static struct platform_driver wsa_irq_driver = {
+	.probe = wsa_irq_probe,
+	.remove = wsa_irq_remove,
+	.driver = {
+		.name = "wsa_intc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(of_match),
+	},
+};
+
+static int wsa_irq_drv_init(void)
+{
+	return platform_driver_register(&wsa_irq_driver);
+}
+subsys_initcall(wsa_irq_drv_init);
+
+static void wsa_irq_drv_exit(void)
+{
+	platform_driver_unregister(&wsa_irq_driver);
+}
+module_exit(wsa_irq_drv_exit);
+
+MODULE_DESCRIPTION("WSA881x IRQ driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wsa881x-irq.h b/asoc/codecs/wsa881x-irq.h
new file mode 100644
index 0000000..270eb91
--- /dev/null
+++ b/asoc/codecs/wsa881x-irq.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WSA881X_IRQ_H__
+#define __WSA881X_IRQ_H__
+
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <sound/soc.h>
+
+/**
+ * enum wsa_interrupts - wsa interrupt number
+ * @WSA_INT_SAF2WAR:	Temp irq interrupt, from safe state to warning state.
+ * @WSA_INT_WAR2SAF:	Temp irq interrupt, from warning state to safe state.
+ * @WSA_INT_DISABLE:	Disable Temp sensor interrupts.
+ * @WSA_INT_OCP:	OCP interrupt.
+ * @WSA_INT_CLIP:	CLIP detect interrupt.
+ * @WSA_NUM_IRQS:	MAX Interrupt number.
+ *
+ * WSA IRQ Interrupt numbers.
+ */
+enum wsa_interrupts {
+	WSA_INT_SAF2WAR = 0,
+	WSA_INT_WAR2SAF,
+	WSA_INT_DISABLE,
+	WSA_INT_OCP,
+	WSA_INT_CLIP,
+	WSA_NUM_IRQS,
+};
+
+/**
+ * struct wsa_resource - the basic wsa_resource structure
+ * @irq_lock:	lock used by irq_chip functions.
+ * @nested_irq_lock: lock used while handling nested interrupts.
+ * @irq:	interrupt number.
+ * @irq_masks_cur: current mask value to be written to mask registers.
+ * @irq_masks_cache: cached mask value.
+ * @num_irqs: number of supported interrupts.
+ * @num_irq_regs: number of irq registers.
+ * @parent:	parent pointer.
+ * @dev:	device pointer.
+ * @domain:	irq domain pointer.
+ * codec:	codec pointer.
+ *
+ * Contains required members used in wsa irq driver.
+ */
+
+struct wsa_resource {
+	struct mutex irq_lock;
+	struct mutex nested_irq_lock;
+	unsigned int irq;
+	u8 irq_masks_cur;
+	u8 irq_masks_cache;
+	bool irq_level_high[8];
+	int num_irqs;
+	int num_irq_regs;
+	void *parent;
+	struct device *dev;
+	struct irq_domain *domain;
+	struct snd_soc_codec *codec;
+};
+
+void wsa_set_codec(struct snd_soc_codec *codec);
+void wsa_free_irq(int irq, void *data);
+void wsa_enable_irq(struct wsa_resource *wsa_res, int irq);
+void wsa_disable_irq(struct wsa_resource *wsa_res, int irq);
+void wsa_disable_irq_sync(struct wsa_resource *wsa_res, int irq);
+int wsa_request_irq(struct wsa_resource *wsa_res,
+			int irq, irq_handler_t handler,
+			const char *name, void *data);
+
+void wsa_irq_exit(struct wsa_resource *wsa_res);
+
+#endif /* __WSA881X_IRQ_H__ */
diff --git a/asoc/codecs/wsa881x-registers-analog.h b/asoc/codecs/wsa881x-registers-analog.h
new file mode 100644
index 0000000..a5ebf8e
--- /dev/null
+++ b/asoc/codecs/wsa881x-registers-analog.h
@@ -0,0 +1,206 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef WSA881X_REGISTERS_H
+#define WSA881X_REGISTERS_H
+
+#define WSA881X_DIGITAL_BASE	0x0000
+#define WSA881X_ANALOG_BASE	0x0100
+
+#define WSA881X_CHIP_ID0                        (WSA881X_DIGITAL_BASE+0x0000)
+#define WSA881X_CHIP_ID1			(WSA881X_DIGITAL_BASE+0x0001)
+#define WSA881X_CHIP_ID2			(WSA881X_DIGITAL_BASE+0x0002)
+#define WSA881X_CHIP_ID3			(WSA881X_DIGITAL_BASE+0x0003)
+#define WSA881X_BUS_ID				(WSA881X_DIGITAL_BASE+0x0004)
+#define WSA881X_CDC_RST_CTL			(WSA881X_DIGITAL_BASE+0x0005)
+#define WSA881X_CDC_TOP_CLK_CTL			(WSA881X_DIGITAL_BASE+0x0006)
+#define WSA881X_CDC_ANA_CLK_CTL			(WSA881X_DIGITAL_BASE+0x0007)
+#define WSA881X_CDC_DIG_CLK_CTL			(WSA881X_DIGITAL_BASE+0x0008)
+#define WSA881X_CLOCK_CONFIG			(WSA881X_DIGITAL_BASE+0x0009)
+#define WSA881X_ANA_CTL				(WSA881X_DIGITAL_BASE+0x000A)
+#define WSA881X_SWR_RESET_EN			(WSA881X_DIGITAL_BASE+0x000B)
+#define WSA881X_RESET_CTL			(WSA881X_DIGITAL_BASE+0x000C)
+#define WSA881X_TADC_VALUE_CTL			(WSA881X_DIGITAL_BASE+0x000F)
+#define WSA881X_TEMP_DETECT_CTL			(WSA881X_DIGITAL_BASE+0x0010)
+#define WSA881X_TEMP_MSB			(WSA881X_DIGITAL_BASE+0x0011)
+#define WSA881X_TEMP_LSB			(WSA881X_DIGITAL_BASE+0x0012)
+#define WSA881X_TEMP_CONFIG0			(WSA881X_DIGITAL_BASE+0x0013)
+#define WSA881X_TEMP_CONFIG1			(WSA881X_DIGITAL_BASE+0x0014)
+#define WSA881X_CDC_CLIP_CTL			(WSA881X_DIGITAL_BASE+0x0015)
+#define WSA881X_SDM_PDM9_LSB			(WSA881X_DIGITAL_BASE+0x0016)
+#define WSA881X_SDM_PDM9_MSB			(WSA881X_DIGITAL_BASE+0x0017)
+#define WSA881X_CDC_RX_CTL			(WSA881X_DIGITAL_BASE+0x0018)
+#define WSA881X_DEM_BYPASS_DATA0		(WSA881X_DIGITAL_BASE+0x0019)
+#define WSA881X_DEM_BYPASS_DATA1		(WSA881X_DIGITAL_BASE+0x001A)
+#define WSA881X_DEM_BYPASS_DATA2		(WSA881X_DIGITAL_BASE+0x001B)
+#define WSA881X_DEM_BYPASS_DATA3		(WSA881X_DIGITAL_BASE+0x001C)
+#define WSA881X_OTP_CTRL0			(WSA881X_DIGITAL_BASE+0x001D)
+#define WSA881X_OTP_CTRL1			(WSA881X_DIGITAL_BASE+0x001E)
+#define WSA881X_HDRIVE_CTL_GROUP1		(WSA881X_DIGITAL_BASE+0x001F)
+#define WSA881X_INTR_MODE			(WSA881X_DIGITAL_BASE+0x0020)
+#define WSA881X_INTR_MASK			(WSA881X_DIGITAL_BASE+0x0021)
+#define WSA881X_INTR_STATUS			(WSA881X_DIGITAL_BASE+0x0022)
+#define WSA881X_INTR_CLEAR			(WSA881X_DIGITAL_BASE+0x0023)
+#define WSA881X_INTR_LEVEL			(WSA881X_DIGITAL_BASE+0x0024)
+#define WSA881X_INTR_SET			(WSA881X_DIGITAL_BASE+0x0025)
+#define WSA881X_INTR_TEST			(WSA881X_DIGITAL_BASE+0x0026)
+#define WSA881X_PDM_TEST_MODE			(WSA881X_DIGITAL_BASE+0x0030)
+#define WSA881X_ATE_TEST_MODE			(WSA881X_DIGITAL_BASE+0x0031)
+#define WSA881X_PIN_CTL_MODE			(WSA881X_DIGITAL_BASE+0x0032)
+#define WSA881X_PIN_CTL_OE			(WSA881X_DIGITAL_BASE+0x0033)
+#define WSA881X_PIN_WDATA_IOPAD			(WSA881X_DIGITAL_BASE+0x0034)
+#define WSA881X_PIN_STATUS			(WSA881X_DIGITAL_BASE+0x0035)
+#define WSA881X_DIG_DEBUG_MODE			(WSA881X_DIGITAL_BASE+0x0037)
+#define WSA881X_DIG_DEBUG_SEL			(WSA881X_DIGITAL_BASE+0x0038)
+#define WSA881X_DIG_DEBUG_EN			(WSA881X_DIGITAL_BASE+0x0039)
+#define WSA881X_SWR_HM_TEST1			(WSA881X_DIGITAL_BASE+0x003B)
+#define WSA881X_SWR_HM_TEST2			(WSA881X_DIGITAL_BASE+0x003C)
+#define WSA881X_TEMP_DETECT_DBG_CTL		(WSA881X_DIGITAL_BASE+0x003D)
+#define WSA881X_TEMP_DEBUG_MSB			(WSA881X_DIGITAL_BASE+0x003E)
+#define WSA881X_TEMP_DEBUG_LSB			(WSA881X_DIGITAL_BASE+0x003F)
+#define WSA881X_SAMPLE_EDGE_SEL			(WSA881X_DIGITAL_BASE+0x0044)
+#define WSA881X_IOPAD_CTL			(WSA881X_DIGITAL_BASE+0x0045)
+#define WSA881X_SPARE_0				(WSA881X_DIGITAL_BASE+0x0050)
+#define WSA881X_SPARE_1				(WSA881X_DIGITAL_BASE+0x0051)
+#define WSA881X_SPARE_2				(WSA881X_DIGITAL_BASE+0x0052)
+#define WSA881X_OTP_REG_0			(WSA881X_DIGITAL_BASE+0x0080)
+#define WSA881X_OTP_REG_1			(WSA881X_DIGITAL_BASE+0x0081)
+#define WSA881X_OTP_REG_2			(WSA881X_DIGITAL_BASE+0x0082)
+#define WSA881X_OTP_REG_3			(WSA881X_DIGITAL_BASE+0x0083)
+#define WSA881X_OTP_REG_4			(WSA881X_DIGITAL_BASE+0x0084)
+#define WSA881X_OTP_REG_5			(WSA881X_DIGITAL_BASE+0x0085)
+#define WSA881X_OTP_REG_6			(WSA881X_DIGITAL_BASE+0x0086)
+#define WSA881X_OTP_REG_7			(WSA881X_DIGITAL_BASE+0x0087)
+#define WSA881X_OTP_REG_8			(WSA881X_DIGITAL_BASE+0x0088)
+#define WSA881X_OTP_REG_9			(WSA881X_DIGITAL_BASE+0x0089)
+#define WSA881X_OTP_REG_10			(WSA881X_DIGITAL_BASE+0x008A)
+#define WSA881X_OTP_REG_11			(WSA881X_DIGITAL_BASE+0x008B)
+#define WSA881X_OTP_REG_12			(WSA881X_DIGITAL_BASE+0x008C)
+#define WSA881X_OTP_REG_13			(WSA881X_DIGITAL_BASE+0x008D)
+#define WSA881X_OTP_REG_14			(WSA881X_DIGITAL_BASE+0x008E)
+#define WSA881X_OTP_REG_15			(WSA881X_DIGITAL_BASE+0x008F)
+#define WSA881X_OTP_REG_16			(WSA881X_DIGITAL_BASE+0x0090)
+#define WSA881X_OTP_REG_17			(WSA881X_DIGITAL_BASE+0x0091)
+#define WSA881X_OTP_REG_18			(WSA881X_DIGITAL_BASE+0x0092)
+#define WSA881X_OTP_REG_19			(WSA881X_DIGITAL_BASE+0x0093)
+#define WSA881X_OTP_REG_20			(WSA881X_DIGITAL_BASE+0x0094)
+#define WSA881X_OTP_REG_21			(WSA881X_DIGITAL_BASE+0x0095)
+#define WSA881X_OTP_REG_22			(WSA881X_DIGITAL_BASE+0x0096)
+#define WSA881X_OTP_REG_23			(WSA881X_DIGITAL_BASE+0x0097)
+#define WSA881X_OTP_REG_24			(WSA881X_DIGITAL_BASE+0x0098)
+#define WSA881X_OTP_REG_25			(WSA881X_DIGITAL_BASE+0x0099)
+#define WSA881X_OTP_REG_26			(WSA881X_DIGITAL_BASE+0x009A)
+#define WSA881X_OTP_REG_27			(WSA881X_DIGITAL_BASE+0x009B)
+#define WSA881X_OTP_REG_28			(WSA881X_DIGITAL_BASE+0x009C)
+#define WSA881X_OTP_REG_29			(WSA881X_DIGITAL_BASE+0x009D)
+#define WSA881X_OTP_REG_30			(WSA881X_DIGITAL_BASE+0x009E)
+#define WSA881X_OTP_REG_31			(WSA881X_DIGITAL_BASE+0x009F)
+#define WSA881X_OTP_REG_32			(WSA881X_DIGITAL_BASE+0x00A0)
+#define WSA881X_OTP_REG_33			(WSA881X_DIGITAL_BASE+0x00A1)
+#define WSA881X_OTP_REG_34			(WSA881X_DIGITAL_BASE+0x00A2)
+#define WSA881X_OTP_REG_35			(WSA881X_DIGITAL_BASE+0x00A3)
+#define WSA881X_OTP_REG_36			(WSA881X_DIGITAL_BASE+0x00A4)
+#define WSA881X_OTP_REG_37			(WSA881X_DIGITAL_BASE+0x00A5)
+#define WSA881X_OTP_REG_38			(WSA881X_DIGITAL_BASE+0x00A6)
+#define WSA881X_OTP_REG_39			(WSA881X_DIGITAL_BASE+0x00A7)
+#define WSA881X_OTP_REG_40			(WSA881X_DIGITAL_BASE+0x00A8)
+#define WSA881X_OTP_REG_41			(WSA881X_DIGITAL_BASE+0x00A9)
+#define WSA881X_OTP_REG_42			(WSA881X_DIGITAL_BASE+0x00AA)
+#define WSA881X_OTP_REG_43			(WSA881X_DIGITAL_BASE+0x00AB)
+#define WSA881X_OTP_REG_44			(WSA881X_DIGITAL_BASE+0x00AC)
+#define WSA881X_OTP_REG_45			(WSA881X_DIGITAL_BASE+0x00AD)
+#define WSA881X_OTP_REG_46			(WSA881X_DIGITAL_BASE+0x00AE)
+#define WSA881X_OTP_REG_47			(WSA881X_DIGITAL_BASE+0x00AF)
+#define WSA881X_OTP_REG_48			(WSA881X_DIGITAL_BASE+0x00B0)
+#define WSA881X_OTP_REG_49			(WSA881X_DIGITAL_BASE+0x00B1)
+#define WSA881X_OTP_REG_50			(WSA881X_DIGITAL_BASE+0x00B2)
+#define WSA881X_OTP_REG_51			(WSA881X_DIGITAL_BASE+0x00B3)
+#define WSA881X_OTP_REG_52			(WSA881X_DIGITAL_BASE+0x00B4)
+#define WSA881X_OTP_REG_53			(WSA881X_DIGITAL_BASE+0x00B5)
+#define WSA881X_OTP_REG_54			(WSA881X_DIGITAL_BASE+0x00B6)
+#define WSA881X_OTP_REG_55			(WSA881X_DIGITAL_BASE+0x00B7)
+#define WSA881X_OTP_REG_56			(WSA881X_DIGITAL_BASE+0x00B8)
+#define WSA881X_OTP_REG_57			(WSA881X_DIGITAL_BASE+0x00B9)
+#define WSA881X_OTP_REG_58			(WSA881X_DIGITAL_BASE+0x00BA)
+#define WSA881X_OTP_REG_59			(WSA881X_DIGITAL_BASE+0x00BB)
+#define WSA881X_OTP_REG_60			(WSA881X_DIGITAL_BASE+0x00BC)
+#define WSA881X_OTP_REG_61			(WSA881X_DIGITAL_BASE+0x00BD)
+#define WSA881X_OTP_REG_62			(WSA881X_DIGITAL_BASE+0x00BE)
+#define WSA881X_OTP_REG_63			(WSA881X_DIGITAL_BASE+0x00BF)
+/* Analog Register address space */
+#define WSA881X_BIAS_REF_CTRL			(WSA881X_ANALOG_BASE+0x0000)
+#define WSA881X_BIAS_TEST			(WSA881X_ANALOG_BASE+0x0001)
+#define WSA881X_BIAS_BIAS			(WSA881X_ANALOG_BASE+0x0002)
+#define WSA881X_TEMP_OP				(WSA881X_ANALOG_BASE+0x0003)
+#define WSA881X_TEMP_IREF_CTRL			(WSA881X_ANALOG_BASE+0x0004)
+#define WSA881X_TEMP_ISENS_CTRL			(WSA881X_ANALOG_BASE+0x0005)
+#define WSA881X_TEMP_CLK_CTRL			(WSA881X_ANALOG_BASE+0x0006)
+#define WSA881X_TEMP_TEST			(WSA881X_ANALOG_BASE+0x0007)
+#define WSA881X_TEMP_BIAS			(WSA881X_ANALOG_BASE+0x0008)
+#define WSA881X_TEMP_ADC_CTRL			(WSA881X_ANALOG_BASE+0x0009)
+#define WSA881X_TEMP_DOUT_MSB			(WSA881X_ANALOG_BASE+0x000A)
+#define WSA881X_TEMP_DOUT_LSB			(WSA881X_ANALOG_BASE+0x000B)
+#define WSA881X_ADC_EN_MODU_V			(WSA881X_ANALOG_BASE+0x0010)
+#define WSA881X_ADC_EN_MODU_I			(WSA881X_ANALOG_BASE+0x0011)
+#define WSA881X_ADC_EN_DET_TEST_V		(WSA881X_ANALOG_BASE+0x0012)
+#define WSA881X_ADC_EN_DET_TEST_I		(WSA881X_ANALOG_BASE+0x0013)
+#define WSA881X_ADC_SEL_IBIAS			(WSA881X_ANALOG_BASE+0x0014)
+#define WSA881X_ADC_EN_SEL_IBIAS		(WSA881X_ANALOG_BASE+0x0015)
+#define WSA881X_SPKR_DRV_EN			(WSA881X_ANALOG_BASE+0x001A)
+#define WSA881X_SPKR_DRV_GAIN			(WSA881X_ANALOG_BASE+0x001B)
+#define WSA881X_SPKR_DAC_CTL			(WSA881X_ANALOG_BASE+0x001C)
+#define WSA881X_SPKR_DRV_DBG			(WSA881X_ANALOG_BASE+0x001D)
+#define WSA881X_SPKR_PWRSTG_DBG			(WSA881X_ANALOG_BASE+0x001E)
+#define WSA881X_SPKR_OCP_CTL			(WSA881X_ANALOG_BASE+0x001F)
+#define WSA881X_SPKR_CLIP_CTL			(WSA881X_ANALOG_BASE+0x0020)
+#define WSA881X_SPKR_BBM_CTL			(WSA881X_ANALOG_BASE+0x0021)
+#define WSA881X_SPKR_MISC_CTL1			(WSA881X_ANALOG_BASE+0x0022)
+#define WSA881X_SPKR_MISC_CTL2			(WSA881X_ANALOG_BASE+0x0023)
+#define WSA881X_SPKR_BIAS_INT			(WSA881X_ANALOG_BASE+0x0024)
+#define WSA881X_SPKR_PA_INT			(WSA881X_ANALOG_BASE+0x0025)
+#define WSA881X_SPKR_BIAS_CAL			(WSA881X_ANALOG_BASE+0x0026)
+#define WSA881X_SPKR_BIAS_PSRR			(WSA881X_ANALOG_BASE+0x0027)
+#define WSA881X_SPKR_STATUS1			(WSA881X_ANALOG_BASE+0x0028)
+#define WSA881X_SPKR_STATUS2			(WSA881X_ANALOG_BASE+0x0029)
+#define WSA881X_BOOST_EN_CTL			(WSA881X_ANALOG_BASE+0x002A)
+#define WSA881X_BOOST_CURRENT_LIMIT		(WSA881X_ANALOG_BASE+0x002B)
+#define WSA881X_BOOST_PS_CTL			(WSA881X_ANALOG_BASE+0x002C)
+#define WSA881X_BOOST_PRESET_OUT1		(WSA881X_ANALOG_BASE+0x002D)
+#define WSA881X_BOOST_PRESET_OUT2		(WSA881X_ANALOG_BASE+0x002E)
+#define WSA881X_BOOST_FORCE_OUT			(WSA881X_ANALOG_BASE+0x002F)
+#define WSA881X_BOOST_LDO_PROG			(WSA881X_ANALOG_BASE+0x0030)
+#define WSA881X_BOOST_SLOPE_COMP_ISENSE_FB	(WSA881X_ANALOG_BASE+0x0031)
+#define WSA881X_BOOST_RON_CTL			(WSA881X_ANALOG_BASE+0x0032)
+#define WSA881X_BOOST_LOOP_STABILITY		(WSA881X_ANALOG_BASE+0x0033)
+#define WSA881X_BOOST_ZX_CTL			(WSA881X_ANALOG_BASE+0x0034)
+#define WSA881X_BOOST_START_CTL			(WSA881X_ANALOG_BASE+0x0035)
+#define WSA881X_BOOST_MISC1_CTL			(WSA881X_ANALOG_BASE+0x0036)
+#define WSA881X_BOOST_MISC2_CTL			(WSA881X_ANALOG_BASE+0x0037)
+#define WSA881X_BOOST_MISC3_CTL			(WSA881X_ANALOG_BASE+0x0038)
+#define WSA881X_BOOST_ATEST_CTL			(WSA881X_ANALOG_BASE+0x0039)
+#define WSA881X_SPKR_PROT_FE_GAIN		(WSA881X_ANALOG_BASE+0x003A)
+#define WSA881X_SPKR_PROT_FE_CM_LDO_SET		(WSA881X_ANALOG_BASE+0x003B)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1	(WSA881X_ANALOG_BASE+0x003C)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2	(WSA881X_ANALOG_BASE+0x003D)
+#define WSA881X_SPKR_PROT_ATEST1		(WSA881X_ANALOG_BASE+0x003E)
+#define WSA881X_SPKR_PROT_ATEST2		(WSA881X_ANALOG_BASE+0x003F)
+#define WSA881X_SPKR_PROT_FE_VSENSE_VCM		(WSA881X_ANALOG_BASE+0x0040)
+#define WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1	(WSA881X_ANALOG_BASE+0x0041)
+#define WSA881X_BONGO_RESRV_REG1		(WSA881X_ANALOG_BASE+0x0042)
+#define WSA881X_BONGO_RESRV_REG2		(WSA881X_ANALOG_BASE+0x0043)
+#define WSA881X_SPKR_PROT_SAR			(WSA881X_ANALOG_BASE+0x0044)
+#define WSA881X_SPKR_STATUS3			(WSA881X_ANALOG_BASE+0x0045)
+
+#define WSA881X_NUM_REGISTERS		(WSA881X_SPKR_STATUS3+1)
+#define WSA881X_MAX_REGISTER		(WSA881X_NUM_REGISTERS-1)
+#define WSA881X_CACHE_SIZE		WSA881X_NUM_REGISTERS
+#endif /* WSA881X_REGISTERS_H */
diff --git a/asoc/codecs/wsa881x-registers.h b/asoc/codecs/wsa881x-registers.h
new file mode 100644
index 0000000..825a5f0
--- /dev/null
+++ b/asoc/codecs/wsa881x-registers.h
@@ -0,0 +1,178 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef WSA881X_REGISTERS_H
+#define WSA881X_REGISTERS_H
+
+#define WSA881X_DIGITAL_BASE		0x3000
+#define WSA881X_ANALOG_BASE		0x3100
+
+/* Digital register address space */
+#define WSA881X_CHIP_ID0			(WSA881X_DIGITAL_BASE+0x0000)
+#define WSA881X_CHIP_ID1			(WSA881X_DIGITAL_BASE+0x0001)
+#define WSA881X_CHIP_ID2			(WSA881X_DIGITAL_BASE+0x0002)
+#define WSA881X_CHIP_ID3			(WSA881X_DIGITAL_BASE+0x0003)
+#define WSA881X_BUS_ID				(WSA881X_DIGITAL_BASE+0x0004)
+#define WSA881X_CDC_RST_CTL			(WSA881X_DIGITAL_BASE+0x0005)
+#define WSA881X_CDC_TOP_CLK_CTL			(WSA881X_DIGITAL_BASE+0x0006)
+#define WSA881X_CDC_ANA_CLK_CTL			(WSA881X_DIGITAL_BASE+0x0007)
+#define WSA881X_CDC_DIG_CLK_CTL			(WSA881X_DIGITAL_BASE+0x0008)
+#define WSA881X_CLOCK_CONFIG			(WSA881X_DIGITAL_BASE+0x0009)
+#define WSA881X_ANA_CTL				(WSA881X_DIGITAL_BASE+0x000A)
+#define WSA881X_SWR_RESET_EN			(WSA881X_DIGITAL_BASE+0x000B)
+#define WSA881X_RESET_CTL			(WSA881X_DIGITAL_BASE+0x000C)
+#define WSA881X_TADC_VALUE_CTL			(WSA881X_DIGITAL_BASE+0x000F)
+#define WSA881X_TEMP_DETECT_CTL			(WSA881X_DIGITAL_BASE+0x0010)
+#define WSA881X_TEMP_MSB			(WSA881X_DIGITAL_BASE+0x0011)
+#define WSA881X_TEMP_LSB			(WSA881X_DIGITAL_BASE+0x0012)
+#define WSA881X_TEMP_CONFIG0			(WSA881X_DIGITAL_BASE+0x0013)
+#define WSA881X_TEMP_CONFIG1			(WSA881X_DIGITAL_BASE+0x0014)
+#define WSA881X_CDC_CLIP_CTL			(WSA881X_DIGITAL_BASE+0x0015)
+#define WSA881X_SDM_PDM9_LSB			(WSA881X_DIGITAL_BASE+0x0016)
+#define WSA881X_SDM_PDM9_MSB			(WSA881X_DIGITAL_BASE+0x0017)
+#define WSA881X_CDC_RX_CTL			(WSA881X_DIGITAL_BASE+0x0018)
+#define WSA881X_DEM_BYPASS_DATA0		(WSA881X_DIGITAL_BASE+0x0019)
+#define WSA881X_DEM_BYPASS_DATA1		(WSA881X_DIGITAL_BASE+0x001A)
+#define WSA881X_DEM_BYPASS_DATA2		(WSA881X_DIGITAL_BASE+0x001B)
+#define WSA881X_DEM_BYPASS_DATA3		(WSA881X_DIGITAL_BASE+0x001C)
+#define WSA881X_OTP_CTRL0			(WSA881X_DIGITAL_BASE+0x001D)
+#define WSA881X_OTP_CTRL1			(WSA881X_DIGITAL_BASE+0x001E)
+#define WSA881X_HDRIVE_CTL_GROUP1		(WSA881X_DIGITAL_BASE+0x001F)
+#define WSA881X_INTR_MODE			(WSA881X_DIGITAL_BASE+0x0020)
+#define WSA881X_INTR_MASK			(WSA881X_DIGITAL_BASE+0x0021)
+#define WSA881X_INTR_STATUS			(WSA881X_DIGITAL_BASE+0x0022)
+#define WSA881X_INTR_CLEAR			(WSA881X_DIGITAL_BASE+0x0023)
+#define WSA881X_INTR_LEVEL			(WSA881X_DIGITAL_BASE+0x0024)
+#define WSA881X_INTR_SET			(WSA881X_DIGITAL_BASE+0x0025)
+#define WSA881X_INTR_TEST			(WSA881X_DIGITAL_BASE+0x0026)
+#define WSA881X_PDM_TEST_MODE			(WSA881X_DIGITAL_BASE+0x0030)
+#define WSA881X_ATE_TEST_MODE			(WSA881X_DIGITAL_BASE+0x0031)
+#define WSA881X_PIN_CTL_MODE			(WSA881X_DIGITAL_BASE+0x0032)
+#define WSA881X_PIN_CTL_OE			(WSA881X_DIGITAL_BASE+0x0033)
+#define WSA881X_PIN_WDATA_IOPAD			(WSA881X_DIGITAL_BASE+0x0034)
+#define WSA881X_PIN_STATUS			(WSA881X_DIGITAL_BASE+0x0035)
+#define WSA881X_DIG_DEBUG_MODE			(WSA881X_DIGITAL_BASE+0x0037)
+#define WSA881X_DIG_DEBUG_SEL			(WSA881X_DIGITAL_BASE+0x0038)
+#define WSA881X_DIG_DEBUG_EN			(WSA881X_DIGITAL_BASE+0x0039)
+#define WSA881X_SWR_HM_TEST1			(WSA881X_DIGITAL_BASE+0x003B)
+#define WSA881X_SWR_HM_TEST2			(WSA881X_DIGITAL_BASE+0x003C)
+#define WSA881X_TEMP_DETECT_DBG_CTL		(WSA881X_DIGITAL_BASE+0x003D)
+#define WSA881X_TEMP_DEBUG_MSB			(WSA881X_DIGITAL_BASE+0x003E)
+#define WSA881X_TEMP_DEBUG_LSB			(WSA881X_DIGITAL_BASE+0x003F)
+#define WSA881X_SAMPLE_EDGE_SEL			(WSA881X_DIGITAL_BASE+0x0044)
+#define WSA881X_IOPAD_CTL			(WSA881X_DIGITAL_BASE+0x0045)
+#define WSA881X_SPARE_0				(WSA881X_DIGITAL_BASE+0x0050)
+#define WSA881X_SPARE_1				(WSA881X_DIGITAL_BASE+0x0051)
+#define WSA881X_SPARE_2				(WSA881X_DIGITAL_BASE+0x0052)
+#define WSA881X_OTP_REG_0			(WSA881X_DIGITAL_BASE+0x0080)
+#define WSA881X_OTP_REG_1			(WSA881X_DIGITAL_BASE+0x0081)
+#define WSA881X_OTP_REG_2			(WSA881X_DIGITAL_BASE+0x0082)
+#define WSA881X_OTP_REG_3			(WSA881X_DIGITAL_BASE+0x0083)
+#define WSA881X_OTP_REG_4			(WSA881X_DIGITAL_BASE+0x0084)
+#define WSA881X_OTP_REG_5			(WSA881X_DIGITAL_BASE+0x0085)
+#define WSA881X_OTP_REG_6			(WSA881X_DIGITAL_BASE+0x0086)
+#define WSA881X_OTP_REG_7			(WSA881X_DIGITAL_BASE+0x0087)
+#define WSA881X_OTP_REG_8			(WSA881X_DIGITAL_BASE+0x0088)
+#define WSA881X_OTP_REG_9			(WSA881X_DIGITAL_BASE+0x0089)
+#define WSA881X_OTP_REG_10			(WSA881X_DIGITAL_BASE+0x008A)
+#define WSA881X_OTP_REG_11			(WSA881X_DIGITAL_BASE+0x008B)
+#define WSA881X_OTP_REG_12			(WSA881X_DIGITAL_BASE+0x008C)
+#define WSA881X_OTP_REG_13			(WSA881X_DIGITAL_BASE+0x008D)
+#define WSA881X_OTP_REG_14			(WSA881X_DIGITAL_BASE+0x008E)
+#define WSA881X_OTP_REG_15			(WSA881X_DIGITAL_BASE+0x008F)
+#define WSA881X_OTP_REG_16			(WSA881X_DIGITAL_BASE+0x0090)
+#define WSA881X_OTP_REG_17			(WSA881X_DIGITAL_BASE+0x0091)
+#define WSA881X_OTP_REG_18			(WSA881X_DIGITAL_BASE+0x0092)
+#define WSA881X_OTP_REG_19			(WSA881X_DIGITAL_BASE+0x0093)
+#define WSA881X_OTP_REG_20			(WSA881X_DIGITAL_BASE+0x0094)
+#define WSA881X_OTP_REG_21			(WSA881X_DIGITAL_BASE+0x0095)
+#define WSA881X_OTP_REG_22			(WSA881X_DIGITAL_BASE+0x0096)
+#define WSA881X_OTP_REG_23			(WSA881X_DIGITAL_BASE+0x0097)
+#define WSA881X_OTP_REG_24			(WSA881X_DIGITAL_BASE+0x0098)
+#define WSA881X_OTP_REG_25			(WSA881X_DIGITAL_BASE+0x0099)
+#define WSA881X_OTP_REG_26			(WSA881X_DIGITAL_BASE+0x009A)
+#define WSA881X_OTP_REG_27			(WSA881X_DIGITAL_BASE+0x009B)
+#define WSA881X_OTP_REG_28			(WSA881X_DIGITAL_BASE+0x009C)
+#define WSA881X_OTP_REG_29			(WSA881X_DIGITAL_BASE+0x009D)
+#define WSA881X_OTP_REG_30			(WSA881X_DIGITAL_BASE+0x009E)
+#define WSA881X_OTP_REG_31			(WSA881X_DIGITAL_BASE+0x009F)
+#define WSA881X_OTP_REG_63			(WSA881X_DIGITAL_BASE+0x00BF)
+
+/* Analog Register address space */
+#define WSA881X_BIAS_REF_CTRL			(WSA881X_ANALOG_BASE+0x0000)
+#define WSA881X_BIAS_TEST			(WSA881X_ANALOG_BASE+0x0001)
+#define WSA881X_BIAS_BIAS			(WSA881X_ANALOG_BASE+0x0002)
+#define WSA881X_TEMP_OP				(WSA881X_ANALOG_BASE+0x0003)
+#define WSA881X_TEMP_IREF_CTRL			(WSA881X_ANALOG_BASE+0x0004)
+#define WSA881X_TEMP_ISENS_CTRL			(WSA881X_ANALOG_BASE+0x0005)
+#define WSA881X_TEMP_CLK_CTRL			(WSA881X_ANALOG_BASE+0x0006)
+#define WSA881X_TEMP_TEST			(WSA881X_ANALOG_BASE+0x0007)
+#define WSA881X_TEMP_BIAS			(WSA881X_ANALOG_BASE+0x0008)
+#define WSA881X_TEMP_ADC_CTRL			(WSA881X_ANALOG_BASE+0x0009)
+#define WSA881X_TEMP_DOUT_MSB			(WSA881X_ANALOG_BASE+0x000A)
+#define WSA881X_TEMP_DOUT_LSB			(WSA881X_ANALOG_BASE+0x000B)
+#define WSA881X_ADC_EN_MODU_V			(WSA881X_ANALOG_BASE+0x0010)
+#define WSA881X_ADC_EN_MODU_I			(WSA881X_ANALOG_BASE+0x0011)
+#define WSA881X_ADC_EN_DET_TEST_V		(WSA881X_ANALOG_BASE+0x0012)
+#define WSA881X_ADC_EN_DET_TEST_I		(WSA881X_ANALOG_BASE+0x0013)
+#define WSA881X_ADC_SEL_IBIAS			(WSA881X_ANALOG_BASE+0x0014)
+#define WSA881X_ADC_EN_SEL_IBAIS		(WSA881X_ANALOG_BASE+0x0015)
+#define WSA881X_SPKR_DRV_EN			(WSA881X_ANALOG_BASE+0x001A)
+#define WSA881X_SPKR_DRV_GAIN			(WSA881X_ANALOG_BASE+0x001B)
+#define WSA881X_SPKR_DAC_CTL			(WSA881X_ANALOG_BASE+0x001C)
+#define WSA881X_SPKR_DRV_DBG			(WSA881X_ANALOG_BASE+0x001D)
+#define WSA881X_SPKR_PWRSTG_DBG			(WSA881X_ANALOG_BASE+0x001E)
+#define WSA881X_SPKR_OCP_CTL			(WSA881X_ANALOG_BASE+0x001F)
+#define WSA881X_SPKR_CLIP_CTL			(WSA881X_ANALOG_BASE+0x0020)
+#define WSA881X_SPKR_BBM_CTL			(WSA881X_ANALOG_BASE+0x0021)
+#define WSA881X_SPKR_MISC_CTL1			(WSA881X_ANALOG_BASE+0x0022)
+#define WSA881X_SPKR_MISC_CTL2			(WSA881X_ANALOG_BASE+0x0023)
+#define WSA881X_SPKR_BIAS_INT			(WSA881X_ANALOG_BASE+0x0024)
+#define WSA881X_SPKR_PA_INT			(WSA881X_ANALOG_BASE+0x0025)
+#define WSA881X_SPKR_BIAS_CAL			(WSA881X_ANALOG_BASE+0x0026)
+#define WSA881X_SPKR_BIAS_PSRR			(WSA881X_ANALOG_BASE+0x0027)
+#define WSA881X_SPKR_STATUS1			(WSA881X_ANALOG_BASE+0x0028)
+#define WSA881X_SPKR_STATUS2			(WSA881X_ANALOG_BASE+0x0029)
+#define WSA881X_BOOST_EN_CTL			(WSA881X_ANALOG_BASE+0x002A)
+#define WSA881X_BOOST_CURRENT_LIMIT		(WSA881X_ANALOG_BASE+0x002B)
+#define WSA881X_BOOST_PS_CTL			(WSA881X_ANALOG_BASE+0x002C)
+#define WSA881X_BOOST_PRESET_OUT1		(WSA881X_ANALOG_BASE+0x002D)
+#define WSA881X_BOOST_PRESET_OUT2		(WSA881X_ANALOG_BASE+0x002E)
+#define WSA881X_BOOST_FORCE_OUT			(WSA881X_ANALOG_BASE+0x002F)
+#define WSA881X_BOOST_LDO_PROG			(WSA881X_ANALOG_BASE+0x0030)
+#define WSA881X_BOOST_SLOPE_COMP_ISENSE_FB	(WSA881X_ANALOG_BASE+0x0031)
+#define WSA881X_BOOST_RON_CTL			(WSA881X_ANALOG_BASE+0x0032)
+#define WSA881X_BOOST_LOOP_STABILITY		(WSA881X_ANALOG_BASE+0x0033)
+#define WSA881X_BOOST_ZX_CTL			(WSA881X_ANALOG_BASE+0x0034)
+#define WSA881X_BOOST_START_CTL			(WSA881X_ANALOG_BASE+0x0035)
+#define WSA881X_BOOST_MISC1_CTL			(WSA881X_ANALOG_BASE+0x0036)
+#define WSA881X_BOOST_MISC2_CTL			(WSA881X_ANALOG_BASE+0x0037)
+#define WSA881X_BOOST_MISC3_CTL			(WSA881X_ANALOG_BASE+0x0038)
+#define WSA881X_BOOST_ATEST_CTL			(WSA881X_ANALOG_BASE+0x0039)
+#define WSA881X_SPKR_PROT_FE_GAIN		(WSA881X_ANALOG_BASE+0x003A)
+#define WSA881X_SPKR_PROT_FE_CM_LDO_SET		(WSA881X_ANALOG_BASE+0x003B)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1	(WSA881X_ANALOG_BASE+0x003C)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2	(WSA881X_ANALOG_BASE+0x003D)
+#define WSA881X_SPKR_PROT_ATEST1		(WSA881X_ANALOG_BASE+0x003E)
+#define WSA881X_SPKR_PROT_ATEST2		(WSA881X_ANALOG_BASE+0x003F)
+#define WSA881X_SPKR_PROT_FE_VSENSE_VCM		(WSA881X_ANALOG_BASE+0x0040)
+#define WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1	(WSA881X_ANALOG_BASE+0x0041)
+#define WSA881X_BONGO_RESRV_REG1		(WSA881X_ANALOG_BASE+0x0042)
+#define WSA881X_BONGO_RESRV_REG2		(WSA881X_ANALOG_BASE+0x0043)
+#define WSA881X_SPKR_PROT_SAR			(WSA881X_ANALOG_BASE+0x0044)
+#define WSA881X_SPKR_STATUS3			(WSA881X_ANALOG_BASE+0x0045)
+
+#define WSA881X_NUM_REGISTERS			(WSA881X_SPKR_STATUS3+1)
+#define WSA881X_MAX_REGISTER			(WSA881X_NUM_REGISTERS-1)
+#define WSA881X_CACHE_SIZE			WSA881X_NUM_REGISTERS
+
+#endif /* WSA881X_REGISTERS_H */
diff --git a/asoc/codecs/wsa881x-regmap-analog.c b/asoc/codecs/wsa881x-regmap-analog.c
new file mode 100644
index 0000000..2bc3c9e
--- /dev/null
+++ b/asoc/codecs/wsa881x-regmap-analog.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa881x-registers-analog.h"
+#include "wsa881x-analog.h"
+
+struct reg_default wsa881x_ana_reg_defaults[] = {
+	{WSA881X_CHIP_ID0, 0x00},
+	{WSA881X_CHIP_ID1, 0x00},
+	{WSA881X_CHIP_ID2, 0x00},
+	{WSA881X_CHIP_ID3, 0x02},
+	{WSA881X_BUS_ID, 0x00},
+	{WSA881X_CDC_RST_CTL, 0x00},
+	{WSA881X_CDC_TOP_CLK_CTL, 0x03},
+	{WSA881X_CDC_ANA_CLK_CTL, 0x00},
+	{WSA881X_CDC_DIG_CLK_CTL, 0x00},
+	{WSA881X_CLOCK_CONFIG, 0x00},
+	{WSA881X_ANA_CTL, 0x08},
+	{WSA881X_SWR_RESET_EN, 0x00},
+	{WSA881X_TEMP_DETECT_CTL, 0x01},
+	{WSA881X_TEMP_MSB, 0x00},
+	{WSA881X_TEMP_LSB, 0x00},
+	{WSA881X_TEMP_CONFIG0, 0x00},
+	{WSA881X_TEMP_CONFIG1, 0x00},
+	{WSA881X_CDC_CLIP_CTL, 0x03},
+	{WSA881X_SDM_PDM9_LSB, 0x00},
+	{WSA881X_SDM_PDM9_MSB, 0x00},
+	{WSA881X_CDC_RX_CTL, 0x7E},
+	{WSA881X_DEM_BYPASS_DATA0, 0x00},
+	{WSA881X_DEM_BYPASS_DATA1, 0x00},
+	{WSA881X_DEM_BYPASS_DATA2, 0x00},
+	{WSA881X_DEM_BYPASS_DATA3, 0x00},
+	{WSA881X_OTP_CTRL0, 0x00},
+	{WSA881X_OTP_CTRL1, 0x00},
+	{WSA881X_HDRIVE_CTL_GROUP1, 0x00},
+	{WSA881X_INTR_MODE, 0x00},
+	{WSA881X_INTR_MASK, 0x1F},
+	{WSA881X_INTR_STATUS, 0x00},
+	{WSA881X_INTR_CLEAR, 0x00},
+	{WSA881X_INTR_LEVEL, 0x00},
+	{WSA881X_INTR_SET, 0x00},
+	{WSA881X_INTR_TEST, 0x00},
+	{WSA881X_PDM_TEST_MODE, 0x00},
+	{WSA881X_ATE_TEST_MODE, 0x00},
+	{WSA881X_PIN_CTL_MODE, 0x00},
+	{WSA881X_PIN_CTL_OE, 0x00},
+	{WSA881X_PIN_WDATA_IOPAD, 0x00},
+	{WSA881X_PIN_STATUS, 0x00},
+	{WSA881X_DIG_DEBUG_MODE, 0x00},
+	{WSA881X_DIG_DEBUG_SEL, 0x00},
+	{WSA881X_DIG_DEBUG_EN, 0x00},
+	{WSA881X_SWR_HM_TEST1, 0x08},
+	{WSA881X_SWR_HM_TEST2, 0x00},
+	{WSA881X_TEMP_DETECT_DBG_CTL, 0x00},
+	{WSA881X_TEMP_DEBUG_MSB, 0x00},
+	{WSA881X_TEMP_DEBUG_LSB, 0x00},
+	{WSA881X_SAMPLE_EDGE_SEL, 0x0C},
+	{WSA881X_SPARE_0, 0x00},
+	{WSA881X_SPARE_1, 0x00},
+	{WSA881X_SPARE_2, 0x00},
+	{WSA881X_OTP_REG_0, 0x01},
+	{WSA881X_OTP_REG_1, 0xFF},
+	{WSA881X_OTP_REG_2, 0xC0},
+	{WSA881X_OTP_REG_3, 0xFF},
+	{WSA881X_OTP_REG_4, 0xC0},
+	{WSA881X_OTP_REG_5, 0xFF},
+	{WSA881X_OTP_REG_6, 0xFF},
+	{WSA881X_OTP_REG_7, 0xFF},
+	{WSA881X_OTP_REG_8, 0xFF},
+	{WSA881X_OTP_REG_9, 0xFF},
+	{WSA881X_OTP_REG_10, 0xFF},
+	{WSA881X_OTP_REG_11, 0xFF},
+	{WSA881X_OTP_REG_12, 0xFF},
+	{WSA881X_OTP_REG_13, 0xFF},
+	{WSA881X_OTP_REG_14, 0xFF},
+	{WSA881X_OTP_REG_15, 0xFF},
+	{WSA881X_OTP_REG_16, 0xFF},
+	{WSA881X_OTP_REG_17, 0xFF},
+	{WSA881X_OTP_REG_18, 0xFF},
+	{WSA881X_OTP_REG_19, 0xFF},
+	{WSA881X_OTP_REG_20, 0xFF},
+	{WSA881X_OTP_REG_21, 0xFF},
+	{WSA881X_OTP_REG_22, 0xFF},
+	{WSA881X_OTP_REG_23, 0xFF},
+	{WSA881X_OTP_REG_24, 0x03},
+	{WSA881X_OTP_REG_25, 0x01},
+	{WSA881X_OTP_REG_26, 0x03},
+	{WSA881X_OTP_REG_27, 0x11},
+	{WSA881X_OTP_REG_28, 0xFF},
+	{WSA881X_OTP_REG_29, 0xFF},
+	{WSA881X_OTP_REG_30, 0xFF},
+	{WSA881X_OTP_REG_31, 0xFF},
+	{WSA881X_OTP_REG_63, 0x40},
+	/* WSA881x Analog registers */
+	{WSA881X_BIAS_REF_CTRL, 0x6C},
+	{WSA881X_BIAS_TEST, 0x16},
+	{WSA881X_BIAS_BIAS, 0xF0},
+	{WSA881X_TEMP_OP, 0x00},
+	{WSA881X_TEMP_IREF_CTRL, 0x56},
+	{WSA881X_TEMP_ISENS_CTRL, 0x47},
+	{WSA881X_TEMP_CLK_CTRL, 0x87},
+	{WSA881X_TEMP_TEST, 0x00},
+	{WSA881X_TEMP_BIAS, 0x51},
+	{WSA881X_TEMP_ADC_CTRL, 0x00},
+	{WSA881X_TEMP_DOUT_MSB, 0x00},
+	{WSA881X_TEMP_DOUT_LSB, 0x00},
+	{WSA881X_ADC_EN_MODU_V, 0x00},
+	{WSA881X_ADC_EN_MODU_I, 0x00},
+	{WSA881X_ADC_EN_DET_TEST_V, 0x00},
+	{WSA881X_ADC_EN_DET_TEST_I, 0x00},
+	{WSA881X_ADC_SEL_IBIAS, 0x25},
+	{WSA881X_ADC_EN_SEL_IBIAS, 0x10},
+	{WSA881X_SPKR_DRV_EN, 0x74},
+	{WSA881X_SPKR_DRV_GAIN, 0x01},
+	{WSA881X_SPKR_DAC_CTL, 0x40},
+	{WSA881X_SPKR_DRV_DBG, 0x15},
+	{WSA881X_SPKR_PWRSTG_DBG, 0x00},
+	{WSA881X_SPKR_OCP_CTL, 0xD4},
+	{WSA881X_SPKR_CLIP_CTL, 0x90},
+	{WSA881X_SPKR_BBM_CTL, 0x00},
+	{WSA881X_SPKR_MISC_CTL1, 0x80},
+	{WSA881X_SPKR_MISC_CTL2, 0x00},
+	{WSA881X_SPKR_BIAS_INT, 0x56},
+	{WSA881X_SPKR_PA_INT, 0x54},
+	{WSA881X_SPKR_BIAS_CAL, 0xAC},
+	{WSA881X_SPKR_BIAS_PSRR, 0x54},
+	{WSA881X_SPKR_STATUS1, 0x00},
+	{WSA881X_SPKR_STATUS2, 0x00},
+	{WSA881X_BOOST_EN_CTL, 0x18},
+	{WSA881X_BOOST_CURRENT_LIMIT, 0x7A},
+	{WSA881X_BOOST_PS_CTL, 0xC0},
+	{WSA881X_BOOST_PRESET_OUT1, 0x77},
+	{WSA881X_BOOST_PRESET_OUT2, 0x70},
+	{WSA881X_BOOST_FORCE_OUT, 0x0E},
+	{WSA881X_BOOST_LDO_PROG, 0x16},
+	{WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x71},
+	{WSA881X_BOOST_RON_CTL, 0x0F},
+	{WSA881X_BOOST_LOOP_STABILITY, 0xAD},
+	{WSA881X_BOOST_ZX_CTL, 0x34},
+	{WSA881X_BOOST_START_CTL, 0x23},
+	{WSA881X_BOOST_MISC1_CTL, 0x80},
+	{WSA881X_BOOST_MISC2_CTL, 0x00},
+	{WSA881X_BOOST_MISC3_CTL, 0x00},
+	{WSA881X_BOOST_ATEST_CTL, 0x00},
+	{WSA881X_SPKR_PROT_FE_GAIN, 0x46},
+	{WSA881X_SPKR_PROT_FE_CM_LDO_SET, 0x3B},
+	{WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1, 0x8D},
+	{WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2, 0x8D},
+	{WSA881X_SPKR_PROT_ATEST1, 0x01},
+	{WSA881X_SPKR_PROT_ATEST2, 0x00},
+	{WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x8D},
+	{WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1, 0x4D},
+	{WSA881X_BONGO_RESRV_REG1, 0x00},
+	{WSA881X_BONGO_RESRV_REG2, 0x00},
+	{WSA881X_SPKR_PROT_SAR, 0x00},
+	{WSA881X_SPKR_STATUS3, 0x00},
+};
+
+struct reg_default wsa881x_ana_reg_defaults_0[] = {
+	{WSA881X_CHIP_ID0, 0x00},
+	{WSA881X_CHIP_ID1, 0x00},
+	{WSA881X_CHIP_ID2, 0x00},
+	{WSA881X_CHIP_ID3, 0x02},
+	{WSA881X_BUS_ID, 0x00},
+	{WSA881X_CDC_RST_CTL, 0x00},
+	{WSA881X_CDC_TOP_CLK_CTL, 0x03},
+	{WSA881X_CDC_ANA_CLK_CTL, 0x00},
+	{WSA881X_CDC_DIG_CLK_CTL, 0x00},
+	{WSA881X_CLOCK_CONFIG, 0x00},
+	{WSA881X_ANA_CTL, 0x08},
+	{WSA881X_SWR_RESET_EN, 0x00},
+	{WSA881X_TEMP_DETECT_CTL, 0x01},
+	{WSA881X_TEMP_MSB, 0x00},
+	{WSA881X_TEMP_LSB, 0x00},
+	{WSA881X_TEMP_CONFIG0, 0x00},
+	{WSA881X_TEMP_CONFIG1, 0x00},
+	{WSA881X_CDC_CLIP_CTL, 0x03},
+	{WSA881X_SDM_PDM9_LSB, 0x00},
+	{WSA881X_SDM_PDM9_MSB, 0x00},
+	{WSA881X_CDC_RX_CTL, 0x7E},
+	{WSA881X_DEM_BYPASS_DATA0, 0x00},
+	{WSA881X_DEM_BYPASS_DATA1, 0x00},
+	{WSA881X_DEM_BYPASS_DATA2, 0x00},
+	{WSA881X_DEM_BYPASS_DATA3, 0x00},
+	{WSA881X_OTP_CTRL0, 0x00},
+	{WSA881X_OTP_CTRL1, 0x00},
+	{WSA881X_HDRIVE_CTL_GROUP1, 0x00},
+	{WSA881X_INTR_MODE, 0x00},
+	{WSA881X_INTR_MASK, 0x1F},
+	{WSA881X_INTR_STATUS, 0x00},
+	{WSA881X_INTR_CLEAR, 0x00},
+	{WSA881X_INTR_LEVEL, 0x00},
+	{WSA881X_INTR_SET, 0x00},
+	{WSA881X_INTR_TEST, 0x00},
+	{WSA881X_PDM_TEST_MODE, 0x00},
+	{WSA881X_ATE_TEST_MODE, 0x00},
+	{WSA881X_PIN_CTL_MODE, 0x00},
+	{WSA881X_PIN_CTL_OE, 0x00},
+	{WSA881X_PIN_WDATA_IOPAD, 0x00},
+	{WSA881X_PIN_STATUS, 0x00},
+	{WSA881X_DIG_DEBUG_MODE, 0x00},
+	{WSA881X_DIG_DEBUG_SEL, 0x00},
+	{WSA881X_DIG_DEBUG_EN, 0x00},
+	{WSA881X_SWR_HM_TEST1, 0x08},
+	{WSA881X_SWR_HM_TEST2, 0x00},
+	{WSA881X_TEMP_DETECT_DBG_CTL, 0x00},
+	{WSA881X_TEMP_DEBUG_MSB, 0x00},
+	{WSA881X_TEMP_DEBUG_LSB, 0x00},
+	{WSA881X_SAMPLE_EDGE_SEL, 0x0C},
+	{WSA881X_SPARE_0, 0x00},
+	{WSA881X_SPARE_1, 0x00},
+	{WSA881X_SPARE_2, 0x00},
+	{WSA881X_OTP_REG_0, 0x01},
+	{WSA881X_OTP_REG_1, 0xFF},
+	{WSA881X_OTP_REG_2, 0xC0},
+	{WSA881X_OTP_REG_3, 0xFF},
+	{WSA881X_OTP_REG_4, 0xC0},
+	{WSA881X_OTP_REG_5, 0xFF},
+	{WSA881X_OTP_REG_6, 0xFF},
+	{WSA881X_OTP_REG_7, 0xFF},
+	{WSA881X_OTP_REG_8, 0xFF},
+	{WSA881X_OTP_REG_9, 0xFF},
+	{WSA881X_OTP_REG_10, 0xFF},
+	{WSA881X_OTP_REG_11, 0xFF},
+	{WSA881X_OTP_REG_12, 0xFF},
+	{WSA881X_OTP_REG_13, 0xFF},
+	{WSA881X_OTP_REG_14, 0xFF},
+	{WSA881X_OTP_REG_15, 0xFF},
+	{WSA881X_OTP_REG_16, 0xFF},
+	{WSA881X_OTP_REG_17, 0xFF},
+	{WSA881X_OTP_REG_18, 0xFF},
+	{WSA881X_OTP_REG_19, 0xFF},
+	{WSA881X_OTP_REG_20, 0xFF},
+	{WSA881X_OTP_REG_21, 0xFF},
+	{WSA881X_OTP_REG_22, 0xFF},
+	{WSA881X_OTP_REG_23, 0xFF},
+	{WSA881X_OTP_REG_24, 0x03},
+	{WSA881X_OTP_REG_25, 0x01},
+	{WSA881X_OTP_REG_26, 0x03},
+	{WSA881X_OTP_REG_27, 0x11},
+	{WSA881X_OTP_REG_28, 0xFF},
+	{WSA881X_OTP_REG_29, 0xFF},
+	{WSA881X_OTP_REG_30, 0xFF},
+	{WSA881X_OTP_REG_31, 0xFF},
+	{WSA881X_OTP_REG_63, 0x40},
+};
+
+struct reg_default wsa881x_ana_reg_defaults_1[] = {
+	{WSA881X_BIAS_REF_CTRL - WSA881X_ANALOG_BASE, 0x6C},
+	{WSA881X_BIAS_TEST - WSA881X_ANALOG_BASE, 0x16},
+	{WSA881X_BIAS_BIAS - WSA881X_ANALOG_BASE, 0xF0},
+	{WSA881X_TEMP_OP - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_TEMP_IREF_CTRL - WSA881X_ANALOG_BASE, 0x56},
+	{WSA881X_TEMP_ISENS_CTRL - WSA881X_ANALOG_BASE, 0x47},
+	{WSA881X_TEMP_CLK_CTRL - WSA881X_ANALOG_BASE, 0x87},
+	{WSA881X_TEMP_TEST - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_TEMP_BIAS - WSA881X_ANALOG_BASE, 0x51},
+	{WSA881X_TEMP_ADC_CTRL - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_TEMP_DOUT_MSB - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_TEMP_DOUT_LSB - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_ADC_EN_MODU_V - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_ADC_EN_MODU_I - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_ADC_EN_DET_TEST_V - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_ADC_EN_DET_TEST_I - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_ADC_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x25},
+	{WSA881X_ADC_EN_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x10},
+	{WSA881X_SPKR_DRV_EN - WSA881X_ANALOG_BASE, 0x74},
+	{WSA881X_SPKR_DRV_GAIN - WSA881X_ANALOG_BASE, 0x01},
+	{WSA881X_SPKR_DAC_CTL - WSA881X_ANALOG_BASE, 0x40},
+	{WSA881X_SPKR_DRV_DBG - WSA881X_ANALOG_BASE, 0x15},
+	{WSA881X_SPKR_PWRSTG_DBG - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_OCP_CTL - WSA881X_ANALOG_BASE, 0xD4},
+	{WSA881X_SPKR_CLIP_CTL - WSA881X_ANALOG_BASE, 0x90},
+	{WSA881X_SPKR_BBM_CTL - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_MISC_CTL1 - WSA881X_ANALOG_BASE, 0x80},
+	{WSA881X_SPKR_MISC_CTL2 - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_BIAS_INT - WSA881X_ANALOG_BASE, 0x56},
+	{WSA881X_SPKR_PA_INT - WSA881X_ANALOG_BASE, 0x54},
+	{WSA881X_SPKR_BIAS_CAL - WSA881X_ANALOG_BASE, 0xAC},
+	{WSA881X_SPKR_BIAS_PSRR - WSA881X_ANALOG_BASE, 0x54},
+	{WSA881X_SPKR_STATUS1 - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_STATUS2 - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_BOOST_EN_CTL - WSA881X_ANALOG_BASE, 0x18},
+	{WSA881X_BOOST_CURRENT_LIMIT - WSA881X_ANALOG_BASE, 0x7A},
+	{WSA881X_BOOST_PS_CTL - WSA881X_ANALOG_BASE, 0xC0},
+	{WSA881X_BOOST_PRESET_OUT1 - WSA881X_ANALOG_BASE, 0x77},
+	{WSA881X_BOOST_PRESET_OUT2 - WSA881X_ANALOG_BASE, 0x70},
+	{WSA881X_BOOST_FORCE_OUT - WSA881X_ANALOG_BASE, 0x0E},
+	{WSA881X_BOOST_LDO_PROG - WSA881X_ANALOG_BASE, 0x16},
+	{WSA881X_BOOST_SLOPE_COMP_ISENSE_FB - WSA881X_ANALOG_BASE, 0x71},
+	{WSA881X_BOOST_RON_CTL - WSA881X_ANALOG_BASE, 0x0F},
+	{WSA881X_BOOST_LOOP_STABILITY - WSA881X_ANALOG_BASE, 0xAD},
+	{WSA881X_BOOST_ZX_CTL - WSA881X_ANALOG_BASE, 0x34},
+	{WSA881X_BOOST_START_CTL - WSA881X_ANALOG_BASE, 0x23},
+	{WSA881X_BOOST_MISC1_CTL - WSA881X_ANALOG_BASE, 0x80},
+	{WSA881X_BOOST_MISC2_CTL - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_BOOST_MISC3_CTL - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_BOOST_ATEST_CTL - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_PROT_FE_GAIN - WSA881X_ANALOG_BASE, 0x46},
+	{WSA881X_SPKR_PROT_FE_CM_LDO_SET - WSA881X_ANALOG_BASE, 0x3B},
+	{WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1 - WSA881X_ANALOG_BASE, 0x8D},
+	{WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2 - WSA881X_ANALOG_BASE, 0x8D},
+	{WSA881X_SPKR_PROT_ATEST1 - WSA881X_ANALOG_BASE, 0x01},
+	{WSA881X_SPKR_PROT_ATEST2 - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_PROT_FE_VSENSE_VCM - WSA881X_ANALOG_BASE, 0x8D},
+	{WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1 - WSA881X_ANALOG_BASE, 0x4D},
+	{WSA881X_BONGO_RESRV_REG1 - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_BONGO_RESRV_REG2 - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_PROT_SAR - WSA881X_ANALOG_BASE, 0x00},
+	{WSA881X_SPKR_STATUS3 - WSA881X_ANALOG_BASE, 0x00},
+};
+
+struct reg_default wsa881x_rev_2_0_dig[] = {
+	{WSA881X_RESET_CTL, 0x00},
+	{WSA881X_TADC_VALUE_CTL, 0x01},
+	{WSA881X_INTR_MASK, 0x1B},
+	{WSA881X_IOPAD_CTL, 0x00},
+	{WSA881X_OTP_REG_28, 0x3F},
+	{WSA881X_OTP_REG_29, 0x3F},
+	{WSA881X_OTP_REG_30, 0x01},
+	{WSA881X_OTP_REG_31, 0x01},
+};
+
+struct reg_default wsa881x_rev_2_0_ana[] = {
+	{WSA881X_TEMP_ADC_CTRL, 0x03},
+	{WSA881X_ADC_SEL_IBIAS, 0x45},
+	{WSA881X_SPKR_DRV_GAIN, 0xC1},
+	{WSA881X_SPKR_DAC_CTL, 0x42},
+	{WSA881X_SPKR_BBM_CTL, 0x02},
+	{WSA881X_SPKR_MISC_CTL1, 0x40},
+	{WSA881X_SPKR_MISC_CTL2, 0x07},
+	{WSA881X_SPKR_BIAS_INT, 0x5F},
+	{WSA881X_SPKR_BIAS_PSRR, 0x44},
+	{WSA881X_BOOST_PS_CTL, 0xA0},
+	{WSA881X_BOOST_PRESET_OUT1, 0xB7},
+	{WSA881X_BOOST_LOOP_STABILITY, 0x8D},
+	{WSA881X_SPKR_PROT_ATEST2, 0x02},
+	{WSA881X_BONGO_RESRV_REG1, 0x5E},
+	{WSA881X_BONGO_RESRV_REG2, 0x07},
+};
+
+struct reg_default wsa881x_rev_2_0_regmap_ana[] = {
+	{WSA881X_TEMP_ADC_CTRL - WSA881X_ANALOG_BASE, 0x03},
+	{WSA881X_ADC_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x45},
+	{WSA881X_SPKR_DRV_GAIN - WSA881X_ANALOG_BASE, 0xC1},
+	{WSA881X_SPKR_DAC_CTL - WSA881X_ANALOG_BASE, 0x42},
+	{WSA881X_SPKR_BBM_CTL - WSA881X_ANALOG_BASE, 0x02},
+	{WSA881X_SPKR_MISC_CTL1 - WSA881X_ANALOG_BASE, 0x40},
+	{WSA881X_SPKR_MISC_CTL2 - WSA881X_ANALOG_BASE, 0x07},
+	{WSA881X_SPKR_BIAS_INT - WSA881X_ANALOG_BASE, 0x5F},
+	{WSA881X_SPKR_BIAS_PSRR - WSA881X_ANALOG_BASE, 0x44},
+	{WSA881X_BOOST_PS_CTL - WSA881X_ANALOG_BASE, 0xA0},
+	{WSA881X_BOOST_PRESET_OUT1 - WSA881X_ANALOG_BASE, 0xB7},
+	{WSA881X_BOOST_LOOP_STABILITY - WSA881X_ANALOG_BASE, 0x8D},
+	{WSA881X_SPKR_PROT_ATEST2 - WSA881X_ANALOG_BASE, 0x02},
+	{WSA881X_BONGO_RESRV_REG1 - WSA881X_ANALOG_BASE, 0x5E},
+	{WSA881X_BONGO_RESRV_REG2 - WSA881X_ANALOG_BASE, 0x07},
+};
+
+/**
+ * wsa881x_update_reg_defaults_2_0 - update default values of regs for v2.0
+ *
+ * WSA881x v2.0 has different default values for certain analog and digital
+ * registers compared to v1.x. Therefore, update the values of these registers
+ * with the values from tables defined above for v2.0.
+ */
+void wsa881x_update_reg_defaults_2_0(void)
+{
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(wsa881x_rev_2_0_dig); i++) {
+		for (j = 0; j < ARRAY_SIZE(wsa881x_ana_reg_defaults); j++)
+			if (wsa881x_ana_reg_defaults[j].reg ==
+						wsa881x_rev_2_0_dig[i].reg)
+				wsa881x_ana_reg_defaults[j].def =
+						wsa881x_rev_2_0_dig[i].def;
+	}
+	for (i = 0; i < ARRAY_SIZE(wsa881x_rev_2_0_ana); i++) {
+		for (j = 0; j < ARRAY_SIZE(wsa881x_ana_reg_defaults); j++)
+			if (wsa881x_ana_reg_defaults[j].reg ==
+						wsa881x_rev_2_0_ana[i].reg)
+				wsa881x_ana_reg_defaults[j].def =
+						wsa881x_rev_2_0_ana[i].def;
+	}
+}
+EXPORT_SYMBOL(wsa881x_update_reg_defaults_2_0);
+
+/**
+ * wsa881x_update_regmap_2_0 - update regmap framework with new tables
+ * @regmap: pointer to WSA881x regmap structure
+ * @flag: indicates digital or analog WSA881x slave
+ *
+ * WSA881x v2.0 has some new registers for both analog and digital slaves.
+ * Update the regmap framework with all the new registers.
+ */
+void wsa881x_update_regmap_2_0(struct regmap *regmap, int flag)
+{
+	u16 ret = 0;
+
+	switch (flag) {
+	case WSA881X_DIGITAL_SLAVE:
+		ret = regmap_register_patch(regmap, wsa881x_rev_2_0_dig,
+					ARRAY_SIZE(wsa881x_rev_2_0_dig));
+		break;
+	case WSA881X_ANALOG_SLAVE:
+		ret = regmap_register_patch(regmap, wsa881x_rev_2_0_ana,
+					ARRAY_SIZE(wsa881x_rev_2_0_ana));
+		break;
+	default:
+		pr_debug("%s: unknown version", __func__);
+		ret = -EINVAL;
+		break;
+	}
+	if (ret)
+		pr_err("%s: Failed to update regmap defaults ret= %d\n",
+			__func__, ret);
+}
+EXPORT_SYMBOL(wsa881x_update_regmap_2_0);
+
+static bool wsa881x_readable_register(struct device *dev, unsigned int reg)
+{
+	return wsa881x_ana_reg_readable[reg];
+}
+
+static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WSA881X_CHIP_ID0:
+	case WSA881X_CHIP_ID1:
+	case WSA881X_CHIP_ID2:
+	case WSA881X_CHIP_ID3:
+	case WSA881X_BUS_ID:
+	case WSA881X_TEMP_MSB:
+	case WSA881X_TEMP_LSB:
+	case WSA881X_SDM_PDM9_LSB:
+	case WSA881X_SDM_PDM9_MSB:
+	case WSA881X_OTP_REG_0:
+	case WSA881X_OTP_REG_1:
+	case WSA881X_OTP_REG_2:
+	case WSA881X_OTP_REG_3:
+	case WSA881X_OTP_REG_4:
+	case WSA881X_OTP_REG_5:
+	case WSA881X_OTP_REG_31:
+	case WSA881X_TEMP_DOUT_MSB:
+	case WSA881X_TEMP_DOUT_LSB:
+	case WSA881X_TEMP_OP:
+	case WSA881X_OTP_CTRL1:
+	case WSA881X_INTR_STATUS:
+	case WSA881X_ATE_TEST_MODE:
+	case WSA881X_PIN_STATUS:
+	case WSA881X_SWR_HM_TEST2:
+	case WSA881X_SPKR_STATUS1:
+	case WSA881X_SPKR_STATUS2:
+	case WSA881X_SPKR_STATUS3:
+	case WSA881X_SPKR_PROT_SAR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct regmap_config wsa881x_ana_regmap_config[] = {
+{
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_NONE,
+	.reg_defaults = wsa881x_ana_reg_defaults_0,
+	.num_reg_defaults = ARRAY_SIZE(wsa881x_ana_reg_defaults_0),
+	.max_register = WSA881X_MAX_REGISTER,
+	.volatile_reg = wsa881x_volatile_register,
+	.readable_reg = wsa881x_readable_register,
+	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian = REGMAP_ENDIAN_NATIVE,
+},
+{
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_NONE,
+	.reg_defaults = wsa881x_ana_reg_defaults_1,
+	.num_reg_defaults = ARRAY_SIZE(wsa881x_ana_reg_defaults_1),
+	.max_register = WSA881X_MAX_REGISTER,
+	.volatile_reg = wsa881x_volatile_register,
+	.readable_reg = wsa881x_readable_register,
+	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian = REGMAP_ENDIAN_NATIVE,
+}
+};
diff --git a/asoc/codecs/wsa881x-regmap.c b/asoc/codecs/wsa881x-regmap.c
new file mode 100644
index 0000000..63bbbfa
--- /dev/null
+++ b/asoc/codecs/wsa881x-regmap.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa881x-registers.h"
+#include "wsa881x.h"
+
+/*
+ * Default register reset values that are common across different versions
+ * are defined here. If a register reset value is changed based on version
+ * then remove it from this structure and add it in version specific
+ * structures.
+ */
+static struct reg_default wsa881x_defaults[] = {
+	{WSA881X_CHIP_ID0, 0x00},
+	{WSA881X_CHIP_ID1, 0x00},
+	{WSA881X_CHIP_ID2, 0x00},
+	{WSA881X_CHIP_ID3, 0x02},
+	{WSA881X_BUS_ID, 0x00},
+	{WSA881X_CDC_RST_CTL, 0x00},
+	{WSA881X_CDC_TOP_CLK_CTL, 0x03},
+	{WSA881X_CDC_ANA_CLK_CTL, 0x00},
+	{WSA881X_CDC_DIG_CLK_CTL, 0x00},
+	{WSA881X_CLOCK_CONFIG, 0x00},
+	{WSA881X_ANA_CTL, 0x08},
+	{WSA881X_SWR_RESET_EN, 0x00},
+	{WSA881X_TEMP_DETECT_CTL, 0x01},
+	{WSA881X_TEMP_MSB, 0x00},
+	{WSA881X_TEMP_LSB, 0x00},
+	{WSA881X_TEMP_CONFIG0, 0x00},
+	{WSA881X_TEMP_CONFIG1, 0x00},
+	{WSA881X_CDC_CLIP_CTL, 0x03},
+	{WSA881X_SDM_PDM9_LSB, 0x00},
+	{WSA881X_SDM_PDM9_MSB, 0x00},
+	{WSA881X_CDC_RX_CTL, 0x7E},
+	{WSA881X_DEM_BYPASS_DATA0, 0x00},
+	{WSA881X_DEM_BYPASS_DATA1, 0x00},
+	{WSA881X_DEM_BYPASS_DATA2, 0x00},
+	{WSA881X_DEM_BYPASS_DATA3, 0x00},
+	{WSA881X_OTP_CTRL0, 0x00},
+	{WSA881X_OTP_CTRL1, 0x00},
+	{WSA881X_HDRIVE_CTL_GROUP1, 0x00},
+	{WSA881X_INTR_MODE, 0x00},
+	{WSA881X_INTR_STATUS, 0x00},
+	{WSA881X_INTR_CLEAR, 0x00},
+	{WSA881X_INTR_LEVEL, 0x00},
+	{WSA881X_INTR_SET, 0x00},
+	{WSA881X_INTR_TEST, 0x00},
+	{WSA881X_PDM_TEST_MODE, 0x00},
+	{WSA881X_ATE_TEST_MODE, 0x00},
+	{WSA881X_PIN_CTL_MODE, 0x00},
+	{WSA881X_PIN_CTL_OE, 0x00},
+	{WSA881X_PIN_WDATA_IOPAD, 0x00},
+	{WSA881X_PIN_STATUS, 0x00},
+	{WSA881X_DIG_DEBUG_MODE, 0x00},
+	{WSA881X_DIG_DEBUG_SEL, 0x00},
+	{WSA881X_DIG_DEBUG_EN, 0x00},
+	{WSA881X_SWR_HM_TEST1, 0x08},
+	{WSA881X_SWR_HM_TEST2, 0x00},
+	{WSA881X_TEMP_DETECT_DBG_CTL, 0x00},
+	{WSA881X_TEMP_DEBUG_MSB, 0x00},
+	{WSA881X_TEMP_DEBUG_LSB, 0x00},
+	{WSA881X_SAMPLE_EDGE_SEL, 0x0C},
+	{WSA881X_SPARE_0, 0x00},
+	{WSA881X_SPARE_1, 0x00},
+	{WSA881X_SPARE_2, 0x00},
+	{WSA881X_OTP_REG_0, 0x01},
+	{WSA881X_OTP_REG_1, 0xFF},
+	{WSA881X_OTP_REG_2, 0xC0},
+	{WSA881X_OTP_REG_3, 0xFF},
+	{WSA881X_OTP_REG_4, 0xC0},
+	{WSA881X_OTP_REG_5, 0xFF},
+	{WSA881X_OTP_REG_6, 0xFF},
+	{WSA881X_OTP_REG_7, 0xFF},
+	{WSA881X_OTP_REG_8, 0xFF},
+	{WSA881X_OTP_REG_9, 0xFF},
+	{WSA881X_OTP_REG_10, 0xFF},
+	{WSA881X_OTP_REG_11, 0xFF},
+	{WSA881X_OTP_REG_12, 0xFF},
+	{WSA881X_OTP_REG_13, 0xFF},
+	{WSA881X_OTP_REG_14, 0xFF},
+	{WSA881X_OTP_REG_15, 0xFF},
+	{WSA881X_OTP_REG_16, 0xFF},
+	{WSA881X_OTP_REG_17, 0xFF},
+	{WSA881X_OTP_REG_18, 0xFF},
+	{WSA881X_OTP_REG_19, 0xFF},
+	{WSA881X_OTP_REG_20, 0xFF},
+	{WSA881X_OTP_REG_21, 0xFF},
+	{WSA881X_OTP_REG_22, 0xFF},
+	{WSA881X_OTP_REG_23, 0xFF},
+	{WSA881X_OTP_REG_24, 0x03},
+	{WSA881X_OTP_REG_25, 0x01},
+	{WSA881X_OTP_REG_26, 0x03},
+	{WSA881X_OTP_REG_27, 0x11},
+	{WSA881X_OTP_REG_63, 0x40},
+	/* WSA881x Analog registers */
+	{WSA881X_BIAS_REF_CTRL, 0x6C},
+	{WSA881X_BIAS_TEST, 0x16},
+	{WSA881X_BIAS_BIAS, 0xF0},
+	{WSA881X_TEMP_OP, 0x00},
+	{WSA881X_TEMP_IREF_CTRL, 0x56},
+	{WSA881X_TEMP_ISENS_CTRL, 0x47},
+	{WSA881X_TEMP_CLK_CTRL, 0x87},
+	{WSA881X_TEMP_TEST, 0x00},
+	{WSA881X_TEMP_BIAS, 0x51},
+	{WSA881X_TEMP_DOUT_MSB, 0x00},
+	{WSA881X_TEMP_DOUT_LSB, 0x00},
+	{WSA881X_ADC_EN_MODU_V, 0x00},
+	{WSA881X_ADC_EN_MODU_I, 0x00},
+	{WSA881X_ADC_EN_DET_TEST_V, 0x00},
+	{WSA881X_ADC_EN_DET_TEST_I, 0x00},
+	{WSA881X_ADC_EN_SEL_IBAIS, 0x10},
+	{WSA881X_SPKR_DRV_EN, 0x74},
+	{WSA881X_SPKR_DRV_DBG, 0x15},
+	{WSA881X_SPKR_PWRSTG_DBG, 0x00},
+	{WSA881X_SPKR_OCP_CTL, 0xD4},
+	{WSA881X_SPKR_CLIP_CTL, 0x90},
+	{WSA881X_SPKR_PA_INT, 0x54},
+	{WSA881X_SPKR_BIAS_CAL, 0xAC},
+	{WSA881X_SPKR_STATUS1, 0x00},
+	{WSA881X_SPKR_STATUS2, 0x00},
+	{WSA881X_BOOST_EN_CTL, 0x18},
+	{WSA881X_BOOST_CURRENT_LIMIT, 0x7A},
+	{WSA881X_BOOST_PRESET_OUT2, 0x70},
+	{WSA881X_BOOST_FORCE_OUT, 0x0E},
+	{WSA881X_BOOST_LDO_PROG, 0x16},
+	{WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x71},
+	{WSA881X_BOOST_RON_CTL, 0x0F},
+	{WSA881X_BOOST_ZX_CTL, 0x34},
+	{WSA881X_BOOST_START_CTL, 0x23},
+	{WSA881X_BOOST_MISC1_CTL, 0x80},
+	{WSA881X_BOOST_MISC2_CTL, 0x00},
+	{WSA881X_BOOST_MISC3_CTL, 0x00},
+	{WSA881X_BOOST_ATEST_CTL, 0x00},
+	{WSA881X_SPKR_PROT_FE_GAIN, 0x46},
+	{WSA881X_SPKR_PROT_FE_CM_LDO_SET, 0x3B},
+	{WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1, 0x8D},
+	{WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2, 0x8D},
+	{WSA881X_SPKR_PROT_ATEST1, 0x01},
+	{WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x8D},
+	{WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1, 0x4D},
+	{WSA881X_SPKR_PROT_SAR, 0x00},
+	{WSA881X_SPKR_STATUS3, 0x00},
+};
+
+/* Default register reset values for WSA881x rev 2.0 */
+static struct reg_sequence wsa881x_rev_2_0[] = {
+	{WSA881X_RESET_CTL, 0x00, 0x00},
+	{WSA881X_TADC_VALUE_CTL, 0x01, 0x00},
+	{WSA881X_INTR_MASK, 0x1B, 0x00},
+	{WSA881X_IOPAD_CTL, 0x00, 0x00},
+	{WSA881X_OTP_REG_28, 0x3F, 0x00},
+	{WSA881X_OTP_REG_29, 0x3F, 0x00},
+	{WSA881X_OTP_REG_30, 0x01, 0x00},
+	{WSA881X_OTP_REG_31, 0x01, 0x00},
+	{WSA881X_TEMP_ADC_CTRL, 0x03, 0x00},
+	{WSA881X_ADC_SEL_IBIAS, 0x45, 0x00},
+	{WSA881X_SPKR_DRV_GAIN, 0xC1, 0x00},
+	{WSA881X_SPKR_DAC_CTL, 0x42, 0x00},
+	{WSA881X_SPKR_BBM_CTL, 0x02, 0x00},
+	{WSA881X_SPKR_MISC_CTL1, 0x40, 0x00},
+	{WSA881X_SPKR_MISC_CTL2, 0x07, 0x00},
+	{WSA881X_SPKR_BIAS_INT, 0x5F, 0x00},
+	{WSA881X_SPKR_BIAS_PSRR, 0x44, 0x00},
+	{WSA881X_BOOST_PS_CTL, 0xA0, 0x00},
+	{WSA881X_BOOST_PRESET_OUT1, 0xB7, 0x00},
+	{WSA881X_BOOST_LOOP_STABILITY, 0x8D, 0x00},
+	{WSA881X_SPKR_PROT_ATEST2, 0x02, 0x00},
+	{WSA881X_BONGO_RESRV_REG1, 0x5E, 0x00},
+	{WSA881X_BONGO_RESRV_REG2, 0x07, 0x00},
+};
+
+/*
+ * wsa881x_regmap_defaults - update regmap default register values
+ * @regmap: pointer to regmap structure
+ * @version: wsa881x version id
+ *
+ * Update regmap default register values based on version id
+ *
+ */
+void wsa881x_regmap_defaults(struct regmap *regmap, u8 version)
+{
+	u16 ret = 0;
+
+	if (!regmap) {
+		pr_debug("%s: regmap structure is NULL\n", __func__);
+		return;
+	}
+
+	regcache_cache_only(regmap, true);
+	ret = regmap_multi_reg_write(regmap, wsa881x_rev_2_0,
+				     ARRAY_SIZE(wsa881x_rev_2_0));
+	regcache_cache_only(regmap, false);
+
+	if (ret)
+		pr_debug("%s: Failed to update regmap defaults ret= %d\n",
+			 __func__, ret);
+}
+EXPORT_SYMBOL(wsa881x_regmap_defaults);
+
+static bool wsa881x_readable_register(struct device *dev, unsigned int reg)
+{
+	return wsa881x_reg_readable[reg];
+}
+
+static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WSA881X_CHIP_ID0:
+	case WSA881X_CHIP_ID1:
+	case WSA881X_CHIP_ID2:
+	case WSA881X_CHIP_ID3:
+	case WSA881X_BUS_ID:
+	case WSA881X_TEMP_MSB:
+	case WSA881X_TEMP_LSB:
+	case WSA881X_SDM_PDM9_LSB:
+	case WSA881X_SDM_PDM9_MSB:
+	case WSA881X_OTP_CTRL1:
+	case WSA881X_INTR_STATUS:
+	case WSA881X_ATE_TEST_MODE:
+	case WSA881X_PIN_STATUS:
+	case WSA881X_SWR_HM_TEST2:
+	case WSA881X_SPKR_STATUS1:
+	case WSA881X_SPKR_STATUS2:
+	case WSA881X_SPKR_STATUS3:
+	case WSA881X_OTP_REG_0:
+	case WSA881X_OTP_REG_1:
+	case WSA881X_OTP_REG_2:
+	case WSA881X_OTP_REG_3:
+	case WSA881X_OTP_REG_4:
+	case WSA881X_OTP_REG_5:
+	case WSA881X_OTP_REG_31:
+	case WSA881X_TEMP_DOUT_MSB:
+	case WSA881X_TEMP_DOUT_LSB:
+	case WSA881X_TEMP_OP:
+	case WSA881X_SPKR_PROT_SAR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct regmap_config wsa881x_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wsa881x_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wsa881x_defaults),
+	.max_register = WSA881X_MAX_REGISTER,
+	.volatile_reg = wsa881x_volatile_register,
+	.readable_reg = wsa881x_readable_register,
+	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian = REGMAP_ENDIAN_NATIVE,
+	.can_multi_write = true,
+};
diff --git a/asoc/codecs/wsa881x-tables-analog.c b/asoc/codecs/wsa881x-tables-analog.c
new file mode 100644
index 0000000..061ed6f
--- /dev/null
+++ b/asoc/codecs/wsa881x-tables-analog.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa881x-registers-analog.h"
+
+const u8 wsa881x_ana_reg_readable[WSA881X_CACHE_SIZE] = {
+	[WSA881X_CHIP_ID0] = 1,
+	[WSA881X_CHIP_ID1] = 1,
+	[WSA881X_CHIP_ID2] = 1,
+	[WSA881X_CHIP_ID3] = 1,
+	[WSA881X_BUS_ID] = 1,
+	[WSA881X_CDC_RST_CTL] = 1,
+	[WSA881X_CDC_TOP_CLK_CTL] = 1,
+	[WSA881X_CDC_ANA_CLK_CTL] = 1,
+	[WSA881X_CDC_DIG_CLK_CTL] = 1,
+	[WSA881X_CLOCK_CONFIG] = 1,
+	[WSA881X_ANA_CTL] = 1,
+	[WSA881X_SWR_RESET_EN] = 1,
+	[WSA881X_RESET_CTL] = 1,
+	[WSA881X_TADC_VALUE_CTL] = 1,
+	[WSA881X_TEMP_DETECT_CTL] = 1,
+	[WSA881X_TEMP_MSB] = 1,
+	[WSA881X_TEMP_LSB] = 1,
+	[WSA881X_TEMP_CONFIG0] = 1,
+	[WSA881X_TEMP_CONFIG1] = 1,
+	[WSA881X_CDC_CLIP_CTL] = 1,
+	[WSA881X_SDM_PDM9_LSB] = 1,
+	[WSA881X_SDM_PDM9_MSB] = 1,
+	[WSA881X_CDC_RX_CTL] = 1,
+	[WSA881X_DEM_BYPASS_DATA0] = 1,
+	[WSA881X_DEM_BYPASS_DATA1] = 1,
+	[WSA881X_DEM_BYPASS_DATA2] = 1,
+	[WSA881X_DEM_BYPASS_DATA3] = 1,
+	[WSA881X_OTP_CTRL0] = 1,
+	[WSA881X_OTP_CTRL1] = 1,
+	[WSA881X_HDRIVE_CTL_GROUP1] = 1,
+	[WSA881X_INTR_MODE] = 1,
+	[WSA881X_INTR_MASK] = 1,
+	[WSA881X_INTR_STATUS] = 1,
+	[WSA881X_INTR_CLEAR] = 1,
+	[WSA881X_INTR_LEVEL] = 1,
+	[WSA881X_INTR_SET] = 1,
+	[WSA881X_INTR_TEST] = 1,
+	[WSA881X_PDM_TEST_MODE] = 1,
+	[WSA881X_ATE_TEST_MODE] = 1,
+	[WSA881X_PIN_CTL_MODE] = 1,
+	[WSA881X_PIN_CTL_OE] = 1,
+	[WSA881X_PIN_WDATA_IOPAD] = 1,
+	[WSA881X_PIN_STATUS] = 1,
+	[WSA881X_DIG_DEBUG_MODE] = 1,
+	[WSA881X_DIG_DEBUG_SEL] = 1,
+	[WSA881X_DIG_DEBUG_EN] = 1,
+	[WSA881X_SWR_HM_TEST1] = 1,
+	[WSA881X_SWR_HM_TEST2] = 1,
+	[WSA881X_TEMP_DETECT_DBG_CTL] = 1,
+	[WSA881X_TEMP_DEBUG_MSB] = 1,
+	[WSA881X_TEMP_DEBUG_LSB] = 1,
+	[WSA881X_SAMPLE_EDGE_SEL] = 1,
+	[WSA881X_IOPAD_CTL] = 1,
+	[WSA881X_SPARE_0] = 1,
+	[WSA881X_SPARE_1] = 1,
+	[WSA881X_SPARE_2] = 1,
+	[WSA881X_OTP_REG_0] = 1,
+	[WSA881X_OTP_REG_1] = 1,
+	[WSA881X_OTP_REG_2] = 1,
+	[WSA881X_OTP_REG_3] = 1,
+	[WSA881X_OTP_REG_4] = 1,
+	[WSA881X_OTP_REG_5] = 1,
+	[WSA881X_OTP_REG_6] = 1,
+	[WSA881X_OTP_REG_7] = 1,
+	[WSA881X_OTP_REG_8] = 1,
+	[WSA881X_OTP_REG_9] = 1,
+	[WSA881X_OTP_REG_10] = 1,
+	[WSA881X_OTP_REG_11] = 1,
+	[WSA881X_OTP_REG_12] = 1,
+	[WSA881X_OTP_REG_13] = 1,
+	[WSA881X_OTP_REG_14] = 1,
+	[WSA881X_OTP_REG_15] = 1,
+	[WSA881X_OTP_REG_16] = 1,
+	[WSA881X_OTP_REG_17] = 1,
+	[WSA881X_OTP_REG_18] = 1,
+	[WSA881X_OTP_REG_19] = 1,
+	[WSA881X_OTP_REG_20] = 1,
+	[WSA881X_OTP_REG_21] = 1,
+	[WSA881X_OTP_REG_22] = 1,
+	[WSA881X_OTP_REG_23] = 1,
+	[WSA881X_OTP_REG_24] = 1,
+	[WSA881X_OTP_REG_25] = 1,
+	[WSA881X_OTP_REG_26] = 1,
+	[WSA881X_OTP_REG_27] = 1,
+	[WSA881X_OTP_REG_28] = 1,
+	[WSA881X_OTP_REG_29] = 1,
+	[WSA881X_OTP_REG_30] = 1,
+	[WSA881X_OTP_REG_31] = 1,
+	[WSA881X_OTP_REG_63] = 1,
+	/* Analog Registers */
+	[WSA881X_BIAS_REF_CTRL] = 1,
+	[WSA881X_BIAS_TEST] = 1,
+	[WSA881X_BIAS_BIAS] = 1,
+	[WSA881X_TEMP_OP] = 1,
+	[WSA881X_TEMP_IREF_CTRL] = 1,
+	[WSA881X_TEMP_ISENS_CTRL] = 1,
+	[WSA881X_TEMP_CLK_CTRL] = 1,
+	[WSA881X_TEMP_TEST] = 1,
+	[WSA881X_TEMP_BIAS] = 1,
+	[WSA881X_TEMP_ADC_CTRL] = 1,
+	[WSA881X_TEMP_DOUT_MSB] = 1,
+	[WSA881X_TEMP_DOUT_LSB] = 1,
+	[WSA881X_ADC_EN_MODU_V] = 1,
+	[WSA881X_ADC_EN_MODU_I] = 1,
+	[WSA881X_ADC_EN_DET_TEST_V] = 1,
+	[WSA881X_ADC_EN_DET_TEST_I] = 1,
+	[WSA881X_ADC_SEL_IBIAS] = 1,
+	[WSA881X_ADC_EN_SEL_IBIAS] = 1,
+	[WSA881X_SPKR_DRV_EN] = 1,
+	[WSA881X_SPKR_DRV_GAIN] = 1,
+	[WSA881X_SPKR_DAC_CTL] = 1,
+	[WSA881X_SPKR_DRV_DBG] = 1,
+	[WSA881X_SPKR_PWRSTG_DBG] = 1,
+	[WSA881X_SPKR_OCP_CTL] = 1,
+	[WSA881X_SPKR_CLIP_CTL] = 1,
+	[WSA881X_SPKR_BBM_CTL] = 1,
+	[WSA881X_SPKR_MISC_CTL1] = 1,
+	[WSA881X_SPKR_MISC_CTL2] = 1,
+	[WSA881X_SPKR_BIAS_INT] = 1,
+	[WSA881X_SPKR_PA_INT] = 1,
+	[WSA881X_SPKR_BIAS_CAL] = 1,
+	[WSA881X_SPKR_BIAS_PSRR] = 1,
+	[WSA881X_SPKR_STATUS1] = 1,
+	[WSA881X_SPKR_STATUS2] = 1,
+	[WSA881X_BOOST_EN_CTL] = 1,
+	[WSA881X_BOOST_CURRENT_LIMIT] = 1,
+	[WSA881X_BOOST_PS_CTL] = 1,
+	[WSA881X_BOOST_PRESET_OUT1] = 1,
+	[WSA881X_BOOST_PRESET_OUT2] = 1,
+	[WSA881X_BOOST_FORCE_OUT] = 1,
+	[WSA881X_BOOST_LDO_PROG] = 1,
+	[WSA881X_BOOST_SLOPE_COMP_ISENSE_FB] = 1,
+	[WSA881X_BOOST_RON_CTL] = 1,
+	[WSA881X_BOOST_LOOP_STABILITY] = 1,
+	[WSA881X_BOOST_ZX_CTL] = 1,
+	[WSA881X_BOOST_START_CTL] = 1,
+	[WSA881X_BOOST_MISC1_CTL] = 1,
+	[WSA881X_BOOST_MISC2_CTL] = 1,
+	[WSA881X_BOOST_MISC3_CTL] = 1,
+	[WSA881X_BOOST_ATEST_CTL] = 1,
+	[WSA881X_SPKR_PROT_FE_GAIN] = 1,
+	[WSA881X_SPKR_PROT_FE_CM_LDO_SET] = 1,
+	[WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1] = 1,
+	[WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2] = 1,
+	[WSA881X_SPKR_PROT_ATEST1] = 1,
+	[WSA881X_SPKR_PROT_ATEST2] = 1,
+	[WSA881X_SPKR_PROT_FE_VSENSE_VCM] = 1,
+	[WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1] = 1,
+	[WSA881X_BONGO_RESRV_REG1] = 1,
+	[WSA881X_BONGO_RESRV_REG2] = 1,
+	[WSA881X_SPKR_PROT_SAR] = 1,
+	[WSA881X_SPKR_STATUS3] = 1,
+};
diff --git a/asoc/codecs/wsa881x-tables.c b/asoc/codecs/wsa881x-tables.c
new file mode 100644
index 0000000..4f1212b
--- /dev/null
+++ b/asoc/codecs/wsa881x-tables.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa881x-registers.h"
+
+const u8 wsa881x_reg_readable[WSA881X_CACHE_SIZE] = {
+	[WSA881X_CHIP_ID0] = 1,
+	[WSA881X_CHIP_ID1] = 1,
+	[WSA881X_CHIP_ID2] = 1,
+	[WSA881X_CHIP_ID3] = 1,
+	[WSA881X_BUS_ID] = 1,
+	[WSA881X_CDC_RST_CTL] = 1,
+	[WSA881X_CDC_TOP_CLK_CTL] = 1,
+	[WSA881X_CDC_ANA_CLK_CTL] = 1,
+	[WSA881X_CDC_DIG_CLK_CTL] = 1,
+	[WSA881X_CLOCK_CONFIG] = 1,
+	[WSA881X_ANA_CTL] = 1,
+	[WSA881X_SWR_RESET_EN] = 1,
+	[WSA881X_RESET_CTL] = 1,
+	[WSA881X_TADC_VALUE_CTL] = 1,
+	[WSA881X_TEMP_DETECT_CTL] = 1,
+	[WSA881X_TEMP_MSB] = 1,
+	[WSA881X_TEMP_LSB] = 1,
+	[WSA881X_TEMP_CONFIG0] = 1,
+	[WSA881X_TEMP_CONFIG1] = 1,
+	[WSA881X_CDC_CLIP_CTL] = 1,
+	[WSA881X_SDM_PDM9_LSB] = 1,
+	[WSA881X_SDM_PDM9_MSB] = 1,
+	[WSA881X_CDC_RX_CTL] = 1,
+	[WSA881X_DEM_BYPASS_DATA0] = 1,
+	[WSA881X_DEM_BYPASS_DATA1] = 1,
+	[WSA881X_DEM_BYPASS_DATA2] = 1,
+	[WSA881X_DEM_BYPASS_DATA3] = 1,
+	[WSA881X_OTP_CTRL0] = 1,
+	[WSA881X_OTP_CTRL1] = 1,
+	[WSA881X_HDRIVE_CTL_GROUP1] = 1,
+	[WSA881X_INTR_MODE] = 1,
+	[WSA881X_INTR_MASK] = 1,
+	[WSA881X_INTR_STATUS] = 1,
+	[WSA881X_INTR_CLEAR] = 1,
+	[WSA881X_INTR_LEVEL] = 1,
+	[WSA881X_INTR_SET] = 1,
+	[WSA881X_INTR_TEST] = 1,
+	[WSA881X_PDM_TEST_MODE] = 1,
+	[WSA881X_ATE_TEST_MODE] = 1,
+	[WSA881X_PIN_CTL_MODE] = 1,
+	[WSA881X_PIN_CTL_OE] = 1,
+	[WSA881X_PIN_WDATA_IOPAD] = 1,
+	[WSA881X_PIN_STATUS] = 1,
+	[WSA881X_DIG_DEBUG_MODE] = 1,
+	[WSA881X_DIG_DEBUG_SEL] = 1,
+	[WSA881X_DIG_DEBUG_EN] = 1,
+	[WSA881X_SWR_HM_TEST1] = 1,
+	[WSA881X_SWR_HM_TEST2] = 1,
+	[WSA881X_TEMP_DETECT_DBG_CTL] = 1,
+	[WSA881X_TEMP_DEBUG_MSB] = 1,
+	[WSA881X_TEMP_DEBUG_LSB] = 1,
+	[WSA881X_SAMPLE_EDGE_SEL] = 1,
+	[WSA881X_IOPAD_CTL] = 1,
+	[WSA881X_SPARE_0] = 1,
+	[WSA881X_SPARE_1] = 1,
+	[WSA881X_SPARE_2] = 1,
+	[WSA881X_OTP_REG_0] = 1,
+	[WSA881X_OTP_REG_1] = 1,
+	[WSA881X_OTP_REG_2] = 1,
+	[WSA881X_OTP_REG_3] = 1,
+	[WSA881X_OTP_REG_4] = 1,
+	[WSA881X_OTP_REG_5] = 1,
+	[WSA881X_OTP_REG_6] = 1,
+	[WSA881X_OTP_REG_7] = 1,
+	[WSA881X_OTP_REG_8] = 1,
+	[WSA881X_OTP_REG_9] = 1,
+	[WSA881X_OTP_REG_10] = 1,
+	[WSA881X_OTP_REG_11] = 1,
+	[WSA881X_OTP_REG_12] = 1,
+	[WSA881X_OTP_REG_13] = 1,
+	[WSA881X_OTP_REG_14] = 1,
+	[WSA881X_OTP_REG_15] = 1,
+	[WSA881X_OTP_REG_16] = 1,
+	[WSA881X_OTP_REG_17] = 1,
+	[WSA881X_OTP_REG_18] = 1,
+	[WSA881X_OTP_REG_19] = 1,
+	[WSA881X_OTP_REG_20] = 1,
+	[WSA881X_OTP_REG_21] = 1,
+	[WSA881X_OTP_REG_22] = 1,
+	[WSA881X_OTP_REG_23] = 1,
+	[WSA881X_OTP_REG_24] = 1,
+	[WSA881X_OTP_REG_25] = 1,
+	[WSA881X_OTP_REG_26] = 1,
+	[WSA881X_OTP_REG_27] = 1,
+	[WSA881X_OTP_REG_28] = 1,
+	[WSA881X_OTP_REG_29] = 1,
+	[WSA881X_OTP_REG_30] = 1,
+	[WSA881X_OTP_REG_31] = 1,
+	[WSA881X_OTP_REG_63] = 1,
+	/* Analog Registers */
+	[WSA881X_BIAS_REF_CTRL] = 1,
+	[WSA881X_BIAS_TEST] = 1,
+	[WSA881X_BIAS_BIAS] = 1,
+	[WSA881X_TEMP_OP] = 1,
+	[WSA881X_TEMP_IREF_CTRL] = 1,
+	[WSA881X_TEMP_ISENS_CTRL] = 1,
+	[WSA881X_TEMP_CLK_CTRL] = 1,
+	[WSA881X_TEMP_TEST] = 1,
+	[WSA881X_TEMP_BIAS] = 1,
+	[WSA881X_TEMP_ADC_CTRL] = 1,
+	[WSA881X_TEMP_DOUT_MSB] = 1,
+	[WSA881X_TEMP_DOUT_LSB] = 1,
+	[WSA881X_ADC_EN_MODU_V] = 1,
+	[WSA881X_ADC_EN_MODU_I] = 1,
+	[WSA881X_ADC_EN_DET_TEST_V] = 1,
+	[WSA881X_ADC_EN_DET_TEST_I] = 1,
+	[WSA881X_ADC_SEL_IBIAS] = 1,
+	[WSA881X_ADC_EN_SEL_IBAIS] = 1,
+	[WSA881X_SPKR_DRV_EN] = 1,
+	[WSA881X_SPKR_DRV_GAIN] = 1,
+	[WSA881X_SPKR_DAC_CTL] = 1,
+	[WSA881X_SPKR_DRV_DBG] = 1,
+	[WSA881X_SPKR_PWRSTG_DBG] = 1,
+	[WSA881X_SPKR_OCP_CTL] = 1,
+	[WSA881X_SPKR_CLIP_CTL] = 1,
+	[WSA881X_SPKR_BBM_CTL] = 1,
+	[WSA881X_SPKR_MISC_CTL1] = 1,
+	[WSA881X_SPKR_MISC_CTL2] = 1,
+	[WSA881X_SPKR_BIAS_INT] = 1,
+	[WSA881X_SPKR_PA_INT] = 1,
+	[WSA881X_SPKR_BIAS_CAL] = 1,
+	[WSA881X_SPKR_BIAS_PSRR] = 1,
+	[WSA881X_SPKR_STATUS1] = 1,
+	[WSA881X_SPKR_STATUS2] = 1,
+	[WSA881X_BOOST_EN_CTL] = 1,
+	[WSA881X_BOOST_CURRENT_LIMIT] = 1,
+	[WSA881X_BOOST_PS_CTL] = 1,
+	[WSA881X_BOOST_PRESET_OUT1] = 1,
+	[WSA881X_BOOST_PRESET_OUT2] = 1,
+	[WSA881X_BOOST_FORCE_OUT] = 1,
+	[WSA881X_BOOST_LDO_PROG] = 1,
+	[WSA881X_BOOST_SLOPE_COMP_ISENSE_FB] = 1,
+	[WSA881X_BOOST_RON_CTL] = 1,
+	[WSA881X_BOOST_LOOP_STABILITY] = 1,
+	[WSA881X_BOOST_ZX_CTL] = 1,
+	[WSA881X_BOOST_START_CTL] = 1,
+	[WSA881X_BOOST_MISC1_CTL] = 1,
+	[WSA881X_BOOST_MISC2_CTL] = 1,
+	[WSA881X_BOOST_MISC3_CTL] = 1,
+	[WSA881X_BOOST_ATEST_CTL] = 1,
+	[WSA881X_SPKR_PROT_FE_GAIN] = 1,
+	[WSA881X_SPKR_PROT_FE_CM_LDO_SET] = 1,
+	[WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1] = 1,
+	[WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2] = 1,
+	[WSA881X_SPKR_PROT_ATEST1] = 1,
+	[WSA881X_SPKR_PROT_ATEST2] = 1,
+	[WSA881X_SPKR_PROT_FE_VSENSE_VCM] = 1,
+	[WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1] = 1,
+	[WSA881X_BONGO_RESRV_REG1] = 1,
+	[WSA881X_BONGO_RESRV_REG2] = 1,
+	[WSA881X_SPKR_PROT_SAR] = 1,
+	[WSA881X_SPKR_STATUS3] = 1,
+};
diff --git a/asoc/codecs/wsa881x-temp-sensor.c b/asoc/codecs/wsa881x-temp-sensor.c
new file mode 100644
index 0000000..5ab0ecf
--- /dev/null
+++ b/asoc/codecs/wsa881x-temp-sensor.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/thermal.h>
+#include <sound/soc.h>
+#include "wsa881x-temp-sensor.h"
+
+#define T1_TEMP -10
+#define T2_TEMP 150
+#define LOW_TEMP_THRESHOLD 5
+#define HIGH_TEMP_THRESHOLD 45
+#define TEMP_INVALID	0xFFFF
+#define WSA881X_TEMP_RETRY 3
+/*
+ * wsa881x_get_temp - get wsa temperature
+ * @thermal: thermal zone device
+ * @temp: temperature value
+ *
+ * Get the temperature of wsa881x.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wsa881x_get_temp(struct thermal_zone_device *thermal,
+		     int *temp)
+{
+	struct wsa881x_tz_priv *pdata;
+	struct snd_soc_codec *codec;
+	struct wsa_temp_register reg;
+	int dmeas, d1, d2;
+	int ret = 0;
+	int temp_val;
+	int t1 = T1_TEMP;
+	int t2 = T2_TEMP;
+	u8 retry = WSA881X_TEMP_RETRY;
+
+	if (!thermal)
+		return -EINVAL;
+
+	if (thermal->devdata) {
+		pdata = thermal->devdata;
+		if (pdata->codec) {
+			codec = pdata->codec;
+		} else {
+			pr_err("%s: codec is NULL\n", __func__);
+			return -EINVAL;
+		}
+	} else {
+		pr_err("%s: pdata is NULL\n", __func__);
+		return -EINVAL;
+	}
+temp_retry:
+	if (pdata->wsa_temp_reg_read) {
+		ret = pdata->wsa_temp_reg_read(codec, &reg);
+		if (ret) {
+			pr_err("%s: temperature register read failed: %d\n",
+				__func__, ret);
+			return ret;
+		}
+	} else {
+		pr_err("%s: wsa_temp_reg_read is NULL\n", __func__);
+		return -EINVAL;
+	}
+	/*
+	 * Temperature register values are expected to be in the
+	 * following range.
+	 * d1_msb  = 68 - 92 and d1_lsb  = 0, 64, 128, 192
+	 * d2_msb  = 185 -218 and  d2_lsb  = 0, 64, 128, 192
+	 */
+	if ((reg.d1_msb < 68 || reg.d1_msb > 92) ||
+	    (!(reg.d1_lsb == 0 || reg.d1_lsb == 64 || reg.d1_lsb == 128 ||
+		reg.d1_lsb == 192)) ||
+	    (reg.d2_msb < 185 || reg.d2_msb > 218) ||
+	    (!(reg.d2_lsb == 0 || reg.d2_lsb == 64 || reg.d2_lsb == 128 ||
+		reg.d2_lsb == 192))) {
+		printk_ratelimited("%s: Temperature registers[%d %d %d %d] are out of range\n",
+				   __func__, reg.d1_msb, reg.d1_lsb, reg.d2_msb,
+				   reg.d2_lsb);
+	}
+	dmeas = ((reg.dmeas_msb << 0x8) | reg.dmeas_lsb) >> 0x6;
+	d1 = ((reg.d1_msb << 0x8) | reg.d1_lsb) >> 0x6;
+	d2 = ((reg.d2_msb << 0x8) | reg.d2_lsb) >> 0x6;
+
+	if (d1 == d2)
+		temp_val = TEMP_INVALID;
+	else
+		temp_val = t1 + (((dmeas - d1) * (t2 - t1))/(d2 - d1));
+
+	if (temp_val <= LOW_TEMP_THRESHOLD ||
+		temp_val >= HIGH_TEMP_THRESHOLD) {
+		printk_ratelimited("%s: T0: %d is out of range[%d, %d]\n",
+				   __func__, temp_val, LOW_TEMP_THRESHOLD,
+				   HIGH_TEMP_THRESHOLD);
+		if (retry--) {
+			msleep(20);
+			goto temp_retry;
+		}
+	}
+	if (temp)
+		*temp = temp_val;
+	pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n",
+		  __func__, temp_val, dmeas, d1, d2);
+	return ret;
+}
+EXPORT_SYMBOL(wsa881x_get_temp);
+
+static struct thermal_zone_device_ops wsa881x_thermal_ops = {
+	.get_temp = wsa881x_get_temp,
+};
+
+int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata)
+{
+	struct thermal_zone_device *tz_dev;
+
+	if (tz_pdata == NULL) {
+		pr_err("%s: thermal pdata is NULL\n", __func__);
+		return -EINVAL;
+	}
+	/* Register with the thermal zone */
+	tz_dev = thermal_zone_device_register(tz_pdata->name,
+				0, 0, tz_pdata,
+				&wsa881x_thermal_ops, NULL, 0, 0);
+	if (IS_ERR(tz_dev)) {
+		pr_err("%s: thermal device register failed.\n", __func__);
+		return -EINVAL;
+	}
+	tz_pdata->tz_dev = tz_dev;
+	return 0;
+}
+EXPORT_SYMBOL(wsa881x_init_thermal);
+
+void wsa881x_deinit_thermal(struct thermal_zone_device *tz_dev)
+{
+	if (tz_dev)
+		thermal_zone_device_unregister(tz_dev);
+}
+EXPORT_SYMBOL(wsa881x_deinit_thermal);
diff --git a/asoc/codecs/wsa881x-temp-sensor.h b/asoc/codecs/wsa881x-temp-sensor.h
new file mode 100644
index 0000000..d6c1eb7
--- /dev/null
+++ b/asoc/codecs/wsa881x-temp-sensor.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef WSA881X_TEMP_SENSOR_H
+#define WSA881X_TEMP_SENSOR_H
+
+#include <linux/thermal.h>
+#include <sound/soc.h>
+
+struct wsa_temp_register {
+	u8 d1_msb;
+	u8 d1_lsb;
+	u8 d2_msb;
+	u8 d2_lsb;
+	u8 dmeas_msb;
+	u8 dmeas_lsb;
+};
+typedef int32_t (*wsa_temp_register_read)(struct snd_soc_codec *codec,
+					struct wsa_temp_register *wsa_temp_reg);
+struct wsa881x_tz_priv {
+	struct thermal_zone_device *tz_dev;
+	struct snd_soc_codec *codec;
+	struct wsa_temp_register *wsa_temp_reg;
+	char name[80];
+	wsa_temp_register_read wsa_temp_reg_read;
+};
+
+int wsa881x_get_temp(struct thermal_zone_device *tz_dev, int *temp);
+int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata);
+void wsa881x_deinit_thermal(struct thermal_zone_device *tz_dev);
+#endif
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
new file mode 100644
index 0000000..456f68c
--- /dev/null
+++ b/asoc/codecs/wsa881x.c
@@ -0,0 +1,1439 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/debugfs.h>
+#include <soc/soundwire.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "msm-cdc-pinctrl.h"
+#include "wsa881x.h"
+#include "wsa881x-temp-sensor.h"
+
+#define WSA881X_NUM_RETRY	5
+
+enum {
+	G_18DB = 0,
+	G_16P5DB,
+	G_15DB,
+	G_13P5DB,
+	G_12DB,
+	G_10P5DB,
+	G_9DB,
+	G_7P5DB,
+	G_6DB,
+	G_4P5DB,
+	G_3DB,
+	G_1P5DB,
+	G_0DB,
+};
+
+enum {
+	DISABLE = 0,
+	ENABLE,
+};
+
+enum {
+	SWR_DAC_PORT,
+	SWR_COMP_PORT,
+	SWR_BOOST_PORT,
+	SWR_VISENSE_PORT,
+};
+
+struct swr_port {
+	u8 port_id;
+	u8 ch_mask;
+	u32 ch_rate;
+	u8 num_ch;
+};
+
+enum {
+	WSA881X_DEV_DOWN,
+	WSA881X_DEV_UP,
+};
+
+/*
+ * Private data Structure for wsa881x. All parameters related to
+ * WSA881X codec needs to be defined here.
+ */
+struct wsa881x_priv {
+	struct regmap *regmap;
+	struct device *dev;
+	struct swr_device *swr_slave;
+	struct snd_soc_codec *codec;
+	bool comp_enable;
+	bool boost_enable;
+	bool visense_enable;
+	u8 pa_gain;
+	struct swr_port port[WSA881X_MAX_SWR_PORTS];
+	int pd_gpio;
+	struct wsa881x_tz_priv tz_pdata;
+	int bg_cnt;
+	int clk_cnt;
+	int version;
+	struct mutex bg_lock;
+	struct mutex res_lock;
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+	int state;
+	struct delayed_work ocp_ctl_work;
+	struct device_node *wsa_rst_np;
+	int pa_mute;
+};
+
+#define SWR_SLV_MAX_REG_ADDR	0x390
+#define SWR_SLV_START_REG_ADDR	0x40
+#define SWR_SLV_MAX_BUF_LEN	20
+#define BYTES_PER_LINE		12
+#define SWR_SLV_RD_BUF_LEN	8
+#define SWR_SLV_WR_BUF_LEN	32
+#define SWR_SLV_MAX_DEVICES	2
+
+#define WSA881X_VERSION_ENTRY_SIZE 27
+#define WSA881X_OCP_CTL_TIMER_SEC 2
+#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
+#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
+
+static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC;
+module_param(wsa881x_ocp_poll_timer_sec, int, 0664);
+MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling");
+
+static struct wsa881x_priv *dbgwsa881x;
+static struct dentry *debugfs_wsa881x_dent;
+static struct dentry *debugfs_peek;
+static struct dentry *debugfs_poke;
+static struct dentry *debugfs_reg_dump;
+static unsigned int read_data;
+static unsigned int devnum;
+
+static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec,
+						bool enable);
+
+static const char * const wsa_pa_gain_text[] = {
+	"G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB",
+	"G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
+	"G_0_DB"
+};
+
+static const struct soc_enum wsa_pa_gain_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text);
+
+static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->pa_gain;
+
+	dev_dbg(codec->dev, "%s: PA gain = 0x%x\n", __func__, wsa881x->pa_gain);
+
+	return 0;
+}
+
+static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0]  = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	wsa881x->pa_gain =  ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int wsa881x_get_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->pa_mute;
+
+	return 0;
+}
+
+static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: mute current %d, new %d\n",
+		__func__, wsa881x->pa_mute, value);
+
+	if (value)
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x80, 0x00);
+	wsa881x->pa_mute = value;
+
+	return 0;
+}
+
+
+static const struct snd_kcontrol_new wsa_snd_controls[] = {
+	SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
+		     wsa_pa_gain_get, wsa_pa_gain_put),
+	SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
+		wsa881x_get_mute, wsa881x_set_mute),
+};
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int get_parameters(char *buf, u32 *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (kstrtou32(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t wsa881x_codec_version_read(struct snd_info_entry *entry,
+			       void *file_private_data, struct file *file,
+			       char __user *buf, size_t count, loff_t pos)
+{
+	struct wsa881x_priv *wsa881x;
+	char buffer[WSA881X_VERSION_ENTRY_SIZE];
+	int len;
+
+	wsa881x = (struct wsa881x_priv *) entry->private_data;
+	if (!wsa881x) {
+		pr_err("%s: wsa881x priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	len = snprintf(buffer, sizeof(buffer), "WSA881X-SOUNDWIRE_2_0\n");
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops wsa881x_codec_info_ops = {
+	.read = wsa881x_codec_version_read,
+};
+
+/*
+ * wsa881x_codec_info_create_codec_entry - creates wsa881x module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates wsa881x module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wsa881x_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_codec *codec)
+{
+	struct snd_info_entry *version_entry;
+	struct wsa881x_priv *wsa881x;
+	struct snd_soc_card *card;
+	char name[80];
+
+	if (!codec_root || !codec)
+		return -EINVAL;
+
+	wsa881x = snd_soc_codec_get_drvdata(codec);
+	card = codec->component.card;
+	snprintf(name, sizeof(name), "%s.%x", "wsa881x",
+		 (u32)wsa881x->swr_slave->addr);
+
+	wsa881x->entry = snd_info_create_subdir(codec_root->module,
+						(const char *)name,
+						codec_root);
+	if (!wsa881x->entry) {
+		dev_dbg(codec->dev, "%s: failed to create wsa881x entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   wsa881x->entry);
+	if (!version_entry) {
+		dev_dbg(codec->dev, "%s: failed to create wsa881x version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = wsa881x;
+	version_entry->size = WSA881X_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &wsa881x_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	wsa881x->version_entry = version_entry;
+
+	return 0;
+}
+EXPORT_SYMBOL(wsa881x_codec_info_create_codec_entry);
+
+static bool is_swr_slv_reg_readable(int reg)
+{
+	bool ret = true;
+
+	if (((reg > 0x46) && (reg < 0x4A)) ||
+	    ((reg > 0x4A) && (reg < 0x50)) ||
+	    ((reg > 0x55) && (reg < 0xE0)) ||
+	    ((reg > 0xE0) && (reg < 0xF0)) ||
+	    ((reg > 0xF0) && (reg < 0x100)) ||
+	    ((reg > 0x105) && (reg < 0x120)) ||
+	    ((reg > 0x128) && (reg < 0x130)) ||
+	    ((reg > 0x138) && (reg < 0x200)) ||
+	    ((reg > 0x205) && (reg < 0x220)) ||
+	    ((reg > 0x228) && (reg < 0x230)) ||
+	    ((reg > 0x238) && (reg < 0x300)) ||
+	    ((reg > 0x305) && (reg < 0x320)) ||
+	    ((reg > 0x328) && (reg < 0x330)) ||
+	    ((reg > 0x338) && (reg < 0x400)) ||
+	    ((reg > 0x405) && (reg < 0x420)))
+		ret = false;
+
+	return ret;
+}
+
+static ssize_t wsa881x_swrslave_reg_show(char __user *ubuf, size_t count,
+					  loff_t *ppos)
+{
+	int i, reg_val, len;
+	ssize_t total = 0;
+	char tmp_buf[SWR_SLV_MAX_BUF_LEN];
+
+	if (!ubuf || !ppos || (devnum == 0))
+		return 0;
+
+	for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
+		i <= SWR_SLV_MAX_REG_ADDR; i++) {
+		if (!is_swr_slv_reg_readable(i))
+			continue;
+		swr_read(dbgwsa881x->swr_slave, devnum,
+			i, &reg_val, 1);
+		len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i,
+			       (reg_val & 0xFF));
+		if ((total + len) >= count - 1)
+			break;
+		if (copy_to_user((ubuf + total), tmp_buf, len)) {
+			pr_err("%s: fail to copy reg dump\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
+		*ppos += len;
+		total += len;
+	}
+
+copy_err:
+	return total;
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_RD_BUF_LEN];
+	char *access_str;
+	ssize_t ret_cnt;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	access_str = file->private_data;
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!strcmp(access_str, "swrslave_peek")) {
+		snprintf(lbuf, sizeof(lbuf), "0x%x\n", (read_data & 0xFF));
+		ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf,
+					       strnlen(lbuf, 7));
+	} else if (!strcmp(access_str, "swrslave_reg_dump")) {
+		ret_cnt = wsa881x_swrslave_reg_show(ubuf, count, ppos);
+	} else {
+		pr_err("%s: %s not permitted to read\n", __func__, access_str);
+		ret_cnt = -EPERM;
+	}
+	return ret_cnt;
+}
+
+static ssize_t codec_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_WR_BUF_LEN];
+	int rc;
+	u32 param[5];
+	char *access_str;
+
+	if (!filp || !ppos || !ubuf)
+		return -EINVAL;
+
+	access_str = filp->private_data;
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	if (!strcmp(access_str, "swrslave_poke")) {
+		/* write */
+		rc = get_parameters(lbuf, param, 3);
+		if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (param[1] <= 0xFF) &&
+			(rc == 0))
+			swr_write(dbgwsa881x->swr_slave, param[2],
+				param[0], &param[1]);
+		else
+			rc = -EINVAL;
+	} else if (!strcmp(access_str, "swrslave_peek")) {
+		/* read */
+		rc = get_parameters(lbuf, param, 2);
+		if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))
+			swr_read(dbgwsa881x->swr_slave, param[1],
+				param[0], &read_data, 1);
+		else
+			rc = -EINVAL;
+	} else if (!strcmp(access_str, "swrslave_reg_dump")) {
+		/* reg dump */
+		rc = get_parameters(lbuf, param, 1);
+		if ((rc == 0) && (param[0] > 0) &&
+		    (param[0] <= SWR_SLV_MAX_DEVICES))
+			devnum = param[0];
+		else
+			rc = -EINVAL;
+	}
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+	.read = codec_debug_read,
+};
+
+static const struct reg_sequence wsa881x_pre_pmu_pa[] = {
+	{WSA881X_SPKR_DRV_GAIN, 0x41, 0},
+	{WSA881X_SPKR_MISC_CTL1, 0x01, 0},
+	{WSA881X_ADC_EN_DET_TEST_I, 0x01, 0},
+	{WSA881X_ADC_EN_MODU_V, 0x02, 0},
+	{WSA881X_ADC_EN_DET_TEST_V, 0x10, 0},
+	{WSA881X_SPKR_PWRSTG_DBG, 0xA0, 0},
+};
+
+static const struct reg_sequence wsa881x_pre_pmu_pa_2_0[] = {
+	{WSA881X_SPKR_DRV_GAIN, 0x41, 0},
+	{WSA881X_SPKR_MISC_CTL1, 0x87, 0},
+};
+
+static const struct reg_sequence wsa881x_post_pmu_pa[] = {
+	{WSA881X_SPKR_PWRSTG_DBG, 0x00, 0},
+	{WSA881X_ADC_EN_DET_TEST_V, 0x00, 0},
+	{WSA881X_ADC_EN_MODU_V, 0x00, 0},
+	{WSA881X_ADC_EN_DET_TEST_I, 0x00, 0},
+};
+
+static const struct reg_sequence wsa881x_vi_txfe_en[] = {
+	{WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
+	{WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
+	{WSA881X_SPKR_PROT_FE_GAIN, 0xCF, 0},
+};
+
+static const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = {
+	{WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
+	{WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
+	{WSA881X_SPKR_PROT_FE_GAIN, 0x47, 0},
+};
+
+static int wsa881x_boost_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	dev_dbg(codec->dev, "%s: enable:%d\n", __func__, enable);
+	if (enable)
+		snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL, 0x80, 0x80);
+	else
+		snd_soc_update_bits(codec, WSA881X_BOOST_EN_CTL, 0x80, 0x00);
+	/*
+	 * 1.5ms sleep is needed after boost enable/disable as per
+	 * HW requirement
+	 */
+	usleep_range(1500, 1510);
+	return 0;
+}
+
+static int wsa881x_visense_txfe_ctrl(struct snd_soc_codec *codec, bool enable,
+				     u8 isense1_gain, u8 isense2_gain,
+				     u8 vsense_gain)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev,
+		"%s: enable:%d, isense1 gain: %d, isense2 gain: %d, vsense_gain %d\n",
+		__func__, enable, isense1_gain, isense2_gain, vsense_gain);
+
+	if (enable) {
+		regmap_multi_reg_write(wsa881x->regmap,
+				wsa881x_vi_txfe_en_2_0,
+				ARRAY_SIZE(wsa881x_vi_txfe_en_2_0));
+	} else {
+		snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_VSENSE_VCM,
+				    0x08, 0x08);
+		/*
+		 * 200us sleep is needed after visense txfe disable as per
+		 * HW requirement.
+		 */
+		usleep_range(200, 210);
+		snd_soc_update_bits(codec, WSA881X_SPKR_PROT_FE_GAIN,
+				    0x01, 0x00);
+	}
+	return 0;
+}
+
+static int wsa881x_visense_adc_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+
+	dev_dbg(codec->dev, "%s: enable:%d\n", __func__, enable);
+	snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_V, (0x01 << 7),
+			    (enable << 7));
+	snd_soc_update_bits(codec, WSA881X_ADC_EN_MODU_I, (0x01 << 7),
+			    (enable << 7));
+	return 0;
+}
+
+static void wsa881x_bandgap_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: enable:%d, bg_count:%d\n", __func__,
+		enable, wsa881x->bg_cnt);
+	mutex_lock(&wsa881x->bg_lock);
+	if (enable) {
+		++wsa881x->bg_cnt;
+		if (wsa881x->bg_cnt == 1) {
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP,
+					    0x08, 0x08);
+			/* 400usec sleep is needed as per HW requirement */
+			usleep_range(400, 410);
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP,
+					    0x04, 0x04);
+		}
+	} else {
+		--wsa881x->bg_cnt;
+		if (wsa881x->bg_cnt <= 0) {
+			WARN_ON(wsa881x->bg_cnt < 0);
+			wsa881x->bg_cnt = 0;
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x04, 0x00);
+			snd_soc_update_bits(codec, WSA881X_TEMP_OP, 0x08, 0x00);
+		}
+	}
+	mutex_unlock(&wsa881x->bg_lock);
+}
+
+static void wsa881x_clk_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: enable:%d, clk_count:%d\n", __func__,
+		enable, wsa881x->clk_cnt);
+	mutex_lock(&wsa881x->res_lock);
+	if (enable) {
+		++wsa881x->clk_cnt;
+		if (wsa881x->clk_cnt == 1) {
+			snd_soc_write(codec, WSA881X_CDC_DIG_CLK_CTL, 0x01);
+			snd_soc_write(codec, WSA881X_CDC_ANA_CLK_CTL, 0x01);
+		}
+	} else {
+		--wsa881x->clk_cnt;
+		if (wsa881x->clk_cnt <= 0) {
+			WARN_ON(wsa881x->clk_cnt < 0);
+			wsa881x->clk_cnt = 0;
+			snd_soc_write(codec, WSA881X_CDC_DIG_CLK_CTL, 0x00);
+			snd_soc_write(codec, WSA881X_CDC_ANA_CLK_CTL, 0x00);
+		}
+	}
+	mutex_unlock(&wsa881x->res_lock);
+}
+
+static int wsa881x_get_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->comp_enable;
+	return 0;
+}
+
+static int wsa881x_set_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: Compander enable current %d, new %d\n",
+		 __func__, wsa881x->comp_enable, value);
+	wsa881x->comp_enable = value;
+	return 0;
+}
+
+static int wsa881x_get_boost(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->boost_enable;
+	return 0;
+}
+
+static int wsa881x_set_boost(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: Boost enable current %d, new %d\n",
+		 __func__, wsa881x->boost_enable, value);
+	wsa881x->boost_enable = value;
+	return 0;
+}
+
+static int wsa881x_get_visense(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->visense_enable;
+	return 0;
+}
+
+static int wsa881x_set_visense(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: VIsense enable current %d, new %d\n",
+		 __func__, wsa881x->visense_enable, value);
+	wsa881x->visense_enable = value;
+	return 0;
+}
+
+static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
+	SOC_SINGLE_EXT("COMP Switch", SND_SOC_NOPM, 0, 1, 0,
+		wsa881x_get_compander, wsa881x_set_compander),
+
+	SOC_SINGLE_EXT("BOOST Switch", SND_SOC_NOPM, 0, 1, 0,
+		wsa881x_get_boost, wsa881x_set_boost),
+
+	SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
+		wsa881x_get_visense, wsa881x_set_visense),
+};
+
+static const struct snd_kcontrol_new swr_dac_port[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static int wsa881x_set_port(struct snd_soc_codec *codec, int port_idx,
+			u8 *port_id, u8 *num_ch, u8 *ch_mask, u32 *ch_rate)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	*port_id = wsa881x->port[port_idx].port_id;
+	*num_ch = wsa881x->port[port_idx].num_ch;
+	*ch_mask = wsa881x->port[port_idx].ch_mask;
+	*ch_rate = wsa881x->port[port_idx].ch_rate;
+	return 0;
+}
+
+static int wsa881x_enable_swr_dac_port(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	u8 port_id[WSA881X_MAX_SWR_PORTS];
+	u8 num_ch[WSA881X_MAX_SWR_PORTS];
+	u8 ch_mask[WSA881X_MAX_SWR_PORTS];
+	u32 ch_rate[WSA881X_MAX_SWR_PORTS];
+	u8 num_port = 0;
+
+	dev_dbg(codec->dev, "%s: event %d name %s\n", __func__,
+		event, w->name);
+	if (wsa881x == NULL)
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wsa881x_set_port(codec, SWR_DAC_PORT,
+				&port_id[num_port], &num_ch[num_port],
+				&ch_mask[num_port], &ch_rate[num_port]);
+		++num_port;
+
+		if (wsa881x->comp_enable) {
+			wsa881x_set_port(codec, SWR_COMP_PORT,
+					&port_id[num_port], &num_ch[num_port],
+					&ch_mask[num_port], &ch_rate[num_port]);
+			++num_port;
+		}
+		if (wsa881x->boost_enable) {
+			wsa881x_set_port(codec, SWR_BOOST_PORT,
+					&port_id[num_port], &num_ch[num_port],
+					&ch_mask[num_port], &ch_rate[num_port]);
+			++num_port;
+		}
+		if (wsa881x->visense_enable) {
+			wsa881x_set_port(codec, SWR_VISENSE_PORT,
+					&port_id[num_port], &num_ch[num_port],
+					&ch_mask[num_port], &ch_rate[num_port]);
+			++num_port;
+		}
+		swr_connect_port(wsa881x->swr_slave, &port_id[0], num_port,
+				&ch_mask[0], &ch_rate[0], &num_ch[0]);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		port_id[num_port] = wsa881x->port[SWR_DAC_PORT].port_id;
+		++num_port;
+		if (wsa881x->comp_enable) {
+			port_id[num_port] =
+				wsa881x->port[SWR_COMP_PORT].port_id;
+			++num_port;
+		}
+		if (wsa881x->boost_enable) {
+			port_id[num_port] =
+				wsa881x->port[SWR_BOOST_PORT].port_id;
+			++num_port;
+		}
+		if (wsa881x->visense_enable) {
+			port_id[num_port] =
+				wsa881x->port[SWR_VISENSE_PORT].port_id;
+			++num_port;
+		}
+		swr_disconnect_port(wsa881x->swr_slave, &port_id[0], num_port);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: %s %d boost %d visense %d\n", __func__,
+		w->name, event,	wsa881x->boost_enable,
+		wsa881x->visense_enable);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wsa881x_resource_acquire(codec, ENABLE);
+		wsa881x_boost_ctrl(codec, ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		swr_slvdev_datapath_control(wsa881x->swr_slave,
+					    wsa881x->swr_slave->dev_num,
+					    false);
+		wsa881x_boost_ctrl(codec, DISABLE);
+		wsa881x_resource_acquire(codec, DISABLE);
+		break;
+	}
+	return 0;
+}
+
+static int wsa881x_ramp_pa_gain(struct snd_soc_codec *codec,
+				int min_gain, int max_gain, int udelay)
+{
+	int val;
+
+	for (val = min_gain; max_gain <= val; val--) {
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN,
+				    0xF0, val << 4);
+		/*
+		 * 1ms delay is needed for every step change in gain as per
+		 * HW requirement.
+		 */
+		usleep_range(udelay, udelay+10);
+	}
+	return 0;
+}
+
+static void wsa881x_ocp_ctl_work(struct work_struct *work)
+{
+	struct wsa881x_priv *wsa881x;
+	struct delayed_work *dwork;
+	struct snd_soc_codec *codec;
+	int temp_val;
+
+	dwork = to_delayed_work(work);
+	wsa881x = container_of(dwork, struct wsa881x_priv, ocp_ctl_work);
+
+	codec = wsa881x->codec;
+	wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
+	dev_dbg(codec->dev, " temp = %d\n", temp_val);
+
+	if (temp_val <= WSA881X_OCP_CTL_TEMP_CELSIUS)
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0x00);
+	else
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
+
+	schedule_delayed_work(&wsa881x->ocp_ctl_work,
+			msecs_to_jiffies(wsa881x_ocp_poll_timer_sec * 1000));
+}
+
+static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int min_gain, max_gain;
+
+	dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0x80);
+		regmap_multi_reg_write(wsa881x->regmap,
+				wsa881x_pre_pmu_pa_2_0,
+				ARRAY_SIZE(wsa881x_pre_pmu_pa_2_0));
+		swr_slvdev_datapath_control(wsa881x->swr_slave,
+					    wsa881x->swr_slave->dev_num,
+					    true);
+		/* Set register mode if compander is not enabled */
+		if (!wsa881x->comp_enable)
+			snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN,
+					    0x08, 0x08);
+		else
+			snd_soc_update_bits(codec, WSA881X_SPKR_DRV_GAIN,
+					    0x08, 0x00);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (!wsa881x->comp_enable) {
+			max_gain = wsa881x->pa_gain;
+			/*
+			 * Gain has to set incrementally in 4 steps
+			 * as per HW sequence
+			 */
+			if (max_gain > G_4P5DB)
+				min_gain = G_0DB;
+			else
+				min_gain = max_gain + 3;
+			/*
+			 * 1ms delay is needed before change in gain
+			 * as per HW requirement.
+			 */
+			usleep_range(1000, 1010);
+			wsa881x_ramp_pa_gain(codec, min_gain, max_gain, 1000);
+		}
+		if (wsa881x->visense_enable) {
+			wsa881x_visense_txfe_ctrl(codec, ENABLE,
+						0x00, 0x03, 0x01);
+			snd_soc_update_bits(codec, WSA881X_ADC_EN_SEL_IBAIS,
+					    0x07, 0x01);
+			wsa881x_visense_adc_ctrl(codec, ENABLE);
+		}
+		schedule_delayed_work(&wsa881x->ocp_ctl_work,
+			msecs_to_jiffies(WSA881X_OCP_CTL_TIMER_SEC * 1000));
+		/* Force remove group */
+		swr_remove_from_group(wsa881x->swr_slave,
+				      wsa881x->swr_slave->dev_num);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (wsa881x->visense_enable) {
+			wsa881x_visense_adc_ctrl(codec, DISABLE);
+			wsa881x_visense_txfe_ctrl(codec, DISABLE,
+						0x00, 0x01, 0x01);
+		}
+		cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
+		snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("IN"),
+
+	SND_SOC_DAPM_MIXER_E("SWR DAC_Port", SND_SOC_NOPM, 0, 0, swr_dac_port,
+		ARRAY_SIZE(swr_dac_port), wsa881x_enable_swr_dac_port,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("RDAC", NULL, WSA881X_SPKR_DAC_CTL, 7, 0,
+		wsa881x_rdac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("SPKR PGA", WSA881X_SPKR_DRV_EN, 7, 0, NULL, 0,
+			wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+};
+
+static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
+	{"SWR DAC_Port", "Switch", "IN"},
+	{"RDAC", NULL, "SWR DAC_Port"},
+	{"SPKR PGA", NULL, "RDAC"},
+	{"SPKR", NULL, "SPKR PGA"},
+};
+
+int wsa881x_set_channel_map(struct snd_soc_codec *codec, u8 *port, u8 num_port,
+				unsigned int *ch_mask, unsigned int *ch_rate)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int i;
+
+	if (!port || !ch_mask || !ch_rate ||
+		(num_port > WSA881X_MAX_SWR_PORTS)) {
+		dev_err(codec->dev,
+			"%s: Invalid port=%pK, ch_mask=%pK, ch_rate=%pK\n",
+			__func__, port, ch_mask, ch_rate);
+		return -EINVAL;
+	}
+	for (i = 0; i < num_port; i++) {
+		wsa881x->port[i].port_id = port[i];
+		wsa881x->port[i].ch_mask = ch_mask[i];
+		wsa881x->port[i].ch_rate = ch_rate[i];
+		wsa881x->port[i].num_ch = __sw_hweight8(ch_mask[i]);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(wsa881x_set_channel_map);
+
+static void wsa881x_init(struct snd_soc_codec *codec)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	wsa881x->version = snd_soc_read(codec, WSA881X_CHIP_ID1);
+	wsa881x_regmap_defaults(wsa881x->regmap, wsa881x->version);
+	/* Bring out of analog reset */
+	snd_soc_update_bits(codec, WSA881X_CDC_RST_CTL, 0x02, 0x02);
+	/* Bring out of digital reset */
+	snd_soc_update_bits(codec, WSA881X_CDC_RST_CTL, 0x01, 0x01);
+
+	snd_soc_update_bits(codec, WSA881X_CLOCK_CONFIG, 0x10, 0x10);
+	snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0x02, 0x02);
+	snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0xC0, 0x80);
+	snd_soc_update_bits(codec, WSA881X_SPKR_MISC_CTL1, 0x06, 0x06);
+	snd_soc_update_bits(codec, WSA881X_SPKR_BIAS_INT, 0xFF, 0x00);
+	snd_soc_update_bits(codec, WSA881X_SPKR_PA_INT, 0xF0, 0x40);
+	snd_soc_update_bits(codec, WSA881X_SPKR_PA_INT, 0x0E, 0x0E);
+	snd_soc_update_bits(codec, WSA881X_BOOST_LOOP_STABILITY,
+			    0x03, 0x03);
+	snd_soc_update_bits(codec, WSA881X_BOOST_MISC2_CTL, 0xFF, 0x14);
+	snd_soc_update_bits(codec, WSA881X_BOOST_START_CTL, 0x80, 0x80);
+	snd_soc_update_bits(codec, WSA881X_BOOST_START_CTL, 0x03, 0x00);
+	snd_soc_update_bits(codec, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
+			    0x0C, 0x04);
+	snd_soc_update_bits(codec, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
+			    0x03, 0x00);
+	if (snd_soc_read(codec, WSA881X_OTP_REG_0))
+		snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT1,
+				    0xF0, 0x70);
+	snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT2,
+			    0xF0, 0x30);
+	snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x08, 0x08);
+	snd_soc_update_bits(codec, WSA881X_BOOST_CURRENT_LIMIT,
+			    0x0F, 0x08);
+	snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0x30, 0x30);
+	snd_soc_update_bits(codec, WSA881X_SPKR_OCP_CTL, 0x0C, 0x00);
+	snd_soc_update_bits(codec, WSA881X_OTP_REG_28, 0x3F, 0x3A);
+	snd_soc_update_bits(codec, WSA881X_BONGO_RESRV_REG1,
+			    0xFF, 0xB2);
+	snd_soc_update_bits(codec, WSA881X_BONGO_RESRV_REG2,
+			    0xFF, 0x05);
+}
+
+static int32_t wsa881x_resource_acquire(struct snd_soc_codec *codec,
+						bool enable)
+{
+	wsa881x_clk_ctrl(codec, enable);
+	wsa881x_bandgap_ctrl(codec, enable);
+	return 0;
+}
+
+static int32_t wsa881x_temp_reg_read(struct snd_soc_codec *codec,
+				     struct wsa_temp_register *wsa_temp_reg)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	struct swr_device *dev;
+	u8 retry = WSA881X_NUM_RETRY;
+	u8 devnum = 0;
+
+	if (!wsa881x) {
+		dev_err(codec->dev, "%s: wsa881x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev = wsa881x->swr_slave;
+	if (dev && (wsa881x->state == WSA881X_DEV_DOWN)) {
+		while (swr_get_logical_dev_num(dev, dev->addr, &devnum) &&
+		       retry--) {
+			/* Retry after 1 msec delay */
+			usleep_range(1000, 1100);
+		}
+		if (retry == 0) {
+			dev_err(codec->dev,
+				"%s get devnum %d for dev addr %lx failed\n",
+				__func__, devnum, dev->addr);
+			return -EINVAL;
+		}
+	}
+	mutex_lock(&wsa881x->res_lock);
+	if (!wsa881x->clk_cnt) {
+		regcache_mark_dirty(wsa881x->regmap);
+		regcache_sync(wsa881x->regmap);
+	}
+	mutex_unlock(&wsa881x->res_lock);
+
+	wsa881x_resource_acquire(codec, ENABLE);
+
+	snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x00);
+	wsa_temp_reg->dmeas_msb = snd_soc_read(codec, WSA881X_TEMP_MSB);
+	wsa_temp_reg->dmeas_lsb = snd_soc_read(codec, WSA881X_TEMP_LSB);
+	snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x01);
+	wsa_temp_reg->d1_msb = snd_soc_read(codec, WSA881X_OTP_REG_1);
+	wsa_temp_reg->d1_lsb = snd_soc_read(codec, WSA881X_OTP_REG_2);
+	wsa_temp_reg->d2_msb = snd_soc_read(codec, WSA881X_OTP_REG_3);
+	wsa_temp_reg->d2_lsb = snd_soc_read(codec, WSA881X_OTP_REG_4);
+
+	wsa881x_resource_acquire(codec, DISABLE);
+
+	return 0;
+}
+
+static int wsa881x_probe(struct snd_soc_codec *codec)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	struct swr_device *dev;
+
+	if (!wsa881x)
+		return -EINVAL;
+
+	dev = wsa881x->swr_slave;
+	wsa881x->codec = codec;
+	mutex_init(&wsa881x->bg_lock);
+	mutex_init(&wsa881x->res_lock);
+	wsa881x_init(codec);
+	snprintf(wsa881x->tz_pdata.name, sizeof(wsa881x->tz_pdata.name),
+		"%s.%x", "wsatz", (u8)dev->addr);
+	wsa881x->bg_cnt = 0;
+	wsa881x->clk_cnt = 0;
+	wsa881x->tz_pdata.codec = codec;
+	wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read;
+	wsa881x_init_thermal(&wsa881x->tz_pdata);
+	snd_soc_add_codec_controls(codec, wsa_snd_controls,
+				   ARRAY_SIZE(wsa_snd_controls));
+	INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work);
+	return 0;
+}
+
+static int wsa881x_remove(struct snd_soc_codec *codec)
+{
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	if (wsa881x->tz_pdata.tz_dev)
+		wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
+	mutex_destroy(&wsa881x->bg_lock);
+	mutex_destroy(&wsa881x->res_lock);
+
+	return 0;
+}
+
+static struct regmap *wsa881x_get_regmap(struct device *dev)
+{
+	struct wsa881x_priv *control = swr_get_dev_data(to_swr_device(dev));
+
+	if (!control)
+		return NULL;
+
+	return control->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wsa881x = {
+	.probe = wsa881x_probe,
+	.remove = wsa881x_remove,
+	.get_regmap = wsa881x_get_regmap,
+	.component_driver = {
+		.controls = wsa881x_snd_controls,
+		.num_controls = ARRAY_SIZE(wsa881x_snd_controls),
+		.dapm_widgets = wsa881x_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
+		.dapm_routes = wsa881x_audio_map,
+		.num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
+	},
+};
+
+static int wsa881x_gpio_ctrl(struct wsa881x_priv *wsa881x, bool enable)
+{
+	int ret = 0;
+
+	if (wsa881x->pd_gpio < 0) {
+		dev_err(wsa881x->dev, "%s: gpio is not valid %d\n",
+			__func__, wsa881x->pd_gpio);
+		return -EINVAL;
+	}
+
+	if (wsa881x->wsa_rst_np) {
+		if (enable)
+			ret = msm_cdc_pinctrl_select_active_state(
+							wsa881x->wsa_rst_np);
+		else
+			ret = msm_cdc_pinctrl_select_sleep_state(
+							wsa881x->wsa_rst_np);
+		if (ret != 0)
+			dev_err(wsa881x->dev,
+				"%s: Failed to turn state %d; ret=%d\n",
+				__func__, enable, ret);
+	} else {
+		if (gpio_is_valid(wsa881x->pd_gpio))
+			gpio_direction_output(wsa881x->pd_gpio, enable);
+	}
+
+	return ret;
+}
+
+static int wsa881x_gpio_init(struct swr_device *pdev)
+{
+	int ret = 0;
+	struct wsa881x_priv *wsa881x;
+
+	wsa881x = swr_get_dev_data(pdev);
+	if (!wsa881x) {
+		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_dbg(&pdev->dev, "%s: gpio %d request with name %s\n",
+		__func__, wsa881x->pd_gpio, dev_name(&pdev->dev));
+	ret = gpio_request(wsa881x->pd_gpio, dev_name(&pdev->dev));
+	if (ret) {
+		if (ret == -EBUSY) {
+			/* GPIO was already requested */
+			dev_dbg(&pdev->dev,
+				 "%s: gpio %d is already set to high\n",
+				 __func__, wsa881x->pd_gpio);
+			ret = 0;
+		} else {
+			dev_err(&pdev->dev, "%s: Failed to request gpio %d, err: %d\n",
+				__func__, wsa881x->pd_gpio, ret);
+		}
+	}
+	return ret;
+}
+
+static int wsa881x_swr_probe(struct swr_device *pdev)
+{
+	int ret = 0;
+	struct wsa881x_priv *wsa881x;
+	u8 devnum = 0;
+	bool pin_state_current = false;
+
+	wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
+			    GFP_KERNEL);
+	if (!wsa881x)
+		return -ENOMEM;
+	wsa881x->wsa_rst_np = of_parse_phandle(pdev->dev.of_node,
+					     "qcom,spkr-sd-n-node", 0);
+	if (!wsa881x->wsa_rst_np) {
+		dev_dbg(&pdev->dev, "%s: Not using pinctrl, fallback to gpio\n",
+			__func__);
+		wsa881x->pd_gpio = of_get_named_gpio(pdev->dev.of_node,
+						     "qcom,spkr-sd-n-gpio", 0);
+		if (wsa881x->pd_gpio < 0) {
+			dev_err(&pdev->dev, "%s: %s property is not found %d\n",
+				__func__, "qcom,spkr-sd-n-gpio",
+				wsa881x->pd_gpio);
+			goto err;
+		}
+		dev_dbg(&pdev->dev, "%s: reset gpio %d\n", __func__,
+			wsa881x->pd_gpio);
+	}
+	swr_set_dev_data(pdev, wsa881x);
+
+	wsa881x->swr_slave = pdev;
+
+	if (!wsa881x->wsa_rst_np) {
+		ret = wsa881x_gpio_init(pdev);
+		if (ret)
+			goto err;
+	}
+	if (wsa881x->wsa_rst_np)
+		pin_state_current = msm_cdc_pinctrl_get_state(
+						wsa881x->wsa_rst_np);
+	wsa881x_gpio_ctrl(wsa881x, true);
+	wsa881x->state = WSA881X_DEV_UP;
+
+	if (!debugfs_wsa881x_dent) {
+		dbgwsa881x = wsa881x;
+		debugfs_wsa881x_dent = debugfs_create_dir(
+						"wsa881x_swr_slave", 0);
+		if (!IS_ERR(debugfs_wsa881x_dent)) {
+			debugfs_peek = debugfs_create_file("swrslave_peek",
+					S_IFREG | 0444, debugfs_wsa881x_dent,
+					(void *) "swrslave_peek",
+					&codec_debug_ops);
+
+			debugfs_poke = debugfs_create_file("swrslave_poke",
+					S_IFREG | 0444, debugfs_wsa881x_dent,
+					(void *) "swrslave_poke",
+					&codec_debug_ops);
+
+			debugfs_reg_dump = debugfs_create_file(
+						"swrslave_reg_dump",
+						S_IFREG | 0444,
+						debugfs_wsa881x_dent,
+						(void *) "swrslave_reg_dump",
+						&codec_debug_ops);
+		}
+	}
+
+	/*
+	 * Add 5msec delay to provide sufficient time for
+	 * soundwire auto enumeration of slave devices as
+	 * as per HW requirement.
+	 */
+	usleep_range(5000, 5010);
+	ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+	if (ret) {
+		dev_dbg(&pdev->dev,
+			"%s get devnum %d for dev addr %lx failed\n",
+			__func__, devnum, pdev->addr);
+		goto dev_err;
+	}
+	pdev->dev_num = devnum;
+
+	wsa881x->regmap = devm_regmap_init_swr(pdev,
+					       &wsa881x_regmap_config);
+	if (IS_ERR(wsa881x->regmap)) {
+		ret = PTR_ERR(wsa881x->regmap);
+		dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
+			__func__, ret);
+		goto dev_err;
+	}
+
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wsa881x,
+				     NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Codec registration failed\n",
+			__func__);
+		goto dev_err;
+	}
+
+	return 0;
+
+dev_err:
+	if (pin_state_current == false)
+		wsa881x_gpio_ctrl(wsa881x, false);
+	swr_remove_device(pdev);
+err:
+	return ret;
+}
+
+static int wsa881x_swr_remove(struct swr_device *pdev)
+{
+	struct wsa881x_priv *wsa881x;
+
+	wsa881x = swr_get_dev_data(pdev);
+	if (!wsa881x) {
+		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	debugfs_remove_recursive(debugfs_wsa881x_dent);
+	debugfs_wsa881x_dent = NULL;
+	snd_soc_unregister_codec(&pdev->dev);
+	if (wsa881x->pd_gpio)
+		gpio_free(wsa881x->pd_gpio);
+	swr_set_dev_data(pdev, NULL);
+	return 0;
+}
+
+static int wsa881x_swr_up(struct swr_device *pdev)
+{
+	int ret;
+	struct wsa881x_priv *wsa881x;
+
+	wsa881x = swr_get_dev_data(pdev);
+	if (!wsa881x) {
+		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	ret = wsa881x_gpio_ctrl(wsa881x, true);
+	if (ret)
+		dev_err(&pdev->dev, "%s: Failed to enable gpio\n", __func__);
+	else
+		wsa881x->state = WSA881X_DEV_UP;
+
+	return ret;
+}
+
+static int wsa881x_swr_down(struct swr_device *pdev)
+{
+	struct wsa881x_priv *wsa881x;
+	int ret;
+
+	wsa881x = swr_get_dev_data(pdev);
+	if (!wsa881x) {
+		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (delayed_work_pending(&wsa881x->ocp_ctl_work))
+		cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
+	ret = wsa881x_gpio_ctrl(wsa881x, false);
+	if (ret)
+		dev_err(&pdev->dev, "%s: Failed to disable gpio\n", __func__);
+	else
+		wsa881x->state = WSA881X_DEV_DOWN;
+
+	return ret;
+}
+
+static int wsa881x_swr_reset(struct swr_device *pdev)
+{
+	struct wsa881x_priv *wsa881x;
+	u8 retry = WSA881X_NUM_RETRY;
+	u8 devnum = 0;
+
+	wsa881x = swr_get_dev_data(pdev);
+	if (!wsa881x) {
+		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	wsa881x->bg_cnt = 0;
+	wsa881x->clk_cnt = 0;
+	while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) {
+		/* Retry after 1 msec delay */
+		usleep_range(1000, 1100);
+	}
+	pdev->dev_num = devnum;
+	regcache_mark_dirty(wsa881x->regmap);
+	regcache_sync(wsa881x->regmap);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wsa881x_swr_suspend(struct device *dev)
+{
+	dev_dbg(dev, "%s: system suspend\n", __func__);
+	return 0;
+}
+
+static int wsa881x_swr_resume(struct device *dev)
+{
+	struct wsa881x_priv *wsa881x = swr_get_dev_data(to_swr_device(dev));
+
+	if (!wsa881x) {
+		dev_err(dev, "%s: wsa881x private data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_dbg(dev, "%s: system resume\n", __func__);
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops wsa881x_swr_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(wsa881x_swr_suspend, wsa881x_swr_resume)
+};
+
+static const struct swr_device_id wsa881x_swr_id[] = {
+	{"wsa881x", 0},
+	{}
+};
+
+static const struct of_device_id wsa881x_swr_dt_match[] = {
+	{
+		.compatible = "qcom,wsa881x",
+	},
+	{}
+};
+
+static struct swr_driver wsa881x_codec_driver = {
+	.driver = {
+		.name = "wsa881x",
+		.owner = THIS_MODULE,
+		.pm = &wsa881x_swr_pm_ops,
+		.of_match_table = wsa881x_swr_dt_match,
+	},
+	.probe = wsa881x_swr_probe,
+	.remove = wsa881x_swr_remove,
+	.id_table = wsa881x_swr_id,
+	.device_up = wsa881x_swr_up,
+	.device_down = wsa881x_swr_down,
+	.reset_device = wsa881x_swr_reset,
+};
+
+static int __init wsa881x_codec_init(void)
+{
+	return swr_driver_register(&wsa881x_codec_driver);
+}
+
+static void __exit wsa881x_codec_exit(void)
+{
+	swr_driver_unregister(&wsa881x_codec_driver);
+}
+
+module_init(wsa881x_codec_init);
+module_exit(wsa881x_codec_exit);
+
+MODULE_DESCRIPTION("WSA881x Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wsa881x.h b/asoc/codecs/wsa881x.h
new file mode 100644
index 0000000..be234ac
--- /dev/null
+++ b/asoc/codecs/wsa881x.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WSA881X_H
+#define _WSA881X_H
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/info.h>
+#include "wsa881x-registers.h"
+
+#define WSA881X_MAX_SWR_PORTS   4
+
+extern int wsa881x_set_channel_map(struct snd_soc_codec *codec, u8 *port,
+				u8 num_port, unsigned int *ch_mask,
+				unsigned int *ch_rate);
+
+extern const u8 wsa881x_reg_readable[WSA881X_CACHE_SIZE];
+extern struct regmap_config wsa881x_regmap_config;
+extern int wsa881x_codec_info_create_codec_entry(
+					struct snd_info_entry *codec_root,
+					struct snd_soc_codec *codec);
+void wsa881x_regmap_defaults(struct regmap *regmap, u8 version);
+
+#endif /* _WSA881X_H */