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 + \