From c9443c282afadaaf50c82512d140e45818ba4489 Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Tue, 28 Aug 2018 05:35:34 +0530 Subject: [PATCH 1/3] ASoC: wcd938x: Add support for wcd938x codec WCD938x codec is a soundwire based codec that supports AMICs, DMICs, Headphones, Ear and Aux paths. Add support to enable all device paths of wcd938x codec. Change-Id: I81b5e603ef73afba74b8d2274012752f9ca5cb6f Signed-off-by: Sudheer Papothi --- Android.mk | 7 + asoc/codecs/wcd938x/Android.mk | 57 + asoc/codecs/wcd938x/Kbuild | 112 + asoc/codecs/wcd938x/internal.h | 182 ++ asoc/codecs/wcd938x/wcd938x-mbhc.c | 1082 +++++++++ asoc/codecs/wcd938x/wcd938x-mbhc.h | 63 + asoc/codecs/wcd938x/wcd938x-registers.h | 502 +++++ asoc/codecs/wcd938x/wcd938x-regmap.c | 513 +++++ asoc/codecs/wcd938x/wcd938x-slave.c | 117 + asoc/codecs/wcd938x/wcd938x-tables.c | 474 ++++ asoc/codecs/wcd938x/wcd938x.c | 2704 +++++++++++++++++++++++ 11 files changed, 5813 insertions(+) create mode 100644 asoc/codecs/wcd938x/Android.mk create mode 100644 asoc/codecs/wcd938x/Kbuild create mode 100644 asoc/codecs/wcd938x/internal.h create mode 100644 asoc/codecs/wcd938x/wcd938x-mbhc.c create mode 100644 asoc/codecs/wcd938x/wcd938x-mbhc.h create mode 100644 asoc/codecs/wcd938x/wcd938x-registers.h create mode 100644 asoc/codecs/wcd938x/wcd938x-regmap.c create mode 100644 asoc/codecs/wcd938x/wcd938x-slave.c create mode 100644 asoc/codecs/wcd938x/wcd938x-tables.c create mode 100644 asoc/codecs/wcd938x/wcd938x.c diff --git a/Android.mk b/Android.mk index e3a969652da3..76813c110967 100644 --- a/Android.mk +++ b/Android.mk @@ -35,3 +35,10 @@ 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, kona),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/wcd938x/Module.symvers) +include $(MY_LOCAL_PATH)/asoc/codecs/wcd938x/Android.mk +endif diff --git a/asoc/codecs/wcd938x/Android.mk b/asoc/codecs/wcd938x/Android.mk new file mode 100644 index 000000000000..81bb35670715 --- /dev/null +++ b/asoc/codecs/wcd938x/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,kona),true) +AUDIO_SELECT := CONFIG_SND_SOC_KONA=m +endif + +AUDIO_CHIPSET := audio +# Build/Package only in case of supported target +ifeq ($(call is-board-platform-in-list,kona),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 := $(shell pwd)/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 _audio.ko as LOCAL_MODULE. +# This means we need to rename the module to _audio.ko +# after audio.ko is built. +KBUILD_OPTIONS += MODNAME=wcd938x_dlkm +KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) +KBUILD_OPTIONS += $(AUDIO_SELECT) + +########################################################### +include $(CLEAR_VARS) +LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd938x.ko +LOCAL_MODULE_KBUILD_NAME := wcd938x_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)_wcd938x_slave.ko +LOCAL_MODULE_KBUILD_NAME := wcd938x_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/wcd938x/Kbuild b/asoc/codecs/wcd938x/Kbuild new file mode 100644 index 000000000000..309089074f24 --- /dev/null +++ b/asoc/codecs/wcd938x/Kbuild @@ -0,0 +1,112 @@ +# 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 := $(shell pwd)/kernel/msm-4.19 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.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) + +############ WCD938X ############ + +# for WCD938X Codec +ifdef CONFIG_SND_SOC_WCD938X + WCD938X_OBJS += wcd938x.o + WCD938X_OBJS += wcd938x-regmap.o + WCD938X_OBJS += wcd938x-tables.o + WCD938X_OBJS += wcd938x-mbhc.o +endif + +ifdef CONFIG_SND_SOC_WCD938X_SLAVE + WCD938X_SLAVE_OBJS += wcd938x-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_WCD938X) += wcd938x_dlkm.o +wcd938x_dlkm-y := $(WCD938X_OBJS) + +obj-$(CONFIG_SND_SOC_WCD938X_SLAVE) += wcd938x_slave_dlkm.o +wcd938x_slave_dlkm-y := $(WCD938X_SLAVE_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h new file mode 100644 index 000000000000..4811bd0f4ad0 --- /dev/null +++ b/asoc/codecs/wcd938x/internal.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _WCD938X_INTERNAL_H +#define _WCD938X_INTERNAL_H + +#include +#include +#include "wcd938x-mbhc.h" + +#define WCD938X_MAX_MICBIAS 4 + +/* 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 + +enum { + TX_HDR12 = 0, + TX_HDR34, + TX_HDR_MAX, +}; + +extern struct regmap_config wcd938x_regmap_config; + +struct codec_port_info { + u32 slave_port_type; + u32 master_port_type; + u32 ch_mask; + u32 num_ch; + u32 ch_rate; +}; + +struct wcd938x_priv { + struct device *dev; + + int variant; + struct snd_soc_component *component; + struct device_node *rst_np; + struct regmap *regmap; + + struct swr_device *rx_swr_dev; + struct swr_device *tx_swr_dev; + + s32 micb_ref[WCD938X_MAX_MICBIAS]; + s32 pullup_ref[WCD938X_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; + s32 dmic_6_7_clk_cnt; + int hdr_en[TX_HDR_MAX]; + /* class h specific info */ + struct wcd_clsh_cdc_info clsh_info; + /* mbhc module */ + struct wcd938x_mbhc *mbhc; + + u32 hph_mode; + bool comp1_enable; + bool comp2_enable; + + struct irq_domain *virq; + struct wcd_irq_info irq_info; + u32 rx_clk_cnt; + int num_irq_regs; + /* to track the status */ + unsigned long status_mask; + + 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 regulator_bulk_data *supplies; + + struct notifier_block nblock; + /* wcd callback to bolero */ + void *handle; + int (*update_wcd_event)(void *handle, u16 event, u32 data); + int (*register_notifier)(void *handle, + struct notifier_block *nblock, + bool enable); + u32 version; + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; +}; + +struct wcd938x_micbias_setting { + u8 ldoh_v; + u32 cfilt1_mv; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u32 micb4_mv; + u8 bias1_cfilt_sel; +}; + +struct wcd938x_pdata { + struct device_node *rst_np; + struct device_node *rx_slave; + struct device_node *tx_slave; + struct wcd938x_micbias_setting micbias; + + struct cdc_regulator *regulator; + int num_supplies; +}; + +struct wcd_ctrl_platform_data { + void *handle; + int (*update_wcd_event)(void *handle, u16 event, u32 data); + int (*register_notifier)(void *handle, + struct notifier_block *nblock, + bool enable); +}; + +enum { + WCD_RX1, + WCD_RX2, + WCD_RX3 +}; + +enum { + BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR = 1, + BOLERO_WCD_EVT_PA_OFF_PRE_SSR, + BOLERO_WCD_EVT_SSR_DOWN, + BOLERO_WCD_EVT_SSR_UP, + BOLERO_WCD_EVT_CLK_NOTIFY, +}; + +enum { + WCD_BOLERO_EVT_RX_MUTE = 1, /* for RX mute/unmute */ + WCD_BOLERO_EVT_IMPED_TRUE, /* for imped true */ + WCD_BOLERO_EVT_IMPED_FALSE, /* for imped false */ +}; + +enum { + /* INTR_CTRL_INT_MASK_0 */ + WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET = 0, + WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, + WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD938X_IRQ_MBHC_SW_DET, + WCD938X_IRQ_HPHR_OCP_INT, + WCD938X_IRQ_HPHR_CNP_INT, + WCD938X_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD938X_IRQ_HPHL_CNP_INT, + WCD938X_IRQ_EAR_CNP_INT, + WCD938X_IRQ_EAR_SCD_INT, + WCD938X_IRQ_AUX_CNP_INT, + WCD938X_IRQ_AUX_SCD_INT, + WCD938X_IRQ_HPHL_PDM_WD_INT, + WCD938X_IRQ_HPHR_PDM_WD_INT, + WCD938X_IRQ_AUX_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD938X_IRQ_LDORT_SCD_INT, + WCD938X_IRQ_MBHC_MOISTURE_INT, + WCD938X_IRQ_HPHL_SURGE_DET_INT, + WCD938X_IRQ_HPHR_SURGE_DET_INT, + WCD938X_NUM_IRQS, +}; + +extern struct wcd938x_mbhc *wcd938x_soc_get_mbhc( + struct snd_soc_component *component); +extern int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int volt, int micb_num); +extern int wcd938x_get_micb_vout_ctl_val(u32 micb_mv); +extern int wcd938x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm); +extern int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component); +#endif /* _WCD938X_INTERNAL_H */ diff --git a/asoc/codecs/wcd938x/wcd938x-mbhc.c b/asoc/codecs/wcd938x/wcd938x-mbhc.c new file mode 100644 index 000000000000..6d9f500378bf --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x-mbhc.c @@ -0,0 +1,1082 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd938x-registers.h" +#include "internal.h" + +#define WCD938X_ZDET_SUPPORTED true +/* Z value defined in milliohm */ +#define WCD938X_ZDET_VAL_32 32000 +#define WCD938X_ZDET_VAL_400 400000 +#define WCD938X_ZDET_VAL_1200 1200000 +#define WCD938X_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define WCD938X_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define WCD938X_ZDET_NUM_MEASUREMENTS 900 +#define WCD938X_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define WCD938X_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define WCD938X_MBHC_ZDET_CONST (86 * 16384) +#define WCD938X_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", + WCD938X_ANA_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + WCD938X_ANA_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + WCD938X_ANA_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + WCD938X_ANA_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + WCD938X_ANA_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + WCD938X_ANA_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + WCD938X_ANA_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + WCD938X_ANA_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + WCD938X_ANA_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + WCD938X_ANA_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + WCD938X_MBHC_NEW_CTL_1, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + WCD938X_MBHC_NEW_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + WCD938X_ANA_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE", + WCD938X_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + WCD938X_ANA_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + WCD938X_ANA_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + WCD938X_ANA_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + WCD938X_HPH_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + WCD938X_ANA_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + WCD938X_ANA_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + WCD938X_ANA_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + WCD938X_ANA_MICB2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + WCD938X_HPH_CNP_WG_TIME, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + WCD938X_ANA_HPH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + WCD938X_ANA_HPH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + WCD938X_ANA_HPH, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + WCD938X_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", + WCD938X_MBHC_CTL_BCS, 0x02, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + WCD938X_MBHC_NEW_FSM_STATUS, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + WCD938X_MBHC_NEW_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD938X_MBHC_NEW_FSM_STATUS, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD938X_HPH_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD938X_HPH_PA_CTL2, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", + WCD938X_HPH_L_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN", + WCD938X_HPH_R_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS", + WCD938X_DIGITAL_INTR_STATUS_0, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS", + WCD938X_DIGITAL_INTR_STATUS_0, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN", + WCD938X_MBHC_NEW_CTL_1, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD938X_MBHC_NEW_FSM_STATUS, + 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD938X_MBHC_NEW_FSM_STATUS, + 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD938X_MBHC_NEW_ADC_RESULT, + 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD938X_ANA_MICB2, 0x3F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE", + WCD938X_MBHC_NEW_CTL_1, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE", + WCD938X_MBHC_NEW_CTL_1, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN", + WCD938X_ANA_MBHC_ZDET, 0x02, 1, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = WCD938X_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = WCD938X_IRQ_HPHL_OCP_INT, + .hph_right_ocp = WCD938X_IRQ_HPHR_OCP_INT, +}; + +struct wcd938x_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static int wcd938x_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(component->dev); + + return wcd_request_irq(&wcd938x->irq_info, irq, name, handler, data); +} + +static void wcd938x_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(component->dev); + + if (enable) + wcd_enable_irq(&wcd938x->irq_info, irq); + else + wcd_disable_irq(&wcd938x->irq_info, irq); +} + +static int wcd938x_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(component->dev); + + wcd_free_irq(&wcd938x->irq_info, irq, data); + + return 0; +} + +static void wcd938x_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_1, + 0x80, 0x00); +} + +static int wcd938x_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read32(component, WCD938X_ANA_MBHC_RESULT_3) & 0x7; +} + +static void wcd938x_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_ELECT, + 0x01, 0x00); +} + +static void wcd938x_mbhc_program_btn_thr(struct snd_soc_component *component, + 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(component->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_component_update_bits(component, WCD938X_ANA_MBHC_BTN0 + i, + 0xFC, vth << 2); + dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n", + __func__, i, btn_high[i], vth); + } +} + +static bool wcd938x_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + return true; +} + +static int wcd938x_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct wcd938x_mbhc *wcd938x_mbhc; + + wcd938x_mbhc = container_of(mbhc, struct wcd938x_mbhc, wcd_mbhc); + + if (enable) + return blocking_notifier_chain_register(&wcd938x_mbhc->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd938x_mbhc->notifier, nblock); +} + +static bool wcd938x_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + u8 val = 0; + + if (micb_num == MIC_BIAS_2) { + val = ((snd_soc_component_read32(mbhc->component, + WCD938X_ANA_MICB2) & 0xC0) + >> 6); + if (val == 0x01) + return true; + } + return false; +} + +static bool wcd938x_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + return (snd_soc_component_read32(component, WCD938X_ANA_HPH) & 0xC0) ? + true : false; +} + +static void wcd938x_mbhc_hph_l_pull_up_control( + struct snd_soc_component *component, + 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(component->dev, "%s: HS pull up current:%d\n", + __func__, pull_up_cur); + + snd_soc_component_update_bits(component, + WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, + 0x1F, pull_up_cur); +} + +static int wcd938x_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + int ret = 0; + + ret = wcd938x_micbias_control(component, micb_num, req, false); + + return ret; +} + +static void wcd938x_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD938X_ANA_MICB2_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, WCD938X_ANA_MICB2_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, WCD938X_ANA_MICB2_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD938X_ANA_MICB2_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *wcd938x_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct wcd938x_mbhc *wcd938x_mbhc; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + wcd938x_mbhc = container_of(mbhc, struct wcd938x_mbhc, wcd_mbhc); + + if (!component) { + pr_err("%s: NULL component pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(wcd938x_mbhc->fw_data, type); + if (!hwdep_cal) + dev_err(component->dev, "%s: cal not sent by %d\n", + __func__, type); + + return hwdep_cal; +} + +static int wcd938x_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd938x_pdata *pdata = dev_get_platdata(component->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 = wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + + return rc; +} + +static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x, + 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(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < WCD938X_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd938x->regmap, WCD938X_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd938x->regmap, WCD938X_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = WCD938X_MBHC_GET_X1(val); + c1 = WCD938X_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(wcd938x->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 = (WCD938X_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = WCD938X_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(wcd938x->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_read(wcd938x->regmap, + WCD938X_ANA_MBHC_RESULT_1, &val); + regmap_read(wcd938x->regmap, + WCD938X_ANA_MBHC_RESULT_2, &val1); + val = val << 0x08; + val |= val1; + x1 = WCD938X_MBHC_GET_X1(val); + i++; + if (i == WCD938X_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void wcd938x_mbhc_zdet_ramp(struct snd_soc_component *component, + struct wcd938x_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(component->dev); + int32_t zdet = 0; + + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL, + 0x70, zdet_param->ldo_ctl << 4); + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN5, 0xFC, + zdet_param->btn5); + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN6, 0xFC, + zdet_param->btn6); + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN7, 0xFC, + zdet_param->btn7); + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL, + 0x0F, zdet_param->noff); + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_ZDET, 0x80, 0x80); + dev_dbg(wcd938x->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_ZDET, 0x40, 0x40); + dev_dbg(wcd938x->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void wcd938x_wcd_mbhc_qfuse_cal( + struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) +{ + s16 q1; + int q1_cal; + + if (*z_val < (WCD938X_ZDET_VAL_400/1000)) + q1 = snd_soc_component_read32(component, + WCD938X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read32(component, + WCD938X_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 wcd938x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd938x_priv *wcd938x = dev_get_drvdata(component->dev); + s16 reg0, reg1, reg2, reg3, reg4; + int32_t z1L, z1R, z1Ls; + int zMono, z_diff1, z_diff2; + bool is_fsm_disable = false; + struct wcd938x_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 wcd938x_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_component_read32(component, WCD938X_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read32(component, WCD938X_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read32(component, WCD938X_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read32(component, WCD938X_MBHC_CTL_CLK); + reg4 = snd_soc_component_read32(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read32(component, WCD938X_ANA_MBHC_ELECT) & 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_MECH, 0x01, 0x00); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + + if (!WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) + goto left_ch_impedance; + + /* Second ramp for left ch */ + if (z1L < WCD938X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1L > WCD938X_ZDET_VAL_400) && + (z1L <= WCD938X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1L > WCD938X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + +left_ch_impedance: + if ((z1L == WCD938X_ZDET_FLOATING_IMPEDANCE) || + (z1L > WCD938X_ZDET_VAL_100K)) { + *zl = WCD938X_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1L/1000; + wcd938x_wcd_mbhc_qfuse_cal(component, zl, 0); + } + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", + __func__, *zl); + + /* Start of right impedance ramp and calculation */ + wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if (WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { + if (((z1R > WCD938X_ZDET_VAL_1200) && + (zdet_param_ptr->noff == 0x6)) || + ((*zl) != WCD938X_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* Second ramp for right ch */ + if (z1R < WCD938X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1R > WCD938X_ZDET_VAL_400) && + (z1R <= WCD938X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1R > WCD938X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd938x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + } +right_ch_impedance: + if ((z1R == WCD938X_ZDET_FLOATING_IMPEDANCE) || + (z1R > WCD938X_ZDET_VAL_100K)) { + *zr = WCD938X_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R/1000; + wcd938x_wcd_mbhc_qfuse_cal(component, zr, 1); + } + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", + __func__, *zr); + + /* Mono/stereo detection */ + if ((*zl == WCD938X_ZDET_FLOATING_IMPEDANCE) && + (*zr == WCD938X_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == WCD938X_ZDET_FLOATING_IMPEDANCE) || + (*zr == WCD938X_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(component->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_component_update_bits(component, WCD938X_HPH_R_ATEST, 0x02, 0x02); + snd_soc_component_update_bits(component, WCD938X_HPH_PA_CTL2, 0x40, 0x01); + if (*zl < (WCD938X_ZDET_VAL_32/1000)) + wcd938x_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls, NULL, d1); + else + wcd938x_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls, NULL, d1); + snd_soc_component_update_bits(component, WCD938X_HPH_PA_CTL2, 0x40, 0x00); + snd_soc_component_update_bits(component, WCD938X_HPH_R_ATEST, 0x02, 0x00); + z1Ls /= 1000; + wcd938x_wcd_mbhc_qfuse_cal(component, &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(component->dev, "%s: stereo plug type detected\n", + __func__); + mbhc->hph_type = WCD_MBHC_HPH_STEREO; + } else { + dev_dbg(component->dev, "%s: MONO plug type detected\n", + __func__); + mbhc->hph_type = WCD_MBHC_HPH_MONO; + } + +zdet_complete: + snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD938X_MBHC_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd938x->regmap, + WCD938X_ANA_MBHC_ELECT, 0x80, 0x80); +} + +static void wcd938x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_MECH, + 0x02, 0x00); + } +} + +static void wcd938x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD938X_HPH_PA_CTL2, + 0x40, 0x40); + snd_soc_component_update_bits(component, WCD938X_HPH_PA_CTL2, + 0x10, 0x10); + } else { + snd_soc_component_update_bits(component, WCD938X_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD938X_HPH_PA_CTL2, + 0x10, 0x00); + } +} + +static void wcd938x_mbhc_moisture_config(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + + if ((mbhc->moist_rref == R_OFF) || + (mbhc->mbhc_cfg->enable_usbc_analog)) { + snd_soc_component_update_bits(component, WCD938X_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(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); +} + +static void wcd938x_mbhc_moisture_detect_en(struct wcd_mbhc *mbhc, bool enable) +{ + struct snd_soc_component *component = mbhc->component; + + if (enable) + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); + else + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); +} + +static bool wcd938x_mbhc_get_moisture_status(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + bool ret = false; + + if ((mbhc->moist_rref == R_OFF) || + (mbhc->mbhc_cfg->enable_usbc_analog)) { + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + goto done; + } + + /* Do not enable moisture detection if jack type is NC */ + if (!mbhc->hphl_swh) { + dev_dbg(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + goto done; + } + + /* + * If moisture_en is already enabled, then skip to plug type + * detection. + */ + if ((snd_soc_component_read32(component, WCD938X_MBHC_NEW_CTL_2) & 0x0C)) + goto done; + + wcd938x_mbhc_moisture_detect_en(mbhc, true); + /* Read moisture comparator status */ + ret = ((snd_soc_component_read32(component, WCD938X_MBHC_NEW_FSM_STATUS) + & 0x20) ? 0 : 1); + +done: + return ret; + +} + +static void wcd938x_mbhc_moisture_polling_ctrl(struct wcd_mbhc *mbhc, + bool enable) +{ + struct snd_soc_component *component = mbhc->component; + + snd_soc_component_update_bits(component, + WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, + 0x04, (enable << 2)); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = wcd938x_mbhc_request_irq, + .irq_control = wcd938x_mbhc_irq_control, + .free_irq = wcd938x_mbhc_free_irq, + .clk_setup = wcd938x_mbhc_clk_setup, + .map_btn_code_to_num = wcd938x_mbhc_btn_to_num, + .mbhc_bias = wcd938x_mbhc_mbhc_bias_control, + .set_btn_thr = wcd938x_mbhc_program_btn_thr, + .lock_sleep = wcd938x_mbhc_lock_sleep, + .register_notifier = wcd938x_mbhc_register_notifier, + .micbias_enable_status = wcd938x_mbhc_micb_en_status, + .hph_pa_on_status = wcd938x_mbhc_hph_pa_on_status, + .hph_pull_up_control_v2 = wcd938x_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = wcd938x_mbhc_request_micbias, + .mbhc_micb_ramp_control = wcd938x_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = wcd938x_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = wcd938x_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = wcd938x_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = wcd938x_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = wcd938x_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = wcd938x_mbhc_moisture_config, + .mbhc_get_moisture_status = wcd938x_mbhc_get_moisture_status, + .mbhc_moisture_polling_ctrl = wcd938x_mbhc_moisture_polling_ctrl, + .mbhc_moisture_detect_en = wcd938x_mbhc_moisture_detect_en, +}; + +static int wcd938x_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd938x_mbhc *wcd938x_mbhc = wcd938x_soc_get_mbhc(component); + struct wcd_mbhc *mbhc; + + if (!wcd938x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + + mbhc = &wcd938x_mbhc->wcd_mbhc; + + ucontrol->value.integer.value[0] = (u32) mbhc->hph_type; + dev_dbg(component->dev, "%s: hph_type = %u\n", __func__, mbhc->hph_type); + + return 0; +} + +static int wcd938x_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_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd938x_mbhc *wcd938x_mbhc = wcd938x_soc_get_mbhc(component); + + if (!wcd938x_mbhc) { + dev_err(component->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(&wcd938x_mbhc->wcd_mbhc, &zl, &zr); + dev_dbg(component->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, + wcd938x_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + wcd938x_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + wcd938x_hph_impedance_get, NULL), +}; + +/* + * wcd938x_mbhc_get_impedance: get impedance of headphone + * left and right channels + * @wcd938x_mbhc: handle to struct wcd938x_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 wcd938x_mbhc_get_impedance(struct wcd938x_mbhc *wcd938x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (!wcd938x_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(&wcd938x_mbhc->wcd_mbhc, zl, zr); +} +EXPORT_SYMBOL(wcd938x_mbhc_get_impedance); + +/* + * wcd938x_mbhc_hs_detect: starts mbhc insertion/removal functionality + * @codec: handle to snd_soc_component * + * @mbhc_cfg: handle to mbhc configuration structure + * return 0 if mbhc_start is success or error code in case of failure + */ +int wcd938x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct wcd938x_priv *wcd938x = NULL; + struct wcd938x_mbhc *wcd938x_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd938x = snd_soc_component_get_drvdata(component); + if (!wcd938x) { + pr_err("%s: wcd938x is NULL\n", __func__); + return -EINVAL; + } + + wcd938x_mbhc = wcd938x->mbhc; + if (!wcd938x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + + return wcd_mbhc_start(&wcd938x_mbhc->wcd_mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(wcd938x_mbhc_hs_detect); + +/* + * wcd938x_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void wcd938x_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = NULL; + struct wcd938x_mbhc *wcd938x_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + wcd938x = snd_soc_component_get_drvdata(component); + if (!wcd938x) { + pr_err("%s: wcd938x is NULL\n", __func__); + return; + } + + wcd938x_mbhc = wcd938x->mbhc; + if (!wcd938x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", __func__); + return; + } + wcd_mbhc_stop(&wcd938x_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL(wcd938x_mbhc_hs_detect_exit); + +/* + * wcd938x_mbhc_post_ssr_init: initialize mbhc for + * wcd938x post subsystem restart + * @mbhc: poniter to wcd938x_mbhc structure + * @component: handle to snd_soc_component * + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int wcd938x_mbhc_post_ssr_init(struct wcd938x_mbhc *mbhc, + struct snd_soc_component *component) +{ + int ret = 0; + struct wcd_mbhc *wcd_mbhc = NULL; + + if (!mbhc || !component) + 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, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, WCD938X_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto done; + } + +done: + return ret; +} +EXPORT_SYMBOL(wcd938x_mbhc_post_ssr_init); + +/* + * wcd938x_mbhc_init: initialize mbhc for wcd938x + * @mbhc: poniter to wcd938x_mbhc struct pointer to store the configs + * @codec: handle to snd_soc_component * + * @fw_data: handle to firmware data + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int wcd938x_mbhc_init(struct wcd938x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + struct wcd938x_mbhc *wcd938x_mbhc = NULL; + struct wcd_mbhc *wcd_mbhc = NULL; + int ret = 0; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd938x_mbhc = devm_kzalloc(component->dev, sizeof(struct wcd938x_mbhc), + GFP_KERNEL); + if (!wcd938x_mbhc) + return -ENOMEM; + + wcd938x_mbhc->fw_data = fw_data; + BLOCKING_INIT_NOTIFIER_HEAD(&wcd938x_mbhc->notifier); + wcd_mbhc = &wcd938x_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, component, &mbhc_cb, + &intr_ids, wcd_mbhc_registers, + WCD938X_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto err; + } + + (*mbhc) = wcd938x_mbhc; + snd_soc_add_component_controls(component, impedance_detect_controls, + ARRAY_SIZE(impedance_detect_controls)); + snd_soc_add_component_controls(component, hph_type_detect_controls, + ARRAY_SIZE(hph_type_detect_controls)); + + return 0; +err: + devm_kfree(component->dev, wcd938x_mbhc); + return ret; +} +EXPORT_SYMBOL(wcd938x_mbhc_init); + +/* + * wcd938x_mbhc_deinit: deinitialize mbhc for wcd938x + * @codec: handle to snd_soc_component * + */ +void wcd938x_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x; + struct wcd938x_mbhc *wcd938x_mbhc; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + wcd938x = snd_soc_component_get_drvdata(component); + if (!wcd938x) { + pr_err("%s: wcd938x is NULL\n", __func__); + return; + } + + wcd938x_mbhc = wcd938x->mbhc; + if (wcd938x_mbhc) { + wcd_mbhc_deinit(&wcd938x_mbhc->wcd_mbhc); + devm_kfree(component->dev, wcd938x_mbhc); + } +} +EXPORT_SYMBOL(wcd938x_mbhc_deinit); diff --git a/asoc/codecs/wcd938x/wcd938x-mbhc.h b/asoc/codecs/wcd938x/wcd938x-mbhc.h new file mode 100644 index 000000000000..cf4c60e0ae6d --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x-mbhc.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ +#ifndef __WCD938X_MBHC_H__ +#define __WCD938X_MBHC_H__ +#include + +struct wcd938x_mbhc { + struct wcd_mbhc wcd_mbhc; + struct blocking_notifier_head notifier; + struct fw_info *fw_data; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD938X) +extern int wcd938x_mbhc_init(struct wcd938x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data); +extern void wcd938x_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern int wcd938x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void wcd938x_mbhc_deinit(struct snd_soc_component *component); +extern int wcd938x_mbhc_post_ssr_init(struct wcd938x_mbhc *mbhc, + struct snd_soc_component *component); +extern int wcd938x_mbhc_get_impedance(struct wcd938x_mbhc *wcd938x_mbhc, + uint32_t *zl, uint32_t *zr); +#else +static inline int wcd938x_mbhc_init(struct wcd938x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + return 0; +} +static inline void wcd938x_mbhc_hs_detect_exit( + struct snd_soc_component *component) +{ +} +static inline int wcd938x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void wcd938x_mbhc_deinit(struct snd_soc_component *component) +{ +} +static inline int wcd938x_mbhc_post_ssr_init(struct wcd938x_mbhc *mbhc, + struct snd_soc_component *component) +{ + return 0; +} + +static inline int wcd938x_mbhc_get_impedance(struct wcd938x_mbhc *wcd938x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + +#endif /* __WCD938X_MBHC_H__ */ diff --git a/asoc/codecs/wcd938x/wcd938x-registers.h b/asoc/codecs/wcd938x/wcd938x-registers.h new file mode 100644 index 000000000000..409c4139fc68 --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x-registers.h @@ -0,0 +1,502 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _WCD938X_REGISTERS_H +#define _WCD938X_REGISTERS_H + +#define WCD938X_BASE_ADDRESS 0x3000 +#define WCD938X_REG(reg) (reg - WCD938X_BASE_ADDRESS) + +enum { + REG_NO_ACCESS, + RD_REG, + WR_REG, + RD_WR_REG +}; + + +#define WCD938X_ANA_PAGE_REGISTER (WCD938X_BASE_ADDRESS + 0x0000) +#define WCD938X_ANA_BIAS (WCD938X_BASE_ADDRESS + 0x0001) +#define WCD938X_ANA_RX_SUPPLIES (WCD938X_BASE_ADDRESS + 0x0008) +#define WCD938X_ANA_HPH (WCD938X_BASE_ADDRESS + 0x0009) +#define WCD938X_ANA_EAR (WCD938X_BASE_ADDRESS + 0x000A) +#define WCD938X_ANA_EAR_COMPANDER_CTL (WCD938X_BASE_ADDRESS + 0x000B) +#define WCD938X_ANA_TX_CH1 (WCD938X_BASE_ADDRESS + 0x000E) +#define WCD938X_ANA_TX_CH2 (WCD938X_BASE_ADDRESS + 0x000F) +#define WCD938X_ANA_TX_CH3 (WCD938X_BASE_ADDRESS + 0x0010) +#define WCD938X_ANA_TX_CH4 (WCD938X_BASE_ADDRESS + 0x0011) +#define WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC (WCD938X_BASE_ADDRESS + 0x0012) +#define WCD938X_ANA_MICB3_DSP_EN_LOGIC (WCD938X_BASE_ADDRESS + 0x0013) +#define WCD938X_ANA_MBHC_MECH (WCD938X_BASE_ADDRESS + 0x0014) +#define WCD938X_ANA_MBHC_ELECT (WCD938X_BASE_ADDRESS + 0x0015) +#define WCD938X_ANA_MBHC_ZDET (WCD938X_BASE_ADDRESS + 0x0016) +#define WCD938X_ANA_MBHC_RESULT_1 (WCD938X_BASE_ADDRESS + 0x0017) +#define WCD938X_ANA_MBHC_RESULT_2 (WCD938X_BASE_ADDRESS + 0x0018) +#define WCD938X_ANA_MBHC_RESULT_3 (WCD938X_BASE_ADDRESS + 0x0019) +#define WCD938X_ANA_MBHC_BTN0 (WCD938X_BASE_ADDRESS + 0x001A) +#define WCD938X_ANA_MBHC_BTN1 (WCD938X_BASE_ADDRESS + 0x001B) +#define WCD938X_ANA_MBHC_BTN2 (WCD938X_BASE_ADDRESS + 0x001C) +#define WCD938X_ANA_MBHC_BTN3 (WCD938X_BASE_ADDRESS + 0x001D) +#define WCD938X_ANA_MBHC_BTN4 (WCD938X_BASE_ADDRESS + 0x001E) +#define WCD938X_ANA_MBHC_BTN5 (WCD938X_BASE_ADDRESS + 0x001F) +#define WCD938X_ANA_MBHC_BTN6 (WCD938X_BASE_ADDRESS + 0x0020) +#define WCD938X_ANA_MBHC_BTN7 (WCD938X_BASE_ADDRESS + 0x0021) +#define WCD938X_ANA_MICB1 (WCD938X_BASE_ADDRESS + 0x0022) +#define WCD938X_ANA_MICB2 (WCD938X_BASE_ADDRESS + 0x0023) +#define WCD938X_ANA_MICB2_RAMP (WCD938X_BASE_ADDRESS + 0x0024) +#define WCD938X_ANA_MICB3 (WCD938X_BASE_ADDRESS + 0x0025) +#define WCD938X_ANA_MICB4 (WCD938X_BASE_ADDRESS + 0x0026) +#define WCD938X_BIAS_CTL (WCD938X_BASE_ADDRESS + 0x0028) +#define WCD938X_BIAS_VBG_FINE_ADJ (WCD938X_BASE_ADDRESS + 0x0029) +#define WCD938X_LDOL_VDDCX_ADJUST (WCD938X_BASE_ADDRESS + 0x0040) +#define WCD938X_LDOL_DISABLE_LDOL (WCD938X_BASE_ADDRESS + 0x0041) +#define WCD938X_MBHC_CTL_CLK (WCD938X_BASE_ADDRESS + 0x0056) +#define WCD938X_MBHC_CTL_ANA (WCD938X_BASE_ADDRESS + 0x0057) +#define WCD938X_MBHC_CTL_SPARE_1 (WCD938X_BASE_ADDRESS + 0x0058) +#define WCD938X_MBHC_CTL_SPARE_2 (WCD938X_BASE_ADDRESS + 0x0059) +#define WCD938X_MBHC_CTL_BCS (WCD938X_BASE_ADDRESS + 0x005A) +#define WCD938X_MBHC_MOISTURE_DET_FSM_STATUS (WCD938X_BASE_ADDRESS + 0x005B) +#define WCD938X_MBHC_TEST_CTL (WCD938X_BASE_ADDRESS + 0x005C) +#define WCD938X_LDOH_MODE (WCD938X_BASE_ADDRESS + 0x0067) +#define WCD938X_LDOH_BIAS (WCD938X_BASE_ADDRESS + 0x0068) +#define WCD938X_LDOH_STB_LOADS (WCD938X_BASE_ADDRESS + 0x0069) +#define WCD938X_LDOH_SLOWRAMP (WCD938X_BASE_ADDRESS + 0x006A) +#define WCD938X_MICB1_TEST_CTL_1 (WCD938X_BASE_ADDRESS + 0x006B) +#define WCD938X_MICB1_TEST_CTL_2 (WCD938X_BASE_ADDRESS + 0x006C) +#define WCD938X_MICB1_TEST_CTL_3 (WCD938X_BASE_ADDRESS + 0x006D) +#define WCD938X_MICB2_TEST_CTL_1 (WCD938X_BASE_ADDRESS + 0x006E) +#define WCD938X_MICB2_TEST_CTL_2 (WCD938X_BASE_ADDRESS + 0x006F) +#define WCD938X_MICB2_TEST_CTL_3 (WCD938X_BASE_ADDRESS + 0x0070) +#define WCD938X_MICB3_TEST_CTL_1 (WCD938X_BASE_ADDRESS + 0x0071) +#define WCD938X_MICB3_TEST_CTL_2 (WCD938X_BASE_ADDRESS + 0x0072) +#define WCD938X_MICB3_TEST_CTL_3 (WCD938X_BASE_ADDRESS + 0x0073) +#define WCD938X_MICB4_TEST_CTL_1 (WCD938X_BASE_ADDRESS + 0x0074) +#define WCD938X_MICB4_TEST_CTL_2 (WCD938X_BASE_ADDRESS + 0x0075) +#define WCD938X_MICB4_TEST_CTL_3 (WCD938X_BASE_ADDRESS + 0x0076) +#define WCD938X_TX_COM_ADC_VCM (WCD938X_BASE_ADDRESS + 0x0077) +#define WCD938X_TX_COM_BIAS_ATEST (WCD938X_BASE_ADDRESS + 0x0078) +#define WCD938X_TX_COM_SPARE1 (WCD938X_BASE_ADDRESS + 0x0079) +#define WCD938X_TX_COM_SPARE2 (WCD938X_BASE_ADDRESS + 0x007A) +#define WCD938X_TX_COM_TXFE_DIV_CTL (WCD938X_BASE_ADDRESS + 0x007B) +#define WCD938X_TX_COM_TXFE_DIV_START (WCD938X_BASE_ADDRESS + 0x007C) +#define WCD938X_TX_COM_SPARE3 (WCD938X_BASE_ADDRESS + 0x007D) +#define WCD938X_TX_COM_SPARE4 (WCD938X_BASE_ADDRESS + 0x007E) +#define WCD938X_TX_1_2_TEST_EN (WCD938X_BASE_ADDRESS + 0x007F) +#define WCD938X_TX_1_2_ADC_IB (WCD938X_BASE_ADDRESS + 0x0080) +#define WCD938X_TX_1_2_ATEST_REFCTL (WCD938X_BASE_ADDRESS + 0x0081) +#define WCD938X_TX_1_2_TEST_CTL (WCD938X_BASE_ADDRESS + 0x0082) +#define WCD938X_TX_1_2_TEST_BLK_EN1 (WCD938X_BASE_ADDRESS + 0x0083) +#define WCD938X_TX_1_2_TXFE1_CLKDIV (WCD938X_BASE_ADDRESS + 0x0084) +#define WCD938X_TX_1_2_SAR2_ERR (WCD938X_BASE_ADDRESS + 0x0085) +#define WCD938X_TX_1_2_SAR1_ERR (WCD938X_BASE_ADDRESS + 0x0086) +#define WCD938X_TX_3_4_TEST_EN (WCD938X_BASE_ADDRESS + 0x0087) +#define WCD938X_TX_3_4_ADC_IB (WCD938X_BASE_ADDRESS + 0x0088) +#define WCD938X_TX_3_4_ATEST_REFCTL (WCD938X_BASE_ADDRESS + 0x0089) +#define WCD938X_TX_3_4_TEST_CTL (WCD938X_BASE_ADDRESS + 0x008A) +#define WCD938X_TX_3_4_TEST_BLK_EN3 (WCD938X_BASE_ADDRESS + 0x008B) +#define WCD938X_TX_3_4_TXFE3_CLKDIV (WCD938X_BASE_ADDRESS + 0x008C) +#define WCD938X_TX_3_4_SAR4_ERR (WCD938X_BASE_ADDRESS + 0x008D) +#define WCD938X_TX_3_4_SAR3_ERR (WCD938X_BASE_ADDRESS + 0x008E) +#define WCD938X_TX_3_4_TEST_BLK_EN2 (WCD938X_BASE_ADDRESS + 0x008F) +#define WCD938X_TX_3_4_TXFE2_CLKDIV (WCD938X_BASE_ADDRESS + 0x0090) +#define WCD938X_TX_3_4_SPARE1 (WCD938X_BASE_ADDRESS + 0x0091) +#define WCD938X_TX_3_4_TEST_BLK_EN4 (WCD938X_BASE_ADDRESS + 0x0092) +#define WCD938X_TX_3_4_TXFE4_CLKDIV (WCD938X_BASE_ADDRESS + 0x0093) +#define WCD938X_TX_3_4_SPARE2 (WCD938X_BASE_ADDRESS + 0x0094) +#define WCD938X_CLASSH_MODE_1 (WCD938X_BASE_ADDRESS + 0x0097) +#define WCD938X_CLASSH_MODE_2 (WCD938X_BASE_ADDRESS + 0x0098) +#define WCD938X_CLASSH_MODE_3 (WCD938X_BASE_ADDRESS + 0x0099) +#define WCD938X_CLASSH_CTRL_VCL_1 (WCD938X_BASE_ADDRESS + 0x009A) +#define WCD938X_CLASSH_CTRL_VCL_2 (WCD938X_BASE_ADDRESS + 0x009B) +#define WCD938X_CLASSH_CTRL_CCL_1 (WCD938X_BASE_ADDRESS + 0x009C) +#define WCD938X_CLASSH_CTRL_CCL_2 (WCD938X_BASE_ADDRESS + 0x009D) +#define WCD938X_CLASSH_CTRL_CCL_3 (WCD938X_BASE_ADDRESS + 0x009E) +#define WCD938X_CLASSH_CTRL_CCL_4 (WCD938X_BASE_ADDRESS + 0x009F) +#define WCD938X_CLASSH_CTRL_CCL_5 (WCD938X_BASE_ADDRESS + 0x00A0) +#define WCD938X_CLASSH_BUCK_TMUX_A_D (WCD938X_BASE_ADDRESS + 0x00A1) +#define WCD938X_CLASSH_BUCK_SW_DRV_CNTL (WCD938X_BASE_ADDRESS + 0x00A2) +#define WCD938X_CLASSH_SPARE (WCD938X_BASE_ADDRESS + 0x00A3) +#define WCD938X_FLYBACK_EN (WCD938X_BASE_ADDRESS + 0x00A4) +#define WCD938X_FLYBACK_VNEG_CTRL_1 (WCD938X_BASE_ADDRESS + 0x00A5) +#define WCD938X_FLYBACK_VNEG_CTRL_2 (WCD938X_BASE_ADDRESS + 0x00A6) +#define WCD938X_FLYBACK_VNEG_CTRL_3 (WCD938X_BASE_ADDRESS + 0x00A7) +#define WCD938X_FLYBACK_VNEG_CTRL_4 (WCD938X_BASE_ADDRESS + 0x00A8) +#define WCD938X_FLYBACK_VNEG_CTRL_5 (WCD938X_BASE_ADDRESS + 0x00A9) +#define WCD938X_FLYBACK_VNEG_CTRL_6 (WCD938X_BASE_ADDRESS + 0x00AA) +#define WCD938X_FLYBACK_VNEG_CTRL_7 (WCD938X_BASE_ADDRESS + 0x00AB) +#define WCD938X_FLYBACK_VNEG_CTRL_8 (WCD938X_BASE_ADDRESS + 0x00AC) +#define WCD938X_FLYBACK_VNEG_CTRL_9 (WCD938X_BASE_ADDRESS + 0x00AD) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_1 (WCD938X_BASE_ADDRESS + 0x00AE) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_2 (WCD938X_BASE_ADDRESS + 0x00AF) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_3 (WCD938X_BASE_ADDRESS + 0x00B0) +#define WCD938X_FLYBACK_CTRL_1 (WCD938X_BASE_ADDRESS + 0x00B1) +#define WCD938X_FLYBACK_TEST_CTL (WCD938X_BASE_ADDRESS + 0x00B2) +#define WCD938X_RX_AUX_SW_CTL (WCD938X_BASE_ADDRESS + 0x00B3) +#define WCD938X_RX_PA_AUX_IN_CONN (WCD938X_BASE_ADDRESS + 0x00B4) +#define WCD938X_RX_TIMER_DIV (WCD938X_BASE_ADDRESS + 0x00B5) +#define WCD938X_RX_OCP_CTL (WCD938X_BASE_ADDRESS + 0x00B6) +#define WCD938X_RX_OCP_COUNT (WCD938X_BASE_ADDRESS + 0x00B7) +#define WCD938X_RX_BIAS_EAR_DAC (WCD938X_BASE_ADDRESS + 0x00B8) +#define WCD938X_RX_BIAS_EAR_AMP (WCD938X_BASE_ADDRESS + 0x00B9) +#define WCD938X_RX_BIAS_HPH_LDO (WCD938X_BASE_ADDRESS + 0x00BA) +#define WCD938X_RX_BIAS_HPH_PA (WCD938X_BASE_ADDRESS + 0x00BB) +#define WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2 (WCD938X_BASE_ADDRESS + 0x00BC) +#define WCD938X_RX_BIAS_HPH_RDAC_LDO (WCD938X_BASE_ADDRESS + 0x00BD) +#define WCD938X_RX_BIAS_HPH_CNP1 (WCD938X_BASE_ADDRESS + 0x00BE) +#define WCD938X_RX_BIAS_HPH_LOWPOWER (WCD938X_BASE_ADDRESS + 0x00BF) +#define WCD938X_RX_BIAS_AUX_DAC (WCD938X_BASE_ADDRESS + 0x00C0) +#define WCD938X_RX_BIAS_AUX_AMP (WCD938X_BASE_ADDRESS + 0x00C1) +#define WCD938X_RX_BIAS_VNEGDAC_BLEEDER (WCD938X_BASE_ADDRESS + 0x00C2) +#define WCD938X_RX_BIAS_MISC (WCD938X_BASE_ADDRESS + 0x00C3) +#define WCD938X_RX_BIAS_BUCK_RST (WCD938X_BASE_ADDRESS + 0x00C4) +#define WCD938X_RX_BIAS_BUCK_VREF_ERRAMP (WCD938X_BASE_ADDRESS + 0x00C5) +#define WCD938X_RX_BIAS_FLYB_ERRAMP (WCD938X_BASE_ADDRESS + 0x00C6) +#define WCD938X_RX_BIAS_FLYB_BUFF (WCD938X_BASE_ADDRESS + 0x00C7) +#define WCD938X_RX_BIAS_FLYB_MID_RST (WCD938X_BASE_ADDRESS + 0x00C8) +#define WCD938X_HPH_L_STATUS (WCD938X_BASE_ADDRESS + 0x00C9) +#define WCD938X_HPH_R_STATUS (WCD938X_BASE_ADDRESS + 0x00CA) +#define WCD938X_HPH_CNP_EN (WCD938X_BASE_ADDRESS + 0x00CB) +#define WCD938X_HPH_CNP_WG_CTL (WCD938X_BASE_ADDRESS + 0x00CC) +#define WCD938X_HPH_CNP_WG_TIME (WCD938X_BASE_ADDRESS + 0x00CD) +#define WCD938X_HPH_OCP_CTL (WCD938X_BASE_ADDRESS + 0x00CE) +#define WCD938X_HPH_AUTO_CHOP (WCD938X_BASE_ADDRESS + 0x00CF) +#define WCD938X_HPH_CHOP_CTL (WCD938X_BASE_ADDRESS + 0x00D0) +#define WCD938X_HPH_PA_CTL1 (WCD938X_BASE_ADDRESS + 0x00D1) +#define WCD938X_HPH_PA_CTL2 (WCD938X_BASE_ADDRESS + 0x00D2) +#define WCD938X_HPH_L_EN (WCD938X_BASE_ADDRESS + 0x00D3) +#define WCD938X_HPH_L_TEST (WCD938X_BASE_ADDRESS + 0x00D4) +#define WCD938X_HPH_L_ATEST (WCD938X_BASE_ADDRESS + 0x00D5) +#define WCD938X_HPH_R_EN (WCD938X_BASE_ADDRESS + 0x00D6) +#define WCD938X_HPH_R_TEST (WCD938X_BASE_ADDRESS + 0x00D7) +#define WCD938X_HPH_R_ATEST (WCD938X_BASE_ADDRESS + 0x00D8) +#define WCD938X_HPH_RDAC_CLK_CTL1 (WCD938X_BASE_ADDRESS + 0x00D9) +#define WCD938X_HPH_RDAC_CLK_CTL2 (WCD938X_BASE_ADDRESS + 0x00DA) +#define WCD938X_HPH_RDAC_LDO_CTL (WCD938X_BASE_ADDRESS + 0x00DB) +#define WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL (WCD938X_BASE_ADDRESS + 0x00DC) +#define WCD938X_HPH_REFBUFF_UHQA_CTL (WCD938X_BASE_ADDRESS + 0x00DD) +#define WCD938X_HPH_REFBUFF_LP_CTL (WCD938X_BASE_ADDRESS + 0x00DE) +#define WCD938X_HPH_L_DAC_CTL (WCD938X_BASE_ADDRESS + 0x00DF) +#define WCD938X_HPH_R_DAC_CTL (WCD938X_BASE_ADDRESS + 0x00E0) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL (WCD938X_BASE_ADDRESS + 0x00E1) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_EN (WCD938X_BASE_ADDRESS + 0x00E2) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1 (WCD938X_BASE_ADDRESS + 0x00E3) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS (WCD938X_BASE_ADDRESS + 0x00E4) +#define WCD938X_EAR_EAR_EN_REG (WCD938X_BASE_ADDRESS + 0x00E9) +#define WCD938X_EAR_EAR_PA_CON (WCD938X_BASE_ADDRESS + 0x00EA) +#define WCD938X_EAR_EAR_SP_CON (WCD938X_BASE_ADDRESS + 0x00EB) +#define WCD938X_EAR_EAR_DAC_CON (WCD938X_BASE_ADDRESS + 0x00EC) +#define WCD938X_EAR_EAR_CNP_FSM_CON (WCD938X_BASE_ADDRESS + 0x00ED) +#define WCD938X_EAR_TEST_CTL (WCD938X_BASE_ADDRESS + 0x00EE) +#define WCD938X_EAR_STATUS_REG_1 (WCD938X_BASE_ADDRESS + 0x00EF) +#define WCD938X_EAR_STATUS_REG_2 (WCD938X_BASE_ADDRESS + 0x00F0) +#define WCD938X_ANA_NEW_PAGE_REGISTER (WCD938X_BASE_ADDRESS + 0x0100) +#define WCD938X_HPH_NEW_ANA_HPH2 (WCD938X_BASE_ADDRESS + 0x0101) +#define WCD938X_HPH_NEW_ANA_HPH3 (WCD938X_BASE_ADDRESS + 0x0102) +#define WCD938X_SLEEP_CTL (WCD938X_BASE_ADDRESS + 0x0103) +#define WCD938X_SLEEP_WATCHDOG_CTL (WCD938X_BASE_ADDRESS + 0x0104) +#define WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL (WCD938X_BASE_ADDRESS + 0x011F) +#define WCD938X_MBHC_NEW_CTL_1 (WCD938X_BASE_ADDRESS + 0x0120) +#define WCD938X_MBHC_NEW_CTL_2 (WCD938X_BASE_ADDRESS + 0x0121) +#define WCD938X_MBHC_NEW_PLUG_DETECT_CTL (WCD938X_BASE_ADDRESS + 0x0122) +#define WCD938X_MBHC_NEW_ZDET_ANA_CTL (WCD938X_BASE_ADDRESS + 0x0123) +#define WCD938X_MBHC_NEW_ZDET_RAMP_CTL (WCD938X_BASE_ADDRESS + 0x0124) +#define WCD938X_MBHC_NEW_FSM_STATUS (WCD938X_BASE_ADDRESS + 0x0125) +#define WCD938X_MBHC_NEW_ADC_RESULT (WCD938X_BASE_ADDRESS + 0x0126) +#define WCD938X_TX_NEW_AMIC_MUX_CFG (WCD938X_BASE_ADDRESS + 0x0127) +#define WCD938X_AUX_AUXPA (WCD938X_BASE_ADDRESS + 0x0128) +#define WCD938X_LDORXTX_MODE (WCD938X_BASE_ADDRESS + 0x0129) +#define WCD938X_LDORXTX_CONFIG (WCD938X_BASE_ADDRESS + 0x012A) +#define WCD938X_DIE_CRACK_DIE_CRK_DET_EN (WCD938X_BASE_ADDRESS + 0x012C) +#define WCD938X_DIE_CRACK_DIE_CRK_DET_OUT (WCD938X_BASE_ADDRESS + 0x012D) +#define WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL (WCD938X_BASE_ADDRESS + 0x0132) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L (WCD938X_BASE_ADDRESS + 0x0133) +#define WCD938X_HPH_NEW_INT_RDAC_VREF_CTL (WCD938X_BASE_ADDRESS + 0x0134) +#define WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL (WCD938X_BASE_ADDRESS + 0x0135) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R (WCD938X_BASE_ADDRESS + 0x0136) +#define WCD938X_HPH_NEW_INT_PA_MISC1 (WCD938X_BASE_ADDRESS + 0x0137) +#define WCD938X_HPH_NEW_INT_PA_MISC2 (WCD938X_BASE_ADDRESS + 0x0138) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC (WCD938X_BASE_ADDRESS + 0x0139) +#define WCD938X_HPH_NEW_INT_HPH_TIMER1 (WCD938X_BASE_ADDRESS + 0x013A) +#define WCD938X_HPH_NEW_INT_HPH_TIMER2 (WCD938X_BASE_ADDRESS + 0x013B) +#define WCD938X_HPH_NEW_INT_HPH_TIMER3 (WCD938X_BASE_ADDRESS + 0x013C) +#define WCD938X_HPH_NEW_INT_HPH_TIMER4 (WCD938X_BASE_ADDRESS + 0x013D) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC2 (WCD938X_BASE_ADDRESS + 0x013E) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC3 (WCD938X_BASE_ADDRESS + 0x013F) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW (WCD938X_BASE_ADDRESS + 0x0140) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW (WCD938X_BASE_ADDRESS + 0x0141) +#define WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (WCD938X_BASE_ADDRESS + 0x0145) +#define WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP (WCD938X_BASE_ADDRESS + 0x0146) +#define WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP (WCD938X_BASE_ADDRESS + 0x0147) +#define WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL \ + (WCD938X_BASE_ADDRESS + 0x01AF) +#define WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL \ + (WCD938X_BASE_ADDRESS + 0x01B0) +#define WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT (WCD938X_BASE_ADDRESS + 0x01B1) +#define WCD938X_MBHC_NEW_INT_SPARE_2 (WCD938X_BASE_ADDRESS + 0x01B2) +#define WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON (WCD938X_BASE_ADDRESS + 0x01B7) +#define WCD938X_EAR_INT_NEW_CNP_VCM_CON1 (WCD938X_BASE_ADDRESS + 0x01B8) +#define WCD938X_EAR_INT_NEW_CNP_VCM_CON2 (WCD938X_BASE_ADDRESS + 0x01B9) +#define WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS (WCD938X_BASE_ADDRESS + 0x01BA) +#define WCD938X_AUX_INT_EN_REG (WCD938X_BASE_ADDRESS + 0x01BD) +#define WCD938X_AUX_INT_PA_CTRL (WCD938X_BASE_ADDRESS + 0x01BE) +#define WCD938X_AUX_INT_SP_CTRL (WCD938X_BASE_ADDRESS + 0x01BF) +#define WCD938X_AUX_INT_DAC_CTRL (WCD938X_BASE_ADDRESS + 0x01C0) +#define WCD938X_AUX_INT_CLK_CTRL (WCD938X_BASE_ADDRESS + 0x01C1) +#define WCD938X_AUX_INT_TEST_CTRL (WCD938X_BASE_ADDRESS + 0x01C2) +#define WCD938X_AUX_INT_STATUS_REG (WCD938X_BASE_ADDRESS + 0x01C3) +#define WCD938X_AUX_INT_MISC (WCD938X_BASE_ADDRESS + 0x01C4) +#define WCD938X_LDORXTX_INT_BIAS (WCD938X_BASE_ADDRESS + 0x01C5) +#define WCD938X_LDORXTX_INT_STB_LOADS_DTEST (WCD938X_BASE_ADDRESS + 0x01C6) +#define WCD938X_LDORXTX_INT_TEST0 (WCD938X_BASE_ADDRESS + 0x01C7) +#define WCD938X_LDORXTX_INT_STARTUP_TIMER (WCD938X_BASE_ADDRESS + 0x01C8) +#define WCD938X_LDORXTX_INT_TEST1 (WCD938X_BASE_ADDRESS + 0x01C9) +#define WCD938X_LDORXTX_INT_STATUS (WCD938X_BASE_ADDRESS + 0x01CA) +#define WCD938X_SLEEP_INT_WATCHDOG_CTL_1 (WCD938X_BASE_ADDRESS + 0x01D0) +#define WCD938X_SLEEP_INT_WATCHDOG_CTL_2 (WCD938X_BASE_ADDRESS + 0x01D1) +#define WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1 (WCD938X_BASE_ADDRESS + 0x01D3) +#define WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2 (WCD938X_BASE_ADDRESS + 0x01D4) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2 (WCD938X_BASE_ADDRESS + 0x01D5) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1 (WCD938X_BASE_ADDRESS + 0x01D6) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0 (WCD938X_BASE_ADDRESS + 0x01D7) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M \ + (WCD938X_BASE_ADDRESS + 0x01D8) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M \ + (WCD938X_BASE_ADDRESS + 0x01D9) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1 \ + (WCD938X_BASE_ADDRESS + 0x01DA) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0 \ + (WCD938X_BASE_ADDRESS + 0x01DB) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP \ + (WCD938X_BASE_ADDRESS + 0x01DC) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1 \ + (WCD938X_BASE_ADDRESS + 0x01DD) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0 \ + (WCD938X_BASE_ADDRESS + 0x01DE) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP \ + (WCD938X_BASE_ADDRESS + 0x01DF) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0 \ + (WCD938X_BASE_ADDRESS + 0x01E0) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP \ + (WCD938X_BASE_ADDRESS + 0x01E1) +#define WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1 \ + (WCD938X_BASE_ADDRESS + 0x01E2) +#define WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP \ + (WCD938X_BASE_ADDRESS + 0x01E3) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L2 (WCD938X_BASE_ADDRESS + 0x01E4) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L1 (WCD938X_BASE_ADDRESS + 0x01E5) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L0 (WCD938X_BASE_ADDRESS + 0x01E6) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP (WCD938X_BASE_ADDRESS + 0x01E7) +#define WCD938X_DIGITAL_PAGE_REGISTER (WCD938X_BASE_ADDRESS + 0x0400) +#define WCD938X_DIGITAL_CHIP_ID0 (WCD938X_BASE_ADDRESS + 0x0401) +#define WCD938X_DIGITAL_CHIP_ID1 (WCD938X_BASE_ADDRESS + 0x0402) +#define WCD938X_DIGITAL_CHIP_ID2 (WCD938X_BASE_ADDRESS + 0x0403) +#define WCD938X_DIGITAL_CHIP_ID3 (WCD938X_BASE_ADDRESS + 0x0404) +#define WCD938X_DIGITAL_SWR_TX_CLK_RATE (WCD938X_BASE_ADDRESS + 0x0405) +#define WCD938X_DIGITAL_CDC_RST_CTL (WCD938X_BASE_ADDRESS + 0x0406) +#define WCD938X_DIGITAL_TOP_CLK_CFG (WCD938X_BASE_ADDRESS + 0x0407) +#define WCD938X_DIGITAL_CDC_ANA_CLK_CTL (WCD938X_BASE_ADDRESS + 0x0408) +#define WCD938X_DIGITAL_CDC_DIG_CLK_CTL (WCD938X_BASE_ADDRESS + 0x0409) +#define WCD938X_DIGITAL_SWR_RST_EN (WCD938X_BASE_ADDRESS + 0x040A) +#define WCD938X_DIGITAL_CDC_PATH_MODE (WCD938X_BASE_ADDRESS + 0x040B) +#define WCD938X_DIGITAL_CDC_RX_RST (WCD938X_BASE_ADDRESS + 0x040C) +#define WCD938X_DIGITAL_CDC_RX0_CTL (WCD938X_BASE_ADDRESS + 0x040D) +#define WCD938X_DIGITAL_CDC_RX1_CTL (WCD938X_BASE_ADDRESS + 0x040E) +#define WCD938X_DIGITAL_CDC_RX2_CTL (WCD938X_BASE_ADDRESS + 0x040F) +#define WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1 (WCD938X_BASE_ADDRESS + 0x0410) +#define WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3 (WCD938X_BASE_ADDRESS + 0x0411) +#define WCD938X_DIGITAL_CDC_COMP_CTL_0 (WCD938X_BASE_ADDRESS + 0x0414) +#define WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL (WCD938X_BASE_ADDRESS + 0x0417) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A1_0 (WCD938X_BASE_ADDRESS + 0x0418) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A1_1 (WCD938X_BASE_ADDRESS + 0x0419) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A2_0 (WCD938X_BASE_ADDRESS + 0x041A) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A2_1 (WCD938X_BASE_ADDRESS + 0x041B) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A3_0 (WCD938X_BASE_ADDRESS + 0x041C) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A3_1 (WCD938X_BASE_ADDRESS + 0x041D) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A4_0 (WCD938X_BASE_ADDRESS + 0x041E) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A4_1 (WCD938X_BASE_ADDRESS + 0x041F) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A5_0 (WCD938X_BASE_ADDRESS + 0x0420) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A5_1 (WCD938X_BASE_ADDRESS + 0x0421) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A6_0 (WCD938X_BASE_ADDRESS + 0x0422) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A7_0 (WCD938X_BASE_ADDRESS + 0x0423) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_0 (WCD938X_BASE_ADDRESS + 0x0424) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_1 (WCD938X_BASE_ADDRESS + 0x0425) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_2 (WCD938X_BASE_ADDRESS + 0x0426) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_3 (WCD938X_BASE_ADDRESS + 0x0427) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R1 (WCD938X_BASE_ADDRESS + 0x0428) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R2 (WCD938X_BASE_ADDRESS + 0x0429) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R3 (WCD938X_BASE_ADDRESS + 0x042A) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R4 (WCD938X_BASE_ADDRESS + 0x042B) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R5 (WCD938X_BASE_ADDRESS + 0x042C) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R6 (WCD938X_BASE_ADDRESS + 0x042D) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R7 (WCD938X_BASE_ADDRESS + 0x042E) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A1_0 (WCD938X_BASE_ADDRESS + 0x042F) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A1_1 (WCD938X_BASE_ADDRESS + 0x0430) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A2_0 (WCD938X_BASE_ADDRESS + 0x0431) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A2_1 (WCD938X_BASE_ADDRESS + 0x0432) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A3_0 (WCD938X_BASE_ADDRESS + 0x0433) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A3_1 (WCD938X_BASE_ADDRESS + 0x0434) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A4_0 (WCD938X_BASE_ADDRESS + 0x0435) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A4_1 (WCD938X_BASE_ADDRESS + 0x0436) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A5_0 (WCD938X_BASE_ADDRESS + 0x0437) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A5_1 (WCD938X_BASE_ADDRESS + 0x0438) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A6_0 (WCD938X_BASE_ADDRESS + 0x0439) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A7_0 (WCD938X_BASE_ADDRESS + 0x043A) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_0 (WCD938X_BASE_ADDRESS + 0x043B) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_1 (WCD938X_BASE_ADDRESS + 0x043C) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_2 (WCD938X_BASE_ADDRESS + 0x043D) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_3 (WCD938X_BASE_ADDRESS + 0x043E) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R1 (WCD938X_BASE_ADDRESS + 0x043F) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R2 (WCD938X_BASE_ADDRESS + 0x0440) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R3 (WCD938X_BASE_ADDRESS + 0x0441) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R4 (WCD938X_BASE_ADDRESS + 0x0442) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R5 (WCD938X_BASE_ADDRESS + 0x0443) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R6 (WCD938X_BASE_ADDRESS + 0x0444) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R7 (WCD938X_BASE_ADDRESS + 0x0445) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0 (WCD938X_BASE_ADDRESS + 0x0446) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1 (WCD938X_BASE_ADDRESS + 0x0447) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0 (WCD938X_BASE_ADDRESS + 0x0448) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1 (WCD938X_BASE_ADDRESS + 0x0449) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2 (WCD938X_BASE_ADDRESS + 0x044A) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0 (WCD938X_BASE_ADDRESS + 0x044B) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1 (WCD938X_BASE_ADDRESS + 0x044C) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2 (WCD938X_BASE_ADDRESS + 0x044D) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_CTL (WCD938X_BASE_ADDRESS + 0x044E) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_CTL (WCD938X_BASE_ADDRESS + 0x044F) +#define WCD938X_DIGITAL_CDC_EAR_PATH_CTL (WCD938X_BASE_ADDRESS + 0x0450) +#define WCD938X_DIGITAL_CDC_SWR_CLH (WCD938X_BASE_ADDRESS + 0x0451) +#define WCD938X_DIGITAL_SWR_CLH_BYP (WCD938X_BASE_ADDRESS + 0x0452) +#define WCD938X_DIGITAL_CDC_TX0_CTL (WCD938X_BASE_ADDRESS + 0x0453) +#define WCD938X_DIGITAL_CDC_TX1_CTL (WCD938X_BASE_ADDRESS + 0x0454) +#define WCD938X_DIGITAL_CDC_TX2_CTL (WCD938X_BASE_ADDRESS + 0x0455) +#define WCD938X_DIGITAL_CDC_TX_RST (WCD938X_BASE_ADDRESS + 0x0456) +#define WCD938X_DIGITAL_CDC_REQ_CTL (WCD938X_BASE_ADDRESS + 0x0457) +#define WCD938X_DIGITAL_CDC_RST (WCD938X_BASE_ADDRESS + 0x0458) +#define WCD938X_DIGITAL_CDC_AMIC_CTL (WCD938X_BASE_ADDRESS + 0x045A) +#define WCD938X_DIGITAL_CDC_DMIC_CTL (WCD938X_BASE_ADDRESS + 0x045B) +#define WCD938X_DIGITAL_CDC_DMIC1_CTL (WCD938X_BASE_ADDRESS + 0x045C) +#define WCD938X_DIGITAL_CDC_DMIC2_CTL (WCD938X_BASE_ADDRESS + 0x045D) +#define WCD938X_DIGITAL_CDC_DMIC3_CTL (WCD938X_BASE_ADDRESS + 0x045E) +#define WCD938X_DIGITAL_CDC_DMIC4_CTL (WCD938X_BASE_ADDRESS + 0x045F) +#define WCD938X_DIGITAL_EFUSE_PRG_CTL (WCD938X_BASE_ADDRESS + 0x0460) +#define WCD938X_DIGITAL_EFUSE_CTL (WCD938X_BASE_ADDRESS + 0x0461) +#define WCD938X_DIGITAL_CDC_DMIC_RATE_1_2 (WCD938X_BASE_ADDRESS + 0x0462) +#define WCD938X_DIGITAL_CDC_DMIC_RATE_3_4 (WCD938X_BASE_ADDRESS + 0x0463) +#define WCD938X_DIGITAL_PDM_WD_CTL0 (WCD938X_BASE_ADDRESS + 0x0465) +#define WCD938X_DIGITAL_PDM_WD_CTL1 (WCD938X_BASE_ADDRESS + 0x0466) +#define WCD938X_DIGITAL_PDM_WD_CTL2 (WCD938X_BASE_ADDRESS + 0x0467) +#define WCD938X_DIGITAL_INTR_MODE (WCD938X_BASE_ADDRESS + 0x046A) +#define WCD938X_DIGITAL_INTR_MASK_0 (WCD938X_BASE_ADDRESS + 0x046B) +#define WCD938X_DIGITAL_INTR_MASK_1 (WCD938X_BASE_ADDRESS + 0x046C) +#define WCD938X_DIGITAL_INTR_MASK_2 (WCD938X_BASE_ADDRESS + 0x046D) +#define WCD938X_DIGITAL_INTR_STATUS_0 (WCD938X_BASE_ADDRESS + 0x046E) +#define WCD938X_DIGITAL_INTR_STATUS_1 (WCD938X_BASE_ADDRESS + 0x046F) +#define WCD938X_DIGITAL_INTR_STATUS_2 (WCD938X_BASE_ADDRESS + 0x0470) +#define WCD938X_DIGITAL_INTR_CLEAR_0 (WCD938X_BASE_ADDRESS + 0x0471) +#define WCD938X_DIGITAL_INTR_CLEAR_1 (WCD938X_BASE_ADDRESS + 0x0472) +#define WCD938X_DIGITAL_INTR_CLEAR_2 (WCD938X_BASE_ADDRESS + 0x0473) +#define WCD938X_DIGITAL_INTR_LEVEL_0 (WCD938X_BASE_ADDRESS + 0x0474) +#define WCD938X_DIGITAL_INTR_LEVEL_1 (WCD938X_BASE_ADDRESS + 0x0475) +#define WCD938X_DIGITAL_INTR_LEVEL_2 (WCD938X_BASE_ADDRESS + 0x0476) +#define WCD938X_DIGITAL_INTR_SET_0 (WCD938X_BASE_ADDRESS + 0x0477) +#define WCD938X_DIGITAL_INTR_SET_1 (WCD938X_BASE_ADDRESS + 0x0478) +#define WCD938X_DIGITAL_INTR_SET_2 (WCD938X_BASE_ADDRESS + 0x0479) +#define WCD938X_DIGITAL_INTR_TEST_0 (WCD938X_BASE_ADDRESS + 0x047A) +#define WCD938X_DIGITAL_INTR_TEST_1 (WCD938X_BASE_ADDRESS + 0x047B) +#define WCD938X_DIGITAL_INTR_TEST_2 (WCD938X_BASE_ADDRESS + 0x047C) +#define WCD938X_DIGITAL_TX_MODE_DBG_EN (WCD938X_BASE_ADDRESS + 0x047F) +#define WCD938X_DIGITAL_TX_MODE_DBG_0_1 (WCD938X_BASE_ADDRESS + 0x0480) +#define WCD938X_DIGITAL_TX_MODE_DBG_2_3 (WCD938X_BASE_ADDRESS + 0x0481) +#define WCD938X_DIGITAL_LB_IN_SEL_CTL (WCD938X_BASE_ADDRESS + 0x0482) +#define WCD938X_DIGITAL_LOOP_BACK_MODE (WCD938X_BASE_ADDRESS + 0x0483) +#define WCD938X_DIGITAL_SWR_DAC_TEST (WCD938X_BASE_ADDRESS + 0x0484) +#define WCD938X_DIGITAL_SWR_HM_TEST_RX_0 (WCD938X_BASE_ADDRESS + 0x0485) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_0 (WCD938X_BASE_ADDRESS + 0x0486) +#define WCD938X_DIGITAL_SWR_HM_TEST_RX_1 (WCD938X_BASE_ADDRESS + 0x0487) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_1 (WCD938X_BASE_ADDRESS + 0x0488) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_2 (WCD938X_BASE_ADDRESS + 0x0489) +#define WCD938X_DIGITAL_SWR_HM_TEST_0 (WCD938X_BASE_ADDRESS + 0x048A) +#define WCD938X_DIGITAL_SWR_HM_TEST_1 (WCD938X_BASE_ADDRESS + 0x048B) +#define WCD938X_DIGITAL_PAD_CTL_SWR_0 (WCD938X_BASE_ADDRESS + 0x048C) +#define WCD938X_DIGITAL_PAD_CTL_SWR_1 (WCD938X_BASE_ADDRESS + 0x048D) +#define WCD938X_DIGITAL_I2C_CTL (WCD938X_BASE_ADDRESS + 0x048E) +#define WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE (WCD938X_BASE_ADDRESS + 0x048F) +#define WCD938X_DIGITAL_EFUSE_TEST_CTL_0 (WCD938X_BASE_ADDRESS + 0x0490) +#define WCD938X_DIGITAL_EFUSE_TEST_CTL_1 (WCD938X_BASE_ADDRESS + 0x0491) +#define WCD938X_DIGITAL_EFUSE_T_DATA_0 (WCD938X_BASE_ADDRESS + 0x0492) +#define WCD938X_DIGITAL_EFUSE_T_DATA_1 (WCD938X_BASE_ADDRESS + 0x0493) +#define WCD938X_DIGITAL_PAD_CTL_PDM_RX0 (WCD938X_BASE_ADDRESS + 0x0494) +#define WCD938X_DIGITAL_PAD_CTL_PDM_RX1 (WCD938X_BASE_ADDRESS + 0x0495) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX0 (WCD938X_BASE_ADDRESS + 0x0496) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX1 (WCD938X_BASE_ADDRESS + 0x0497) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX2 (WCD938X_BASE_ADDRESS + 0x0498) +#define WCD938X_DIGITAL_PAD_INP_DIS_0 (WCD938X_BASE_ADDRESS + 0x0499) +#define WCD938X_DIGITAL_PAD_INP_DIS_1 (WCD938X_BASE_ADDRESS + 0x049A) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_0 (WCD938X_BASE_ADDRESS + 0x049B) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_1 (WCD938X_BASE_ADDRESS + 0x049C) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_2 (WCD938X_BASE_ADDRESS + 0x049D) +#define WCD938X_DIGITAL_RX_DATA_EDGE_CTL (WCD938X_BASE_ADDRESS + 0x049E) +#define WCD938X_DIGITAL_TX_DATA_EDGE_CTL (WCD938X_BASE_ADDRESS + 0x049F) +#define WCD938X_DIGITAL_GPIO_MODE (WCD938X_BASE_ADDRESS + 0x04A0) +#define WCD938X_DIGITAL_PIN_CTL_OE (WCD938X_BASE_ADDRESS + 0x04A1) +#define WCD938X_DIGITAL_PIN_CTL_DATA_0 (WCD938X_BASE_ADDRESS + 0x04A2) +#define WCD938X_DIGITAL_PIN_CTL_DATA_1 (WCD938X_BASE_ADDRESS + 0x04A3) +#define WCD938X_DIGITAL_PIN_STATUS_0 (WCD938X_BASE_ADDRESS + 0x04A4) +#define WCD938X_DIGITAL_PIN_STATUS_1 (WCD938X_BASE_ADDRESS + 0x04A5) +#define WCD938X_DIGITAL_DIG_DEBUG_CTL (WCD938X_BASE_ADDRESS + 0x04A6) +#define WCD938X_DIGITAL_DIG_DEBUG_EN (WCD938X_BASE_ADDRESS + 0x04A7) +#define WCD938X_DIGITAL_ANA_CSR_DBG_ADD (WCD938X_BASE_ADDRESS + 0x04A8) +#define WCD938X_DIGITAL_ANA_CSR_DBG_CTL (WCD938X_BASE_ADDRESS + 0x04A9) +#define WCD938X_DIGITAL_SSP_DBG (WCD938X_BASE_ADDRESS + 0x04AA) +#define WCD938X_DIGITAL_MODE_STATUS_0 (WCD938X_BASE_ADDRESS + 0x04AB) +#define WCD938X_DIGITAL_MODE_STATUS_1 (WCD938X_BASE_ADDRESS + 0x04AC) +#define WCD938X_DIGITAL_SPARE_0 (WCD938X_BASE_ADDRESS + 0x04AD) +#define WCD938X_DIGITAL_SPARE_1 (WCD938X_BASE_ADDRESS + 0x04AE) +#define WCD938X_DIGITAL_SPARE_2 (WCD938X_BASE_ADDRESS + 0x04AF) +#define WCD938X_DIGITAL_EFUSE_REG_0 (WCD938X_BASE_ADDRESS + 0x04B0) +#define WCD938X_DIGITAL_EFUSE_REG_1 (WCD938X_BASE_ADDRESS + 0x04B1) +#define WCD938X_DIGITAL_EFUSE_REG_2 (WCD938X_BASE_ADDRESS + 0x04B2) +#define WCD938X_DIGITAL_EFUSE_REG_3 (WCD938X_BASE_ADDRESS + 0x04B3) +#define WCD938X_DIGITAL_EFUSE_REG_4 (WCD938X_BASE_ADDRESS + 0x04B4) +#define WCD938X_DIGITAL_EFUSE_REG_5 (WCD938X_BASE_ADDRESS + 0x04B5) +#define WCD938X_DIGITAL_EFUSE_REG_6 (WCD938X_BASE_ADDRESS + 0x04B6) +#define WCD938X_DIGITAL_EFUSE_REG_7 (WCD938X_BASE_ADDRESS + 0x04B7) +#define WCD938X_DIGITAL_EFUSE_REG_8 (WCD938X_BASE_ADDRESS + 0x04B8) +#define WCD938X_DIGITAL_EFUSE_REG_9 (WCD938X_BASE_ADDRESS + 0x04B9) +#define WCD938X_DIGITAL_EFUSE_REG_10 (WCD938X_BASE_ADDRESS + 0x04BA) +#define WCD938X_DIGITAL_EFUSE_REG_11 (WCD938X_BASE_ADDRESS + 0x04BB) +#define WCD938X_DIGITAL_EFUSE_REG_12 (WCD938X_BASE_ADDRESS + 0x04BC) +#define WCD938X_DIGITAL_EFUSE_REG_13 (WCD938X_BASE_ADDRESS + 0x04BD) +#define WCD938X_DIGITAL_EFUSE_REG_14 (WCD938X_BASE_ADDRESS + 0x04BE) +#define WCD938X_DIGITAL_EFUSE_REG_15 (WCD938X_BASE_ADDRESS + 0x04BF) +#define WCD938X_DIGITAL_EFUSE_REG_16 (WCD938X_BASE_ADDRESS + 0x04C0) +#define WCD938X_DIGITAL_EFUSE_REG_17 (WCD938X_BASE_ADDRESS + 0x04C1) +#define WCD938X_DIGITAL_EFUSE_REG_18 (WCD938X_BASE_ADDRESS + 0x04C2) +#define WCD938X_DIGITAL_EFUSE_REG_19 (WCD938X_BASE_ADDRESS + 0x04C3) +#define WCD938X_DIGITAL_EFUSE_REG_20 (WCD938X_BASE_ADDRESS + 0x04C4) +#define WCD938X_DIGITAL_EFUSE_REG_21 (WCD938X_BASE_ADDRESS + 0x04C5) +#define WCD938X_DIGITAL_EFUSE_REG_22 (WCD938X_BASE_ADDRESS + 0x04C6) +#define WCD938X_DIGITAL_EFUSE_REG_23 (WCD938X_BASE_ADDRESS + 0x04C7) +#define WCD938X_DIGITAL_EFUSE_REG_24 (WCD938X_BASE_ADDRESS + 0x04C8) +#define WCD938X_DIGITAL_EFUSE_REG_25 (WCD938X_BASE_ADDRESS + 0x04C9) +#define WCD938X_DIGITAL_EFUSE_REG_26 (WCD938X_BASE_ADDRESS + 0x04CA) +#define WCD938X_DIGITAL_EFUSE_REG_27 (WCD938X_BASE_ADDRESS + 0x04CB) +#define WCD938X_DIGITAL_EFUSE_REG_28 (WCD938X_BASE_ADDRESS + 0x04CC) +#define WCD938X_DIGITAL_EFUSE_REG_29 (WCD938X_BASE_ADDRESS + 0x04CD) +#define WCD938X_DIGITAL_EFUSE_REG_30 (WCD938X_BASE_ADDRESS + 0x04CE) +#define WCD938X_DIGITAL_EFUSE_REG_31 (WCD938X_BASE_ADDRESS + 0x04CF) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_0 (WCD938X_BASE_ADDRESS + 0x04D0) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_1 (WCD938X_BASE_ADDRESS + 0x04D1) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_2 (WCD938X_BASE_ADDRESS + 0x04D2) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_3 (WCD938X_BASE_ADDRESS + 0x04D3) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_4 (WCD938X_BASE_ADDRESS + 0x04D4) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA0 (WCD938X_BASE_ADDRESS + 0x04D5) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA1 (WCD938X_BASE_ADDRESS + 0x04D6) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA2 (WCD938X_BASE_ADDRESS + 0x04D7) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA3 (WCD938X_BASE_ADDRESS + 0x04D8) + +#define WCD938X_REGISTERS_MAX_SIZE (WCD938X_DIGITAL_DEM_BYPASS_DATA3 + 1) +#define WCD938X_MAX_REGISTER (WCD938X_REGISTERS_MAX_SIZE - 1) + +#endif /*_WCD938X_REGISTERS_H*/ diff --git a/asoc/codecs/wcd938x/wcd938x-regmap.c b/asoc/codecs/wcd938x/wcd938x-regmap.c new file mode 100644 index 000000000000..a06f97532d8d --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x-regmap.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "wcd938x-registers.h" + +extern const u8 wcd938x_reg_access[WCD938X_REGISTERS_MAX_SIZE]; + +static const struct reg_default wcd938x_defaults[] = { + {WCD938X_ANA_PAGE_REGISTER, 0x00}, + {WCD938X_ANA_BIAS, 0x00}, + {WCD938X_ANA_RX_SUPPLIES, 0x00}, + {WCD938X_ANA_HPH, 0x0C}, + {WCD938X_ANA_EAR, 0x00}, + {WCD938X_ANA_EAR_COMPANDER_CTL, 0x02}, + {WCD938X_ANA_TX_CH1, 0x20}, + {WCD938X_ANA_TX_CH2, 0x00}, + {WCD938X_ANA_TX_CH3, 0x20}, + {WCD938X_ANA_TX_CH4, 0x00}, + {WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00}, + {WCD938X_ANA_MICB3_DSP_EN_LOGIC, 0x00}, + {WCD938X_ANA_MBHC_MECH, 0x39}, + {WCD938X_ANA_MBHC_ELECT, 0x08}, + {WCD938X_ANA_MBHC_ZDET, 0x00}, + {WCD938X_ANA_MBHC_RESULT_1, 0x00}, + {WCD938X_ANA_MBHC_RESULT_2, 0x00}, + {WCD938X_ANA_MBHC_RESULT_3, 0x00}, + {WCD938X_ANA_MBHC_BTN0, 0x00}, + {WCD938X_ANA_MBHC_BTN1, 0x10}, + {WCD938X_ANA_MBHC_BTN2, 0x20}, + {WCD938X_ANA_MBHC_BTN3, 0x30}, + {WCD938X_ANA_MBHC_BTN4, 0x40}, + {WCD938X_ANA_MBHC_BTN5, 0x50}, + {WCD938X_ANA_MBHC_BTN6, 0x60}, + {WCD938X_ANA_MBHC_BTN7, 0x70}, + {WCD938X_ANA_MICB1, 0x10}, + {WCD938X_ANA_MICB2, 0x10}, + {WCD938X_ANA_MICB2_RAMP, 0x00}, + {WCD938X_ANA_MICB3, 0x10}, + {WCD938X_ANA_MICB4, 0x10}, + {WCD938X_BIAS_CTL, 0x2A}, + {WCD938X_BIAS_VBG_FINE_ADJ, 0x55}, + {WCD938X_LDOL_VDDCX_ADJUST, 0x01}, + {WCD938X_LDOL_DISABLE_LDOL, 0x00}, + {WCD938X_MBHC_CTL_CLK, 0x00}, + {WCD938X_MBHC_CTL_ANA, 0x00}, + {WCD938X_MBHC_CTL_SPARE_1, 0x00}, + {WCD938X_MBHC_CTL_SPARE_2, 0x00}, + {WCD938X_MBHC_CTL_BCS, 0x00}, + {WCD938X_MBHC_MOISTURE_DET_FSM_STATUS, 0x00}, + {WCD938X_MBHC_TEST_CTL, 0x00}, + {WCD938X_LDOH_MODE, 0x2B}, + {WCD938X_LDOH_BIAS, 0x68}, + {WCD938X_LDOH_STB_LOADS, 0x00}, + {WCD938X_LDOH_SLOWRAMP, 0x50}, + {WCD938X_MICB1_TEST_CTL_1, 0x1A}, + {WCD938X_MICB1_TEST_CTL_2, 0x00}, + {WCD938X_MICB1_TEST_CTL_3, 0xA4}, + {WCD938X_MICB2_TEST_CTL_1, 0x1A}, + {WCD938X_MICB2_TEST_CTL_2, 0x00}, + {WCD938X_MICB2_TEST_CTL_3, 0x24}, + {WCD938X_MICB3_TEST_CTL_1, 0x1A}, + {WCD938X_MICB3_TEST_CTL_2, 0x00}, + {WCD938X_MICB3_TEST_CTL_3, 0xA4}, + {WCD938X_MICB4_TEST_CTL_1, 0x1A}, + {WCD938X_MICB4_TEST_CTL_2, 0x00}, + {WCD938X_MICB4_TEST_CTL_3, 0xA4}, + {WCD938X_TX_COM_ADC_VCM, 0x39}, + {WCD938X_TX_COM_BIAS_ATEST, 0xE0}, + {WCD938X_TX_COM_SPARE1, 0x00}, + {WCD938X_TX_COM_SPARE2, 0x00}, + {WCD938X_TX_COM_TXFE_DIV_CTL, 0x22}, + {WCD938X_TX_COM_TXFE_DIV_START, 0x00}, + {WCD938X_TX_COM_SPARE3, 0x00}, + {WCD938X_TX_COM_SPARE4, 0x00}, + {WCD938X_TX_1_2_TEST_EN, 0xCC}, + {WCD938X_TX_1_2_ADC_IB, 0xE9}, + {WCD938X_TX_1_2_ATEST_REFCTL, 0x0A}, + {WCD938X_TX_1_2_TEST_CTL, 0x38}, + {WCD938X_TX_1_2_TEST_BLK_EN1, 0xFF}, + {WCD938X_TX_1_2_TXFE1_CLKDIV, 0x00}, + {WCD938X_TX_1_2_SAR2_ERR, 0x00}, + {WCD938X_TX_1_2_SAR1_ERR, 0x00}, + {WCD938X_TX_3_4_TEST_EN, 0xCC}, + {WCD938X_TX_3_4_ADC_IB, 0xE9}, + {WCD938X_TX_3_4_ATEST_REFCTL, 0x0A}, + {WCD938X_TX_3_4_TEST_CTL, 0x38}, + {WCD938X_TX_3_4_TEST_BLK_EN3, 0xFF}, + {WCD938X_TX_3_4_TXFE3_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SAR4_ERR, 0x00}, + {WCD938X_TX_3_4_SAR3_ERR, 0x00}, + {WCD938X_TX_3_4_TEST_BLK_EN2, 0xFB}, + {WCD938X_TX_3_4_TXFE2_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SPARE1, 0x00}, + {WCD938X_TX_3_4_TEST_BLK_EN4, 0xFB}, + {WCD938X_TX_3_4_TXFE4_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SPARE2, 0x00}, + {WCD938X_CLASSH_MODE_1, 0x40}, + {WCD938X_CLASSH_MODE_2, 0x3A}, + {WCD938X_CLASSH_MODE_3, 0x00}, + {WCD938X_CLASSH_CTRL_VCL_1, 0x70}, + {WCD938X_CLASSH_CTRL_VCL_2, 0x82}, + {WCD938X_CLASSH_CTRL_CCL_1, 0x31}, + {WCD938X_CLASSH_CTRL_CCL_2, 0x80}, + {WCD938X_CLASSH_CTRL_CCL_3, 0x80}, + {WCD938X_CLASSH_CTRL_CCL_4, 0x51}, + {WCD938X_CLASSH_CTRL_CCL_5, 0x00}, + {WCD938X_CLASSH_BUCK_TMUX_A_D, 0x00}, + {WCD938X_CLASSH_BUCK_SW_DRV_CNTL, 0x77}, + {WCD938X_CLASSH_SPARE, 0x00}, + {WCD938X_FLYBACK_EN, 0x4E}, + {WCD938X_FLYBACK_VNEG_CTRL_1, 0x0B}, + {WCD938X_FLYBACK_VNEG_CTRL_2, 0x45}, + {WCD938X_FLYBACK_VNEG_CTRL_3, 0x74}, + {WCD938X_FLYBACK_VNEG_CTRL_4, 0x7F}, + {WCD938X_FLYBACK_VNEG_CTRL_5, 0x83}, + {WCD938X_FLYBACK_VNEG_CTRL_6, 0x98}, + {WCD938X_FLYBACK_VNEG_CTRL_7, 0xA9}, + {WCD938X_FLYBACK_VNEG_CTRL_8, 0x68}, + {WCD938X_FLYBACK_VNEG_CTRL_9, 0x64}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_1, 0xED}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_2, 0xF0}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_3, 0xA6}, + {WCD938X_FLYBACK_CTRL_1, 0x65}, + {WCD938X_FLYBACK_TEST_CTL, 0x00}, + {WCD938X_RX_AUX_SW_CTL, 0x00}, + {WCD938X_RX_PA_AUX_IN_CONN, 0x01}, + {WCD938X_RX_TIMER_DIV, 0x32}, + {WCD938X_RX_OCP_CTL, 0x1F}, + {WCD938X_RX_OCP_COUNT, 0x77}, + {WCD938X_RX_BIAS_EAR_DAC, 0xA0}, + {WCD938X_RX_BIAS_EAR_AMP, 0xAA}, + {WCD938X_RX_BIAS_HPH_LDO, 0xA9}, + {WCD938X_RX_BIAS_HPH_PA, 0xAA}, + {WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A}, + {WCD938X_RX_BIAS_HPH_RDAC_LDO, 0x88}, + {WCD938X_RX_BIAS_HPH_CNP1, 0x82}, + {WCD938X_RX_BIAS_HPH_LOWPOWER, 0x82}, + {WCD938X_RX_BIAS_AUX_DAC, 0xA0}, + {WCD938X_RX_BIAS_AUX_AMP, 0xAA}, + {WCD938X_RX_BIAS_VNEGDAC_BLEEDER, 0x50}, + {WCD938X_RX_BIAS_MISC, 0x00}, + {WCD938X_RX_BIAS_BUCK_RST, 0x08}, + {WCD938X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44}, + {WCD938X_RX_BIAS_FLYB_ERRAMP, 0x40}, + {WCD938X_RX_BIAS_FLYB_BUFF, 0xAA}, + {WCD938X_RX_BIAS_FLYB_MID_RST, 0x14}, + {WCD938X_HPH_L_STATUS, 0x04}, + {WCD938X_HPH_R_STATUS, 0x04}, + {WCD938X_HPH_CNP_EN, 0x80}, + {WCD938X_HPH_CNP_WG_CTL, 0x9A}, + {WCD938X_HPH_CNP_WG_TIME, 0x14}, + {WCD938X_HPH_OCP_CTL, 0x28}, + {WCD938X_HPH_AUTO_CHOP, 0x16}, + {WCD938X_HPH_CHOP_CTL, 0x83}, + {WCD938X_HPH_PA_CTL1, 0x46}, + {WCD938X_HPH_PA_CTL2, 0x50}, + {WCD938X_HPH_L_EN, 0x80}, + {WCD938X_HPH_L_TEST, 0xE0}, + {WCD938X_HPH_L_ATEST, 0x50}, + {WCD938X_HPH_R_EN, 0x80}, + {WCD938X_HPH_R_TEST, 0xE0}, + {WCD938X_HPH_R_ATEST, 0x54}, + {WCD938X_HPH_RDAC_CLK_CTL1, 0x99}, + {WCD938X_HPH_RDAC_CLK_CTL2, 0x9B}, + {WCD938X_HPH_RDAC_LDO_CTL, 0x33}, + {WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00}, + {WCD938X_HPH_REFBUFF_UHQA_CTL, 0x68}, + {WCD938X_HPH_REFBUFF_LP_CTL, 0x0E}, + {WCD938X_HPH_L_DAC_CTL, 0x20}, + {WCD938X_HPH_R_DAC_CTL, 0x20}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0x19}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xA0}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS, 0x00}, + {WCD938X_EAR_EAR_EN_REG, 0x22}, + {WCD938X_EAR_EAR_PA_CON, 0x44}, + {WCD938X_EAR_EAR_SP_CON, 0xDB}, + {WCD938X_EAR_EAR_DAC_CON, 0x80}, + {WCD938X_EAR_EAR_CNP_FSM_CON, 0xB2}, + {WCD938X_EAR_TEST_CTL, 0x00}, + {WCD938X_EAR_STATUS_REG_1, 0x00}, + {WCD938X_EAR_STATUS_REG_2, 0x08}, + {WCD938X_ANA_NEW_PAGE_REGISTER, 0x00}, + {WCD938X_HPH_NEW_ANA_HPH2, 0x00}, + {WCD938X_HPH_NEW_ANA_HPH3, 0x00}, + {WCD938X_SLEEP_CTL, 0x16}, + {WCD938X_SLEEP_WATCHDOG_CTL, 0x00}, + {WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00}, + {WCD938X_MBHC_NEW_CTL_1, 0x02}, + {WCD938X_MBHC_NEW_CTL_2, 0x05}, + {WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0xE9}, + {WCD938X_MBHC_NEW_ZDET_ANA_CTL, 0x0F}, + {WCD938X_MBHC_NEW_ZDET_RAMP_CTL, 0x00}, + {WCD938X_MBHC_NEW_FSM_STATUS, 0x00}, + {WCD938X_MBHC_NEW_ADC_RESULT, 0x00}, + {WCD938X_TX_NEW_AMIC_MUX_CFG, 0x00}, + {WCD938X_AUX_AUXPA, 0x00}, + {WCD938X_LDORXTX_MODE, 0x0C}, + {WCD938X_LDORXTX_CONFIG, 0x10}, + {WCD938X_DIE_CRACK_DIE_CRK_DET_EN, 0x00}, + {WCD938X_DIE_CRACK_DIE_CRK_DET_OUT, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81}, + {WCD938X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10}, + {WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81}, + {WCD938X_HPH_NEW_INT_PA_MISC1, 0x22}, + {WCD938X_HPH_NEW_INT_PA_MISC2, 0x00}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC, 0x00}, + {WCD938X_HPH_NEW_INT_HPH_TIMER1, 0xFE}, + {WCD938X_HPH_NEW_INT_HPH_TIMER2, 0x02}, + {WCD938X_HPH_NEW_INT_HPH_TIMER3, 0x4E}, + {WCD938X_HPH_NEW_INT_HPH_TIMER4, 0x54}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, 0x90}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, 0x90}, + {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62}, + {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01}, + {WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11}, + {WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57}, + {WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01}, + {WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00}, + {WCD938X_MBHC_NEW_INT_SPARE_2, 0x00}, + {WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xA8}, + {WCD938X_EAR_INT_NEW_CNP_VCM_CON1, 0x42}, + {WCD938X_EAR_INT_NEW_CNP_VCM_CON2, 0x22}, + {WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00}, + {WCD938X_AUX_INT_EN_REG, 0x00}, + {WCD938X_AUX_INT_PA_CTRL, 0x06}, + {WCD938X_AUX_INT_SP_CTRL, 0xD2}, + {WCD938X_AUX_INT_DAC_CTRL, 0x80}, + {WCD938X_AUX_INT_CLK_CTRL, 0x50}, + {WCD938X_AUX_INT_TEST_CTRL, 0x00}, + {WCD938X_AUX_INT_STATUS_REG, 0x00}, + {WCD938X_AUX_INT_MISC, 0x00}, + {WCD938X_LDORXTX_INT_BIAS, 0x6E}, + {WCD938X_LDORXTX_INT_STB_LOADS_DTEST, 0x50}, + {WCD938X_LDORXTX_INT_TEST0, 0x1C}, + {WCD938X_LDORXTX_INT_STARTUP_TIMER, 0xFF}, + {WCD938X_LDORXTX_INT_TEST1, 0x1F}, + {WCD938X_LDORXTX_INT_STATUS, 0x00}, + {WCD938X_SLEEP_INT_WATCHDOG_CTL_1, 0x0A}, + {WCD938X_SLEEP_INT_WATCHDOG_CTL_2, 0x0A}, + {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02}, + {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2, 0xFF}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1, 0x7F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0, 0x3F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M, 0x1F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M, 0x0F}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1, 0xD7}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0, 0xC8}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP, 0xC6}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1, 0xD5}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0, 0xCA}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, 0x05}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0, 0xA5}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, 0x13}, + {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1, 0x88}, + {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP, 0x42}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L2, 0xFF}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L1, 0x64}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L0, 0x64}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP, 0x77}, + {WCD938X_DIGITAL_PAGE_REGISTER, 0x00}, + {WCD938X_DIGITAL_CHIP_ID0, 0x00}, + {WCD938X_DIGITAL_CHIP_ID1, 0x00}, + {WCD938X_DIGITAL_CHIP_ID2, 0x0D}, + {WCD938X_DIGITAL_CHIP_ID3, 0x01}, + {WCD938X_DIGITAL_SWR_TX_CLK_RATE, 0x00}, + {WCD938X_DIGITAL_CDC_RST_CTL, 0x03}, + {WCD938X_DIGITAL_TOP_CLK_CFG, 0x00}, + {WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xF0}, + {WCD938X_DIGITAL_SWR_RST_EN, 0x00}, + {WCD938X_DIGITAL_CDC_PATH_MODE, 0x55}, + {WCD938X_DIGITAL_CDC_RX_RST, 0x00}, + {WCD938X_DIGITAL_CDC_RX0_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_RX1_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_RX2_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x00}, + {WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x00}, + {WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x00}, + {WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x1E}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A3_0, 0xAC}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1A}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A5_0, 0xBC}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A6_0, 0xC7}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A7_0, 0xF8}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_0, 0x47}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_1, 0x43}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_2, 0xB1}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_3, 0x17}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R1, 0x4D}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R2, 0x29}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R3, 0x34}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R4, 0x59}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R5, 0x66}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R6, 0x87}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R7, 0x64}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A3_0, 0xAB}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1C}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A6_0, 0xAA}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A7_0, 0xE3}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_0, 0x69}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_1, 0x54}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_2, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_3, 0x15}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R1, 0xA4}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R2, 0xB5}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R3, 0x86}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R4, 0x85}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R5, 0xAA}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R6, 0xE2}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R7, 0x62}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xA9}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3D}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2E}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xFC}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_SWR_CLH, 0x00}, + {WCD938X_DIGITAL_SWR_CLH_BYP, 0x00}, + {WCD938X_DIGITAL_CDC_TX0_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX1_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX2_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX_RST, 0x00}, + {WCD938X_DIGITAL_CDC_REQ_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_RST, 0x00}, + {WCD938X_DIGITAL_CDC_AMIC_CTL, 0x0F}, + {WCD938X_DIGITAL_CDC_DMIC_CTL, 0x04}, + {WCD938X_DIGITAL_CDC_DMIC1_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC2_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC3_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC4_CTL, 0x01}, + {WCD938X_DIGITAL_EFUSE_PRG_CTL, 0x00}, + {WCD938X_DIGITAL_EFUSE_CTL, 0x2B}, + {WCD938X_DIGITAL_CDC_DMIC_RATE_1_2, 0x11}, + {WCD938X_DIGITAL_CDC_DMIC_RATE_3_4, 0x11}, + {WCD938X_DIGITAL_PDM_WD_CTL0, 0x00}, + {WCD938X_DIGITAL_PDM_WD_CTL1, 0x00}, + {WCD938X_DIGITAL_PDM_WD_CTL2, 0x00}, + {WCD938X_DIGITAL_INTR_MODE, 0x00}, + {WCD938X_DIGITAL_INTR_MASK_0, 0xFF}, + {WCD938X_DIGITAL_INTR_MASK_1, 0xFF}, + {WCD938X_DIGITAL_INTR_MASK_2, 0x3F}, + {WCD938X_DIGITAL_INTR_STATUS_0, 0x00}, + {WCD938X_DIGITAL_INTR_STATUS_1, 0x00}, + {WCD938X_DIGITAL_INTR_STATUS_2, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_0, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_1, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_2, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_0, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_1, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_2, 0x00}, + {WCD938X_DIGITAL_INTR_SET_0, 0x00}, + {WCD938X_DIGITAL_INTR_SET_1, 0x00}, + {WCD938X_DIGITAL_INTR_SET_2, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_0, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_1, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_2, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_EN, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_0_1, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_2_3, 0x00}, + {WCD938X_DIGITAL_LB_IN_SEL_CTL, 0x00}, + {WCD938X_DIGITAL_LOOP_BACK_MODE, 0x00}, + {WCD938X_DIGITAL_SWR_DAC_TEST, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_RX_0, 0x40}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_0, 0x40}, + {WCD938X_DIGITAL_SWR_HM_TEST_RX_1, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_1, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_2, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_0, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_1, 0x00}, + {WCD938X_DIGITAL_PAD_CTL_SWR_0, 0x8F}, + {WCD938X_DIGITAL_PAD_CTL_SWR_1, 0x06}, + {WCD938X_DIGITAL_I2C_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE, 0x00}, + {WCD938X_DIGITAL_EFUSE_TEST_CTL_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_TEST_CTL_1, 0x00}, + {WCD938X_DIGITAL_EFUSE_T_DATA_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_T_DATA_1, 0x00}, + {WCD938X_DIGITAL_PAD_CTL_PDM_RX0, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_RX1, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX0, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX1, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX2, 0xF1}, + {WCD938X_DIGITAL_PAD_INP_DIS_0, 0x00}, + {WCD938X_DIGITAL_PAD_INP_DIS_1, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_0, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_1, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_2, 0x00}, + {WCD938X_DIGITAL_RX_DATA_EDGE_CTL, 0x1F}, + {WCD938X_DIGITAL_TX_DATA_EDGE_CTL, 0x80}, + {WCD938X_DIGITAL_GPIO_MODE, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_OE, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_DATA_0, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_DATA_1, 0x00}, + {WCD938X_DIGITAL_PIN_STATUS_0, 0x00}, + {WCD938X_DIGITAL_PIN_STATUS_1, 0x00}, + {WCD938X_DIGITAL_DIG_DEBUG_CTL, 0x00}, + {WCD938X_DIGITAL_DIG_DEBUG_EN, 0x00}, + {WCD938X_DIGITAL_ANA_CSR_DBG_ADD, 0x00}, + {WCD938X_DIGITAL_ANA_CSR_DBG_CTL, 0x48}, + {WCD938X_DIGITAL_SSP_DBG, 0x00}, + {WCD938X_DIGITAL_MODE_STATUS_0, 0x00}, + {WCD938X_DIGITAL_MODE_STATUS_1, 0x00}, + {WCD938X_DIGITAL_SPARE_0, 0x00}, + {WCD938X_DIGITAL_SPARE_1, 0x00}, + {WCD938X_DIGITAL_SPARE_2, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_1, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_2, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_3, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_4, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_5, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_6, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_7, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_8, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_9, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_10, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_11, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_12, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_13, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_14, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_15, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_16, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_17, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_18, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_19, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_20, 0x0E}, + {WCD938X_DIGITAL_EFUSE_REG_21, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_22, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_23, 0xF8}, + {WCD938X_DIGITAL_EFUSE_REG_24, 0x16}, + {WCD938X_DIGITAL_EFUSE_REG_25, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_26, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_27, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_28, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_29, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_30, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_31, 0x00}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0x88}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA0, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA1, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA2, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA3, 0x01}, +}; + +static bool wcd938x_readable_register(struct device *dev, unsigned int reg) +{ + if(reg <= WCD938X_BASE_ADDRESS) + return 0; + return wcd938x_reg_access[WCD938X_REG(reg)] & RD_REG; +} + +static bool wcd938x_writeable_register(struct device *dev, unsigned int reg) +{ + if(reg <= WCD938X_BASE_ADDRESS) + return 0; + return wcd938x_reg_access[WCD938X_REG(reg)] & WR_REG; +} + +static bool wcd938x_volatile_register(struct device *dev, unsigned int reg) +{ + if(reg <= WCD938X_BASE_ADDRESS) + return 0; + return (wcd938x_reg_access[WCD938X_REG(reg)] & RD_REG) + & ~(wcd938x_reg_access[WCD938X_REG(reg)] & WR_REG); +} + +struct regmap_config wcd938x_regmap_config = { + .name = "wcd938x_csr", + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd938x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults), + .max_register = WCD938X_MAX_REGISTER, + .readable_reg = wcd938x_readable_register, + .writeable_reg = wcd938x_writeable_register, + .volatile_reg = wcd938x_volatile_register, + .can_multi_write = true, +}; diff --git a/asoc/codecs/wcd938x/wcd938x-slave.c b/asoc/codecs/wcd938x/wcd938x-slave.c new file mode 100644 index 000000000000..b7c02306cb99 --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x-slave.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct wcd938x_slave_priv { + struct swr_device *swr_slave; +}; + +static int wcd938x_slave_bind(struct device *dev, + struct device *master, void *data) +{ + int ret = 0; + uint8_t devnum = 0; + struct swr_device *pdev = to_swr_device(dev); + + 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); + return ret; + } + pdev->dev_num = devnum; + + return ret; +} + +static void wcd938x_slave_unbind(struct device *dev, + struct device *master, void *data) +{ + struct wcd938x_slave_priv *wcd938x_slave = NULL; + struct swr_device *pdev = to_swr_device(dev); + + wcd938x_slave = swr_get_dev_data(pdev); + if (!wcd938x_slave) { + dev_err(&pdev->dev, "%s: wcd938x_slave is NULL\n", __func__); + return; + } +} + +static const struct swr_device_id wcd938x_swr_id[] = { + {"wcd938x-slave", 0}, + {} +}; + +static const struct of_device_id wcd938x_swr_dt_match[] = { + { + .compatible = "qcom,wcd938x-slave", + }, + {} +}; + +static const struct component_ops wcd938x_slave_comp_ops = { + .bind = wcd938x_slave_bind, + .unbind = wcd938x_slave_unbind, +}; + +static int wcd938x_swr_probe(struct swr_device *pdev) +{ + struct wcd938x_slave_priv *wcd938x_slave = NULL; + + wcd938x_slave = devm_kzalloc(&pdev->dev, + sizeof(struct wcd938x_slave_priv), GFP_KERNEL); + if (!wcd938x_slave) + return -ENOMEM; + + swr_set_dev_data(pdev, wcd938x_slave); + + wcd938x_slave->swr_slave = pdev; + + return component_add(&pdev->dev, &wcd938x_slave_comp_ops); +} + +static int wcd938x_swr_remove(struct swr_device *pdev) +{ + component_del(&pdev->dev, &wcd938x_slave_comp_ops); + swr_set_dev_data(pdev, NULL); + swr_remove_device(pdev); + + return 0; +} + +static struct swr_driver wcd938x_slave_driver = { + .driver = { + .name = "wcd938x-slave", + .owner = THIS_MODULE, + .of_match_table = wcd938x_swr_dt_match, + }, + .probe = wcd938x_swr_probe, + .remove = wcd938x_swr_remove, + .id_table = wcd938x_swr_id, +}; + +static int __init wcd938x_slave_init(void) +{ + return swr_driver_register(&wcd938x_slave_driver); +} + +static void __exit wcd938x_slave_exit(void) +{ + swr_driver_unregister(&wcd938x_slave_driver); +} + +module_init(wcd938x_slave_init); +module_exit(wcd938x_slave_exit); + +MODULE_DESCRIPTION("WCD938X Swr Slave driver"); +MODULE_LICENSE("GPL v2"); diff --git a/asoc/codecs/wcd938x/wcd938x-tables.c b/asoc/codecs/wcd938x/wcd938x-tables.c new file mode 100644 index 000000000000..d2f7d61b6d63 --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x-tables.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018 , The Linux Foundation. All rights reserved. + */ + +#include +#include "wcd938x-registers.h" + +const u8 wcd938x_reg_access[WCD938X_REG(WCD938X_REGISTERS_MAX_SIZE)] = { + [WCD938X_REG(WCD938X_ANA_PAGE_REGISTER)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_BIAS)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_RX_SUPPLIES)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_HPH)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_EAR)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_EAR_COMPANDER_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_TX_CH1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_TX_CH2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_TX_CH3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_TX_CH4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MICB3_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_MECH)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_ELECT)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_ZDET)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_RESULT_1)] = RD_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_RESULT_2)] = RD_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_RESULT_3)] = RD_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN5)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN6)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MBHC_BTN7)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MICB1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MICB2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MICB2_RAMP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MICB3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_ANA_MICB4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_BIAS_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_BIAS_VBG_FINE_ADJ)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDOL_VDDCX_ADJUST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDOL_DISABLE_LDOL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_CTL_CLK)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_CTL_ANA)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_CTL_SPARE_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_CTL_SPARE_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_CTL_BCS)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_MOISTURE_DET_FSM_STATUS)] = RD_REG, + [WCD938X_REG(WCD938X_MBHC_TEST_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDOH_MODE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDOH_BIAS)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDOH_STB_LOADS)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDOH_SLOWRAMP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB1_TEST_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB1_TEST_CTL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB1_TEST_CTL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB2_TEST_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB2_TEST_CTL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB2_TEST_CTL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB3_TEST_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB3_TEST_CTL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB3_TEST_CTL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB4_TEST_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB4_TEST_CTL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MICB4_TEST_CTL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_ADC_VCM)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_BIAS_ATEST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_SPARE1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_SPARE2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_TXFE_DIV_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_TXFE_DIV_START)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_SPARE3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_SPARE4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_1_2_TEST_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_1_2_ADC_IB)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_1_2_ATEST_REFCTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_1_2_TEST_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_1_2_TEST_BLK_EN1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_1_2_TXFE1_CLKDIV)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_1_2_SAR2_ERR)] = RD_REG, + [WCD938X_REG(WCD938X_TX_1_2_SAR1_ERR)] = RD_REG, + [WCD938X_REG(WCD938X_TX_3_4_TEST_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_ADC_IB)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_ATEST_REFCTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_TEST_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_TEST_BLK_EN3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_TXFE3_CLKDIV)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_SAR4_ERR)] = RD_REG, + [WCD938X_REG(WCD938X_TX_3_4_SAR3_ERR)] = RD_REG, + [WCD938X_REG(WCD938X_TX_3_4_TEST_BLK_EN2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_TXFE2_CLKDIV)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_SPARE1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_TEST_BLK_EN4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_TXFE4_CLKDIV)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_3_4_SPARE2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_MODE_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_MODE_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_MODE_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_CTRL_VCL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_CTRL_VCL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_CTRL_CCL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_CTRL_CCL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_CTRL_CCL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_CTRL_CCL_4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_CTRL_CCL_5)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_BUCK_TMUX_A_D)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_BUCK_SW_DRV_CNTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_CLASSH_SPARE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_5)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_6)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_7)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_8)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEG_CTRL_9)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEGDAC_CTRL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEGDAC_CTRL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_VNEGDAC_CTRL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_CTRL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_FLYBACK_TEST_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_AUX_SW_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_PA_AUX_IN_CONN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_TIMER_DIV)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_OCP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_OCP_COUNT)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_EAR_DAC)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_EAR_AMP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_HPH_LDO)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_HPH_PA)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_HPH_RDAC_LDO)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_HPH_CNP1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_HPH_LOWPOWER)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_AUX_DAC)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_AUX_AMP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_VNEGDAC_BLEEDER)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_MISC)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_BUCK_RST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_BUCK_VREF_ERRAMP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_FLYB_ERRAMP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_FLYB_BUFF)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_BIAS_FLYB_MID_RST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_L_STATUS)] = RD_REG, + [WCD938X_REG(WCD938X_HPH_R_STATUS)] = RD_REG, + [WCD938X_REG(WCD938X_HPH_CNP_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_CNP_WG_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_CNP_WG_TIME)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_OCP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_AUTO_CHOP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_CHOP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_PA_CTL1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_PA_CTL2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_L_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_L_TEST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_L_ATEST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_R_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_R_TEST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_R_ATEST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_RDAC_CLK_CTL1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_RDAC_CLK_CTL2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_RDAC_LDO_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_REFBUFF_UHQA_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_REFBUFF_LP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_L_DAC_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_R_DAC_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_SURGE_HPHLR_SURGE_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS)] = RD_REG, + [WCD938X_REG(WCD938X_EAR_EAR_EN_REG)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_EAR_PA_CON)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_EAR_SP_CON)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_EAR_DAC_CON)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_EAR_CNP_FSM_CON)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_TEST_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_STATUS_REG_1)] = RD_REG, + [WCD938X_REG(WCD938X_EAR_STATUS_REG_2)] = RD_REG, + [WCD938X_REG(WCD938X_ANA_NEW_PAGE_REGISTER)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_ANA_HPH2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_ANA_HPH3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_SLEEP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_SLEEP_WATCHDOG_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_CTL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_PLUG_DETECT_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_ZDET_ANA_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_ZDET_RAMP_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_FSM_STATUS)] = RD_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_ADC_RESULT)] = RD_REG, + [WCD938X_REG(WCD938X_TX_NEW_AMIC_MUX_CFG)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_AUXPA)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_MODE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_CONFIG)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIE_CRACK_DIE_CRK_DET_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIE_CRACK_DIE_CRK_DET_OUT)] = RD_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_RDAC_VREF_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_PA_MISC1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_PA_MISC2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_PA_RDAC_MISC)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_HPH_TIMER1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_HPH_TIMER2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_HPH_TIMER3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_HPH_TIMER4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_PA_RDAC_MISC2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_PA_RDAC_MISC3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW)] = RD_WR_REG, + [WCD938X_REG(WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT)] = RD_WR_REG, + [WCD938X_REG(WCD938X_MBHC_NEW_INT_SPARE_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_INT_NEW_CNP_VCM_CON1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_INT_NEW_CNP_VCM_CON2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_INT_EN_REG)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_INT_PA_CTRL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_INT_SP_CTRL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_INT_DAC_CTRL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_INT_CLK_CTRL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_INT_TEST_CTRL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_AUX_INT_STATUS_REG)] = RD_REG, + [WCD938X_REG(WCD938X_AUX_INT_MISC)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_INT_BIAS)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_INT_STB_LOADS_DTEST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_INT_TEST0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_INT_STARTUP_TIMER)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_INT_TEST1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_LDORXTX_INT_STATUS)] = RD_REG, + [WCD938X_REG(WCD938X_SLEEP_INT_WATCHDOG_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_SLEEP_INT_WATCHDOG_CTL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0)]=RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXADC_INT_L2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXADC_INT_L1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXADC_INT_L0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAGE_REGISTER)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CHIP_ID0)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_CHIP_ID1)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_CHIP_ID2)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_CHIP_ID3)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_TX_CLK_RATE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_RST_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TOP_CLK_CFG)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_ANA_CLK_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DIG_CLK_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_RST_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_PATH_MODE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_RX_RST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_RX0_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_RX1_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_RX2_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_COMP_CTL_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A1_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A1_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A2_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A2_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A3_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A3_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A4_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A4_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A5_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A5_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A6_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_A7_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_C_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_C_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_C_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_C_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_R1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_R2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_R3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_R4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_R5)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_R6)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_DSM_R7)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A1_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A1_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A2_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A2_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A3_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A3_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A4_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A4_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A5_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A5_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A6_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_A7_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_C_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_C_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_C_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_C_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_R1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_R2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_R3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_R4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_R5)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_R6)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_DSM_R7)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_HPH_GAIN_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AUX_GAIN_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_EAR_PATH_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_SWR_CLH)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_CLH_BYP)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_TX0_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_TX1_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_TX2_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_TX_RST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_REQ_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_RST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_AMIC_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DMIC_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DMIC1_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DMIC2_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DMIC3_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DMIC4_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_PRG_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DMIC_RATE_1_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_DMIC_RATE_3_4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PDM_WD_CTL0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PDM_WD_CTL1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PDM_WD_CTL2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_MODE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_MASK_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_MASK_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_MASK_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_STATUS_0)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_STATUS_1)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_STATUS_2)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_CLEAR_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_CLEAR_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_CLEAR_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_LEVEL_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_LEVEL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_LEVEL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_SET_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_SET_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_SET_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_TEST_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_TEST_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_INTR_TEST_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_MODE_DBG_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_MODE_DBG_0_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_MODE_DBG_2_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_LB_IN_SEL_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_LOOP_BACK_MODE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_DAC_TEST)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_HM_TEST_RX_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_HM_TEST_TX_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_HM_TEST_RX_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_HM_TEST_TX_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_HM_TEST_TX_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_HM_TEST_0)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_SWR_HM_TEST_1)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_CTL_SWR_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_CTL_SWR_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_I2C_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_TEST_CTL_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_TEST_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_T_DATA_0)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_T_DATA_1)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_CTL_PDM_RX0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_CTL_PDM_RX1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_CTL_PDM_TX0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_CTL_PDM_TX1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_CTL_PDM_TX2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_INP_DIS_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PAD_INP_DIS_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DRIVE_STRENGTH_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DRIVE_STRENGTH_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DRIVE_STRENGTH_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_RX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_GPIO_MODE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PIN_CTL_OE)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PIN_CTL_DATA_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PIN_CTL_DATA_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_PIN_STATUS_0)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_PIN_STATUS_1)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_DIG_DEBUG_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DIG_DEBUG_EN)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_ANA_CSR_DBG_ADD)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_ANA_CSR_DBG_CTL)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SSP_DBG)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_MODE_STATUS_0)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_MODE_STATUS_1)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_SPARE_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SPARE_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_SPARE_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_0)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_1)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_2)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_3)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_4)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_5)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_6)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_7)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_8)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_9)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_10)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_11)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_12)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_13)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_14)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_15)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_16)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_17)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_18)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_19)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_20)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_21)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_22)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_23)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_24)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_25)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_26)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_27)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_28)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_29)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_30)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_EFUSE_REG_31)] = RD_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_REQ_FB_CTL_0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_REQ_FB_CTL_1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_REQ_FB_CTL_2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_REQ_FB_CTL_3)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_TX_REQ_FB_CTL_4)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DEM_BYPASS_DATA0)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DEM_BYPASS_DATA1)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DEM_BYPASS_DATA2)] = RD_WR_REG, + [WCD938X_REG(WCD938X_DIGITAL_DEM_BYPASS_DATA3)] = RD_WR_REG, +}; diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c new file mode 100644 index 000000000000..2905c59e19bc --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -0,0 +1,2704 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "wcd938x-registers.h" + +#define WCD938X_DRV_NAME "wcd938x_codec" +#define NUM_SWRS_DT_PARAMS 5 + +#define WCD938X_VERSION_1_0 1 +#define WCD938X_VERSION_ENTRY_SIZE 32 + +enum { + WCD9380 = 0, + WCD9385, + WCD9385FX, +}; + +enum { + CODEC_TX = 0, + CODEC_RX, +}; + +enum { + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, +}; + +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +static int wcd938x_handle_post_irq(void *data); +static int wcd938x_reset(struct device *dev); +static int wcd938x_reset_low(struct device *dev); + +static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_EAR_SCD_INT, 1, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_CNP_INT, 1, 0x08), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_SCD_INT, 1, 0x10), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_PDM_WD_INT, 1, 0x80), + REGMAP_IRQ_REG(WCD938X_IRQ_LDORT_SCD_INT, 2, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), +}; + +static struct regmap_irq_chip wcd938x_regmap_irq_chip = { + .name = "wcd938x", + .irqs = wcd938x_irqs, + .num_irqs = ARRAY_SIZE(wcd938x_irqs), + .num_regs = 3, + .status_base = WCD938X_DIGITAL_INTR_STATUS_0, + .mask_base = WCD938X_DIGITAL_INTR_MASK_0, + .type_base = WCD938X_DIGITAL_INTR_LEVEL_0, + .ack_base = WCD938X_DIGITAL_INTR_CLEAR_0, + .use_ack = 1, + .clear_ack = 1, + .runtime_pm = true, + .handle_post_irq = wcd938x_handle_post_irq, + .irq_drv_data = NULL, +}; + +static int wcd938x_handle_post_irq(void *data) +{ + struct wcd938x_priv *wcd938x = data; + u32 sts1 = 0, sts2 = 0, sts3 = 0; + + regmap_read(wcd938x->regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1); + regmap_read(wcd938x->regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2); + regmap_read(wcd938x->regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3); + + wcd938x->tx_swr_dev->slave_irq_pending = + ((sts1 || sts2 || sts3) ? true : false); + + return IRQ_HANDLED; +} + +static int wcd938x_init_reg(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x0E, 0x0E); + snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x80, 0x80); + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x40, 0x40); + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, WCD938X_LDORXTX_CONFIG, + 0x10, 0x00); + snd_soc_component_update_bits(component, WCD938X_BIAS_VBG_FINE_ADJ, + 0xF0, 0x80); + snd_soc_component_update_bits(component, WCD938X_ANA_BIAS, 0x80, 0x80); + snd_soc_component_update_bits(component, WCD938X_ANA_BIAS, 0x40, 0x40); + /* 10 msec delay as per HW requirement */ + usleep_range(10000, 10010); + snd_soc_component_update_bits(component, WCD938X_ANA_BIAS, 0x40, 0x00); + snd_soc_component_update_bits(component, WCD938X_HPH_OCP_CTL, + 0xFF, 0x3A); + snd_soc_component_update_bits(component, WCD938X_RX_OCP_CTL, + 0x0F, 0x02); + snd_soc_component_update_bits(component, WCD938X_HPH_R_TEST, + 0x01, 0x01); + snd_soc_component_update_bits(component, WCD938X_HPH_L_TEST, + 0x01, 0x01); + + return 0; +} + +static int wcd938x_set_port_params(struct snd_soc_component *component, + 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 wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (path) { + case CODEC_RX: + map = &wcd938x->rx_port_mapping; + num_ports = wcd938x->num_rx_ports; + break; + case CODEC_TX: + map = &wcd938x->tx_port_mapping; + num_ports = wcd938x->num_tx_ports; + break; + } + + for (i = 0; i <= num_ports; i++) { + for (j = 0; j < MAX_CH_PER_PORT; j++) { + if ((*map)[i][j].port_type == slv_prt_type) + goto found; + } + } +found: + if (i > num_ports || j == MAX_CH_PER_PORT) { + dev_err(component->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 wcd938x_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 wcd938x_priv *wcd938x = dev_get_drvdata(dev); + + switch (path) { + case CODEC_RX: + map = &wcd938x->rx_port_mapping; + num_ports = &wcd938x->num_rx_ports; + break; + case CODEC_TX: + map = &wcd938x->tx_port_mapping; + num_ports = &wcd938x->num_tx_ports; + break; + } + + if (!of_find_property(dev->of_node, prop, + &map_size)) { + dev_err(dev, "missing port mapping prop %s\n", prop); + ret = -EINVAL; + goto err_port_map; + } + + map_length = map_size / (NUM_SWRS_DT_PARAMS * sizeof(u32)); + + dt_array = kzalloc(map_size, GFP_KERNEL); + + if (!dt_array) { + ret = -ENOMEM; + goto err_alloc; + } + 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].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); +err_alloc: +err_port_map: + return ret; +} + +static int wcd938x_tx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + u8 port_id, num_ch, ch_mask, port_type; + u32 ch_rate; + u8 num_port = 1; + int ret = 0; + + ret = wcd938x_set_port_params(component, 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(wcd938x->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + else + ret = swr_disconnect_port(wcd938x->tx_swr_dev, &port_id, + num_port, &ch_mask, &port_type); + return ret; + +} +static int wcd938x_rx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + u8 port_id, num_ch, ch_mask, port_type; + u32 ch_rate; + u8 num_port = 1; + int ret = 0; + + ret = wcd938x_set_port_params(component, 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(wcd938x->rx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + else + ret = swr_disconnect_port(wcd938x->rx_swr_dev, &port_id, + num_port, &ch_mask, &port_type); + return ret; +} + +static int wcd938x_rx_clk_enable(struct snd_soc_component *component) +{ + + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (wcd938x->rx_clk_cnt == 0) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_RX0_CTL, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_RX1_CTL, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_RX2_CTL, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02); + } + wcd938x->rx_clk_cnt++; + + return 0; +} + +static int wcd938x_rx_clk_disable(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x->rx_clk_cnt--; + if (wcd938x->rx_clk_cnt == 0) { + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00); + } + return 0; +} + +/* + * wcd938x_soc_get_mbhc: get wcd938x_mbhc handle of corresponding component + * @component: handle to snd_soc_component * + * + * return wcd938x_mbhc handle or error code in case of failure + */ +struct wcd938x_mbhc *wcd938x_soc_get_mbhc(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x; + + if (!component) { + pr_err("%s: Invalid params, NULL component\n", __func__); + return NULL; + } + wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) { + pr_err("%s: wcd938x is NULL\n", __func__); + return NULL; + } + + return wcd938x->mbhc; +} +EXPORT_SYMBOL(wcd938x_soc_get_mbhc); + +static int wcd938x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD938X_HPH_RDAC_CLK_CTL1, 0x80, 0x00); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x0F, 0x02); + if (wcd938x->comp1_enable) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x02, 0x02); + /* 5msec compander delay as per HW requirement */ + if (!wcd938x->comp2_enable || + (snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x01)) + usleep_range(5000, 5010); + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00); + } else { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD938X_HPH_L_EN, 0x20, 0x20); + + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0F, 0x01); + break; + } + + return 0; +} + +static int wcd938x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD938X_HPH_RDAC_CLK_CTL1, 0x80, 0x00); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x0F, 0x02); + if (wcd938x->comp2_enable) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x01, 0x01); + /* 5msec compander delay as per HW requirement */ + if (!wcd938x->comp1_enable || + (snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x02)) + usleep_range(5000, 5010); + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00); + } else { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD938X_HPH_R_EN, 0x20, 0x20); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0F, 0x01); + break; + } + + return 0; +} + +static int wcd938x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x02, 0x02); + /* 5 msec delay as per HW requirement */ + usleep_range(5000, 5010); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + wcd938x->hph_mode); + break; + case SND_SOC_DAPM_POST_PMD: + break; + }; + return 0; + +} + +static int wcd938x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x01); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_AUX, + wcd938x->hph_mode); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x04, 0x00); + break; + }; + return ret; + +} + +static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int ret = 0; + int hph_mode = wcd938x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = swr_slvdev_datapath_control(wcd938x->rx_swr_dev, + wcd938x->rx_swr_dev->dev_num, + true); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + hph_mode); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x10, 0x10); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x02, 0x02); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10)); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + WCD_EVENT_PRE_HPHR_PA_OFF, + &wcd938x->mbhc->wcd_mbhc); + break; + case SND_SOC_DAPM_POST_PMD: + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + WCD_EVENT_POST_HPHR_PA_OFF, + &wcd938x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x10, 0x00); + wcd_cls_h_fsm(component, &wcd93x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + hph_mode); + break; + }; + return ret; +} + +static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int ret = 0; + int hph_mode = wcd938x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = swr_slvdev_datapath_control(wcd938x->rx_swr_dev, + wcd938x->rx_swr_dev->dev_num, + true); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + hph_mode); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x20, 0x20); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x02, 0x02); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + WCD_EVENT_PRE_HPHL_PA_OFF, + &wcd938x->mbhc->wcd_mbhc); + break; + case SND_SOC_DAPM_POST_PMD: + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + WCD_EVENT_POST_HPHL_PA_OFF, + &wcd938x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x20, 0x00); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + hph_mode); + break; + }; + return ret; +} + +static int wcd938x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = swr_slvdev_datapath_control(wcd938x->rx_swr_dev, + wcd938x->rx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, + 0x20, 0x20); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10)); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10 | 0x1)); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_AUX, + hph_mode); + break; + }; + return ret; +} + +static int wcd938x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = swr_slvdev_datapath_control(wcd938x->rx_swr_dev, + wcd938x->rx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 6 msec delay as per HW requirement */ + usleep_range(6000, 6010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + break; + case SND_SOC_DAPM_POST_PMD: + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + hph_mode); + break; + }; + return ret; +} + +static int wcd938x_enable_clsh(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int mode = wcd938x->hph_mode; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP || + mode == CLS_H_HIFI || mode == CLS_H_LP) { + wcd938x_rx_connect_port(component, CLSH, + SND_SOC_DAPM_EVENT_ON(event)); + } + if (SND_SOC_DAPM_EVENT_OFF(event)) + ret = swr_slvdev_datapath_control( + wcd938x->rx_swr_dev, + wcd938x->rx_swr_dev->dev_num, + false); + return ret; +} + +static int wcd938x_enable_rx1(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_rx_connect_port(component, HPH_L, true); + if (wcd938x->comp1_enable) + wcd938x_rx_connect_port(component, COMP_L, true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_rx_connect_port(component, HPH_L, false); + if (wcd938x->comp1_enable) + wcd938x_rx_connect_port(component, COMP_L, false); + wcd938x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + 0x01, 0x00); + break; + }; + + return 0; +} + +static int wcd938x_enable_rx2(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_rx_connect_port(component, HPH_R, true); + if (wcd938x->comp2_enable) + wcd938x_rx_connect_port(component, COMP_R, true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_rx_connect_port(component, HPH_R, false); + if (wcd938x->comp2_enable) + wcd938x_rx_connect_port(component, COMP_R, false); + wcd938x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + 0x02, 0x00); + break; + }; + + return 0; +} + +static int wcd938x_enable_rx3(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_rx_connect_port(component, LO, true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_rx_connect_port(component, LO, false); + /* 6 msec delay as per HW requirement */ + usleep_range(6000, 6010); + wcd938x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x00); + break; + } + + return 0; +} + +static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + 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(component->dev, "%s: widget not found\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(wname, 10, &dmic); + if (ret < 0) { + dev_err(component->dev, "%s: Invalid DMIC line on the codec\n", + __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(wcd938x->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(wcd938x->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd938x->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + }; + dev_dbg(component->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_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x80); + snd_soc_component_update_bits(component, + dmic_clk_reg, 0x07, 0x02); + snd_soc_component_update_bits(component, + dmic_clk_reg, 0x08, 0x08); + snd_soc_component_update_bits(component, + dmic_clk_reg, 0x70, 0x20); + wcd938x_tx_connect_port(component, DMIC0 + (w->shift), true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_tx_connect_port(component, DMIC0 + (w->shift), false); + break; + + }; + return 0; +} + +/* + * wcd938x_get_micb_vout_ctl_val: converts micbias from volts to register value + * @micb_mv: micbias in mv + * + * return register value converted + */ +int wcd938x_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(wcd938x_get_micb_vout_ctl_val); + +/* + * wcd938x_mbhc_micb_adjust_voltage: adjust specific micbias voltage + * @component: handle to snd_soc_component * + * @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 wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + 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 = WCD938X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD938X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD938X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD938X_ANA_MICB4; + break; + default: + return -EINVAL; + } + mutex_lock(&wcd938x->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_component_read32(component, micb_reg); + micb_en = (micb_val & 0xC0) >> 6; + cur_vout_ctl = micb_val & 0x3F; + + req_vout_ctl = wcd938x_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(component->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_component_update_bits(component, micb_reg, 0xC0, 0x80); + + snd_soc_component_update_bits(component, micb_reg, 0x3F, req_vout_ctl); + + if (micb_en == 0x1) { + snd_soc_component_update_bits(component, micb_reg, 0xC0, 0x40); + /* + * Add 2ms delay as per HW requirement after enabling + * micbias + */ + usleep_range(2000, 2100); + } +exit: + mutex_unlock(&wcd938x->micb_lock); + return ret; +} +EXPORT_SYMBOL(wcd938x_mbhc_micb_adjust_voltage); + +static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + false); + break; + }; + + return ret; +} + +static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event){ + + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + wcd938x_tx_connect_port(component, ADC1 + (w->shift), true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_tx_connect_port(component, ADC1 + (w->shift), false); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00); + break; + }; + + return 0; +} + +static int wcd938x_enable_req(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x40, 0x40); + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x30, 0x30); + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH1, 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x20, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH1, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00); + break; + }; + return 0; +} + +int wcd938x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + 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 > WCD938X_MAX_MICBIAS - 1)) { + dev_err(component->dev, + "%s: Invalid micbias index, micb_ind:%d\n", + __func__, micb_index); + return -EINVAL; + } + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD938X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD938X_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 = WCD938X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD938X_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + }; + mutex_lock(&wcd938x->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd938x->pullup_ref[micb_index]++; + if ((wcd938x->pullup_ref[micb_index] == 1) && + (wcd938x->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + if (wcd938x->pullup_ref[micb_index] > 0) + wcd938x->pullup_ref[micb_index]--; + if ((wcd938x->pullup_ref[micb_index] == 0) && + (wcd938x->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + wcd938x->micb_ref[micb_index]++; + if (wcd938x->micb_ref[micb_index] == 1) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD938X_MICB1_TEST_CTL_2, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD938X_MICB2_TEST_CTL_2, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD938X_MICB3_TEST_CTL_2, 0x01, 0x01); + snd_soc_component_update_bits(component, + micb_reg, 0xC0, 0x40); + if (post_on_event) + blocking_notifier_call_chain( + &wcd938x->mbhc->notifier, + post_on_event, + &wcd938x->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_on && wcd938x->mbhc) + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + post_dapm_on, + &wcd938x->mbhc->wcd_mbhc); + break; + case MICB_DISABLE: + if (wcd938x->micb_ref[micb_index] > 0) + wcd938x->micb_ref[micb_index]--; + if ((wcd938x->micb_ref[micb_index] == 0) && + (wcd938x->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((wcd938x->micb_ref[micb_index] == 0) && + (wcd938x->pullup_ref[micb_index] == 0)) { + if (pre_off_event && wcd938x->mbhc) + blocking_notifier_call_chain( + &wcd938x->mbhc->notifier, + pre_off_event, + &wcd938x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + if (post_off_event && wcd938x->mbhc) + blocking_notifier_call_chain( + &wcd938x->mbhc->notifier, + post_off_event, + &wcd938x->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_off && wcd938x->mbhc) + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + post_dapm_off, + &wcd938x->mbhc->wcd_mbhc); + break; + }; + + dev_dbg(component->dev, + "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, wcd938x->micb_ref[micb_index], + wcd938x->pullup_ref[micb_index]); + mutex_unlock(&wcd938x->micb_lock); + + return 0; +} +EXPORT_SYMBOL(wcd938x_micbias_control); + +static int wcd938x_get_logical_addr(struct swr_device *swr_dev) +{ + int ret = 0; + uint8_t devnum = 0; + + ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum); + if (ret) { + dev_err(&swr_dev->dev, + "%s get devnum %d for dev addr %lx failed\n", + __func__, devnum, swr_dev->addr); + swr_remove_device(swr_dev); + return ret; + } + swr_dev->dev_num = devnum; + return 0; +} + +static int wcd938x_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + u16 amic; + u16 mask = 0x40, reg = 0x0; + int ret = 0; + struct wcd938x_priv *wcd938x = dev_get_drvdata((struct device *)data); + struct snd_soc_component *component = wcd938x->component; + struct wcd_mbhc *mbhc; + + switch (event) { + case BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR: + amic = (val >> 0x10); + if (amic == 0x1 || amic == 0x2) + reg = WCD938X_ANA_TX_CH2; + else if (amic == 0x3) + reg = WCD938X_ANA_TX_CH3_HPF; + else + return 0; + if (amic == 0x2) + mask = 0x20; + snd_soc_component_update_bits(component, reg, mask, 0x00); + break; + case BOLERO_WCD_EVT_PA_OFF_PRE_SSR: + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0xC0, 0x00); + snd_soc_component_update_bits(component, WCD938X_ANA_EAR, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD938X_AUX_AUXPA, + 0x80, 0x00); + break; + case BOLERO_WCD_EVT_SSR_DOWN: + wcd938x_reset_low(wcd938x->dev); + break; + case BOLERO_WCD_EVT_SSR_UP: + wcd938x_reset(wcd938x->dev); + wcd938x_get_logical_addr(wcd938x->tx_swr_dev); + wcd938x_get_logical_addr(wcd938x->rx_swr_dev); + regcache_mark_dirty(wcd938x->regmap); + regcache_sync(wcd938x->regmap); + /* Initialize MBHC module */ + mbhc = &wcd938x->mbhc->wcd_mbhc; + ret = wcd938x_mbhc_post_ssr_init(wcd938x->mbhc, component); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + } else { + wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg); + } + break; + case BOLERO_WCD_EVT_CLK_NOTIFY: + snd_soc_update_bits(codec, WCD938X_DIGITAL_TOP_CLK_CFG, 0x06, + ((val >> 0x10) << 0x01)); + break; + default: + dev_dbg(component->dev, "%s: invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static int __wcd938x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num; + + dev_dbg(component->dev, "%s: wname: %s, event: %d\n", + __func__, w->name, event); + + if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) + micb_num = MIC_BIAS_4; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_micbias_control(component, micb_num, + MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_micbias_control(component, micb_num, + MICB_DISABLE, true); + break; + }; + + return 0; + +} + +static int wcd938x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd938x_codec_enable_micbias(w, event); +} + +static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd938x->hph_mode; + return 0; +} + +static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + u32 mode_val; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: mode: %d\n", __func__, mode_val); + + if (mode_val == 0) { + dev_info(component->dev, + "%s:Invalid HPH Mode, default to class_AB\n", + __func__); + mode_val = 3; /* enum will be updated later */ + } + wcd938x->hph_mode = mode_val; + return 0; +} + +static int wcd938x_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + bool hphr; + struct soc_multi_mixer_control *mc; + + mc = (struct soc_multi_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + + ucontrol->value.integer.value[0] = hphr ? wcd938x->comp2_enable : + wcd938x->comp1_enable; + return 0; +} + +static int wcd938x_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int value = ucontrol->value.integer.value[0]; + bool hphr; + struct soc_multi_mixer_control *mc; + + mc = (struct soc_multi_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + if (hphr) + wcd938x->comp2_enable = value; + else + wcd938x->comp1_enable = value; + + return 0; +} + +static int wcd938x_codec_enable_vdd_buck(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct wcd938x_pdata *pdata = NULL; + int ret = 0; + + pdata = dev_get_platdata(wcd938x->dev); + + if (!pdata) { + dev_err(component->dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = msm_cdc_enable_ondemand_supply(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck"); + if (ret == -EINVAL) { + dev_err(component->dev, "%s: vdd buck is not enabled\n", + __func__); + return ret; + } + /* + * 200us sleep is required after LDO15 is enabled as per + * HW requirement + */ + usleep_range(200, 250); + break; + case SND_SOC_DAPM_POST_PMD: + ret = msm_cdc_disable_ondemand_supply(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck"); + if (ret == -EINVAL) { + dev_err(dev, "%s: vdd buck is not disabled\n", + __func__); + return 0; + } + break; + } + return 0; +} + +static int wcd938x_tx_hdr_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hdr = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = wcd938x->hdr_en[hdr]; + + return 0; +} + +static int wcd938x_tx_hdr_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hdr = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int val = ucontrol->value.integer.value[0]; + u8 mask = 0; + + wcd938x->hdr_en[hdr] = val; + + switch(val) { + case TX_HDR12: + mask = (1 << 4); + val = (val << 4); + break; + case TX_HDR34: + mask = (1 << 3); + val = (val << 3); + break; + default: + dev_err(component->dev, "%s: unknown HDR input: %d\n", + __func__, hdr); + break; + } + + if (mask) + snd_soc_component_update_bits(component, + WCD938X_TX_NEW_AMIC_MUX_CFG, mask, 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 wcd938x_snd_controls[] = { + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), + + SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0, + wcd938x_get_compander, wcd938x_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0, + wcd938x_get_compander, wcd938x_set_compander), + + SOC_SINGLE_EXT("TX HDR12", SND_SOC_NOPM, TX_HDR12, 1, 0, + wcd938x_tx_hdr_get, wcd938x_tx_hdr_put), + + SOC_SINGLE_EXT("TX HDR34", SND_SOC_NOPM, TX_HDR34, 1, 0, + wcd938x_tx_hdr_get, wcd938x_tx_hdr_put), + + SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD938X_ANA_TX_CH3, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD938X_ANA_TX_CH4, 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 adc4_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 dmic7_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic8_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 struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 7, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +static const struct snd_kcontrol_new tx_adc2_mux = + SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); + +static const char * const adc3_mux_text[] = { + "INP4", "INP6" +}; + +static const struct soc_enum adc3_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 6, + ARRAY_SIZE(adc3_mux_text), adc3_mux_text); + +static const struct snd_kcontrol_new tx_adc3_mux = + SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum); + +static const char * const adc4_mux_text[] = { + "INP5", "INP7" +}; + +static const struct soc_enum adc4_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 5, + ARRAY_SIZE(adc4_mux_text), adc4_mux_text); + +static const struct snd_kcontrol_new tx_adc4_mux = + SOC_DAPM_ENUM("ADC4 MUX Mux", adc4_enum); + +static const char * const rdac3_mux_text[] = { + "RX1", "RX3" +}; + +static const struct soc_enum rdac3_enum = + SOC_ENUM_SINGLE(WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0, + ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); + +static const struct snd_kcontrol_new rx_rdac3_mux = + SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); + +static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { + + /*input widgets*/ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + SND_SOC_DAPM_INPUT("AMIC6"), + SND_SOC_DAPM_INPUT("AMIC7"), + 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, + wcd938x_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, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 0, 2, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 0, 3, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 0, 6, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 0, 7, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd938x_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, wcd938x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd938x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd938x_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), + SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, + &tx_adc3_mux), + SND_SOC_DAPM_MUX("ADC4 MUX", SND_SOC_NOPM, 0, 0, + &tx_adc4_mux), + + /*tx mixers*/ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, + adc1_switch, ARRAY_SIZE(adc1_switch), + wcd938x_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), + wcd938x_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), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, 0, 0, adc4_switch, + ARRAY_SIZE(adc4_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, + 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), + wcd938x_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), + wcd938x_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), + wcd938x_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), + wcd938x_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), + wcd938x_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), + wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, 0, + 0, dmic7_switch, ARRAY_SIZE(dmic7_switch), + wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, 0, + 0, dmic8_switch, ARRAY_SIZE(dmic8_switch), + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS4", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_vdd_buck, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, + wcd938x_enable_clsh, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /*rx widgets*/ + SND_SOC_DAPM_PGA_E("EAR PGA", WCD938X_ANA_EAR, 7, 0, NULL, 0, + wcd938x_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AUX PGA", WCD938X_AUX_AUXPA, 7, 0, NULL, 0, + wcd938x_codec_enable_aux_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", WCD938X_ANA_HPH, 7, 0, NULL, 0, + wcd938x_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", WCD938X_ANA_HPH, 6, 0, NULL, 0, + wcd938x_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_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, + wcd938x_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"), + SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT"), + 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("DMIC7_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC8_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_route wcd938x_audio_map[] = { + + {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1 REQ"}, + {"ADC1 REQ", NULL, "ADC1"}, + {"ADC1", NULL, "AMIC1"}, + + {"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"}, + + {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_MIXER", "Switch", "ADC3 REQ"}, + {"ADC3 REQ", NULL, "ADC3"}, + {"ADC3", NULL, "ADC3 MUX"}, + {"ADC3 MUX", "INP4", "AMIC4"}, + {"ADC3 MUX", "INP6", "AMIC6"}, + + {"ADC4_OUTPUT", NULL, "ADC4_MIXER"}, + {"ADC4_MIXER", "Switch", "ADC4 REQ"}, + {"ADC4 REQ", NULL, "ADC4"}, + {"ADC4", NULL, "ADC4 MUX"}, + {"ADC4 MUX", "INP5", "AMIC5"}, + {"ADC4 MUX", "INP7", "AMIC7"}, + + {"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"}, + + {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"}, + {"DMIC7_MIXER", "Switch", "DMIC7"}, + + {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"}, + {"DMIC8_MIXER", "Switch", "DMIC8"}, + + {"IN1_HPHL", NULL, "VDD_BUCK"}, + {"IN1_HPHL", NULL, "CLS_H_PORT"}, + {"RX1", NULL, "IN1_HPHL"}, + {"RDAC1", NULL, "RX1"}, + {"HPHL_RDAC", "Switch", "RDAC1"}, + {"HPHL PGA", NULL, "HPHL_RDAC"}, + {"HPHL", NULL, "HPHL PGA"}, + + {"IN2_HPHR", NULL, "VDD_BUCK"}, + {"IN2_HPHR", NULL, "CLS_H_PORT"}, + {"RX2", NULL, "IN2_HPHR"}, + {"RDAC2", NULL, "RX2"}, + {"HPHR_RDAC", "Switch", "RDAC2"}, + {"HPHR PGA", NULL, "HPHR_RDAC"}, + {"HPHR", NULL, "HPHR PGA"}, + + {"IN3_AUX", NULL, "VDD_BUCK"}, + {"IN3_AUX", NULL, "CLS_H_PORT"}, + {"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 ssize_t wcd938x_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct wcd938x_priv *priv; + char buffer[WCD938X_VERSION_ENTRY_SIZE]; + int len = 0; + + priv = (struct wcd938x_priv *) entry->private_data; + if (!priv) { + pr_err("%s: wcd938x priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->version) { + case WCD938X_VERSION_1_0: + len = snprintf(buffer, sizeof(buffer), "WCD938X_1_0\n"); + break; + default: + len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + } + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static struct snd_info_entry_ops wcd938x_info_ops = { + .read = wcd938x_version_read, +}; + +/* + * wcd938x_info_create_codec_entry - creates wcd938x module + * @codec_root: The parent directory + * @component: component instance + * + * Creates wcd938x module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct wcd938x_priv *priv; + struct snd_soc_card *card; + + if (!codec_root || !component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (priv->entry) { + dev_dbg(priv->dev, + "%s:wcd938x module already created\n", __func__); + return 0; + } + card = component->card; + priv->entry = snd_info_create_subdir(codec_root->module, + "wcd938x", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create wcd938x entry\n", + __func__); + return -ENOMEM; + } + version_entry = snd_info_create_card_entry(card->snd_card, + "version", + priv->entry); + if (!version_entry) { + dev_dbg(component->dev, "%s: failed to create wcd938x version entry\n", + __func__); + return -ENOMEM; + } + + version_entry->private_data = priv; + version_entry->size = WCD938X_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &wcd938x_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + return -ENOMEM; + } + priv->version_entry = version_entry; + + return 0; +} +EXPORT_SYMBOL(wcd938x_info_create_codec_entry); + +static int wcd938x_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int variant; + int ret = -EINVAL; + + dev_info(component->dev, "%s()\n", __func__); + wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return -EINVAL; + + wcd938x->component = component; + snd_soc_component_init_regmap(component, wcd938x->regmap); + + variant = (snd_soc_component_read32(component, + WCD938X_DIGITAL_EFUSE_REG_0) & 0x1E) >> 1; + wcd938x->variant = variant; + + wcd938x->fw_data = devm_kzalloc(component->dev, + sizeof(*(wcd938x->fw_data)), + GFP_KERNEL); + if (!wcd938x->fw_data) { + dev_err(component->dev, "Failed to allocate fw_data\n"); + ret = -ENOMEM; + goto err; + } + + set_bit(WCD9XXX_MBHC_CAL, wcd938x->fw_data->cal_bit); + ret = wcd_cal_create_hwdep(wcd938x->fw_data, + WCD9XXX_CODEC_HWDEP_NODE, component); + + if (ret < 0) { + dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret); + goto err_hwdep; + } + + ret = wcd938x_mbhc_init(&wcd938x->mbhc, component, wcd938x->fw_data); + if (ret) { + pr_err("%s: mbhc initialization failed\n", __func__); + goto err_hwdep; + } + + 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_ignore_suspend(dapm, "AMIC5"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC6"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC7"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC1_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC2_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC3_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC4_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC5_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC6_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC7_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC8_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC1_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC2_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC3_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC4_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "IN1_HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "IN2_HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "IN3_AUX"); + 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_sync(dapm); + + wcd_cls_h_init(&wcd938x->clsh_info); + wcd938x_init_reg(component); + + wcd938x->version = WCD938X_VERSION_1_0; + /* Register event notifier */ + wcd938x->nblock.notifier_call = wcd938x_event_notify; + if (wcd938x->register_notifier) { + ret = wcd938x->register_notifier(wcd938x->handle, + &wcd938x->nblock, + true); + if (ret) { + dev_err(component->dev, + "%s: Failed to register notifier %d\n", + __func__, ret); + return ret; + } + } + return ret; + +err_hwdep: + wcd938x->fw_data = NULL; + +err: + return ret; +} + +static void wcd938x_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) { + dev_err(component->dev, "%s: wcd938x is already NULL\n", + __func__); + return; + } + if (wcd938x->register_notifier) + wcd938x->register_notifier(wcd938x->handle, + &wcd938x->nblock, + false); +} + +static struct snd_soc_component_driver soc_codec_dev_wcd938x = { + .name = WCD938X_DRV_NAME, + .probe = wcd938x_soc_codec_probe, + .remove = wcd938x_soc_codec_remove, + .controls = wcd938x_snd_controls, + .num_controls = ARRAY_SIZE(wcd938x_snd_controls), + .dapm_widgets = wcd938x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets), + .dapm_routes = wcd938x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), +}; + +static int wcd938x_reset(struct device *dev) +{ + struct wcd938x_priv *wcd938x = NULL; + int rc = 0; + int value = 0; + + if (!dev) + return -ENODEV; + + wcd938x = dev_get_drvdata(dev); + if (!wcd938x) + return -EINVAL; + + if (!wcd938x->rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + value = msm_cdc_pinctrl_get_state(wcd938x->rst_np); + if (value > 0) + return 0; + + rc = msm_cdc_pinctrl_select_sleep_state(wcd938x->rst_np); + if (rc) { + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + return rc; + } + /* 20us sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + + rc = msm_cdc_pinctrl_select_active_state(wcd938x->rst_np); + if (rc) { + dev_err(dev, "%s: wcd active state request fail!\n", + __func__); + return rc; + } + /* 20us sleep required after pulling the reset gpio to HIGH */ + usleep_range(20, 30); + + return rc; +} + +static int wcd938x_read_of_property_u32(struct device *dev, const char *name, + u32 *val) +{ + int rc = 0; + + rc = of_property_read_u32(dev->of_node, name, val); + if (rc) + dev_err(dev, "%s: Looking up %s property in node %s failed\n", + __func__, name, dev->of_node->full_name); + + return rc; +} + +static void wcd938x_dt_parse_micbias_info(struct device *dev, + struct wcd938x_micbias_setting *mb) +{ + u32 prop_val = 0; + int rc = 0; + + /* MB1 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv", + NULL)) { + rc = wcd938x_read_of_property_u32(dev, + "qcom,cdc-micbias1-mv", + &prop_val); + if (!rc) + mb->micb1_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias1 DT property not found\n", + __func__); + } + + /* MB2 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias2-mv", + NULL)) { + rc = wcd938x_read_of_property_u32(dev, + "qcom,cdc-micbias2-mv", + &prop_val); + if (!rc) + mb->micb2_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias2 DT property not found\n", + __func__); + } + + /* MB3 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias3-mv", + NULL)) { + rc = wcd938x_read_of_property_u32(dev, + "qcom,cdc-micbias3-mv", + &prop_val); + if (!rc) + mb->micb3_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias3 DT property not found\n", + __func__); + } +} + +static int wcd938x_reset_low(struct device *dev) +{ + struct wcd938x_priv *wcd938x = NULL; + int rc = 0; + + if (!dev) + return -ENODEV; + + wcd938x = dev_get_drvdata(dev); + if (!wcd938x) + return -EINVAL; + + if (!wcd938x->rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + rc = msm_cdc_pinctrl_select_sleep_state(wcd938x->rst_np); + if (rc) { + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + return rc; + } + /* 20us sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + + return rc; +} + +struct wcd938x_pdata *wcd938x_populate_dt_data(struct device *dev) +{ + struct wcd938x_pdata *pdata = NULL; + + pdata = devm_kzalloc(dev, sizeof(struct wcd938x_pdata), + GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->rst_np = of_parse_phandle(dev->of_node, + "qcom,wcd-rst-gpio-node", 0); + + if (!pdata->rst_np) { + dev_err(dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,wcd-rst-gpio-node", + dev->of_node->full_name); + return NULL; + } + + /* Parse power supplies */ + msm_cdc_get_power_supplies(dev, &pdata->regulator, + &pdata->num_supplies); + if (!pdata->regulator || (pdata->num_supplies <= 0)) { + dev_err(dev, "%s: no power supplies defined for codec\n", + __func__); + return NULL; + } + + pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-swr-slave", 0); + pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-swr-slave", 0); + + wcd938x_dt_parse_micbias_info(dev, &pdata->micbias); + + return pdata; +} + +static int wcd938x_bind(struct device *dev) +{ + int ret = 0, i = 0; + struct wcd938x_pdata *pdata = dev_get_platdata(dev); + struct wcd938x_priv *wcd938x = dev_get_drvdata(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, wcd938x); + if (ret) { + dev_err(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + return ret; + } + + wcd938x->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave); + if (!wcd938x->rx_swr_dev) { + dev_err(dev, "%s: Could not find RX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + + wcd938x->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave); + if (!wcd938x->tx_swr_dev) { + dev_err(dev, "%s: Could not find TX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + + wcd938x->regmap = devm_regmap_init_swr(wcd938x->tx_swr_dev, + &wcd938x_regmap_config); + if (!wcd938x->regmap) { + dev_err(dev, "%s: Regmap init failed\n", + __func__); + goto err; + } + + /* Set all interupts as edge triggered */ + for (i = 0; i < wcd938x_regmap_irq_chip.num_regs; i++) + regmap_write(wcd938x->regmap, + (WCD938X_DIGITAL_INTR_LEVEL_0 + i), 0); + + wcd938x_regmap_irq_chip.irq_drv_data = wcd938x; + wcd938x->irq_info.wcd_regmap_irq_chip = &wcd938x_regmap_irq_chip; + wcd938x->irq_info.codec_name = "WCD938X"; + wcd938x->irq_info.regmap = wcd938x->regmap; + wcd938x->irq_info.dev = dev; + ret = wcd_irq_init(&wcd938x->irq_info, &wcd938x->virq); + + if (ret) { + dev_err(wcd938x->dev, "%s: IRQ init failed: %d\n", + __func__, ret); + goto err; + } + wcd938x->tx_swr_dev->slave_irq = wcd938x->virq; + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x, + NULL, 0); + if (ret) { + dev_err(dev, "%s: Codec registration failed\n", + __func__); + goto err_irq; + } + + return ret; +err_irq: + wcd_irq_exit(&wcd938x->irq_info, wcd938x->virq); +err: + component_unbind_all(dev, wcd938x); + return ret; +} + +static void wcd938x_unbind(struct device *dev) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); + + wcd_irq_exit(&wcd938x->irq_info, wcd938x->virq); + snd_soc_unregister_component(dev); + component_unbind_all(dev, wcd938x); +} + +static const struct of_device_id wcd938x_dt_match[] = { + { .compatible = "qcom,wcd938x-codec" }, + {} +}; + +static const struct component_master_ops wcd938x_comp_ops = { + .bind = wcd938x_bind, + .unbind = wcd938x_unbind, +}; + +static int wcd938x_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void wcd938x_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int wcd938x_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-swr-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, + wcd938x_release_of, + wcd938x_compare_of, + rx_node); + + tx_node = of_parse_phandle(np, "qcom,tx-swr-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, + wcd938x_release_of, + wcd938x_compare_of, + tx_node); + return 0; +} + +static int wcd938x_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct wcd938x_priv *wcd938x = NULL; + struct wcd938x_pdata *pdata = NULL; + int ret; + + wcd938x = devm_kzalloc(&pdev->dev, sizeof(struct wcd938x_priv), + GFP_KERNEL); + if (!wcd938x) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, wcd938x); + + pdata = wcd938x_populate_dt_data(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "%s: Fail to obtain platform data\n", __func__); + return -EINVAL; + } + dev->platform_data = pdata; + + wcd938x->rst_np = pdata->rst_np; + ret = msm_cdc_init_supplies(&pdev->dev, &wcd938x->supplies, + pdata->regulator, pdata->num_supplies); + if (!wcd938x->supplies) { + dev_err(&pdev->dev, "%s: Cannot init wcd supplies\n", + __func__); + return ret; + } + + wcd938x->handle = (void *)pdata->handle; + if (!wcd938x->handle) { + dev_err(dev, "%s: handle is NULL\n", __func__); + return -EINVAL; + } + + wcd938x->update_wcd_event = pdata->update_wcd_event; + if (!wcd938x->update_wcd_event) { + dev_err(dev, "%s: update_wcd_event api is null!\n", + __func__); + return -EINVAL; + } + wcd938x->register_notifier = pdata->register_notifier; + if (!wcd938x->register_notifier) { + dev_err(dev, "%s: register_notifier api is null!\n", + __func__); + return -EINVAL; + } + + ret = msm_cdc_enable_static_supplies(&pdev->dev, wcd938x->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(&pdev->dev, "%s: wcd static supply enable failed!\n", + __func__); + return ret; + } + + ret = wcd938x_parse_port_mapping(&pdev->dev, "qcom,rx_swr_ch_map", + CODEC_RX); + ret |= wcd938x_parse_port_mapping(&pdev->dev, "qcom,tx_swr_ch_map", + CODEC_TX); + + if (ret) { + dev_err(&pdev->dev, "Failed to read port mapping\n"); + goto err; + } + + ret = wcd938x_add_slave_components(&pdev->dev, &match); + if (ret) + goto err; + + wcd938x_reset(dev); + + return component_master_add_with_match(&pdev->dev, + &wcd938x_comp_ops, match); + +err: + return ret; +} + +static int wcd938x_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &wcd938x_comp_ops); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int wcd938x_suspend(struct device *dev) +{ + return 0; +} + +static int wcd938x_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops wcd938x_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + wcd938x_suspend, + wcd938x_resume + ) +}; +#endif + +static struct platform_driver wcd938x_codec_driver = { + .probe = wcd938x_probe, + .remove = wcd938x_remove, + .driver = { + .name = "wcd938x_codec", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wcd938x_dt_match), +#ifdef CONFIG_PM_SLEEP + .pm = &wcd938x_dev_pm_ops, +#endif + }, +}; + +module_platform_driver(wcd938x_codec_driver); +MODULE_DESCRIPTION("WCD938X Codec driver"); +MODULE_LICENSE("GPL v2"); From 4d31c00084f0e7782dba4a61565cd30737b9c37a Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Fri, 7 Dec 2018 01:23:01 +0530 Subject: [PATCH 2/3] asoc: wcd938x: Move APIs from internal header file Move APIs from internal header file for access to other audio modules. Change-Id: Ib34d052e4beb63c6805abacc3c99dbff18c9af6c Signed-off-by: Sudheer Papothi --- asoc/codecs/wcd938x/internal.h | 2 -- asoc/codecs/wcd938x/wcd938x.h | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 asoc/codecs/wcd938x/wcd938x.h diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h index 4811bd0f4ad0..71528c71d6ad 100644 --- a/asoc/codecs/wcd938x/internal.h +++ b/asoc/codecs/wcd938x/internal.h @@ -177,6 +177,4 @@ extern int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, extern int wcd938x_get_micb_vout_ctl_val(u32 micb_mv); extern int wcd938x_micbias_control(struct snd_soc_component *component, int micb_num, int req, bool is_dapm); -extern int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root, - struct snd_soc_component *component); #endif /* _WCD938X_INTERNAL_H */ diff --git a/asoc/codecs/wcd938x/wcd938x.h b/asoc/codecs/wcd938x/wcd938x.h new file mode 100644 index 000000000000..12b5f1a12686 --- /dev/null +++ b/asoc/codecs/wcd938x/wcd938x.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _WCD938X_H +#define _WCD938X_H + +#ifdef CONFIG_SND_SOC_WCD938X +extern int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component); +#else +extern int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD938X */ +#endif /* _WCD938X_H */ From d1c3e9b51e0b7d36cb1d1cf339fa46ecdceb0b89 Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Wed, 5 Sep 2018 05:43:51 +0530 Subject: [PATCH 3/3] ASoC: wcd938x: Add support for codec wakeup Add an API to wakeup codec from sleep. Change-Id: I90de653947f794cbc4a47a91bd5f22251440ef75 Signed-off-by: Sudheer Papothi --- asoc/codecs/wcd938x/internal.h | 2 +- asoc/codecs/wcd938x/wcd938x.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h index 71528c71d6ad..616a2eaff85e 100644 --- a/asoc/codecs/wcd938x/internal.h +++ b/asoc/codecs/wcd938x/internal.h @@ -79,7 +79,6 @@ struct wcd938x_priv { struct codec_port_info rx_port_mapping[MAX_PORT][MAX_CH_PER_PORT]; struct regulator_bulk_data *supplies; - struct notifier_block nblock; /* wcd callback to bolero */ void *handle; @@ -87,6 +86,7 @@ struct wcd938x_priv { int (*register_notifier)(void *handle, struct notifier_block *nblock, bool enable); + int (*wakeup)(void *handle, bool enable); u32 version; /* Entry for version info */ struct snd_info_entry *entry; diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index 2905c59e19bc..40136e43181d 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -2578,6 +2578,25 @@ static int wcd938x_add_slave_components(struct device *dev, return 0; } +static int wcd938x_wakeup(void *handle, bool enable) +{ + struct wcd938x_priv *priv; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + priv = (struct wcd938x_priv *)handle; + if (!priv->tx_swr_dev) { + pr_err("%s: tx swr dev is NULL\n", __func__); + return -EINVAL; + } + if (enable) + return swr_device_wakeup_vote(priv->tx_swr_dev); + else + return swr_device_wakeup_unvote(priv->tx_swr_dev); +} + static int wcd938x_probe(struct platform_device *pdev) { struct component_match *match = NULL; @@ -2652,6 +2671,8 @@ static int wcd938x_probe(struct platform_device *pdev) wcd938x_reset(dev); + wcd938x->wakeup = wcd938x_wakeup; + return component_master_add_with_match(&pdev->dev, &wcd938x_comp_ops, match);