Merge "asoc: bolero: Update route map to enable MCLK for adie loopback"
diff --git a/Android.mk b/Android.mk
index b4278fa..c515dc5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,6 +32,8 @@
 ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE)),true)
 $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/bolero/Module.symvers)
 include $(MY_LOCAL_PATH)/asoc/codecs/bolero/Android.mk
+$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Module.symvers)
+include $(MY_LOCAL_PATH)/asoc/codecs/wcd937x/Android.mk
 endif
 
 ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true)
diff --git a/asoc/Android.mk b/asoc/Android.mk
index 26c898b..a5d1c7e 100644
--- a/asoc/Android.mk
+++ b/asoc/Android.mk
@@ -19,7 +19,7 @@
 endif
 
 ifeq ($(call is-board-platform,$(MSMSTEPPE)),true)
-TARGET := $(MSMSTEPPE)
+TARGET := talos
 AUDIO_SELECT  := CONFIG_SND_SOC_SM6150=m
 endif
 
diff --git a/asoc/codecs/Kbuild b/asoc/codecs/Kbuild
index 662c62f..45018ed 100644
--- a/asoc/codecs/Kbuild
+++ b/asoc/codecs/Kbuild
@@ -141,6 +141,10 @@
 	HDMICODEC_OBJS += msm_hdmi_codec_rx.o
 endif
 
+ifdef CONFIG_SND_SOC_WCD_IRQ
+	CORE_OBJS += wcd-irq.o
+endif
+
 LINUX_INC +=	-Iinclude/linux
 
 INCS +=		$(COMMON_INC) \
@@ -186,6 +190,7 @@
 	obj-y	+= sdm660_cdc/
 	obj-y	+= msm_sdw/
 	obj-y	+= wcd9360/
+	obj-y	+= wcd937x/
 endif
 # Module information used by KBuild framework
 obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd_core_dlkm.o
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index ea464c2..905a0ed 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -189,7 +189,8 @@
 };
 
 enum {
-	RX_MACRO_AIF1_PB = 0,
+	RX_MACRO_AIF_INVALID = 0,
+	RX_MACRO_AIF1_PB,
 	RX_MACRO_AIF2_PB,
 	RX_MACRO_AIF3_PB,
 	RX_MACRO_AIF4_PB,
@@ -1301,16 +1302,16 @@
 	switch (rx_port_value) {
 	case 0:
 		clear_bit(widget->shift,
-			&rx_priv->active_ch_mask[aif_rst - 1]);
-		rx_priv->active_ch_cnt[aif_rst - 1]--;
+			&rx_priv->active_ch_mask[aif_rst]);
+		rx_priv->active_ch_cnt[aif_rst]--;
 		break;
 	case 1:
 	case 2:
 	case 3:
 	case 4:
 		set_bit(widget->shift,
-			&rx_priv->active_ch_mask[rx_port_value - 1]);
-		rx_priv->active_ch_cnt[rx_port_value - 1]++;
+			&rx_priv->active_ch_mask[rx_port_value]);
+		rx_priv->active_ch_cnt[rx_port_value]++;
 		break;
 	default:
 		dev_err(codec->dev,
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index 5ad0e73..05642c9 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -80,7 +80,8 @@
 };
 
 enum {
-	TX_MACRO_AIF1_CAP = 0,
+	TX_MACRO_AIF_INVALID = 0,
+	TX_MACRO_AIF1_CAP,
 	TX_MACRO_AIF2_CAP,
 	TX_MACRO_MAX_DAIS
 };
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index 45e1dbb..53e01cc 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -53,7 +53,8 @@
 MODULE_PARM_DESC(va_tx_unmute_delay, "delay to unmute the tx path");
 
 enum {
-	VA_MACRO_AIF1_CAP = 0,
+	VA_MACRO_AIF_INVALID = 0,
+	VA_MACRO_AIF1_CAP,
 	VA_MACRO_AIF2_CAP,
 	VA_MACRO_MAX_DAIS,
 };
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index 5a7adb3..1f1af22 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -142,7 +142,8 @@
 };
 
 enum {
-	WSA_MACRO_AIF1_PB = 0,
+	WSA_MACRO_AIF_INVALID = 0,
+	WSA_MACRO_AIF1_PB,
 	WSA_MACRO_AIF_MIX1_PB,
 	WSA_MACRO_AIF_VI,
 	WSA_MACRO_AIF_ECHO,
@@ -1606,14 +1607,14 @@
 	switch (rx_port_value) {
 	case 0:
 		clear_bit(bit_input,
-			  &wsa_priv->active_ch_mask[aif_rst - 1]);
-		wsa_priv->active_ch_cnt[aif_rst - 1]--;
+			  &wsa_priv->active_ch_mask[aif_rst]);
+		wsa_priv->active_ch_cnt[aif_rst]--;
 		break;
 	case 1:
 	case 2:
 		set_bit(bit_input,
-			&wsa_priv->active_ch_mask[rx_port_value - 1]);
-		wsa_priv->active_ch_cnt[rx_port_value - 1]++;
+			&wsa_priv->active_ch_mask[rx_port_value]);
+		wsa_priv->active_ch_cnt[rx_port_value]++;
 		break;
 	default:
 		dev_err(wsa_dev,
diff --git a/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c b/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c
index 662f484..de4f399 100644
--- a/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -1011,10 +1011,12 @@
 {
 	struct wcd_dsp_cntl *cntl = container_of(filep->private_data,
 						 struct wcd_dsp_cntl, miscdev);
-	char val[WCD_MISCDEV_CMD_MAX_LEN];
+	char val[WCD_MISCDEV_CMD_MAX_LEN + 1];
 	bool vote;
 	int ret = 0;
 
+	memset(val, 0, WCD_MISCDEV_CMD_MAX_LEN + 1);
+
 	if (count == 0 || count > WCD_MISCDEV_CMD_MAX_LEN) {
 		pr_err("%s: Invalid count = %zd\n", __func__, count);
 		ret = -EINVAL;
diff --git a/asoc/codecs/wcd9360/wcd9360-dsp-cntl.c b/asoc/codecs/wcd9360/wcd9360-dsp-cntl.c
index 863024a..37536f8 100644
--- a/asoc/codecs/wcd9360/wcd9360-dsp-cntl.c
+++ b/asoc/codecs/wcd9360/wcd9360-dsp-cntl.c
@@ -894,10 +894,12 @@
 {
 	struct wcd_dsp_cntl *cntl = container_of(filep->private_data,
 						 struct wcd_dsp_cntl, miscdev);
-	char val[WCD_MISCDEV_CMD_MAX_LEN];
+	char val[WCD_MISCDEV_CMD_MAX_LEN + 1];
 	bool vote;
 	int ret = 0;
 
+	memset(val, 0, WCD_MISCDEV_CMD_MAX_LEN + 1);
+
 	if (count == 0 || count > WCD_MISCDEV_CMD_MAX_LEN) {
 		pr_err("%s: Invalid count = %zd\n", __func__, count);
 		ret = -EINVAL;
diff --git a/asoc/codecs/wcd937x/Android.mk b/asoc/codecs/wcd937x/Android.mk
new file mode 100644
index 0000000..51c4bc0
--- /dev/null
+++ b/asoc/codecs/wcd937x/Android.mk
@@ -0,0 +1,57 @@
+# Android makefile for audio kernel modules
+
+# Assume no targets will be supported
+
+# Check if this driver needs be built for current target
+ifeq ($(call is-board-platform,$(MSMSTEPPE)),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_SM6150=m
+endif
+
+AUDIO_CHIPSET := audio
+# Build/Package only in case of supported target
+ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile $(MSMSTEPPE)),true)
+
+LOCAL_PATH := $(call my-dir)
+
+# This makefile is only for DLKM
+ifneq ($(findstring vendor,$(LOCAL_PATH)),)
+
+ifneq ($(findstring opensource,$(LOCAL_PATH)),)
+	AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/vendor/qcom/opensource/audio-kernel
+endif # opensource
+
+DLKM_DIR := $(TOP)/device/qcom/common/dlkm
+
+# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko
+###########################################################
+# This is set once per LOCAL_PATH, not per (kernel) module
+KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR)
+
+# We are actually building audio.ko here, as per the
+# requirement we are specifying <chipset>_audio.ko as LOCAL_MODULE.
+# This means we need to rename the module to <chipset>_audio.ko
+# after audio.ko is built.
+KBUILD_OPTIONS += MODNAME=wcd937x_dlkm
+KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
+KBUILD_OPTIONS += $(AUDIO_SELECT)
+
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE              := $(AUDIO_CHIPSET)_wcd937x.ko
+LOCAL_MODULE_KBUILD_NAME  := wcd937x_dlkm.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE              := $(AUDIO_CHIPSET)_wcd937x_slave.ko
+LOCAL_MODULE_KBUILD_NAME  := wcd937x_slave_dlkm.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+
+endif # DLKM check
+endif # supported target check
diff --git a/asoc/codecs/wcd937x/Kbuild b/asoc/codecs/wcd937x/Kbuild
new file mode 100644
index 0000000..c3d8e38
--- /dev/null
+++ b/asoc/codecs/wcd937x/Kbuild
@@ -0,0 +1,113 @@
+# We can build either as part of a standalone Kernel build or as
+# an external module.  Determine which mechanism is being used
+ifeq ($(MODNAME),)
+	KERNEL_BUILD := 1
+else
+	KERNEL_BUILD := 0
+endif
+
+
+
+ifeq ($(KERNEL_BUILD), 1)
+	# These are configurable via Kconfig for kernel-based builds
+	# Need to explicitly configure for Android-based builds
+	AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.9
+	AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+	ifeq ($(CONFIG_ARCH_SM6150), y)
+		include $(AUDIO_ROOT)/config/sm6150auto.conf
+		export
+		INCS    +=  -include $(AUDIO_ROOT)/config/sm6150autoconf.h
+	endif
+endif
+
+# As per target team, build is done as follows:
+# Defconfig : build with default flags
+# Slub      : defconfig  + CONFIG_SLUB_DEBUG := y +
+#	      CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
+# Perf      : Using appropriate msmXXXX-perf_defconfig
+#
+# Shipment builds (user variants) should not have any debug feature
+# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
+# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
+# there is no other way to identify defconfig builds, QTI internal
+# representation of perf builds (identified using the string 'perf'),
+# is used to identify if the build is a slub or defconfig one. This
+# way no critical debug feature will be enabled for perf and shipment
+# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
+# config.
+
+############ UAPI ############
+UAPI_DIR :=	uapi
+UAPI_INC :=	-I$(AUDIO_ROOT)/include/$(UAPI_DIR)
+
+############ COMMON ############
+COMMON_DIR :=	include
+COMMON_INC :=	-I$(AUDIO_ROOT)/$(COMMON_DIR)
+
+############ WCD937X ############
+
+# for WCD937X Codec
+ifdef CONFIG_SND_SOC_WCD937X
+	WCD937X_OBJS += wcd937x.o
+	WCD937X_OBJS += wcd937x-regmap.o
+	WCD937X_OBJS += wcd937x-tables.o
+	WCD937X_OBJS += wcd937x-mbhc.o
+endif
+
+ifdef CONFIG_SND_SOC_WCD937X_SLAVE
+	WCD937X_SLAVE_OBJS += wcd937x_slave.o
+endif
+
+LINUX_INC +=	-Iinclude/linux
+
+INCS +=		$(COMMON_INC) \
+		$(UAPI_INC)
+
+EXTRA_CFLAGS += $(INCS)
+
+
+CDEFINES +=	-DANI_LITTLE_BYTE_ENDIAN \
+		-DANI_LITTLE_BIT_ENDIAN \
+		-DDOT11F_LITTLE_ENDIAN_HOST \
+		-DANI_COMPILER_TYPE_GCC \
+		-DANI_OS_TYPE_ANDROID=6 \
+		-DPTT_SOCK_SVC_ENABLE \
+		-Wall\
+		-Werror\
+		-D__linux__
+
+KBUILD_CPPFLAGS += $(CDEFINES)
+
+# Currently, for versions of gcc which support it, the kernel Makefile
+# is disabling the maybe-uninitialized warning.  Re-enable it for the
+# AUDIO driver.  Note that we must use EXTRA_CFLAGS here so that it
+# will override the kernel settings.
+ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
+EXTRA_CFLAGS += -Wmaybe-uninitialized
+endif
+#EXTRA_CFLAGS += -Wmissing-prototypes
+
+ifeq ($(call cc-option-yn, -Wheader-guard),y)
+EXTRA_CFLAGS += -Wheader-guard
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
+endif
+
+# Module information used by KBuild framework
+obj-$(CONFIG_SND_SOC_WCD937X) += wcd937x_dlkm.o
+wcd937x_dlkm-y := $(WCD937X_OBJS)
+
+obj-$(CONFIG_SND_SOC_WCD937X_SLAVE) += wcd937x_slave_dlkm.o
+wcd937x_slave_dlkm-y := $(WCD937X_SLAVE_OBJS)
+
+# inject some build related information
+DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
diff --git a/asoc/codecs/wcd937x/internal.h b/asoc/codecs/wcd937x/internal.h
new file mode 100644
index 0000000..ba1b626
--- /dev/null
+++ b/asoc/codecs/wcd937x/internal.h
@@ -0,0 +1,125 @@
+/* Copyright (c) 2018, 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 _WCD937X_INTERNAL_H
+#define _WCD937X_INTERNAL_H
+
+#include "../wcd-mbhc-v2.h"
+#include "asoc/wcd-irq.h"
+#include "wcd937x-mbhc.h"
+
+#define WCD937X_MAX_MICBIAS 3
+
+/* Convert from vout ctl to micbias voltage in mV */
+#define  WCD_VOUT_CTL_TO_MICB(v)  (1000 + v * 50)
+#define MAX_PORT 8
+#define MAX_CH_PER_PORT 8
+
+extern struct regmap_config wcd937x_regmap_config;
+
+struct codec_port_info {
+	u32 slave_port_type;
+	u32 master_port_type;
+	u32 ch_mask;
+	u32 num_ch;
+	u32 ch_rate;
+};
+struct wcd937x_priv {
+	struct device *dev;
+
+	int variant;
+	struct snd_soc_codec *codec;
+	struct device_node *rst_np;
+	struct regmap *regmap;
+
+	struct swr_device *rx_swr_dev;
+	struct swr_device *tx_swr_dev;
+
+	s32 micb_ref[WCD937X_MAX_MICBIAS];
+	s32 pullup_ref[WCD937X_MAX_MICBIAS];
+
+	struct fw_info *fw_data;
+	struct device_node *wcd_rst_np;
+
+	struct mutex micb_lock;
+	s32 dmic_0_1_clk_cnt;
+	s32 dmic_2_3_clk_cnt;
+	s32 dmic_4_5_clk_cnt;
+	/* mbhc module */
+	struct wcd937x_mbhc *mbhc;
+	struct blocking_notifier_head notifier;
+
+	u32 hph_mode;
+
+	struct irq_domain *virq;
+	struct wcd_irq_info *irq_info;
+	u32 rx_clk_cnt;
+	int num_irq_regs;
+
+	u8 num_tx_ports;
+	u8 num_rx_ports;
+	struct codec_port_info
+			tx_port_mapping[MAX_PORT][MAX_CH_PER_PORT];
+	struct codec_port_info
+			rx_port_mapping[MAX_PORT][MAX_CH_PER_PORT];
+};
+
+struct wcd937x_micbias_setting {
+	u8 ldoh_v;
+	u32 cfilt1_mv;
+	u32 micb2_mv;
+	u8 bias1_cfilt_sel;
+};
+
+struct wcd937x_pdata {
+	struct device_node *rst_np;
+	struct device_node *rx_slave;
+	struct device_node *tx_slave;
+	struct wcd937x_micbias_setting micbias;
+};
+
+enum {
+	/* INTR_CTRL_INT_MASK_0 */
+	WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET = 0,
+	WCD937X_IRQ_MBHC_BUTTON_PRESS_DET,
+	WCD937X_IRQ_MBHC_ELECT_INS_REM_DET,
+	WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	WCD937X_IRQ_MBHC_SW_DET,
+	WCD937X_IRQ_HPHR_OCP_INT,
+	WCD937X_IRQ_HPHR_CNP_INT,
+	WCD937X_IRQ_HPHL_OCP_INT,
+
+	/* INTR_CTRL_INT_MASK_1 */
+	WCD937X_IRQ_HPHL_CNP_INT,
+	WCD937X_IRQ_EAR_CNP_INT,
+	WCD937X_IRQ_EAR_SCD_INT,
+	WCD937X_IRQ_AUX_CNP_INT,
+	WCD937X_IRQ_AUX_SCD_INT,
+	WCD937X_IRQ_HPHL_PDM_WD_INT,
+	WCD937X_IRQ_HPHR_PDM_WD_INT,
+	WCD937X_IRQ_AUX_PDM_WD_INT,
+
+	/* INTR_CTRL_INT_MASK_2 */
+	WCD937X_IRQ_LDORT_SCD_INT,
+	WCD937X_IRQ_MBHC_MOISTURE_INT,
+	WCD937X_IRQ_HPHL_SURGE_DET_INT,
+	WCD937X_IRQ_HPHR_SURGE_DET_INT,
+	WCD937X_NUM_IRQS,
+};
+
+extern struct wcd937x_mbhc *wcd937x_soc_get_mbhc(struct snd_soc_codec *codec);
+extern int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_codec *codec,
+					int volt, int micb_num);
+extern int wcd937x_get_micb_vout_ctl_val(u32 micb_mv);
+extern int wcd937x_micbias_control(struct snd_soc_codec *codec, int micb_num,
+			int req, bool is_dapm);
+#endif
diff --git a/asoc/codecs/wcd937x/wcd937x-mbhc.c b/asoc/codecs/wcd937x/wcd937x-mbhc.c
new file mode 100644
index 0000000..d1a36ba
--- /dev/null
+++ b/asoc/codecs/wcd937x/wcd937x-mbhc.c
@@ -0,0 +1,1011 @@
+/* Copyright (c) 2018, 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 <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "wcd937x-registers.h"
+#include "../wcdcal-hwdep.h"
+#include "../wcd-mbhc-v2-api.h"
+#include "internal.h"
+
+#define WCD937X_ZDET_SUPPORTED          true
+/* Z value defined in milliohm */
+#define WCD937X_ZDET_VAL_32             32000
+#define WCD937X_ZDET_VAL_400            400000
+#define WCD937X_ZDET_VAL_1200           1200000
+#define WCD937X_ZDET_VAL_100K           100000000
+/* Z floating defined in ohms */
+#define WCD937X_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
+
+#define WCD937X_ZDET_NUM_MEASUREMENTS   900
+#define WCD937X_MBHC_GET_C1(c)          ((c & 0xC000) >> 14)
+#define WCD937X_MBHC_GET_X1(x)          (x & 0x3FFF)
+/* Z value compared in milliOhm */
+#define WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
+#define WCD937X_MBHC_ZDET_CONST         (86 * 16384)
+#define WCD937X_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",
+			  WCD937X_ANA_MBHC_MECH, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+			  WCD937X_ANA_MBHC_MECH, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+			  WCD937X_ANA_MBHC_MECH, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+			  WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x30, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+			  WCD937X_ANA_MBHC_ELECT, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+			  WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+			  WCD937X_ANA_MBHC_MECH, 0x04, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+			  WCD937X_ANA_MBHC_MECH, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+			  WCD937X_ANA_MBHC_MECH, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+			  WCD937X_ANA_MBHC_MECH, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+			  WCD937X_ANA_MBHC_ELECT, 0x06, 1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+			  WCD937X_ANA_MBHC_ELECT, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+			  WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+			  WCD937X_MBHC_NEW_CTL_1, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+			  WCD937X_MBHC_NEW_CTL_2, 0x03, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+			  WCD937X_ANA_MBHC_RESULT_3, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+			  WCD937X_ANA_MBHC_RESULT_3, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+			  WCD937X_ANA_MBHC_RESULT_3, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+			  WCD937X_ANA_MBHC_RESULT_3, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+			  WCD937X_HPH_OCP_CTL, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+			  WCD937X_ANA_MBHC_RESULT_3, 0x07, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+			  WCD937X_ANA_MBHC_ELECT, 0x70, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+			  WCD937X_ANA_MBHC_RESULT_3, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+			  WCD937X_ANA_MICB2, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+			  WCD937X_HPH_CNP_WG_TIME, 0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+			  WCD937X_ANA_HPH, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+			  WCD937X_ANA_HPH, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+			  WCD937X_ANA_HPH, 0xC0, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+			  WCD937X_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",
+			  WCD937X_MBHC_CTL_BCS, 0x02, 1, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
+			  WCD937X_MBHC_NEW_FSM_STATUS, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
+			  WCD937X_MBHC_NEW_CTL_2, 0x70, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS",
+			  WCD937X_MBHC_NEW_FSM_STATUS, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND",
+			  WCD937X_HPH_PA_CTL2, 0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND",
+			  WCD937X_HPH_PA_CTL2, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN",
+			  WCD937X_HPH_L_TEST, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN",
+			  WCD937X_HPH_R_TEST, 0x01, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS",
+			  WCD937X_DIGITAL_INTR_STATUS_0, 0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS",
+			  WCD937X_DIGITAL_INTR_STATUS_0, 0x20, 5, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN",
+			  WCD937X_MBHC_NEW_CTL_1, 0x08, 3, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD937X_MBHC_NEW_FSM_STATUS,
+			  0x40, 6, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD937X_MBHC_NEW_FSM_STATUS,
+			  0x80, 7, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD937X_MBHC_NEW_ADC_RESULT,
+			  0xFF, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD937X_ANA_MICB1, 0x3F, 0, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE",
+			  WCD937X_MBHC_NEW_CTL_1, 0x10, 4, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE",
+			  WCD937X_MBHC_NEW_CTL_1, 0x04, 2, 0),
+	WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN",
+			  WCD937X_ANA_MBHC_ZDET, 0x02, 1, 0),
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+	.mbhc_sw_intr =  WCD937X_IRQ_MBHC_SW_DET,
+	.mbhc_btn_press_intr = WCD937X_IRQ_MBHC_BUTTON_PRESS_DET,
+	.mbhc_btn_release_intr = WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET,
+	.mbhc_hs_ins_intr = WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	.mbhc_hs_rem_intr = WCD937X_IRQ_MBHC_ELECT_INS_REM_DET,
+	.hph_left_ocp = WCD937X_IRQ_HPHL_OCP_INT,
+	.hph_right_ocp = WCD937X_IRQ_HPHR_OCP_INT,
+};
+
+struct wcd937x_mbhc_zdet_param {
+	u16 ldo_ctl;
+	u16 noff;
+	u16 nshift;
+	u16 btn5;
+	u16 btn6;
+	u16 btn7;
+};
+
+static int wcd937x_mbhc_request_irq(struct snd_soc_codec *codec,
+				  int irq, irq_handler_t handler,
+				  const char *name, void *data)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(codec->dev);
+
+	return wcd_request_irq(wcd937x->irq_info, irq, name, handler, data);
+}
+
+static void wcd937x_mbhc_irq_control(struct snd_soc_codec *codec,
+				   int irq, bool enable)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(codec->dev);
+
+	if (enable)
+		wcd_enable_irq(wcd937x->irq_info, irq);
+	else
+		wcd_disable_irq(wcd937x->irq_info, irq);
+}
+
+static int wcd937x_mbhc_free_irq(struct snd_soc_codec *codec,
+			       int irq, void *data)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(codec->dev);
+
+	wcd_free_irq(wcd937x->irq_info, irq, data);
+
+	return 0;
+}
+
+static void wcd937x_mbhc_clk_setup(struct snd_soc_codec *codec,
+				 bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD937X_MBHC_NEW_CTL_1,
+				    0x80, 0x80);
+	else
+		snd_soc_update_bits(codec, WCD937X_MBHC_NEW_CTL_1,
+				    0x80, 0x00);
+}
+
+static int wcd937x_mbhc_btn_to_num(struct snd_soc_codec *codec)
+{
+	return snd_soc_read(codec, WCD937X_ANA_MBHC_RESULT_3) & 0x7;
+}
+
+static void wcd937x_mbhc_mbhc_bias_control(struct snd_soc_codec *codec,
+					 bool enable)
+{
+	if (enable)
+		snd_soc_update_bits(codec, WCD937X_ANA_MBHC_ELECT,
+				    0x01, 0x01);
+	else
+		snd_soc_update_bits(codec, WCD937X_ANA_MBHC_ELECT,
+				    0x01, 0x00);
+}
+
+static void wcd937x_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;
+	}
+
+	for (i = 0; i < num_btn; i++) {
+		vth = ((btn_high[i] * 2) / 25) & 0x3F;
+		snd_soc_update_bits(codec, WCD937X_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 wcd937x_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+	return true;
+}
+
+static int wcd937x_mbhc_register_notifier(struct wcd_mbhc *mbhc,
+					struct notifier_block *nblock,
+					bool enable)
+{
+	struct wcd937x_mbhc *wcd937x_mbhc;
+
+	wcd937x_mbhc = container_of(mbhc, struct wcd937x_mbhc, wcd_mbhc);
+
+	if (enable)
+		return blocking_notifier_chain_register(&wcd937x_mbhc->notifier,
+							nblock);
+	else
+		return blocking_notifier_chain_unregister(
+				&wcd937x_mbhc->notifier, nblock);
+}
+
+static bool wcd937x_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+	u8 val = 0;
+
+	if (micb_num == MIC_BIAS_2) {
+		val = ((snd_soc_read(mbhc->codec, WCD937X_ANA_MICB2) & 0xC0)
+			>> 6);
+		if (val == 0x01)
+			return true;
+	}
+	return false;
+}
+
+static bool wcd937x_mbhc_hph_pa_on_status(struct snd_soc_codec *codec)
+{
+	return (snd_soc_read(codec, WCD937X_ANA_HPH) & 0xC0) ? true : false;
+}
+
+static void wcd937x_mbhc_hph_l_pull_up_control(struct snd_soc_codec *codec,
+					       int pull_up_cur)
+{
+	/* Default pull up current to 2uA */
+	if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA ||
+	    pull_up_cur == HS_PULLUP_I_DEFAULT)
+		pull_up_cur = HS_PULLUP_I_2P0_UA;
+
+	dev_dbg(codec->dev, "%s: HS pull up current:%d\n",
+		__func__, pull_up_cur);
+
+	snd_soc_update_bits(codec, WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT,
+			    0x1F, pull_up_cur);
+}
+
+static int wcd937x_mbhc_request_micbias(struct snd_soc_codec *codec,
+					int micb_num, int req)
+{
+	int ret = 0;
+
+	ret = wcd937x_micbias_control(codec, micb_num, req, false);
+
+	return ret;
+}
+
+static void wcd937x_mbhc_micb_ramp_control(struct snd_soc_codec *codec,
+					   bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD937X_ANA_MICB2_RAMP,
+				    0x1C, 0x0C);
+		snd_soc_update_bits(codec, WCD937X_ANA_MICB2_RAMP,
+				    0x80, 0x80);
+	} else {
+		snd_soc_update_bits(codec, WCD937X_ANA_MICB2_RAMP,
+				    0x80, 0x00);
+		snd_soc_update_bits(codec, WCD937X_ANA_MICB2_RAMP,
+				    0x1C, 0x00);
+	}
+}
+
+static struct firmware_cal *wcd937x_get_hwdep_fw_cal(struct wcd_mbhc *mbhc,
+						   enum wcd_cal_type type)
+{
+	struct wcd937x_mbhc *wcd937x_mbhc;
+	struct firmware_cal *hwdep_cal;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	wcd937x_mbhc = container_of(mbhc, struct wcd937x_mbhc, wcd_mbhc);
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer\n", __func__);
+		return NULL;
+	}
+	hwdep_cal = wcdcal_get_fw_cal(wcd937x_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 wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_codec *codec,
+					      int micb_num, bool req_en)
+{
+	struct wcd937x_pdata *pdata = dev_get_platdata(codec->dev);
+	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 = wcd937x_mbhc_micb_adjust_voltage(codec, micb_mv, MIC_BIAS_2);
+
+	return rc;
+}
+
+static inline void wcd937x_mbhc_get_result_params(struct wcd937x_priv *wcd937x,
+						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(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x20);
+	for (i = 0; i < WCD937X_ZDET_NUM_MEASUREMENTS; i++) {
+		regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_2, &val);
+		if (val & 0x80)
+			break;
+	}
+	val = val << 0x8;
+	regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_1, &val1);
+	val |= val1;
+	regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x00);
+	x1 = WCD937X_MBHC_GET_X1(val);
+	c1 = WCD937X_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(wcd937x->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 = (WCD937X_MBHC_ZDET_CONST * 1000) / denom;
+	else if (x1 < minCode_param[noff])
+		*zdet = WCD937X_ZDET_FLOATING_IMPEDANCE;
+
+	dev_dbg(wcd937x->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(wcd937x->regmap,
+				 WCD937X_ANA_MBHC_RESULT_1, (u8 *)&val, 2);
+		x1 = WCD937X_MBHC_GET_X1(val);
+		i++;
+		if (i == WCD937X_ZDET_NUM_MEASUREMENTS)
+			break;
+	}
+}
+
+static void wcd937x_mbhc_zdet_ramp(struct snd_soc_codec *codec,
+				 struct wcd937x_mbhc_zdet_param *zdet_param,
+				 int32_t *zl, int32_t *zr, s16 *d1_a)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(codec->dev);
+	int32_t zdet = 0;
+
+	snd_soc_update_bits(codec, WCD937X_MBHC_NEW_ZDET_ANA_CTL, 0x70,
+			    zdet_param->ldo_ctl << 4);
+	snd_soc_update_bits(codec, WCD937X_ANA_MBHC_BTN5, 0xFC,
+			    zdet_param->btn5);
+	snd_soc_update_bits(codec, WCD937X_ANA_MBHC_BTN6, 0xFC,
+			    zdet_param->btn6);
+	snd_soc_update_bits(codec, WCD937X_ANA_MBHC_BTN7, 0xFC,
+			    zdet_param->btn7);
+	snd_soc_update_bits(codec, WCD937X_MBHC_NEW_ZDET_ANA_CTL, 0x0F,
+			    zdet_param->noff);
+	snd_soc_update_bits(codec, WCD937X_MBHC_NEW_ZDET_RAMP_CTL, 0x0F,
+			    zdet_param->nshift);
+
+	if (!zl)
+		goto z_right;
+	/* Start impedance measurement for HPH_L */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x80, 0x80);
+	dev_dbg(wcd937x->dev, "%s: ramp for HPH_L, noff = %d\n",
+		__func__, zdet_param->noff);
+	wcd937x_mbhc_get_result_params(wcd937x, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x80, 0x00);
+
+	*zl = zdet;
+
+z_right:
+	if (!zr)
+		return;
+	/* Start impedance measurement for HPH_R */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x40, 0x40);
+	dev_dbg(wcd937x->dev, "%s: ramp for HPH_R, noff = %d\n",
+		__func__, zdet_param->noff);
+	wcd937x_mbhc_get_result_params(wcd937x, d1_a, zdet_param->noff, &zdet);
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_ZDET, 0x40, 0x00);
+
+	*zr = zdet;
+}
+
+static inline void wcd937x_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 < (WCD937X_ZDET_VAL_400/1000))
+		q1 = snd_soc_read(codec,
+			WCD937X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
+	else
+		q1 = snd_soc_read(codec,
+			WCD937X_DIGITAL_EFUSE_REG_24 + (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 wcd937x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
+					  uint32_t *zr)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(codec->dev);
+	s16 reg0, reg1, reg2, reg3, reg4;
+	int32_t z1L, z1R, z1Ls;
+	int zMono, z_diff1, z_diff2;
+	bool is_fsm_disable = false;
+	struct wcd937x_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 wcd937x_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, WCD937X_ANA_MBHC_BTN5);
+	reg1 = snd_soc_read(codec, WCD937X_ANA_MBHC_BTN6);
+	reg2 = snd_soc_read(codec, WCD937X_ANA_MBHC_BTN7);
+	reg3 = snd_soc_read(codec, WCD937X_MBHC_CTL_CLK);
+	reg4 = snd_soc_read(codec, WCD937X_MBHC_NEW_ZDET_ANA_CTL);
+
+	if (snd_soc_read(codec, WCD937X_ANA_MBHC_ELECT) & 0x80) {
+		is_fsm_disable = true;
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_ELECT, 0x80, 0x00);
+	}
+
+	/* For NO-jack, disable L_DET_EN before Z-det measurements */
+	if (mbhc->hphl_swh)
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_MECH, 0x80, 0x00);
+
+	/* Turn off 100k pull down on HPHL */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_MECH, 0x01, 0x00);
+
+	/* First get impedance on Left */
+	d1 = d1_a[1];
+	zdet_param_ptr = &zdet_param[1];
+	wcd937x_mbhc_zdet_ramp(codec, zdet_param_ptr, &z1L, NULL, d1);
+
+	if (!WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1L))
+		goto left_ch_impedance;
+
+	/* Second ramp for left ch */
+	if (z1L < WCD937X_ZDET_VAL_32) {
+		zdet_param_ptr = &zdet_param[0];
+		d1 = d1_a[0];
+	} else if ((z1L > WCD937X_ZDET_VAL_400) &&
+		  (z1L <= WCD937X_ZDET_VAL_1200)) {
+		zdet_param_ptr = &zdet_param[2];
+		d1 = d1_a[2];
+	} else if (z1L > WCD937X_ZDET_VAL_1200) {
+		zdet_param_ptr = &zdet_param[3];
+		d1 = d1_a[3];
+	}
+	wcd937x_mbhc_zdet_ramp(codec, zdet_param_ptr, &z1L, NULL, d1);
+
+left_ch_impedance:
+	if ((z1L == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+		(z1L > WCD937X_ZDET_VAL_100K)) {
+		*zl = WCD937X_ZDET_FLOATING_IMPEDANCE;
+		zdet_param_ptr = &zdet_param[1];
+		d1 = d1_a[1];
+	} else {
+		*zl = z1L/1000;
+		wcd937x_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 */
+	wcd937x_mbhc_zdet_ramp(codec, zdet_param_ptr, NULL, &z1R, d1);
+	if (WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) {
+		if (((z1R > WCD937X_ZDET_VAL_1200) &&
+			(zdet_param_ptr->noff == 0x6)) ||
+			((*zl) != WCD937X_ZDET_FLOATING_IMPEDANCE))
+			goto right_ch_impedance;
+		/* Second ramp for right ch */
+		if (z1R < WCD937X_ZDET_VAL_32) {
+			zdet_param_ptr = &zdet_param[0];
+			d1 = d1_a[0];
+		} else if ((z1R > WCD937X_ZDET_VAL_400) &&
+			(z1R <= WCD937X_ZDET_VAL_1200)) {
+			zdet_param_ptr = &zdet_param[2];
+			d1 = d1_a[2];
+		} else if (z1R > WCD937X_ZDET_VAL_1200) {
+			zdet_param_ptr = &zdet_param[3];
+			d1 = d1_a[3];
+		}
+		wcd937x_mbhc_zdet_ramp(codec, zdet_param_ptr, NULL, &z1R, d1);
+	}
+right_ch_impedance:
+	if ((z1R == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+		(z1R > WCD937X_ZDET_VAL_100K)) {
+		*zr = WCD937X_ZDET_FLOATING_IMPEDANCE;
+	} else {
+		*zr = z1R/1000;
+		wcd937x_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 == WCD937X_ZDET_FLOATING_IMPEDANCE) &&
+		(*zr == WCD937X_ZDET_FLOATING_IMPEDANCE)) {
+		dev_dbg(codec->dev,
+			"%s: plug type is invalid or extension cable\n",
+			__func__);
+		goto zdet_complete;
+	}
+	if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+	    (*zr == WCD937X_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, WCD937X_HPH_R_ATEST, 0x02, 0x02);
+	snd_soc_update_bits(codec, WCD937X_HPH_PA_CTL2, 0x40, 0x01);
+	if (*zl < (WCD937X_ZDET_VAL_32/1000))
+		wcd937x_mbhc_zdet_ramp(codec, &zdet_param[0], &z1Ls, NULL, d1);
+	else
+		wcd937x_mbhc_zdet_ramp(codec, &zdet_param[1], &z1Ls, NULL, d1);
+	snd_soc_update_bits(codec, WCD937X_HPH_PA_CTL2, 0x40, 0x00);
+	snd_soc_update_bits(codec, WCD937X_HPH_R_ATEST, 0x02, 0x00);
+	z1Ls /= 1000;
+	wcd937x_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, WCD937X_ANA_MBHC_BTN5, reg0);
+	snd_soc_write(codec, WCD937X_ANA_MBHC_BTN6, reg1);
+	snd_soc_write(codec, WCD937X_ANA_MBHC_BTN7, reg2);
+	/* Turn on 100k pull down on HPHL */
+	regmap_update_bits(wcd937x->regmap,
+			   WCD937X_ANA_MBHC_MECH, 0x01, 0x01);
+
+	/* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+	if (mbhc->hphl_swh)
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_MECH, 0x80, 0x80);
+
+	snd_soc_write(codec, WCD937X_MBHC_NEW_ZDET_ANA_CTL, reg4);
+	snd_soc_write(codec, WCD937X_MBHC_CTL_CLK, reg3);
+	if (is_fsm_disable)
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+
+static void wcd937x_mbhc_gnd_det_ctrl(struct snd_soc_codec *codec, bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD937X_ANA_MBHC_MECH,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_ANA_MBHC_MECH,
+				    0x40, 0x40);
+	} else {
+		snd_soc_update_bits(codec, WCD937X_ANA_MBHC_MECH,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, WCD937X_ANA_MBHC_MECH,
+				    0x02, 0x00);
+	}
+}
+
+static void wcd937x_mbhc_hph_pull_down_ctrl(struct snd_soc_codec *codec,
+					  bool enable)
+{
+	if (enable) {
+		snd_soc_update_bits(codec, WCD937X_HPH_PA_CTL2,
+				    0x40, 0x40);
+		snd_soc_update_bits(codec, WCD937X_HPH_PA_CTL2,
+				    0x10, 0x10);
+	} else {
+		snd_soc_update_bits(codec, WCD937X_HPH_PA_CTL2,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, WCD937X_HPH_PA_CTL2,
+				    0x10, 0x00);
+	}
+}
+
+static void wcd937x_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, WCD937X_MBHC_NEW_CTL_2,
+				    0x0C, R_OFF << 2);
+		return;
+	}
+
+	/* Do not 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, WCD937X_MBHC_NEW_CTL_2,
+				    0x0C, R_OFF << 2);
+		return;
+	}
+
+	snd_soc_update_bits(codec, WCD937X_MBHC_NEW_CTL_2,
+			    0x0C, mbhc->moist_rref << 2);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+	.request_irq = wcd937x_mbhc_request_irq,
+	.irq_control = wcd937x_mbhc_irq_control,
+	.free_irq = wcd937x_mbhc_free_irq,
+	.clk_setup = wcd937x_mbhc_clk_setup,
+	.map_btn_code_to_num = wcd937x_mbhc_btn_to_num,
+	.mbhc_bias = wcd937x_mbhc_mbhc_bias_control,
+	.set_btn_thr = wcd937x_mbhc_program_btn_thr,
+	.lock_sleep = wcd937x_mbhc_lock_sleep,
+	.register_notifier = wcd937x_mbhc_register_notifier,
+	.micbias_enable_status = wcd937x_mbhc_micb_en_status,
+	.hph_pa_on_status = wcd937x_mbhc_hph_pa_on_status,
+	.hph_pull_up_control_v2 = wcd937x_mbhc_hph_l_pull_up_control,
+	.mbhc_micbias_control = wcd937x_mbhc_request_micbias,
+	.mbhc_micb_ramp_control = wcd937x_mbhc_micb_ramp_control,
+	.get_hwdep_fw_cal = wcd937x_get_hwdep_fw_cal,
+	.mbhc_micb_ctrl_thr_mic = wcd937x_mbhc_micb_ctrl_threshold_mic,
+	.compute_impedance = wcd937x_wcd_mbhc_calc_impedance,
+	.mbhc_gnd_det_ctrl = wcd937x_mbhc_gnd_det_ctrl,
+	.hph_pull_down_ctrl = wcd937x_mbhc_hph_pull_down_ctrl,
+	.mbhc_moisture_config = wcd937x_mbhc_moisture_config,
+};
+
+static int wcd937x_get_hph_type(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wcd937x_mbhc *wcd937x_mbhc = wcd937x_soc_get_mbhc(codec);
+	struct wcd_mbhc *mbhc;
+
+	if (!wcd937x_mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__);
+		return -EINVAL;
+	}
+
+	mbhc = &wcd937x_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 wcd937x_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 wcd937x_mbhc *wcd937x_mbhc = wcd937x_soc_get_mbhc(codec);
+
+	if (!wcd937x_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(&wcd937x_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,
+		       wcd937x_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+		       wcd937x_hph_impedance_get, NULL),
+	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+		       wcd937x_hph_impedance_get, NULL),
+};
+
+/*
+ * wcd937x_mbhc_get_impedance: get impedance of headphone
+ * left and right channels
+ * @wcd937x_mbhc: handle to struct wcd937x_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 wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc,
+			     uint32_t *zl, uint32_t *zr)
+{
+	if (!wcd937x_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(&wcd937x_mbhc->wcd_mbhc, zl, zr);
+}
+EXPORT_SYMBOL(wcd937x_mbhc_get_impedance);
+
+/*
+ * wcd937x_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 wcd937x_mbhc_hs_detect(struct snd_soc_codec *codec,
+			 struct wcd_mbhc_config *mbhc_cfg)
+{
+	struct wcd937x_priv *wcd937x = NULL;
+	struct wcd937x_mbhc *wcd937x_mbhc = NULL;
+
+	if (!codec) {
+		pr_err("%s: codec is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd937x = snd_soc_codec_get_drvdata(codec);
+	if (!wcd937x) {
+		pr_err("%s: wcd937x is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd937x_mbhc = wcd937x->mbhc;
+	if (!wcd937x_mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__);
+		return -EINVAL;
+	}
+
+	return wcd_mbhc_start(&wcd937x_mbhc->wcd_mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(wcd937x_mbhc_hs_detect);
+
+/*
+ * wcd937x_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality
+ * @codec: handle to snd_soc_codec *
+ */
+void wcd937x_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct wcd937x_priv *wcd937x = NULL;
+	struct wcd937x_mbhc *wcd937x_mbhc = NULL;
+
+	if (!codec) {
+		pr_err("%s: codec is NULL\n", __func__);
+		return;
+	}
+
+	wcd937x = snd_soc_codec_get_drvdata(codec);
+	if (!wcd937x) {
+		pr_err("%s: wcd937x is NULL\n", __func__);
+		return;
+	}
+
+	wcd937x_mbhc = wcd937x->mbhc;
+	if (!wcd937x_mbhc) {
+		dev_err(codec->dev, "%s: mbhc not initialized!\n", __func__);
+		return;
+	}
+	wcd_mbhc_stop(&wcd937x_mbhc->wcd_mbhc);
+}
+EXPORT_SYMBOL(wcd937x_mbhc_hs_detect_exit);
+
+/*
+ * wcd937x_mbhc_post_ssr_init: initialize mbhc for
+ * wcd937x post subsystem restart
+ * @mbhc: poniter to wcd937x_mbhc structure
+ * @codec: handle to snd_soc_codec *
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc,
+			     struct snd_soc_codec *codec)
+{
+	int ret = 0;
+	struct wcd_mbhc *wcd_mbhc = NULL;
+
+	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, WCD937X_ZDET_SUPPORTED);
+	if (ret) {
+		dev_err(codec->dev, "%s: mbhc initialization failed\n",
+			__func__);
+		goto done;
+	}
+
+done:
+	return ret;
+}
+EXPORT_SYMBOL(wcd937x_mbhc_post_ssr_init);
+
+/*
+ * wcd937x_mbhc_init: initialize mbhc for wcd937x
+ * @mbhc: poniter to wcd937x_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 wcd937x_mbhc_init(struct wcd937x_mbhc **mbhc, struct snd_soc_codec *codec,
+		    struct fw_info *fw_data)
+{
+	struct wcd937x_mbhc *wcd937x_mbhc = NULL;
+	struct wcd_mbhc *wcd_mbhc = NULL;
+	int ret = 0;
+
+	if (!codec) {
+		pr_err("%s: codec is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd937x_mbhc = devm_kzalloc(codec->dev, sizeof(struct wcd937x_mbhc),
+				    GFP_KERNEL);
+	if (!wcd937x_mbhc)
+		return -ENOMEM;
+
+	wcd937x_mbhc->fw_data = fw_data;
+	BLOCKING_INIT_NOTIFIER_HEAD(&wcd937x_mbhc->notifier);
+	wcd_mbhc = &wcd937x_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 */
+	wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
+
+	ret = wcd_mbhc_init(wcd_mbhc, codec, &mbhc_cb,
+				&intr_ids, wcd_mbhc_registers,
+				WCD937X_ZDET_SUPPORTED);
+	if (ret) {
+		dev_err(codec->dev, "%s: mbhc initialization failed\n",
+			__func__);
+		goto err;
+	}
+
+	(*mbhc) = wcd937x_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));
+
+	return 0;
+err:
+	devm_kfree(codec->dev, wcd937x_mbhc);
+	return ret;
+}
+EXPORT_SYMBOL(wcd937x_mbhc_init);
+
+/*
+ * wcd937x_mbhc_deinit: deinitialize mbhc for wcd937x
+ * @codec: handle to snd_soc_codec *
+ */
+void wcd937x_mbhc_deinit(struct snd_soc_codec *codec)
+{
+	struct wcd937x_priv *wcd937x;
+	struct wcd937x_mbhc *wcd937x_mbhc;
+
+	if (!codec) {
+		pr_err("%s: codec is NULL\n", __func__);
+		return;
+	}
+
+	wcd937x = snd_soc_codec_get_drvdata(codec);
+	if (!wcd937x) {
+		pr_err("%s: wcd937x is NULL\n", __func__);
+		return;
+	}
+
+	wcd937x_mbhc = wcd937x->mbhc;
+	if (wcd937x_mbhc) {
+		wcd_mbhc_deinit(&wcd937x_mbhc->wcd_mbhc);
+		devm_kfree(codec->dev, wcd937x_mbhc);
+	}
+}
+EXPORT_SYMBOL(wcd937x_mbhc_deinit);
diff --git a/asoc/codecs/wcd937x/wcd937x-mbhc.h b/asoc/codecs/wcd937x/wcd937x-mbhc.h
new file mode 100644
index 0000000..648d81c
--- /dev/null
+++ b/asoc/codecs/wcd937x/wcd937x-mbhc.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2018, 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 __WCD937X_MBHC_H__
+#define __WCD937X_MBHC_H__
+#include "../wcd-mbhc-v2.h"
+
+struct wcd937x_mbhc {
+	struct wcd_mbhc wcd_mbhc;
+	struct blocking_notifier_head notifier;
+	struct fw_info *fw_data;
+	bool mbhc_started;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD937X)
+extern int wcd937x_mbhc_init(struct wcd937x_mbhc **mbhc,
+			   struct snd_soc_codec *codec,
+			   struct fw_info *fw_data);
+extern void wcd937x_mbhc_hs_detect_exit(struct snd_soc_codec *codec);
+extern int wcd937x_mbhc_hs_detect(struct snd_soc_codec *codec,
+				struct wcd_mbhc_config *mbhc_cfg);
+extern void wcd937x_mbhc_deinit(struct snd_soc_codec *codec);
+extern int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc,
+				    struct snd_soc_codec *codec);
+extern int wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc,
+				    uint32_t *zl, uint32_t *zr);
+#else
+static inline int wcd937x_mbhc_init(struct wcd937x_mbhc **mbhc,
+				  struct snd_soc_codec *codec,
+				  struct fw_info *fw_data)
+{
+	return 0;
+}
+static inline void wcd937x_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+}
+static inline int wcd937x_mbhc_hs_detect(struct snd_soc_codec *codec,
+				       struct wcd_mbhc_config *mbhc_cfg)
+{
+		return 0;
+}
+static inline void wcd937x_mbhc_deinit(struct snd_soc_codec *codec)
+{
+}
+static inline int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc,
+					   struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static inline int wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc,
+					   uint32_t *zl, uint32_t *zr)
+{
+	if (zl)
+		*zl = 0;
+	if (zr)
+		*zr = 0;
+	return -EINVAL;
+}
+#endif
+
+#endif /* __WCD937X_MBHC_H__ */
diff --git a/asoc/codecs/wcd937x/wcd937x-registers.h b/asoc/codecs/wcd937x/wcd937x-registers.h
new file mode 100644
index 0000000..1f89f80
--- /dev/null
+++ b/asoc/codecs/wcd937x/wcd937x-registers.h
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2018, 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 _WCD937X_REGISTERS_H
+#define _WCD937X_REGISTERS_H
+
+#define WCD937X_BASE_ADDRESS 0x3000
+
+#define WCD937X_REG(reg)  (reg - WCD937X_BASE_ADDRESS)
+
+enum {
+	REG_NO_ACCESS,
+	RD_REG,
+	WR_REG,
+	RD_WR_REG
+};
+
+#define WCD937X_ANA_BIAS                            (WCD937X_BASE_ADDRESS+0x001)
+#define WCD937X_ANA_RX_SUPPLIES                     (WCD937X_BASE_ADDRESS+0x008)
+#define WCD937X_ANA_HPH                             (WCD937X_BASE_ADDRESS+0x009)
+#define WCD937X_ANA_EAR                             (WCD937X_BASE_ADDRESS+0x00A)
+#define WCD937X_ANA_EAR_COMPANDER_CTL               (WCD937X_BASE_ADDRESS+0x00B)
+#define WCD937X_ANA_TX_CH1                          (WCD937X_BASE_ADDRESS+0x00E)
+#define WCD937X_ANA_TX_CH2                          (WCD937X_BASE_ADDRESS+0x00F)
+#define WCD937X_ANA_TX_CH3                          (WCD937X_BASE_ADDRESS+0x010)
+#define WCD937X_ANA_TX_CH3_HPF                      (WCD937X_BASE_ADDRESS+0x011)
+#define WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC        (WCD937X_BASE_ADDRESS+0x012)
+#define WCD937X_ANA_MICB3_DSP_EN_LOGIC              (WCD937X_BASE_ADDRESS+0x013)
+#define WCD937X_ANA_MBHC_MECH                       (WCD937X_BASE_ADDRESS+0x014)
+#define WCD937X_ANA_MBHC_ELECT                      (WCD937X_BASE_ADDRESS+0x015)
+#define WCD937X_ANA_MBHC_ZDET                       (WCD937X_BASE_ADDRESS+0x016)
+#define WCD937X_ANA_MBHC_RESULT_1                   (WCD937X_BASE_ADDRESS+0x017)
+#define WCD937X_ANA_MBHC_RESULT_2                   (WCD937X_BASE_ADDRESS+0x018)
+#define WCD937X_ANA_MBHC_RESULT_3                   (WCD937X_BASE_ADDRESS+0x019)
+#define WCD937X_ANA_MBHC_BTN0                       (WCD937X_BASE_ADDRESS+0x01A)
+#define WCD937X_ANA_MBHC_BTN1                       (WCD937X_BASE_ADDRESS+0x01B)
+#define WCD937X_ANA_MBHC_BTN2                       (WCD937X_BASE_ADDRESS+0x01C)
+#define WCD937X_ANA_MBHC_BTN3                       (WCD937X_BASE_ADDRESS+0x01D)
+#define WCD937X_ANA_MBHC_BTN4                       (WCD937X_BASE_ADDRESS+0x01E)
+#define WCD937X_ANA_MBHC_BTN5                       (WCD937X_BASE_ADDRESS+0x01F)
+#define WCD937X_ANA_MBHC_BTN6                       (WCD937X_BASE_ADDRESS+0x020)
+#define WCD937X_ANA_MBHC_BTN7                       (WCD937X_BASE_ADDRESS+0x021)
+#define WCD937X_ANA_MICB1                           (WCD937X_BASE_ADDRESS+0x022)
+#define WCD937X_ANA_MICB2                           (WCD937X_BASE_ADDRESS+0x023)
+#define WCD937X_ANA_MICB2_RAMP                      (WCD937X_BASE_ADDRESS+0x024)
+#define WCD937X_ANA_MICB3                           (WCD937X_BASE_ADDRESS+0x025)
+#define WCD937X_BIAS_CTL                            (WCD937X_BASE_ADDRESS+0x028)
+#define WCD937X_BIAS_VBG_FINE_ADJ                   (WCD937X_BASE_ADDRESS+0x029)
+#define WCD937X_LDOL_VDDCX_ADJUST                   (WCD937X_BASE_ADDRESS+0x040)
+#define WCD937X_LDOL_DISABLE_LDOL                   (WCD937X_BASE_ADDRESS+0x041)
+#define WCD937X_MBHC_CTL_CLK                        (WCD937X_BASE_ADDRESS+0x056)
+#define WCD937X_MBHC_CTL_ANA                        (WCD937X_BASE_ADDRESS+0x057)
+#define WCD937X_MBHC_CTL_SPARE_1                    (WCD937X_BASE_ADDRESS+0x058)
+#define WCD937X_MBHC_CTL_SPARE_2                    (WCD937X_BASE_ADDRESS+0x059)
+#define WCD937X_MBHC_CTL_BCS                        (WCD937X_BASE_ADDRESS+0x05A)
+#define WCD937X_MBHC_MOISTURE_DET_FSM_STATUS        (WCD937X_BASE_ADDRESS+0x05B)
+#define WCD937X_MBHC_TEST_CTL                       (WCD937X_BASE_ADDRESS+0x05C)
+#define WCD937X_LDOH_MODE                           (WCD937X_BASE_ADDRESS+0x067)
+#define WCD937X_LDOH_BIAS                           (WCD937X_BASE_ADDRESS+0x068)
+#define WCD937X_LDOH_STB_LOADS                      (WCD937X_BASE_ADDRESS+0x069)
+#define WCD937X_LDOH_SLOWRAMP                       (WCD937X_BASE_ADDRESS+0x06A)
+#define WCD937X_MICB1_TEST_CTL_1                    (WCD937X_BASE_ADDRESS+0x06B)
+#define WCD937X_MICB1_TEST_CTL_2                    (WCD937X_BASE_ADDRESS+0x06C)
+#define WCD937X_MICB1_TEST_CTL_3                    (WCD937X_BASE_ADDRESS+0x06D)
+#define WCD937X_MICB2_TEST_CTL_1                    (WCD937X_BASE_ADDRESS+0x06E)
+#define WCD937X_MICB2_TEST_CTL_2                    (WCD937X_BASE_ADDRESS+0x06F)
+#define WCD937X_MICB2_TEST_CTL_3                    (WCD937X_BASE_ADDRESS+0x070)
+#define WCD937X_MICB3_TEST_CTL_1                    (WCD937X_BASE_ADDRESS+0x071)
+#define WCD937X_MICB3_TEST_CTL_2                    (WCD937X_BASE_ADDRESS+0x072)
+#define WCD937X_MICB3_TEST_CTL_3                    (WCD937X_BASE_ADDRESS+0x073)
+#define WCD937X_TX_COM_ADC_VCM                      (WCD937X_BASE_ADDRESS+0x077)
+#define WCD937X_TX_COM_BIAS_ATEST                   (WCD937X_BASE_ADDRESS+0x078)
+#define WCD937X_TX_COM_ADC_INT1_IB                  (WCD937X_BASE_ADDRESS+0x079)
+#define WCD937X_TX_COM_ADC_INT2_IB                  (WCD937X_BASE_ADDRESS+0x07A)
+#define WCD937X_TX_COM_TXFE_DIV_CTL                 (WCD937X_BASE_ADDRESS+0x07B)
+#define WCD937X_TX_COM_TXFE_DIV_START               (WCD937X_BASE_ADDRESS+0x07C)
+#define WCD937X_TX_COM_TXFE_DIV_STOP_9P6M           (WCD937X_BASE_ADDRESS+0x07D)
+#define WCD937X_TX_COM_TXFE_DIV_STOP_12P288M        (WCD937X_BASE_ADDRESS+0x07E)
+#define WCD937X_TX_1_2_TEST_EN                      (WCD937X_BASE_ADDRESS+0x07F)
+#define WCD937X_TX_1_2_ADC_IB                       (WCD937X_BASE_ADDRESS+0x080)
+#define WCD937X_TX_1_2_ATEST_REFCTL                 (WCD937X_BASE_ADDRESS+0x081)
+#define WCD937X_TX_1_2_TEST_CTL                     (WCD937X_BASE_ADDRESS+0x082)
+#define WCD937X_TX_1_2_TEST_BLK_EN                  (WCD937X_BASE_ADDRESS+0x083)
+#define WCD937X_TX_1_2_TXFE_CLKDIV                  (WCD937X_BASE_ADDRESS+0x084)
+#define WCD937X_TX_1_2_SAR2_ERR                     (WCD937X_BASE_ADDRESS+0x085)
+#define WCD937X_TX_1_2_SAR1_ERR                     (WCD937X_BASE_ADDRESS+0x086)
+#define WCD937X_TX_3_TEST_EN                        (WCD937X_BASE_ADDRESS+0x087)
+#define WCD937X_TX_3_ADC_IB                         (WCD937X_BASE_ADDRESS+0x088)
+#define WCD937X_TX_3_ATEST_REFCTL                   (WCD937X_BASE_ADDRESS+0x089)
+#define WCD937X_TX_3_TEST_CTL                       (WCD937X_BASE_ADDRESS+0x08A)
+#define WCD937X_TX_3_TEST_BLK_EN                    (WCD937X_BASE_ADDRESS+0x08B)
+#define WCD937X_TX_3_TXFE_CLKDIV                    (WCD937X_BASE_ADDRESS+0x08C)
+#define WCD937X_TX_3_SPARE_MONO                     (WCD937X_BASE_ADDRESS+0x08D)
+#define WCD937X_TX_3_SAR1_ERR                       (WCD937X_BASE_ADDRESS+0x08E)
+#define WCD937X_CLASSH_MODE_1                       (WCD937X_BASE_ADDRESS+0x097)
+#define WCD937X_CLASSH_MODE_2                       (WCD937X_BASE_ADDRESS+0x098)
+#define WCD937X_CLASSH_MODE_3                       (WCD937X_BASE_ADDRESS+0x099)
+#define WCD937X_CLASSH_CTRL_VCL_1                   (WCD937X_BASE_ADDRESS+0x09A)
+#define WCD937X_CLASSH_CTRL_VCL_2                   (WCD937X_BASE_ADDRESS+0x09B)
+#define WCD937X_CLASSH_CTRL_CCL_1                   (WCD937X_BASE_ADDRESS+0x09C)
+#define WCD937X_CLASSH_CTRL_CCL_2                   (WCD937X_BASE_ADDRESS+0x09D)
+#define WCD937X_CLASSH_CTRL_CCL_3                   (WCD937X_BASE_ADDRESS+0x09E)
+#define WCD937X_CLASSH_CTRL_CCL_4                   (WCD937X_BASE_ADDRESS+0x09F)
+#define WCD937X_CLASSH_CTRL_CCL_5                   (WCD937X_BASE_ADDRESS+0x0A0)
+#define WCD937X_CLASSH_BUCK_TMUX_A_D                (WCD937X_BASE_ADDRESS+0x0A1)
+#define WCD937X_CLASSH_BUCK_SW_DRV_CNTL             (WCD937X_BASE_ADDRESS+0x0A2)
+#define WCD937X_CLASSH_SPARE                        (WCD937X_BASE_ADDRESS+0x0A3)
+#define WCD937X_FLYBACK_EN                          (WCD937X_BASE_ADDRESS+0x0A4)
+#define WCD937X_FLYBACK_VNEG_CTRL_1                 (WCD937X_BASE_ADDRESS+0x0A5)
+#define WCD937X_FLYBACK_VNEG_CTRL_2                 (WCD937X_BASE_ADDRESS+0x0A6)
+#define WCD937X_FLYBACK_VNEG_CTRL_3                 (WCD937X_BASE_ADDRESS+0x0A7)
+#define WCD937X_FLYBACK_VNEG_CTRL_4                 (WCD937X_BASE_ADDRESS+0x0A8)
+#define WCD937X_FLYBACK_VNEG_CTRL_5                 (WCD937X_BASE_ADDRESS+0x0A9)
+#define WCD937X_FLYBACK_VNEG_CTRL_6                 (WCD937X_BASE_ADDRESS+0x0AA)
+#define WCD937X_FLYBACK_VNEG_CTRL_7                 (WCD937X_BASE_ADDRESS+0x0AB)
+#define WCD937X_FLYBACK_VNEG_CTRL_8                 (WCD937X_BASE_ADDRESS+0x0AC)
+#define WCD937X_FLYBACK_VNEG_CTRL_9                 (WCD937X_BASE_ADDRESS+0x0AD)
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_1              (WCD937X_BASE_ADDRESS+0x0AE)
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_2              (WCD937X_BASE_ADDRESS+0x0AF)
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_3              (WCD937X_BASE_ADDRESS+0x0B0)
+#define WCD937X_FLYBACK_CTRL_1                      (WCD937X_BASE_ADDRESS+0x0B1)
+#define WCD937X_FLYBACK_TEST_CTL                    (WCD937X_BASE_ADDRESS+0x0B2)
+#define WCD937X_RX_AUX_SW_CTL                       (WCD937X_BASE_ADDRESS+0x0B3)
+#define WCD937X_RX_PA_AUX_IN_CONN                   (WCD937X_BASE_ADDRESS+0x0B4)
+#define WCD937X_RX_TIMER_DIV                        (WCD937X_BASE_ADDRESS+0x0B5)
+#define WCD937X_RX_OCP_CTL                          (WCD937X_BASE_ADDRESS+0x0B6)
+#define WCD937X_RX_OCP_COUNT                        (WCD937X_BASE_ADDRESS+0x0B7)
+#define WCD937X_RX_BIAS_EAR_DAC                     (WCD937X_BASE_ADDRESS+0x0B8)
+#define WCD937X_RX_BIAS_EAR_AMP                     (WCD937X_BASE_ADDRESS+0x0B9)
+#define WCD937X_RX_BIAS_HPH_LDO                     (WCD937X_BASE_ADDRESS+0x0BA)
+#define WCD937X_RX_BIAS_HPH_PA                      (WCD937X_BASE_ADDRESS+0x0BB)
+#define WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2           (WCD937X_BASE_ADDRESS+0x0BC)
+#define WCD937X_RX_BIAS_HPH_RDAC_LDO                (WCD937X_BASE_ADDRESS+0x0BD)
+#define WCD937X_RX_BIAS_HPH_CNP1                    (WCD937X_BASE_ADDRESS+0x0BE)
+#define WCD937X_RX_BIAS_HPH_LOWPOWER                (WCD937X_BASE_ADDRESS+0x0BF)
+#define WCD937X_RX_BIAS_AUX_DAC                     (WCD937X_BASE_ADDRESS+0x0C0)
+#define WCD937X_RX_BIAS_AUX_AMP                     (WCD937X_BASE_ADDRESS+0x0C1)
+#define WCD937X_RX_BIAS_VNEGDAC_BLEEDER             (WCD937X_BASE_ADDRESS+0x0C2)
+#define WCD937X_RX_BIAS_MISC                        (WCD937X_BASE_ADDRESS+0x0C3)
+#define WCD937X_RX_BIAS_BUCK_RST                    (WCD937X_BASE_ADDRESS+0x0C4)
+#define WCD937X_RX_BIAS_BUCK_VREF_ERRAMP            (WCD937X_BASE_ADDRESS+0x0C5)
+#define WCD937X_RX_BIAS_FLYB_ERRAMP                 (WCD937X_BASE_ADDRESS+0x0C6)
+#define WCD937X_RX_BIAS_FLYB_BUFF                   (WCD937X_BASE_ADDRESS+0x0C7)
+#define WCD937X_RX_BIAS_FLYB_MID_RST                (WCD937X_BASE_ADDRESS+0x0C8)
+#define WCD937X_HPH_L_STATUS                        (WCD937X_BASE_ADDRESS+0x0C9)
+#define WCD937X_HPH_R_STATUS                        (WCD937X_BASE_ADDRESS+0x0CA)
+#define WCD937X_HPH_CNP_EN                          (WCD937X_BASE_ADDRESS+0x0CB)
+#define WCD937X_HPH_CNP_WG_CTL                      (WCD937X_BASE_ADDRESS+0x0CC)
+#define WCD937X_HPH_CNP_WG_TIME                     (WCD937X_BASE_ADDRESS+0x0CD)
+#define WCD937X_HPH_OCP_CTL                         (WCD937X_BASE_ADDRESS+0x0CE)
+#define WCD937X_HPH_AUTO_CHOP                       (WCD937X_BASE_ADDRESS+0x0CF)
+#define WCD937X_HPH_CHOP_CTL                        (WCD937X_BASE_ADDRESS+0x0D0)
+#define WCD937X_HPH_PA_CTL1                         (WCD937X_BASE_ADDRESS+0x0D1)
+#define WCD937X_HPH_PA_CTL2                         (WCD937X_BASE_ADDRESS+0x0D2)
+#define WCD937X_HPH_L_EN                            (WCD937X_BASE_ADDRESS+0x0D3)
+#define WCD937X_HPH_L_TEST                          (WCD937X_BASE_ADDRESS+0x0D4)
+#define WCD937X_HPH_L_ATEST                         (WCD937X_BASE_ADDRESS+0x0D5)
+#define WCD937X_HPH_R_EN                            (WCD937X_BASE_ADDRESS+0x0D6)
+#define WCD937X_HPH_R_TEST                          (WCD937X_BASE_ADDRESS+0x0D7)
+#define WCD937X_HPH_R_ATEST                         (WCD937X_BASE_ADDRESS+0x0D8)
+#define WCD937X_HPH_RDAC_CLK_CTL1                   (WCD937X_BASE_ADDRESS+0x0D9)
+#define WCD937X_HPH_RDAC_CLK_CTL2                   (WCD937X_BASE_ADDRESS+0x0DA)
+#define WCD937X_HPH_RDAC_LDO_CTL                    (WCD937X_BASE_ADDRESS+0x0DB)
+#define WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL            (WCD937X_BASE_ADDRESS+0x0DC)
+#define WCD937X_HPH_REFBUFF_UHQA_CTL                (WCD937X_BASE_ADDRESS+0x0DD)
+#define WCD937X_HPH_REFBUFF_LP_CTL                  (WCD937X_BASE_ADDRESS+0x0DE)
+#define WCD937X_HPH_L_DAC_CTL                       (WCD937X_BASE_ADDRESS+0x0DF)
+#define WCD937X_HPH_R_DAC_CTL                       (WCD937X_BASE_ADDRESS+0x0E0)
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL      (WCD937X_BASE_ADDRESS+0x0E1)
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_EN            (WCD937X_BASE_ADDRESS+0x0E2)
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1         (WCD937X_BASE_ADDRESS+0x0E3)
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS        (WCD937X_BASE_ADDRESS+0x0E4)
+#define WCD937X_EAR_EAR_EN_REG                      (WCD937X_BASE_ADDRESS+0x0E9)
+#define WCD937X_EAR_EAR_PA_CON                      (WCD937X_BASE_ADDRESS+0x0EA)
+#define WCD937X_EAR_EAR_SP_CON                      (WCD937X_BASE_ADDRESS+0x0EB)
+#define WCD937X_EAR_EAR_DAC_CON                     (WCD937X_BASE_ADDRESS+0x0EC)
+#define WCD937X_EAR_EAR_CNP_FSM_CON                 (WCD937X_BASE_ADDRESS+0x0ED)
+#define WCD937X_EAR_TEST_CTL                        (WCD937X_BASE_ADDRESS+0x0EE)
+#define WCD937X_EAR_STATUS_REG_1                    (WCD937X_BASE_ADDRESS+0x0EF)
+#define WCD937X_EAR_STATUS_REG_2                    (WCD937X_BASE_ADDRESS+0x0F0)
+#define WCD937X_ANA_NEW_PAGE_REGISTER               (WCD937X_BASE_ADDRESS+0x100)
+#define WCD937X_HPH_NEW_ANA_HPH2                    (WCD937X_BASE_ADDRESS+0x101)
+#define WCD937X_HPH_NEW_ANA_HPH3                    (WCD937X_BASE_ADDRESS+0x102)
+#define WCD937X_SLEEP_CTL                           (WCD937X_BASE_ADDRESS+0x103)
+#define WCD937X_SLEEP_WATCHDOG_CTL                  (WCD937X_BASE_ADDRESS+0x104)
+#define WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL        (WCD937X_BASE_ADDRESS+0x11F)
+#define WCD937X_MBHC_NEW_CTL_1                      (WCD937X_BASE_ADDRESS+0x120)
+#define WCD937X_MBHC_NEW_CTL_2                      (WCD937X_BASE_ADDRESS+0x121)
+#define WCD937X_MBHC_NEW_PLUG_DETECT_CTL            (WCD937X_BASE_ADDRESS+0x122)
+#define WCD937X_MBHC_NEW_ZDET_ANA_CTL               (WCD937X_BASE_ADDRESS+0x123)
+#define WCD937X_MBHC_NEW_ZDET_RAMP_CTL              (WCD937X_BASE_ADDRESS+0x124)
+#define WCD937X_MBHC_NEW_FSM_STATUS                 (WCD937X_BASE_ADDRESS+0x125)
+#define WCD937X_MBHC_NEW_ADC_RESULT                 (WCD937X_BASE_ADDRESS+0x126)
+#define WCD937X_TX_NEW_TX_CH2_SEL                   (WCD937X_BASE_ADDRESS+0x127)
+#define WCD937X_AUX_AUXPA                           (WCD937X_BASE_ADDRESS+0x128)
+#define WCD937X_LDORXTX_MODE                        (WCD937X_BASE_ADDRESS+0x129)
+#define WCD937X_LDORXTX_CONFIG                      (WCD937X_BASE_ADDRESS+0x12A)
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_EN            (WCD937X_BASE_ADDRESS+0x12C)
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_OUT           (WCD937X_BASE_ADDRESS+0x12D)
+#define WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL           (WCD937X_BASE_ADDRESS+0x132)
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L          (WCD937X_BASE_ADDRESS+0x133)
+#define WCD937X_HPH_NEW_INT_RDAC_VREF_CTL           (WCD937X_BASE_ADDRESS+0x134)
+#define WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL       (WCD937X_BASE_ADDRESS+0x135)
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R          (WCD937X_BASE_ADDRESS+0x136)
+#define WCD937X_HPH_NEW_INT_PA_MISC1                (WCD937X_BASE_ADDRESS+0x137)
+#define WCD937X_HPH_NEW_INT_PA_MISC2                (WCD937X_BASE_ADDRESS+0x138)
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC            (WCD937X_BASE_ADDRESS+0x139)
+#define WCD937X_HPH_NEW_INT_HPH_TIMER1              (WCD937X_BASE_ADDRESS+0x13A)
+#define WCD937X_HPH_NEW_INT_HPH_TIMER2              (WCD937X_BASE_ADDRESS+0x13B)
+#define WCD937X_HPH_NEW_INT_HPH_TIMER3              (WCD937X_BASE_ADDRESS+0x13C)
+#define WCD937X_HPH_NEW_INT_HPH_TIMER4              (WCD937X_BASE_ADDRESS+0x13D)
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC2           (WCD937X_BASE_ADDRESS+0x13E)
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC3           (WCD937X_BASE_ADDRESS+0x13F)
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI     (WCD937X_BASE_ADDRESS+0x145)
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP        (WCD937X_BASE_ADDRESS+0x146)
+#define WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP          (WCD937X_BASE_ADDRESS+0x147)
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL   (WCD937X_BASE_ADDRESS+0x1AF)
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL \
+						    (WCD937X_BASE_ADDRESS+0x1B0)
+#define WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT       (WCD937X_BASE_ADDRESS+0x1B1)
+#define WCD937X_MBHC_NEW_INT_SPARE_2                (WCD937X_BASE_ADDRESS+0x1B2)
+#define WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON         (WCD937X_BASE_ADDRESS+0x1B7)
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON1            (WCD937X_BASE_ADDRESS+0x1B8)
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON2            (WCD937X_BASE_ADDRESS+0x1B9)
+#define WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS        (WCD937X_BASE_ADDRESS+0x1BA)
+#define WCD937X_AUX_INT_EN_REG                      (WCD937X_BASE_ADDRESS+0x1BD)
+#define WCD937X_AUX_INT_PA_CTRL                     (WCD937X_BASE_ADDRESS+0x1BE)
+#define WCD937X_AUX_INT_SP_CTRL                     (WCD937X_BASE_ADDRESS+0x1BF)
+#define WCD937X_AUX_INT_DAC_CTRL                    (WCD937X_BASE_ADDRESS+0x1C0)
+#define WCD937X_AUX_INT_CLK_CTRL                    (WCD937X_BASE_ADDRESS+0x1C1)
+#define WCD937X_AUX_INT_TEST_CTRL                   (WCD937X_BASE_ADDRESS+0x1C2)
+#define WCD937X_AUX_INT_STATUS_REG                  (WCD937X_BASE_ADDRESS+0x1C3)
+#define WCD937X_AUX_INT_MISC                        (WCD937X_BASE_ADDRESS+0x1C4)
+#define WCD937X_LDORXTX_INT_BIAS                    (WCD937X_BASE_ADDRESS+0x1C5)
+#define WCD937X_LDORXTX_INT_STB_LOADS_DTEST         (WCD937X_BASE_ADDRESS+0x1C6)
+#define WCD937X_LDORXTX_INT_TEST0                   (WCD937X_BASE_ADDRESS+0x1C7)
+#define WCD937X_LDORXTX_INT_STARTUP_TIMER           (WCD937X_BASE_ADDRESS+0x1C8)
+#define WCD937X_LDORXTX_INT_TEST1                   (WCD937X_BASE_ADDRESS+0x1C9)
+#define WCD937X_LDORXTX_INT_STATUS                  (WCD937X_BASE_ADDRESS+0x1CA)
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_1            (WCD937X_BASE_ADDRESS+0x1D0)
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_2            (WCD937X_BASE_ADDRESS+0x1D1)
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1      (WCD937X_BASE_ADDRESS+0x1D3)
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2      (WCD937X_BASE_ADDRESS+0x1D4)
+#define WCD937X_DIGITAL_PAGE_REGISTER               (WCD937X_BASE_ADDRESS+0x400)
+#define WCD937X_DIGITAL_CHIP_ID0                    (WCD937X_BASE_ADDRESS+0x401)
+#define WCD937X_DIGITAL_CHIP_ID1                    (WCD937X_BASE_ADDRESS+0x402)
+#define WCD937X_DIGITAL_CHIP_ID2                    (WCD937X_BASE_ADDRESS+0x403)
+#define WCD937X_DIGITAL_CHIP_ID3                    (WCD937X_BASE_ADDRESS+0x404)
+#define WCD937X_DIGITAL_CDC_RST_CTL                 (WCD937X_BASE_ADDRESS+0x406)
+#define WCD937X_DIGITAL_TOP_CLK_CFG                 (WCD937X_BASE_ADDRESS+0x407)
+#define WCD937X_DIGITAL_CDC_ANA_CLK_CTL             (WCD937X_BASE_ADDRESS+0x408)
+#define WCD937X_DIGITAL_CDC_DIG_CLK_CTL             (WCD937X_BASE_ADDRESS+0x409)
+#define WCD937X_DIGITAL_SWR_RST_EN                  (WCD937X_BASE_ADDRESS+0x40A)
+#define WCD937X_DIGITAL_CDC_PATH_MODE               (WCD937X_BASE_ADDRESS+0x40B)
+#define WCD937X_DIGITAL_CDC_RX_RST                  (WCD937X_BASE_ADDRESS+0x40C)
+#define WCD937X_DIGITAL_CDC_RX0_CTL                 (WCD937X_BASE_ADDRESS+0x40D)
+#define WCD937X_DIGITAL_CDC_RX1_CTL                 (WCD937X_BASE_ADDRESS+0x40E)
+#define WCD937X_DIGITAL_CDC_RX2_CTL                 (WCD937X_BASE_ADDRESS+0x40F)
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA0            (WCD937X_BASE_ADDRESS+0x410)
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA1            (WCD937X_BASE_ADDRESS+0x411)
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA2            (WCD937X_BASE_ADDRESS+0x412)
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA3            (WCD937X_BASE_ADDRESS+0x413)
+#define WCD937X_DIGITAL_CDC_COMP_CTL_0              (WCD937X_BASE_ADDRESS+0x414)
+#define WCD937X_DIGITAL_CDC_RX_DELAY_CTL            (WCD937X_BASE_ADDRESS+0x417)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_0            (WCD937X_BASE_ADDRESS+0x418)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_1            (WCD937X_BASE_ADDRESS+0x419)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_0            (WCD937X_BASE_ADDRESS+0x41A)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_1            (WCD937X_BASE_ADDRESS+0x41B)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_0            (WCD937X_BASE_ADDRESS+0x41C)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_1            (WCD937X_BASE_ADDRESS+0x41D)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_0            (WCD937X_BASE_ADDRESS+0x41E)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_1            (WCD937X_BASE_ADDRESS+0x41F)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_0            (WCD937X_BASE_ADDRESS+0x420)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_1            (WCD937X_BASE_ADDRESS+0x421)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A6_0            (WCD937X_BASE_ADDRESS+0x422)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A7_0            (WCD937X_BASE_ADDRESS+0x423)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_0             (WCD937X_BASE_ADDRESS+0x424)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_1             (WCD937X_BASE_ADDRESS+0x425)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_2             (WCD937X_BASE_ADDRESS+0x426)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_3             (WCD937X_BASE_ADDRESS+0x427)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R1              (WCD937X_BASE_ADDRESS+0x428)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R2              (WCD937X_BASE_ADDRESS+0x429)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R3              (WCD937X_BASE_ADDRESS+0x42A)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R4              (WCD937X_BASE_ADDRESS+0x42B)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R5              (WCD937X_BASE_ADDRESS+0x42C)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R6              (WCD937X_BASE_ADDRESS+0x42D)
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R7              (WCD937X_BASE_ADDRESS+0x42E)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_0            (WCD937X_BASE_ADDRESS+0x42F)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_1            (WCD937X_BASE_ADDRESS+0x430)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_0            (WCD937X_BASE_ADDRESS+0x431)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_1            (WCD937X_BASE_ADDRESS+0x432)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_0            (WCD937X_BASE_ADDRESS+0x433)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_1            (WCD937X_BASE_ADDRESS+0x434)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_0            (WCD937X_BASE_ADDRESS+0x435)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_1            (WCD937X_BASE_ADDRESS+0x436)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_0            (WCD937X_BASE_ADDRESS+0x437)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_1            (WCD937X_BASE_ADDRESS+0x438)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A6_0            (WCD937X_BASE_ADDRESS+0x439)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A7_0            (WCD937X_BASE_ADDRESS+0x43A)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_0             (WCD937X_BASE_ADDRESS+0x43B)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_1             (WCD937X_BASE_ADDRESS+0x43C)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_2             (WCD937X_BASE_ADDRESS+0x43D)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_3             (WCD937X_BASE_ADDRESS+0x43E)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R1              (WCD937X_BASE_ADDRESS+0x43F)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R2              (WCD937X_BASE_ADDRESS+0x440)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R3              (WCD937X_BASE_ADDRESS+0x441)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R4              (WCD937X_BASE_ADDRESS+0x442)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R5              (WCD937X_BASE_ADDRESS+0x443)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R6              (WCD937X_BASE_ADDRESS+0x444)
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R7              (WCD937X_BASE_ADDRESS+0x445)
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0           (WCD937X_BASE_ADDRESS+0x446)
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1           (WCD937X_BASE_ADDRESS+0x447)
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0          (WCD937X_BASE_ADDRESS+0x448)
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1          (WCD937X_BASE_ADDRESS+0x449)
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2          (WCD937X_BASE_ADDRESS+0x44A)
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0          (WCD937X_BASE_ADDRESS+0x44B)
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1          (WCD937X_BASE_ADDRESS+0x44C)
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2          (WCD937X_BASE_ADDRESS+0x44D)
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_CTL            (WCD937X_BASE_ADDRESS+0x44E)
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_CTL            (WCD937X_BASE_ADDRESS+0x44F)
+#define WCD937X_DIGITAL_CDC_EAR_PATH_CTL            (WCD937X_BASE_ADDRESS+0x450)
+#define WCD937X_DIGITAL_CDC_SWR_CLH                 (WCD937X_BASE_ADDRESS+0x451)
+#define WCD937X_DIGITAL_SWR_CLH_BYP                 (WCD937X_BASE_ADDRESS+0x452)
+#define WCD937X_DIGITAL_CDC_TX0_CTL                 (WCD937X_BASE_ADDRESS+0x453)
+#define WCD937X_DIGITAL_CDC_TX1_CTL                 (WCD937X_BASE_ADDRESS+0x454)
+#define WCD937X_DIGITAL_CDC_TX2_CTL                 (WCD937X_BASE_ADDRESS+0x455)
+#define WCD937X_DIGITAL_CDC_TX_RST                  (WCD937X_BASE_ADDRESS+0x456)
+#define WCD937X_DIGITAL_CDC_REQ_CTL                 (WCD937X_BASE_ADDRESS+0x457)
+#define WCD937X_DIGITAL_CDC_AMIC_CTL                (WCD937X_BASE_ADDRESS+0x45A)
+#define WCD937X_DIGITAL_CDC_DMIC_CTL                (WCD937X_BASE_ADDRESS+0x45B)
+#define WCD937X_DIGITAL_CDC_DMIC0_CTL               (WCD937X_BASE_ADDRESS+0x45C)
+#define WCD937X_DIGITAL_CDC_DMIC1_CTL               (WCD937X_BASE_ADDRESS+0x45D)
+#define WCD937X_DIGITAL_CDC_DMIC2_CTL               (WCD937X_BASE_ADDRESS+0x45E)
+#define WCD937X_DIGITAL_EFUSE_CTL                   (WCD937X_BASE_ADDRESS+0x45F)
+#define WCD937X_DIGITAL_EFUSE_PRG_CTL               (WCD937X_BASE_ADDRESS+0x460)
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_0            (WCD937X_BASE_ADDRESS+0x461)
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_1            (WCD937X_BASE_ADDRESS+0x462)
+#define WCD937X_DIGITAL_EFUSE_T_DATA_0              (WCD937X_BASE_ADDRESS+0x463)
+#define WCD937X_DIGITAL_EFUSE_T_DATA_1              (WCD937X_BASE_ADDRESS+0x464)
+#define WCD937X_DIGITAL_PDM_WD_CTL0                 (WCD937X_BASE_ADDRESS+0x465)
+#define WCD937X_DIGITAL_PDM_WD_CTL1                 (WCD937X_BASE_ADDRESS+0x466)
+#define WCD937X_DIGITAL_PDM_WD_CTL2                 (WCD937X_BASE_ADDRESS+0x467)
+#define WCD937X_DIGITAL_INTR_MODE                   (WCD937X_BASE_ADDRESS+0x46A)
+#define WCD937X_DIGITAL_INTR_MASK_0                 (WCD937X_BASE_ADDRESS+0x46B)
+#define WCD937X_DIGITAL_INTR_MASK_1                 (WCD937X_BASE_ADDRESS+0x46C)
+#define WCD937X_DIGITAL_INTR_MASK_2                 (WCD937X_BASE_ADDRESS+0x46D)
+#define WCD937X_DIGITAL_INTR_STATUS_0               (WCD937X_BASE_ADDRESS+0x46E)
+#define WCD937X_DIGITAL_INTR_STATUS_1               (WCD937X_BASE_ADDRESS+0x46F)
+#define WCD937X_DIGITAL_INTR_STATUS_2               (WCD937X_BASE_ADDRESS+0x470)
+#define WCD937X_DIGITAL_INTR_CLEAR_0                (WCD937X_BASE_ADDRESS+0x471)
+#define WCD937X_DIGITAL_INTR_CLEAR_1                (WCD937X_BASE_ADDRESS+0x472)
+#define WCD937X_DIGITAL_INTR_CLEAR_2                (WCD937X_BASE_ADDRESS+0x473)
+#define WCD937X_DIGITAL_INTR_LEVEL_0                (WCD937X_BASE_ADDRESS+0x474)
+#define WCD937X_DIGITAL_INTR_LEVEL_1                (WCD937X_BASE_ADDRESS+0x475)
+#define WCD937X_DIGITAL_INTR_LEVEL_2                (WCD937X_BASE_ADDRESS+0x476)
+#define WCD937X_DIGITAL_INTR_SET_0                  (WCD937X_BASE_ADDRESS+0x477)
+#define WCD937X_DIGITAL_INTR_SET_1                  (WCD937X_BASE_ADDRESS+0x478)
+#define WCD937X_DIGITAL_INTR_SET_2                  (WCD937X_BASE_ADDRESS+0x479)
+#define WCD937X_DIGITAL_INTR_TEST_0                 (WCD937X_BASE_ADDRESS+0x47A)
+#define WCD937X_DIGITAL_INTR_TEST_1                 (WCD937X_BASE_ADDRESS+0x47B)
+#define WCD937X_DIGITAL_INTR_TEST_2                 (WCD937X_BASE_ADDRESS+0x47C)
+#define WCD937X_DIGITAL_CDC_CONN_RX0_CTL            (WCD937X_BASE_ADDRESS+0x47F)
+#define WCD937X_DIGITAL_CDC_CONN_RX1_CTL            (WCD937X_BASE_ADDRESS+0x480)
+#define WCD937X_DIGITAL_CDC_CONN_RX2_CTL            (WCD937X_BASE_ADDRESS+0x481)
+#define WCD937X_DIGITAL_CDC_CONN_TX_CTL             (WCD937X_BASE_ADDRESS+0x482)
+#define WCD937X_DIGITAL_LOOP_BACK_MODE              (WCD937X_BASE_ADDRESS+0x483)
+#define WCD937X_DIGITAL_SWR_DAC_TEST                (WCD937X_BASE_ADDRESS+0x484)
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_0            (WCD937X_BASE_ADDRESS+0x485)
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_0            (WCD937X_BASE_ADDRESS+0x491)
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_1            (WCD937X_BASE_ADDRESS+0x492)
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_1            (WCD937X_BASE_ADDRESS+0x493)
+#define WCD937X_DIGITAL_SWR_HM_TEST                 (WCD937X_BASE_ADDRESS+0x494)
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX0             (WCD937X_BASE_ADDRESS+0x495)
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX1             (WCD937X_BASE_ADDRESS+0x496)
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX2             (WCD937X_BASE_ADDRESS+0x497)
+#define WCD937X_DIGITAL_PAD_CTL_PDM_TX              (WCD937X_BASE_ADDRESS+0x498)
+#define WCD937X_DIGITAL_PAD_INP_DIS_0               (WCD937X_BASE_ADDRESS+0x499)
+#define WCD937X_DIGITAL_PAD_INP_DIS_1               (WCD937X_BASE_ADDRESS+0x49A)
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_0            (WCD937X_BASE_ADDRESS+0x49B)
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_1            (WCD937X_BASE_ADDRESS+0x49C)
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_2            (WCD937X_BASE_ADDRESS+0x49D)
+#define WCD937X_DIGITAL_RX_DATA_EDGE_CTL            (WCD937X_BASE_ADDRESS+0x49E)
+#define WCD937X_DIGITAL_TX_DATA_EDGE_CTL            (WCD937X_BASE_ADDRESS+0x49F)
+#define WCD937X_DIGITAL_GPIO_MODE                   (WCD937X_BASE_ADDRESS+0x4A0)
+#define WCD937X_DIGITAL_PIN_CTL_OE                  (WCD937X_BASE_ADDRESS+0x4A1)
+#define WCD937X_DIGITAL_PIN_CTL_DATA_0              (WCD937X_BASE_ADDRESS+0x4A2)
+#define WCD937X_DIGITAL_PIN_CTL_DATA_1              (WCD937X_BASE_ADDRESS+0x4A3)
+#define WCD937X_DIGITAL_PIN_STATUS_0                (WCD937X_BASE_ADDRESS+0x4A4)
+#define WCD937X_DIGITAL_PIN_STATUS_1                (WCD937X_BASE_ADDRESS+0x4A5)
+#define WCD937X_DIGITAL_DIG_DEBUG_CTL               (WCD937X_BASE_ADDRESS+0x4A6)
+#define WCD937X_DIGITAL_DIG_DEBUG_EN                (WCD937X_BASE_ADDRESS+0x4A7)
+#define WCD937X_DIGITAL_ANA_CSR_DBG_ADD             (WCD937X_BASE_ADDRESS+0x4A8)
+#define WCD937X_DIGITAL_ANA_CSR_DBG_CTL             (WCD937X_BASE_ADDRESS+0x4A9)
+#define WCD937X_DIGITAL_SSP_DBG                     (WCD937X_BASE_ADDRESS+0x4AA)
+#define WCD937X_DIGITAL_MODE_STATUS_0               (WCD937X_BASE_ADDRESS+0x4AB)
+#define WCD937X_DIGITAL_MODE_STATUS_1               (WCD937X_BASE_ADDRESS+0x4AC)
+#define WCD937X_DIGITAL_SPARE_0                     (WCD937X_BASE_ADDRESS+0x4AD)
+#define WCD937X_DIGITAL_SPARE_1                     (WCD937X_BASE_ADDRESS+0x4AE)
+#define WCD937X_DIGITAL_SPARE_2                     (WCD937X_BASE_ADDRESS+0x4AF)
+#define WCD937X_DIGITAL_EFUSE_REG_0                 (WCD937X_BASE_ADDRESS+0x4B0)
+#define WCD937X_DIGITAL_EFUSE_REG_1                 (WCD937X_BASE_ADDRESS+0x4B1)
+#define WCD937X_DIGITAL_EFUSE_REG_2                 (WCD937X_BASE_ADDRESS+0x4B2)
+#define WCD937X_DIGITAL_EFUSE_REG_3                 (WCD937X_BASE_ADDRESS+0x4B3)
+#define WCD937X_DIGITAL_EFUSE_REG_4                 (WCD937X_BASE_ADDRESS+0x4B4)
+#define WCD937X_DIGITAL_EFUSE_REG_5                 (WCD937X_BASE_ADDRESS+0x4B5)
+#define WCD937X_DIGITAL_EFUSE_REG_6                 (WCD937X_BASE_ADDRESS+0x4B6)
+#define WCD937X_DIGITAL_EFUSE_REG_7                 (WCD937X_BASE_ADDRESS+0x4B7)
+#define WCD937X_DIGITAL_EFUSE_REG_8                 (WCD937X_BASE_ADDRESS+0x4B8)
+#define WCD937X_DIGITAL_EFUSE_REG_9                 (WCD937X_BASE_ADDRESS+0x4B9)
+#define WCD937X_DIGITAL_EFUSE_REG_10                (WCD937X_BASE_ADDRESS+0x4BA)
+#define WCD937X_DIGITAL_EFUSE_REG_11                (WCD937X_BASE_ADDRESS+0x4BB)
+#define WCD937X_DIGITAL_EFUSE_REG_12                (WCD937X_BASE_ADDRESS+0x4BC)
+#define WCD937X_DIGITAL_EFUSE_REG_13                (WCD937X_BASE_ADDRESS+0x4BD)
+#define WCD937X_DIGITAL_EFUSE_REG_14                (WCD937X_BASE_ADDRESS+0x4BE)
+#define WCD937X_DIGITAL_EFUSE_REG_15                (WCD937X_BASE_ADDRESS+0x4BF)
+#define WCD937X_DIGITAL_EFUSE_REG_16                (WCD937X_BASE_ADDRESS+0x4C0)
+#define WCD937X_DIGITAL_EFUSE_REG_17                (WCD937X_BASE_ADDRESS+0x4C1)
+#define WCD937X_DIGITAL_EFUSE_REG_18                (WCD937X_BASE_ADDRESS+0x4C2)
+#define WCD937X_DIGITAL_EFUSE_REG_19                (WCD937X_BASE_ADDRESS+0x4C3)
+#define WCD937X_DIGITAL_EFUSE_REG_20                (WCD937X_BASE_ADDRESS+0x4C4)
+#define WCD937X_DIGITAL_EFUSE_REG_21                (WCD937X_BASE_ADDRESS+0x4C5)
+#define WCD937X_DIGITAL_EFUSE_REG_22                (WCD937X_BASE_ADDRESS+0x4C6)
+#define WCD937X_DIGITAL_EFUSE_REG_23                (WCD937X_BASE_ADDRESS+0x4C7)
+#define WCD937X_DIGITAL_EFUSE_REG_24                (WCD937X_BASE_ADDRESS+0x4C8)
+#define WCD937X_DIGITAL_EFUSE_REG_25                (WCD937X_BASE_ADDRESS+0x4C9)
+#define WCD937X_DIGITAL_EFUSE_REG_26                (WCD937X_BASE_ADDRESS+0x4CA)
+#define WCD937X_DIGITAL_EFUSE_REG_27                (WCD937X_BASE_ADDRESS+0x4CB)
+#define WCD937X_DIGITAL_EFUSE_REG_28                (WCD937X_BASE_ADDRESS+0x4CC)
+#define WCD937X_DIGITAL_EFUSE_REG_29                (WCD937X_BASE_ADDRESS+0x4CD)
+#define WCD937X_DIGITAL_EFUSE_REG_30                (WCD937X_BASE_ADDRESS+0x4CE)
+#define WCD937X_DIGITAL_EFUSE_REG_31                (WCD937X_BASE_ADDRESS+0x4CF)
+
+#define WCD937X_REGISTERS_MAX_SIZE (WCD937X_BASE_ADDRESS+0x4D0)
+#define WCD937X_MAX_REGISTER (WCD937X_REGISTERS_MAX_SIZE - 1)
+
+#endif
diff --git a/asoc/codecs/wcd937x/wcd937x-regmap.c b/asoc/codecs/wcd937x/wcd937x-regmap.c
new file mode 100644
index 0000000..cccf8db
--- /dev/null
+++ b/asoc/codecs/wcd937x/wcd937x-regmap.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2018, 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 "wcd937x-registers.h"
+
+extern const u8 wcd937x_reg_access[WCD937X_REGISTERS_MAX_SIZE];
+
+static const struct reg_default wcd937x_defaults[] = {
+	{ WCD937X_ANA_BIAS,                      0x00 },
+	{ WCD937X_ANA_RX_SUPPLIES,               0x00 },
+	{ WCD937X_ANA_HPH,                       0x0C },
+	{ WCD937X_ANA_EAR,                       0x00 },
+	{ WCD937X_ANA_EAR_COMPANDER_CTL,         0x02 },
+	{ WCD937X_ANA_TX_CH1,                    0x20 },
+	{ WCD937X_ANA_TX_CH2,                    0x00 },
+	{ WCD937X_ANA_TX_CH3,                    0x20 },
+	{ WCD937X_ANA_TX_CH3_HPF,                0x00 },
+	{ WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC,  0x00 },
+	{ WCD937X_ANA_MICB3_DSP_EN_LOGIC,        0x00 },
+	{ WCD937X_ANA_MBHC_MECH,                 0x39 },
+	{ WCD937X_ANA_MBHC_ELECT,                0x08 },
+	{ WCD937X_ANA_MBHC_ZDET,                 0x00 },
+	{ WCD937X_ANA_MBHC_RESULT_1,             0x00 },
+	{ WCD937X_ANA_MBHC_RESULT_2,             0x00 },
+	{ WCD937X_ANA_MBHC_RESULT_3,             0x00 },
+	{ WCD937X_ANA_MBHC_BTN0,                 0x00 },
+	{ WCD937X_ANA_MBHC_BTN1,                 0x10 },
+	{ WCD937X_ANA_MBHC_BTN2,                 0x20 },
+	{ WCD937X_ANA_MBHC_BTN3,                 0x30 },
+	{ WCD937X_ANA_MBHC_BTN4,                 0x40 },
+	{ WCD937X_ANA_MBHC_BTN5,                 0x50 },
+	{ WCD937X_ANA_MBHC_BTN6,                 0x60 },
+	{ WCD937X_ANA_MBHC_BTN7,                 0x70 },
+	{ WCD937X_ANA_MICB1,                     0x10 },
+	{ WCD937X_ANA_MICB2,                     0x10 },
+	{ WCD937X_ANA_MICB2_RAMP,                0x00 },
+	{ WCD937X_ANA_MICB3,                     0x10 },
+	{ WCD937X_BIAS_CTL,                      0x2A },
+	{ WCD937X_BIAS_VBG_FINE_ADJ,             0x55 },
+	{ WCD937X_LDOL_VDDCX_ADJUST,             0x01 },
+	{ WCD937X_LDOL_DISABLE_LDOL,             0x00 },
+	{ WCD937X_MBHC_CTL_CLK,                  0x00 },
+	{ WCD937X_MBHC_CTL_ANA,                  0x00 },
+	{ WCD937X_MBHC_CTL_SPARE_1,              0x00 },
+	{ WCD937X_MBHC_CTL_SPARE_2,              0x00 },
+	{ WCD937X_MBHC_CTL_BCS,                  0x00 },
+	{ WCD937X_MBHC_MOISTURE_DET_FSM_STATUS,  0x00 },
+	{ WCD937X_MBHC_TEST_CTL,                 0x00 },
+	{ WCD937X_LDOH_MODE,                     0x2B },
+	{ WCD937X_LDOH_BIAS,                     0x68 },
+	{ WCD937X_LDOH_STB_LOADS,                0x00 },
+	{ WCD937X_LDOH_SLOWRAMP,                 0x50 },
+	{ WCD937X_MICB1_TEST_CTL_1,              0x1A },
+	{ WCD937X_MICB1_TEST_CTL_2,              0x18 },
+	{ WCD937X_MICB1_TEST_CTL_3,              0xA4 },
+	{ WCD937X_MICB2_TEST_CTL_1,              0x1A },
+	{ WCD937X_MICB2_TEST_CTL_2,              0x18 },
+	{ WCD937X_MICB2_TEST_CTL_3,              0xA4 },
+	{ WCD937X_MICB3_TEST_CTL_1,              0x1A },
+	{ WCD937X_MICB3_TEST_CTL_2,              0x18 },
+	{ WCD937X_MICB3_TEST_CTL_3,              0xA4 },
+	{ WCD937X_TX_COM_ADC_VCM,                0x39 },
+	{ WCD937X_TX_COM_BIAS_ATEST,             0xC0 },
+	{ WCD937X_TX_COM_ADC_INT1_IB,            0x6F },
+	{ WCD937X_TX_COM_ADC_INT2_IB,            0x4F },
+	{ WCD937X_TX_COM_TXFE_DIV_CTL,           0x2E },
+	{ WCD937X_TX_COM_TXFE_DIV_START,         0x00 },
+	{ WCD937X_TX_COM_TXFE_DIV_STOP_9P6M,     0xC7 },
+	{ WCD937X_TX_COM_TXFE_DIV_STOP_12P288M,  0xFF },
+	{ WCD937X_TX_1_2_TEST_EN,                0xCC },
+	{ WCD937X_TX_1_2_ADC_IB,                 0x09 },
+	{ WCD937X_TX_1_2_ATEST_REFCTL,           0x0A },
+	{ WCD937X_TX_1_2_TEST_CTL,               0x38 },
+	{ WCD937X_TX_1_2_TEST_BLK_EN,            0xFF },
+	{ WCD937X_TX_1_2_TXFE_CLKDIV,            0x00 },
+	{ WCD937X_TX_1_2_SAR2_ERR,               0x00 },
+	{ WCD937X_TX_1_2_SAR1_ERR,               0x00 },
+	{ WCD937X_TX_3_TEST_EN,                  0xCC },
+	{ WCD937X_TX_3_ADC_IB,                   0x09 },
+	{ WCD937X_TX_3_ATEST_REFCTL,             0x0A },
+	{ WCD937X_TX_3_TEST_CTL,                 0x38 },
+	{ WCD937X_TX_3_TEST_BLK_EN,              0xFF },
+	{ WCD937X_TX_3_TXFE_CLKDIV,              0x00 },
+	{ WCD937X_TX_3_SPARE_MONO,               0x00 },
+	{ WCD937X_TX_3_SAR1_ERR,                 0x00 },
+	{ WCD937X_CLASSH_MODE_1,                 0x40 },
+	{ WCD937X_CLASSH_MODE_2,                 0x3A },
+	{ WCD937X_CLASSH_MODE_3,                 0x00 },
+	{ WCD937X_CLASSH_CTRL_VCL_1,             0x70 },
+	{ WCD937X_CLASSH_CTRL_VCL_2,             0x82 },
+	{ WCD937X_CLASSH_CTRL_CCL_1,             0x31 },
+	{ WCD937X_CLASSH_CTRL_CCL_2,             0x80 },
+	{ WCD937X_CLASSH_CTRL_CCL_3,             0x80 },
+	{ WCD937X_CLASSH_CTRL_CCL_4,             0x51 },
+	{ WCD937X_CLASSH_CTRL_CCL_5,             0x00 },
+	{ WCD937X_CLASSH_BUCK_TMUX_A_D,          0x00 },
+	{ WCD937X_CLASSH_BUCK_SW_DRV_CNTL,       0x77 },
+	{ WCD937X_CLASSH_SPARE,                  0x00 },
+	{ WCD937X_FLYBACK_EN,                    0x4E },
+	{ WCD937X_FLYBACK_VNEG_CTRL_1,           0x0B },
+	{ WCD937X_FLYBACK_VNEG_CTRL_2,           0x45 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_3,           0x74 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_4,           0x7F },
+	{ WCD937X_FLYBACK_VNEG_CTRL_5,           0x83 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_6,           0x98 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_7,           0xA9 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_8,           0x68 },
+	{ WCD937X_FLYBACK_VNEG_CTRL_9,           0x64 },
+	{ WCD937X_FLYBACK_VNEGDAC_CTRL_1,        0xED },
+	{ WCD937X_FLYBACK_VNEGDAC_CTRL_2,        0xF0 },
+	{ WCD937X_FLYBACK_VNEGDAC_CTRL_3,        0xA6 },
+	{ WCD937X_FLYBACK_CTRL_1,                0x65 },
+	{ WCD937X_FLYBACK_TEST_CTL,              0x00 },
+	{ WCD937X_RX_AUX_SW_CTL,                 0x00 },
+	{ WCD937X_RX_PA_AUX_IN_CONN,             0x00 },
+	{ WCD937X_RX_TIMER_DIV,                  0x32 },
+	{ WCD937X_RX_OCP_CTL,                    0x1F },
+	{ WCD937X_RX_OCP_COUNT,                  0x77 },
+	{ WCD937X_RX_BIAS_EAR_DAC,               0xA0 },
+	{ WCD937X_RX_BIAS_EAR_AMP,               0xAA },
+	{ WCD937X_RX_BIAS_HPH_LDO,               0xA9 },
+	{ WCD937X_RX_BIAS_HPH_PA,                0xAA },
+	{ WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2,     0x8A },
+	{ WCD937X_RX_BIAS_HPH_RDAC_LDO,          0x88 },
+	{ WCD937X_RX_BIAS_HPH_CNP1,              0x82 },
+	{ WCD937X_RX_BIAS_HPH_LOWPOWER,          0x82 },
+	{ WCD937X_RX_BIAS_AUX_DAC,               0xA0 },
+	{ WCD937X_RX_BIAS_AUX_AMP,               0xAA },
+	{ WCD937X_RX_BIAS_VNEGDAC_BLEEDER,       0x50 },
+	{ WCD937X_RX_BIAS_MISC,                  0x00 },
+	{ WCD937X_RX_BIAS_BUCK_RST,              0x08 },
+	{ WCD937X_RX_BIAS_BUCK_VREF_ERRAMP,      0x44 },
+	{ WCD937X_RX_BIAS_FLYB_ERRAMP,           0x40 },
+	{ WCD937X_RX_BIAS_FLYB_BUFF,             0xAA },
+	{ WCD937X_RX_BIAS_FLYB_MID_RST,          0x14 },
+	{ WCD937X_HPH_L_STATUS,                  0x04 },
+	{ WCD937X_HPH_R_STATUS,                  0x04 },
+	{ WCD937X_HPH_CNP_EN,                    0x80 },
+	{ WCD937X_HPH_CNP_WG_CTL,                0x9A },
+	{ WCD937X_HPH_CNP_WG_TIME,               0x14 },
+	{ WCD937X_HPH_OCP_CTL,                   0x28 },
+	{ WCD937X_HPH_AUTO_CHOP,                 0x16 },
+	{ WCD937X_HPH_CHOP_CTL,                  0x83 },
+	{ WCD937X_HPH_PA_CTL1,                   0x46 },
+	{ WCD937X_HPH_PA_CTL2,                   0x50 },
+	{ WCD937X_HPH_L_EN,                      0x80 },
+	{ WCD937X_HPH_L_TEST,                    0xE0 },
+	{ WCD937X_HPH_L_ATEST,                   0x50 },
+	{ WCD937X_HPH_R_EN,                      0x80 },
+	{ WCD937X_HPH_R_TEST,                    0xE0 },
+	{ WCD937X_HPH_R_ATEST,                   0x54 },
+	{ WCD937X_HPH_RDAC_CLK_CTL1,             0x99 },
+	{ WCD937X_HPH_RDAC_CLK_CTL2,             0x9B },
+	{ WCD937X_HPH_RDAC_LDO_CTL,              0x33 },
+	{ WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL,      0x00 },
+	{ WCD937X_HPH_REFBUFF_UHQA_CTL,          0xA8 },
+	{ WCD937X_HPH_REFBUFF_LP_CTL,            0x0E },
+	{ WCD937X_HPH_L_DAC_CTL,                 0x20 },
+	{ WCD937X_HPH_R_DAC_CTL,                 0x20 },
+	{ WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55 },
+	{ WCD937X_HPH_SURGE_HPHLR_SURGE_EN,      0x19 },
+	{ WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1,   0xA0 },
+	{ WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS,  0x00 },
+	{ WCD937X_EAR_EAR_EN_REG,                0x22 },
+	{ WCD937X_EAR_EAR_PA_CON,                0x44 },
+	{ WCD937X_EAR_EAR_SP_CON,                0xDB },
+	{ WCD937X_EAR_EAR_DAC_CON,               0x80 },
+	{ WCD937X_EAR_EAR_CNP_FSM_CON,           0xB2 },
+	{ WCD937X_EAR_TEST_CTL,                  0x00 },
+	{ WCD937X_EAR_STATUS_REG_1,              0x00 },
+	{ WCD937X_EAR_STATUS_REG_2,              0x00 },
+	{ WCD937X_ANA_NEW_PAGE_REGISTER,         0x00 },
+	{ WCD937X_HPH_NEW_ANA_HPH2,              0x00 },
+	{ WCD937X_HPH_NEW_ANA_HPH3,              0x00 },
+	{ WCD937X_SLEEP_CTL,                     0x16 },
+	{ WCD937X_SLEEP_WATCHDOG_CTL,            0x00 },
+	{ WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL,  0x00 },
+	{ WCD937X_MBHC_NEW_CTL_1,                0x02 },
+	{ WCD937X_MBHC_NEW_CTL_2,                0x05 },
+	{ WCD937X_MBHC_NEW_PLUG_DETECT_CTL,      0xE9 },
+	{ WCD937X_MBHC_NEW_ZDET_ANA_CTL,         0x0F },
+	{ WCD937X_MBHC_NEW_ZDET_RAMP_CTL,        0x00 },
+	{ WCD937X_MBHC_NEW_FSM_STATUS,           0x00 },
+	{ WCD937X_MBHC_NEW_ADC_RESULT,           0x00 },
+	{ WCD937X_TX_NEW_TX_CH2_SEL,             0x00 },
+	{ WCD937X_AUX_AUXPA,                     0x00 },
+	{ WCD937X_LDORXTX_MODE,                  0x0C },
+	{ WCD937X_LDORXTX_CONFIG,                0x10 },
+	{ WCD937X_DIE_CRACK_DIE_CRK_DET_EN,      0x00 },
+	{ WCD937X_DIE_CRACK_DIE_CRK_DET_OUT,     0x00 },
+	{ WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL,     0x40 },
+	{ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,    0x81 },
+	{ WCD937X_HPH_NEW_INT_RDAC_VREF_CTL,     0x10 },
+	{ WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
+	{ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,    0x81 },
+	{ WCD937X_HPH_NEW_INT_PA_MISC1,          0x22 },
+	{ WCD937X_HPH_NEW_INT_PA_MISC2,          0x00 },
+	{ WCD937X_HPH_NEW_INT_PA_RDAC_MISC,      0x00 },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER1,        0xFE },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER2,        0x02 },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER3,        0x4E },
+	{ WCD937X_HPH_NEW_INT_HPH_TIMER4,        0x54 },
+	{ WCD937X_HPH_NEW_INT_PA_RDAC_MISC2,     0x00 },
+	{ WCD937X_HPH_NEW_INT_PA_RDAC_MISC3,     0x00 },
+	{ WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62 },
+	{ WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP,  0x01 },
+	{ WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP,    0x11 },
+	{ WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57 },
+	{ WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01 },
+	{ WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT,  0x00 },
+	{ WCD937X_MBHC_NEW_INT_SPARE_2,           0x00 },
+	{ WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON,    0xA8 },
+	{ WCD937X_EAR_INT_NEW_CNP_VCM_CON1,       0x42 },
+	{ WCD937X_EAR_INT_NEW_CNP_VCM_CON2,       0x22 },
+	{ WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS,   0x00 },
+	{ WCD937X_AUX_INT_EN_REG,                 0x00 },
+	{ WCD937X_AUX_INT_PA_CTRL,                0x06 },
+	{ WCD937X_AUX_INT_SP_CTRL,                0xD2 },
+	{ WCD937X_AUX_INT_DAC_CTRL,               0x80 },
+	{ WCD937X_AUX_INT_CLK_CTRL,               0x50 },
+	{ WCD937X_AUX_INT_TEST_CTRL,              0x00 },
+	{ WCD937X_AUX_INT_STATUS_REG,             0x00 },
+	{ WCD937X_AUX_INT_MISC,                   0x00 },
+	{ WCD937X_LDORXTX_INT_BIAS,               0x6E },
+	{ WCD937X_LDORXTX_INT_STB_LOADS_DTEST,    0x50 },
+	{ WCD937X_LDORXTX_INT_TEST0,              0x1C },
+	{ WCD937X_LDORXTX_INT_STARTUP_TIMER,      0xFF },
+	{ WCD937X_LDORXTX_INT_TEST1,              0x1F },
+	{ WCD937X_LDORXTX_INT_STATUS,             0x00 },
+	{ WCD937X_SLEEP_INT_WATCHDOG_CTL_1,       0x0A },
+	{ WCD937X_SLEEP_INT_WATCHDOG_CTL_2,       0x0A },
+	{ WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02 },
+	{ WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60 },
+	{ WCD937X_DIGITAL_PAGE_REGISTER,          0x00 },
+	{ WCD937X_DIGITAL_CHIP_ID0,               0x00 },
+	{ WCD937X_DIGITAL_CHIP_ID1,               0x00 },
+	{ WCD937X_DIGITAL_CHIP_ID2,               0x0A },
+	{ WCD937X_DIGITAL_CHIP_ID3,               0x01 },
+	{ WCD937X_DIGITAL_CDC_RST_CTL,            0x03 },
+	{ WCD937X_DIGITAL_TOP_CLK_CFG,            0x00 },
+	{ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,        0x00 },
+	{ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,        0x00 },
+	{ WCD937X_DIGITAL_SWR_RST_EN,             0x00 },
+	{ WCD937X_DIGITAL_CDC_PATH_MODE,          0x55 },
+	{ WCD937X_DIGITAL_CDC_RX_RST,             0x00 },
+	{ WCD937X_DIGITAL_CDC_RX0_CTL,            0xFC },
+	{ WCD937X_DIGITAL_CDC_RX1_CTL,            0xFC },
+	{ WCD937X_DIGITAL_CDC_RX2_CTL,            0xFC },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA0,       0x55 },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA1,       0x55 },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA2,       0x55 },
+	{ WCD937X_DIGITAL_DEM_BYPASS_DATA3,       0x01 },
+	{ WCD937X_DIGITAL_CDC_COMP_CTL_0,         0x00 },
+	{ WCD937X_DIGITAL_CDC_RX_DELAY_CTL,       0x66 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A1_0,       0x00 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A1_1,       0x01 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A2_0,       0x63 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A2_1,       0x04 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A3_0,       0xAC },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A3_1,       0x04 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A4_0,       0x1A },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A4_1,       0x03 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A5_0,       0xBC },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A5_1,       0x02 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A6_0,       0xC7 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_A7_0,       0xF8 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_0,        0x47 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_1,        0x43 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_2,        0xB1 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_C_3,        0x17 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R1,         0x4B },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R2,         0x27 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R3,         0x32 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R4,         0x57 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R4,         0x63 },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R4,         0x7C },
+	{ WCD937X_DIGITAL_CDC_HPH_DSM_R4,         0x57 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A1_0,       0x00 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A1_1,       0x01 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A2_0,       0x96 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A2_1,       0x09 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A3_0,       0xAB },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A3_1,       0x05 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A4_0,       0x1C },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A4_1,       0x02 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A5_0,       0x17 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A5_1,       0x02 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A6_0,       0xAA },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_A7_0,       0xE3 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_0,        0x69 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_1,        0x54 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_2,        0x02 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_C_3,        0x15 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R1,         0xA4 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R2,         0xB5 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R3,         0x86 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R4,         0x85 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R5,         0xAA },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R6,         0xE2 },
+	{ WCD937X_DIGITAL_CDC_AUX_DSM_R7,         0x62 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0,      0x55 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1,      0xA9 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0,     0x3D },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1,     0x2E },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2,     0x01 },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0,     0x00 },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1,     0xFC },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2,     0x01 },
+	{ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,       0x00 },
+	{ WCD937X_DIGITAL_CDC_AUX_GAIN_CTL,       0x00 },
+	{ WCD937X_DIGITAL_CDC_EAR_PATH_CTL,       0x00 },
+	{ WCD937X_DIGITAL_CDC_SWR_CLH,            0x00 },
+	{ WCD937X_DIGITAL_SWR_CLH_BYP,            0x00 },
+	{ WCD937X_DIGITAL_CDC_TX0_CTL,            0x68 },
+	{ WCD937X_DIGITAL_CDC_TX1_CTL,            0x68 },
+	{ WCD937X_DIGITAL_CDC_TX2_CTL,            0x68 },
+	{ WCD937X_DIGITAL_CDC_TX_RST,             0x00 },
+	{ WCD937X_DIGITAL_CDC_REQ_CTL,            0x01 },
+	{ WCD937X_DIGITAL_CDC_AMIC_CTL,           0x07 },
+	{ WCD937X_DIGITAL_CDC_DMIC_CTL,           0x00 },
+	{ WCD937X_DIGITAL_CDC_DMIC0_CTL,          0x01 },
+	{ WCD937X_DIGITAL_CDC_DMIC1_CTL,          0x01 },
+	{ WCD937X_DIGITAL_CDC_DMIC2_CTL,          0x01 },
+	{ WCD937X_DIGITAL_EFUSE_CTL,              0x2B },
+	{ WCD937X_DIGITAL_EFUSE_PRG_CTL,          0x00 },
+	{ WCD937X_DIGITAL_EFUSE_TEST_CTL_0,       0x00 },
+	{ WCD937X_DIGITAL_EFUSE_TEST_CTL_1,       0x00 },
+	{ WCD937X_DIGITAL_EFUSE_T_DATA_0,         0x00 },
+	{ WCD937X_DIGITAL_EFUSE_T_DATA_1,         0x00 },
+	{ WCD937X_DIGITAL_PDM_WD_CTL0,            0x00 },
+	{ WCD937X_DIGITAL_PDM_WD_CTL1,            0x00 },
+	{ WCD937X_DIGITAL_PDM_WD_CTL2,            0x00 },
+	{ WCD937X_DIGITAL_INTR_MODE,              0x00 },
+	{ WCD937X_DIGITAL_INTR_MASK_0,            0xFF },
+	{ WCD937X_DIGITAL_INTR_MASK_1,            0xFF },
+	{ WCD937X_DIGITAL_INTR_MASK_2,            0xFF },
+	{ WCD937X_DIGITAL_INTR_STATUS_0,          0x00 },
+	{ WCD937X_DIGITAL_INTR_STATUS_1,          0x00 },
+	{ WCD937X_DIGITAL_INTR_STATUS_2,          0x00 },
+	{ WCD937X_DIGITAL_INTR_CLEAR_0,           0x00 },
+	{ WCD937X_DIGITAL_INTR_CLEAR_1,           0x00 },
+	{ WCD937X_DIGITAL_INTR_CLEAR_2,           0x00 },
+	{ WCD937X_DIGITAL_INTR_LEVEL_0,           0x00 },
+	{ WCD937X_DIGITAL_INTR_LEVEL_1,           0x00 },
+	{ WCD937X_DIGITAL_INTR_LEVEL_2,           0x00 },
+	{ WCD937X_DIGITAL_INTR_SET_0,             0x00 },
+	{ WCD937X_DIGITAL_INTR_SET_1,             0x00 },
+	{ WCD937X_DIGITAL_INTR_SET_2,             0x00 },
+	{ WCD937X_DIGITAL_INTR_TEST_0,            0x00 },
+	{ WCD937X_DIGITAL_INTR_TEST_1,            0x00 },
+	{ WCD937X_DIGITAL_INTR_TEST_2,            0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_RX0_CTL,       0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_RX1_CTL,       0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_RX2_CTL,       0x00 },
+	{ WCD937X_DIGITAL_CDC_CONN_TX_CTL,        0x00 },
+	{ WCD937X_DIGITAL_LOOP_BACK_MODE,         0x00 },
+	{ WCD937X_DIGITAL_SWR_DAC_TEST,           0x00 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_RX_0,       0x40 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_TX_0,       0x40 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_RX_1,       0x00 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST_TX_1,       0x00 },
+	{ WCD937X_DIGITAL_SWR_HM_TEST,            0x00 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_RX0,        0xF1 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_RX1,        0xF1 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_RX2,        0xF1 },
+	{ WCD937X_DIGITAL_PAD_CTL_PDM_TX,         0xF1 },
+	{ WCD937X_DIGITAL_PAD_INP_DIS_1,          0x00 },
+	{ WCD937X_DIGITAL_DRIVE_STRENGTH_0,       0x00 },
+	{ WCD937X_DIGITAL_DRIVE_STRENGTH_1,       0x00 },
+	{ WCD937X_DIGITAL_DRIVE_STRENGTH_2,       0x00 },
+	{ WCD937X_DIGITAL_RX_DATA_EDGE_CTL,       0x1F },
+	{ WCD937X_DIGITAL_TX_DATA_EDGE_CTL,       0x10 },
+	{ WCD937X_DIGITAL_GPIO_MODE,              0x00 },
+	{ WCD937X_DIGITAL_PIN_CTL_OE,             0x00 },
+	{ WCD937X_DIGITAL_PIN_CTL_DATA_0,         0x00 },
+	{ WCD937X_DIGITAL_PIN_CTL_DATA_1,         0x00 },
+	{ WCD937X_DIGITAL_PIN_STATUS_0,           0x00 },
+	{ WCD937X_DIGITAL_PIN_STATUS_1,           0x00 },
+	{ WCD937X_DIGITAL_DIG_DEBUG_CTL,          0x00 },
+	{ WCD937X_DIGITAL_DIG_DEBUG_EN,           0x00 },
+	{ WCD937X_DIGITAL_ANA_CSR_DBG_ADD,        0x00 },
+	{ WCD937X_DIGITAL_ANA_CSR_DBG_CTL,        0x48 },
+	{ WCD937X_DIGITAL_SSP_DBG,                0x00 },
+	{ WCD937X_DIGITAL_MODE_STATUS_0,          0x00 },
+	{ WCD937X_DIGITAL_MODE_STATUS_1,          0x00 },
+	{ WCD937X_DIGITAL_SPARE_0,                0x00 },
+	{ WCD937X_DIGITAL_SPARE_1,                0x00 },
+	{ WCD937X_DIGITAL_SPARE_2,                0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_0,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_1,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_2,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_3,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_4,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_5,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_6,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_7,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_8,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_9,            0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_10,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_11,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_12,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_13,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_14,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_15,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_16,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_17,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_18,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_19,           0xFF },
+	{ WCD937X_DIGITAL_EFUSE_REG_20,           0x0E },
+	{ WCD937X_DIGITAL_EFUSE_REG_21,           0x8F },
+	{ WCD937X_DIGITAL_EFUSE_REG_22,           0x16 },
+	{ WCD937X_DIGITAL_EFUSE_REG_23,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_24,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_25,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_26,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_27,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_28,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_29,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_30,           0x00 },
+	{ WCD937X_DIGITAL_EFUSE_REG_31,           0x00 },
+};
+
+static bool wcd937x_readable_register(struct device *dev, unsigned int reg)
+{
+	return wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG;
+}
+
+static bool wcd937x_writeable_register(struct device *dev, unsigned int reg)
+{
+	return wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG;
+}
+
+static bool wcd937x_volatile_register(struct device *dev, unsigned int reg)
+{
+	return (wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG)
+		& ~(wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG);
+}
+
+struct regmap_config wcd937x_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wcd937x_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wcd937x_defaults),
+	.max_register = WCD937X_MAX_REGISTER,
+	.readable_reg = wcd937x_readable_register,
+	.writeable_reg = wcd937x_writeable_register,
+	.volatile_reg = wcd937x_volatile_register,
+	.can_multi_write = true,
+};
diff --git a/asoc/codecs/wcd937x/wcd937x-tables.c b/asoc/codecs/wcd937x/wcd937x-tables.c
new file mode 100644
index 0000000..7050730
--- /dev/null
+++ b/asoc/codecs/wcd937x/wcd937x-tables.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2018 , 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 "wcd937x-registers.h"
+
+const u8 wcd937x_reg_access[WCD937X_REG(WCD937X_REGISTERS_MAX_SIZE)] = {
+	[WCD937X_REG(WCD937X_ANA_BIAS)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_RX_SUPPLIES)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_HPH)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_EAR)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_EAR_COMPANDER_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_TX_CH1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_TX_CH2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_TX_CH3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_TX_CH3_HPF)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MICB3_DSP_EN_LOGIC)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_MECH)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_ELECT)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_ZDET)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_RESULT_1)] = RD_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_RESULT_2)] = RD_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_RESULT_3)] = RD_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN5)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN6)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MBHC_BTN7)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MICB1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MICB2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MICB2_RAMP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_ANA_MICB3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_BIAS_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_BIAS_VBG_FINE_ADJ)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDOL_VDDCX_ADJUST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDOL_DISABLE_LDOL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_CTL_CLK)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_CTL_ANA)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_CTL_SPARE_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_CTL_SPARE_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_CTL_BCS)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_MOISTURE_DET_FSM_STATUS)] = RD_REG,
+	[WCD937X_REG(WCD937X_MBHC_TEST_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDOH_MODE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDOH_BIAS)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDOH_STB_LOADS)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDOH_SLOWRAMP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB1_TEST_CTL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB1_TEST_CTL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB1_TEST_CTL_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB2_TEST_CTL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB2_TEST_CTL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB2_TEST_CTL_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB3_TEST_CTL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB3_TEST_CTL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MICB3_TEST_CTL_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_ADC_VCM)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_BIAS_ATEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_ADC_INT1_IB)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_ADC_INT2_IB)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_START)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_STOP_9P6M)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_STOP_12P288M)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_TEST_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_ADC_IB)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_ATEST_REFCTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_TEST_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_TEST_BLK_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_TXFE_CLKDIV)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_SAR2_ERR)] = RD_REG,
+	[WCD937X_REG(WCD937X_TX_1_2_SAR1_ERR)] = RD_REG,
+	[WCD937X_REG(WCD937X_TX_3_TEST_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_3_ADC_IB)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_3_ATEST_REFCTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_3_TEST_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_3_TEST_BLK_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_3_TXFE_CLKDIV)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_TX_3_SPARE_MONO)] = RD_REG,
+	[WCD937X_REG(WCD937X_TX_3_SAR1_ERR)] = RD_REG,
+	[WCD937X_REG(WCD937X_CLASSH_MODE_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_MODE_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_MODE_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_CTRL_VCL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_CTRL_VCL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_5)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_BUCK_TMUX_A_D)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_BUCK_SW_DRV_CNTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_CLASSH_SPARE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_5)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_6)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_7)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_8)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_9)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEGDAC_CTRL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEGDAC_CTRL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_VNEGDAC_CTRL_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_CTRL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_FLYBACK_TEST_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_AUX_SW_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_PA_AUX_IN_CONN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_TIMER_DIV)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_OCP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_OCP_COUNT)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_EAR_DAC)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_EAR_AMP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_HPH_LDO)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_HPH_PA)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_HPH_RDAC_LDO)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_HPH_CNP1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_HPH_LOWPOWER)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_AUX_DAC)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_AUX_AMP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_VNEGDAC_BLEEDER)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_MISC)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_BUCK_RST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_BUCK_VREF_ERRAMP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_FLYB_ERRAMP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_FLYB_BUFF)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_BIAS_FLYB_MID_RST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_L_STATUS)] = RD_REG,
+	[WCD937X_REG(WCD937X_HPH_R_STATUS)] = RD_REG,
+	[WCD937X_REG(WCD937X_HPH_CNP_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_CNP_WG_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_CNP_WG_TIME)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_OCP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_AUTO_CHOP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_CHOP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_PA_CTL1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_PA_CTL2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_L_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_L_TEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_L_ATEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_R_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_R_TEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_R_ATEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_RDAC_CLK_CTL1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_RDAC_CLK_CTL2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_RDAC_LDO_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_REFBUFF_UHQA_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_REFBUFF_LP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_L_DAC_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_R_DAC_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS)] = RD_REG,
+	[WCD937X_REG(WCD937X_EAR_EAR_EN_REG)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_EAR_PA_CON)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_EAR_SP_CON)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_EAR_DAC_CON)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_EAR_CNP_FSM_CON)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_TEST_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_STATUS_REG_1)] = RD_REG,
+	[WCD937X_REG(WCD937X_EAR_STATUS_REG_2)] = RD_REG,
+	[WCD937X_REG(WCD937X_ANA_NEW_PAGE_REGISTER)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_ANA_HPH2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_ANA_HPH3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_SLEEP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_SLEEP_WATCHDOG_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_CTL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_CTL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_PLUG_DETECT_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_ZDET_ANA_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_ZDET_RAMP_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_FSM_STATUS)] = RD_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_ADC_RESULT)] = RD_REG,
+	[WCD937X_REG(WCD937X_TX_NEW_TX_CH2_SEL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_AUXPA)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_MODE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_CONFIG)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIE_CRACK_DIE_CRK_DET_EN)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIE_CRACK_DIE_CRK_DET_OUT)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_VREF_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_PA_MISC1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_PA_MISC2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_PA_RDAC_MISC)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_PA_RDAC_MISC2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_HPH_NEW_INT_PA_RDAC_MISC3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL)]
+								= RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_MBHC_NEW_INT_SPARE_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_INT_NEW_CNP_VCM_CON1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_INT_NEW_CNP_VCM_CON2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_EN_REG)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_PA_CTRL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_SP_CTRL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_DAC_CTRL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_CLK_CTRL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_TEST_CTRL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_STATUS_REG)] = RD_REG,
+	[WCD937X_REG(WCD937X_AUX_INT_MISC)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_INT_BIAS)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_INT_STB_LOADS_DTEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_INT_TEST0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_INT_STARTUP_TIMER)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_INT_TEST1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_LDORXTX_INT_STATUS)] = RD_REG,
+	[WCD937X_REG(WCD937X_SLEEP_INT_WATCHDOG_CTL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_SLEEP_INT_WATCHDOG_CTL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PAGE_REGISTER)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CHIP_ID0)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CHIP_ID1)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CHIP_ID2)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CHIP_ID3)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_RST_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_TOP_CLK_CFG)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_ANA_CLK_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_DIG_CLK_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_RST_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_PATH_MODE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_RX_RST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_RX0_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_RX1_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_RX2_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_COMP_CTL_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_RX_DELAY_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A1_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A1_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A2_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A2_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A3_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A3_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A4_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A4_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A5_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A5_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A6_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A7_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A1_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A1_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A2_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A2_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A3_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A3_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A4_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A4_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A5_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A5_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A6_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A7_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R5)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R6)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R7)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_EAR_PATH_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_SWR_CLH)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_CLH_BYP)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_TX0_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_TX1_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_TX2_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_TX_RST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_REQ_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_AMIC_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC0_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC1_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC2_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_PRG_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_TEST_CTL_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_TEST_CTL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_T_DATA_0)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_T_DATA_1)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PDM_WD_CTL0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PDM_WD_CTL1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PDM_WD_CTL2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_MODE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_MASK_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_MASK_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_MASK_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_STATUS_0)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_STATUS_1)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_STATUS_2)] = RD_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_CLEAR_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_CLEAR_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_CLEAR_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_LEVEL_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_LEVEL_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_LEVEL_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_SET_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_SET_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_SET_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_TEST_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_TEST_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_INTR_TEST_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_RX0_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_RX1_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_RX2_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_TX_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_LOOP_BACK_MODE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_DAC_TEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_RX_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_TX_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_RX_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_TX_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_RX0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_RX1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_RX2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_TX)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_TX)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PAD_INP_DIS_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DRIVE_STRENGTH_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DRIVE_STRENGTH_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DRIVE_STRENGTH_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_RX_DATA_EDGE_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_TX_DATA_EDGE_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_GPIO_MODE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PIN_CTL_OE)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PIN_CTL_DATA_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PIN_CTL_DATA_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PIN_STATUS_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_PIN_STATUS_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DIG_DEBUG_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_DIG_DEBUG_EN)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_ANA_CSR_DBG_ADD)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_ANA_CSR_DBG_CTL)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SSP_DBG)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_MODE_STATUS_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_MODE_STATUS_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SPARE_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SPARE_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_SPARE_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_0)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_1)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_2)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_3)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_4)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_5)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_6)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_7)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_8)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_9)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_10)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_11)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_12)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_13)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_14)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_15)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_16)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_17)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_18)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_19)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_20)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_21)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_22)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_23)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_24)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_25)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_26)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_27)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_28)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_29)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_30)] = RD_WR_REG,
+	[WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_31)] = RD_WR_REG,
+};
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
new file mode 100644
index 0000000..45a3b96
--- /dev/null
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -0,0 +1,1942 @@
+/*
+ * Copyright (c) 2018, 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 <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <soc/soundwire.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "internal.h"
+#include "../wcdcal-hwdep.h"
+#include "wcd937x-registers.h"
+#include "../msm-cdc-pinctrl.h"
+#include <dt-bindings/sound/audio-codec-port-types.h>
+
+#define WCD9370_VARIANT 0
+#define WCD9375_VARIANT 5
+
+#define NUM_SWRS_DT_PARAMS 5
+
+enum {
+	CODEC_TX = 0,
+	CODEC_RX,
+};
+
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static int wcd937x_handle_pre_irq(void *data);
+static int wcd937x_handle_post_irq(void *data);
+
+static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = {
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_SW_DET, 0, 0x10),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_OCP_INT, 0, 0x20),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_CNP_INT, 0, 0x40),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_OCP_INT, 0, 0x80),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_CNP_INT, 1, 0x01),
+	REGMAP_IRQ_REG(WCD937X_IRQ_EAR_CNP_INT, 1, 0x02),
+	REGMAP_IRQ_REG(WCD937X_IRQ_EAR_SCD_INT, 1, 0x04),
+	REGMAP_IRQ_REG(WCD937X_IRQ_AUX_CNP_INT, 1, 0x08),
+	REGMAP_IRQ_REG(WCD937X_IRQ_AUX_SCD_INT, 1, 0x10),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_PDM_WD_INT, 1, 0x20),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_PDM_WD_INT, 1, 0x40),
+	REGMAP_IRQ_REG(WCD937X_IRQ_AUX_PDM_WD_INT, 1, 0x80),
+	REGMAP_IRQ_REG(WCD937X_IRQ_LDORT_SCD_INT, 2, 0x01),
+	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_MOISTURE_INT, 2, 0x02),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04),
+	REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08),
+};
+
+static struct regmap_irq_chip wcd937x_regmap_irq_chip = {
+	.name = "wcd937x",
+	.irqs = wcd937x_irqs,
+	.num_irqs = ARRAY_SIZE(wcd937x_irqs),
+	.num_regs = 3,
+	.status_base = WCD937X_DIGITAL_INTR_STATUS_0,
+	.mask_base = WCD937X_DIGITAL_INTR_MASK_0,
+	.type_base = WCD937X_DIGITAL_INTR_LEVEL_0,
+	.runtime_pm = true,
+	.handle_post_irq = wcd937x_handle_post_irq,
+	.handle_pre_irq = wcd937x_handle_pre_irq,
+};
+
+static int wcd937x_handle_pre_irq(void *data)
+{
+	struct wcd937x_priv *wcd937x = data;
+	int num_irq_regs = wcd937x->num_irq_regs;
+	int ret = 0;
+	u8 sts[num_irq_regs];
+	struct wcd937x_pdata *pdata;
+
+	pdata = dev_get_platdata(wcd937x->dev);
+
+	memset(sts, 0, sizeof(sts));
+	ret = regmap_bulk_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_0,
+			       sts, num_irq_regs);
+	if (ret < 0) {
+		dev_err(wcd937x->dev, "%s: Failed to read intr status: %d\n",
+			__func__, ret);
+	} else if (ret == 0) {
+		dev_dbg(wcd937x->dev,
+			"%s: clear interrupts except OCP and SCD\n", __func__);
+		/* Do not affect OCP and SCD interrupts */
+		sts[0] = sts[0] & 0x5F;
+		sts[1] = sts[1] & 0xEB;
+		regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_0,
+			     sts[0]);
+		regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_1,
+			     sts[1]);
+		regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_2,
+			     sts[2]);
+	}
+	return IRQ_HANDLED;
+}
+
+static int wcd937x_handle_post_irq(void *data)
+{
+	struct wcd937x_priv *wcd937x = data;
+	int val = 0;
+	struct wcd937x_pdata *pdata = NULL;
+
+	pdata = dev_get_platdata(wcd937x->dev);
+
+	regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_0, &val);
+	if ((val & 0xA0) != 0) {
+		dev_dbg(wcd937x->dev, "%s Clear OCP interupts\n", __func__);
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_DIGITAL_INTR_CLEAR_0, 0xA0, 0x00);
+	}
+	regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_1, &val);
+	if ((val & 0x14) != 0) {
+		dev_dbg(wcd937x->dev, "%s Clear SCD interupts\n", __func__);
+		regmap_update_bits(wcd937x->regmap,
+				   WCD937X_DIGITAL_INTR_CLEAR_1, 0x14, 0x00);
+	}
+	return IRQ_HANDLED;
+}
+
+static int wcd937x_init_reg(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, WCD937X_SLEEP_CTL, 0x0E, 0x0E);
+	snd_soc_update_bits(codec, WCD937X_SLEEP_CTL, 0x80, 0x80);
+	usleep_range(1000, 1010);
+	snd_soc_update_bits(codec, WCD937X_SLEEP_CTL, 0x40, 0x40);
+	usleep_range(1000, 1010);
+	snd_soc_update_bits(codec, WCD937X_LDORXTX_CONFIG, 0x10, 0x00);
+	snd_soc_update_bits(codec, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0x80);
+	snd_soc_update_bits(codec, WCD937X_ANA_BIAS, 0x80, 0x80);
+	snd_soc_update_bits(codec, WCD937X_ANA_BIAS, 0x40, 0x40);
+	usleep_range(10000, 10010);
+	snd_soc_update_bits(codec, WCD937X_ANA_BIAS, 0x40, 0x00);
+
+	return 0;
+}
+
+static int wcd937x_set_port_params(struct snd_soc_codec *codec, u8 slv_prt_type,
+			u8 *port_id, u8 *num_ch, u8 *ch_mask, u32 *ch_rate,
+			u8 *port_type, u8 path)
+{
+	int i, j;
+	u8 num_ports;
+	struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT];
+	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+
+	switch (path) {
+	case CODEC_RX:
+		map = &wcd937x->rx_port_mapping;
+		num_ports = wcd937x->num_rx_ports;
+		break;
+	case CODEC_TX:
+		map = &wcd937x->tx_port_mapping;
+		num_ports = wcd937x->num_tx_ports;
+		break;
+	}
+
+	for (i = 0; i <= num_ports; i++) {
+		for (j = 0; j < MAX_CH_PER_PORT; j++) {
+			if ((*map)[i][j].slave_port_type == slv_prt_type)
+				goto found;
+		}
+	}
+found:
+	if (i > num_ports || j == MAX_CH_PER_PORT) {
+		dev_err(codec->dev, "%s Failed to find slave port for type %u\n",
+						__func__, slv_prt_type);
+		return -EINVAL;
+	}
+	*port_id = i;
+	*num_ch = (*map)[i][j].num_ch;
+	*ch_mask = (*map)[i][j].ch_mask;
+	*ch_rate = (*map)[i][j].ch_rate;
+	*port_type = (*map)[i][j].master_port_type;
+
+	return 0;
+}
+
+static int wcd937x_parse_port_mapping(struct device *dev,
+			char *prop, u8 path)
+{
+	u32 *dt_array, map_size, map_length;
+	u32 port_num, ch_mask, ch_rate, old_port_num = 0;
+	u32 slave_port_type, master_port_type;
+	u32 i, ch_iter = 0;
+	int ret = 0;
+	u8 *num_ports;
+	struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT];
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+	switch (path) {
+	case CODEC_RX:
+		map = &wcd937x->rx_port_mapping;
+		num_ports = &wcd937x->num_rx_ports;
+		break;
+	case CODEC_TX:
+		map = &wcd937x->tx_port_mapping;
+		num_ports = &wcd937x->num_tx_ports;
+		break;
+	}
+
+	if (!of_find_property(dev->of_node, prop,
+				&map_size)) {
+		dev_err(dev, "missing port mapping prop %s\n", prop);
+		goto err_pdata_fail;
+	}
+
+	map_length = map_size / (NUM_SWRS_DT_PARAMS * sizeof(u32));
+
+	dt_array = kzalloc(map_size, GFP_KERNEL);
+
+	if (!dt_array) {
+		ret = -ENOMEM;
+		goto err_pdata_fail;
+	}
+	ret = of_property_read_u32_array(dev->of_node, prop, dt_array,
+				NUM_SWRS_DT_PARAMS * map_length);
+	if (ret) {
+		dev_err(dev, "%s: Failed to read  port mapping from prop %s\n",
+					__func__, prop);
+		goto err_pdata_fail;
+	}
+
+	for (i = 0; i < map_length; i++) {
+		port_num = dt_array[NUM_SWRS_DT_PARAMS * i];
+		slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1];
+		ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2];
+		ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3];
+		master_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 4];
+
+		if (port_num != old_port_num)
+			ch_iter = 0;
+
+		(*map)[port_num][ch_iter].slave_port_type = slave_port_type;
+		(*map)[port_num][ch_iter].ch_mask = ch_mask;
+		(*map)[port_num][ch_iter].master_port_type = master_port_type;
+		(*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask);
+		(*map)[port_num][ch_iter++].ch_rate = ch_rate;
+		old_port_num = port_num;
+	}
+	*num_ports = port_num;
+	kfree(dt_array);
+	return 0;
+
+err_pdata_fail:
+	kfree(dt_array);
+	return -EINVAL;
+}
+
+static int wcd937x_tx_connect_port(struct snd_soc_codec *codec,
+					u8 slv_port_type, u8 enable)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	u8 port_id;
+	u8 num_ch;
+	u8 ch_mask;
+	u32 ch_rate;
+	u8 port_type;
+	u8 num_port = 1;
+	int ret = 0;
+
+	ret = wcd937x_set_port_params(codec, slv_port_type, &port_id,
+				&num_ch, &ch_mask, &ch_rate,
+				&port_type, CODEC_TX);
+
+	if (ret)
+		return ret;
+
+	if (enable)
+		ret = swr_connect_port(wcd937x->tx_swr_dev, &port_id,
+					num_port, &ch_mask, &ch_rate,
+					 &num_ch, &port_type);
+	else
+		ret = swr_disconnect_port(wcd937x->tx_swr_dev, &port_id,
+					num_port, &ch_mask, &port_type);
+	return ret;
+
+}
+static int wcd937x_rx_connect_port(struct snd_soc_codec *codec,
+					u8 slv_port_type, u8 enable)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	u8 port_id;
+	u8 num_ch;
+	u8 ch_mask;
+	u32 ch_rate;
+	u8 port_type;
+	u8 num_port = 1;
+	int ret = 0;
+
+	ret = wcd937x_set_port_params(codec, slv_port_type, &port_id,
+				&num_ch, &ch_mask, &ch_rate,
+				&port_type, CODEC_RX);
+
+	if (ret)
+		return ret;
+
+	if (enable)
+		ret = swr_connect_port(wcd937x->rx_swr_dev, &port_id,
+					num_port, &ch_mask, &ch_rate,
+					&num_ch, &port_type);
+	else
+		ret = swr_disconnect_port(wcd937x->rx_swr_dev, &port_id,
+					num_port, &ch_mask, &port_type);
+	return ret;
+}
+
+static int wcd937x_rx_clk_enable(struct snd_soc_codec *codec)
+{
+
+	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+
+	if (wcd937x->rx_clk_cnt == 0) {
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x08, 0x08);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES, 0x01, 0x01);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_RX0_CTL,
+				    0x40, 0x00);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x02, 0x02);
+	}
+	wcd937x->rx_clk_cnt++;
+
+	return 0;
+}
+
+static int wcd937x_rx_clk_disable(struct snd_soc_codec *codec)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+
+	wcd937x->rx_clk_cnt--;
+	if (wcd937x->rx_clk_cnt == 0) {
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES, 0x40, 0x00);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES, 0x80, 0x00);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES, 0x01, 0x00);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x02, 0x00);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x01, 0x00);
+	}
+	return 0;
+}
+
+/*
+ * wcd937x_soc_get_mbhc: get wcd937x_mbhc handle of corresponding codec
+ * @codec: handle to snd_soc_codec *
+ *
+ * return wcd937x_mbhc handle or error code in case of failure
+ */
+struct wcd937x_mbhc *wcd937x_soc_get_mbhc(struct snd_soc_codec *codec)
+{
+	struct wcd937x_priv *wcd937x;
+
+	if (!codec) {
+		pr_err("%s: Invalid params, NULL codec\n", __func__);
+		return NULL;
+	}
+	wcd937x = snd_soc_codec_get_drvdata(codec);
+
+	if (!wcd937x) {
+		pr_err("%s: Invalid params, NULL tavil\n", __func__);
+		return NULL;
+	}
+
+	return wcd937x->mbhc;
+}
+EXPORT_SYMBOL(wcd937x_soc_get_mbhc);
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+				    0x04, 0x04);
+		snd_soc_update_bits(codec, WCD937X_HPH_RDAC_CLK_CTL1,
+				    0x80, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+				    0x0F, 0x02);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_COMP_CTL_0,
+				    0x02, 0x02);
+		usleep_range(5000, 5010);
+		snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+		    wcd937x->rx_swr_dev->dev_num,
+		    false);
+		break;
+	}
+
+	return ret;
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+				    0x08, 0x08);
+		snd_soc_update_bits(codec, WCD937X_HPH_RDAC_CLK_CTL1,
+				    0x80, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+				    0x0F, 0x02);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_COMP_CTL_0,
+				    0x01, 0x01);
+		usleep_range(5000, 5010);
+		snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+		    wcd937x->rx_swr_dev->dev_num,
+		    false);
+		break;
+	}
+
+	return ret;
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+				    0x04, 0x04);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x01, 0x01);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_COMP_CTL_0,
+				    0x02, 0x02);
+		usleep_range(5000, 5010);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+		    wcd937x->rx_swr_dev->dev_num,
+		    false);
+		break;
+	};
+	return ret;
+
+}
+
+static int wcd937x_codec_aux_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_rx_clk_enable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x04, 0x04);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x04, 0x04);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_AUX_GAIN_CTL,
+				    0x01, 0x01);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+		    wcd937x->rx_swr_dev->dev_num,
+		    false);
+		wcd937x_rx_clk_disable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x04, 0x00);
+		break;
+	};
+	return ret;
+
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x10, 0x10);
+		usleep_range(100, 110);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(7000, 7010);
+		snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x02, 0x02);
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+					    wcd937x->rx_swr_dev->dev_num,
+					    true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(7000, 7010);
+		snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x10, 0x00);
+		break;
+	};
+	return ret;
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x0C, 0x08);
+		snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x20, 0x20);
+		usleep_range(100, 110);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(7000, 7010);
+		snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x02, 0x02);
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+				    wcd937x->rx_swr_dev->dev_num,
+				    true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(7000, 7010);
+		snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x20, 0x00);
+		break;
+	};
+	return ret;
+}
+
+static int wcd937x_codec_enable_aux_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x80, 0x80);
+		usleep_range(500, 510);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_2, 0xFF, 0x3A);
+		usleep_range(500, 510);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(1000, 1010);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x20, 0x20);
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+			    wcd937x->rx_swr_dev->dev_num,
+			    true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(1000, 1010);
+		usleep_range(1000, 1010);
+		break;
+	};
+	return ret;
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x08, 0x08);
+		usleep_range(500, 510);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_2, 0xFF, 0x3A);
+		usleep_range(500, 510);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(6000, 6010);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x02, 0x02);
+		ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev,
+			    wcd937x->rx_swr_dev->dev_num,
+			    true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(7000, 7010);
+		break;
+	};
+	return ret;
+}
+
+static int wcd937x_enable_rx1(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 wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEG_CTRL_4,
+				    0xF0, 0x80);
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEGDAC_CTRL_2,
+				    0xE0, 0xA0);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_3,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_2,
+				    0xFF, 0x1C);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x40, 0x40);
+		usleep_range(100, 110);
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEGDAC_CTRL_2,
+				    0xE0, 0xE0);
+		usleep_range(100, 110);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x80, 0x80);
+		usleep_range(500, 510);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_2, 0xFF, 0x3A);
+		usleep_range(500, 510);
+
+		wcd937x_rx_connect_port(codec, HPH_L, true);
+		wcd937x_rx_connect_port(codec, COMP_L, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_rx_connect_port(codec, HPH_L, false);
+		wcd937x_rx_connect_port(codec, COMP_L, false);
+		wcd937x_rx_clk_disable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x01, 0x00);
+		break;
+	};
+	return 0;
+}
+static int wcd937x_enable_rx2(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 wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEG_CTRL_4,
+				    0xF0, 0x80);
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEGDAC_CTRL_2,
+				    0xE0, 0xA0);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_3, 0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_2, 0xFF, 0x1C);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x40, 0x40);
+		usleep_range(100, 110);
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEGDAC_CTRL_2,
+				    0xE0, 0xE0);
+		usleep_range(100, 110);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x80, 0x80);
+		usleep_range(500, 510);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_2, 0xFF, 0x3A);
+		usleep_range(500, 510);
+
+		wcd937x_rx_connect_port(codec, HPH_R, true);
+		wcd937x_rx_connect_port(codec, COMP_R, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_rx_connect_port(codec, HPH_R, false);
+		wcd937x_rx_connect_port(codec, COMP_R, false);
+		wcd937x_rx_clk_disable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x02, 0x00);
+		break;
+	};
+
+	return 0;
+}
+
+static int wcd937x_enable_rx3(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 wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEG_CTRL_2,
+				    0xE0, 0xA0);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_3, 0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_CLASSH_MODE_2, 0xFF, 0x1C);
+		snd_soc_update_bits(codec, WCD937X_ANA_RX_SUPPLIES,
+				    0x40, 0x40);
+		usleep_range(100, 110);
+		snd_soc_update_bits(codec, WCD937X_FLYBACK_VNEG_CTRL_2,
+				    0xE0, 0xE0);
+		usleep_range(100, 110);
+		wcd937x_rx_connect_port(codec, LO, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_rx_connect_port(codec, LO, false);
+		usleep_range(6000, 6010);
+		wcd937x_rx_clk_disable(codec);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x04, 0x00);
+		break;
+	}
+	return 0;
+
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	unsigned int dmic;
+	char *wname;
+	int ret = 0;
+
+	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;
+	}
+
+	dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (dmic) {
+	case 0:
+	case 1:
+		dmic_clk_cnt = &(wcd937x->dmic_0_1_clk_cnt);
+		dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC0_CTL;
+		break;
+	case 2:
+	case 3:
+		dmic_clk_cnt = &(wcd937x->dmic_2_3_clk_cnt);
+		dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC1_CTL;
+		break;
+	case 4:
+	case 5:
+		dmic_clk_cnt = &(wcd937x->dmic_4_5_clk_cnt);
+		dmic_clk_reg = WCD937X_DIGITAL_CDC_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:
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x80, 0x80);
+		snd_soc_update_bits(codec, dmic_clk_reg, 0x07, 0x02);
+		snd_soc_update_bits(codec, dmic_clk_reg, 0x08, 0x08);
+		snd_soc_update_bits(codec, dmic_clk_reg, 0x70, 0x20);
+		wcd937x_tx_connect_port(codec, DMIC0 + (w->shift), true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_tx_connect_port(codec, DMIC0 + (w->shift), false);
+		break;
+
+	};
+	return 0;
+}
+
+/*
+ * wcd937x_get_micb_vout_ctl_val: converts micbias from volts to register value
+ * @micb_mv: micbias in mv
+ *
+ * return register value converted
+ */
+int wcd937x_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(wcd937x_get_micb_vout_ctl_val);
+
+/*
+ * wcd937x_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 wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_codec *codec,
+				   int req_volt, int micb_num)
+{
+	struct wcd937x_priv *wcd937x = 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 = WCD937X_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD937X_ANA_MICB2;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD937X_ANA_MICB3;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mutex_lock(&wcd937x->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 = wcd937x_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(&wcd937x->micb_lock);
+	return ret;
+}
+EXPORT_SYMBOL(wcd937x_mbhc_micb_adjust_voltage);
+
+static int wcd937x_tx_swr_ctrl(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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = swr_slvdev_datapath_control(wcd937x->tx_swr_dev,
+		    wcd937x->tx_swr_dev->dev_num,
+		    true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = swr_slvdev_datapath_control(wcd937x->tx_swr_dev,
+		    wcd937x->tx_swr_dev->dev_num,
+		    false);
+		break;
+	};
+
+	return ret;
+}
+
+static int wcd937x_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 wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x80, 0x80);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x08, 0x08);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x10, 0x10);
+		wcd937x_tx_connect_port(codec, ADC1 + (w->shift), true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_tx_connect_port(codec, ADC1 + (w->shift), false);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x08, 0x00);
+		break;
+	};
+
+	return 0;
+}
+
+static int wcd937x_enable_req(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 wname: %s event: %d\n", __func__,
+		w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_REQ_CTL,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_REQ_CTL, 0x01,
+				    0x00);
+		snd_soc_update_bits(codec, WCD937X_ANA_TX_CH2, 0x40, 0x40);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x10, 0x10);
+		snd_soc_update_bits(codec, WCD937X_ANA_TX_CH1, 0x80, 0x80);
+		snd_soc_update_bits(codec, WCD937X_ANA_TX_CH2, 0x40, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, WCD937X_ANA_TX_CH1, 0x80, 0x00);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x10, 0x00);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+				    0x10, 0x00);
+		snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+				    0x80, 0x00);
+		break;
+	};
+	return 0;
+}
+
+int wcd937x_micbias_control(struct snd_soc_codec *codec,
+				int micb_num, int req, bool is_dapm)
+{
+
+	struct wcd937x_priv *wcd937x = 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 > WCD937X_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 = WCD937X_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD937X_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 = WCD937X_ANA_MICB3;
+		break;
+	default:
+		dev_err(codec->dev, "%s: Invalid micbias number: %d\n",
+			__func__, micb_num);
+		return -EINVAL;
+	};
+	mutex_lock(&wcd937x->micb_lock);
+
+	switch (req) {
+	case MICB_PULLUP_ENABLE:
+		wcd937x->pullup_ref[micb_index]++;
+		if ((wcd937x->pullup_ref[micb_index] == 1) &&
+		    (wcd937x->micb_ref[micb_index] == 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+		break;
+	case MICB_PULLUP_DISABLE:
+		if (wcd937x->pullup_ref[micb_index] > 0)
+			wcd937x->pullup_ref[micb_index]--;
+		if ((wcd937x->pullup_ref[micb_index] == 0) &&
+		    (wcd937x->micb_ref[micb_index] == 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
+		break;
+	case MICB_ENABLE:
+		wcd937x->micb_ref[micb_index]++;
+		if (wcd937x->micb_ref[micb_index] == 1) {
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40);
+			if (post_on_event)
+				blocking_notifier_call_chain(&wcd937x->notifier,
+							     post_on_event,
+							     &wcd937x->mbhc);
+		}
+		if (is_dapm && post_dapm_on)
+			blocking_notifier_call_chain(&wcd937x->notifier,
+						     post_dapm_on,
+						     &wcd937x->mbhc);
+		break;
+	case MICB_DISABLE:
+		if (wcd937x->micb_ref[micb_index] > 0)
+			wcd937x->micb_ref[micb_index]--;
+		if ((wcd937x->micb_ref[micb_index] == 0) &&
+		    (wcd937x->pullup_ref[micb_index] > 0))
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
+		else if ((wcd937x->micb_ref[micb_index] == 0) &&
+			 (wcd937x->pullup_ref[micb_index] == 0)) {
+			if (pre_off_event)
+				blocking_notifier_call_chain(&wcd937x->notifier,
+							     pre_off_event,
+							     &wcd937x->mbhc);
+			snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
+			if (post_off_event)
+				blocking_notifier_call_chain(&wcd937x->notifier,
+							     post_off_event,
+							     &wcd937x->mbhc);
+		}
+		if (is_dapm && post_dapm_off)
+			blocking_notifier_call_chain(&wcd937x->notifier,
+							post_dapm_off,
+							&wcd937x->mbhc);
+		break;
+	};
+
+	dev_dbg(codec->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
+		__func__, micb_num, wcd937x->micb_ref[micb_index],
+		wcd937x->pullup_ref[micb_index]);
+	mutex_unlock(&wcd937x->micb_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd937x_micbias_control);
+
+static int __wcd937x_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
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd937x_micbias_control(codec, micb_num, MICB_ENABLE, true);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(1000, 1100);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd937x_micbias_control(codec, micb_num, MICB_DISABLE, true);
+		break;
+	};
+
+	return 0;
+
+}
+
+static int wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kcontrol,
+					int event)
+{
+	return __wcd937x_codec_enable_micbias(w, event);
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wcd937x->hph_mode;
+	return 0;
+}
+
+static int wcd937x_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 wcd937x_priv *wcd937x = 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 class_AB\n",
+			__func__);
+		mode_val = 3; /* enum will be updated later */
+	}
+	wcd937x->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 struct snd_kcontrol_new wcd937x_snd_controls[] = {
+	SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+		wcd937x_rx_hph_mode_get, wcd937x_rx_hph_mode_put),
+
+	SOC_SINGLE_TLV("HPHL Volume", WCD937X_HPH_L_EN, 0, 20, 1, line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", WCD937X_HPH_R_EN, 0, 20, 1, line_gain),
+	SOC_SINGLE_TLV("ADC1 Volume", WCD937X_ANA_TX_CH1, 0, 20, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", WCD937X_ANA_TX_CH2, 0, 20, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", WCD937X_ANA_TX_CH3, 0, 20, 0, analog_gain),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc3_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic3_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic4_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic5_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic6_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new aux_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc2_mux_text[] = {
+	"INP2", "INP3"
+};
+
+static const char * const rdac3_mux_text[] = {
+	"RX1", "RX3"
+};
+
+static const struct soc_enum adc2_enum =
+	SOC_ENUM_SINGLE(WCD937X_TX_NEW_TX_CH2_SEL, 7,
+		ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+
+static const struct soc_enum rdac3_enum =
+	SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0,
+		ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text);
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+	SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+static const struct snd_kcontrol_new rx_rdac3_mux =
+	SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum);
+
+static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = {
+
+	/*input widgets*/
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_INPUT("IN1_HPHL"),
+	SND_SOC_DAPM_INPUT("IN2_HPHR"),
+	SND_SOC_DAPM_INPUT("IN3_AUX"),
+
+	/*tx widgets*/
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
+				wcd937x_codec_enable_adc,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 0, 1,
+				wcd937x_codec_enable_adc,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0,
+				NULL, 0, wcd937x_enable_req,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 0, 0,
+				NULL, 0, wcd937x_enable_req,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
+				&tx_adc2_mux),
+
+	/*tx mixers*/
+	SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0,
+				adc1_switch, ARRAY_SIZE(adc1_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0,
+				adc2_switch, ARRAY_SIZE(adc2_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+
+	/* micbias widgets*/
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0,
+				wcd937x_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,
+				wcd937x_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,
+				wcd937x_codec_enable_micbias,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
+
+	/*rx widgets*/
+	SND_SOC_DAPM_PGA_E("EAR PGA", WCD937X_ANA_EAR, 7, 0, NULL, 0,
+				wcd937x_codec_enable_ear_pa,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("AUX PGA", WCD937X_AUX_AUXPA, 7, 0, NULL, 0,
+				wcd937x_codec_enable_aux_pa,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHL PGA", WCD937X_ANA_HPH, 7, 0, NULL, 0,
+				wcd937x_codec_enable_hphl_pa,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHR PGA", WCD937X_ANA_HPH, 6, 0, NULL, 0,
+				wcd937x_codec_enable_hphr_pa,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+				wcd937x_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("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+				wcd937x_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("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+				wcd937x_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("RDAC4", NULL, SND_SOC_NOPM, 0, 0,
+				wcd937x_codec_aux_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_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux),
+
+	SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0,
+				wcd937x_enable_rx1, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0,
+				wcd937x_enable_rx2, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0,
+				wcd937x_enable_rx3, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+
+	/* rx mixer widgets*/
+
+	SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+			   ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+	SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0,
+			   aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)),
+	SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+			   hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+	SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+			   hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+	/*output widgets tx*/
+
+	SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+
+	/*output widgets rx*/
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("AUX"),
+	SND_SOC_DAPM_OUTPUT("HPHL"),
+	SND_SOC_DAPM_OUTPUT("HPHR"),
+
+};
+
+static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = {
+
+	/*input widgets*/
+	SND_SOC_DAPM_INPUT("AMIC4"),
+
+	/*tx widgets*/
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 0, 2,
+				wcd937x_codec_enable_adc,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 0, 0,
+				NULL, 0, wcd937x_enable_req,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+				wcd937x_codec_enable_dmic,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 1,
+				wcd937x_codec_enable_dmic,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 2,
+				wcd937x_codec_enable_dmic,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 3,
+				wcd937x_codec_enable_dmic,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 4,
+				wcd937x_codec_enable_dmic,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 5,
+				wcd937x_codec_enable_dmic,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/*tx mixer widgets*/
+	SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0,
+				0, dmic1_switch, ARRAY_SIZE(dmic1_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0,
+				0, dmic2_switch, ARRAY_SIZE(dmic2_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 0,
+				0, dmic3_switch, ARRAY_SIZE(dmic3_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 0,
+				0, dmic4_switch, ARRAY_SIZE(dmic4_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 0,
+				0, dmic5_switch, ARRAY_SIZE(dmic5_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 0,
+				0, dmic6_switch, ARRAY_SIZE(dmic6_switch),
+				wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 0, 0, adc3_switch,
+				ARRAY_SIZE(adc3_switch), wcd937x_tx_swr_ctrl,
+				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/*output widgets*/
+	SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"),
+	SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"),
+
+};
+
+static const struct snd_soc_dapm_route wcd937x_audio_map[] = {
+
+	{"ADC2_OUTPUT", NULL, "ADC2_MIXER"},
+	{"ADC2_MIXER", "Switch", "ADC2 REQ"},
+	{"ADC2 REQ", "NULL", "ADC2"},
+	{"ADC2", "NULL", "ADC2 MUX"},
+	{"ADC2 MUX", "INP3", "AMIC3"},
+	{"ADC2 MUX", "INP2", "AMIC2"},
+
+
+	{"ADC1_OUTPUT", NULL, "ADC1_MIXER"},
+	{"ADC1_MIXER", "Switch", "ADC1 REQ"},
+	{"ADC1 REQ", NULL, "ADC1"},
+	{"ADC1", NULL, "AMIC1"},
+
+	{"RX1", NULL, "IN1_HPHL"},
+	{"RDAC1", NULL, "RX1"},
+	{"HPHL_RDAC", "Switch", "RDAC1"},
+	{"HPHL PGA", NULL, "HPHL_RDAC"},
+	{"HPHL", NULL, "HPHL PGA"},
+
+	{"RX2", NULL, "IN2_HPHR"},
+	{"RDAC2", NULL, "RX2"},
+	{"HPHR_RDAC", "Switch", "RDAC2"},
+	{"HPHR PGA", NULL, "HPHR_RDAC"},
+	{"HPHR", NULL, "HPHR PGA"},
+
+	{"RX3", NULL, "IN3_AUX"},
+	{"RDAC4", NULL, "RX3"},
+	{"AUX_RDAC", "Switch", "RDAC4"},
+	{"AUX PGA", NULL, "AUX_RDAC"},
+	{"AUX", NULL, "AUX PGA"},
+
+	{"RDAC3_MUX", "RX3", "RX3"},
+	{"RDAC3_MUX", "RX1", "RX1"},
+	{"RDAC3", NULL, "RDAC3_MUX"},
+	{"EAR_RDAC", "Switch", "RDAC3"},
+	{"EAR PGA", NULL, "EAR_RDAC"},
+	{"EAR", NULL, "EAR PGA"},
+
+};
+
+static const struct snd_soc_dapm_route wcd9375_audio_map[] = {
+
+	{"ADC3_OUTPUT", NULL, "ADC3_MIXER"},
+	{"ADC3_MIXER", "Switch", "ADC3 REQ"},
+	{"ADC3 REQ", NULL, "ADC3"},
+	{"ADC3", NULL, "AMIC4"},
+
+	{"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"},
+	{"DMIC1_MIXER", "Switch", "DMIC1"},
+
+	{"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"},
+	{"DMIC2_MIXER", "Switch", "DMIC2"},
+
+	{"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"},
+	{"DMIC3_MIXER", "Switch", "DMIC3"},
+
+	{"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"},
+	{"DMIC4_MIXER", "Switch", "DMIC4"},
+
+	{"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"},
+	{"DMIC5_MIXER", "Switch", "DMIC5"},
+
+	{"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"},
+	{"DMIC6_MIXER", "Switch", "DMIC6"},
+
+};
+
+static int wcd937x_soc_codec_probe(struct snd_soc_codec *codec)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int variant;
+	int ret = -EINVAL;
+
+	dev_info(codec->dev, "%s()\n", __func__);
+	wcd937x = snd_soc_codec_get_drvdata(codec);
+
+	if (!wcd937x)
+		return -EINVAL;
+
+	wcd937x->codec = codec;
+
+	variant = (snd_soc_read(codec, WCD937X_DIGITAL_EFUSE_REG_0) & 0x0E) >> 1;
+	wcd937x->variant = variant;
+
+	wcd937x->fw_data = devm_kzalloc(codec->dev,
+					sizeof(*(wcd937x->fw_data)),
+					GFP_KERNEL);
+	if (!wcd937x->fw_data) {
+		dev_err(codec->dev, "Failed to allocate fw_data\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	set_bit(WCD9XXX_MBHC_CAL, wcd937x->fw_data->cal_bit);
+	ret = wcd_cal_create_hwdep(wcd937x->fw_data,
+				   WCD9XXX_CODEC_HWDEP_NODE, codec);
+
+	if (ret < 0) {
+		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
+		goto err_hwdep;
+	}
+
+	ret = wcd937x_mbhc_init(&wcd937x->mbhc, codec, wcd937x->fw_data);
+	if (ret) {
+		pr_err("%s: mbhc initialization failed\n", __func__);
+		goto err_hwdep;
+	}
+
+	wcd937x_init_reg(codec);
+
+	if (wcd937x->variant == WCD9375_VARIANT) {
+		ret = snd_soc_dapm_new_controls(dapm, wcd9375_dapm_widgets,
+					ARRAY_SIZE(wcd9375_dapm_widgets));
+		if (ret < 0) {
+			dev_err(codec->dev, "%s: Failed to add snd_ctls\n",
+				__func__);
+			goto err_hwdep;
+		}
+		ret = snd_soc_dapm_add_routes(dapm, wcd9375_audio_map,
+					ARRAY_SIZE(wcd9375_audio_map));
+		if (ret < 0) {
+			dev_err(codec->dev, "%s: Failed to add routes\n",
+				__func__);
+			goto err_hwdep;
+		}
+		ret = snd_soc_dapm_new_widgets(dapm->card);
+		if (ret < 0) {
+			dev_err(codec->dev, "%s: Failed to add widgets\n",
+				__func__);
+			goto err_hwdep;
+		}
+	}
+	return ret;
+
+err_hwdep:
+	wcd937x->fw_data = NULL;
+
+err:
+	return ret;
+}
+
+static int wcd937x_soc_codec_remove(struct snd_soc_codec *codec)
+{
+	struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec);
+
+	if (!wcd937x)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct regmap *wcd937x_get_regmap(struct device *dev)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+	return wcd937x->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wcd937x = {
+	.probe = wcd937x_soc_codec_probe,
+	.remove = wcd937x_soc_codec_remove,
+	.get_regmap = wcd937x_get_regmap,
+	.component_driver = {
+		.controls = wcd937x_snd_controls,
+		.num_controls = ARRAY_SIZE(wcd937x_snd_controls),
+		.dapm_widgets = wcd937x_dapm_widgets,
+		.num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets),
+		.dapm_routes = wcd937x_audio_map,
+		.num_dapm_routes = ARRAY_SIZE(wcd937x_audio_map),
+	},
+};
+
+int wcd937x_reset(struct device *dev)
+{
+	struct wcd937x_priv *wcd937x = NULL;
+	int rc = 0;
+	int value = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd937x = dev_get_drvdata(dev);
+	if (!wcd937x)
+		return -EINVAL;
+
+	if (!wcd937x->rst_np) {
+		dev_err(dev, "%s: reset gpio device node not specified\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	value = msm_cdc_pinctrl_get_state(wcd937x->rst_np);
+	if (value > 0)
+		return 0;
+
+	rc = msm_cdc_pinctrl_select_sleep_state(wcd937x->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 */
+	usleep_range(20, 30);
+
+	rc = msm_cdc_pinctrl_select_active_state(wcd937x->rst_np);
+	if (rc) {
+		dev_err(dev, "%s: wcd active state request fail!\n",
+				__func__);
+		return rc;
+	}
+	/* 20ms sleep required after pulling the reset gpio to HIGH */
+	usleep_range(20, 30);
+
+	return rc;
+}
+
+struct wcd937x_pdata *wcd937x_populate_dt_data(struct device *dev)
+{
+	struct wcd937x_pdata *pdata = NULL;
+
+	pdata = devm_kzalloc(dev, sizeof(struct wcd937x_pdata),
+				GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	pdata->rst_np = of_parse_phandle(dev->of_node,
+			"qcom,wcd937x-reset-node", 0);
+
+	if (!pdata->rst_np) {
+		dev_err(dev, "%s: Looking up %s property in node %s failed\n",
+				__func__, "qcom,wcd937x-reset-node",
+				dev->of_node->full_name);
+		return NULL;
+	}
+
+	pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-slave", 0);
+	pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0);
+
+	return pdata;
+}
+
+static int wcd937x_bind(struct device *dev)
+{
+	int ret = 0, i = 0;
+	struct wcd937x_priv *wcd937x = NULL;
+	struct wcd937x_pdata *pdata = NULL;
+
+	wcd937x = devm_kzalloc(dev, sizeof(struct wcd937x_priv), GFP_KERNEL);
+	if (!wcd937x)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, wcd937x);
+
+	pdata = wcd937x_populate_dt_data(dev);
+	if (!pdata) {
+		dev_err(dev, "%s: Fail to obtain platform data\n", __func__);
+		return -EINVAL;
+	}
+
+	wcd937x->rst_np = pdata->rst_np;
+	wcd937x_reset(dev);
+	/*
+	 * Add 5msec delay to provide sufficient time for
+	 * soundwire auto enumeration of slave devices as
+	 * as per HW requirement.
+	 */
+	usleep_range(5000, 5010);
+	ret = component_bind_all(dev, wcd937x);
+	if (ret) {
+		dev_err(dev, "%s: Slave bind failed, ret = %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ret = wcd937x_parse_port_mapping(dev, "qcom,rx_swr_ch_map", CODEC_RX);
+	ret |= wcd937x_parse_port_mapping(dev, "qcom,tx_swr_ch_map", CODEC_TX);
+
+	if (ret) {
+		dev_err(dev, "Failed to read port mapping\n");
+		goto err;
+	}
+
+	wcd937x->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave);
+	if (!wcd937x->rx_swr_dev) {
+		dev_err(dev, "%s: Could not find RX swr slave device\n",
+			 __func__);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	wcd937x->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave);
+	if (!wcd937x->tx_swr_dev) {
+		dev_err(dev, "%s: Could not find TX swr slave device\n",
+			__func__);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	wcd937x->regmap = devm_regmap_init_swr(wcd937x->tx_swr_dev,
+					       &wcd937x_regmap_config);
+	if (!wcd937x->regmap) {
+		dev_err(dev, "%s: Regmap init failed\n",
+				__func__);
+		goto err;
+	}
+
+	/* Set all interupts as edge triggered */
+	for (i = 0; i < wcd937x_regmap_irq_chip.num_regs; i++)
+		regmap_write(wcd937x->regmap,
+			     (WCD937X_DIGITAL_INTR_LEVEL_0 + i), 0);
+
+	wcd937x->irq_info->wcd_regmap_irq_chip = &wcd937x_regmap_irq_chip;
+	wcd937x->irq_info->codec_name = "WCD937X";
+	wcd937x->irq_info->regmap = wcd937x->regmap;
+	wcd937x->irq_info->dev = dev;
+	ret = wcd_irq_init(wcd937x->irq_info, &wcd937x->virq);
+
+	if (ret) {
+		dev_err(wcd937x->dev, "%s: IRQ init failed: %d\n",
+			__func__, ret);
+		goto err;
+	}
+	wcd937x->tx_swr_dev->slave_irq = wcd937x->virq;
+
+	ret = snd_soc_register_codec(dev, &soc_codec_dev_wcd937x,
+				     NULL, 0);
+	if (ret) {
+		dev_err(dev, "%s: Codec registration failed\n",
+				__func__);
+		goto err_irq;
+	}
+
+	return ret;
+err_irq:
+	wcd_irq_exit(wcd937x->irq_info, wcd937x->virq);
+err:
+	component_unbind_all(dev, wcd937x);
+	return ret;
+}
+
+static void wcd937x_unbind(struct device *dev)
+{
+	struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+	wcd_irq_exit(wcd937x->irq_info, wcd937x->virq);
+	snd_soc_unregister_codec(dev);
+	component_unbind_all(dev, wcd937x);
+}
+
+static const struct of_device_id wcd937x_dt_match[] = {
+	{ .compatible = "qcom,wcd937x-codec" },
+	{}
+};
+
+static const struct component_master_ops wcd937x_comp_ops = {
+	.bind   = wcd937x_bind,
+	.unbind = wcd937x_unbind,
+};
+
+static int wcd937x_compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static void wcd937x_release_of(struct device *dev, void *data)
+{
+	of_node_put(data);
+}
+
+static int wcd937x_add_slave_components(struct device *dev,
+				struct component_match **matchptr)
+{
+	struct device_node *np, *rx_node, *tx_node;
+
+	np = dev->of_node;
+
+	rx_node = of_parse_phandle(np, "qcom,rx-slave", 0);
+	if (!rx_node) {
+		dev_err(dev, "%s: Rx-slave node not defined\n", __func__);
+		return -ENODEV;
+	}
+	of_node_get(rx_node);
+	component_match_add_release(dev, matchptr,
+			wcd937x_release_of,
+			wcd937x_compare_of,
+			rx_node);
+
+	tx_node = of_parse_phandle(np, "qcom,tx-slave", 0);
+	if (!tx_node) {
+		dev_err(dev, "%s: Tx-slave node not defined\n", __func__);
+			return -ENODEV;
+	}
+	of_node_get(tx_node);
+	component_match_add_release(dev, matchptr,
+			wcd937x_release_of,
+			wcd937x_compare_of,
+			tx_node);
+	return 0;
+}
+
+static int wcd937x_probe(struct platform_device *pdev)
+{
+	struct component_match *match = NULL;
+	int ret;
+
+	ret = wcd937x_add_slave_components(&pdev->dev, &match);
+	if (ret)
+		return ret;
+
+	return component_master_add_with_match(&pdev->dev,
+					&wcd937x_comp_ops, match);
+}
+
+static int wcd937x_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &wcd937x_comp_ops);
+	return 0;
+}
+
+static struct platform_driver wcd937x_codec_driver = {
+	.probe = wcd937x_probe,
+	.remove = wcd937x_remove,
+	.driver = {
+		.name = "wcd937x_codec",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(wcd937x_dt_match),
+	},
+};
+
+module_platform_driver(wcd937x_codec_driver);
+MODULE_DESCRIPTION("WCD937X Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd937x/wcd937x_slave.c b/asoc/codecs/wcd937x/wcd937x_slave.c
new file mode 100644
index 0000000..36c2af1
--- /dev/null
+++ b/asoc/codecs/wcd937x/wcd937x_slave.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018, 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 <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <soc/soundwire.h>
+
+struct wcd937x_slave_priv {
+	struct swr_device *swr_slave;
+};
+
+static int wcd937x_slave_bind(struct device *dev,
+				struct device *master, void *data)
+{
+	int ret = 0;
+	struct wcd937x_slave_priv *wcd937x_slave = NULL;
+	uint8_t devnum = 0;
+	struct swr_device *pdev = to_swr_device(dev);
+
+	wcd937x_slave = devm_kzalloc(&pdev->dev,
+				sizeof(struct wcd937x_slave_priv), GFP_KERNEL);
+	if (!wcd937x_slave)
+		return -ENOMEM;
+
+	swr_set_dev_data(pdev, wcd937x_slave);
+
+	wcd937x_slave->swr_slave = pdev;
+
+	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);
+		swr_remove_device(pdev);
+		return ret;
+	}
+	pdev->dev_num = devnum;
+
+	return ret;
+}
+
+static void wcd937x_slave_unbind(struct device *dev,
+				struct device *master, void *data)
+{
+	struct wcd937x_slave_priv *wcd937x_slave = NULL;
+	struct swr_device *pdev = to_swr_device(dev);
+
+	wcd937x_slave = swr_get_dev_data(pdev);
+	if (!wcd937x_slave) {
+		dev_err(&pdev->dev, "%s: wcd937x_slave is NULL\n", __func__);
+		return;
+	}
+
+	swr_set_dev_data(pdev, NULL);
+}
+
+static const struct swr_device_id wcd937x_swr_id[] = {
+	{"wcd937x-slave", 0},
+	{}
+};
+
+static const struct of_device_id wcd937x_swr_dt_match[] = {
+	{
+		.compatible = "qcom,wcd937x-slave",
+	},
+	{}
+};
+
+static const struct component_ops wcd937x_slave_comp_ops = {
+	.bind   = wcd937x_slave_bind,
+	.unbind = wcd937x_slave_unbind,
+};
+
+static int wcd937x_swr_probe(struct swr_device *pdev)
+{
+	return component_add(&pdev->dev, &wcd937x_slave_comp_ops);
+}
+
+static int wcd937x_swr_remove(struct swr_device *pdev)
+{
+	component_del(&pdev->dev, &wcd937x_slave_comp_ops);
+	return 0;
+}
+
+static struct swr_driver wcd937x_slave_driver = {
+	.driver = {
+		.name = "wcd937x-slave",
+		.owner = THIS_MODULE,
+		.of_match_table = wcd937x_swr_dt_match,
+	},
+	.probe = wcd937x_swr_probe,
+	.remove = wcd937x_swr_remove,
+	.id_table = wcd937x_swr_id,
+};
+
+static int __init wcd937x_slave_init(void)
+{
+	return swr_driver_register(&wcd937x_slave_driver);
+}
+
+static void __exit wcd937x_slave_exit(void)
+{
+	swr_driver_unregister(&wcd937x_slave_driver);
+}
+
+module_init(wcd937x_slave_init);
+module_exit(wcd937x_slave_exit);
+
+MODULE_DESCRIPTION("WCD937X Swr Slave driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
index 0d1ab7b..c8ae53d 100644
--- a/asoc/codecs/wsa881x.c
+++ b/asoc/codecs/wsa881x.c
@@ -77,6 +77,7 @@
 enum {
 	WSA881X_DEV_DOWN,
 	WSA881X_DEV_UP,
+	WSA881X_DEV_READY,
 };
 
 /*
@@ -100,6 +101,7 @@
 	int version;
 	struct mutex bg_lock;
 	struct mutex res_lock;
+	struct mutex temp_lock;
 	struct snd_info_entry *entry;
 	struct snd_info_entry *version_entry;
 	int state;
@@ -492,6 +494,17 @@
 	.read = codec_debug_read,
 };
 
+static void wsa881x_regcache_sync(struct wsa881x_priv *wsa881x)
+{
+	mutex_lock(&wsa881x->res_lock);
+	if (wsa881x->state != WSA881X_DEV_READY) {
+		regcache_mark_dirty(wsa881x->regmap);
+		regcache_sync(wsa881x->regmap);
+		wsa881x->state = WSA881X_DEV_READY;
+	}
+	mutex_unlock(&wsa881x->res_lock);
+}
+
 static const struct reg_sequence wsa881x_pre_pmu_pa[] = {
 	{WSA881X_SPKR_DRV_GAIN, 0x41, 0},
 	{WSA881X_SPKR_MISC_CTL1, 0x01, 0},
@@ -870,7 +883,9 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		mutex_lock(&wsa881x->temp_lock);
 		wsa881x_resource_acquire(codec, ENABLE);
+		mutex_unlock(&wsa881x->temp_lock);
 		wsa881x_boost_ctrl(codec, ENABLE);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -878,7 +893,9 @@
 					    wsa881x->swr_slave->dev_num,
 					    false);
 		wsa881x_boost_ctrl(codec, DISABLE);
+		mutex_lock(&wsa881x->temp_lock);
 		wsa881x_resource_acquire(codec, DISABLE);
+		mutex_unlock(&wsa881x->temp_lock);
 		break;
 	}
 	return 0;
@@ -1126,13 +1143,8 @@
 			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_regcache_sync(wsa881x);
+	mutex_lock(&wsa881x->temp_lock);
 	wsa881x_resource_acquire(codec, ENABLE);
 
 	snd_soc_update_bits(codec, WSA881X_TADC_VALUE_CTL, 0x01, 0x00);
@@ -1145,6 +1157,7 @@
 	wsa_temp_reg->d2_lsb = snd_soc_read(codec, WSA881X_OTP_REG_4);
 
 	wsa881x_resource_acquire(codec, DISABLE);
+	mutex_unlock(&wsa881x->temp_lock);
 
 	return 0;
 }
@@ -1160,7 +1173,6 @@
 	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);
@@ -1182,7 +1194,6 @@
 	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;
 }
@@ -1365,6 +1376,8 @@
 			__func__);
 		goto dev_err;
 	}
+	mutex_init(&wsa881x->res_lock);
+	mutex_init(&wsa881x->temp_lock);
 
 	return 0;
 
@@ -1387,6 +1400,8 @@
 	}
 	debugfs_remove_recursive(debugfs_wsa881x_dent);
 	debugfs_wsa881x_dent = NULL;
+	mutex_destroy(&wsa881x->res_lock);
+	mutex_destroy(&wsa881x->temp_lock);
 	snd_soc_unregister_codec(&pdev->dev);
 	if (wsa881x->pd_gpio)
 		gpio_free(wsa881x->pd_gpio);
@@ -1445,6 +1460,11 @@
 		dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
 		return -EINVAL;
 	}
+	if (wsa881x->state == WSA881X_DEV_READY) {
+		dev_dbg(&pdev->dev, "%s: device already active\n", __func__);
+		return 0;
+	}
+
 	wsa881x->bg_cnt = 0;
 	wsa881x->clk_cnt = 0;
 	while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) {
@@ -1452,8 +1472,8 @@
 		usleep_range(1000, 1100);
 	}
 	pdev->dev_num = devnum;
-	regcache_mark_dirty(wsa881x->regmap);
-	regcache_sync(wsa881x->regmap);
+	wsa881x_regcache_sync(wsa881x);
+
 	return 0;
 }
 
diff --git a/asoc/msm-dai-fe.c b/asoc/msm-dai-fe.c
index a711a25..c352cb3 100644
--- a/asoc/msm-dai-fe.c
+++ b/asoc/msm-dai-fe.c
@@ -2612,6 +2612,39 @@
 		.probe = fe_dai_probe,
 	},
 	{
+		.playback = {
+			.stream_name = "MultiMedia21 Playback",
+			.aif_name = "MM_DL21",
+			.rates = (SNDRV_PCM_RATE_8000_384000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE |
+				    SNDRV_PCM_FMTBIT_S24_3LE |
+				    SNDRV_PCM_FMTBIT_S32_LE),
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     384000,
+		},
+		.capture = {
+			.stream_name = "MultiMedia21 Capture",
+			.aif_name = "MM_UL21",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE |
+				    SNDRV_PCM_FMTBIT_S24_3LE |
+				    SNDRV_PCM_FMTBIT_S32_LE),
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_Multimedia_dai_ops,
+		.name = "MultiMedia21",
+		.probe = fe_dai_probe,
+	},
+	{
 		.capture = {
 		.stream_name = "MultiMedia28 Capture",
 		.aif_name = "MM_UL28",
diff --git a/asoc/msm-pcm-q6-noirq.c b/asoc/msm-pcm-q6-noirq.c
index 249f8a5..c89efb9 100644
--- a/asoc/msm-pcm-q6-noirq.c
+++ b/asoc/msm-pcm-q6-noirq.c
@@ -275,6 +275,8 @@
 	int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT;
 	unsigned long topology;
 	int perf_mode;
+	bool use_default_chmap = true;
+	char *chmap = NULL;
 
 	pdata = (struct msm_plat_data *)
 		dev_get_drvdata(soc_prtd->platform->dev);
@@ -311,6 +313,13 @@
 	if (prtd->enabled)
 		return 0;
 
+	if (pdata->ch_map[soc_prtd->dai_link->id]) {
+		use_default_chmap =
+			!(pdata->ch_map[soc_prtd->dai_link->id]->set_ch_map);
+		chmap =
+			pdata->ch_map[soc_prtd->dai_link->id]->channel_map;
+	}
+
 	switch (runtime->format) {
 	case SNDRV_PCM_FORMAT_S24_LE:
 		bits_per_sample = 24;
@@ -335,7 +344,8 @@
 	config.bufsz = params_buffer_bytes(params) / params_periods(params);
 	config.bufcnt = params_periods(params);
 
-	ret = q6asm_open_shared_io(prtd->audio_client, &config, dir);
+	ret = q6asm_open_shared_io(prtd->audio_client, &config, dir,
+				   use_default_chmap, chmap);
 	if (ret) {
 		pr_err("%s: q6asm_open_write_shared_io failed ret: %d\n",
 		       __func__, ret);
@@ -718,89 +728,126 @@
 	return 0;
 }
 
-static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
+static int msm_pcm_channel_map_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
 {
-	int i;
-	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	struct snd_pcm_substream *substream;
-	struct msm_audio *prtd;
+	struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
+	u64 fe_id = kcontrol->private_value;
+	struct msm_plat_data *pdata = (struct msm_plat_data *)
+			snd_soc_component_get_drvdata(pcm);
+	int rc = 0, i = 0;
 
-	pr_debug("%s", __func__);
-	substream = snd_pcm_chmap_substream(info, idx);
-	if (!substream)
-		return -ENODEV;
-	if (!substream->runtime)
-		return 0;
+	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
 
-	prtd = substream->runtime->private_data;
-	if (prtd) {
-		prtd->set_channel_map = true;
-			for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
-				prtd->channel_map[i] =
-				(char)(ucontrol->value.integer.value[i]);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bounds fe_id %llu\n",
+			__func__, fe_id);
+		rc = -EINVAL;
+		goto end;
 	}
+
+	if (pdata->ch_map[fe_id]) {
+		pdata->ch_map[fe_id]->set_ch_map = true;
+		for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+			pdata->ch_map[fe_id]->channel_map[i] =
+				(char)(ucontrol->value.integer.value[i]);
+	} else {
+		pr_debug("%s: no memory for ch_map, default will be set\n",
+			__func__);
+	}
+end:
+	pr_debug("%s: ret %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_pcm_channel_map_info(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 8;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xFFFFFFFF;
 	return 0;
 }
 
-static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
+static int msm_pcm_channel_map_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
 {
-	int i;
-	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
-	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	struct snd_pcm_substream *substream;
-	struct msm_audio *prtd;
+	struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
+	u64 fe_id = kcontrol->private_value;
+	struct msm_plat_data *pdata = (struct msm_plat_data *)
+			snd_soc_component_get_drvdata(pcm);
+	int rc = 0, i = 0;
 
-	pr_debug("%s", __func__);
-	substream = snd_pcm_chmap_substream(info, idx);
-	if (!substream)
-		return -ENODEV;
-	memset(ucontrol->value.integer.value, 0,
-		sizeof(ucontrol->value.integer.value));
-	if (!substream->runtime)
-		return 0; /* no channels set */
-
-	prtd = substream->runtime->private_data;
-
-	if (prtd && prtd->set_channel_map == true) {
+	pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s: Received out of bounds fe_id %llu\n",
+			__func__, fe_id);
+		rc = -EINVAL;
+		goto end;
+	}
+	if (pdata->ch_map[fe_id]) {
 		for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
 			ucontrol->value.integer.value[i] =
-					(int)prtd->channel_map[i];
-	} else {
-		for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
-			ucontrol->value.integer.value[i] = 0;
+				pdata->ch_map[fe_id]->channel_map[i];
 	}
-
-	return 0;
+end:
+	pr_debug("%s: ret %d\n", __func__, rc);
+	return rc;
 }
 
-static int msm_pcm_add_chmap_control(struct snd_soc_pcm_runtime *rtd)
+static int msm_pcm_add_channel_map_control(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_pcm *pcm = rtd->pcm;
-	struct snd_pcm_chmap *chmap_info;
-	struct snd_kcontrol *kctl;
-	char device_num[12];
-	int i, ret;
+	const char *mixer_ctl_name = "Playback Channel Map";
+	const char *deviceNo       = "NN";
+	char *mixer_str = NULL;
+	struct msm_plat_data *pdata = NULL;
+	int ctl_len = 0;
+	struct snd_kcontrol_new fe_channel_map_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_pcm_channel_map_info,
+		.get = msm_pcm_channel_map_get,
+		.put = msm_pcm_channel_map_put,
+		.private_value = 0,
+		}
+	};
 
-	pr_debug("%s, Channel map cntrl add\n", __func__);
-	ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-				     snd_pcm_std_chmaps,
-				     PCM_FORMAT_MAX_NUM_CHANNEL, 0,
-				     &chmap_info);
-	if (ret)
-		return ret;
+	if (!rtd) {
+		pr_err("%s: NULL rtd\n", __func__);
+		return -EINVAL;
+	}
 
-	kctl = chmap_info->kctl;
-	for (i = 0; i < kctl->count; i++)
-		kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
-	snprintf(device_num, sizeof(device_num), "%d", pcm->device);
-	strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
-	pr_debug("%s, Overwriting channel map control name to: %s",
-		__func__, kctl->id.name);
-	kctl->put = msm_pcm_chmap_ctl_put;
-	kctl->get = msm_pcm_chmap_ctl_get;
+	pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
+		 __func__, rtd->dai_link->name, rtd->dai_link->id,
+		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+
+	ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str)
+		return -ENOMEM;
+
+	snprintf(mixer_str, ctl_len, "%s%d", mixer_ctl_name, rtd->pcm->device);
+
+	fe_channel_map_control[0].name = mixer_str;
+	fe_channel_map_control[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	snd_soc_add_platform_controls(rtd->platform,
+				fe_channel_map_control,
+				ARRAY_SIZE(fe_channel_map_control));
+
+	pdata = snd_soc_platform_get_drvdata(rtd->platform);
+	pdata->ch_map[rtd->dai_link->id] =
+		 kzalloc(sizeof(struct msm_pcm_ch_map), GFP_KERNEL);
+	if (!pdata->ch_map[rtd->dai_link->id]) {
+		pr_err("%s: Could not allocate memory for channel map\n",
+			__func__);
+		kfree(mixer_str);
+		return -ENOMEM;
+	}
+	kfree(mixer_str);
 	return 0;
 }
 
@@ -1155,11 +1202,11 @@
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	ret = msm_pcm_add_chmap_control(rtd);
-	if (ret) {
-		pr_err("%s failed to add chmap cntls\n", __func__);
-		goto exit;
-	}
+	ret = msm_pcm_add_channel_map_control(rtd);
+	if (ret)
+		pr_err("%s: Could not add pcm Channel Map Control\n",
+			__func__);
+
 	ret = msm_pcm_add_volume_control(rtd);
 	if (ret) {
 		pr_err("%s: Could not add pcm Volume Control %d\n",
@@ -1181,7 +1228,7 @@
 	if (ret)
 		pr_err("%s: Could not add hw dep node\n", __func__);
 	pcm->nonatomic = true;
-exit:
+
 	return ret;
 }
 
diff --git a/asoc/msm-pcm-q6-v2.h b/asoc/msm-pcm-q6-v2.h
index 0177b2d..21d09cd 100644
--- a/asoc/msm-pcm-q6-v2.h
+++ b/asoc/msm-pcm-q6-v2.h
@@ -20,7 +20,7 @@
 #define _MSM_PCM_H
 #include <dsp/apr_audio-v2.h>
 #include <dsp/q6asm-v2.h>
-
+#include "msm-pcm-routing-v2.h"
 
 
 /* Support unconventional sample rates 12000, 24000 as well */
@@ -125,6 +125,12 @@
 struct msm_plat_data {
 	int perf_mode;
 	struct snd_pcm *pcm;
+	struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
+};
+
+struct msm_pcm_ch_map {
+	bool set_ch_map;
+	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
 };
 
 #endif /*_MSM_PCM_H*/
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index 84f98e7..cdcd29d 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -703,6 +703,9 @@
 	/* MULTIMEDIA20 */
 	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
 	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* MULTIMEDIA21 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
 	/* MULTIMEDIA28 */
 	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
 	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
@@ -6895,6 +6898,10 @@
 	MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
@@ -6982,6 +6989,10 @@
 	MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM,
 	MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer,
@@ -7257,6 +7268,10 @@
 	MSM_BACKEND_DAI_PRI_TDM_RX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
@@ -7324,6 +7339,10 @@
 	MSM_BACKEND_DAI_PRI_TDM_RX_1,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = {
@@ -7391,6 +7410,10 @@
 	MSM_BACKEND_DAI_PRI_TDM_RX_2,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = {
@@ -7458,6 +7481,10 @@
 	MSM_BACKEND_DAI_PRI_TDM_RX_3,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = {
@@ -7592,6 +7619,10 @@
 	MSM_BACKEND_DAI_SEC_TDM_RX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_RX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
@@ -7659,6 +7690,10 @@
 	MSM_BACKEND_DAI_SEC_TDM_RX_1,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = {
@@ -7726,6 +7761,10 @@
 	MSM_BACKEND_DAI_SEC_TDM_RX_2,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = {
@@ -7793,6 +7832,10 @@
 	MSM_BACKEND_DAI_SEC_TDM_RX_3,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = {
@@ -7927,6 +7970,10 @@
 	MSM_BACKEND_DAI_TERT_TDM_RX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_RX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = {
@@ -8061,6 +8108,10 @@
 	MSM_BACKEND_DAI_TERT_TDM_RX_1,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = {
@@ -8128,6 +8179,10 @@
 	MSM_BACKEND_DAI_TERT_TDM_RX_2,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = {
@@ -8195,6 +8250,10 @@
 	MSM_BACKEND_DAI_TERT_TDM_RX_3,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
@@ -8262,6 +8321,10 @@
 	MSM_BACKEND_DAI_TERT_TDM_RX_4,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
@@ -8333,6 +8396,10 @@
 	MSM_BACKEND_DAI_QUAT_TDM_RX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = {
@@ -8471,6 +8538,10 @@
 	MSM_BACKEND_DAI_QUAT_TDM_RX_1,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
@@ -8542,6 +8613,10 @@
 	MSM_BACKEND_DAI_QUAT_TDM_RX_2,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
@@ -8613,6 +8688,10 @@
 	MSM_BACKEND_DAI_QUAT_TDM_RX_3,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quin_tdm_rx_0_mixer_controls[] = {
@@ -8684,6 +8763,10 @@
 	MSM_BACKEND_DAI_QUIN_TDM_RX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_RX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quin_tdm_tx_0_mixer_controls[] = {
@@ -8822,6 +8905,10 @@
 	MSM_BACKEND_DAI_QUIN_TDM_RX_1,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quin_tdm_rx_2_mixer_controls[] = {
@@ -8893,6 +8980,10 @@
 	MSM_BACKEND_DAI_QUIN_TDM_RX_2,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quin_tdm_rx_3_mixer_controls[] = {
@@ -8964,6 +9055,10 @@
 	MSM_BACKEND_DAI_QUIN_TDM_RX_3,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -11275,6 +11370,97 @@
 	MSM_BACKEND_DAI_QUIN_TDM_TX_3,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul21_mixer_controls[] = {
+	SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_TERT_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUIN_TDM_TX_0", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUIN_TDM_TX_1", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUIN_TDM_TX_2", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_DOUBLE_EXT("QUIN_TDM_TX_3", SND_SOC_NOPM,
+	MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_DOUBLE_EXT("WSA_CDC_DMA_TX_0", SND_SOC_NOPM,
 			MSM_BACKEND_DAI_WSA_CDC_DMA_TX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
@@ -17306,6 +17492,7 @@
 	SND_SOC_DAPM_AIF_IN("MM_DL15", "MultiMedia15 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL16", "MultiMedia16 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL20", "MultiMedia20 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL21", "MultiMedia21 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
@@ -17321,6 +17508,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL20", "MultiMedia20 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL21", "MultiMedia21 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL28", "MultiMedia28 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL29", "MultiMedia29 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
@@ -18272,6 +18460,8 @@
 	mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia20 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul20_mixer_controls, ARRAY_SIZE(mmul20_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia21 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul21_mixer_controls, ARRAY_SIZE(mmul21_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia28 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul28_mixer_controls, ARRAY_SIZE(mmul28_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia29 Mixer", SND_SOC_NOPM, 0, 0,
@@ -19280,6 +19470,7 @@
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
 
 	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19298,6 +19489,7 @@
 	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Audio Mixer"},
 
 	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19316,6 +19508,7 @@
 	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Audio Mixer"},
 
 	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19334,6 +19527,7 @@
 	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Audio Mixer"},
 
 	{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19370,6 +19564,7 @@
 	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
 
 	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19388,6 +19583,7 @@
 	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Audio Mixer"},
 
 	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19406,6 +19602,7 @@
 	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Audio Mixer"},
 
 	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19424,6 +19621,7 @@
 	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Audio Mixer"},
 
 	{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19460,6 +19658,7 @@
 	{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Audio Mixer"},
 
 	{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19496,6 +19695,7 @@
 	{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1 Audio Mixer"},
 
 	{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19514,6 +19714,7 @@
 	{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2 Audio Mixer"},
 
 	{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19532,6 +19733,7 @@
 	{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"},
 
 	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19550,6 +19752,7 @@
 	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"},
 
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19569,6 +19772,7 @@
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
 
 	{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19606,6 +19810,7 @@
 	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Audio Mixer"},
 
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19625,6 +19830,7 @@
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Audio Mixer"},
 
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19644,6 +19850,7 @@
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Audio Mixer"},
 
 	{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19663,6 +19870,7 @@
 	{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUIN_TDM_RX_0", NULL, "QUIN_TDM_RX_0 Audio Mixer"},
 
 	{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19700,6 +19908,7 @@
 	{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUIN_TDM_RX_1", NULL, "QUIN_TDM_RX_1 Audio Mixer"},
 
 	{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19719,6 +19928,7 @@
 	{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUIN_TDM_RX_2", NULL, "QUIN_TDM_RX_2 Audio Mixer"},
 
 	{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -19738,6 +19948,7 @@
 	{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia20", "MM_DL20"},
+	{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"QUIN_TDM_RX_3", NULL, "QUIN_TDM_RX_3 Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -20135,6 +20346,29 @@
 	{"MultiMedia20 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"},
 	{"MultiMedia20 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"},
 
+	{"MultiMedia21 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"MultiMedia21 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"MultiMedia21 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia21 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia21 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia21 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia21 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia21 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia21 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia21 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+	{"MultiMedia21 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+	{"MultiMedia21 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+	{"MultiMedia21 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+	{"MultiMedia21 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+	{"MultiMedia21 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"MultiMedia21 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"MultiMedia21 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"MultiMedia21 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+	{"MultiMedia21 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+	{"MultiMedia21 Mixer", "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"},
+	{"MultiMedia21 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
+	{"MultiMedia21 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+
 	{"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
 	{"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
 	{"MultiMedia4 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
@@ -20335,6 +20569,7 @@
 	{"MM_UL18", NULL, "MultiMedia18 Mixer"},
 	{"MM_UL19", NULL, "MultiMedia19 Mixer"},
 	{"MM_UL20", NULL, "MultiMedia20 Mixer"},
+	{"MM_UL21", NULL, "MultiMedia21 Mixer"},
 	{"MM_UL28", NULL, "MultiMedia28 Mixer"},
 	{"MM_UL29", NULL, "MultiMedia29 Mixer"},
 
@@ -20354,6 +20589,7 @@
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
 
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -20372,6 +20608,7 @@
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_DL21"},
 	{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"},
 
 	{"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index fe40b77..b4ff50f 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -239,6 +239,7 @@
 	MSM_FRONTEND_DAI_MULTIMEDIA18,
 	MSM_FRONTEND_DAI_MULTIMEDIA19,
 	MSM_FRONTEND_DAI_MULTIMEDIA20,
+	MSM_FRONTEND_DAI_MULTIMEDIA21,
 	MSM_FRONTEND_DAI_MULTIMEDIA28,
 	MSM_FRONTEND_DAI_MULTIMEDIA29,
 	MSM_FRONTEND_DAI_VOIP,
diff --git a/asoc/qcs405.c b/asoc/qcs405.c
index 0045beb..6697859 100644
--- a/asoc/qcs405.c
+++ b/asoc/qcs405.c
@@ -31,6 +31,7 @@
 #include <dsp/audio_notifier.h>
 #include <dsp/q6afe-v2.h>
 #include <dsp/q6core.h>
+#include <dsp/msm_mdf.h>
 #include "device_event.h"
 #include "msm-pcm-routing-v2.h"
 #include "codecs/msm-cdc-pinctrl.h"
@@ -1263,38 +1264,44 @@
 	case SAMPLING_RATE_8KHZ:
 		sample_rate_val = 0;
 		break;
-	case SAMPLING_RATE_16KHZ:
+	case SAMPLING_RATE_11P025KHZ:
 		sample_rate_val = 1;
 		break;
-	case SAMPLING_RATE_32KHZ:
+	case SAMPLING_RATE_16KHZ:
 		sample_rate_val = 2;
 		break;
-	case SAMPLING_RATE_44P1KHZ:
+	case SAMPLING_RATE_22P05KHZ:
 		sample_rate_val = 3;
 		break;
-	case SAMPLING_RATE_48KHZ:
+	case SAMPLING_RATE_32KHZ:
 		sample_rate_val = 4;
 		break;
-	case SAMPLING_RATE_88P2KHZ:
+	case SAMPLING_RATE_44P1KHZ:
 		sample_rate_val = 5;
 		break;
-	case SAMPLING_RATE_96KHZ:
+	case SAMPLING_RATE_48KHZ:
 		sample_rate_val = 6;
 		break;
-	case SAMPLING_RATE_176P4KHZ:
+	case SAMPLING_RATE_88P2KHZ:
 		sample_rate_val = 7;
 		break;
-	case SAMPLING_RATE_192KHZ:
+	case SAMPLING_RATE_96KHZ:
 		sample_rate_val = 8;
 		break;
-	case SAMPLING_RATE_352P8KHZ:
+	case SAMPLING_RATE_176P4KHZ:
 		sample_rate_val = 9;
 		break;
-	case SAMPLING_RATE_384KHZ:
+	case SAMPLING_RATE_192KHZ:
 		sample_rate_val = 10;
 		break;
+	case SAMPLING_RATE_352P8KHZ:
+		sample_rate_val = 11;
+		break;
+	case SAMPLING_RATE_384KHZ:
+		sample_rate_val = 12;
+		break;
 	default:
-		sample_rate_val = 4;
+		sample_rate_val = 6;
 		break;
 	}
 	return sample_rate_val;
@@ -1309,33 +1316,39 @@
 		sample_rate = SAMPLING_RATE_8KHZ;
 		break;
 	case 1:
-		sample_rate = SAMPLING_RATE_16KHZ;
+		sample_rate = SAMPLING_RATE_11P025KHZ;
 		break;
 	case 2:
-		sample_rate = SAMPLING_RATE_32KHZ;
+		sample_rate = SAMPLING_RATE_16KHZ;
 		break;
 	case 3:
-		sample_rate = SAMPLING_RATE_44P1KHZ;
+		sample_rate = SAMPLING_RATE_22P05KHZ;
 		break;
 	case 4:
-		sample_rate = SAMPLING_RATE_48KHZ;
+		sample_rate = SAMPLING_RATE_32KHZ;
 		break;
 	case 5:
-		sample_rate = SAMPLING_RATE_88P2KHZ;
+		sample_rate = SAMPLING_RATE_44P1KHZ;
 		break;
 	case 6:
-		sample_rate = SAMPLING_RATE_96KHZ;
+		sample_rate = SAMPLING_RATE_48KHZ;
 		break;
 	case 7:
-		sample_rate = SAMPLING_RATE_176P4KHZ;
+		sample_rate = SAMPLING_RATE_88P2KHZ;
 		break;
 	case 8:
-		sample_rate = SAMPLING_RATE_192KHZ;
+		sample_rate = SAMPLING_RATE_96KHZ;
 		break;
 	case 9:
-		sample_rate = SAMPLING_RATE_352P8KHZ;
+		sample_rate = SAMPLING_RATE_176P4KHZ;
 		break;
 	case 10:
+		sample_rate = SAMPLING_RATE_192KHZ;
+		break;
+	case 11:
+		sample_rate = SAMPLING_RATE_352P8KHZ;
+		break;
+	case 12:
 		sample_rate = SAMPLING_RATE_384KHZ;
 		break;
 	default:
@@ -8402,6 +8415,11 @@
 	dev_info(&pdev->dev, "Sound card %s registered\n", card->name);
 	spdev = pdev;
 
+	ret = msm_mdf_mem_init();
+	if (ret)
+		dev_err(&pdev->dev, "msm_mdf_mem_init failed (%d)\n",
+			 ret);
+
 	/* Parse pinctrl info from devicetree */
 	ret = msm_get_pinctrl(pdev);
 	if (!ret) {
@@ -8426,6 +8444,7 @@
 {
 	audio_notifier_deregister("qcs405");
 	msm_i2s_auxpcm_deinit();
+	msm_mdf_mem_deinit();
 
 	msm_release_pinctrl(pdev);
 	return 0;
diff --git a/asoc/sm6150.c b/asoc/sm6150.c
index de76951..f7105d4 100644
--- a/asoc/sm6150.c
+++ b/asoc/sm6150.c
@@ -39,6 +39,7 @@
 #include "codecs/wsa881x.h"
 #include "codecs/bolero/bolero-cdc.h"
 #include <dt-bindings/sound/audio-codec-port-types.h>
+#include "codecs/bolero/wsa-macro.h"
 
 #define DRV_NAME "sm6150-asoc-snd"
 
@@ -496,10 +497,13 @@
 static const char *const cdc_dma_tx_ch_text[] = {"One", "Two", "Three", "Four",
 						"Five", "Six", "Seven",
 						"Eight"};
-static char const *cdc_dma_sample_rate_text[] = {"KHZ_8", "KHZ_16",
-					"KHZ_32", "KHZ_44P1", "KHZ_48",
-					"KHZ_88P2", "KHZ_96", "KHZ_176P4",
-					"KHZ_192", "KHZ_352P8", "KHZ_384"};
+static char const *cdc_dma_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
+						 "KHZ_16", "KHZ_22P05",
+						 "KHZ_32", "KHZ_44P1", "KHZ_48",
+						 "KHZ_88P2", "KHZ_96",
+						 "KHZ_176P4", "KHZ_192",
+						 "KHZ_352P8", "KHZ_384"};
+
 
 static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text);
@@ -1323,6 +1327,7 @@
 	return rc;
 }
 
+
 static int cdc_dma_get_sample_rate_val(int sample_rate)
 {
 	int sample_rate_val = 0;
@@ -1331,38 +1336,44 @@
 	case SAMPLING_RATE_8KHZ:
 		sample_rate_val = 0;
 		break;
-	case SAMPLING_RATE_16KHZ:
+	case SAMPLING_RATE_11P025KHZ:
 		sample_rate_val = 1;
 		break;
-	case SAMPLING_RATE_32KHZ:
+	case SAMPLING_RATE_16KHZ:
 		sample_rate_val = 2;
 		break;
-	case SAMPLING_RATE_44P1KHZ:
+	case SAMPLING_RATE_22P05KHZ:
 		sample_rate_val = 3;
 		break;
-	case SAMPLING_RATE_48KHZ:
+	case SAMPLING_RATE_32KHZ:
 		sample_rate_val = 4;
 		break;
-	case SAMPLING_RATE_88P2KHZ:
+	case SAMPLING_RATE_44P1KHZ:
 		sample_rate_val = 5;
 		break;
-	case SAMPLING_RATE_96KHZ:
+	case SAMPLING_RATE_48KHZ:
 		sample_rate_val = 6;
 		break;
-	case SAMPLING_RATE_176P4KHZ:
+	case SAMPLING_RATE_88P2KHZ:
 		sample_rate_val = 7;
 		break;
-	case SAMPLING_RATE_192KHZ:
+	case SAMPLING_RATE_96KHZ:
 		sample_rate_val = 8;
 		break;
-	case SAMPLING_RATE_352P8KHZ:
+	case SAMPLING_RATE_176P4KHZ:
 		sample_rate_val = 9;
 		break;
-	case SAMPLING_RATE_384KHZ:
+	case SAMPLING_RATE_192KHZ:
 		sample_rate_val = 10;
 		break;
+	case SAMPLING_RATE_352P8KHZ:
+		sample_rate_val = 11;
+		break;
+	case SAMPLING_RATE_384KHZ:
+		sample_rate_val = 12;
+		break;
 	default:
-		sample_rate_val = 4;
+		sample_rate_val = 6;
 		break;
 	}
 	return sample_rate_val;
@@ -1377,33 +1388,39 @@
 		sample_rate = SAMPLING_RATE_8KHZ;
 		break;
 	case 1:
-		sample_rate = SAMPLING_RATE_16KHZ;
+		sample_rate = SAMPLING_RATE_11P025KHZ;
 		break;
 	case 2:
-		sample_rate = SAMPLING_RATE_32KHZ;
+		sample_rate = SAMPLING_RATE_16KHZ;
 		break;
 	case 3:
-		sample_rate = SAMPLING_RATE_44P1KHZ;
+		sample_rate = SAMPLING_RATE_22P05KHZ;
 		break;
 	case 4:
-		sample_rate = SAMPLING_RATE_48KHZ;
+		sample_rate = SAMPLING_RATE_32KHZ;
 		break;
 	case 5:
-		sample_rate = SAMPLING_RATE_88P2KHZ;
+		sample_rate = SAMPLING_RATE_44P1KHZ;
 		break;
 	case 6:
-		sample_rate = SAMPLING_RATE_96KHZ;
+		sample_rate = SAMPLING_RATE_48KHZ;
 		break;
 	case 7:
-		sample_rate = SAMPLING_RATE_176P4KHZ;
+		sample_rate = SAMPLING_RATE_88P2KHZ;
 		break;
 	case 8:
-		sample_rate = SAMPLING_RATE_192KHZ;
+		sample_rate = SAMPLING_RATE_96KHZ;
 		break;
 	case 9:
-		sample_rate = SAMPLING_RATE_352P8KHZ;
+		sample_rate = SAMPLING_RATE_176P4KHZ;
 		break;
 	case 10:
+		sample_rate = SAMPLING_RATE_192KHZ;
+		break;
+	case 11:
+		sample_rate = SAMPLING_RATE_352P8KHZ;
+		break;
+	case 12:
 		sample_rate = SAMPLING_RATE_384KHZ;
 		break;
 	default:
@@ -1413,7 +1430,6 @@
 	return sample_rate;
 }
 
-
 static int cdc_dma_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
@@ -1639,7 +1655,6 @@
 	return rc;
 }
 
-/***************/
 static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
@@ -3763,7 +3778,7 @@
 	struct msm_asoc_mach_data *pdata = NULL;
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 	int ret = 0;
-	uint32_t dmic_idx;
+	u32 dmic_idx;
 	int *dmic_gpio_cnt;
 	struct device_node *dmic_gpio;
 	char  *wname;
@@ -4839,6 +4854,7 @@
 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct snd_card *card;
 	struct snd_info_entry *entry;
+	struct snd_soc_component *aux_comp;
 	struct msm_asoc_mach_data *pdata =
 				snd_soc_card_get_drvdata(rtd->card);
 
@@ -4860,23 +4876,43 @@
 	snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets,
 				ARRAY_SIZE(msm_int_dapm_widgets));
 
+	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
 	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
 	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
 	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
-	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
 
 	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic1");
 	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic2");
 	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3");
 	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
 
-	snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
-	snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
-	snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
-	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+	snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK1 OUT");
+	snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK2 OUT");
+	snd_soc_dapm_ignore_suspend(dapm, "WSA AIF VI");
+	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_WSA");
 
 	snd_soc_dapm_sync(dapm);
 
+	/*
+	 * Send speaker configuration only for WSA8810.
+	 * Default configuration is for WSA8815.
+	 */
+	dev_dbg(codec->dev, "%s: Number of aux devices: %d\n",
+		__func__, rtd->card->num_aux_devs);
+	if (rtd->card->num_aux_devs &&
+	    !list_empty(&rtd->card->component_dev_list)) {
+		aux_comp = list_first_entry(
+				&rtd->card->component_dev_list,
+				struct snd_soc_component,
+				card_aux_list);
+		if (!strcmp(aux_comp->name, WSA8810_NAME_1) ||
+		    !strcmp(aux_comp->name, WSA8810_NAME_2)) {
+			wsa_macro_set_spkr_mode(rtd->codec,
+						WSA_MACRO_SPKR_MODE_1);
+			wsa_macro_set_spkr_gain_offset(rtd->codec,
+					WSA_MACRO_GAIN_OFFSET_M1P5_DB);
+		}
+	}
 	card = rtd->card->snd_card;
 	entry = snd_info_create_subdir(card->module, "codecs",
 					 card->proc_root);
@@ -7299,20 +7335,6 @@
 		.ignore_suspend = 1,
 		.ops = &msm_cdc_dma_be_ops,
 	},
-	{
-		.name = LPASS_BE_WSA_CDC_DMA_TX_2,
-		.stream_name = "WSA CDC DMA2 Capture",
-		.cpu_dai_name = "msm-dai-cdc-dma-dev.45061",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "bolero_codec",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_WSA_CDC_DMA_TX_2,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-		.ops = &msm_cdc_dma_be_ops,
-	},
 };
 
 static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
@@ -7679,7 +7701,10 @@
 {
 	struct snd_soc_card *card = NULL;
 	struct snd_soc_dai_link *dailink;
-	int total_links = 0;
+	int total_links = 0, rc = 0;
+	u32 tavil_codec = 0, auxpcm_audio_intf = 0;
+	u32 mi2s_audio_intf = 0, ext_disp_audio_intf = 0;
+	u32 wcn_btfm_intf = 0;
 	const struct of_device_id *match;
 
 	match = of_match_node(sm6150_asoc_machine_of_match, dev->of_node);
@@ -7703,20 +7728,29 @@
 
 		total_links += ARRAY_SIZE(msm_common_misc_fe_dai_links);
 
-		if (of_property_read_bool(dev->of_node, "qcom,tavil_codec")) {
-
-			dev_dbg(dev, "%s(): Tavil codec is present\n",
+		rc = of_property_read_u32(dev->of_node, "qcom,tavil_codec",
+						&tavil_codec);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match for tavil codec\n",
 				__func__);
-			card->late_probe = msm_snd_card_tavil_late_probe;
-			memcpy(msm_sm6150_dai_links + total_links,
+		} else {
+			if (tavil_codec) {
+				card->late_probe =
+					msm_snd_card_tavil_late_probe;
+				memcpy(msm_sm6150_dai_links + total_links,
 					msm_tavil_fe_dai_links,
 					sizeof(msm_tavil_fe_dai_links));
-			total_links += ARRAY_SIZE(msm_tavil_fe_dai_links);
-		} else {
+				total_links +=
+					ARRAY_SIZE(msm_tavil_fe_dai_links);
+			}
+		}
+
+		if (!tavil_codec) {
 			memcpy(msm_sm6150_dai_links + total_links,
-					msm_bolero_fe_dai_links,
-					sizeof(msm_bolero_fe_dai_links));
-			total_links += ARRAY_SIZE(msm_bolero_fe_dai_links);
+				msm_bolero_fe_dai_links,
+				sizeof(msm_bolero_fe_dai_links));
+			total_links +=
+				ARRAY_SIZE(msm_bolero_fe_dai_links);
 		}
 
 		memcpy(msm_sm6150_dai_links + total_links,
@@ -7725,7 +7759,7 @@
 
 		total_links += ARRAY_SIZE(msm_common_be_dai_links);
 
-		if (of_property_read_bool(dev->of_node, "qcom,tavil_codec")) {
+		if (tavil_codec) {
 			memcpy(msm_sm6150_dai_links + total_links,
 					msm_tavil_be_dai_links,
 					sizeof(msm_tavil_be_dai_links));
@@ -7734,7 +7768,8 @@
 			memcpy(msm_sm6150_dai_links + total_links,
 			       msm_wsa_cdc_dma_be_dai_links,
 			       sizeof(msm_wsa_cdc_dma_be_dai_links));
-			total_links += ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links);
+			total_links +=
+				ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links);
 
 			memcpy(msm_sm6150_dai_links + total_links,
 			       msm_rx_tx_cdc_dma_be_dai_links,
@@ -7743,37 +7778,69 @@
 				ARRAY_SIZE(msm_rx_tx_cdc_dma_be_dai_links);
 		}
 
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,ext-disp-audio-rx")) {
-			dev_dbg(dev, "%s(): External display audio support present\n",
+		rc = of_property_read_u32(dev->of_node,
+					  "qcom,ext-disp-audio-rx",
+					  &ext_disp_audio_intf);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match Ext Disp interface\n",
 				__func__);
-			memcpy(msm_sm6150_dai_links + total_links,
-			ext_disp_be_dai_link,
-			sizeof(ext_disp_be_dai_link));
-			total_links += ARRAY_SIZE(ext_disp_be_dai_link);
+		} else {
+			if (auxpcm_audio_intf) {
+				memcpy(msm_sm6150_dai_links + total_links,
+					ext_disp_be_dai_link,
+					sizeof(ext_disp_be_dai_link));
+				total_links +=
+					ARRAY_SIZE(ext_disp_be_dai_link);
+			}
 		}
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,mi2s-audio-intf")) {
-			memcpy(msm_sm6150_dai_links + total_links,
-			       msm_mi2s_be_dai_links,
-			       sizeof(msm_mi2s_be_dai_links));
-			total_links += ARRAY_SIZE(msm_mi2s_be_dai_links);
+
+		rc = of_property_read_u32(dev->of_node, "qcom,mi2s-audio-intf",
+					  &mi2s_audio_intf);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match MI2S audio interface\n",
+				__func__);
+		} else {
+			if (mi2s_audio_intf) {
+				memcpy(msm_sm6150_dai_links + total_links,
+					msm_mi2s_be_dai_links,
+					sizeof(msm_mi2s_be_dai_links));
+				total_links +=
+					ARRAY_SIZE(msm_mi2s_be_dai_links);
+			}
 		}
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,auxpcm-audio-intf")) {
-			memcpy(msm_sm6150_dai_links + total_links,
-			       msm_auxpcm_be_dai_links,
-			       sizeof(msm_auxpcm_be_dai_links));
-			total_links += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+
+
+		rc = of_property_read_u32(dev->of_node, "qcom,wcn-btfm",
+					  &wcn_btfm_intf);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match wcn btfm interface\n",
+				__func__);
+		} else {
+			if (wcn_btfm_intf) {
+				memcpy(msm_sm6150_dai_links + total_links,
+					msm_wcn_be_dai_links,
+					sizeof(msm_wcn_be_dai_links));
+				total_links +=
+					ARRAY_SIZE(msm_wcn_be_dai_links);
+			}
 		}
-		if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
-			dev_dbg(dev, "%s(): WCN BTFM support present\n",
-					__func__);
-			memcpy(msm_sm6150_dai_links + total_links,
-				   msm_wcn_be_dai_links,
-				   sizeof(msm_wcn_be_dai_links));
-			total_links += ARRAY_SIZE(msm_wcn_be_dai_links);
+
+		rc = of_property_read_u32(dev->of_node,
+					  "qcom,auxpcm-audio-intf",
+					  &auxpcm_audio_intf);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match Aux PCM interface\n",
+				__func__);
+		} else {
+			if (auxpcm_audio_intf) {
+				memcpy(msm_sm6150_dai_links + total_links,
+					msm_auxpcm_be_dai_links,
+					sizeof(msm_auxpcm_be_dai_links));
+				total_links +=
+					ARRAY_SIZE(msm_auxpcm_be_dai_links);
+			}
 		}
+
 		dailink = msm_sm6150_dai_links;
 	} else if (!strcmp(match->data, "stub_codec")) {
 		card = &snd_soc_card_stub_msm;
@@ -7858,6 +7925,19 @@
 
 static int msm_aux_codec_init(struct snd_soc_component *component)
 {
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	snd_soc_dapm_ignore_suspend(dapm, "EAR");
+	snd_soc_dapm_ignore_suspend(dapm, "AUX");
+	snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+	snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+	snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+	snd_soc_dapm_sync(dapm);
+
 	return 0;
 }
 
@@ -8326,7 +8406,7 @@
 };
 module_platform_driver(sm6150_asoc_machine_driver);
 
-MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_DESCRIPTION("ALSA SoC SM6150 Machine driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRV_NAME);
 MODULE_DEVICE_TABLE(of, sm6150_asoc_machine_of_match);
diff --git a/asoc/sm8150.c b/asoc/sm8150.c
index 606ce1d..5f3fc8f 100644
--- a/asoc/sm8150.c
+++ b/asoc/sm8150.c
@@ -6958,6 +6958,8 @@
 	int len_1, len_2, len_3, len_4;
 	int total_links;
 	const struct of_device_id *match;
+	int ret = 0;
+	u32 val = 0;
 
 	match = of_match_node(sm8150_asoc_machine_of_match, dev->of_node);
 	if (!match) {
@@ -6989,7 +6991,8 @@
 			   msm_pahu_be_dai_links,
 			   sizeof(msm_pahu_be_dai_links));
 
-		if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+		ret = of_property_read_u32(dev->of_node, "qcom,wcn-btfm", &val);
+		if (!ret && val) {
 			dev_dbg(dev, "%s(): WCN BTFM support present\n",
 				__func__);
 			memcpy(msm_pahu_snd_card_dai_links + total_links,
@@ -6998,8 +7001,9 @@
 			total_links += ARRAY_SIZE(msm_wcn_be_dai_links);
 		}
 
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,ext-disp-audio-rx")) {
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,ext-disp-audio-rx", &val);
+		if (!ret && val) {
 			dev_dbg(dev, "%s(): ext disp audio support present\n",
 				__func__);
 			memcpy(msm_pahu_snd_card_dai_links + total_links,
@@ -7007,15 +7011,19 @@
 			       sizeof(ext_disp_be_dai_link));
 			total_links += ARRAY_SIZE(ext_disp_be_dai_link);
 		}
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,mi2s-audio-intf")) {
+
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,mi2s-audio-intf", &val);
+		if (!ret && val) {
 			memcpy(msm_pahu_snd_card_dai_links + total_links,
 			       msm_mi2s_be_dai_links,
 			       sizeof(msm_mi2s_be_dai_links));
 			total_links += ARRAY_SIZE(msm_mi2s_be_dai_links);
 		}
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,auxpcm-audio-intf")) {
+
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,auxpcm-audio-intf", &val);
+		if (!ret && val) {
 			memcpy(msm_pahu_snd_card_dai_links + total_links,
 			msm_auxpcm_be_dai_links,
 			sizeof(msm_auxpcm_be_dai_links));
@@ -7046,7 +7054,8 @@
 		       msm_tavil_be_dai_links,
 		       sizeof(msm_tavil_be_dai_links));
 
-		if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+		ret = of_property_read_u32(dev->of_node, "qcom,wcn-btfm", &val);
+		if (!ret && val) {
 			dev_dbg(dev, "%s(): WCN BTFM support present\n",
 				__func__);
 			memcpy(msm_tavil_dai_links + total_links,
@@ -7055,8 +7064,9 @@
 			total_links += ARRAY_SIZE(msm_wcn_be_dai_links);
 		}
 
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,ext-disp-audio-rx")) {
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,ext-disp-audio-rx", &val);
+		if (!ret && val) {
 			dev_dbg(dev, "%s(): ext disp audio support present\n",
 				__func__);
 			memcpy(msm_tavil_dai_links + total_links,
@@ -7064,15 +7074,19 @@
 			       sizeof(ext_disp_be_dai_link));
 			total_links += ARRAY_SIZE(ext_disp_be_dai_link);
 		}
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,mi2s-audio-intf")) {
+
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,mi2s-audio-intf", &val);
+		if (!ret && val) {
 			memcpy(msm_tavil_dai_links + total_links,
 			       msm_mi2s_be_dai_links,
 			       sizeof(msm_mi2s_be_dai_links));
 			total_links += ARRAY_SIZE(msm_mi2s_be_dai_links);
 		}
-		if (of_property_read_bool(dev->of_node,
-					  "qcom,auxpcm-audio-intf")) {
+
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,auxpcm-audio-intf", &val);
+		if (!ret && val) {
 			memcpy(msm_tavil_dai_links + total_links,
 			msm_auxpcm_be_dai_links,
 			sizeof(msm_auxpcm_be_dai_links));
diff --git a/config/qcs405auto.conf b/config/qcs405auto.conf
index f5a99f1..61620eb 100644
--- a/config/qcs405auto.conf
+++ b/config/qcs405auto.conf
@@ -31,6 +31,7 @@
 CONFIG_DOLBY_DS2=m
 CONFIG_DOLBY_LICENSE=m
 CONFIG_DTS_SRS_TM=m
+CONFIG_MSM_MDF=m
 CONFIG_SND_SOC_MSM_STUB=m
 CONFIG_MSM_AVTIMER=m
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=m
diff --git a/config/qcs405autoconf.h b/config/qcs405autoconf.h
index 4562621..98cd166 100644
--- a/config/qcs405autoconf.h
+++ b/config/qcs405autoconf.h
@@ -44,6 +44,7 @@
 #define CONFIG_DOLBY_LICENSE 1
 #define CONFIG_DTS_SRS_TM 1
 #define CONFIG_SND_SOC_MSM_STUB 1
+#define CONFIG_MSM_MDF 1
 #define CONFIG_MSM_AVTIMER 1
 #define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1
 #define CONFIG_SND_SOC_EP92 1
diff --git a/config/sm6150auto.conf b/config/sm6150auto.conf
index cd06ead..1fb50df 100644
--- a/config/sm6150auto.conf
+++ b/config/sm6150auto.conf
@@ -42,3 +42,6 @@
 CONFIG_VA_MACRO=m
 CONFIG_RX_MACRO=m
 CONFIG_TX_MACRO=m
+CONFIG_SND_SOC_WCD_IRQ=m
+CONFIG_SND_SOC_WCD937X=m
+CONFIG_SND_SOC_WCD937X_SLAVE=m
diff --git a/config/sm6150autoconf.h b/config/sm6150autoconf.h
index f64e863..5cc79c3 100644
--- a/config/sm6150autoconf.h
+++ b/config/sm6150autoconf.h
@@ -55,3 +55,6 @@
 #define CONFIG_VA_MACRO 1
 #define CONFIG_RX_MACRO 1
 #define CONFIG_TX_MACRO 1
+#define CONFIG_SND_SOC_WCD_IRQ 1
+#define CONFIG_SND_SOC_WCD937X 1
+#define CONFIG_SND_SOC_WCD937X_SLAVE 1
diff --git a/dsp/Kbuild b/dsp/Kbuild
index 1cad5ce..ba5f82c 100644
--- a/dsp/Kbuild
+++ b/dsp/Kbuild
@@ -123,6 +123,10 @@
 USF_OBJS += usf.o usfcdev.o q6usm.o
 endif
 
+ifdef CONFIG_MSM_MDF
+	Q6_OBJS += msm_mdf.o
+endif
+
 LINUX_INC +=	-Iinclude/linux
 
 INCS +=		$(COMMON_INC) \
diff --git a/dsp/msm_audio_ion.c b/dsp/msm_audio_ion.c
index 018b1a9..5a80916 100644
--- a/dsp/msm_audio_ion.c
+++ b/dsp/msm_audio_ion.c
@@ -220,6 +220,28 @@
 	return rc;
 }
 
+int msm_audio_ion_get_smmu_info(struct device **cb_dev,
+		u64 *smmu_sid)
+{
+	if (!cb_dev || !smmu_sid) {
+		pr_err("%s: Invalid params\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (!msm_audio_ion_data.cb_dev ||
+		!msm_audio_ion_data.smmu_sid_bits) {
+		pr_err("%s: Params not initialized\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	*cb_dev = msm_audio_ion_data.cb_dev;
+	*smmu_sid = msm_audio_ion_data.smmu_sid_bits;
+
+	return 0;
+}
+
 static void *msm_audio_ion_map_kernel(struct dma_buf *dma_buf)
 {
 	int rc = 0;
diff --git a/dsp/msm_mdf.c b/dsp/msm_mdf.c
new file mode 100644
index 0000000..849b76c
--- /dev/null
+++ b/dsp/msm_mdf.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2018, 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/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-buf.h>
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/ion_kernel.h>
+#include <linux/msm_ion.h>
+#include <dsp/msm_audio_ion.h>
+#include <ipc/apr.h>
+#include <dsp/msm_mdf.h>
+#include <asm/dma-iommu.h>
+#include <soc/qcom/secure_buffer.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <dsp/q6audio-v2.h>
+#include <dsp/q6core.h>
+
+#define VMID_SSC_Q6     5
+#define VMID_LPASS      6
+#define VMID_MSS_MSA    15
+#define VMID_CDSP	8
+
+#define MSM_MDF_PROBED         (1 << 0)
+#define MSM_MDF_INITIALIZED    (1 << 1)
+#define MSM_MDF_MEM_ALLOCATED  (1 << 2)
+#define MSM_MDF_MEM_MAPPED     (1 << 3)
+#define MSM_MDF_MEM_PERMISSION (1 << 4) /* 0 - HLOS, 1 - Subsys */
+
+/* TODO: Update IOVA range for subsys SMMUs */
+#define MSM_MDF_IOVA_START 0x80000000
+#define MSM_MDF_IOVA_LEN 0x800000
+
+#define MSM_MDF_SMMU_SID_OFFSET 32
+
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
+enum {
+	SUBSYS_ADSP, /* Audio DSP must have index 0 */
+	SUBSYS_SCC,  /* Sensor DSP */
+	SUBSYS_MSS,  /* Modem DSP */
+	SUBSYS_CDSP, /* Compute DSP */
+	SUBSYS_MAX,
+};
+
+struct msm_mdf_mem {
+	struct device *dev;
+	uint8_t device_status;
+	uint32_t map_handle;
+	struct dma_buf *dma_buf;
+	dma_addr_t dma_addr;
+	size_t size;
+	void *va;
+};
+
+static struct msm_mdf_mem mdf_mem_data = {NULL,};
+
+struct msm_mdf_smmu {
+	bool enabled;
+	char *subsys;
+	int vmid;
+	uint32_t proc_id;
+	struct device *cb_dev;
+	uint8_t device_status;
+	uint64_t sid;
+	struct dma_iommu_mapping *mapping;
+	dma_addr_t pa;
+	size_t pa_len;
+};
+
+static struct msm_mdf_smmu mdf_smmu_data[SUBSYS_MAX] = {
+	{
+		.subsys = "adsp",
+		.vmid = VMID_LPASS,
+	},
+	{
+		.subsys = "dsps",
+		.vmid = VMID_SSC_Q6,
+		.proc_id = AVS_MDF_SSC_PROC_ID,
+	},
+	{
+		.subsys = "modem",
+		.vmid = VMID_MSS_MSA,
+		.proc_id = AVS_MDF_MDSP_PROC_ID,
+	},
+	{
+		.subsys = "cdsp",
+		.vmid = VMID_CDSP,
+		.proc_id = AVS_MDF_CDSP_PROC_ID,
+	},
+};
+
+static void *ssr_handle;
+
+static inline uint64_t buf_page_start(uint64_t buf)
+{
+	uint64_t start = (uint64_t) buf & PAGE_MASK;
+	return start;
+}
+
+static inline uint64_t buf_page_offset(uint64_t buf)
+{
+	uint64_t offset = (uint64_t) buf & (PAGE_SIZE - 1);
+	return offset;
+}
+
+static inline int buf_num_pages(uint64_t buf, ssize_t len)
+{
+	uint64_t start = buf_page_start(buf) >> PAGE_SHIFT;
+	uint64_t end = (((uint64_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
+	int nPages = end - start + 1;
+	return nPages;
+}
+
+static inline uint64_t buf_page_size(uint32_t size)
+{
+	uint64_t sz = (size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+	return sz > PAGE_SIZE ? sz : PAGE_SIZE;
+}
+
+static inline void *uint64_to_ptr(uint64_t addr)
+{
+	void *ptr = (void *)((uintptr_t)addr);
+	return ptr;
+}
+
+static inline uint64_t ptr_to_uint64(void *ptr)
+{
+	uint64_t addr = (uint64_t)((uintptr_t)ptr);
+	return addr;
+}
+
+static int msm_mdf_dma_buf_map(struct msm_mdf_mem *mem,
+			       struct msm_mdf_smmu *smmu)
+{
+	int rc = 0;
+
+	if (!smmu)
+		return -EINVAL;
+	if (smmu->device_status & MSM_MDF_MEM_MAPPED)
+		return 0;
+	if (smmu->enabled) {
+		if (smmu->cb_dev == NULL) {
+			pr_err("%s: cb device is not initialized\n",
+				__func__);
+			/* Retry if LPASS cb device is not ready
+			 * from audio ION during probing.
+			 */
+			if (!strcmp("adsp", smmu->subsys)) {
+				rc = msm_audio_ion_get_smmu_info(&smmu->cb_dev,
+						&smmu->sid);
+				if (rc) {
+					pr_err("%s: msm_audio_ion_get_smmu_info failed, rc = %d\n",
+						__func__, rc);
+					goto err;
+				}
+			} else
+				return -ENODEV;
+		}
+
+		smmu->pa = dma_map_single(smmu->cb_dev, mem->va,
+					  mem->size, DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(smmu->cb_dev, smmu->pa)) {
+			rc = -ENOMEM;
+			pr_err("%s: failed to map single, rc = %d\n",
+				__func__, rc);
+			goto err;
+		}
+		smmu->pa_len = mem->size;
+
+		/* Append the SMMU SID information to the IOVA address */
+		if (smmu->sid)
+			smmu->pa |= smmu->sid;
+	} else {
+		smmu->pa = mem->dma_addr;
+		smmu->pa_len = mem->size;
+	}
+	pr_err("%s: pa=%pa, pa_len=%zd\n", __func__,
+		&smmu->pa, smmu->pa_len);
+
+	smmu->device_status |= MSM_MDF_MEM_MAPPED;
+
+	return 0;
+err:
+	return rc;
+}
+
+static int msm_mdf_alloc_dma_buf(struct msm_mdf_mem *mem)
+{
+	int rc = 0;
+
+	if (!mem)
+		return -EINVAL;
+
+	if (mem->device_status & MSM_MDF_MEM_ALLOCATED)
+		return 0;
+
+	if (mem->dev == NULL) {
+		pr_err("%s: device is not initialized\n",
+		__func__);
+		return -ENODEV;
+	}
+
+	mem->va = dma_alloc_coherent(mem->dev, mem->size,
+			&mem->dma_addr, GFP_KERNEL);
+	if (IS_ERR_OR_NULL(mem->va)) {
+		pr_err("%s: failed to allocate dma memory, rc = %d\n",
+			__func__, rc);
+		return -ENOMEM;
+	}
+	mem->va = phys_to_virt(mem->dma_addr);
+	mem->device_status |= MSM_MDF_MEM_ALLOCATED;
+	return rc;
+}
+
+static int msm_mdf_free_dma_buf(struct msm_mdf_mem *mem)
+{
+	if (!mem)
+		return -EINVAL;
+
+	if (mem->dev == NULL) {
+		pr_err("%s: device is not initialized\n",
+		__func__);
+		return -ENODEV;
+	}
+
+	//dma_free_coherent(mem->dev, mem->size, mem->va,
+	//				  mem->dma_addr);
+
+	mem->device_status &= ~MSM_MDF_MEM_ALLOCATED;
+	return 0;
+}
+
+static int msm_mdf_dma_buf_unmap(struct msm_mdf_mem *mem,
+				 struct msm_mdf_smmu *smmu)
+{
+	if (!smmu)
+		return -EINVAL;
+
+	if (smmu->enabled) {
+		if (smmu->cb_dev == NULL) {
+			pr_err("%s: cb device is not initialized\n",
+				__func__);
+			return -ENODEV;
+		}
+		//if (smmu->pa && mem->size)
+			//dma_unmap_single(smmu->cb_dev, smmu->pa,
+			//		 mem->size, DMA_BIDIRECTIONAL);
+	}
+
+	smmu->device_status &= ~MSM_MDF_MEM_MAPPED;
+
+	return 0;
+}
+
+static int msm_mdf_map_memory_to_subsys(struct msm_mdf_mem *mem,
+				struct msm_mdf_smmu *smmu)
+{
+	int rc = 0;
+
+	if (!mem || !smmu)
+		return -EINVAL;
+
+	/* Map mdf shared memory to ADSP */
+	if (!strcmp("adsp", smmu->subsys)) {
+		rc = q6core_map_memory_regions((phys_addr_t *)&smmu->pa,
+				ADSP_MEMORY_MAP_MDF_SHMEM_4K_POOL,
+				(uint32_t *)&smmu->pa_len, 1, &mem->map_handle);
+		if (rc)  {
+			pr_err("%s: q6core_map_memory_regions failed, rc = %d\n",
+				__func__, rc);
+		}
+	} else {
+		if (mem->map_handle) {
+			/* Map mdf shared memory to remote DSPs */
+			rc = q6core_map_mdf_shared_memory(mem->map_handle,
+					(phys_addr_t *)&smmu->pa, smmu->proc_id,
+					(uint32_t *)&smmu->pa_len, 1);
+			if (rc)  {
+				pr_err("%s: q6core_map_mdf_shared_memory failed, rc = %d\n",
+					__func__, rc);
+			}
+		}
+	}
+	return rc;
+}
+
+static void msm_mdf_unmap_memory_to_subsys(struct msm_mdf_mem *mem,
+				struct msm_mdf_smmu *smmu)
+{
+	if (!mem || !smmu)
+		return;
+
+	if (!strcmp("adsp", smmu->subsys)) {
+		if (mem->map_handle)
+			q6core_memory_unmap_regions(mem->map_handle);
+	}
+}
+
+/**
+ * msm_mdf_mem_init - Initializes MDF memory pool and
+ * map memory to subsystem
+ *
+ * Returns 0 on success or ret on failure.
+ */
+
+int msm_mdf_mem_init(void)
+{
+	int rc = 0, i, j;
+	struct msm_mdf_mem *mem = &mdf_mem_data;
+	struct msm_mdf_smmu *smmu;
+	unsigned long timeout = jiffies +
+		msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+	int adsp_ready = 0;
+
+	if (!(mdf_mem_data.device_status & MSM_MDF_PROBED))
+		return -ENODEV;
+
+	if (mdf_mem_data.device_status & MSM_MDF_INITIALIZED)
+		return 0;
+
+	/* TODO: pulling may not be needed as Q6 Core state should be
+	 * checked during machine driver probing.
+	 */
+	do {
+		if (!q6core_is_adsp_ready()) {
+			pr_err("%s: ADSP Audio NOT Ready\n",
+				__func__);
+			/* ADSP will be coming up after subsystem restart and
+			 * it might not be fully up when the control reaches
+			 * here. So, wait for 50msec before checking ADSP state
+			 */
+			msleep(50);
+		} else {
+			pr_debug("%s: ADSP Audio Ready\n",
+					__func__);
+			adsp_ready = 1;
+			break;
+		}
+	} while (time_after(timeout, jiffies));
+
+	if (!adsp_ready) {
+		pr_err("%s: timed out waiting for ADSP Audio\n",
+			__func__);
+		return -ETIMEDOUT;
+	}
+
+	if (mem->device_status & MSM_MDF_MEM_ALLOCATED) {
+		for (i = 0; i < SUBSYS_MAX; i++) {
+			smmu = &mdf_smmu_data[i];
+			rc = msm_mdf_dma_buf_map(mem, smmu);
+			if (rc) {
+				pr_err("%s: msm_mdf_dma_buf_map failed, rc = %d\n",
+					__func__, rc);
+				goto err;
+			}
+		}
+
+		for (j = 0; j < SUBSYS_MAX; j++) {
+			smmu = &mdf_smmu_data[j];
+			rc = msm_mdf_map_memory_to_subsys(mem, smmu);
+			if (rc) {
+				pr_err("%s: msm_mdf_map_memory_to_subsys failed\n",
+					__func__);
+				goto err;
+			}
+		}
+
+		mdf_mem_data.device_status |= MSM_MDF_INITIALIZED;
+	}
+	return 0;
+err:
+	return rc;
+}
+EXPORT_SYMBOL(msm_mdf_mem_init);
+
+int msm_mdf_mem_deinit(void)
+{
+	int rc = 0, i;
+	struct msm_mdf_mem *mem = &mdf_mem_data;
+	struct msm_mdf_smmu *smmu;
+
+	if (!(mdf_mem_data.device_status & MSM_MDF_INITIALIZED))
+		return -ENODEV;
+
+	for (i = SUBSYS_MAX - 1; i >= 0; i--) {
+		smmu = &mdf_smmu_data[i];
+		msm_mdf_unmap_memory_to_subsys(mem, smmu);
+	}
+
+	if (!rc) {
+		for (i = SUBSYS_MAX - 1; i >= 0; i--) {
+			smmu = &mdf_smmu_data[i];
+			msm_mdf_dma_buf_unmap(mem, smmu);
+		}
+
+		msm_mdf_free_dma_buf(mem);
+		mem->device_status &= ~MSM_MDF_MEM_ALLOCATED;
+	}
+
+	mdf_mem_data.device_status &= ~MSM_MDF_INITIALIZED;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_mdf_mem_deinit);
+
+static int msm_mdf_restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *_cmd)
+{
+	static int boot_count = 3;
+
+	/* During LPASS boot, HLOS receives events:
+	 *  SUBSYS_BEFORE_POWERUP
+	 *  SUBSYS_PROXY_VOTE
+	 *  SUBSYS_AFTER_POWERUP - need skip
+	 *  SUBSYS_PROXY_UNVOTE
+	 */
+	if (boot_count) {
+		boot_count--;
+		return NOTIFY_OK;
+	}
+
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("Subsys Notify: Shutdown Started\n");
+		/* Unmap and free memory upon restart event. */
+		msm_mdf_mem_deinit();
+		break;
+	case SUBSYS_AFTER_SHUTDOWN:
+		pr_debug("Subsys Notify: Shutdown Completed\n");
+		break;
+	case SUBSYS_BEFORE_POWERUP:
+		pr_debug("Subsys Notify: Bootup Started\n");
+		break;
+	case SUBSYS_AFTER_POWERUP:
+		pr_debug("Subsys Notify: Bootup Completed\n");
+		/* Allocate and map memory after restart complete. */
+		if (msm_mdf_mem_init())
+			pr_err("msm_mdf_mem_init failed\n");
+		break;
+	default:
+		pr_err("Subsys Notify: Generel: %lu\n", code);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static const struct of_device_id msm_mdf_match_table[] = {
+	{ .compatible = "qcom,msm-mdf", },
+	{ .compatible = "qcom,msm-mdf-mem-region", },
+	{ .compatible = "qcom,msm-mdf-cb", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_mdf_match_table);
+
+static int msm_mdf_cb_probe(struct device *dev)
+{
+	struct msm_mdf_smmu *smmu;
+	const char *subsys;
+	int rc = 0, i;
+
+	subsys = of_get_property(dev->of_node, "label", NULL);
+	if (!subsys) {
+		dev_err(dev, "%s: could not get label\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < SUBSYS_MAX; i++) {
+		if (!mdf_smmu_data[i].subsys)
+			continue;
+		if (!strcmp(subsys, mdf_smmu_data[i].subsys))
+			break;
+	}
+	if (i >= SUBSYS_MAX) {
+		dev_err(dev, "%s: subsys %s not supported\n",
+			__func__, subsys);
+		return -EINVAL;
+	}
+
+	smmu = &mdf_smmu_data[i];
+
+	smmu->enabled = of_property_read_bool(dev->of_node,
+						"qcom,smmu-enabled");
+
+	dev_info(dev, "%s: SMMU is %s for %s\n", __func__,
+		(smmu->enabled) ? "enabled" : "disabled",
+		smmu->subsys);
+
+	if (smmu->enabled) {
+		if (!strcmp("adsp", smmu->subsys)) {
+			/* Get SMMU info from audio ION */
+			rc = msm_audio_ion_get_smmu_info(&smmu->cb_dev,
+					&smmu->sid);
+			if (rc) {
+				dev_err(dev, "%s: msm_audio_ion_get_smmu_info failed, rc = %d\n",
+					__func__, rc);
+				goto err;
+			}
+		}
+	} else {
+		/* Setup SMMU CB if enabled for subsys other than ADSP */
+	}
+	return 0;
+err:
+	return rc;
+}
+
+static int msm_mdf_remove(struct platform_device *pdev)
+{
+	int rc = 0, i;
+
+	for (i = 0; i < SUBSYS_MAX; i++) {
+		if (!IS_ERR_OR_NULL(mdf_smmu_data[i].cb_dev))
+			arm_iommu_detach_device(mdf_smmu_data[i].cb_dev);
+		if (!IS_ERR_OR_NULL(mdf_smmu_data[i].mapping))
+			arm_iommu_release_mapping(mdf_smmu_data[i].mapping);
+		mdf_smmu_data[i].enabled = 0;
+	}
+	mdf_mem_data.device_status = 0;
+
+	return rc;
+}
+
+static int msm_mdf_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	enum apr_subsys_state q6_state;
+	struct device *dev = &pdev->dev;
+	uint32_t mdf_mem_data_size = 0;
+
+	/* TODO: MDF probing should have no dependency
+	 * on ADSP Q6 state.
+	 */
+	q6_state = apr_get_q6_state();
+	if (q6_state == APR_SUBSYS_DOWN) {
+		dev_dbg(dev, "defering %s, adsp_state %d\n",
+			__func__, q6_state);
+		rc = -EPROBE_DEFER;
+		goto err;
+	} else
+		dev_dbg(dev, "%s: adsp is ready\n", __func__);
+
+	if (of_device_is_compatible(dev->of_node,
+					"qcom,msm-mdf-cb"))
+		return msm_mdf_cb_probe(dev);
+
+	if (of_device_is_compatible(dev->of_node,
+					"qcom,msm-mdf-mem-region")) {
+		mdf_mem_data.dev = dev;
+
+		rc = of_property_read_u32(dev->of_node,
+				    "qcom,msm-mdf-mem-data-size",
+				    &mdf_mem_data_size);
+		if (rc) {
+			dev_dbg(&pdev->dev, "MDF mem data size entry not found\n");
+			goto err;
+		}
+
+		mdf_mem_data.size = mdf_mem_data_size;
+		dev_info(dev, "%s: mem region size %zd\n",
+			__func__, mdf_mem_data.size);
+		msm_mdf_alloc_dma_buf(&mdf_mem_data);
+		return 0;
+	}
+
+	rc = of_platform_populate(pdev->dev.of_node,
+					msm_mdf_match_table,
+					NULL, &pdev->dev);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to populate child nodes",
+			__func__);
+		goto err;
+	}
+	mdf_mem_data.device_status |= MSM_MDF_PROBED;
+
+err:
+	return rc;
+}
+
+static struct platform_driver msm_mdf_driver = {
+	.probe = msm_mdf_probe,
+	.remove = msm_mdf_remove,
+	.driver = {
+		.name = "msm-mdf",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_mdf_match_table,
+	},
+};
+
+static struct notifier_block nb = {
+	.priority = 0,
+	.notifier_call = msm_mdf_restart_notifier_cb,
+};
+
+int __init msm_mdf_init(void)
+{
+	/* Only need to monitor SSR from ADSP, which
+	 * is the master DSP managing MDF memory.
+	 */
+	ssr_handle = subsys_notif_register_notifier("adsp", &nb);
+	return platform_driver_register(&msm_mdf_driver);
+}
+
+void __exit msm_mdf_exit(void)
+{
+	platform_driver_unregister(&msm_mdf_driver);
+
+	if (ssr_handle)
+		subsys_notif_unregister_notifier(ssr_handle, &nb);
+}
+
+MODULE_DESCRIPTION("MSM MDF Module");
+MODULE_LICENSE("GPL v2");
diff --git a/dsp/q6_init.c b/dsp/q6_init.c
index 3b885dc..5c194fb 100644
--- a/dsp/q6_init.c
+++ b/dsp/q6_init.c
@@ -30,11 +30,13 @@
 	msm_audio_ion_init();
 	audio_slimslave_init();
 	avtimer_init();
+	msm_mdf_init();
 	return 0;
 }
 
 static void __exit audio_q6_exit(void)
 {
+	msm_mdf_exit();
 	avtimer_exit();
 	audio_slimslave_exit();
 	msm_audio_ion_exit();
diff --git a/dsp/q6_init.h b/dsp/q6_init.h
index 971e9b2..541fbe7 100644
--- a/dsp/q6_init.h
+++ b/dsp/q6_init.h
@@ -26,6 +26,20 @@
 int msm_audio_ion_init(void);
 int audio_slimslave_init(void);
 int avtimer_init(void);
+#ifdef CONFIG_MSM_MDF
+int msm_mdf_init(void);
+void msm_mdf_exit(void);
+#else
+static inline int msm_mdf_init(void)
+{
+	return 0;
+}
+
+static inline void msm_mdf_exit(void)
+{
+	return;
+}
+#endif
 
 void avtimer_exit(void);
 void audio_slimslave_exit(void);
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 31f86d6..b2d43bd 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -1796,8 +1796,11 @@
 	}
 	mutex_unlock(&this_afe.cal_data[AFE_FB_SPKR_PROT_EX_VI_CAL]->lock);
 
-	/* Register for DC detection event */
-	afe_spkr_prot_reg_event_cfg(port_id);
+	/* Register for DC detection event if speaker protection is enabled */
+	if (this_afe.prot_cfg.mode != MSM_SPKR_PROT_DISABLED &&
+		(this_afe.vi_tx_port == port_id)) {
+		afe_spkr_prot_reg_event_cfg(port_id);
+	}
 }
 
 static void afe_send_cal_spkr_prot_rx(int port_id)
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 378279a..db95d3b 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -98,6 +98,7 @@
 struct audio_session {
 	struct audio_client *ac;
 	spinlock_t session_lock;
+	struct mutex mutex_lock_per_session;
 };
 /* session id: 0 reserved */
 static struct audio_session session[ASM_ACTIVE_STREAMS_ALLOWED + 1];
@@ -564,6 +565,10 @@
 		if (session[n].ac == ac)
 			return n;
 	}
+
+	pr_debug("%s: cannot find matching audio client. ac = %pK\n",
+		__func__, ac);
+
 	return 0;
 }
 
@@ -579,6 +584,7 @@
 
 	pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
 	session_id = ac->session;
+	mutex_lock(&session[session_id].mutex_lock_per_session);
 	rtac_remove_popp_from_adm_devices(ac->session);
 	spin_lock_irqsave(&(session[session_id].session_lock), flags);
 	session[ac->session].ac = NULL;
@@ -590,6 +596,7 @@
 	kfree(ac);
 	ac = NULL;
 	spin_unlock_irqrestore(&(session[session_id].session_lock), flags);
+	mutex_unlock(&session[session_id].mutex_lock_per_session);
 }
 
 static uint32_t q6asm_get_next_buf(struct audio_client *ac,
@@ -1192,6 +1199,7 @@
 	int rc;
 	uint32_t sz = 0;
 	uint64_t actual_sz = 0;
+	int session_id = 0;
 
 	if (!data || !ac) {
 		pr_err("%s: %s is NULL\n", __func__,
@@ -1200,6 +1208,12 @@
 		goto done;
 	}
 
+	session_id = q6asm_get_session_id_from_audio_client(ac);
+	if (!session_id) {
+		rc = -EINVAL;
+		goto done;
+	}
+
 	if (data->event_type >= ARRAY_SIZE(adsp_reg_event_opcode)) {
 		pr_err("%s: event %u out of boundary of array size of (%lu)\n",
 		       __func__, data->event_type,
@@ -1223,6 +1237,12 @@
 		goto done;
 	}
 
+	mutex_lock(&session[session_id].mutex_lock_per_session);
+	if (!q6asm_is_valid_audio_client(ac)) {
+		rc = -EINVAL;
+		goto fail_send_param;
+	}
+
 	q6asm_add_hdr_async(ac, &hdr, sz, TRUE);
 	atomic_set(&ac->cmd_state_pp, -1);
 	hdr.opcode = adsp_reg_event_opcode[data->event_type];
@@ -1255,6 +1275,7 @@
 
 	rc = 0;
 fail_send_param:
+	mutex_unlock(&session[session_id].mutex_lock_per_session);
 	kfree(asm_params);
 done:
 	return rc;
@@ -2696,6 +2717,7 @@
 	struct asm_stream_cmd_set_pp_params *asm_set_param = NULL;
 	int pkt_size = 0;
 	int ret = 0;
+	int session_id = 0;
 
 	if (ac == NULL) {
 		pr_err("%s: Audio Client is NULL\n", __func__);
@@ -2705,6 +2727,10 @@
 		return -EINVAL;
 	}
 
+	session_id = q6asm_get_session_id_from_audio_client(ac);
+	if (!session_id)
+		return -EINVAL;
+
 	pkt_size = sizeof(struct asm_stream_cmd_set_pp_params);
 	/* Add param size to packet size when sending in-band only */
 	if (param_data != NULL)
@@ -2713,6 +2739,18 @@
 	if (!asm_set_param)
 		return -ENOMEM;
 
+	mutex_lock(&session[session_id].mutex_lock_per_session);
+	if (!q6asm_is_valid_audio_client(ac)) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (ac->apr == NULL) {
+		pr_err("%s: AC APR handle NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
 	q6asm_add_hdr_async(ac, &asm_set_param->apr_hdr, pkt_size, TRUE);
 
 	/* With pre-packed data, only the opcode differs from V2 and V3. */
@@ -2765,6 +2803,7 @@
 	}
 	ret = 0;
 done:
+	mutex_unlock(&session[session_id].mutex_lock_per_session);
 	kfree(asm_set_param);
 	return ret;
 }
@@ -4027,11 +4066,13 @@
  * parameters
  *   config - session parameters (channels, bits_per_sample, sr)
  *   dir - stream direction (IN for playback, OUT for capture)
+ *   use_default_chmap: true if default channel map to be used
+ *   channel_map: input channel map
  * returns 0 if successful, error code otherwise
  */
 int q6asm_open_shared_io(struct audio_client *ac,
 			 struct shared_io_config *config,
-			 int dir)
+			 int dir, bool use_default_chmap, u8 *channel_map)
 {
 	struct asm_stream_cmd_open_shared_io *open;
 	u8 *channel_mapping;
@@ -4041,6 +4082,12 @@
 	if (!ac || !config)
 		return -EINVAL;
 
+	if (!use_default_chmap && (channel_map == NULL)) {
+		pr_err("%s: No valid chan map and can't use default\n",
+			__func__);
+		return -EINVAL;
+	}
+
 	bufsz = config->bufsz;
 	bufcnt = config->bufcnt;
 	num_watermarks = 0;
@@ -4137,10 +4184,17 @@
 
 	memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
 
-	rc = q6asm_map_channels(channel_mapping, config->channels, false);
-	if (rc) {
-		pr_err("%s: Map channels failed, ret: %d\n", __func__, rc);
-		goto done;
+	if (use_default_chmap) {
+		rc = q6asm_map_channels(channel_mapping, config->channels,
+					false);
+		if (rc) {
+			pr_err("%s: Map channels failed, ret: %d\n",
+				 __func__, rc);
+			goto done;
+		}
+	} else {
+		memcpy(channel_mapping, channel_map,
+				PCM_FORMAT_MAX_NUM_CHANNEL);
 	}
 
 	open->num_watermark_levels = num_watermarks;
@@ -10313,8 +10367,10 @@
 
 	memset(session, 0, sizeof(struct audio_session) *
 		(ASM_ACTIVE_STREAMS_ALLOWED + 1));
-	for (lcnt = 0; lcnt <= ASM_ACTIVE_STREAMS_ALLOWED; lcnt++)
+	for (lcnt = 0; lcnt <= ASM_ACTIVE_STREAMS_ALLOWED; lcnt++) {
 		spin_lock_init(&(session[lcnt].session_lock));
+		mutex_init(&(session[lcnt].mutex_lock_per_session));
+	}
 	set_custom_topology = 1;
 
 	/*setup common client used for cal mem map */
diff --git a/dsp/q6core.c b/dsp/q6core.c
index 34f0dd0..b94d264 100644
--- a/dsp/q6core.c
+++ b/dsp/q6core.c
@@ -39,6 +39,8 @@
 
 #define ADSP_STATE_READY_TIMEOUT_MS 3000
 
+#define APR_ENOTREADY 10
+
 enum {
 	META_CAL,
 	CUST_TOP_CAL,
@@ -274,12 +276,24 @@
 		case AVCS_CMD_SHARED_MEM_UNMAP_REGIONS:
 			pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS status[0x%x]\n",
 				__func__, payload1[1]);
+			/* -ADSP status to match Linux error standard */
+			q6core_lcl.adsp_status = -payload1[1];
 			q6core_lcl.bus_bw_resp_received = 1;
 			wake_up(&q6core_lcl.bus_bw_req_wait);
 			break;
 		case AVCS_CMD_SHARED_MEM_MAP_REGIONS:
 			pr_debug("%s: Cmd = AVCS_CMD_SHARED_MEM_MAP_REGIONS status[0x%x]\n",
 				__func__, payload1[1]);
+			/* -ADSP status to match Linux error standard */
+			q6core_lcl.adsp_status = -payload1[1];
+			q6core_lcl.bus_bw_resp_received = 1;
+			wake_up(&q6core_lcl.bus_bw_req_wait);
+			break;
+		case AVCS_CMD_MAP_MDF_SHARED_MEMORY:
+			pr_debug("%s: Cmd = AVCS_CMD_MAP_MDF_SHARED_MEMORY status[0x%x]\n",
+				__func__, payload1[1]);
+			/* -ADSP status to match Linux error standard */
+			q6core_lcl.adsp_status = -payload1[1];
 			q6core_lcl.bus_bw_resp_received = 1;
 			wake_up(&q6core_lcl.bus_bw_req_wait);
 			break;
@@ -923,7 +937,7 @@
 }
 EXPORT_SYMBOL(q6core_is_adsp_ready);
 
-static int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id,
+int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id,
 			uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle)
 {
 	struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
@@ -951,7 +965,7 @@
 	mmap_regions->hdr.dest_port = 0;
 	mmap_regions->hdr.token = 0;
 	mmap_regions->hdr.opcode = AVCS_CMD_SHARED_MEM_MAP_REGIONS;
-	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
+	mmap_regions->mem_pool_id = mempool_id & 0x00ff;
 	mmap_regions->num_regions = bufcnt & 0x00ff;
 	mmap_regions->property_flag = 0x00;
 
@@ -971,6 +985,7 @@
 		__func__, buf_add, bufsz[0], mmap_regions->num_regions);
 
 	*map_handle = 0;
+	q6core_lcl.adsp_status = 0;
 	q6core_lcl.bus_bw_resp_received = 0;
 	ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
 		mmap_regions);
@@ -988,6 +1003,16 @@
 		pr_err("%s: timeout. waited for memory map\n", __func__);
 		ret = -ETIME;
 		goto done;
+	} else {
+		/* set ret to 0 as no timeout happened */
+		ret = 0;
+	}
+
+	if (q6core_lcl.adsp_status < 0) {
+		pr_err("%s: DSP returned error %d\n",
+			__func__, q6core_lcl.adsp_status);
+		ret = q6core_lcl.adsp_status;
+		goto done;
 	}
 
 	*map_handle = q6core_lcl.mem_map_cal_handle;
@@ -996,7 +1021,7 @@
 	return ret;
 }
 
-static int q6core_memory_unmap_regions(uint32_t mem_map_handle)
+int q6core_memory_unmap_regions(uint32_t mem_map_handle)
 {
 	struct avs_cmd_shared_mem_unmap_regions unmap_regions;
 	int ret = 0;
@@ -1015,6 +1040,7 @@
 	unmap_regions.hdr.opcode = AVCS_CMD_SHARED_MEM_UNMAP_REGIONS;
 	unmap_regions.mem_map_handle = mem_map_handle;
 
+	q6core_lcl.adsp_status = 0;
 	q6core_lcl.bus_bw_resp_received = 0;
 
 	pr_debug("%s: unmap regions map handle %d\n",
@@ -1037,11 +1063,110 @@
 		       __func__);
 		ret = -ETIME;
 		goto done;
+	} else {
+		/* set ret to 0 as no timeout happened */
+		ret = 0;
+	}
+	if (q6core_lcl.adsp_status < 0) {
+		pr_err("%s: DSP returned error %d\n",
+			__func__, q6core_lcl.adsp_status);
+		ret = q6core_lcl.adsp_status;
+		goto done;
 	}
 done:
 	return ret;
 }
 
+
+int q6core_map_mdf_shared_memory(uint32_t map_handle, phys_addr_t *buf_add,
+			uint32_t proc_id, uint32_t *bufsz, uint32_t bufcnt)
+{
+	struct avs_cmd_map_mdf_shared_memory *mmap_regions = NULL;
+	struct avs_shared_map_region_payload *mregions = NULL;
+	void *mmap_region_cmd = NULL;
+	void *payload = NULL;
+	int ret = 0;
+	int i = 0;
+	int cmd_size = 0;
+
+	cmd_size = sizeof(struct avs_cmd_map_mdf_shared_memory)
+			+ sizeof(struct avs_shared_map_region_payload)
+			* bufcnt;
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (mmap_region_cmd == NULL)
+		return -ENOMEM;
+
+	mmap_regions = (struct avs_cmd_map_mdf_shared_memory *)mmap_region_cmd;
+	mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+								APR_PKT_VER);
+	mmap_regions->hdr.pkt_size = cmd_size;
+	mmap_regions->hdr.src_port = 0;
+	mmap_regions->hdr.dest_port = 0;
+	mmap_regions->hdr.token = 0;
+	mmap_regions->hdr.opcode = AVCS_CMD_MAP_MDF_SHARED_MEMORY;
+	mmap_regions->mem_map_handle = map_handle;
+	mmap_regions->proc_id = proc_id & 0x00ff;
+	mmap_regions->num_regions = bufcnt & 0x00ff;
+
+	payload = ((u8 *) mmap_region_cmd +
+				sizeof(struct avs_cmd_map_mdf_shared_memory));
+	mregions = (struct avs_shared_map_region_payload *)payload;
+
+	for (i = 0; i < bufcnt; i++) {
+		mregions->shm_addr_lsw = lower_32_bits(buf_add[i]);
+		mregions->shm_addr_msw =
+				msm_audio_populate_upper_32_bits(buf_add[i]);
+		mregions->mem_size_bytes = bufsz[i];
+		++mregions;
+	}
+
+	pr_debug("%s: sending mdf memory map, addr %pa, size %d, bufcnt = %d\n",
+		__func__, buf_add, bufsz[0], mmap_regions->num_regions);
+
+	q6core_lcl.adsp_status = 0;
+	q6core_lcl.bus_bw_resp_received = 0;
+	ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)
+		mmap_regions);
+	if (ret < 0) {
+		pr_err("%s: mdf memory map failed %d\n",
+			__func__, ret);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+				(q6core_lcl.bus_bw_resp_received == 1),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: timeout. waited for mdf memory map\n",
+			__func__);
+		ret = -ETIME;
+		goto done;
+	} else {
+		/* set ret to 0 as no timeout happened */
+		ret = 0;
+	}
+
+	/*
+	 * When the remote DSP is not ready, the ADSP will validate and store
+	 * the memory information and return APR_ENOTREADY to HLOS. The ADSP
+	 * will map the memory with remote DSP when it is ready. HLOS should
+	 * not treat APR_ENOTREADY as an error.
+	 */
+	if (q6core_lcl.adsp_status != -APR_ENOTREADY) {
+		pr_err("%s: DSP returned error %d\n",
+			__func__, q6core_lcl.adsp_status);
+		ret = q6core_lcl.adsp_status;
+		goto done;
+	}
+
+done:
+	kfree(mmap_region_cmd);
+	return ret;
+}
+
 static int q6core_dereg_all_custom_topologies(void)
 {
 	int ret = 0;
@@ -1119,10 +1244,11 @@
 
 	q6core_dereg_all_custom_topologies();
 
-	ret = q6core_map_memory_regions(&cal_block->cal_data.paddr, 0,
+	ret = q6core_map_memory_regions(&cal_block->cal_data.paddr,
+		ADSP_MEMORY_MAP_SHMEM8_4K_POOL,
 		(uint32_t *)&cal_block->map_data.map_size, 1,
 		&cal_block->map_data.q6map_handle);
-	if (!ret)  {
+	if (ret)  {
 		pr_err("%s: q6core_map_memory_regions failed\n", __func__);
 		goto unlock;
 	}
@@ -1172,7 +1298,7 @@
 		ret = q6core_lcl.adsp_status;
 unmap:
 	ret2 = q6core_memory_unmap_regions(cal_block->map_data.q6map_handle);
-	if (!ret2)  {
+	if (ret2)  {
 		pr_err("%s: q6core_memory_unmap_regions failed for map handle %d\n",
 			__func__, cal_block->map_data.q6map_handle);
 		ret = ret2;
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index f4e1f76..4ce9973 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -4521,6 +4521,7 @@
 #define ADSP_MEMORY_MAP_SMI_POOL      1
 #define ADSP_MEMORY_MAP_IMEM_POOL      2
 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL      3
+#define ADSP_MEMORY_MAP_MDF_SHMEM_4K_POOL   4
 
 /* Definition of virtual memory flag */
 #define ADSP_MEMORY_MAP_VIRTUAL_MEMORY 1
@@ -4645,6 +4646,53 @@
 
 } __packed;
 
+#define AVS_MDF_MDSP_PROC_ID	 0x2
+#define AVS_MDF_SSC_PROC_ID      0x3
+#define AVS_MDF_CDSP_PROC_ID	 0x4
+
+/* Shared memory map command payload used by the
+ * #AVCS_CMD_MAP_MDF_SHARED_MEMORY.
+ *
+ * This structure allows clients to map multiple shared memory
+ * regions with remote processor ID. All mapped regions must be
+ * from the same memory pool. Following this structure are
+ * num_regions of avs_shared_map_region_payload.
+ */
+struct avs_cmd_map_mdf_shared_memory {
+	struct apr_hdr hdr;
+	uint32_t mem_map_handle;
+/* Unique identifier for the shared memory address.
+ *
+ * The aDSP returns this handle for
+ * #AVCS_CMD_SHARED_MEM_MAP_REGIONS
+ *
+ * Supported values:
+ * Any 32-bit value
+ *
+ * The aDSP uses this handle to retrieve the shared memory
+ * attributes. This handle can be an abstract representation
+ * of the shared memory regions that are being mapped.
+ */
+
+	uint32_t proc_id;
+/* Supported values:
+ * #AVS_MDF_MDSP_PROC_ID
+ * #AVS_MDF_SSC_PROC_ID
+ * #AVS_MDF_CDSP_PROC_ID
+ */
+
+	uint32_t num_regions;
+/* Number of regions to be mapped with the remote DSP processor
+ * mentioned by proc_id field.
+ *
+ * Array of structures of avs_shared_map_region_payload will follow.
+ * The address fields in those arrays should correspond to the remote
+ * processor mentioned by proc_id.
+ * In case of DSPs with SMMU enabled, the address should be IOVA.
+ * And for DSPs without SMMU, the address should be physical address.
+ */
+} __packed;
+
 /*adsp_audio_memmap_api.h*/
 
 /* ASM related data structures */
diff --git a/include/dsp/msm_audio_ion.h b/include/dsp/msm_audio_ion.h
index dae1d1d..9235adc 100644
--- a/include/dsp/msm_audio_ion.h
+++ b/include/dsp/msm_audio_ion.h
@@ -33,4 +33,5 @@
 int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op);
 
 u32 msm_audio_populate_upper_32_bits(dma_addr_t pa);
+int msm_audio_ion_get_smmu_info(struct device **cb_dev, u64 *smmu_sid);
 #endif /* _LINUX_MSM_AUDIO_ION_H */
diff --git a/include/dsp/msm_mdf.h b/include/dsp/msm_mdf.h
new file mode 100644
index 0000000..5b27f12
--- /dev/null
+++ b/include/dsp/msm_mdf.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, 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 _LINUX_MSM_MDF_H
+#define _LINUX_MSM_MDF_H
+
+#ifdef CONFIG_MSM_MDF
+
+/**
+ *  msm_mdf_mem_init - allocate and map memory to ADSP be shared
+ *                     across multiple remote DSPs.
+ */
+int msm_mdf_mem_init(void);
+
+/**
+ *  msm_mdf_mem_init - unmap and free memory to ADSP.
+ */
+int msm_mdf_mem_deinit(void);
+
+#else
+
+static inline int msm_mdf_mem_init(void)
+{
+	return 0;
+}
+
+static inline int msm_mdf_mem_deinit(void)
+{
+	return 0;
+}
+
+#endif /* CONFIG_MSM_MDF */
+
+#endif /* _LINUX_MSM_MDF_H */
diff --git a/include/dsp/q6asm-v2.h b/include/dsp/q6asm-v2.h
index 633e16c..5fa03be 100644
--- a/include/dsp/q6asm-v2.h
+++ b/include/dsp/q6asm-v2.h
@@ -303,7 +303,8 @@
 			uint16_t bits_per_sample);
 
 int q6asm_open_shared_io(struct audio_client *ac,
-			 struct shared_io_config *c, int dir);
+			 struct shared_io_config *c, int dir,
+			 bool use_default_chmap, u8 *channel_map);
 
 int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
 			uint16_t bits_per_sample);
diff --git a/include/dsp/q6core.h b/include/dsp/q6core.h
index cdee048..4d5a973 100644
--- a/include/dsp/q6core.h
+++ b/include/dsp/q6core.h
@@ -110,6 +110,20 @@
 #define AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS                          0x00012925
 #define AVCS_CMD_SHARED_MEM_UNMAP_REGIONS                           0x00012926
 
+/* Commands the AVCS to map multiple shared memory regions with remote
+ * processor ID. All mapped regions must be from the same memory pool.
+ *
+ * Return:
+ * ADSP_EOK        : SUCCESS
+ * ADSP_EHANDLE    : Failed due to incorrect handle.
+ * ADSP_EBADPARAM  : Failed due to bad parameters.
+ *
+ * Dependencies:
+ * The mem_map_handle should be obtained earlier
+ * using AVCS_CMD_SHARED_MEM_MAP_REGIONS with pool ID
+ * ADSP_MEMORY_MAP_MDF_SHMEM_4K_POOL.
+ */
+#define AVCS_CMD_MAP_MDF_SHARED_MEMORY                              0x00012930
 
 #define AVCS_CMD_REGISTER_TOPOLOGIES                                0x00012923
 
@@ -183,10 +197,15 @@
 } __packed;
 
 
+int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id,
+			uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle);
+int q6core_memory_unmap_regions(uint32_t mem_map_handle);
+int q6core_map_mdf_shared_memory(uint32_t map_handle, phys_addr_t *buf_add,
+			uint32_t proc_id, uint32_t *bufsz, uint32_t bufcnt);
+
 int32_t core_set_license(uint32_t key, uint32_t module_id);
 int32_t core_get_license_status(uint32_t module_id);
 
 int32_t q6core_load_unload_topo_modules(uint32_t topology_id,
 			bool preload_type);
-
 #endif /* __Q6CORE_H__ */
diff --git a/include/soc/soundwire.h b/include/soc/soundwire.h
index d2ebb76..2796428 100644
--- a/include/soc/soundwire.h
+++ b/include/soc/soundwire.h
@@ -15,6 +15,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/mod_devicetable.h>
+#include <linux/irqdomain.h>
 
 extern struct bus_type soundwire_type;
 
@@ -76,6 +77,8 @@
 	u8 hstop;
 	u8 blk_grp_count;
 	u8 blk_pack_mode;
+	u8 word_length;
+	u8 lane_ctrl;
 	u8 ch_en;
 	u8 req_ch;
 	u8 num_ch;
@@ -204,7 +207,7 @@
 	struct device    dev;
 	unsigned long    addr;
 	u8 group_id;
-	u8 slave_irq;
+	struct irq_domain *slave_irq;
 };
 
 static inline struct swr_device *to_swr_device(struct device *dev)
@@ -334,4 +337,7 @@
 extern int swr_remove_from_group(struct swr_device *dev, u8 dev_num);
 
 extern void swr_remove_device(struct swr_device *swr_dev);
+
+extern struct swr_device *get_matching_swr_slave_device(struct device_node *np);
+
 #endif /* _LINUX_SOUNDWIRE_H */
diff --git a/soc/soundwire.c b/soc/soundwire.c
index f05a5f9..fff5c15 100644
--- a/soc/soundwire.c
+++ b/soc/soundwire.c
@@ -245,7 +245,7 @@
 	if (!dev->group_id)
 		return 0;
 
-	if (master->gr_sid == dev_num)
+	if (master->gr_sid != dev_num)
 		return 0;
 
 	if (master->remove_from_group && master->remove_from_group(master))
@@ -792,6 +792,26 @@
 }
 EXPORT_SYMBOL(swr_master_add_boarddevices);
 
+struct swr_device *get_matching_swr_slave_device(struct device_node *np)
+{
+	struct swr_device *swr = NULL;
+	struct swr_master *master;
+
+	mutex_lock(&board_lock);
+	list_for_each_entry(master, &swr_master_list, list) {
+		mutex_lock(&master->mlock);
+		list_for_each_entry(swr, &master->devices, dev_list) {
+			if (swr->dev.of_node == np)
+				break;
+		}
+		mutex_unlock(&master->mlock);
+	}
+	mutex_unlock(&board_lock);
+
+	return swr;
+}
+EXPORT_SYMBOL(get_matching_swr_slave_device);
+
 static void swr_unregister_device(struct swr_device *swr)
 {
 	if (swr)
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 68354b8..b2449e7 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -1078,7 +1078,9 @@
 				if (swr_dev->dev_num != devnum)
 					continue;
 				if (swr_dev->slave_irq)
-					handle_nested_irq(swr_dev->slave_irq);
+					handle_nested_irq(
+						irq_find_mapping(
+						swr_dev->slave_irq, 0));
 			}
 			break;
 		case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED:
diff --git a/soc/swr-wcd-ctrl.c b/soc/swr-wcd-ctrl.c
index 729eb38..ecca5f6 100644
--- a/soc/swr-wcd-ctrl.c
+++ b/soc/swr-wcd-ctrl.c
@@ -1790,6 +1790,8 @@
 		    (swrm->state == SWR_MSTR_UP)) {
 			dev_dbg(swrm->dev, "%s: SWR master is already UP: %d\n",
 				__func__, swrm->state);
+			list_for_each_entry(swr_dev, &mstr->devices, dev_list)
+				swr_reset_device(swr_dev);
 		} else {
 			pm_runtime_mark_last_busy(&pdev->dev);
 			mutex_unlock(&swrm->reslock);
diff --git a/soc/swrm_registers.h b/soc/swrm_registers.h
index f1d2586..0147e45 100644
--- a/soc/swrm_registers.h
+++ b/soc/swrm_registers.h
@@ -179,6 +179,30 @@
 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT		0x08
 #define SWRM_DP_PORT_CTRL_SAMPLE_INTERVAL	0x00
 
+#define SWRM_DP_PORT_CTRL_2_BANK(n, m)	(SWRM_BASE_ADDRESS + \
+							0x00001128 + \
+							0x100*(n-1) + \
+							0x40*m)
+
+#define SWRM_DP_BLOCK_CTRL_1(n)		(SWRM_BASE_ADDRESS + \
+							0x0000112C + 0x100*n)
+
+#define SWRM_DP_BLOCK_CTRL2_BANK(n, m)	(SWRM_BASE_ADDRESS + \
+							0x00001130 + \
+							0x100*(n-1) + \
+							0x40*m)
+
+#define SWRM_DP_PORT_HCTRL_BANK(n, m)	(SWRM_BASE_ADDRESS + \
+							0x00001134 + \
+							0x100*(n-1) + \
+							0x40*m)
+
+#define SWRM_DP_BLOCK_CTRL3_BANK(n, m)	(SWRM_BASE_ADDRESS + \
+							0x00001138 + \
+							0x100*(n-1) + \
+							0x40*m)
+
+
 #define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (SWRM_BASE_ADDRESS + \
 						0x00001054 + 0x100*n)
 
@@ -190,8 +214,14 @@
 
 #define SWRS_DP_REG_OFFSET(port, bank)		((0x100*port)+(0x10*bank))
 
+#define SWRS_SCP_CONTROL				0x44
+#define SWRS_DP_BLOCK_CONTROL_1(n)		(SWRS_BASE_ADDRESS + 0x120 + \
+						0x100 * n)
+
 #define SWRS_DP_CHANNEL_ENABLE_BANK(n, m)	(SWRS_BASE_ADDRESS + 0x120 + \
 						 SWRS_DP_REG_OFFSET(n, m))
+#define SWRS_DP_BLOCK_CONTROL_2_BANK(n, m)	(SWRS_BASE_ADDRESS + 0x121 + \
+						 SWRS_DP_REG_OFFSET(n, m))
 #define SWRS_DP_SAMPLE_CONTROL_1_BANK(n, m)	(SWRS_BASE_ADDRESS + 0x122 + \
 						 SWRS_DP_REG_OFFSET(n, m))
 #define SWRS_DP_OFFSET_CONTROL_1_BANK(n, m)	(SWRS_BASE_ADDRESS + 0x124 + \
@@ -202,6 +232,8 @@
 						 SWRS_DP_REG_OFFSET(n, m))
 #define SWRS_DP_BLOCK_CONTROL_3_BANK(n, m)	(SWRS_BASE_ADDRESS + 0x127 + \
 						 SWRS_DP_REG_OFFSET(n, m))
+#define SWRS_DP_LANE_CONTROL_BANK(n, m) (SWRS_BASE_ADDRESS + 0x128 + \
+						 SWRS_DP_REG_OFFSET(n, m))
 #define SWRS_SCP_FRAME_CTRL_BANK(m)		(SWRS_BASE_ADDRESS + 0x60 + \
 						 0x10*m)
 #define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m)	(SWRS_BASE_ADDRESS + 0xE0 + \