diff --git a/qcom/opensource/audio-kernel/Android.bp b/qcom/opensource/audio-kernel/Android.bp new file mode 100644 index 0000000000..91c4d60020 --- /dev/null +++ b/qcom/opensource/audio-kernel/Android.bp @@ -0,0 +1,43 @@ +headers_src = [ + "include/uapi/audio/*/**/*.h", +] + +audio_headers_out = [ + "linux/msm_audio.h", + "sound/audio_effects.h", + "sound/audio_slimslave.h", + "sound/devdep_params.h", + "sound/lsm_params.h", + "sound/msmcal-hwdep.h", + "sound/voice_params.h", + "sound/wcd-dsp-glink.h", + "linux/msm_audio_calibration.h", +] + +audio_kernel_headers_verbose = "--verbose " +genrule { + name: "qti_generate_audio_kernel_headers", + tools: ["headers_install.sh", + "unifdef" + ], + tool_files: [ + "audio_kernel_headers.py", + ], + srcs: headers_src, + cmd: "python3 -u $(location audio_kernel_headers.py) " + + audio_kernel_headers_verbose + + "--header_arch arm64 " + + "--gen_dir $(genDir) " + + "--audio_include_uapi $(locations include/uapi/audio/*/**/*.h) " + + "--unifdef $(location unifdef) " + + "--headers_install $(location headers_install.sh)", + out: audio_headers_out, +} + +cc_library_headers { + name: "qti_audio_kernel_uapi", + generated_headers: ["qti_generate_audio_kernel_headers"], + export_generated_headers: ["qti_generate_audio_kernel_headers"], + vendor: true, + recovery_available: true +} diff --git a/qcom/opensource/audio-kernel/Android.mk b/qcom/opensource/audio-kernel/Android.mk new file mode 100644 index 0000000000..c495ffe8db --- /dev/null +++ b/qcom/opensource/audio-kernel/Android.mk @@ -0,0 +1,575 @@ +# Android makefile for audio kernel modules + +LOCAL_PATH := $(call my-dir) + +ifeq ($(call is-board-platform-in-list,taro),true) +AUDIO_SELECT := CONFIG_SND_SOC_WAIPIO=m +endif + +ifeq ($(call is-board-platform-in-list,kalama),true) +AUDIO_SELECT := CONFIG_SND_SOC_KALAMA=m +endif + +ifeq ($(call is-board-platform-in-list,bengal),true) +AUDIO_SELECT := CONFIG_SND_SOC_BENGAL=m +endif + +ifeq ($(call is-board-platform-in-list,holi blair),true) +AUDIO_SELECT := CONFIG_SND_SOC_HOLI=m +endif + +ifeq ($(call is-board-platform-in-list,pineapple cliffs volcano),true) +AUDIO_SELECT := CONFIG_SND_SOC_PINEAPPLE=m +endif + +ifeq ($(call is-board-platform-in-list,volcano),true) +AUDIO_SELECT := CONFIG_SND_SOC_VOLCANO=m +endif + +ifeq ($(call is-board-platform-in-list,pitti),true) +AUDIO_SELECT := CONFIG_SND_SOC_PITTI=m +endif + +ifeq ($(ENABLE_AUDIO_LEGACY_TECHPACK),true) +include $(call all-subdir-makefiles) +LOCAL_PATH := vendor/qcom/opensource/audio-kernel +endif + +# Build/Package only in case of supported target +ifeq ($(call is-board-platform-in-list,taro kalama bengal pineapple cliffs pitti holi blair gen4 msmnile niobe volcano), true) + +# This makefile is only for DLKM +ifneq ($(findstring vendor,$(LOCAL_PATH)),) + +ifneq ($(findstring opensource,$(LOCAL_PATH)),) + AUDIO_BLD_DIR := $(abspath .)/vendor/qcom/opensource/audio-kernel +endif # opensource + +include $(AUDIO_BLD_DIR)/EnableBazel.mk +DLKM_DIR := $(TOP)/device/qcom/common/dlkm + + +########################################################### +# 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=audio_dlkm +KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) +KBUILD_OPTIONS += $(AUDIO_SELECT) + +ifneq ($(call is-board-platform-in-list, bengal holi blair msmnile gen4),true) +KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(PWD)/$(call intermediates-dir-for,DLKM,msm-ext-disp-module-symvers)/Module.symvers +endif + +ifeq ($(call is-board-platform-in-list, gen4 msmnile),true) +KBUILD_OPTIONS += CONFIG_SND_SOC_AUTO=y +ifneq (,$(filter $(TARGET_BOARD_PLATFORM)$(TARGET_BOARD_SUFFIX), gen4_gvm msmnile_gvmq)) +KBUILD_OPTIONS +=CONFIG_SND_SOC_GVM=y +endif +endif + +AUDIO_SRC_FILES := \ + $(wildcard $(LOCAL_PATH)/*) \ + $(wildcard $(LOCAL_PATH)/*/*) \ + $(wildcard $(LOCAL_PATH)/*/*/*) \ + $(wildcard $(LOCAL_PATH)/*/*/*/*) + +ifneq (,$(filter $(TARGET_BOARD_PLATFORM)$(TARGET_BOARD_SUFFIX), gen4_gvm msmnile_gvmq)) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := stub_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/stub_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### ASOC MACHINE ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := machine_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/spf_machine_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### LPASS-CDC CODEC ########################### +else +########################### dsp ################################ + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := q6_notifier_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := dsp/q6_notifier_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := spf_core_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := dsp/spf_core_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := audpkt_ion_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := dsp/audpkt_ion_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := gpr_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := ipc/gpr_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := audio_pkt_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := ipc/audio_pkt_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := q6_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := dsp/q6_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := adsp_loader_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := dsp/adsp_loader_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk + +########################### ipc ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := audio_prm_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := dsp/audio_prm_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := q6_pdr_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := dsp/q6_pdr_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk + +############################ soc ############################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := pinctrl_lpi_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := soc/pinctrl_lpi_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := swr_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := soc/swr_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := swr_ctrl_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := soc/swr_ctrl_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := snd_event_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := soc/snd_event_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### ASOC CODEC ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd_core_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd_core_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := mbhc_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/mbhc_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +ifneq ($(call is-board-platform-in-list, bengal holi blair pitti),true) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := swr_dmic_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/swr_dmic_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd9xxx_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd9xxx_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +ifneq ($(call is-board-platform-in-list, bengal holi blair),true) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := swr_haptics_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/swr_haptics_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := stub_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/stub_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### ASOC MACHINE ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := machine_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/machine_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### LPASS-CDC CODEC ########################### +ifneq ($(call is-board-platform-in-list, bengal holi blair),true) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := lpass_cdc_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/lpass-cdc/lpass_cdc_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := lpass_cdc_wsa2_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/lpass-cdc/lpass_cdc_wsa2_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := lpass_cdc_wsa_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/lpass-cdc/lpass_cdc_wsa_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := lpass_cdc_va_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/lpass-cdc/lpass_cdc_va_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := lpass_cdc_tx_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/lpass-cdc/lpass_cdc_tx_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := lpass_cdc_rx_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/lpass-cdc/lpass_cdc_rx_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk + +ifneq ($(call is-board-platform-in-list, pitti),true) +########################### WSA884x CODEC ########################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wsa884x_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wsa884x/wsa884x_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk + +########################### WSA883x CODEC ########################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wsa883x_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wsa883x/wsa883x_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk + +########################### WCD937x CODEC ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd937x_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd937x/wcd937x_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd937x_slave_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd937x/wcd937x_slave_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### WCD938x CODEC ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd938x_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd938x/wcd938x_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd938x_slave_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd938x/wcd938x_slave_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### WCD939x CODEC ################################ +endif + +ifneq ($(call is-board-platform-in-list, niobe pitti),true) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd939x_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd939x/wcd939x_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd939x_slave_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd939x/wcd939x_slave_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd9378_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd9378/wcd9378_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd9378_slave_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd9378/wcd9378_slave_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif +ifeq ($(call is-board-platform-in-list, pitti),true) +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wsa881x_analog_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wsa881x_analog_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd9378_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd9378/wcd9378_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd9378_slave_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd9378/wcd9378_slave_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif +########################################################### +ifeq ($(AUDIO_DLKM_ENABLE), true) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := hdmi_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/hdmi_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +LOCAL_REQUIRED_MODULES := msm-ext-disp-module-symvers +LOCAL_ADDITIONAL_DEPENDENCIES := $(call intermediates-dir-for,DLKM,msm-ext-disp-module-symvers)/Module.symvers +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif +endif + +ifeq ($(call is-board-platform-in-list, bengal holi blair),true) +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := bolero_cdc_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/bolero/bolero_cdc_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := va_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/bolero/va_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := tx_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/bolero/tx_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := rx_macro_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/bolero/rx_macro_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wsa881x_analog_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wsa881x_analog_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################### WCD937x CODEC ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd937x_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd937x/wcd937x_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd937x_slave_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd937x/wcd937x_slave_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif + +ifeq ($(call is-board-platform-in-list,holi blair),true) +########################### WCD938x CODEC ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd938x_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd938x/wcd938x_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(AUDIO_SRC_FILES) +LOCAL_MODULE := wcd938x_slave_dlkm.ko +LOCAL_MODULE_KBUILD_NAME := asoc/codecs/wcd938x/wcd938x_slave_dlkm.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif +########################################################## +endif # DLKM check +endif # supported target check +endif diff --git a/qcom/opensource/audio-kernel/BUILD.bazel b/qcom/opensource/audio-kernel/BUILD.bazel new file mode 100644 index 0000000000..b51c92b830 --- /dev/null +++ b/qcom/opensource/audio-kernel/BUILD.bazel @@ -0,0 +1,50 @@ +package( + default_visibility = [ + "//visibility:public", + ], +) + +load("//build/kernel/kleaf:kernel.bzl", "ddk_headers") + +ddk_headers( + name = "audio_common_headers", + hdrs = glob([ + "include/asoc/*.h", + "include/bindings/*.h", + "include/dsp/*.h", + "include/ipc/*.h", + "include/soc/*.h" + ]), + includes = ["include"] +) +ddk_headers( + name = "audio_uapi_headers", + hdrs = glob([ + "include/uapi/audio/**/*.h" + ]), + includes = ["include/uapi/audio"] +) +ddk_headers( + name = "audio_src_headers", + hdrs = glob([ + "asoc/**/*.h", + "dsp/**/*.h", + "ipc/**/*.h", + "soc/**/*.h" + ]) +) +ddk_headers( + name = "audio_configs", + hdrs = glob([ + "config/*.h" + ]), + includes = ["config"] +) +ddk_headers( + name = "audio_headers", + hdrs = [":audio_common_headers", ":audio_uapi_headers", ":audio_src_headers", ":audio_configs"] +) + +load(":build/audio_target.bzl", "define_audio_target") + +define_audio_target() diff --git a/qcom/opensource/audio-kernel/EnableBazel.mk b/qcom/opensource/audio-kernel/EnableBazel.mk new file mode 100644 index 0000000000..c868d294e6 --- /dev/null +++ b/qcom/opensource/audio-kernel/EnableBazel.mk @@ -0,0 +1,153 @@ +ifeq ($(call is-board-platform-in-list,pineapple cliffs volcano),true) +LOCAL_MODULE_DDK_BUILD := true + +LOCAL_MODULE_DDK_SUBTARGET_REGEX := "$(TARGET_BOARD_PLATFORM)_audio.*" + +LOCAL_MODULE_KO_DIRS := dsp/q6_notifier_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/spf_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audpkt_ion_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/gpr_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/audio_pkt_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/adsp_loader_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audio_prm_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_pdr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/pinctrl_lpi_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_ctrl_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/snd_event_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/mbhc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/swr_dmic_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9xxx_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/swr_haptics_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/stub_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/machine_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_wsa2_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_wsa_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_va_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_tx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_rx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wsa884x/wsa884x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wsa883x/wsa883x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd937x/wcd937x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd937x/wcd937x_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd938x/wcd938x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd938x/wcd938x_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd939x/wcd939x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd939x/wcd939x_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9378/wcd9378_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9378/wcd9378_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/hdmi_dlkm.ko +endif + +ifeq ($(call is-board-platform-in-list,pitti),true) +LOCAL_MODULE_DDK_BUILD := true + +LOCAL_MODULE_DDK_SUBTARGET_REGEX := "audio.*" + +LOCAL_MODULE_KO_DIRS := dsp/q6_notifier_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/spf_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audpkt_ion_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/gpr_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/audio_pkt_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/adsp_loader_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audio_prm_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_pdr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/pinctrl_lpi_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_ctrl_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/snd_event_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/mbhc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9xxx_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/swr_haptics_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/stub_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/machine_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_wsa_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_wsa2_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_va_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_tx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_rx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wsa881x_analog_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9378/wcd9378_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9378/wcd9378_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/hdmi_dlkm.ko +endif + +ifeq ($(call is-board-platform-in-list,blair),true) +LOCAL_MODULE_DDK_BUILD := true + +LOCAL_MODULE_DDK_SUBTARGET_REGEX := "audio.*" + +LOCAL_MODULE_KO_DIRS := dsp/q6_notifier_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/spf_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audpkt_ion_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/gpr_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/audio_pkt_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/adsp_loader_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audio_prm_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_pdr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/pinctrl_lpi_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_ctrl_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/snd_event_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/mbhc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9xxx_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/stub_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/machine_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/bolero/bolero_cdc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/bolero/va_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/bolero/tx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/bolero/rx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wsa881x_analog_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd937x/wcd937x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd937x/wcd937x_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd938x/wcd938x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd938x/wcd938x_slave_dlkm.ko +endif + +ifeq ($(call is-board-platform-in-list, niobe),true) +LOCAL_MODULE_DDK_BUILD := true + +LOCAL_MODULE_DDK_SUBTARGET_REGEX := "audio.*" + +LOCAL_MODULE_KO_DIRS := dsp/q6_notifier_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/spf_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audpkt_ion_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/gpr_dlkm.ko +LOCAL_MODULE_KO_DIRS += ipc/audio_pkt_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/adsp_loader_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/audio_prm_dlkm.ko +LOCAL_MODULE_KO_DIRS += dsp/q6_pdr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/pinctrl_lpi_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/swr_ctrl_dlkm.ko +LOCAL_MODULE_KO_DIRS += soc/snd_event_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd_core_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/mbhc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/swr_dmic_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd9xxx_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/swr_haptics_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/stub_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/machine_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_wsa2_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_wsa_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_va_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_tx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/lpass-cdc/lpass_cdc_rx_macro_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wsa884x/wsa884x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wsa883x/wsa883x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd937x/wcd937x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd937x/wcd937x_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd938x/wcd938x_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/wcd938x/wcd938x_slave_dlkm.ko +LOCAL_MODULE_KO_DIRS += asoc/codecs/hdmi_dlkm.ko +endif diff --git a/qcom/opensource/audio-kernel/Kbuild b/qcom/opensource/audio-kernel/Kbuild new file mode 100644 index 0000000000..dfcc7190e9 --- /dev/null +++ b/qcom/opensource/audio-kernel/Kbuild @@ -0,0 +1 @@ +obj-y := dsp/ ipc/ soc/ asoc/ asoc/codecs/ asoc/codecs/lpass-cdc/ asoc/codecs/bolero/ asoc/codecs/wcd939x/ asoc/codecs/wsa884x/ asoc/codecs/wcd938x/ asoc/codecs/wsa883x/ asoc/codecs/wcd937x/ asoc/codecs/wcd9378/ diff --git a/qcom/opensource/audio-kernel/Makefile b/qcom/opensource/audio-kernel/Makefile new file mode 100644 index 0000000000..a26a0e1a2a --- /dev/null +++ b/qcom/opensource/audio-kernel/Makefile @@ -0,0 +1,25 @@ +ifeq ($(TARGET_SUPPORT), monaco) +KBUILD_OPTIONS := CONFIG_SND_SOC_AUTO=y +KBUILD_OPTIONS += CONFIG_SND_SOC_SA7255=m +KBUILD_OPTIONS += MODNAME=audio_dlkm +endif + +ifeq ($(AUTO_GVM), yes) +KBUILD_OPTIONS += CONFIG_SND_SOC_AUTO=y +KBUILD_OPTIONS += CONFIG_SND_SOC_GVM=y +KBUILD_OPTIONS += MODNAME=audio_dlkm +endif + +M=$(PWD) +AUDIO_ROOT=$(KERNEL_SRC)/$(M) + +KBUILD_OPTIONS+= AUDIO_ROOT=$(AUDIO_ROOT) + +all: modules + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean + +%: + $(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS) + diff --git a/qcom/opensource/audio-kernel/Makefile.am b/qcom/opensource/audio-kernel/Makefile.am new file mode 100644 index 0000000000..62f3b6f572 --- /dev/null +++ b/qcom/opensource/audio-kernel/Makefile.am @@ -0,0 +1,96 @@ +AUDIO_ROOT=$(PWD) +UAPI_OUT=$(PWD) +HEADER_INSTALL_DIR=$(KERNEL_SRC)/scripts +KERNEL_BINARY_DIR=$(KERNEL_SRC)/../kernel-build-artifacts + +KBUILD_OPTIONS := AUDIO_ROOT=$(PWD) +KBUILD_OPTIONS += MODNAME=audio +KBUILD_OPTIONS += UAPI_OUT=$(PWD) + +AUDIO_KERNEL_HEADERS_PATH1 = $(shell ls ./include/uapi/audio/linux/*.h) +AUDIO_KERNEL_HEADERS_PATH2 = $(shell ls ./include/uapi/audio/linux/mfd/wcd9xxx/*.h) +AUDIO_KERNEL_HEADERS_PATH3 = $(shell ls ./include/uapi/audio/sound/*.h) + +ifeq ($(TARGET_SUPPORT),qcs40x) +KBUILD_OPTIONS += CONFIG_ARCH_QCS405=y +endif +ifeq ($(TARGET_SUPPORT), sdmsteppe) +KBUILD_OPTIONS += CONFIG_ARCH_SM6150=y +endif +ifeq ($(TARGET_SUPPORT), sdxlemur)) +KBUILD_OPTIONS += CONFIG_ARCH_SDXLEMUR=y +endif + +subdir-ccflags-y += -I$(AUDIO_ROOT)/include/uapi/ + +subdir-ccflags-y += -I$(AUDIO_ROOT)/include/uapi/ + +obj-m := ipc/ +obj-m += dsp/ +obj-m += soc/ +obj-m += asoc/ +obj-m += asoc/codecs/ +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sdmsteppe sdxlemur)) +obj-m += asoc/codecs/wcd934x/ +endif +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), qcs40x)) +obj-m += asoc/codecs/bolero/ +obj-m += asoc/codecs/csra66x0/ +obj-m += asoc/codecs/ep92/ +endif +ifeq ($(TARGET_SUPPORT), sdmsteppe) +obj-m += asoc/codecs/bolero/ +obj-m += asoc/codecs/wcd937x/ +endif + +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sa8155 sa8155ivi sa6155 sa8195 qtiquingvm)) +KBUILD_OPTIONS += CONFIG_SND_SOC_AUTO=y +obj-m := ipc/ +obj-m += dsp/ +obj-m += asoc/ +obj-m += asoc/codecs/ +obj-m += soc/ +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sa8155 sa8155ivi sa8195 qtiquingvm)) +KBUILD_OPTIONS += CONFIG_SND_SOC_SA8155=m +endif +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sa6155)) +KBUILD_OPTIONS += CONFIG_SND_SOC_SA6155=m +endif +endif + +define PROCESS_HEADERS + $(foreach name,$(1),$(shell cd $(KERNEL_BINARY_DIR) && $(KERNEL_SRC)/scripts/headers_install.sh $(2)$(name) $(3)$(name))) +endef + +all: + $(shell rm -fr $(shell pwd)/soc/core.h) + $(shell ln -s $(KERNEL_SRC)/drivers/pinctrl/core.h $(shell pwd)/soc/core.h) + $(shell rm -fr $(shell pwd)/include/soc/internal.h) + $(shell ln -s $(KERNEL_SRC)/drivers/base/regmap/internal.h $(shell pwd)/include/soc/internal.h) + $(shell rm -fr $(shell pwd)/soc/pinctrl-utils.h) + $(shell ln -s $(KERNEL_SRC)/drivers/pinctrl/pinctrl-utils.h $(shell pwd)/soc/pinctrl-utils.h) + $(shell rm -fr $(shell pwd)/include/soc/qcom/secure_buffer.h) + $(shell ln -s $(KERNEL_SRC)/include/soc/qcom/secure_buffer.h $(shell pwd)/include/soc/qcom/secure_buffer.h) + $(shell mkdir $(shell pwd)/linux) + $(shell mkdir $(shell pwd)/sound) + $(shell mkdir $(shell pwd)/linux/mfd) + $(shell mkdir $(shell pwd)/linux/mfd/wcd9xxx) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/, $(UAPI_OUT)/linux/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/, $(UAPI_OUT)/linux/mfd/wcd9xxx/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/sound/*.h)), $(AUDIO_ROOT)/include/uapi/audio/sound/, $(UAPI_OUT)/sound/) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/sound) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/linux) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/linux/mfd) + $(shell mkdir $(KERNEL_BINARY_DIR)/usr/include/audio/linux/mfd/wcd9xxx) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/, $(KERNEL_BINARY_DIR)/usr/include/audio/linux/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/*.h)), $(AUDIO_ROOT)/include/uapi/audio/linux/mfd/wcd9xxx/, $(KERNEL_BINARY_DIR)/usr/include/audio/linux/mfd/wcd9xxx/) + $(call PROCESS_HEADERS, $(notdir $(shell ls $(AUDIO_ROOT)/include/uapi/audio/sound/*.h)), $(AUDIO_ROOT)/include/uapi/audio/sound/, $(KERNEL_BINARY_DIR)/usr/include/audio/sound/) + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers + rm -rf .tmp_versions diff --git a/qcom/opensource/audio-kernel/NOTICE b/qcom/opensource/audio-kernel/NOTICE new file mode 100644 index 0000000000..9ad222017a --- /dev/null +++ b/qcom/opensource/audio-kernel/NOTICE @@ -0,0 +1,24 @@ +Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 and +only version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +________________________________________ + +Copyright (C) 2008 Google, Inc. +Copyright (C) 2008 HTC Corporation +Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. + +This software is licensed under the terms of the GNU General Public +License version 2, as published by the Free Software Foundation, and +may be copied, distributed, and modified under those terms. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. diff --git a/qcom/opensource/audio-kernel/asoc/Kbuild b/qcom/opensource/audio-kernel/asoc/Kbuild new file mode 100644 index 0000000000..a40e929be5 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/Kbuild @@ -0,0 +1,347 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(CONFIG_SND_SOC_AUTO), y) + ifdef CONFIG_SND_SOC_SA8155 + include $(AUDIO_ROOT)/config/sa8155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa8155autoconf.h + endif + ifdef CONFIG_SND_SOC_SA6155 + include $(AUDIO_ROOT)/config/sa6155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa6155autoconf.h + endif + ifdef CONFIG_SND_SOC_GVM + include $(AUDIO_ROOT)/config/gvmauto.conf + INCS += -include $(AUDIO_ROOT)/config/gvmautoconf.h + endif + ifdef CONFIG_SND_SOC_SA7255 + include $(AUDIO_ROOT)/config/sa7255auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa7255autoconf.h + endif + +else +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM8150), y) + ifdef CONFIG_SND_SOC_SA8155 + include $(AUDIO_ROOT)/config/sa8155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa8155autoconf.h + else + include $(AUDIO_ROOT)/config/sm8150auto.conf + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + endif + ifeq ($(CONFIG_ARCH_SM6150), y) + ifdef CONFIG_SND_SOC_SA6155 + include $(AUDIO_ROOT)/config/sa6155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa6155autoconf.h + else + include $(AUDIO_ROOT)/config/sm6150auto.conf + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + endif + ifeq ($(CONFIG_ARCH_TRINKET), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_KALAMA), y) + include $(AUDIO_ROOT)/config/kalamaauto.conf + INCS += -include $(AUDIO_ROOT)/config/kalamaautoconf.h + endif + ifeq ($(BOARD_PLATFORM), pineapple) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.h + endif + ifeq ($(BOARD_PLATFORM), cliffs) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.h + endif + ifeq ($(BOARD_PLATFORM), volcano) + include $(AUDIO_ROOT)/config/volcanoauto.conf + INCS += -include $(AUDIO_ROOT)/config/volcanoautoconf.h + endif + ifeq ($(CONFIG_ARCH_PITTI), y) + include $(AUDIO_ROOT)/config/pittiauto.conf + INCS += -include $(AUDIO_ROOT)/config/pittiautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_KHAJE), y) + include $(AUDIO_ROOT)/config/bengalauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h + endif + ifeq ($(CONFIG_ARCH_HOLI), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_BLAIR), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_SDMSHRIKE), y) + ifdef CONFIG_SND_SOC_SA8155 + include $(AUDIO_ROOT)/config/sa8155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa8155autoconf.h + else + include $(AUDIO_ROOT)/config/sm8150auto.conf + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + endif + ifeq ($(CONFIG_ARCH_QCS405), y) + include $(AUDIO_ROOT)/config/qcs405auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/qcs405autoconf.h + endif + ifeq ($(CONFIG_QTI_QUIN_GVM), y) + include $(AUDIO_ROOT)/config/gvmauto.conf + INCS += -include $(AUDIO_ROOT)/config/gvmautoconf.h + endif + ifeq ($(CONFIG_ARCH_SDXLEMUR), y) + include $(AUDIO_ROOT)/config/sdxlemurauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdxlemurautoconf.h + endif +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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ ASoC Drivers ############ + +MACHINE_OBJS += msm_common.o + +# for SM8150 sound card driver +ifdef CONFIG_SND_SOC_SM8150 + MACHINE_OBJS += sm8150.o + MACHINE_OBJS += machine_815x_init.o +endif + +# for SM6150 sound card driver +ifdef CONFIG_SND_SOC_SM6150 + MACHINE_OBJS += sm6150.o + MACHINE_OBJS += machine_615x_init.o +endif + +# For sa6155 sound card driver +ifdef CONFIG_SND_SOC_SA6155 + MACHINE_OBJS += sa6155.o +endif + +# for qcs405 sound card driver +ifdef CONFIG_SND_SOC_QCS405 + MACHINE_OBJS += qcs405.o +endif + +# for KONA sound card driver +ifdef CONFIG_SND_SOC_KONA + MACHINE_OBJS += kona.o +endif + +# for LAHAINA sound card driver +ifdef CONFIG_SND_SOC_LAHAINA + MACHINE_OBJS += lahaina.o +endif + +# for WAIPIO sound card driver +ifdef CONFIG_SND_SOC_WAIPIO + MACHINE_OBJS += waipio.o +endif + +# for KALAMA sound card driver +ifdef CONFIG_SND_SOC_KALAMA + MACHINE_OBJS += kalama.o +endif + +# for PINEAPPLE sound card driver +ifdef CONFIG_SND_SOC_PINEAPPLE + MACHINE_OBJS += pineapple.o +endif + +# for VOLCANO sound card driver +ifdef CONFIG_SND_SOC_VOLCANO + MACHINE_OBJS += pineapple.o +endif + +# for PITTI sound card driver +ifdef CONFIG_SND_SOC_PITTI + MACHINE_OBJS += pineapple.o +endif + +# for HOLI sound card driver +ifdef CONFIG_SND_SOC_HOLI + MACHINE_OBJS += holi.o +endif + +ifdef CONFIG_SND_SOC_LITO + MACHINE_OBJS += kona.o +endif + +# for BENGAL sound card driver +ifdef CONFIG_SND_SOC_BENGAL + MACHINE_OBJS += bengal.o +endif + +# for sa8155 sound card driver +ifdef CONFIG_SND_SOC_SA8155 + MACHINE_OBJS += sa8155.o +endif + +# for sa7255 sound card driver +ifdef CONFIG_SND_SOC_SA7255_AUTO_SPF + SPF_MACHINE_OBJS += msm_common.o + SPF_MACHINE_OBJS += auto_spf_dummy.o +endif + +ifdef CONFIG_SND_SOC_QDSP6V2 + PLATFORM_OBJS += platform_init.o +endif + +ifdef CONFIG_SND_SOC_SDX + MACHINE_OBJS += sdx-target.o +endif + +ifdef CONFIG_SND_SOC_GVM_AUTO_SPF + SPF_MACHINE_OBJS += gvm_auto_spf_dummy.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), 1) + obj-y += codecs/ +endif +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_QDSP6V2) += platform_dlkm.o +platform_dlkm-y := $(PLATFORM_OBJS) + +obj-$(CONFIG_SND_SOC_SM8150) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_SM6150) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_SA6155) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_QCS405) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_KONA) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_LAHAINA) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_WAIPIO) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_KALAMA) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_PINEAPPLE) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_VOLCANO) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_PITTI) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_HOLI) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_LITO) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_BENGAL) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_SA8155) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_SDX) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_GVM_AUTO_SPF) += spf_machine_dlkm.o +spf_machine_dlkm-y := $(SPF_MACHINE_OBJS) + +obj-$(CONFIG_SND_SOC_SA7255_AUTO_SPF) += spf_machine_dlkm.o +spf_machine_dlkm-y := $(SPF_MACHINE_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/Makefile b/qcom/opensource/audio-kernel/asoc/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/auto_spf_dummy.c b/qcom/opensource/audio-kernel/asoc/auto_spf_dummy.c new file mode 100644 index 0000000000..5e282085ff --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/auto_spf_dummy.c @@ -0,0 +1,1704 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_dailink.h" +#include "msm_common.h" + + +#define DRV_NAME "spf-asoc-snd" +#define DRV_PINCTRL_NAME "audio-pcm-pinctrl" + +#define __CHIPSET__ "SA8xx5 " +#define MSM_DAILINK_NAME(name) (__CHIPSET__#name) + +#ifdef CONFIG_MSM_COUPLED_SSR +enum subsys_state { + SUBSYS_DOWN = 0, + SUBSYS_UP = 1 +}; + +enum subsys_doamin { + SUBSYS_DOMAIN_ADSP = 0, + SUBSYS_DOMAIN_MDSP, + SUBSYS_DOMAIN_MAX +}; + +static struct dsps_state_t { + struct mutex lock; + enum subsys_state states[SUBSYS_DOMAIN_MAX]; +} dsps_state; +#endif + + +enum pinctrl_pin_state { + STATE_SLEEP = 0, /* All pins are in sleep state */ + STATE_ACTIVE, /* TDM = active */ +}; + +struct msm_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *sleep; + struct pinctrl_state *active; + enum pinctrl_pin_state curr_state; +}; + +static const char *const pin_states[] = {"sleep", "active"}; + +static const char *const tdm_gpio_phandle[] = {"qcom,pri-tdm-gpios", + "qcom,sec-tdm-gpios", + "qcom,tert-tdm-gpios", + "qcom,quat-tdm-gpios", + "qcom,quin-tdm-gpios", + "qcom,sen-tdm-gpios", + "qcom,sep-tdm-gpios", + "qcom,oct-tdm-gpios", + "qcom,hsif0-tdm-gpios", + "qcom,hsif1-tdm-gpios", + "qcom,hsif2-tdm-gpios", + }; + +static const char *const mclk_gpio_phandle[] = { "qcom,internal-mclk1-gpios" }; + +enum { + TDM_PRI = 0, + TDM_SEC, + TDM_TERT, + TDM_QUAT, + TDM_QUIN, + TDM_SEN, + TDM_SEP, + TDM_OCT, + TDM_HSIF0, + TDM_HSIF1, + TDM_HSIF2, + TDM_INTERFACE_MAX, +}; + +enum { + IDX_PRIMARY_TDM_RX_0, + IDX_PRIMARY_TDM_TX_0, + IDX_SECONDARY_TDM_RX_0, + IDX_SECONDARY_TDM_TX_0, + IDX_TERTIARY_TDM_RX_0, + IDX_TERTIARY_TDM_TX_0, + IDX_QUATERNARY_TDM_RX_0, + IDX_QUATERNARY_TDM_TX_0, + IDX_QUINARY_TDM_RX_0, + IDX_QUINARY_TDM_TX_0, + IDX_SENARY_TDM_RX_0, + IDX_SENARY_TDM_TX_0, + IDX_SEPTENARY_TDM_RX_0, + IDX_SEPTENARY_TDM_TX_0, + IDX_OCTONARY_TDM_RX_0, + IDX_OCTONARY_TDM_TX_0, + IDX_HSIF0_TDM_RX_0, + IDX_HSIF0_TDM_TX_0, + IDX_HSIF1_TDM_RX_0, + IDX_HSIF1_TDM_TX_0, + IDX_HSIF2_TDM_RX_0, + IDX_HSIF2_TDM_TX_0, + IDX_HSIF3_TDM_RX_0, + IDX_HSIF3_TDM_TX_0, + IDX_HSIF4_TDM_RX_0, + IDX_HSIF4_TDM_TX_0, + IDX_QUATERNARY_TDM_RX_DUMMY_0, + IDX_QUATERNARY_TDM_TX_DUMMY_0, + IDX_QUINARY_TDM_RX_DUMMY_0, + IDX_QUINARY_TDM_TX_DUMMY_0, + IDX_GROUP_TDM_MAX, +}; + +enum msm_mclk_index { + MCLK_NONE = -1, + MCLK1 = 0, + MCLK_MAX, +}; + +enum msm_mclk_status { + MCLK_DISABLED = 0, + MCLK_ENABLED, +}; + +struct msm_mclk_conf { + struct mutex lock; + enum msm_mclk_status mclk_status; +}; + +struct tdm_conf { + struct mutex lock; + u32 ref_cnt; +}; + +struct msm_asoc_mach_data { + struct msm_common_pdata *common_pdata; + struct tdm_conf tdm_intf_conf[TDM_INTERFACE_MAX]; + struct msm_pinctrl_info pinctrl_info[TDM_INTERFACE_MAX]; + bool mclk_used; + struct msm_pinctrl_info mclk_pinctrl_info[MCLK_MAX]; + struct msm_mclk_conf mclk_conf[MCLK_MAX]; + struct snd_pcm_hardware hw_params; +}; + +static struct platform_device *spdev; + +static struct clk_cfg internal_mclk[MCLK_MAX] = { + { + CLOCK_ID_MCLK_1, + IBIT_CLOCK_12_P288_MHZ, + CLOCK_ATTRIBUTE_COUPLE_NO, + CLOCK_ROOT_DEFAULT, + } +}; + +struct snd_soc_card sa8155_snd_soc_card_auto_msm = { + .name = "sa8155-adp-star-snd-card", +}; + +struct snd_soc_card sa8295_snd_soc_card_auto_msm = { + .name = "sa8295-adp-star-snd-card", +}; + +struct snd_soc_card sa8255_snd_soc_card_auto_msm = { + .name = "sa8255-adp-star-snd-card", +}; + +struct snd_soc_card sa7255_snd_soc_card_auto_msm = { + .name = "sa7255-adp-star-snd-card", +}; + +/* FIXME: it may various on different platform, + * better to move to dt configuration in future + */ +static enum msm_mclk_index msm_get_mclk_index(int intf_idx) +{ + switch (intf_idx) { +/* for sa8255 */ +#ifdef CONFIG_SND_SOC_SA8255_AUTO_SPF + case TDM_HSIF2: + return MCLK1; +#endif +/* for sa7255 */ +#ifdef CONFIG_SND_SOC_SA7255_AUTO_SPF + case TDM_HSIF0: + return MCLK1; +#endif + + default: return MCLK_NONE; + } + + return MCLK_NONE; +} + +static int msm_tdm_get_intf_idx(u16 id) +{ + switch (id) { + case IDX_PRIMARY_TDM_RX_0: + case IDX_PRIMARY_TDM_TX_0: + return TDM_PRI; + case IDX_SECONDARY_TDM_RX_0: + case IDX_SECONDARY_TDM_TX_0: + return TDM_SEC; + case IDX_TERTIARY_TDM_RX_0: + case IDX_TERTIARY_TDM_TX_0: + return TDM_TERT; + case IDX_QUATERNARY_TDM_RX_0: + case IDX_QUATERNARY_TDM_TX_0: + case IDX_QUATERNARY_TDM_RX_DUMMY_0: + case IDX_QUATERNARY_TDM_TX_DUMMY_0: + return TDM_QUAT; + case IDX_QUINARY_TDM_RX_0: + case IDX_QUINARY_TDM_TX_0: + case IDX_QUINARY_TDM_RX_DUMMY_0: + case IDX_QUINARY_TDM_TX_DUMMY_0: + return TDM_QUIN; + case IDX_SENARY_TDM_RX_0: + case IDX_SENARY_TDM_TX_0: + return TDM_SEN; + case IDX_SEPTENARY_TDM_RX_0: + case IDX_SEPTENARY_TDM_TX_0: + return TDM_SEP; + case IDX_OCTONARY_TDM_RX_0: + case IDX_OCTONARY_TDM_TX_0: + return TDM_OCT; + case IDX_HSIF0_TDM_RX_0: + case IDX_HSIF0_TDM_TX_0: + return TDM_HSIF0; + case IDX_HSIF1_TDM_RX_0: + case IDX_HSIF1_TDM_TX_0: + return TDM_HSIF1; + case IDX_HSIF2_TDM_RX_0: + case IDX_HSIF2_TDM_TX_0: + return TDM_HSIF2; + case IDX_HSIF3_TDM_RX_0: + case IDX_HSIF3_TDM_TX_0: + return TDM_SEC; //muxed + case IDX_HSIF4_TDM_RX_0: + case IDX_HSIF4_TDM_TX_0: + return TDM_TERT; //muxed + + default: return -EINVAL; + } +} + +#ifdef CONFIG_MSM_COUPLED_SSR +static void set_subsys_state_l(enum subsys_doamin subsys, + enum subsys_state state) +{ + dsps_state.states[subsys] = state; +} + +static void set_combined_subsystem_state_l(enum subsys_state state) +{ + int i; + + for (i = 0; i < SUBSYS_DOMAIN_MAX; i++) + dsps_state.states[i] = state; +} + +static enum subsys_state get_combined_dsps_state_l(void) +{ + int i; + + for (i = 0; i < SUBSYS_DOMAIN_MAX; i++) { + if (!dsps_state.states[i]) + return SUBSYS_DOWN; + } + return SUBSYS_UP; +} + +static int modem_notifier_service_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + pr_info("%s: modem pdr service opcode 0x%lx\n", __func__, opcode); + switch (opcode) { + case AUDIO_NOTIFIER_SERVICE_DOWN: + mutex_lock(&dsps_state.lock); + if (get_combined_dsps_state_l() == SUBSYS_UP) { + set_combined_subsystem_state_l(SUBSYS_DOWN); + pr_info("%s: setting snd_card to ONLINE\n", __func__); + snd_card_notify_user(SND_CARD_STATUS_OFFLINE); + } + mutex_unlock(&dsps_state.lock); + break; + case AUDIO_NOTIFIER_SERVICE_UP: + mutex_lock(&dsps_state.lock); + set_subsys_state_l(SUBSYS_DOMAIN_MDSP, SUBSYS_UP); + if (get_combined_dsps_state_l() == SUBSYS_UP) { + pr_info("%s: setting snd_card to ONLINE\n", __func__); + snd_card_notify_user(SND_CARD_STATUS_ONLINE); + } + mutex_unlock(&dsps_state.lock); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block modem_service_nb = { + .notifier_call = modem_notifier_service_cb, + .priority = 0, +}; +#endif + +static int auto_adsp_ssr_enable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + int ret = 0; + + if (!card) { + dev_err(dev, "%s: card is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + +#ifdef CONFIG_MSM_COUPLED_SSR + mutex_lock(&dsps_state.lock); + set_subsys_state_l(SUBSYS_DOMAIN_ADSP, SUBSYS_UP); + if (get_combined_dsps_state_l() == SUBSYS_UP) { + dev_dbg(dev, "%s: setting snd_card to ONLINE\n", __func__); + snd_card_notify_user(SND_CARD_STATUS_ONLINE); + } + mutex_unlock(&dsps_state.lock); +#else + dev_dbg(dev, "%s: setting snd_card to ONLINE\n", __func__); + snd_card_notify_user(SND_CARD_STATUS_ONLINE); +#endif + +err: + return ret; +} + +static void auto_adsp_ssr_disable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + + if (!card) { + dev_err(dev, "%s: card is NULL\n", __func__); + return; + } + +#ifdef CONFIG_MSM_COUPLED_SSR + mutex_lock(&dsps_state.lock); + if (get_combined_dsps_state_l() == SUBSYS_UP) { + set_combined_subsystem_state_l(SUBSYS_DOWN); + dev_dbg(dev, "%s: setting snd_card to OFFLINE\n", __func__); + snd_card_notify_user(SND_CARD_STATUS_OFFLINE); + } + mutex_unlock(&dsps_state.lock); +#else + dev_dbg(dev, "%s: setting snd_card to OFFLINE\n", __func__); + snd_card_notify_user(SND_CARD_STATUS_OFFLINE); +#endif +} + +static const struct snd_event_ops auto_adsp_ssr_ops = { + .enable = auto_adsp_ssr_enable, + .disable = auto_adsp_ssr_disable, +}; + + +static int msm_audio_ssr_compare(struct device *dev, void *data) +{ + struct device_node *node = data; + + dev_dbg(dev, "%s: dev->of_node = 0x%p, node = 0x%p\n", + __func__, dev->of_node, node); + return (dev->of_node && dev->of_node == node); +} + +static int msm_audio_adsp_ssr_register(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct snd_event_clients *ssr_clients = NULL; + struct device_node *node = NULL; + int ret = 0; + int i = 0; + + for (i = 0; ; i++) { + node = of_parse_phandle(np, "qcom,msm_audio_ssr_devs", i); + if (!node) + break; + snd_event_mstr_add_client(&ssr_clients, + msm_audio_ssr_compare, node); + } + + ret = snd_event_master_register(dev, &auto_adsp_ssr_ops, + ssr_clients, NULL); + if (!ret) + snd_event_notify(dev, SND_EVENT_UP); + + return ret; +} + +static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info, + enum pinctrl_pin_state new_state) +{ + int ret = 0; + int curr_state = 0; + + if (pinctrl_info == NULL) { + pr_err("%s: pinctrl info is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + if (pinctrl_info->pinctrl == NULL) { + pr_err("%s: pinctrl handle is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + curr_state = pinctrl_info->curr_state; + pinctrl_info->curr_state = new_state; + pr_debug("%s: curr_state = %s new_state = %s\n", __func__, + pin_states[curr_state], pin_states[pinctrl_info->curr_state]); + + if (curr_state == pinctrl_info->curr_state) { + pr_err("%s: pin already in same state\n", __func__); + goto err; + } + + if (curr_state != STATE_SLEEP && + pinctrl_info->curr_state != STATE_SLEEP) { + pr_err("%s: pin state is already active, cannot switch\n", + __func__); + ret = -EIO; + goto err; + } + switch (pinctrl_info->curr_state) { + case STATE_ACTIVE: + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->active); + if (ret) { + pr_err("%s: state select to active failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + break; + case STATE_SLEEP: + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->sleep); + if (ret) { + pr_err("%s: state select to sleep failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + break; + default: + pr_err("%s: pin state is invalid\n", __func__); + return -EINVAL; + } + +err: + return ret; +} + + +static int msm_mclk_disable(struct snd_soc_card *card, + enum msm_mclk_index index) +{ + struct msm_asoc_mach_data *pdata = NULL; + struct msm_pinctrl_info *pinctrl_info = NULL; + int ret = 0; + + if (!card) { + pr_err("%s: failed to get snd card!\n", __func__); + return -EINVAL; + } + + pdata = snd_soc_card_get_drvdata(card); + if (!pdata) { + pr_err("%s: no pdata\n", __func__); + return -EINVAL; + } + if (!pdata->mclk_used) { + pr_info("%s: mclk is not used\n", __func__); + return 0; + } + + mutex_lock(&pdata->mclk_conf[index].lock); + pinctrl_info = &pdata->mclk_pinctrl_info[index]; + if (pinctrl_info && pinctrl_info->pinctrl) { + ret = msm_set_pinctrl(pinctrl_info, STATE_SLEEP); + if (ret != 0) { + pr_err("%s: set pin state to sleep for mclk[%d], failed with %d\n", + __func__, index, ret); + } + pinctrl_info->curr_state = STATE_SLEEP; + } + + if (pdata->mclk_conf[index].mclk_status == MCLK_ENABLED) { + ret = audio_prm_set_lpass_clk_cfg(&internal_mclk[index], 0); + if (ret < 0) { + pr_err("%s: audio_prm_set_lpass_clk_cfg failed to disable mclk[%d], err:%d\n", + __func__, index, ret); + } + pdata->mclk_conf[index].mclk_status = MCLK_DISABLED; + } else { + pr_info("%s: mclk[%d] already disabled\n", __func__, index); + } + mutex_unlock(&pdata->mclk_conf[index].lock); + return ret; +} + +static int msm_mclk_enable(struct snd_soc_card *card, + enum msm_mclk_index index) +{ + struct msm_asoc_mach_data *pdata = NULL; + struct msm_pinctrl_info *pinctrl_info = NULL; + int ret = 0; + + if (!card) { + pr_err("%s: failed to get snd card!\n", __func__); + return -EINVAL; + } + + pdata = snd_soc_card_get_drvdata(card); + if (!pdata) { + pr_err("%s: no pdata\n", __func__); + return -EINVAL; + } + if (!pdata->mclk_used) { + pr_info("%s: mclk is not used\n", __func__); + return 0; + } + + mutex_lock(&pdata->mclk_conf[index].lock); + if (pdata->mclk_conf[index].mclk_status == MCLK_DISABLED) { + ret = audio_prm_set_lpass_clk_cfg(&internal_mclk[index], 1); + if (ret < 0) { + pr_err("%s: audio_prm_set_lpass_clk_cfg failed to enable mclk[%d], err:%d\n", + __func__, index, ret); + } else { + pdata->mclk_conf[index].mclk_status = MCLK_ENABLED; + } + } else { + pr_info("%s: mclk[%d] already enabled\n", __func__, index); + } + + pinctrl_info = &pdata->mclk_pinctrl_info[index]; + if (pinctrl_info && pinctrl_info->pinctrl) { + ret = msm_set_pinctrl(pinctrl_info, STATE_ACTIVE); + if (ret != 0) { + pr_err("%s: set pin state to active for mclk[%d], failed with %d\n", + __func__, index, ret); + } + pinctrl_info->curr_state = STATE_ACTIVE; + } + mutex_unlock(&pdata->mclk_conf[index].lock); + return ret; +} + +static int tdm_snd_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct tdm_conf *intf_conf = NULL; + struct msm_pinctrl_info *pinctrl_info = NULL; + int ret_pinctrl = 0; + int index, mclk_index; + + if (!dai_link->no_pcm) + snd_soc_set_runtime_hwparams(substream, &pdata->hw_params); + + index = msm_tdm_get_intf_idx(dai_link->id); + if (index < 0) { + ret = -EINVAL; + pr_err("%s: DAI link id (%d) out of range\n", + __func__, dai_link->id); + goto err; + } + + if (pdata->mclk_used) { + mclk_index = msm_get_mclk_index(index); + if (mclk_index != MCLK_NONE) + msm_mclk_enable(card, mclk_index); + } + /* + * Mutex protection in case the same TDM + * interface using for both TX and RX so + * that the same clock won't be enable twice. + */ + intf_conf = &pdata->tdm_intf_conf[index]; + mutex_lock(&intf_conf->lock); + if (++intf_conf->ref_cnt == 1) { + pinctrl_info = &pdata->pinctrl_info[index]; + if (pinctrl_info->pinctrl) { + ret_pinctrl = msm_set_pinctrl(pinctrl_info, + STATE_ACTIVE); + if (ret_pinctrl) + pr_err("%s: TDM TLMM pinctrl set failed with %d\n", + __func__, ret_pinctrl); + } + } + mutex_unlock(&intf_conf->lock); + +err: + return ret; +} + +static void tdm_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = NULL; + struct tdm_conf *intf_conf = NULL; + int ret_pinctrl = 0; + int index, mclk_index; + + pr_debug("%s: substream = %s, stream = %d\n", __func__, + substream->name, substream->stream); + + index = msm_tdm_get_intf_idx(dai_link->id); + if (index < 0) { + pr_err("%s: DAI link id (%d) out of range\n", + __func__, dai_link->id); + return; + } + + if (pdata->mclk_used) { + mclk_index = msm_get_mclk_index(index); + if (mclk_index != MCLK_NONE) + msm_mclk_disable(card, mclk_index); + } + + intf_conf = &pdata->tdm_intf_conf[index]; + mutex_lock(&intf_conf->lock); + if (--intf_conf->ref_cnt == 0) { + pinctrl_info = &pdata->pinctrl_info[index]; + if (pinctrl_info->pinctrl) { + ret_pinctrl = msm_set_pinctrl(pinctrl_info, + STATE_SLEEP); + if (ret_pinctrl) + pr_err("%s: TDM TLMM pinctrl set failed with %d\n", + __func__, ret_pinctrl); + } + } + mutex_unlock(&intf_conf->lock); +} + +static const struct snd_soc_ops tdm_be_ops = { + .startup = tdm_snd_startup, + .shutdown = tdm_snd_shutdown +}; + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link msm_common_dai_links[] = { +/* BackEnd DAI Links */ +{ + .name = "LPASS_BE_AUXPCM_RX_DUMMY", + .stream_name = "AUXPCM-LPAIF-RX-PRIMARY", + .dpcm_playback = 1, + .ops = &tdm_be_ops, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_PRIMARY_TDM_RX_0, + SND_SOC_DAILINK_REG(lpass_be_auxpcm_rx_dummy), +}, +{ + .name = "LPASS_BE_AUXPCM_TX_DUMMY", + .stream_name = "AUXPCM-LPAIF-TX-PRIMARY", + .dpcm_capture = 1, + .ops = &tdm_be_ops, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_PRIMARY_TDM_TX_0, + SND_SOC_DAILINK_REG(lpass_be_auxpcm_tx_dummy), +}, +{ + .name = "SEC_TDM_RX_0", + .stream_name = "TDM-LPAIF-RX-SECONDARY", + .dpcm_playback = 1, + .ops = &tdm_be_ops, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_SECONDARY_TDM_RX_0, + SND_SOC_DAILINK_REG(sec_tdm_rx_0), +}, +{ + .name = "SEC_TDM_TX_0", + .stream_name = "TDM-LPAIF-TX-SECONDARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_SECONDARY_TDM_TX_0, + SND_SOC_DAILINK_REG(sec_tdm_tx_0), +}, +{ + .name = "TERT_TDM_RX_0", + .stream_name = "TDM-LPAIF-RX-TERTIARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_TERTIARY_TDM_RX_0, + SND_SOC_DAILINK_REG(tert_tdm_rx_0), +}, +{ + .name = "TERT_TDM_TX_0", + .stream_name = "TDM-LPAIF-TX-TERTIARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_TERTIARY_TDM_TX_0, + SND_SOC_DAILINK_REG(tert_tdm_tx_0), +}, +{ + .name = "QUAT_TDM_RX_0", + .stream_name = "TDM-LPAIF_RXTX-RX-PRIMARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUATERNARY_TDM_RX_0, + SND_SOC_DAILINK_REG(quat_tdm_rx_0), +}, +{ + .name = "QUAT_TDM_TX_0", + .stream_name = "TDM-LPAIF_RXTX-TX-PRIMARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUATERNARY_TDM_TX_0, + SND_SOC_DAILINK_REG(quat_tdm_tx_0), +}, +{ + .name = "QUIN_TDM_RX_0", + .stream_name = "TDM-LPAIF_VA-RX-PRIMARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUINARY_TDM_RX_0, + SND_SOC_DAILINK_REG(quin_tdm_rx_0), +}, +{ + .name = "QUIN_TDM_TX_0", + .stream_name = "TDM-LPAIF_VA-TX-PRIMARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUINARY_TDM_TX_0, + SND_SOC_DAILINK_REG(quin_tdm_tx_0), +}, +{ + .name = "SEN_TDM_RX_0", + .stream_name = "TDM-LPAIF_WSA-RX-PRIMARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_SENARY_TDM_RX_0, + SND_SOC_DAILINK_REG(sen_tdm_rx_0), +}, +{ + .name = "SEN_TDM_TX_0", + .stream_name = "TDM-LPAIF_WSA-TX-PRIMARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_SENARY_TDM_TX_0, + SND_SOC_DAILINK_REG(sen_tdm_tx_0), +}, +{ + .name = "SEP_TDM_RX_0", + .stream_name = "TDM-LPAIF_AUD-RX-PRIMARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_SEPTENARY_TDM_RX_0, + SND_SOC_DAILINK_REG(sep_tdm_rx_0), +}, +{ + .name = "SEP_TDM_TX_0", + .stream_name = "TDM-LPAIF_AUD-TX-PRIMARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_SEPTENARY_TDM_TX_0, + SND_SOC_DAILINK_REG(sep_tdm_tx_0), +}, +{ + .name = "OCT_TDM_RX_0", + .stream_name = "TDM-LPAIF_WSA2-RX-PRIMARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_OCTONARY_TDM_RX_0, + SND_SOC_DAILINK_REG(oct_tdm_rx_0), +}, +{ + .name = "OCT_TDM_TX_0", + .stream_name = "TDM-LPAIF_WSA2-TX-PRIMARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_OCTONARY_TDM_TX_0, + SND_SOC_DAILINK_REG(oct_tdm_tx_0), +}, +{ + .name = "HS_IF0_TDM_RX_0", + .stream_name = "TDM-LPAIF_SDR-RX-PRIMARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF0_TDM_RX_0, + SND_SOC_DAILINK_REG(hs_if0_tdm_rx_0), +}, +{ + .name = "HS_IF0_TDM_TX_0", + .stream_name = "TDM-LPAIF_SDR-TX-PRIMARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF0_TDM_TX_0, + SND_SOC_DAILINK_REG(hs_if0_tdm_tx_0), +}, +{ + .name = "HS_IF1_TDM_RX_0", + .stream_name = "TDM-LPAIF_SDR-RX-SECONDARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF1_TDM_RX_0, + SND_SOC_DAILINK_REG(hs_if1_tdm_rx_0), +}, +{ + .name = "HS_IF1_TDM_TX_0", + .stream_name = "TDM-LPAIF_SDR-TX-SECONDARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF1_TDM_TX_0, + SND_SOC_DAILINK_REG(hs_if1_tdm_tx_0), +}, +{ + .name = "HS_IF2_TDM_RX_0", + .stream_name = "TDM-LPAIF_SDR-RX-TERTIARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF2_TDM_RX_0, + SND_SOC_DAILINK_REG(hs_if2_tdm_rx_0), +}, +{ + .name = "HS_IF2_TDM_TX_0", + .stream_name = "TDM-LPAIF_SDR-TX-TERTIARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF2_TDM_TX_0, + SND_SOC_DAILINK_REG(hs_if2_tdm_tx_0), +}, +{ + .name = "HS_IF3_TDM_RX_0", + .stream_name = "TDM-LPAIF_SDR-RX-QUATERNARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF3_TDM_RX_0, + SND_SOC_DAILINK_REG(hs_if3_tdm_rx_0), +}, +{ + .name = "HS_IF3_TDM_TX_0", + .stream_name = "TDM-LPAIF_SDR-TX-QUATERNARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF3_TDM_TX_0, + SND_SOC_DAILINK_REG(hs_if3_tdm_tx_0), +}, +{ + .name = "HS_IF4_TDM_RX_0", + .stream_name = "TDM-LPAIF_SDR-RX-QUINARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF4_TDM_RX_0, + SND_SOC_DAILINK_REG(hs_if4_tdm_rx_0), +}, +{ + .name = "HS_IF4_TDM_TX_0", + .stream_name = "TDM-LPAIF_SDR-TX-QUINARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_HSIF4_TDM_TX_0, + SND_SOC_DAILINK_REG(hs_if4_tdm_tx_0), +}, +{ + .name = "QUAT_TDM_RX_0_DUMMY", + .stream_name = "TDM-LPAIF-RX-QUATERNARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUATERNARY_TDM_RX_DUMMY_0, + SND_SOC_DAILINK_REG(quat_tdm_rx_0_dummy), +}, +{ + .name = "QUAT_TDM_TX_0_DUMMY", + .stream_name = "TDM-LPAIF-TX-QUATERNARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUATERNARY_TDM_TX_DUMMY_0, + SND_SOC_DAILINK_REG(quat_tdm_tx_0_dummy), +}, +{ + .name = "QUIN_TDM_RX_0_DUMMY", + .stream_name = "TDM-LPAIF-RX-QUINARY", + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUINARY_TDM_RX_DUMMY_0, + SND_SOC_DAILINK_REG(quin_tdm_rx_0_dummy), +}, +{ + .name = "QUIN_TDM_TX_0_DUMMY", + .stream_name = "TDM-LPAIF-TX-QUINARY", + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &tdm_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = IDX_QUINARY_TDM_TX_DUMMY_0, + SND_SOC_DAILINK_REG(quin_tdm_tx_0_dummy), +}, +}; + + +static int msm_populate_dai_link_component_of_node( + struct snd_soc_card *card) +{ + int i, j, index, ret = 0; + struct device *cdev = card->dev; + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *np; + + if (!cdev) { + pr_err("%s: Sound card device memory NULL\n", __func__); + return -ENODEV; + } + + for (i = 0; i < card->num_links; i++) { + if (dai_link[i].platforms->of_node && dai_link[i].cpus->of_node) + continue; + + /* populate platform_of_node for snd card dai links + * Skip this part for dummy snd card + */ + if (0) { + if (dai_link[i].platforms->name && + !dai_link[i].platforms->of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-platform-names", + dai_link[i].platforms->name); + if (index < 0) { + pr_err("%s: No match found for platform name: %s\n index: %i cdev_of_node: %s\n", + __func__, + dai_link[i].platforms->name, + index, + cdev->of_node); + ret = index; + goto err; + } + np = of_parse_phandle(cdev->of_node, "asoc-platform", + index); + if (!np) { + pr_err("%s: retrieving phandle for platform %s, index %d failed\n", + __func__, dai_link[i].platforms->name, + index); + ret = -ENODEV; + goto err; + } + dai_link[i].platforms->of_node = np; + dai_link[i].platforms->name = NULL; + } + } + + + /* populate cpu_of_node for snd card dai links */ + if (dai_link[i].cpus->dai_name && !dai_link[i].cpus->of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-cpu-names", + dai_link[i].cpus->dai_name); + pr_err("%s: retrieving cpu_of_node for %s\n", + __func__, + dai_link[i].cpus->dai_name); + if (index >= 0) { + np = of_parse_phandle(cdev->of_node, "asoc-cpu", + index); + if (!np) { + pr_err("%s: retrieving phandle for cpu dai %s failed\n", + __func__, + dai_link[i].cpus->dai_name); + ret = -ENODEV; + goto err; + } + dai_link[i].cpus->of_node = np; + dai_link[i].cpus->dai_name = NULL; + } + } + + /* populate codec_of_node for snd card dai links */ + if (dai_link[i].num_codecs > 0) { + for (j = 0; j < dai_link[i].num_codecs; j++) { + if (dai_link[i].codecs[j].of_node || + !dai_link[i].codecs[j].name) + continue; + + index = of_property_match_string(cdev->of_node, + "asoc-codec-names", + dai_link[i].codecs[j].name); + if (index < 0) + continue; + np = of_parse_phandle(cdev->of_node, + "asoc-codec", + index); + if (!np) { + pr_err("%s: retrieving phandle for codec %s failed\n", + __func__, + dai_link[i].codecs[j].name); + ret = -ENODEV; + goto err; + } + dai_link[i].codecs[j].of_node = np; + dai_link[i].codecs[j].name = NULL; + } + } + } + +err: + return ret; +} + +static const struct of_device_id asoc_machine_of_match[] = { + { .compatible = "qcom,sa8295-asoc-snd-adp-star", + .data = "adp_star_codec"}, + { .compatible = "qcom,sa8155-asoc-snd-adp-star", + .data = "adp_star_codec"}, + { .compatible = "qcom,sa8255-asoc-snd-adp-star", + .data = "adp_star_codec"}, + { .compatible = "qcom,sa7255-asoc-snd-adp-star", + .data = "adp_star_codec"}, + {}, +}; + +static const struct of_device_id audio_pinctrl_dummy_match[] = { + { .compatible = "qcom,msm-pcm-pinctrl" }, + { }, +}; + +static struct snd_soc_dai_link msm_auto_dai_links[ + ARRAY_SIZE(msm_common_dai_links)]; + +static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) +{ + struct snd_soc_card *card = NULL; + struct snd_soc_dai_link *dailink; + int total_links; + const struct of_device_id *match; + + match = of_match_node(asoc_machine_of_match, dev->of_node); + if (!match) { + dev_err(dev, "%s: No DT match found for sound card\n", + __func__); + return NULL; + } + + if (!strcmp(match->compatible, "qcom,sa8155-asoc-snd-adp-star")) + card = &sa8155_snd_soc_card_auto_msm; + else if (!strcmp(match->compatible, "qcom,sa8295-asoc-snd-adp-star")) + card = &sa8295_snd_soc_card_auto_msm; + else if (!strcmp(match->compatible, "qcom,sa8255-asoc-snd-adp-star")) + card = &sa8255_snd_soc_card_auto_msm; + else if (!strcmp(match->compatible, "qcom,sa7255-asoc-snd-adp-star")) + card = &sa7255_snd_soc_card_auto_msm; + + total_links = ARRAY_SIZE(msm_common_dai_links); + memcpy(msm_auto_dai_links, + msm_common_dai_links, + sizeof(msm_common_dai_links)); + dailink = msm_auto_dai_links; + + if (card) { + card->dai_link = dailink; + card->num_links = total_links; + } + + return card; +} + +static int msm_get_hwparams(struct platform_device *pdev) +{ + struct snd_soc_card *card = NULL; + struct msm_asoc_mach_data *pdata = NULL; + u32 pcm_info = 0; + u32 buffer_bytes_max = 0; + u32 periods_bytes[2] = {0}; + u32 periods_count[2] = {0}; + int ret = 0; + + card = platform_get_drvdata(pdev); + if (!card) { + pr_err("%s: card is NULL\n", + __func__); + return -EINVAL; + } + pdata = snd_soc_card_get_drvdata(card); + if (!pdata) { + pr_err("%s: pdata is NULL\n", + __func__); + return -EINVAL; + } + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,hw_pcm_info", + &pcm_info); + if (ret) { + pr_err("%s: read pcm info failed\n", + __func__); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,hw_buffer_size_max", + &buffer_bytes_max); + if (ret) { + pr_err("%s: read buffer size max failed\n", + __func__); + return ret; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,hw_period_byte_size", + periods_bytes, 2); + if (ret) { + pr_err("%s: read period byte size failed\n", + __func__); + return ret; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,hw_period_count_size", + periods_count, 2); + if (ret) { + pr_err("%s: read period count size failed\n", + __func__); + return ret; + } + + pdata->hw_params.info = pcm_info; + pdata->hw_params.buffer_bytes_max = buffer_bytes_max; + pdata->hw_params.period_bytes_min = periods_bytes[0]; + pdata->hw_params.period_bytes_max = periods_bytes[1]; + pdata->hw_params.periods_min = periods_count[0]; + pdata->hw_params.periods_max = periods_count[1]; + + return ret; +} + +struct msm_common_pdata *msm_common_get_pdata(struct snd_soc_card *card) +{ + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + if (!pdata) + return NULL; + + return pdata->common_pdata; +} + +void msm_common_set_pdata(struct snd_soc_card *card, + struct msm_common_pdata *common_pdata) +{ + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + if (!pdata) + return; + + pdata->common_pdata = common_pdata; +} + +/***************************************************************************** + * pinctrl + *****************************************************************************/ +static void msm_release_pinctrl(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = NULL; + int i; + + for (i = TDM_PRI; i < TDM_INTERFACE_MAX; i++) { + pinctrl_info = &pdata->pinctrl_info[i]; + if (pinctrl_info == NULL) + continue; + if (pinctrl_info->pinctrl) { + devm_pinctrl_put(pinctrl_info->pinctrl); + pinctrl_info->pinctrl = NULL; + } + } +} + +static void msm_release_mclk_pinctrl(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = NULL; + int i; + + for (i = 0; i < MCLK_MAX; i++) { + pinctrl_info = &pdata->mclk_pinctrl_info[i]; + if (pinctrl_info == NULL) + continue; + if (pinctrl_info->pinctrl) { + devm_pinctrl_put(pinctrl_info->pinctrl); + pinctrl_info->pinctrl = NULL; + } + } +} + +static int msm_get_pinctrl(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = NULL; + struct pinctrl *pinctrl = NULL; + int i, j; + struct device_node *np = NULL; + struct platform_device *pdev_np = NULL; + int ret = 0; + + for (i = TDM_PRI; i < TDM_INTERFACE_MAX; i++) { + np = of_parse_phandle(pdev->dev.of_node, + tdm_gpio_phandle[i], 0); + if (!np) { + pr_debug("%s: device node %s is null\n", + __func__, tdm_gpio_phandle[i]); + continue; + } + + pdev_np = of_find_device_by_node(np); + if (!pdev_np) { + pr_err("%s: platform device not found\n", + __func__); + continue; + } + + pinctrl_info = &pdata->pinctrl_info[i]; + if (pinctrl_info == NULL) { + pr_err("%s: pinctrl info is null\n", + __func__); + continue; + } + + pinctrl = devm_pinctrl_get(&pdev_np->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("%s: fail to get pinctrl handle\n", + __func__); + goto err; + } + pinctrl_info->pinctrl = pinctrl; + + /* get all the states handles from Device Tree */ + pinctrl_info->sleep = pinctrl_lookup_state(pinctrl, + "default"); + if (IS_ERR(pinctrl_info->sleep)) { + pr_err("%s: could not get sleep pin state\n", + __func__); + goto err; + } + pinctrl_info->active = pinctrl_lookup_state(pinctrl, + "active"); + if (IS_ERR(pinctrl_info->active)) { + pr_err("%s: could not get active pin state\n", + __func__); + goto err; + } + + /* Reset the TLMM pins to a sleep state */ + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->sleep); + if (ret != 0) { + pr_err("%s: set pin state to sleep failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + pinctrl_info->curr_state = STATE_SLEEP; + } + return 0; + +err: + for (j = i; j >= 0; j--) { + pinctrl_info = &pdata->pinctrl_info[j]; + if (pinctrl_info == NULL) + continue; + if (pinctrl_info->pinctrl) { + devm_pinctrl_put(pinctrl_info->pinctrl); + pinctrl_info->pinctrl = NULL; + } + } + return -EINVAL; +} + +static int msm_get_mclk_pinctrl(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = NULL; + struct pinctrl *pinctrl = NULL; + int i, j; + struct device_node *np = NULL; + struct platform_device *pdev_np = NULL; + int ret = 0; + + for (i = 0; i < MCLK_MAX; i++) { + + np = of_parse_phandle(pdev->dev.of_node, + mclk_gpio_phandle[i], + 0); + if (!np) { + pr_err("%s: device node %s is null\n", + __func__, mclk_gpio_phandle[i]); + continue; + } + pdev_np = of_find_device_by_node(np); + if (!pdev_np) { + pr_err("%s: platform device not found\n", + __func__); + continue; + } + + pinctrl_info = &pdata->mclk_pinctrl_info[i]; + if (pinctrl_info == NULL) { + pr_err("%s: pinctrl info is null\n", + __func__); + continue; + } + + pinctrl = devm_pinctrl_get(&pdev_np->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("%s: fail to get pinctrl handle\n", + __func__); + goto err; + } + pinctrl_info->pinctrl = pinctrl; + /* get all the states handles from Device Tree */ + pinctrl_info->sleep = pinctrl_lookup_state(pinctrl, + "default"); + if (IS_ERR(pinctrl_info->sleep)) { + pr_err("%s: could not get sleep pin state\n", + __func__); + goto err; + } + pinctrl_info->active = pinctrl_lookup_state(pinctrl, + "active"); + if (IS_ERR(pinctrl_info->active)) { + pr_err("%s: could not get active pin state\n", + __func__); + goto err; + } + + /* Reset the mclk pins to a sleep state */ + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->sleep); + if (ret != 0) { + pr_err("%s: set pin state to sleep failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + pinctrl_info->curr_state = STATE_SLEEP; + } + return 0; + +err: + for (j = i; j >= 0; j--) { + pinctrl_info = &pdata->mclk_pinctrl_info[i]; + if (pinctrl_info == NULL) + continue; + if (pinctrl_info->pinctrl) { + devm_pinctrl_put(pinctrl_info->pinctrl); + pinctrl_info->pinctrl = NULL; + } + } + return -EINVAL; +} + +static int msm_asoc_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = NULL; + struct msm_asoc_mach_data *pdata = NULL; + int ret = 0; + const struct of_device_id *match = NULL; + + dev_err(&pdev->dev, "%s: audio_reach\n", + __func__); + + match = of_match_node(asoc_machine_of_match, pdev->dev.of_node); + if (!match) { + dev_err(&pdev->dev, "%s: No DT match found for sound card\n", + __func__); + return -EINVAL; + } + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "No platform supplied from device tree\n"); + return -EINVAL; + } + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct msm_asoc_mach_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + card = populate_snd_card_dailinks(&pdev->dev); + if (!card) { + dev_err(&pdev->dev, "%s: Card uninitialized\n", + __func__); + ret = -EINVAL; + goto err; + } + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, pdata); + + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(&pdev->dev, "parse card name failed, err:%d\n", + ret); + pr_err("%s: parse card name failed with err:%d\n", + __func__, ret); + goto err; + } + + ret = msm_populate_dai_link_component_of_node(card); + if (ret) { + ret = -EPROBE_DEFER; + goto err; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + + if (ret == -EPROBE_DEFER) { + goto err; + } else if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + pr_err("snd_soc_register_card failed (%d)\n", + ret); + goto err; + } + + msm_common_snd_init(pdev, card); + + /* Parse pinctrl info from devicetree */ + ret = msm_get_pinctrl(pdev); + if (!ret) { + pr_err("%s: pinctrl parsing successful\n", + __func__); + } else { + dev_dbg(&pdev->dev, + "%s: pinctrl parsing failed with %d\n", + __func__, ret); + ret = 0; + } + + pdata->mclk_used = false; + if (strnstr(match->compatible, "sa8295", + sizeof(match->compatible)) || + strnstr(match->compatible, "sa8255", + sizeof(match->compatible)) || + strnstr(match->compatible, "sa7255", + sizeof(match->compatible))) { + /* get mclk pinctrl info from devicetree */ + ret = msm_get_mclk_pinctrl(pdev); + if (!ret) { + pr_debug("%s: pinctrl mclk parsing successful\n", + __func__); + pdata->mclk_used = true; + } else { + dev_err(&pdev->dev, + "%s: pinctrl mclk parsing failed with %d\n", + __func__, ret); + ret = 0; + } + } + + ret = msm_get_hwparams(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: hwparams get failed with %d\n", + __func__, ret); + goto err; + } + + dev_info(&pdev->dev, "Sound card %s registered\n", + card->name); + pr_err("Sound card %s registered\n", + card->name); + spdev = pdev; + +#ifdef CONFIG_MSM_COUPLED_SSR + mutex_init(&dsps_state.lock); + ret = audio_notifier_register("auto_modem", + AUDIO_NOTIFIER_MODEM_ROOT_DOMAIN, + &modem_service_nb); + if (ret < 0) + pr_err("%s: Registration with modem PDR failed ret = %d\n", + __func__, ret); +#endif + + ret = msm_audio_adsp_ssr_register(&pdev->dev); + if (ret) + pr_err("%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + + snd_card_notify_user(SND_CARD_STATUS_ONLINE); + return 0; +err: + msm_release_mclk_pinctrl(pdev); + msm_release_pinctrl(pdev); + return ret; +} + +static int msm_asoc_machine_remove(struct platform_device *pdev) +{ + msm_release_mclk_pinctrl(pdev); + msm_release_pinctrl(pdev); + snd_event_master_deregister(&pdev->dev); +#ifdef CONFIG_MSM_COUPLED_SSR + audio_notifier_deregister("auto_modem"); + mutex_destroy(&dsps_state.lock); +#endif + return 0; +} + +static int audio_pinctrl_dummy_probe(struct platform_device *pdev) +{ + return 0; +} + +static int audio_pinctrl_dummy_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver audio_pinctrl_dummy_driver = { + .driver = { + .name = DRV_PINCTRL_NAME, + .of_match_table = audio_pinctrl_dummy_match, + .suppress_bind_attrs = true, + }, + .probe = audio_pinctrl_dummy_probe, + .remove = audio_pinctrl_dummy_remove, +}; + +static struct platform_driver asoc_machine_driver = { + .driver = { + .name = DRV_NAME, + .pm = &snd_soc_pm_ops, + .of_match_table = asoc_machine_of_match, + .suppress_bind_attrs = true, + }, + .probe = msm_asoc_machine_probe, + .remove = msm_asoc_machine_remove, +}; + +int __init auto_spf_init(void) +{ + snd_card_sysfs_init(); + platform_driver_register(&audio_pinctrl_dummy_driver); + return platform_driver_register(&asoc_machine_driver); +} + +void auto_spf_exit(void) +{ + platform_driver_unregister(&audio_pinctrl_dummy_driver); + platform_driver_unregister(&asoc_machine_driver); +} + +module_init(auto_spf_init); +module_exit(auto_spf_exit); + +MODULE_DESCRIPTION("ALSA SoC Machine Driver for SPF"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS("platform:" DRV_PINCTRL_NAME); +MODULE_DEVICE_TABLE(of, asoc_machine_of_match); +MODULE_DEVICE_TABLE(of, audio_pinctrl_dummy_match); diff --git a/qcom/opensource/audio-kernel/asoc/bengal-port-config.h b/qcom/opensource/audio-kernel/asoc/bengal-port-config.h new file mode 100644 index 0000000000..37d4f740aa --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/bengal-port-config.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _BENGAL_PORT_CONFIG +#define _BENGAL_PORT_CONFIG + +#include + +/* + * Add port configuration in the format + *{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl} + */ + +static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, + {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0}, + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0}, +}; + +static struct port_params rx_frame_params_rouleur[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, + {31, 1, 0, 0xFF, 0xFF, 4, 1, 0xFF, 0}, + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0}, +}; + + +static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, + {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0}, + {7, 9, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0}, + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 3, 0}, +}; + +/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */ +static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = { + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX1 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX2 */ + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX3 */ +}; + +static struct swr_mstr_port_map sm_port_map[] = { + {VA_MACRO, SWR_UC0, tx_frame_params_default}, + {RX_MACRO, SWR_UC0, rx_frame_params_default}, + {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, +}; + +static struct swr_mstr_port_map sm_port_map_rouleur[] = { + {VA_MACRO, SWR_UC0, tx_frame_params_default}, + {RX_MACRO, SWR_UC0, rx_frame_params_rouleur}, + {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, +}; +#endif /* _BENGAL_PORT_CONFIG */ diff --git a/qcom/opensource/audio-kernel/asoc/bengal.c b/qcom/opensource/audio-kernel/asoc/bengal.c new file mode 100644 index 0000000000..e059f0a4e6 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/bengal.c @@ -0,0 +1,1631 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "device_event.h" +#include "asoc/msm-cdc-pinctrl.h" +#include "asoc/wcd-mbhc-v2.h" +#include "codecs/wcd937x/wcd937x-mbhc.h" +#include "codecs/rouleur/rouleur-mbhc.h" +#include "codecs/wsa881x-analog.h" +#include "codecs/wcd937x/wcd937x.h" +#include "codecs/rouleur/rouleur.h" +#include "codecs/bolero/bolero-cdc.h" +#include +#include "bengal-port-config.h" +#include "msm-audio-defs.h" +#include "msm_common.h" +#include "msm_bengal_dailink.h" + +#define DRV_NAME "bengal-asoc-snd" +#define __CHIPSET__ "BENGAL " +#define MSM_DAILINK_NAME(name) (__CHIPSET__#name) + +#define WCD9XXX_MBHC_DEF_RLOADS 5 +#define WCD9XXX_MBHC_DEF_BUTTONS 8 +#define DEV_NAME_STR_LEN 32 +#define WCD_MBHC_HS_V_MAX 1600 + +#define WCN_CDC_SLIM_RX_CH_MAX 2 +#define WCN_CDC_SLIM_TX_CH_MAX 3 + +enum { + PRIM_MI2S = 0, + SEC_MI2S, + TERT_MI2S, + QUAT_MI2S, + MI2S_MAX, +}; + +struct msm_asoc_mach_data { + struct snd_info_entry *codec_root; + struct msm_common_pdata *common_pdata; + int usbc_en2_gpio; /* used by gpio driver API */ + struct device_node *dmic01_gpio_p; /* used by pinctrl API */ + struct device_node *dmic23_gpio_p; /* used by pinctrl API */ + struct device_node *mi2s_gpio_p[MI2S_MAX]; /* used by pinctrl API */ + atomic_t mi2s_gpio_ref_count[MI2S_MAX]; /* used by pinctrl API */ + struct device_node *us_euro_gpio_p; /* used by pinctrl API */ + struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */ + struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ + struct device_node *hph_en0_gpio_p; /* used by pinctrl API */ + struct device_node *fsa_handle; + u32 wsa_max_devs; +}; + +static bool va_disable; +static int msm_rx_tx_codec_init(struct snd_soc_pcm_runtime *rtd); +static int msm_int_wsa_init(struct snd_soc_pcm_runtime *rtd); + +static bool is_initial_boot; +static bool codec_reg_done; +static struct snd_soc_card snd_soc_card_bengal_msm; +static int dmic_0_1_gpio_cnt; +static int dmic_2_3_gpio_cnt; + +static void *def_wcd_mbhc_cal(void); + +/* + * Need to report LINEIN + * if R/L channel impedance is larger than 5K ohm + */ +static struct wcd_mbhc_config wcd_mbhc_cfg = { + .read_fw_bin = false, + .calibration = NULL, + .detect_extn_cable = true, + .mono_stero_detection = false, + .swap_gnd_mic = NULL, + .hs_ext_micbias = true, + .key_code[0] = KEY_MEDIA, + .key_code[1] = KEY_VOICECOMMAND, + .key_code[2] = KEY_VOLUMEUP, + .key_code[3] = KEY_VOLUMEDOWN, + .key_code[4] = 0, + .key_code[5] = 0, + .key_code[6] = 0, + .key_code[7] = 0, + .linein_th = 5000, + .moisture_en = false, + .mbhc_micbias = MIC_BIAS_2, + .anc_micbias = MIC_BIAS_2, + .enable_anc_mic_detect = false, + .moisture_duty_cycle_en = true, +}; + +static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component, + bool active) +{ + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + if (!pdata->fsa_handle) + return false; + + return fsa4480_switch_event(pdata->fsa_handle, FSA_MIC_GND_SWAP); +} + +static bool msm_swap_gnd_mic(struct snd_soc_component *component, bool active) +{ + int value = 0; + bool ret = false; + struct snd_soc_card *card; + struct msm_asoc_mach_data *pdata; + + if (!component) { + pr_err("%s component is NULL\n", __func__); + return false; + } + card = component->card; + pdata = snd_soc_card_get_drvdata(card); + + if (!pdata) + return false; + + if (wcd_mbhc_cfg.enable_usbc_analog) + return msm_usbc_swap_gnd_mic(component, active); + + /* if usbc is not defined, swap using us_euro_gpio_p */ + if (pdata->us_euro_gpio_p) { + value = msm_cdc_pinctrl_get_state( + pdata->us_euro_gpio_p); + if (value) + msm_cdc_pinctrl_select_sleep_state( + pdata->us_euro_gpio_p); + else + msm_cdc_pinctrl_select_active_state( + pdata->us_euro_gpio_p); + dev_dbg(component->dev, "%s: swap select switch %d to %d\n", + __func__, value, !value); + ret = true; + } + + return ret; +} + +static int msm_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct msm_asoc_mach_data *pdata = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + u32 dmic_idx; + int *dmic_gpio_cnt; + struct device_node *dmic_gpio; + char *wname; + + wname = strpbrk(w->name, "0123"); + if (!wname) { + dev_err(component->dev, "%s: widget not found\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(wname, 10, &dmic_idx); + if (ret < 0) { + dev_err(component->dev, "%s: Invalid DMIC line on the codec\n", + __func__); + return -EINVAL; + } + + pdata = snd_soc_card_get_drvdata(component->card); + + switch (dmic_idx) { + case 0: + case 1: + dmic_gpio_cnt = &dmic_0_1_gpio_cnt; + dmic_gpio = pdata->dmic01_gpio_p; + break; + case 2: + case 3: + dmic_gpio_cnt = &dmic_2_3_gpio_cnt; + dmic_gpio = pdata->dmic23_gpio_p; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: event %d DMIC%d dmic_gpio_cnt %d\n", + __func__, event, dmic_idx, *dmic_gpio_cnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + (*dmic_gpio_cnt)++; + if (*dmic_gpio_cnt == 1) { + ret = msm_cdc_pinctrl_select_active_state( + dmic_gpio); + if (ret < 0) { + pr_err("%s: gpio set cannot be activated %sd", + __func__, "dmic_gpio"); + return ret; + } + } + + break; + case SND_SOC_DAPM_POST_PMD: + (*dmic_gpio_cnt)--; + if (*dmic_gpio_cnt == 0) { + ret = msm_cdc_pinctrl_select_sleep_state( + dmic_gpio); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %sd", + __func__, "dmic_gpio"); + return ret; + } + } + break; + default: + pr_err("%s: invalid DAPM event %d\n", __func__, event); + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dapm_widget msm_int_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Analog Mic1", NULL), + SND_SOC_DAPM_MIC("Analog Mic2", NULL), + SND_SOC_DAPM_MIC("Analog Mic3", NULL), + SND_SOC_DAPM_MIC("Analog Mic4", NULL), + SND_SOC_DAPM_MIC("Digital Mic0", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic1", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic2", msm_dmic_event), + SND_SOC_DAPM_MIC("Digital Mic3", msm_dmic_event), +}; + +static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd) +{ + unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158}; + unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161}; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret = 0; + + ret = snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + if (ret) + return ret; + + msm_common_dai_link_init(rtd); + return ret; +} + +static struct snd_info_entry *msm_snd_info_create_subdir(struct module *mod, + const char *name, + struct snd_info_entry *parent) +{ + struct snd_info_entry *entry; + + entry = snd_info_create_module_entry(mod, name, parent); + if (!entry) + return NULL; + entry->mode = S_IFDIR | 0555; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + return NULL; + } + return entry; +} + +static void *def_wcd_mbhc_cal(void) +{ + void *wcd_mbhc_cal; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_high; + + wcd_mbhc_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS, + WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL); + if (!wcd_mbhc_cal) + return NULL; + + WCD_MBHC_CAL_PLUG_TYPE_PTR(wcd_mbhc_cal)->v_hs_max = WCD_MBHC_HS_V_MAX; + WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal)->num_btn = WCD_MBHC_DEF_BUTTONS; + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal); + btn_high = ((void *)&btn_cfg->_v_btn_low) + + (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); + + btn_high[0] = 75; + btn_high[1] = 150; + btn_high[2] = 237; + btn_high[3] = 500; + btn_high[4] = 500; + btn_high[5] = 500; + btn_high[6] = 500; + btn_high[7] = 500; + + return wcd_mbhc_cal; +} + +static struct snd_soc_ops msm_common_be_ops = { + .hw_params = msm_common_snd_hw_params, + .startup = msm_common_snd_startup, + .shutdown = msm_common_snd_shutdown, +}; + +static struct snd_soc_dai_link msm_common_be_dai_links[] = { + /* Backend AFE DAI Links */ +#if 0 + /* Incall Record Uplink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_TX, + .stream_name = "Voice Uplink Capture", + .cpu_dai_name = "msm-dai-q6-dev.32772", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_INCALL_RECORD_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Record Downlink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_RX, + .stream_name = "Voice Downlink Capture", + .cpu_dai_name = "msm-dai-q6-dev.32771", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_INCALL_RECORD_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Music BACK END DAI Link */ + { + .name = LPASS_BE_VOICE_PLAYBACK_TX, + .stream_name = "Voice Farend Playback", + .cpu_dai_name = "msm-dai-q6-dev.32773", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + /* Incall Music 2 BACK END DAI Link */ + { + .name = LPASS_BE_VOICE2_PLAYBACK_TX, + .stream_name = "Voice2 Farend Playback", + .cpu_dai_name = "msm-dai-q6-dev.32770", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, +#endif + /* Proxy Tx BACK END DAI Link */ + { + .name = LPASS_BE_RT_PROXY_PCM_TX, + .stream_name = LPASS_BE_RT_PROXY_PCM_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(proxy_tx), + }, + /* Proxy Rx BACK END DAI Link */ + { + .name = LPASS_BE_RT_PROXY_PCM_RX, + .stream_name = LPASS_BE_RT_PROXY_PCM_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(proxy_rx), + }, + { + .name = LPASS_BE_USB_AUDIO_RX, + .stream_name = LPASS_BE_USB_AUDIO_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(usb_audio_rx), + }, + { + .name = LPASS_BE_USB_AUDIO_TX, + .stream_name = LPASS_BE_USB_AUDIO_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(usb_audio_tx), + }, +}; + +static struct snd_soc_dai_link msm_tdm_be_dai_links[] = { + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = LPASS_BE_PRI_TDM_RX_0, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(pri_tdm_rx_0), + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = LPASS_BE_PRI_TDM_TX_0, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pri_tdm_tx_0), + }, + { + .name = LPASS_BE_SEC_TDM_RX_0, + .stream_name = LPASS_BE_SEC_TDM_RX_0, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(sec_tdm_rx_0), + }, + { + .name = LPASS_BE_SEC_TDM_TX_0, + .stream_name = LPASS_BE_SEC_TDM_TX_0, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_tdm_tx_0), + }, + { + .name = LPASS_BE_TERT_TDM_RX_0, + .stream_name = LPASS_BE_TERT_TDM_RX_0, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(tert_tdm_tx_0), + }, + { + .name = LPASS_BE_TERT_TDM_TX_0, + .stream_name = LPASS_BE_TERT_TDM_TX_0, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_tdm_tx_0), + }, + { + .name = LPASS_BE_QUAT_TDM_RX_0, + .stream_name = LPASS_BE_QUAT_TDM_RX_0, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(quat_tdm_rx_0), + }, + { + .name = LPASS_BE_QUAT_TDM_TX_0, + .stream_name = LPASS_BE_QUAT_TDM_TX_0, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_tdm_tx_0), + }, +}; + +static struct snd_soc_dai_link msm_wcn_btfm_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_7_RX, + .stream_name = LPASS_BE_SLIMBUS_7_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .init = &msm_wcn_init, + .ops = &msm_common_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(slimbus_7_rx), + }, + { + .name = LPASS_BE_SLIMBUS_7_TX, + .stream_name = LPASS_BE_SLIMBUS_7_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(slimbus_7_tx), + }, + { + .name = LPASS_BE_SLIMBUS_8_TX, + .stream_name = LPASS_BE_SLIMBUS_8_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(slimbus_8_tx), + }, +}; + +static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { + { + .name = LPASS_BE_PRI_MI2S_RX, + .stream_name = LPASS_BE_PRI_MI2S_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(pri_mi2s_rx), + }, + { + .name = LPASS_BE_PRI_MI2S_TX, + .stream_name = LPASS_BE_PRI_MI2S_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pri_mi2s_tx), + }, + { + .name = LPASS_BE_SEC_MI2S_RX, + .stream_name = LPASS_BE_SEC_MI2S_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(sec_mi2s_rx), + }, + { + .name = LPASS_BE_SEC_MI2S_TX, + .stream_name = LPASS_BE_SEC_MI2S_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_mi2s_tx), + }, + { + .name = LPASS_BE_TERT_MI2S_RX, + .stream_name = LPASS_BE_TERT_MI2S_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(tert_mi2s_rx), + }, + { + .name = LPASS_BE_TERT_MI2S_TX, + .stream_name = LPASS_BE_TERT_MI2S_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_mi2s_tx), + }, + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = LPASS_BE_QUAT_MI2S_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + SND_SOC_DAILINK_REG(quat_mi2s_rx), + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = LPASS_BE_QUAT_MI2S_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_mi2s_tx), + }, +}; + +static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { + /* Primary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_PRI_AUXPCM_RX, + .stream_name = LPASS_BE_PRI_AUXPCM_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops,// TODO for AUX + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(auxpcm_rx), + }, + { + .name = LPASS_BE_PRI_AUXPCM_TX, + .stream_name = LPASS_BE_PRI_AUXPCM_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(auxpcm_tx), + }, + /* Secondary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_SEC_AUXPCM_RX, + .stream_name = LPASS_BE_SEC_AUXPCM_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops,// TODO for AUX + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_auxpcm_rx), + }, + { + .name = LPASS_BE_SEC_AUXPCM_TX, + .stream_name = LPASS_BE_SEC_AUXPCM_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(sec_auxpcm_tx), + }, + /* Tertiary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_TERT_AUXPCM_RX, + .stream_name = LPASS_BE_TERT_AUXPCM_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops,// TODO for AUX + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_auxpcm_rx), + }, + { + .name = LPASS_BE_TERT_AUXPCM_TX, + .stream_name = LPASS_BE_TERT_AUXPCM_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tert_auxpcm_tx), + }, + /* Quaternary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_QUAT_AUXPCM_RX, + .stream_name = LPASS_BE_QUAT_AUXPCM_RX, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops,// TODO for AUX + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_auxpcm_rx), + }, + { + .name = LPASS_BE_QUAT_AUXPCM_TX, + .stream_name = LPASS_BE_QUAT_AUXPCM_TX, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &msm_common_be_ops, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(quat_auxpcm_tx), + }, +}; + +static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { + /* RX CDC DMA Backend DAI Links */ + { + .name = LPASS_BE_RX_CDC_DMA_RX_0, + .stream_name = LPASS_BE_RX_CDC_DMA_RX_0, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx0), + .init = &msm_rx_tx_codec_init, + }, + { + .name = LPASS_BE_RX_CDC_DMA_RX_1, + .stream_name = LPASS_BE_RX_CDC_DMA_RX_1, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx1), + .init = &msm_int_wsa_init, + }, + { + .name = LPASS_BE_RX_CDC_DMA_RX_2, + .stream_name = LPASS_BE_RX_CDC_DMA_RX_2, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx2), + }, + { + .name = LPASS_BE_RX_CDC_DMA_RX_3, + .stream_name = LPASS_BE_RX_CDC_DMA_RX_3, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx3), + }, + /* TX CDC DMA Backend DAI Links */ + { + .name = LPASS_BE_TX_CDC_DMA_TX_3, + .stream_name = LPASS_BE_TX_CDC_DMA_TX_3, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(tx_dma_tx3), + }, + { + .name = LPASS_BE_TX_CDC_DMA_TX_4, + .stream_name = LPASS_BE_TX_CDC_DMA_TX_4, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(tx_dma_tx4), + }, +}; + +static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = { + { + .name = LPASS_BE_VA_CDC_DMA_TX_0, + .stream_name = LPASS_BE_VA_CDC_DMA_TX_0, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(va_dma_tx0), + }, + { + .name = LPASS_BE_VA_CDC_DMA_TX_1, + .stream_name = LPASS_BE_VA_CDC_DMA_TX_1, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(va_dma_tx1), + }, + { + .name = LPASS_BE_VA_CDC_DMA_TX_2, + .stream_name = LPASS_BE_VA_CDC_DMA_TX_2, + .capture_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(va_dma_tx2), + }, +}; + +static struct snd_soc_dai_link msm_bengal_dai_links[ + ARRAY_SIZE(msm_common_be_dai_links) + + ARRAY_SIZE(msm_mi2s_be_dai_links) + + ARRAY_SIZE(msm_auxpcm_be_dai_links) + + ARRAY_SIZE(msm_rx_tx_cdc_dma_be_dai_links) + + ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) + + ARRAY_SIZE(msm_wcn_btfm_be_dai_links) + + ARRAY_SIZE(msm_tdm_be_dai_links)]; + +static int msm_populate_dai_link_component_of_node( + struct snd_soc_card *card) +{ + int i, j, index, ret = 0; + struct device *cdev = card->dev; + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *np = NULL; + int codecs_enabled = 0; + struct snd_soc_dai_link_component *codecs_comp = NULL; + + if (!cdev) { + dev_err(cdev, "%s: Sound card device memory NULL\n", __func__); + return -ENODEV; + } + + for (i = 0; i < card->num_links; i++) { + if (dai_link[i].init == NULL) + dai_link[i].init = &msm_common_dai_link_init; + + /* populate codec_of_node for snd card dai links */ + if (dai_link[i].num_codecs > 0) { + for (j = 0; j < dai_link[i].num_codecs; j++) { + if (dai_link[i].codecs[j].of_node || + !dai_link[i].codecs[j].name) + continue; + index = of_property_match_string(cdev->of_node, + "asoc-codec-names", + dai_link[i].codecs[j].name); + if (index < 0) + continue; + np = of_parse_phandle(cdev->of_node, "asoc-codec", + index); + if (!np) { + dev_err(cdev, + "%s: retrieving phandle for codec %s failed\n", + __func__, dai_link[i].codecs[j].name); + ret = -ENODEV; + goto err; + } + dai_link[i].codecs[j].of_node = np; + dai_link[i].codecs[j].name = NULL; + } + } + } + + /* In multi-codec scenario, check if codecs are enabled for this platform */ + for (i = 0; i < card->num_links; i++) { + codecs_enabled = 0; + if (dai_link[i].num_codecs > 1) { + for (j = 0; j < dai_link[i].num_codecs; j++) { + if (!dai_link[i].codecs[j].of_node) + continue; + np = dai_link[i].codecs[j].of_node; + if (!of_device_is_available(np)) { + dev_dbg(cdev, "%s: codec is disabled: %s\n", + __func__,np->full_name); + dai_link[i].codecs[j].of_node = NULL; + continue; + } + codecs_enabled++; + } + if (codecs_enabled > 0 && + codecs_enabled < dai_link[i].num_codecs) { + codecs_comp = devm_kzalloc(cdev, + sizeof(struct snd_soc_dai_link_component) + * codecs_enabled, GFP_KERNEL); + if (!codecs_comp) { + dev_err(cdev, "%s: %s dailink codec component alloc failed\n", + __func__, dai_link[i].name); + ret = -ENOMEM; + goto err; + } + index = 0; + for (j = 0; j < dai_link[i].num_codecs; j++) { + if(dai_link[i].codecs[j].of_node) { + codecs_comp[index].of_node = + dai_link[i].codecs[j].of_node; + codecs_comp[index].dai_name = + dai_link[i].codecs[j].dai_name; + codecs_comp[index].name = NULL; + index++; + } + } + dai_link[i].codecs = codecs_comp; + dai_link[i].num_codecs = codecs_enabled; + } + } + } +err: + return ret; +} + +struct snd_soc_card snd_soc_card_stub_msm = { + .name = "bengal-stub-snd-card", +}; + +static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd) +{ + return 0; +} + +static int msm_snd_stub_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return 0; +} + +static struct snd_soc_ops msm_stub_be_ops = { + .hw_params = msm_snd_stub_hw_params, +}; + +static struct snd_soc_dai_link msm_stub_be_dai_links[] = { + /* Backend DAI Links */ + { + .name = LPASS_BE_PRI_AUXPCM_RX, + .stream_name = LPASS_BE_PRI_AUXPCM_RX, + .playback_only = 1, + .init = &msm_audrx_stub_init, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_stub_be_ops, + SND_SOC_DAILINK_REG(auxpcm_rx), + }, + { + .name = LPASS_BE_PRI_AUXPCM_TX, + .stream_name = LPASS_BE_PRI_AUXPCM_TX, + .capture_only = 1, + .ignore_suspend = 1, + .ops = &msm_stub_be_ops, + SND_SOC_DAILINK_REG(auxpcm_tx), + }, +}; + +static struct snd_soc_dai_link msm_stub_dai_links[ + ARRAY_SIZE(msm_stub_be_dai_links)]; + +static struct snd_soc_card snd_soc_card_bengal_msm; +static const struct of_device_id bengal_asoc_machine_of_match[] = { + { .compatible = "qcom,bengal-asoc-snd", + .data = "codec"}, + { .compatible = "qcom,bengal-asoc-snd-stub", + .data = "stub_codec"}, + {}, +}; + +static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) +{ + struct snd_soc_card *card = NULL; + struct snd_soc_dai_link *dailink = NULL; + int total_links = 0; + int len_1 = 0; + int rc = 0; + u32 mi2s_audio_intf = 0; + u32 auxpcm_audio_intf = 0; + u32 rxtx_bolero_codec = 0; + u32 va_bolero_codec = 0; + u32 val = 0; + u32 wcn_btfm_intf = 0; + const struct of_device_id *match; + + match = of_match_node(bengal_asoc_machine_of_match, dev->of_node); + if (!match) { + dev_err(dev, "%s: No DT match found for sound card\n", + __func__); + return NULL; + } + + if (!strcmp(match->data, "codec")) { + card = &snd_soc_card_bengal_msm; + + memcpy(msm_bengal_dai_links + total_links, + msm_common_be_dai_links, + sizeof(msm_common_be_dai_links)); + total_links += ARRAY_SIZE(msm_common_be_dai_links); + + rc = of_property_read_u32(dev->of_node, + "qcom,rxtx-bolero-codec", + &rxtx_bolero_codec); + if (rc) { + dev_dbg(dev, "%s: No DT match RXTX Macro codec\n", + __func__); + } else { + if (rxtx_bolero_codec) { + memcpy(msm_bengal_dai_links + total_links, + msm_rx_tx_cdc_dma_be_dai_links, + sizeof(msm_rx_tx_cdc_dma_be_dai_links)); + total_links += + ARRAY_SIZE( + msm_rx_tx_cdc_dma_be_dai_links); + } + } + + rc = of_property_read_u32(dev->of_node, "qcom,va-bolero-codec", + &va_bolero_codec); + if (rc) { + dev_dbg(dev, "%s: No DT match VA Macro codec\n", + __func__); + } else { + if (va_bolero_codec) { + memcpy(msm_bengal_dai_links + total_links, + msm_va_cdc_dma_be_dai_links, + sizeof(msm_va_cdc_dma_be_dai_links)); + total_links += + ARRAY_SIZE(msm_va_cdc_dma_be_dai_links); + } + } + + rc = of_property_read_u32(dev->of_node, "qcom,mi2s-audio-intf", + &mi2s_audio_intf); + if (rc) { + dev_dbg(dev, "%s: No DT match MI2S audio interface\n", + __func__); + } else { + if (mi2s_audio_intf) { + memcpy(msm_bengal_dai_links + total_links, + msm_mi2s_be_dai_links, + sizeof(msm_mi2s_be_dai_links)); + total_links += + ARRAY_SIZE(msm_mi2s_be_dai_links); + } + } + + rc = of_property_read_u32(dev->of_node, + "qcom,auxpcm-audio-intf", + &auxpcm_audio_intf); + if (rc) { + dev_dbg(dev, "%s: No DT match Aux PCM interface\n", + __func__); + } else { + if (auxpcm_audio_intf) { + memcpy(msm_bengal_dai_links + total_links, + msm_auxpcm_be_dai_links, + sizeof(msm_auxpcm_be_dai_links)); + total_links += + ARRAY_SIZE(msm_auxpcm_be_dai_links); + } + } + + rc = of_property_read_u32(dev->of_node, "qcom,tdm-audio-intf", + &val); + if (!rc && val) { + memcpy(msm_bengal_dai_links + total_links, + msm_tdm_be_dai_links, + sizeof(msm_tdm_be_dai_links)); + total_links += + ARRAY_SIZE(msm_tdm_be_dai_links); + } + + rc = of_property_read_u32(dev->of_node, "qcom,wcn-btfm", + &wcn_btfm_intf); + if (rc) { + dev_dbg(dev, "%s: No DT match wcn btfm interface\n", + __func__); + } else { + if (wcn_btfm_intf) { + memcpy(msm_bengal_dai_links + total_links, + msm_wcn_btfm_be_dai_links, + sizeof(msm_wcn_btfm_be_dai_links)); + total_links += + ARRAY_SIZE(msm_wcn_btfm_be_dai_links); + } + } + dailink = msm_bengal_dai_links; + } + + else if (!strcmp(match->data, "stub_codec")) { + card = &snd_soc_card_stub_msm; + len_1 = ARRAY_SIZE(msm_stub_be_dai_links); + + memcpy(msm_stub_dai_links + len_1, + msm_stub_be_dai_links, + sizeof(msm_stub_be_dai_links)); + + dailink = msm_stub_dai_links; + total_links = len_1; + } + + if (card) { + card->dai_link = dailink; + card->num_links = total_links; + } + + return card; +} + +static int msm_rx_tx_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *bolero_component = NULL; + struct snd_soc_component *component = NULL; + struct snd_soc_dapm_context *dapm = NULL; + int ret = 0; + void *mbhc_calibration; + struct snd_info_entry *entry; + struct snd_card *card = NULL; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + + pr_err("%s:: enter \n", __func__); + + bolero_component = snd_soc_rtdcom_lookup(rtd, "bolero_codec"); + if (!bolero_component) { + pr_err("%s: could not find component for bolero_codec\n", + __func__); + return -EINVAL; + } + pr_err("%s:: bolero comp lookup done\n", __func__); + + dapm = snd_soc_component_get_dapm(bolero_component); + snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets, + ARRAY_SIZE(msm_int_dapm_widgets)); + pr_err("%s:: dapm new controls msm_int_dapm_widgets \n", __func__); + + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3"); + + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4"); + + snd_soc_dapm_sync(dapm); + card = rtd->card->snd_card; + + if (!pdata->codec_root) { + entry = msm_snd_info_create_subdir(card->module, "codecs", + card->proc_root); + if (!entry) { + pr_debug("%s: Cannot create codecs module entry\n", + __func__); + ret = 0; + goto err; + } + pdata->codec_root = entry; + } + + bolero_info_create_codec_entry(pdata->codec_root, bolero_component); + bolero_register_wake_irq(bolero_component, false); + + component = snd_soc_rtdcom_lookup(rtd, WCD937X_DRV_NAME); + if (!component) + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + + if (!component) { + pr_err("%s component is NULL\n", __func__); + return -EINVAL; + } + + dapm = snd_soc_component_get_dapm(component); + card = component->card->snd_card; + + pdata = snd_soc_card_get_drvdata(component->card); + if (!pdata) + return -EINVAL; + + if (!pdata->codec_root) { + entry = msm_snd_info_create_subdir(card->module, "codecs", + card->proc_root); + if (!entry) { + dev_dbg(component->dev, "%s: Cannot create codecs module entry\n", + __func__); + ret = 0; + goto mbhc_cfg_cal; + } + pdata->codec_root = entry; + } + + if (!strncmp(component->driver->name, WCD937X_DRV_NAME, 13)) { + wcd937x_info_create_codec_entry(pdata->codec_root, component); + bolero_set_port_map(bolero_component, + ARRAY_SIZE(sm_port_map), + sm_port_map); + } + + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "AUX"); + snd_soc_dapm_ignore_suspend(dapm, "LO"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC4"); + snd_soc_dapm_sync(dapm); + + codec_reg_done = true; + msm_common_dai_link_init(rtd); +mbhc_cfg_cal: + if (!strncmp(component->driver->name, WCD937X_DRV_NAME, 13)) { + mbhc_calibration = def_wcd_mbhc_cal(); + if (!mbhc_calibration) + return -ENOMEM; + wcd_mbhc_cfg.calibration = mbhc_calibration; + ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg); + } + + if (ret) { + dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n", + __func__, ret); + goto err_hs_detect; + } + return 0; + +err_hs_detect: + kfree(mbhc_calibration); +err: + pr_err("%s:: return %d \n", __func__, ret); + return ret; +} + +static int msm_int_wsa_init(struct snd_soc_pcm_runtime *rtd) +{ + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + + int ret = 0; + + if (pdata->wsa_max_devs == 0) + pr_info("%s: WSA is not enabled\n", __func__); + + msm_common_dai_link_init(rtd); + + return ret; +} + +static int bengal_ssr_enable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + int ret = 0; + + if (!card) { + dev_err_ratelimited(dev, "%s: card is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + if (!strcmp(card->name, "bengal-stub-snd-card")) { + /* TODO */ + dev_dbg(dev, "%s: TODO\n", __func__); + } + + snd_card_notify_user(SND_CARD_STATUS_ONLINE); + dev_dbg(dev, "%s: setting snd_card to ONLINE\n", __func__); + +err: + return ret; +} + +static void bengal_ssr_disable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + + if (!card) { + dev_err(dev, "%s: card is NULL\n", __func__); + return; + } + + dev_dbg(dev, "%s: setting snd_card to OFFLINE\n", __func__); + snd_card_notify_user(SND_CARD_STATUS_OFFLINE); + + if (!strcmp(card->name, "bengal-stub-snd-card")) { + /* TODO */ + dev_dbg(dev, "%s: TODO\n", __func__); + } +} + +static const struct snd_event_ops bengal_ssr_ops = { + .enable = bengal_ssr_enable, + .disable = bengal_ssr_disable, +}; + +static int msm_audio_ssr_compare(struct device *dev, void *data) +{ + struct device_node *node = data; + + dev_dbg(dev, "%s: dev->of_node = 0x%p, node = 0x%p\n", + __func__, dev->of_node, node); + return (dev->of_node && dev->of_node == node); +} + +static int msm_audio_ssr_register(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct snd_event_clients *ssr_clients = NULL; + struct device_node *node = NULL; + int ret = 0; + int i = 0; + + for (i = 0; ; i++) { + node = of_parse_phandle(np, "qcom,msm_audio_ssr_devs", i); + if (!node) + break; + snd_event_mstr_add_client(&ssr_clients, + msm_audio_ssr_compare, node); + } + + ret = snd_event_master_register(dev, &bengal_ssr_ops, + ssr_clients, NULL); + if (!ret) + snd_event_notify(dev, SND_EVENT_UP); + + return ret; +} + +struct msm_common_pdata *msm_common_get_pdata(struct snd_soc_card *card) +{ + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + if (!pdata) + return NULL; + + return pdata->common_pdata; +} + +void msm_common_set_pdata(struct snd_soc_card *card, + struct msm_common_pdata *common_pdata) +{ + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + if (!pdata) + return; + + pdata->common_pdata = common_pdata; +} + +static int msm_asoc_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = NULL; + struct msm_asoc_mach_data *pdata = NULL; + const char *mbhc_audio_jack_type = NULL; + int ret = 0; + uint index = 0; + struct nvmem_cell *cell; + size_t len; + u32 *buf; + u32 adsp_var_idx = 0; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, + "%s: No platform supplied from device tree\n", + __func__); + return -EINVAL; + } + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct msm_asoc_mach_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + card = populate_snd_card_dailinks(&pdev->dev); + if (!card) { + dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__); + ret = -EINVAL; + goto err; + } + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, pdata); + + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(&pdev->dev, "%s: parse card name failed, err:%d\n", + __func__, ret); + goto err; + } + + ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing"); + if (ret) { + dev_err(&pdev->dev, "%s: parse audio routing failed, err:%d\n", + __func__, ret); + goto err; + } + + ret = msm_populate_dai_link_component_of_node(card); + if (ret) { + ret = -EPROBE_DEFER; + goto err; + } + + /* Get maximum WSA device count for this platform */ + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,wsa-max-devs", &pdata->wsa_max_devs); + if (ret) { + dev_info(&pdev->dev, + "%s: wsa-max-devs property missing in DT %s, ret = %d\n", + __func__, pdev->dev.of_node->full_name, ret); + pdata->wsa_max_devs = 0; + } + + /* Make sure prefix string passed for each WSA device */ + ret = of_property_count_strings(pdev->dev.of_node, + "qcom,wsa-aux-dev-prefix"); + if (!ret) { + dev_err(&pdev->dev, + "property %s not defined in DT\n", + __func__, "qcom,wsa-aux-dev-prefix"); + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret == -EPROBE_DEFER) { + if (codec_reg_done) + ret = -EINVAL; + goto err; + } else if (ret) { + dev_err(&pdev->dev, "%s: snd_soc_register_card failed (%d)\n", + __func__, ret); + goto err; + } + dev_info(&pdev->dev, "%s: Sound card %s registered\n", + __func__, card->name); + + pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en1-gpio", 0); + if (!pdata->hph_en1_gpio_p) { + dev_dbg(&pdev->dev, "%s: property %s not detected in node %s\n", + __func__, "qcom,hph-en1-gpio", + pdev->dev.of_node->full_name); + } + + pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en0-gpio", 0); + if (!pdata->hph_en0_gpio_p) { + dev_dbg(&pdev->dev, "%s: property %s not detected in node %s\n", + __func__, "qcom,hph-en0-gpio", + pdev->dev.of_node->full_name); + } + + ret = of_property_read_string(pdev->dev.of_node, + "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); + if (ret) { + dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,mbhc-audio-jack-type", + pdev->dev.of_node->full_name); + dev_dbg(&pdev->dev, "Jack type properties set to default\n"); + } else { + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); + } else { + wcd_mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Unknown value, set to default\n"); + } + } + /* + * Parse US-Euro gpio info from DT. Report no error if us-euro + * entry is not found in DT file as some targets do not support + * US-Euro detection + */ + pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,us-euro-gpios", 0); + if (!pdata->us_euro_gpio_p) { + dev_dbg(&pdev->dev, "property %s not detected in node %s", + "qcom,us-euro-gpios", pdev->dev.of_node->full_name); + } else { + dev_dbg(&pdev->dev, "%s detected\n", + "qcom,us-euro-gpios"); + wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic; + } + + if (wcd_mbhc_cfg.enable_usbc_analog) + wcd_mbhc_cfg.swap_gnd_mic = msm_usbc_swap_gnd_mic; + + pdata->fsa_handle = of_parse_phandle(pdev->dev.of_node, + "fsa4480-i2c-handle", 0); + if (!pdata->fsa_handle) + dev_dbg(&pdev->dev, "property %s not detected in node %s\n", + "fsa4480-i2c-handle", pdev->dev.of_node->full_name); + + pdata->dmic01_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-dmic01-gpios", + 0); + pdata->dmic23_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,cdc-dmic23-gpios", + 0); + + pdata->mi2s_gpio_p[PRIM_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,pri-mi2s-gpios", 0); + pdata->mi2s_gpio_p[SEC_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,sec-mi2s-gpios", 0); + pdata->mi2s_gpio_p[TERT_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,tert-mi2s-gpios", 0); + pdata->mi2s_gpio_p[QUAT_MI2S] = of_parse_phandle(pdev->dev.of_node, + "qcom,quat-mi2s-gpios", 0); + for (index = PRIM_MI2S; index < MI2S_MAX; index++) + atomic_set(&(pdata->mi2s_gpio_ref_count[index]), 0); + + msm_common_snd_init(pdev, card); + + ret = msm_audio_ssr_register(&pdev->dev); + if (ret) + pr_err("%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + + is_initial_boot = true; + /* get adsp variant idx */ + cell = nvmem_cell_get(&pdev->dev, "adsp_variant"); + if (IS_ERR_OR_NULL(cell)) { + dev_dbg(&pdev->dev, "%s: FAILED to get nvmem cell \n", __func__); + goto ret; + } + buf = nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); + if (IS_ERR_OR_NULL(buf)) { + dev_dbg(&pdev->dev, "%s: FAILED to read nvmem cell \n", __func__); + goto ret; + } + if (len <= 0 || len > sizeof(u32)) { + dev_dbg(&pdev->dev, "%s: nvmem cell length out of range: %d\n", + __func__, len); + kfree(buf); + goto ret; + } + memcpy(&adsp_var_idx, buf, len); + kfree(buf); + va_disable = adsp_var_idx; + +ret: + return 0; +err: + devm_kfree(&pdev->dev, pdata); + return ret; +} + +static int msm_asoc_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = NULL; + struct msm_common_pdata *common_pdata = NULL; + + if (card) + pdata = snd_soc_card_get_drvdata(card); + + if (pdata) + common_pdata = pdata->common_pdata; + + msm_common_snd_deinit(common_pdata); + snd_event_master_deregister(&pdev->dev); + snd_soc_unregister_card(card); + + return 0; +} + +static struct platform_driver bengal_asoc_machine_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = bengal_asoc_machine_of_match, + .suppress_bind_attrs = true, + }, + .probe = msm_asoc_machine_probe, + .remove = msm_asoc_machine_remove, +}; + +static int __init msm_asoc_machine_init(void) +{ + snd_card_sysfs_init(); + return platform_driver_register(&bengal_asoc_machine_driver); +} +module_init(msm_asoc_machine_init); + +static void __exit msm_asoc_machine_exit(void) +{ + platform_driver_unregister(&bengal_asoc_machine_driver); +} +module_exit(msm_asoc_machine_exit); + +MODULE_DESCRIPTION("ALSA SoC msm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, bengal_asoc_machine_of_match); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/Kbuild new file mode 100644 index 0000000000..5630947443 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/Kbuild @@ -0,0 +1,330 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(CONFIG_SND_SOC_AUTO), y) + ifdef CONFIG_SND_SOC_SA8155 + include $(AUDIO_ROOT)/config/sa8155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa8155autoconf.h + endif + ifdef CONFIG_SND_SOC_SA6155 + include $(AUDIO_ROOT)/config/sa6155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa6155autoconf.h + endif + ifdef CONFIG_SND_SOC_GVM + include $(AUDIO_ROOT)/config/gvmauto.conf + INCS += -include $(AUDIO_ROOT)/config/gvmautoconf.h + endif + ifdef CONFIG_SND_SOC_SA7255 + include $(AUDIO_ROOT)/config/sa7255auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa7255autoconf.h + endif +else +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM8150), y) + ifdef CONFIG_SND_SOC_SA8155 + include $(AUDIO_ROOT)/config/sa8155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa8155autoconf.h + else + include $(AUDIO_ROOT)/config/sm8150auto.conf + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + endif + ifeq ($(CONFIG_ARCH_SM6150), y) + ifdef CONFIG_SND_SOC_SA6155 + include $(AUDIO_ROOT)/config/sa6155auto.conf + INCS += -include $(AUDIO_ROOT)/config/sa6155autoconf.h + else + include $(AUDIO_ROOT)/config/sm6150auto.conf + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + endif + ifeq ($(CONFIG_ARCH_TRINKET), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_KALAMA), y) + include $(AUDIO_ROOT)/config/kalamaauto.conf + INCS += -include $(AUDIO_ROOT)/config/kalamaautoconf.h + endif + ifeq ($(CONFIG_ARCH_PINEAPPLE), y) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.h + endif + ifeq ($(CONFIG_ARCH_PITTI), y) + include $(AUDIO_ROOT)/config/pittiauto.conf + INCS += -include $(AUDIO_ROOT)/config/pittiautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_KHAJE), y) + include $(AUDIO_ROOT)/config/bengalauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h + endif + ifeq ($(CONFIG_ARCH_HOLI), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_BLAIR), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_SDMSHRIKE), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + ifeq ($(CONFIG_ARCH_QCS405), y) + include $(AUDIO_ROOT)/config/qcs405auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/qcs405autoconf.h + endif + ifeq ($(CONFIG_QTI_QUIN_GVM), y) + include $(AUDIO_ROOT)/config/gvmauto.conf + INCS += -include $(AUDIO_ROOT)/config/gvmautoconf.h + endif + ifeq ($(CONFIG_ARCH_SDXLEMUR), y) + include $(AUDIO_ROOT)/config/sdxlemurauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdxlemurautoconf.h + endif +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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ ASoC Codecs ############ +ifdef CONFIG_WCD9XXX_CODEC_CORE + CORE_OBJS += wcd9xxx-rst.o + CORE_OBJS += wcd9xxx-core-init.o + CORE_OBJS += wcd9xxx-core.o + CORE_OBJS += wcd9xxx-irq.o + CORE_OBJS += wcd9xxx-slimslave.o + CORE_OBJS += wcd9xxx-utils.o + CORE_OBJS += wcd9335-regmap.o + CORE_OBJS += wcd9335-tables.o + CORE_OBJS += msm-cdc-pinctrl.o + CORE_OBJS += msm-cdc-supply.o + CORE_OBJS += wcd934x/wcd934x-regmap.o + CORE_OBJS += wcd934x/wcd934x-tables.o +endif + +ifdef CONFIG_WCD9XXX_CODEC_CORE_V2 + CORE_OBJS += wcd9xxx-core-init.o + CORE_OBJS += msm-cdc-pinctrl.o + CORE_OBJS += msm-cdc-supply.o +endif + +ifdef CONFIG_SND_SOC_WCD9XXX_V2 +ifdef CONFIG_WCD9XXX_CODEC_CORE + WCD9XXX_OBJS += wcd9xxx-common-v2.o + WCD9XXX_OBJS += wcd9xxx-resmgr-v2.o + WCD9XXX_OBJS += wcd-dsp-utils.o + WCD9XXX_OBJS += wcd-dsp-mgr.o +else + WCD9XXX_OBJS += wcd-clsh.o +endif + WCD9XXX_OBJS += wcdcal-hwdep.o + WCD9XXX_OBJS += wcd9xxx-soc-init.o + WCD9XXX_OBJS += audio-ext-clk-up.o +endif + +ifdef CONFIG_SND_SOC_WCD9335 + WCD9335_OBJS += wcd9335.o +endif + +ifdef CONFIG_SND_SOC_WSA881X + WSA881X_OBJS += wsa881x.o + WSA881X_OBJS += wsa881x-tables.o + WSA881X_OBJS += wsa881x-regmap.o + WSA881X_OBJS += wsa881x-temp-sensor.o +endif + +ifdef CONFIG_SND_SOC_SWR_DMIC + SWR_DMIC_OBJS += swr-dmic.o +endif + +ifdef CONFIG_SND_SOC_WSA881X_ANALOG + INCS += -include $(KERNEL_SRC)/drivers/base/regmap/internal.h + WSA881X_ANALOG_OBJS += wsa881x-analog.o + WSA881X_ANALOG_OBJS += wsa881x-tables-analog.o + WSA881X_ANALOG_OBJS += wsa881x-regmap-analog.o +ifndef CONFIG_WSA881X_TEMP_SENSOR_DISABLE + WSA881X_ANALOG_OBJS += wsa881x-temp-sensor.o +endif +endif +ifdef CONFIG_SND_SOC_MSM_STUB + STUB_OBJS += msm_stub.o +endif +ifdef CONFIG_SND_SOC_WCD_SPI + SPI_OBJS += wcd-spi.o +endif + +ifdef CONFIG_SND_SOC_WCD_CPE + WCD_CPE_OBJS += wcd_cpe_core.o + WCD_CPE_OBJS += wcd_cpe_services.o +endif + +ifdef CONFIG_SND_SOC_WCD_MBHC + MBHC_OBJS += wcd-mbhc-v2.o +endif + +ifdef CONFIG_SND_SOC_WCD_MBHC_ADC + MBHC_OBJS += wcd-mbhc-adc.o +endif + +ifdef CONFIG_SND_SOC_WCD_MBHC_LEGACY + MBHC_OBJS += wcd-mbhc-legacy.o +endif + +ifdef CONFIG_SND_SOC_MSM_HDMI_CODEC_RX + HDMICODEC_OBJS += msm_hdmi_codec_rx.o +endif + +ifdef CONFIG_SND_SOC_WCD_IRQ + CORE_OBJS += wcd-irq.o +endif + +ifdef CONFIG_SND_SWR_HAPTICS + SWR_HAP_OBJS += swr-haptics.o +endif + +ifdef CONFIG_LPASS_BT_SWR + LPASS_BT_SWR_OBJS += lpass-bt-swr.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), 1) + obj-y += wcd934x/ + obj-y += wcd937x/ + obj-y += wcd938x/ + obj-y += wcd939x/ + obj-y += wcd9378/ + obj-y += bolero/ + obj-y += lpass-cdc/ + obj-y += wsa884x/ + obj-y += wsa883x/ + obj-y += rouleur/ + obj-y += ./ +endif +# Module information used by KBuild framework +obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd_core_dlkm.o +obj-$(CONFIG_WCD9XXX_CODEC_CORE_V2) += wcd_core_dlkm.o +wcd_core_dlkm-y := $(CORE_OBJS) + +obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += wcd9xxx_dlkm.o +wcd9xxx_dlkm-y := $(WCD9XXX_OBJS) + +obj-$(CONFIG_SND_SOC_WCD9335) += wcd9335_dlkm.o +wcd9335_dlkm-y := $(WCD9335_OBJS) + +obj-$(CONFIG_SND_SOC_WSA881X) += wsa881x_dlkm.o +wsa881x_dlkm-y := $(WSA881X_OBJS) + +obj-$(CONFIG_SND_SOC_SWR_DMIC) += swr_dmic_dlkm.o +swr_dmic_dlkm-y := $(SWR_DMIC_OBJS) + +obj-$(CONFIG_SND_SOC_WSA881X_ANALOG) += wsa881x_analog_dlkm.o +wsa881x_analog_dlkm-y := $(WSA881X_ANALOG_OBJS) + +obj-$(CONFIG_SND_SOC_MSM_STUB) += stub_dlkm.o +stub_dlkm-y := $(STUB_OBJS) + +obj-$(CONFIG_SND_SOC_WCD_CPE) += wcd_cpe_dlkm.o +wcd_cpe_dlkm-y := $(WCD_CPE_OBJS) + +obj-$(CONFIG_SND_SOC_WCD_SPI) += wcd_spi_dlkm.o +wcd_spi_dlkm-y := $(SPI_OBJS) + +obj-$(CONFIG_SND_SOC_WCD_MBHC) += mbhc_dlkm.o +mbhc_dlkm-y := $(MBHC_OBJS) + +obj-$(CONFIG_SND_SOC_MSM_HDMI_CODEC_RX) += hdmi_dlkm.o +hdmi_dlkm-y := $(HDMICODEC_OBJS) + +obj-$(CONFIG_SND_SWR_HAPTICS) += swr_haptics_dlkm.o +swr_haptics_dlkm-y := $(SWR_HAP_OBJS) + +obj-$(CONFIG_LPASS_BT_SWR) += lpass_bt_swr_dlkm.o +lpass_bt_swr_dlkm-y := $(LPASS_BT_SWR_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/Makefile b/qcom/opensource/audio-kernel/asoc/codecs/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/Kbuild new file mode 100644 index 0000000000..f5f18785e9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/Kbuild @@ -0,0 +1,120 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + + ifeq ($(CONFIG_ARCH_SDM670), y) + include $(AUDIO_ROOT)/config/sdm670auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm670autoconf.h + endif + + ifeq ($(CONFIG_ARCH_SM8150), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + + ifeq ($(CONFIG_ARCH_SDMSHRIKE), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +# for AQT1000 Codec +ifeq ($(CONFIG_SND_SOC_AQT1000), m) + AQT1000_CDC_OBJS += aqt1000-regmap.o + AQT1000_CDC_OBJS += aqt1000-utils.o + AQT1000_CDC_OBJS += aqt1000-core.o + AQT1000_CDC_OBJS += aqt1000-irq.o + AQT1000_CDC_OBJS += aqt1000-clsh.o + AQT1000_CDC_OBJS += aqt1000.o + AQT1000_CDC_OBJS += aqt1000-mbhc.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 +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/Module.symvers +endif + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_AQT1000) += aqt1000_cdc_dlkm.o +aqt1000_cdc_dlkm-y := $(AQT1000_CDC_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-api.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-api.h new file mode 100644 index 0000000000..bf90fad02a --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-api.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef AQT1000_API_H +#define AQT1000_API_H + +#include +#include +#include +#include + +extern int aqt_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int volt, int micb_num); +extern int aqt_cdc_mclk_enable(struct snd_soc_component *component, + bool enable); +extern int aqt_get_micb_vout_ctl_val(u32 micb_mv); +extern int aqt_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm); + +#endif /* AQT1000_API_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-clsh.c b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-clsh.c new file mode 100644 index 0000000000..ef70cc941c --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-clsh.c @@ -0,0 +1,833 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "aqt1000-registers.h" +#include "aqt1000-clsh.h" + +#define AQT_USLEEP_RANGE 50 +#define MAX_IMPED_PARAMS 6 + +enum aqt_vref_dac_sel { + VREF_N1P9V = 0, + VREF_N1P86V, + VREF_N181V, + VREF_N1P74V, + VREF_N1P7V, + VREF_N0P9V, + VREF_N1P576V, + VREF_N1P827V, +}; + +enum aqt_vref_ctl { + CONTROLLER = 0, + I2C, +}; + +enum aqt_hd2_res_div_ctl { + DISCONNECT = 0, + P5_0P35, + P75_0P68, + P82_0P77, + P9_0P87, +}; + +enum aqt_curr_bias_err_amp { + I_0P25UA = 0, + I_0P5UA, + I_0P75UA, + I_1UA, + I_1P25UA, + I_1P5UA, + I_1P75UA, + I_2UA, +}; + +static const struct aqt_reg_mask_val imped_table_aqt[][MAX_IMPED_PARAMS] = { + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xf2}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xf2}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xf4}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xf4}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {AQT1000_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, +}; + +static const struct aqt_imped_val imped_index[] = { + {4, 0}, + {5, 1}, + {6, 2}, + {7, 3}, + {8, 4}, + {9, 5}, + {10, 6}, + {11, 7}, + {12, 8}, + {13, 9}, +}; + +static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_component *, + struct aqt_clsh_cdc_data *, + u8 req_state, bool en, int mode); + +static int get_impedance_index(int imped) +{ + int i = 0; + + if (imped < imped_index[i].imped_val) { + pr_debug("%s, detected impedance is less than 4 Ohm\n", + __func__); + i = 0; + goto ret; + } + if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) { + pr_debug("%s, detected impedance is greater than 12 Ohm\n", + __func__); + i = ARRAY_SIZE(imped_index) - 1; + goto ret; + } + for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) { + if (imped >= imped_index[i].imped_val && + imped < imped_index[i + 1].imped_val) + break; + } +ret: + pr_debug("%s: selected impedance index = %d\n", + __func__, imped_index[i].index); + return imped_index[i].index; +} + +/* + * Function: aqt_clsh_imped_config + * Params: component, imped, reset + * Description: + * This function updates HPHL and HPHR gain settings + * according to the impedance value. + */ +void aqt_clsh_imped_config(struct snd_soc_component *component, + int imped, bool reset) +{ + int i; + int index = 0; + int table_size; + + static const struct aqt_reg_mask_val + (*imped_table_ptr)[MAX_IMPED_PARAMS]; + + table_size = ARRAY_SIZE(imped_table_aqt); + imped_table_ptr = imped_table_aqt; + + /* reset = 1, which means request is to reset the register values */ + if (reset) { + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, 0); + return; + } + index = get_impedance_index(imped); + if (index >= (ARRAY_SIZE(imped_index) - 1)) { + pr_debug("%s, impedance not in range = %d\n", __func__, imped); + return; + } + if (index >= table_size) { + pr_debug("%s, impedance index not in range = %d\n", __func__, + index); + return; + } + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, + imped_table_ptr[index][i].val); +} +EXPORT_SYMBOL(aqt_clsh_imped_config); + +static const char *mode_to_str(int mode) +{ + switch (mode) { + case CLS_H_NORMAL: + return "CLS_H_NORMAL"; + case CLS_H_HIFI: + return "CLS_H_HIFI"; + case CLS_H_LOHIFI: + return "CLS_H_LOHIFI"; + case CLS_H_LP: + return "CLS_H_LP"; + case CLS_H_ULP: + return "CLS_H_ULP"; + case CLS_AB: + return "CLS_AB"; + case CLS_AB_HIFI: + return "CLS_AB_HIFI"; + default: + return "CLS_H_INVALID"; + }; +} + +static const char *const state_to_str[] = { + [AQT_CLSH_STATE_IDLE] = "STATE_IDLE", + [AQT_CLSH_STATE_HPHL] = "STATE_HPH_L", + [AQT_CLSH_STATE_HPHR] = "STATE_HPH_R", + [AQT_CLSH_STATE_HPH_ST] = "STATE_HPH_ST", +}; + +static inline void +aqt_enable_clsh_block(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *clsh_d, bool enable) +{ + if ((enable && ++clsh_d->clsh_users == 1) || + (!enable && --clsh_d->clsh_users == 0)) + snd_soc_component_update_bits(component, AQT1000_CDC_CLSH_CRC, + 0x01, (u8) enable); + if (clsh_d->clsh_users < 0) + clsh_d->clsh_users = 0; + dev_dbg(component->dev, "%s: clsh_users %d, enable %d", __func__, + clsh_d->clsh_users, enable); +} + +static inline bool aqt_clsh_enable_status(struct snd_soc_component *component) +{ + return snd_soc_component_read32( + component, AQT1000_CDC_CLSH_CRC) & 0x01; +} + +static inline int aqt_clsh_get_int_mode(struct aqt_clsh_cdc_data *clsh_d, + int clsh_state) +{ + int mode; + + if ((clsh_state != AQT_CLSH_STATE_HPHL) && + (clsh_state != AQT_CLSH_STATE_HPHR)) + mode = CLS_NONE; + else + mode = clsh_d->interpolator_modes[ffs(clsh_state)]; + + return mode; +} + +static inline void aqt_clsh_set_int_mode(struct aqt_clsh_cdc_data *clsh_d, + int clsh_state, int mode) +{ + if ((clsh_state != AQT_CLSH_STATE_HPHL) && + (clsh_state != AQT_CLSH_STATE_HPHR)) + return; + + clsh_d->interpolator_modes[ffs(clsh_state)] = mode; +} + +static inline void aqt_clsh_set_buck_mode(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + 0x08, 0x08); /* set to HIFI */ + else + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + 0x08, 0x00); /* set to default */ +} + +static inline void aqt_clsh_set_flyback_mode( + struct snd_soc_component *component, int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + 0x04, 0x04); /* set to HIFI */ + else + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + 0x04, 0x00); /* set to Default */ +} + +static inline void aqt_clsh_gm3_boost_disable( + struct snd_soc_component *component, int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) { + snd_soc_component_update_bits(component, + AQT1000_HPH_CNP_WG_CTL, + 0x80, 0x0); /* disable GM3 Boost */ + snd_soc_component_update_bits(component, + AQT1000_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x80); + } else { + snd_soc_component_update_bits(component, + AQT1000_HPH_CNP_WG_CTL, + 0x80, 0x80); /* set to Default */ + snd_soc_component_update_bits(component, + AQT1000_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x70); + } +} + +static inline void aqt_clsh_flyback_dac_ctl( + struct snd_soc_component *component, int vref) +{ + snd_soc_component_update_bits(component, + AQT1000_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, (vref << 5)); +} + +static inline void aqt_clsh_mode_vref_ctl(struct snd_soc_component *component, + int vref_ctl) +{ + if (vref_ctl == I2C) { + snd_soc_component_update_bits(component, AQT1000_CLASSH_MODE_3, + 0x02, 0x02); + snd_soc_component_update_bits(component, AQT1000_CLASSH_MODE_2, + 0xFF, 0x1C); + } else { + snd_soc_component_update_bits(component, AQT1000_CLASSH_MODE_2, + 0xFF, 0x3A); + snd_soc_component_update_bits(component, AQT1000_CLASSH_MODE_3, + 0x02, 0x00); + } +} + +static inline void aqt_clsh_buck_current_bias_ctl( + struct snd_soc_component *component, bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, + AQT1000_BUCK_5V_IBIAS_CTL_4, + 0x70, (I_2UA << 4)); + snd_soc_component_update_bits(component, + AQT1000_BUCK_5V_IBIAS_CTL_4, + 0x07, I_0P25UA); + snd_soc_component_update_bits(component, + AQT1000_BUCK_5V_CTRL_CCL_2, + 0x3F, 0x3F); + } else { + snd_soc_component_update_bits(component, + AQT1000_BUCK_5V_IBIAS_CTL_4, + 0x70, (I_1UA << 4)); + snd_soc_component_update_bits(component, + AQT1000_BUCK_5V_IBIAS_CTL_4, + 0x07, I_1UA); + snd_soc_component_update_bits(component, + AQT1000_BUCK_5V_CTRL_CCL_2, + 0x3F, 0x20); + } +} + +static inline void aqt_clsh_rdac_hd2_ctl(struct snd_soc_component *component, + u8 hd2_div_ctl, u8 state) +{ + u16 reg = 0; + + if (state == AQT_CLSH_STATE_HPHL) + reg = AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_L; + else if (state == AQT_CLSH_STATE_HPHR) + reg = AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_R; + else + dev_err(component->dev, "%s: Invalid state: %d\n", + __func__, state); + if (!reg) + snd_soc_component_update_bits(component, reg, + 0x0F, hd2_div_ctl); +} + +static inline void aqt_clsh_force_iq_ctl(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_LOHIFI || mode == CLS_AB) { + snd_soc_component_update_bits(component, + AQT1000_HPH_NEW_INT_PA_MISC2, + 0x20, 0x20); + snd_soc_component_update_bits(component, + AQT1000_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0xC0); + snd_soc_component_update_bits(component, + AQT1000_HPH_PA_CTL1, + 0x0E, 0x02); + } else { + + snd_soc_component_update_bits(component, + AQT1000_HPH_NEW_INT_PA_MISC2, + 0x20, 0x0); + snd_soc_component_update_bits(component, + AQT1000_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0x80); + snd_soc_component_update_bits(component, + AQT1000_HPH_PA_CTL1, + 0x0E, 0x06); + } +} + +static void aqt_clsh_buck_ctrl(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *clsh_d, + int mode, + bool enable) +{ + /* enable/disable buck */ + if ((enable && (++clsh_d->buck_users == 1)) || + (!enable && (--clsh_d->buck_users == 0))) + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + (1 << 7), (enable << 7)); + dev_dbg(component->dev, "%s: buck_users %d, enable %d, mode: %s", + __func__, clsh_d->buck_users, enable, mode_to_str(mode)); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + AQT_USLEEP_RANGE); +} + +static void aqt_clsh_flyback_ctrl(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *clsh_d, + int mode, + bool enable) +{ + /* enable/disable flyback */ + if ((enable && (++clsh_d->flyback_users == 1)) || + (!enable && (--clsh_d->flyback_users == 0))) { + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + (1 << 6), (enable << 6)); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + } + dev_dbg(component->dev, "%s: flyback_users %d, enable %d, mode: %s", + __func__, clsh_d->flyback_users, enable, mode_to_str(mode)); + /* + * 500us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + AQT_USLEEP_RANGE); +} + +static void aqt_clsh_set_hph_mode(struct snd_soc_component *component, + int mode) +{ + u8 val = 0; + u8 gain = 0; + u8 res_val = VREF_FILT_R_0OHM; + u8 ipeak = DELTA_I_50MA; + + switch (mode) { + case CLS_H_NORMAL: + res_val = VREF_FILT_R_50KOHM; + val = 0x00; + gain = DAC_GAIN_0DB; + ipeak = DELTA_I_50MA; + break; + case CLS_AB: + val = 0x00; + gain = DAC_GAIN_0DB; + ipeak = DELTA_I_50MA; + break; + case CLS_AB_HIFI: + val = 0x08; + break; + case CLS_H_HIFI: + val = 0x08; + gain = DAC_GAIN_M0P2DB; + ipeak = DELTA_I_50MA; + break; + case CLS_H_LOHIFI: + val = 0x00; + break; + case CLS_H_ULP: + val = 0x0C; + break; + case CLS_H_LP: + val = 0x04; + ipeak = DELTA_I_30MA; + break; + default: + return; + }; + + if (mode == CLS_H_LOHIFI || mode == CLS_AB) + val = 0x04; + + snd_soc_component_update_bits(component, AQT1000_ANA_HPH, 0x0C, val); +} + +static void aqt_clsh_set_buck_regulator_mode( + struct snd_soc_component *component, int mode) +{ + snd_soc_component_update_bits(component, AQT1000_ANA_RX_SUPPLIES, + 0x02, 0x00); +} + +static void aqt_clsh_state_hph_st(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (mode == CLS_AB || mode == CLS_AB_HIFI) + return; + + if (is_enable) { + if (req_state == AQT_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x40); + if (req_state == AQT_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x40); + } else { + if (req_state == AQT_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x00); + if (req_state == AQT_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x00); + } +} + +static void aqt_clsh_state_hph_r(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (mode == CLS_H_NORMAL) { + dev_err(component->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + aqt_enable_clsh_block(component, clsh_d, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(component, + AQT1000_CDC_CLSH_K1_MSB, + 0x0F, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLSH_K1_LSB, + 0xFF, 0xC0); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x40); + } + aqt_clsh_set_buck_regulator_mode(component, mode); + aqt_clsh_set_flyback_mode(component, mode); + aqt_clsh_gm3_boost_disable(component, mode); + aqt_clsh_flyback_dac_ctl(component, VREF_N0P9V); + aqt_clsh_mode_vref_ctl(component, I2C); + aqt_clsh_force_iq_ctl(component, mode); + aqt_clsh_rdac_hd2_ctl(component, P82_0P77, req_state); + aqt_clsh_flyback_ctrl(component, clsh_d, mode, true); + aqt_clsh_flyback_dac_ctl(component, VREF_N1P827V); + aqt_clsh_set_buck_mode(component, mode); + aqt_clsh_buck_ctrl(component, clsh_d, mode, true); + aqt_clsh_mode_vref_ctl(component, CONTROLLER); + aqt_clsh_buck_current_bias_ctl(component, true); + aqt_clsh_set_hph_mode(component, mode); + } else { + aqt_clsh_set_hph_mode(component, CLS_H_NORMAL); + aqt_clsh_buck_current_bias_ctl(component, false); + + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x00); + aqt_enable_clsh_block(component, clsh_d, false); + } + /* buck and flyback set to default mode and disable */ + aqt_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false); + aqt_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false); + aqt_clsh_rdac_hd2_ctl(component, P5_0P35, req_state); + aqt_clsh_force_iq_ctl(component, CLS_H_NORMAL); + aqt_clsh_gm3_boost_disable(component, CLS_H_NORMAL); + aqt_clsh_set_flyback_mode(component, CLS_H_NORMAL); + aqt_clsh_set_buck_mode(component, CLS_H_NORMAL); + aqt_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL); + } +} + +static void aqt_clsh_state_hph_l(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); + + if (mode == CLS_H_NORMAL) { + dev_err(component->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + aqt_enable_clsh_block(component, clsh_d, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(component, + AQT1000_CDC_CLSH_K1_MSB, + 0x0F, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLSH_K1_LSB, + 0xFF, 0xC0); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x40); + } + aqt_clsh_set_buck_regulator_mode(component, mode); + aqt_clsh_set_flyback_mode(component, mode); + aqt_clsh_gm3_boost_disable(component, mode); + aqt_clsh_flyback_dac_ctl(component, VREF_N0P9V); + aqt_clsh_mode_vref_ctl(component, I2C); + aqt_clsh_force_iq_ctl(component, mode); + aqt_clsh_rdac_hd2_ctl(component, P82_0P77, req_state); + aqt_clsh_flyback_ctrl(component, clsh_d, mode, true); + aqt_clsh_flyback_dac_ctl(component, VREF_N1P827V); + aqt_clsh_set_buck_mode(component, mode); + aqt_clsh_buck_ctrl(component, clsh_d, mode, true); + aqt_clsh_mode_vref_ctl(component, CONTROLLER); + aqt_clsh_buck_current_bias_ctl(component, true); + aqt_clsh_set_hph_mode(component, mode); + } else { + aqt_clsh_set_hph_mode(component, CLS_H_NORMAL); + aqt_clsh_buck_current_bias_ctl(component, false); + + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x00); + aqt_enable_clsh_block(component, clsh_d, false); + } + /* set buck and flyback to Default Mode */ + aqt_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false); + aqt_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false); + aqt_clsh_rdac_hd2_ctl(component, P5_0P35, req_state); + aqt_clsh_force_iq_ctl(component, CLS_H_NORMAL); + aqt_clsh_gm3_boost_disable(component, CLS_H_NORMAL); + aqt_clsh_set_flyback_mode(component, CLS_H_NORMAL); + aqt_clsh_set_buck_mode(component, CLS_H_NORMAL); + aqt_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL); + } +} + +static void aqt_clsh_state_err(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_err(component->dev, + "%s Wrong request for class H state machine requested to %s %s", + __func__, is_enable ? "enable" : "disable", + state_to_str[req_state]); +} + +/* + * Function: aqt_clsh_is_state_valid + * Params: state + * Description: + * Provides information on valid states of Class H configuration + */ +static bool aqt_clsh_is_state_valid(u8 state) +{ + switch (state) { + case AQT_CLSH_STATE_IDLE: + case AQT_CLSH_STATE_HPHL: + case AQT_CLSH_STATE_HPHR: + case AQT_CLSH_STATE_HPH_ST: + return true; + default: + return false; + }; +} + +/* + * Function: aqt_clsh_fsm + * Params: component, cdc_clsh_d, req_state, req_type, clsh_event + * Description: + * This function handles PRE DAC and POST DAC conditions of different devices + * and updates class H configuration of different combination of devices + * based on validity of their states. cdc_clsh_d will contain current + * class h state information + */ +void aqt_clsh_fsm(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *cdc_clsh_d, + u8 clsh_event, u8 req_state, + int int_mode) +{ + u8 old_state, new_state; + + switch (clsh_event) { + case AQT_CLSH_EVENT_PRE_DAC: + old_state = cdc_clsh_d->state; + new_state = old_state | req_state; + + if (!aqt_clsh_is_state_valid(new_state)) { + dev_err(component->dev, + "%s: Class-H not a valid new state: %s\n", + __func__, state_to_str[new_state]); + return; + } + if (new_state == old_state) { + dev_err(component->dev, + "%s: Class-H already in requested state: %s\n", + __func__, state_to_str[new_state]); + return; + } + cdc_clsh_d->state = new_state; + aqt_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode); + (*clsh_state_fp[new_state]) (component, cdc_clsh_d, req_state, + CLSH_REQ_ENABLE, int_mode); + dev_dbg(component->dev, + "%s: ClassH state transition from %s to %s\n", + __func__, state_to_str[old_state], + state_to_str[cdc_clsh_d->state]); + break; + case AQT_CLSH_EVENT_POST_PA: + old_state = cdc_clsh_d->state; + new_state = old_state & (~req_state); + if (new_state < NUM_CLSH_STATES) { + if (!aqt_clsh_is_state_valid(old_state)) { + dev_err(component->dev, + "%s:Invalid old state:%s\n", + __func__, state_to_str[old_state]); + return; + } + if (new_state == old_state) { + dev_err(component->dev, + "%s: Class-H already in requested state: %s\n", + __func__,state_to_str[new_state]); + return; + } + (*clsh_state_fp[old_state]) (component, cdc_clsh_d, + req_state, CLSH_REQ_DISABLE, + int_mode); + cdc_clsh_d->state = new_state; + aqt_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE); + dev_dbg(component->dev, "%s: ClassH state transition from %s to %s\n", + __func__, state_to_str[old_state], + state_to_str[cdc_clsh_d->state]); + } + break; + }; +} +EXPORT_SYMBOL(aqt_clsh_fsm); + +/* + * Function: aqt_clsh_get_clsh_state + * Params: clsh + * Description: + * This function returns the state of the class H controller + */ +int aqt_clsh_get_clsh_state(struct aqt_clsh_cdc_data *clsh) +{ + return clsh->state; +} +EXPORT_SYMBOL(aqt_clsh_get_clsh_state); + +/* + * Function: aqt_clsh_init + * Params: clsh + * Description: + * This function initializes the class H controller + */ +void aqt_clsh_init(struct aqt_clsh_cdc_data *clsh) +{ + int i; + + clsh->state = AQT_CLSH_STATE_IDLE; + + for (i = 0; i < NUM_CLSH_STATES; i++) + clsh_state_fp[i] = aqt_clsh_state_err; + + clsh_state_fp[AQT_CLSH_STATE_HPHL] = aqt_clsh_state_hph_l; + clsh_state_fp[AQT_CLSH_STATE_HPHR] = aqt_clsh_state_hph_r; + clsh_state_fp[AQT_CLSH_STATE_HPH_ST] = aqt_clsh_state_hph_st; + /* Set interpolator modes to NONE */ + aqt_clsh_set_int_mode(clsh, AQT_CLSH_STATE_HPHL, CLS_NONE); + aqt_clsh_set_int_mode(clsh, AQT_CLSH_STATE_HPHR, CLS_NONE); + clsh->flyback_users = 0; + clsh->buck_users = 0; + clsh->clsh_users = 0; +} +EXPORT_SYMBOL(aqt_clsh_init); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-clsh.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-clsh.h new file mode 100644 index 0000000000..5a0b427a65 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-clsh.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _AQT1000_CLSH_H +#define _AQT1000_CLSH_H + +#include +#include +#include +#include + +#define CLSH_REQ_ENABLE true +#define CLSH_REQ_DISABLE false + +#define AQT_CLSH_EVENT_PRE_DAC 0x01 +#define AQT_CLSH_EVENT_POST_PA 0x02 +/* + * Basic states for Class H state machine. + * represented as a bit mask within a u8 data type + * bit 0: HPH Left mode + * bit 1: HPH Right mode + */ +#define AQT_CLSH_STATE_IDLE 0x00 +#define AQT_CLSH_STATE_HPHL (0x01 << 0) +#define AQT_CLSH_STATE_HPHR (0x01 << 1) + +/* + * Though number of CLSH states are 2, max state shoulbe be 3 + * because state array index starts from 1. + */ +#define AQT_CLSH_STATE_MAX 3 +#define NUM_CLSH_STATES (0x01 << AQT_CLSH_STATE_MAX) + + +/* Derived State: Bits 1 and 2 should be set for Headphone stereo */ +#define AQT_CLSH_STATE_HPH_ST (AQT_CLSH_STATE_HPHL | \ + AQT_CLSH_STATE_HPHR) + +enum { + CLS_H_NORMAL = 0, /* Class-H Default */ + CLS_H_HIFI, /* Class-H HiFi */ + CLS_H_LP, /* Class-H Low Power */ + CLS_AB, /* Class-AB Low HIFI*/ + CLS_H_LOHIFI, /* LoHIFI */ + CLS_H_ULP, /* Ultra Low power */ + CLS_AB_HIFI, /* Class-AB */ + CLS_NONE, /* None of the above modes */ +}; + +enum { + DAC_GAIN_0DB = 0, + DAC_GAIN_0P2DB, + DAC_GAIN_0P4DB, + DAC_GAIN_0P6DB, + DAC_GAIN_0P8DB, + DAC_GAIN_M0P2DB, + DAC_GAIN_M0P4DB, + DAC_GAIN_M0P6DB, +}; + +enum { + VREF_FILT_R_0OHM = 0, + VREF_FILT_R_25KOHM, + VREF_FILT_R_50KOHM, + VREF_FILT_R_100KOHM, +}; + +enum { + DELTA_I_0MA, + DELTA_I_10MA, + DELTA_I_20MA, + DELTA_I_30MA, + DELTA_I_40MA, + DELTA_I_50MA, +}; + +struct aqt_imped_val { + u32 imped_val; + u8 index; +}; + +struct aqt_clsh_cdc_data { + u8 state; + int flyback_users; + int buck_users; + int clsh_users; + int interpolator_modes[AQT_CLSH_STATE_MAX]; +}; + +struct aqt_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +extern void aqt_clsh_fsm(struct snd_soc_component *component, + struct aqt_clsh_cdc_data *cdc_clsh_d, + u8 clsh_event, u8 req_state, + int int_mode); + +extern void aqt_clsh_init(struct aqt_clsh_cdc_data *clsh); +extern int aqt_clsh_get_clsh_state(struct aqt_clsh_cdc_data *clsh); +extern void aqt_clsh_imped_config(struct snd_soc_component *component, + int imped, bool reset); + +#endif /* _AQT1000_CLSH_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-core.c b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-core.c new file mode 100644 index 0000000000..7b4efa1a00 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-core.c @@ -0,0 +1,638 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2011-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 +#include +#include "aqt1000-registers.h" +#include "aqt1000-internal.h" +#include "aqt1000.h" +#include "aqt1000-utils.h" +#include "aqt1000-irq.h" + +static int aqt1000_bringup(struct aqt1000 *aqt) +{ + struct aqt1000_pdata *pdata; + u8 clk_div = 0, mclk = 1; + + if (!aqt->regmap) { + dev_err(aqt->dev, "%s: aqt regmap is NULL\n", __func__); + return -EINVAL; + } + + /* Bringup register write sequence */ + regmap_update_bits(aqt->regmap, AQT1000_BUCK_5V_CTRL_CCL_1, 0xF0, 0xF0); + regmap_update_bits(aqt->regmap, AQT1000_BIAS_CCOMP_FINE_ADJ, + 0xF0, 0x90); + regmap_update_bits(aqt->regmap, AQT1000_ANA_BIAS, 0x80, 0x80); + regmap_update_bits(aqt->regmap, AQT1000_ANA_BIAS, 0x40, 0x40); + + /* Added 1msec sleep as per HW requirement */ + usleep_range(1000, 1010); + + regmap_update_bits(aqt->regmap, AQT1000_ANA_BIAS, 0x40, 0x00); + + clk_div = 0x04; /* Assumption is CLK DIV 2 */ + pdata = dev_get_platdata(aqt->dev); + if (pdata) { + if (pdata->mclk_rate == AQT1000_CLK_12P288MHZ) + mclk = 0; + clk_div = (((pdata->ext_clk_rate / pdata->mclk_rate) >> 1) + << 2); + } + regmap_update_bits(aqt->regmap, AQT1000_CHIP_CFG0_CLK_CFG_MCLK, + 0x03, mclk); + + regmap_update_bits(aqt->regmap, AQT1000_CLK_SYS_MCLK1_PRG, + 0x0C, clk_div); + + /* Source clock enable */ + regmap_update_bits(aqt->regmap, AQT1000_CLK_SYS_MCLK1_PRG, 0x02, 0x02); + + /* Ungate the source clock */ + regmap_update_bits(aqt->regmap, AQT1000_CLK_SYS_MCLK1_PRG, 0x10, 0x10); + + /* Set the I2S_HS_CLK reference to CLK DIV 2 */ + regmap_update_bits(aqt->regmap, AQT1000_CLK_SYS_MCLK2_I2S_HS_CLK_PRG, + 0x60, 0x20); + + /* Set the PLL preset to CLK9P6M_IN_12P288M_OUT */ + regmap_update_bits(aqt->regmap, AQT1000_CLK_SYS_PLL_PRESET, 0x0F, 0x02); + + /* Enable clock PLL */ + regmap_update_bits(aqt->regmap, AQT1000_CLK_SYS_PLL_ENABLES, + 0x01, 0x01); + + /* Add 100usec delay as per HW requirement */ + usleep_range(100, 110); + + /* Set AQT to I2S Master */ + regmap_update_bits(aqt->regmap, AQT1000_I2S_I2S_0_CTL, 0x02, 0x02); + + /* Enable I2S HS clock */ + regmap_update_bits(aqt->regmap, AQT1000_CLK_SYS_MCLK2_I2S_HS_CLK_PRG, + 0x01, 0x01); + + regmap_update_bits(aqt->regmap, AQT1000_CHIP_CFG0_CLK_CFG_MCLK, + 0x04, 0x00); + + /* Add 100usec delay as per HW requirement */ + usleep_range(100, 110); + regmap_update_bits(aqt->regmap, AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + regmap_update_bits(aqt->regmap, AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + regmap_update_bits(aqt->regmap, AQT1000_CHIP_CFG0_CLK_CTL_CDC_DIG, + 0x01, 0x01); + + /* Codec digital reset */ + regmap_update_bits(aqt->regmap, AQT1000_CHIP_CFG0_RST_CTL, 0x01, 0x01); + /* Add 100usec delay as per HW requirement */ + usleep_range(100, 110); + + return 0; +} + +static int aqt1000_device_init(struct aqt1000 *aqt) +{ + int ret = 0; + + mutex_init(&aqt->io_lock); + mutex_init(&aqt->xfer_lock); + mutex_init(&aqt->cdc_bg_clk_lock); + mutex_init(&aqt->master_bias_lock); + + ret = aqt1000_bringup(aqt); + if (ret) { + ret = -EPROBE_DEFER; + goto done; + } + + ret = aqt_irq_init(aqt); + if (ret) + goto done; + + return ret; +done: + mutex_destroy(&aqt->io_lock); + mutex_destroy(&aqt->xfer_lock); + mutex_destroy(&aqt->cdc_bg_clk_lock); + mutex_destroy(&aqt->master_bias_lock); + return ret; +} + +static int aqt1000_i2c_write(struct aqt1000 *aqt1000, unsigned short reg, + void *val, int bytes) +{ + struct i2c_msg *msg; + int ret = 0; + u8 reg_addr = 0; + u8 data[bytes + 1]; + struct aqt1000_i2c *aqt1000_i2c; + u8 *value = (u8 *)val; + + aqt1000_i2c = &aqt1000->i2c_dev; + if (aqt1000_i2c == NULL || aqt1000_i2c->client == NULL) { + pr_err("%s: Failed to get device info\n", __func__); + return -ENODEV; + } + reg_addr = (u8)reg; + msg = &aqt1000_i2c->xfer_msg[0]; + msg->addr = aqt1000_i2c->client->addr; + msg->len = bytes + 1; + msg->flags = 0; + data[0] = reg; + data[1] = *value; + msg->buf = data; + ret = i2c_transfer(aqt1000_i2c->client->adapter, + aqt1000_i2c->xfer_msg, 1); + /* Try again if the write fails */ + if (ret != 1) { + ret = i2c_transfer(aqt1000_i2c->client->adapter, + aqt1000_i2c->xfer_msg, 1); + if (ret != 1) { + dev_err(aqt1000->dev, + "%s: I2C write failed, reg: 0x%x ret: %d\n", + __func__, reg, ret); + return ret; + } + } + dev_dbg(aqt1000->dev, "%s: write success register = %x val = %x\n", + __func__, reg, data[1]); + return 0; +} + +static int aqt1000_i2c_read(struct aqt1000 *aqt1000, unsigned short reg, + void *dst, int bytes) +{ + struct i2c_msg *msg; + int ret = 0; + u8 reg_addr = 0; + struct aqt1000_i2c *aqt1000_i2c; + u8 i = 0; + unsigned char *dest = (unsigned char *)dst; + + aqt1000_i2c = &aqt1000->i2c_dev; + if (aqt1000_i2c == NULL || aqt1000_i2c->client == NULL) { + pr_err("%s: Failed to get device info\n", __func__); + return -ENODEV; + } + for (i = 0; i < bytes; i++) { + reg_addr = (u8)reg++; + msg = &aqt1000_i2c->xfer_msg[0]; + msg->addr = aqt1000_i2c->client->addr; + msg->len = 1; + msg->flags = 0; + msg->buf = ®_addr; + + msg = &aqt1000_i2c->xfer_msg[1]; + msg->addr = aqt1000_i2c->client->addr; + msg->len = 1; + msg->flags = I2C_M_RD; + msg->buf = dest++; + ret = i2c_transfer(aqt1000_i2c->client->adapter, + aqt1000_i2c->xfer_msg, 2); + + /* Try again if read fails first time */ + if (ret != 2) { + ret = i2c_transfer(aqt1000_i2c->client->adapter, + aqt1000_i2c->xfer_msg, 2); + if (ret != 2) { + dev_err(aqt1000->dev, + "%s: I2C read failed, reg: 0x%x\n", + __func__, reg); + return ret; + } + } + } + return 0; +} + +static int aqt1000_reset(struct device *dev) +{ + struct aqt1000 *aqt1000; + int rc = 0; + + if (!dev) + return -ENODEV; + + aqt1000 = dev_get_drvdata(dev); + if (!aqt1000) + return -EINVAL; + + if (!aqt1000->aqt_rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + if (!msm_cdc_pinctrl_get_state(aqt1000->aqt_rst_np)) { + rc = msm_cdc_pinctrl_select_sleep_state(aqt1000->aqt_rst_np); + if (rc) { + dev_err(dev, "%s: aqt sleep state request fail!\n", + __func__); + return rc; + } + + /* 20ms sleep required after pulling the reset gpio to LOW */ + msleep(20); + + rc = msm_cdc_pinctrl_select_active_state(aqt1000->aqt_rst_np); + if (rc) { + dev_err(dev, + "%s: aqt active state request fail, ret: %d\n", + __func__, rc); + return rc; + } + /* 20ms sleep required after pulling the reset gpio to HIGH */ + msleep(20); + } + + return rc; +} + +static int aqt1000_read_of_property_u32(struct device *dev, const char *name, + u32 *val) +{ + int rc = 0; + + rc = of_property_read_u32(dev->of_node, name, val); + if (rc) + dev_err(dev, "%s: Looking up %s property in node %s failed", + __func__, name, dev->of_node->full_name); + + return rc; +} + +static void aqt1000_dt_parse_micbias_info(struct device *dev, + struct aqt1000_micbias_setting *mb) +{ + u32 prop_val; + int rc; + + if (of_find_property(dev->of_node, "qcom,cdc-micbias-ldoh-v", NULL)) { + rc = aqt1000_read_of_property_u32(dev, + "qcom,cdc-micbias-ldoh-v", + &prop_val); + if (!rc) + mb->ldoh_v = (u8)prop_val; + } + + /* MB1 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt1-mv", + NULL)) { + rc = aqt1000_read_of_property_u32(dev, + "qcom,cdc-micbias-cfilt1-mv", + &prop_val); + if (!rc) + mb->cfilt1_mv = prop_val; + + rc = aqt1000_read_of_property_u32(dev, + "qcom,cdc-micbias1-cfilt-sel", + &prop_val); + if (!rc) + mb->bias1_cfilt_sel = (u8)prop_val; + + } else if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv", + NULL)) { + rc = aqt1000_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__); + } + + /* Print micbias info */ + dev_dbg(dev, "%s: ldoh_v %u cfilt1_mv %u micb1_mv %u \n", __func__, + (u32)mb->ldoh_v, (u32)mb->cfilt1_mv, (u32)mb->micb1_mv); +} + +static struct aqt1000_pdata *aqt1000_populate_dt_data(struct device *dev) +{ + struct aqt1000_pdata *pdata; + u32 prop_val; + + if (!dev || !dev->of_node) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(struct aqt1000_pdata), + GFP_KERNEL); + if (!pdata) + return NULL; + + /* Parse power supplies */ + msm_cdc_get_power_supplies(dev, &pdata->regulator, + &pdata->num_supplies); + if (!pdata->regulator || (pdata->num_supplies <= 0)) { + dev_err(dev, "%s: no power supplies defined for codec\n", + __func__); + goto err_power_sup; + } + + /* Parse micbias info */ + aqt1000_dt_parse_micbias_info(dev, &pdata->micbias); + + pdata->aqt_rst_np = of_parse_phandle(dev->of_node, + "qcom,aqt-rst-gpio-node", 0); + if (!pdata->aqt_rst_np) { + dev_err(dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,aqt-rst-gpio-node", + dev->of_node->full_name); + goto err_parse_dt_prop; + } + + if (!(aqt1000_read_of_property_u32(dev, "qcom,cdc-ext-clk-rate", + &prop_val))) + pdata->ext_clk_rate = prop_val; + if (pdata->ext_clk_rate != AQT1000_CLK_24P576MHZ && + pdata->ext_clk_rate != AQT1000_CLK_19P2MHZ && + pdata->ext_clk_rate != AQT1000_CLK_12P288MHZ) { + /* Use the default ext_clk_rate if the DT value is wrong */ + pdata->ext_clk_rate = AQT1000_CLK_9P6MHZ; + } + + prop_val = 0; + if (!(aqt1000_read_of_property_u32(dev, "qcom,cdc-mclk-clk-rate", + &prop_val))) + pdata->mclk_rate = prop_val; + + if (pdata->mclk_rate != AQT1000_CLK_9P6MHZ && + pdata->mclk_rate != AQT1000_CLK_12P288MHZ) { + dev_err(dev, "%s: Invalid mclk_rate = %u\n", __func__, + pdata->mclk_rate); + goto err_parse_dt_prop; + } + if (pdata->ext_clk_rate % pdata->mclk_rate) { + dev_err(dev, + "%s: Invalid clock group, ext_clk = %d mclk = %d\n", + __func__, pdata->ext_clk_rate, pdata->mclk_rate); + goto err_parse_dt_prop; + } + + pdata->irq_gpio = of_get_named_gpio(dev->of_node, + "qcom,gpio-connect", 0); + if (!gpio_is_valid(pdata->irq_gpio)) { + dev_err(dev, "%s: TLMM connect gpio not found\n", __func__); + goto err_parse_dt_prop; + } + + return pdata; + +err_parse_dt_prop: + devm_kfree(dev, pdata->regulator); + pdata->regulator = NULL; + pdata->num_supplies = 0; +err_power_sup: + devm_kfree(dev, pdata); + return NULL; +} + +static int aqt1000_bringdown(struct device *dev) +{ + /* No sequence for teardown */ + + return 0; +} + +static void aqt1000_device_exit(struct aqt1000 *aqt) +{ + aqt_irq_exit(aqt); + aqt1000_bringdown(aqt->dev); + mutex_destroy(&aqt->io_lock); + mutex_destroy(&aqt->xfer_lock); + mutex_destroy(&aqt->cdc_bg_clk_lock); + mutex_destroy(&aqt->master_bias_lock); +} + +static int aqt1000_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct aqt1000 *aqt1000 = NULL; + struct aqt1000_pdata *pdata = NULL; + int ret = 0; + + pdata = aqt1000_populate_dt_data(&client->dev); + if (!pdata) { + dev_err(&client->dev, + "%s: Fail to obtain pdata from device tree\n", + __func__); + ret = -EINVAL; + goto fail; + } + client->dev.platform_data = pdata; + + aqt1000 = devm_kzalloc(&client->dev, sizeof(struct aqt1000), + GFP_KERNEL); + if (!aqt1000) { + ret = -ENOMEM; + goto fail; + } + + aqt1000->regmap = aqt1000_regmap_init(&client->dev, + &aqt1000_regmap_config); + if (IS_ERR(aqt1000->regmap)) { + ret = PTR_ERR(aqt1000->regmap); + dev_err(&client->dev, + "%s: Failed to init register map: %d\n", + __func__, ret); + goto fail; + } + aqt1000->aqt_rst_np = pdata->aqt_rst_np; + if (!aqt1000->aqt_rst_np) { + dev_err(&client->dev, "%s: pinctrl not used for rst_n\n", + __func__); + ret = -EINVAL; + goto fail; + } + + if (i2c_check_functionality(client->adapter, + I2C_FUNC_I2C) == 0) { + dev_dbg(&client->dev, "%s: can't talk I2C?\n", __func__); + ret = -EIO; + goto fail; + } + dev_set_drvdata(&client->dev, aqt1000); + aqt1000->dev = &client->dev; + aqt1000->dev_up = true; + aqt1000->mclk_rate = pdata->mclk_rate; + aqt1000->irq = client->irq; + + aqt1000->num_of_supplies = pdata->num_supplies; + ret = msm_cdc_init_supplies(aqt1000->dev, &aqt1000->supplies, + pdata->regulator, + pdata->num_supplies); + if (!aqt1000->supplies) { + dev_err(aqt1000->dev, "%s: Cannot init aqt supplies\n", + __func__); + goto err_codec; + } + ret = msm_cdc_enable_static_supplies(aqt1000->dev, + aqt1000->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(aqt1000->dev, "%s: aqt static supply enable failed!\n", + __func__); + goto err_codec; + } + /* 5 usec sleep is needed as per HW requirement */ + usleep_range(5, 10); + + ret = aqt1000_reset(aqt1000->dev); + if (ret) { + dev_err(aqt1000->dev, "%s: Codec reset failed\n", __func__); + goto err_supplies; + } + + aqt1000->i2c_dev.client = client; + aqt1000->read_dev = aqt1000_i2c_read; + aqt1000->write_dev = aqt1000_i2c_write; + + ret = aqt1000_device_init(aqt1000); + if (ret) { + pr_err("%s: error, initializing device failed (%d)\n", + __func__, ret); + goto err_supplies; + } + + pm_runtime_set_active(aqt1000->dev); + pm_runtime_enable(aqt1000->dev); + + ret = aqt_register_codec(&client->dev); + if (ret) { + dev_err(aqt1000->dev, "%s: Codec registration failed\n", + __func__); + goto err_cdc_register; + } + + return ret; + +err_cdc_register: + pm_runtime_disable(aqt1000->dev); + aqt1000_device_exit(aqt1000); +err_supplies: + msm_cdc_release_supplies(aqt1000->dev, aqt1000->supplies, + pdata->regulator, + pdata->num_supplies); + pdata->regulator = NULL; + pdata->num_supplies = 0; +err_codec: + devm_kfree(&client->dev, aqt1000); + dev_set_drvdata(&client->dev, NULL); +fail: + return ret; +} + +static int aqt1000_i2c_remove(struct i2c_client *client) +{ + struct aqt1000 *aqt; + struct aqt1000_pdata *pdata = client->dev.platform_data; + + aqt = dev_get_drvdata(&client->dev); + + pm_runtime_disable(aqt->dev); + msm_cdc_release_supplies(aqt->dev, aqt->supplies, + pdata->regulator, + pdata->num_supplies); + aqt1000_device_exit(aqt); + dev_set_drvdata(&client->dev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int aqt1000_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "%s system resume\n", __func__); + + return 0; +} + +static int aqt1000_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "%s system suspend\n", __func__); + + return 0; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int aqt1000_i2c_resume(struct device *dev) +{ + pr_debug("%s system resume\n", __func__); + return 0; +} + +static int aqt1000_i2c_suspend(struct device *dev) +{ + pr_debug("%s system suspend\n", __func__); + return 0; +} +#endif + +static struct i2c_device_id aqt1000_id_table[] = { + {"aqt1000-i2c", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, aqt1000_id_table); + +static const struct dev_pm_ops aqt1000_i2c_pm_ops = { + SET_RUNTIME_PM_OPS(aqt1000_runtime_suspend, + aqt1000_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(aqt1000_i2c_suspend, + aqt1000_i2c_resume) +}; + +static const struct of_device_id aqt_match_table[] = { + {.compatible = "qcom,aqt1000-i2c-codec"}, + {} +}; +MODULE_DEVICE_TABLE(of, aqt_match_table); + +static struct i2c_driver aqt1000_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "aqt1000-i2c-codec", +#ifdef CONFIG_PM_SLEEP + .pm = &aqt1000_i2c_pm_ops, +#endif + .of_match_table = aqt_match_table, + }, + .id_table = aqt1000_id_table, + .probe = aqt1000_i2c_probe, + .remove = aqt1000_i2c_remove, +}; + +static int __init aqt1000_init(void) +{ + return i2c_add_driver(&aqt1000_i2c_driver); +} +module_init(aqt1000_init); + +static void __exit aqt1000_exit(void) +{ + i2c_del_driver(&aqt1000_i2c_driver); +} +module_exit(aqt1000_exit); + +MODULE_DESCRIPTION("AQT1000 Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-internal.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-internal.h new file mode 100644 index 0000000000..0ae66703f0 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-internal.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _AQT1000_INTERNAL_H +#define _AQT1000_INTERNAL_H + +#include +#include +#include + +#define AQT1000_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define AQT1000_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400) + +#define AQT1000_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +#define AQT1000_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define AQT1000_FORMATS_S16_LE (SNDRV_PCM_FMTBIT_S16_LE) + +/* Macros for packing register writes into a U32 */ +#define AQT1000_PACKED_REG_SIZE sizeof(u32) +#define AQT1000_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \ + do { \ + ((reg) = ((packed >> 16) & (0xffff))); \ + ((mask) = ((packed >> 8) & (0xff))); \ + ((val) = ((packed) & (0xff))); \ + } while (0) + +#define STRING(name) #name +#define AQT_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define AQT_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define AQT_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + + +#define AQT1000_INTERP_MUX_NUM_INPUTS 3 +#define AQT1000_RX_PATH_CTL_OFFSET 20 + +#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE)) + +#define AQT1000_REG_BITS 8 +#define AQT1000_MAX_VALID_ADC_MUX 3 + +#define AQT1000_AMIC_PWR_LEVEL_LP 0 +#define AQT1000_AMIC_PWR_LEVEL_DEFAULT 1 +#define AQT1000_AMIC_PWR_LEVEL_HP 2 +#define AQT1000_AMIC_PWR_LVL_MASK 0x60 +#define AQT1000_AMIC_PWR_LVL_SHIFT 0x5 + +#define AQT1000_DEC_PWR_LVL_MASK 0x06 +#define AQT1000_DEC_PWR_LVL_DF 0x00 +#define AQT1000_DEC_PWR_LVL_LP 0x02 +#define AQT1000_DEC_PWR_LVL_HP 0x04 +#define AQT1000_STRING_LEN 100 + +#define AQT1000_CDC_SIDETONE_IIR_COEFF_MAX 5 + +#define AQT1000_MAX_MICBIAS 1 +#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone" + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +enum { + AUDIO_NOMINAL, + HPH_PA_DELAY, + CLSH_Z_CONFIG, + ANC_MIC_AMIC1, + ANC_MIC_AMIC2, + ANC_MIC_AMIC3, +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, + INTn_1_INP_SEL_IIR0, + INTn_1_INP_SEL_IIR1, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_PROXIMITY, +}; + +/* Codec supports 2 IIR filters */ +enum { + IIR0 = 0, + IIR1, + IIR_MAX, +}; + +enum { + ASRC_IN_HPHL, + ASRC_IN_HPHR, + ASRC_INVALID, +}; + +enum { + CONV_88P2K_TO_384K, + CONV_96K_TO_352P8K, + CONV_352P8K_TO_384K, + CONV_384K_TO_352P8K, + CONV_384K_TO_384K, + CONV_96K_TO_384K, +}; + +enum aqt_notify_event { + AQT_EVENT_INVALID, + /* events for micbias ON and OFF */ + AQT_EVENT_PRE_MICBIAS_1_OFF, + AQT_EVENT_POST_MICBIAS_1_OFF, + AQT_EVENT_PRE_MICBIAS_1_ON, + AQT_EVENT_POST_MICBIAS_1_ON, + AQT_EVENT_PRE_DAPM_MICBIAS_1_OFF, + AQT_EVENT_POST_DAPM_MICBIAS_1_OFF, + AQT_EVENT_PRE_DAPM_MICBIAS_1_ON, + AQT_EVENT_POST_DAPM_MICBIAS_1_ON, + /* events for PA ON and OFF */ + AQT_EVENT_PRE_HPHL_PA_ON, + AQT_EVENT_POST_HPHL_PA_OFF, + AQT_EVENT_PRE_HPHR_PA_ON, + AQT_EVENT_POST_HPHR_PA_OFF, + AQT_EVENT_PRE_HPHL_PA_OFF, + AQT_EVENT_PRE_HPHR_PA_OFF, + AQT_EVENT_OCP_OFF, + AQT_EVENT_OCP_ON, + AQT_EVENT_LAST, +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +extern struct regmap_config aqt1000_regmap_config; +extern int aqt_register_codec(struct device *dev); + +#endif /* _AQT1000_INTERNAL_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-irq.c b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-irq.c new file mode 100644 index 0000000000..34d647a8f8 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-irq.c @@ -0,0 +1,283 @@ +// 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 "pdata.h" +#include "aqt1000.h" + +#include "aqt1000-registers.h" +#include "aqt1000-irq.h" + +static const struct regmap_irq aqt1000_irqs[AQT1000_NUM_IRQS] = { + REGMAP_IRQ_REG(AQT1000_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x01), + REGMAP_IRQ_REG(AQT1000_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x02), + REGMAP_IRQ_REG(AQT1000_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(AQT1000_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(AQT1000_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(AQT1000_IRQ_HPH_PA_OCPL_FAULT, 0, 0x20), + REGMAP_IRQ_REG(AQT1000_IRQ_HPH_PA_OCPR_FAULT, 0, 0x40), + REGMAP_IRQ_REG(AQT1000_IRQ_HPH_PA_CNPL_COMPLETE, 0, 0x80), + REGMAP_IRQ_REG(AQT1000_IRQ_HPH_PA_CNPR_COMPLETE, 1, 0x01), + REGMAP_IRQ_REG(AQT1000_CDC_HPHL_SURGE, 1, 0x02), + REGMAP_IRQ_REG(AQT1000_CDC_HPHR_SURGE, 1, 0x04), +}; + +static const struct regmap_irq_chip aqt_regmap_irq_chip = { + .name = "AQT1000", + .irqs = aqt1000_irqs, + .num_irqs = ARRAY_SIZE(aqt1000_irqs), + .num_regs = 2, + .status_base = AQT1000_INTR_CTRL_INT_STATUS_2, + .mask_base = AQT1000_INTR_CTRL_INT_MASK_2, + .unmask_base = AQT1000_INTR_CTRL_INT_CLEAR_2, + .ack_base = AQT1000_INTR_CTRL_INT_STATUS_2, + .runtime_pm = true, +}; + +static int aqt_map_irq(struct aqt1000 *aqt, int irq) +{ + return regmap_irq_get_virq(aqt->irq_chip, irq); +} + +/** + * aqt_request_irq: Request a thread handler for the given IRQ + * @aqt: pointer to aqt1000 structure + * @irq: irq number + * @name: name for the IRQ thread + * @handler: irq handler + * @data: data pointer + * + * Returns 0 on success or error on failure + */ +int aqt_request_irq(struct aqt1000 *aqt, int irq, const char *name, + irq_handler_t handler, void *data) +{ + irq = aqt_map_irq(aqt, irq); + if (irq < 0) + return irq; + + return request_threaded_irq(irq, NULL, handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + name, data); +} +EXPORT_SYMBOL(aqt_request_irq); + +/** + * aqt_free_irq: Free the IRQ resources allocated during request_irq + * @aqt: pointer to aqt1000 structure + * @irq: irq number + * @data: data pointer + */ +void aqt_free_irq(struct aqt1000 *aqt, int irq, void *data) +{ + irq = aqt_map_irq(aqt, irq); + if (irq < 0) + return; + + free_irq(irq, data); +} +EXPORT_SYMBOL(aqt_free_irq); + +/** + * aqt_enable_irq: Enable the given IRQ + * @aqt: pointer to aqt1000 structure + * @irq: irq number + */ +void aqt_enable_irq(struct aqt1000 *aqt, int irq) +{ + if (aqt) + enable_irq(aqt_map_irq(aqt, irq)); +} +EXPORT_SYMBOL(aqt_enable_irq); + +/** + * aqt_disable_irq: Disable the given IRQ + * @aqt: pointer to aqt1000 structure + * @irq: irq number + */ +void aqt_disable_irq(struct aqt1000 *aqt, int irq) +{ + if (aqt) + disable_irq(aqt_map_irq(aqt, irq)); +} +EXPORT_SYMBOL(aqt_disable_irq); + +static irqreturn_t aqt_irq_thread(int irq, void *data) +{ + int ret = 0; + u8 sts[2]; + struct aqt1000 *aqt = data; + int num_irq_regs = aqt->num_irq_regs; + struct aqt1000_pdata *pdata; + + pdata = dev_get_platdata(aqt->dev); + + memset(sts, 0, sizeof(sts)); + ret = regmap_bulk_read(aqt->regmap, AQT1000_INTR_CTRL_INT_STATUS_2, + sts, num_irq_regs); + if (ret < 0) { + dev_err(aqt->dev, "%s: Failed to read intr status: %d\n", + __func__, ret); + } else if (ret == 0) { + while (gpio_get_value_cansleep(pdata->irq_gpio)) + handle_nested_irq(irq_find_mapping(aqt->virq, 0)); + } + + return IRQ_HANDLED; +} + +static void aqt_irq_disable(struct irq_data *data) +{ +} + +static void aqt_irq_enable(struct irq_data *data) +{ +} + +static struct irq_chip aqt_irq_chip = { + .name = "AQT", + .irq_disable = aqt_irq_disable, + .irq_enable = aqt_irq_enable, +}; + +static struct lock_class_key aqt_irq_lock_class; +static struct lock_class_key aqt_irq_lock_requested_class; + +static int aqt_irq_map(struct irq_domain *irqd, unsigned int virq, + irq_hw_number_t hw) +{ + struct aqt1000 *data = irqd->host_data; + + irq_set_chip_data(virq, data); + irq_set_chip_and_handler(virq, &aqt_irq_chip, handle_simple_irq); + irq_set_lockdep_class(virq, &aqt_irq_lock_class, + &aqt_irq_lock_requested_class); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops aqt_domain_ops = { + .map = aqt_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +/** + * aqt_irq_init: Initializes IRQ module + * @aqt: pointer to aqt1000 structure + * + * Returns 0 on success or error on failure + */ +int aqt_irq_init(struct aqt1000 *aqt) +{ + int i, ret; + unsigned int flags = IRQF_ONESHOT; + struct irq_data *irq_data; + struct aqt1000_pdata *pdata; + + if (!aqt) { + pr_err("%s: Null pointer handle\n", __func__); + return -EINVAL; + } + + pdata = dev_get_platdata(aqt->dev); + if (!pdata) { + dev_err(aqt->dev, "%s: Invalid platform data\n", __func__); + return -EINVAL; + } + + /* Select default if not defined in DT */ + flags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; + if (pdata->irq_flags) + flags = pdata->irq_flags; + + if (pdata->irq_gpio) { + aqt->irq = gpio_to_irq(pdata->irq_gpio); + ret = devm_gpio_request_one(aqt->dev, pdata->irq_gpio, + GPIOF_IN, "AQT IRQ"); + if (ret) { + dev_err(aqt->dev, "%s: Failed to request gpio %d\n", + __func__, ret); + pdata->irq_gpio = 0; + return ret; + } + } + + irq_data = irq_get_irq_data(aqt->irq); + if (!irq_data) { + dev_err(aqt->dev, "%s: Invalid IRQ: %d\n", + __func__, aqt->irq); + return -EINVAL; + } + + aqt->num_irq_regs = aqt_regmap_irq_chip.num_regs; + for (i = 0; i < aqt->num_irq_regs; i++) { + regmap_write(aqt->regmap, + (AQT1000_INTR_CTRL_INT_TYPE_2 + i), 0); + } + + aqt->virq = irq_domain_add_linear(NULL, 1, &aqt_domain_ops, aqt); + if (!aqt->virq) { + dev_err(aqt->dev, "%s: Failed to add IRQ domain\n", __func__); + ret = -EINVAL; + goto err; + } + ret = regmap_add_irq_chip(aqt->regmap, + irq_create_mapping(aqt->virq, 0), + IRQF_ONESHOT, 0, &aqt_regmap_irq_chip, + &aqt->irq_chip); + if (ret) { + dev_err(aqt->dev, "%s: Failed to add IRQs: %d\n", + __func__, ret); + goto err; + } + + ret = request_threaded_irq(aqt->irq, NULL, aqt_irq_thread, flags, + "aqt", aqt); + if (ret) { + dev_err(aqt->dev, "%s: failed to register irq: %d\n", + __func__, ret); + goto err_irq; + } + + return 0; + +err_irq: + regmap_del_irq_chip(irq_create_mapping(aqt->virq, 1), aqt->irq_chip); +err: + return ret; +} +EXPORT_SYMBOL(aqt_irq_init); + +/** + * aqt_irq_exit: Uninitialize regmap IRQ and free IRQ resources + * @aqt: pointer to aqt1000 structure + * + * Returns 0 on success or error on failure + */ +int aqt_irq_exit(struct aqt1000 *aqt) +{ + if (!aqt) { + pr_err("%s: Null pointer handle\n", __func__); + return -EINVAL; + } + regmap_del_irq_chip(irq_create_mapping(aqt->virq, 1), aqt->irq_chip); + free_irq(aqt->irq, aqt); + + return 0; +} +EXPORT_SYMBOL(aqt_irq_exit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-irq.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-irq.h new file mode 100644 index 0000000000..6fb29b1a68 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-irq.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __AQT1000_IRQ_H_ +#define __AQT1000_IRQ_H_ + +#include +#include +#include + +enum { + /* INTR_CTRL_INT_MASK_2 */ + AQT1000_IRQ_MBHC_BUTTON_RELEASE_DET = 0, + AQT1000_IRQ_MBHC_BUTTON_PRESS_DET, + AQT1000_IRQ_MBHC_ELECT_INS_REM_DET, + AQT1000_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + AQT1000_IRQ_MBHC_SW_DET, + AQT1000_IRQ_HPH_PA_OCPL_FAULT, + AQT1000_IRQ_HPH_PA_OCPR_FAULT, + AQT1000_IRQ_HPH_PA_CNPL_COMPLETE, + + /* INTR_CTRL_INT_MASK_3 */ + AQT1000_IRQ_HPH_PA_CNPR_COMPLETE, + AQT1000_CDC_HPHL_SURGE, + AQT1000_CDC_HPHR_SURGE, + AQT1000_NUM_IRQS, +}; + +int aqt_request_irq(struct aqt1000 *aqt, int irq, const char *name, + irq_handler_t handler, void *data); +void aqt_free_irq(struct aqt1000 *aqt, int irq, void *data); +int aqt_irq_init(struct aqt1000 *aqt); +int aqt_irq_exit(struct aqt1000 *aqt); +void aqt_enable_irq(struct aqt1000 *aqt, int irq); +void aqt_disable_irq(struct aqt1000 *aqt, int irq); + +#endif /* __AQT1000_IRQ_H_ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-mbhc.c b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-mbhc.c new file mode 100644 index 0000000000..33a7c974cd --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-mbhc.c @@ -0,0 +1,1088 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aqt1000.h" +#include "aqt1000-api.h" +#include "aqt1000-mbhc.h" +#include "aqt1000-registers.h" +#include "aqt1000-irq.h" +#include "pdata.h" +#include +#include + +#define AQT_ZDET_SUPPORTED true +/* Z value defined in milliohm */ +#define AQT_ZDET_VAL_32 32000 +#define AQT_ZDET_VAL_400 400000 +#define AQT_ZDET_VAL_1200 1200000 +#define AQT_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define AQT_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define AQT_ZDET_NUM_MEASUREMENTS 900 +#define AQT_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define AQT_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define AQT_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define AQT_MBHC_ZDET_CONST (86 * 16384) +#define AQT_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", + AQT1000_ANA_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + AQT1000_ANA_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + AQT1000_ANA_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + AQT1000_MBHC_NEW_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + AQT1000_ANA_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + AQT1000_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + AQT1000_ANA_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + AQT1000_ANA_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + AQT1000_ANA_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + AQT1000_ANA_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + AQT1000_ANA_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + AQT1000_ANA_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + AQT1000_MBHC_NEW_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + AQT1000_MBHC_NEW_CTL_1, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + AQT1000_MBHC_NEW_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + AQT1000_ANA_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + AQT1000_ANA_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + AQT1000_ANA_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + AQT1000_ANA_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + AQT1000_HPH_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + AQT1000_ANA_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + AQT1000_ANA_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + AQT1000_ANA_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + AQT1000_ANA_MICB1, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + AQT1000_HPH_CNP_WG_TIME, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + AQT1000_ANA_HPH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + AQT1000_ANA_HPH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + AQT1000_ANA_HPH, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + AQT1000_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", + AQT1000_MBHC_CTL_BCS, 0x02, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + AQT1000_MBHC_NEW_FSM_STATUS, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + AQT1000_MBHC_NEW_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", + AQT1000_HPH_L_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN", + AQT1000_HPH_R_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS", + AQT1000_INTR_CTRL_INT_STATUS_2, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS", + AQT1000_INTR_CTRL_INT_STATUS_2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN", + AQT1000_MBHC_NEW_CTL_1, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", AQT1000_MBHC_NEW_FSM_STATUS, + 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", AQT1000_MBHC_NEW_FSM_STATUS, + 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", AQT1000_MBHC_NEW_ADC_RESULT, + 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", AQT1000_ANA_MICB1, 0x3F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE", + AQT1000_MBHC_NEW_CTL_1, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE", + AQT1000_MBHC_NEW_CTL_1, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN", + AQT1000_ANA_MBHC_ZDET, 0x02, 1, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = AQT1000_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = AQT1000_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = AQT1000_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = AQT1000_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = AQT1000_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = AQT1000_IRQ_HPH_PA_OCPL_FAULT, + .hph_right_ocp = AQT1000_IRQ_HPH_PA_OCPR_FAULT, +}; + +struct aqt_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static int aqt_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct aqt1000 *aqt = dev_get_drvdata(component->dev); + + return aqt_request_irq(aqt, irq, name, handler, data); +} + +static void aqt_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct aqt1000 *aqt = dev_get_drvdata(component->dev); + + if (enable) + aqt_enable_irq(aqt, irq); + else + aqt_disable_irq(aqt, irq); +} + +static int aqt_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct aqt1000 *aqt = dev_get_drvdata(component->dev); + + aqt_free_irq(aqt, irq, data); + + return 0; +} + +static void aqt_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, + AQT1000_MBHC_NEW_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, + AQT1000_MBHC_NEW_CTL_1, + 0x80, 0x00); +} + +static int aqt_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read32(component, + AQT1000_ANA_MBHC_RESULT_3) & 0x7; +} + +static void aqt_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, + AQT1000_ANA_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, + AQT1000_ANA_MBHC_ELECT, + 0x01, 0x00); +} + +static void aqt_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, + AQT1000_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 aqt_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + struct snd_soc_component *component = mbhc->component; + struct aqt1000 *aqt = dev_get_drvdata(component->dev); + bool ret = 0; + + dev_dbg(aqt->dev, "%s: lock: %d\n", __func__, lock); + + return ret; +} + +static int aqt_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct aqt1000_mbhc *aqt_mbhc; + + aqt_mbhc = container_of(mbhc, struct aqt1000_mbhc, wcd_mbhc); + + if (enable) + return blocking_notifier_chain_register(&aqt_mbhc->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &aqt_mbhc->notifier, nblock); +} + +static bool aqt_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + u8 val; + + if (micb_num == MIC_BIAS_1) { + val = ((snd_soc_component_read32( + mbhc->component, AQT1000_ANA_MICB1) & 0xC0) + >> 6); + if (val == 0x01) + return true; + } + return false; +} + +static bool aqt_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + return (snd_soc_component_read32(component, AQT1000_ANA_HPH) & 0xC0) ? + true : false; +} + +static void aqt_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, + AQT1000_MBHC_NEW_INT_MECH_DET_CURRENT, + 0x1F, pull_up_cur); +} + +static int aqt_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + int ret = 0; + + /* + * If micbias is requested, make sure that there + * is vote to enable mclk + */ + if (req == MICB_ENABLE) + aqt_cdc_mclk_enable(component, true); + + ret = aqt_micbias_control(component, micb_num, req, false); + + /* + * Release vote for mclk while requesting for + * micbias disable + */ + if (req == MICB_DISABLE) + aqt_cdc_mclk_enable(component, false); + + return ret; +} + +static void aqt_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, + AQT1000_ANA_MICB1_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, + AQT1000_ANA_MICB1_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, + AQT1000_ANA_MICB1_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, + AQT1000_ANA_MICB1_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *aqt_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct aqt1000_mbhc *aqt_mbhc; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + aqt_mbhc = container_of(mbhc, struct aqt1000_mbhc, wcd_mbhc); + + if (!component) { + pr_err("%s: NULL codec pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(aqt_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 aqt_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct aqt1000_pdata *pdata = dev_get_platdata(component->dev); + int rc, micb_mv; + + if (micb_num != MIC_BIAS_1) + 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.micb1_mv >= WCD_MBHC_THR_HS_MICB_MV) + return 0; + + micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb1_mv; + + rc = aqt_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_1); + + return rc; +} + +static inline void aqt_mbhc_get_result_params(struct aqt1000 *aqt, + 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(aqt->regmap, AQT1000_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < AQT_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(aqt->regmap, AQT1000_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(aqt->regmap, AQT1000_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(aqt->regmap, AQT1000_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = AQT_MBHC_GET_X1(val); + c1 = AQT_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(aqt->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 = (AQT_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = AQT_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(aqt->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + while (x1) { + regmap_bulk_read(aqt->regmap, + AQT1000_ANA_MBHC_RESULT_1, (u8 *)&val, 2); + x1 = AQT_MBHC_GET_X1(val); + i++; + if (i == AQT_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void aqt_mbhc_zdet_ramp(struct snd_soc_component *component, + struct aqt_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct aqt1000 *aqt = dev_get_drvdata(component->dev); + int32_t zdet = 0; + + snd_soc_component_update_bits(component, + AQT1000_MBHC_NEW_ZDET_ANA_CTL, 0x70, + zdet_param->ldo_ctl << 4); + snd_soc_component_update_bits(component, AQT1000_ANA_MBHC_BTN5, + 0xFC, zdet_param->btn5); + snd_soc_component_update_bits(component, AQT1000_ANA_MBHC_BTN6, + 0xFC, zdet_param->btn6); + snd_soc_component_update_bits(component, AQT1000_ANA_MBHC_BTN7, + 0xFC, zdet_param->btn7); + snd_soc_component_update_bits(component, AQT1000_MBHC_NEW_ZDET_ANA_CTL, + 0x0F, zdet_param->noff); + snd_soc_component_update_bits(component, AQT1000_MBHC_NEW_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_ZDET, 0x80, 0x80); + dev_dbg(aqt->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + aqt_mbhc_get_result_params(aqt, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_ZDET, 0x40, 0x40); + dev_dbg(aqt->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + aqt_mbhc_get_result_params(aqt, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void aqt_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 < (AQT_ZDET_VAL_400/1000)) + q1 = snd_soc_component_read32(component, + AQT1000_CHIP_CFG0_EFUSE_VAL_OUT1 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read32(component, + AQT1000_CHIP_CFG0_EFUSE_VAL_OUT2 + (2 * flag_l_r)); + if (q1 & 0x80) + q1_cal = (10000 - ((q1 & 0x7F) * 25)); + else + q1_cal = (10000 + (q1 * 25)); + if (q1_cal > 0) + *z_val = ((*z_val) * 10000) / q1_cal; +} + +static void aqt_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct aqt1000 *aqt = 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 aqt_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 aqt_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, AQT1000_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read32(component, AQT1000_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read32(component, AQT1000_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read32(component, AQT1000_MBHC_CTL_CLK); + reg4 = snd_soc_component_read32(component, + AQT1000_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read32(component, + AQT1000_ANA_MBHC_ELECT) & 0x80) { + is_fsm_disable = true; + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_MECH, 0x01, 0x00); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + aqt_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + + if (!AQT_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) + goto left_ch_impedance; + + /* Second ramp for left ch */ + if (z1L < AQT_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1L > AQT_ZDET_VAL_400) && (z1L <= AQT_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1L > AQT_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + aqt_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + +left_ch_impedance: + if ((z1L == AQT_ZDET_FLOATING_IMPEDANCE) || + (z1L > AQT_ZDET_VAL_100K)) { + *zl = AQT_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1L/1000; + aqt_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 */ + aqt_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if (AQT_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { + if (((z1R > AQT_ZDET_VAL_1200) && + (zdet_param_ptr->noff == 0x6)) || + ((*zl) != AQT_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* Second ramp for right ch */ + if (z1R < AQT_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1R > AQT_ZDET_VAL_400) && + (z1R <= AQT_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1R > AQT_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + aqt_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + } +right_ch_impedance: + if ((z1R == AQT_ZDET_FLOATING_IMPEDANCE) || + (z1R > AQT_ZDET_VAL_100K)) { + *zr = AQT_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R/1000; + aqt_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 == AQT_ZDET_FLOATING_IMPEDANCE) && + (*zr == AQT_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == AQT_ZDET_FLOATING_IMPEDANCE) || + (*zr == AQT_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, AQT1000_HPH_R_ATEST, + 0x02, 0x02); + snd_soc_component_update_bits(component, AQT1000_HPH_PA_CTL2, + 0x40, 0x01); + if (*zl < (AQT_ZDET_VAL_32/1000)) + aqt_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls, NULL, d1); + else + aqt_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls, NULL, d1); + snd_soc_component_update_bits(component, AQT1000_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, AQT1000_HPH_R_ATEST, + 0x02, 0x00); + z1Ls /= 1000; + aqt_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, AQT1000_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, AQT1000_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, AQT1000_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, AQT1000_MBHC_NEW_ZDET_ANA_CTL, + reg4); + snd_soc_component_write(component, AQT1000_MBHC_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(aqt->regmap, + AQT1000_ANA_MBHC_ELECT, 0x80, 0x80); +} + +static void aqt_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, AQT1000_ANA_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, AQT1000_ANA_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, AQT1000_ANA_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, AQT1000_ANA_MBHC_MECH, + 0x02, 0x00); + } +} + +static void aqt_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, AQT1000_HPH_PA_CTL2, + 0x40, 0x40); + snd_soc_component_update_bits(component, AQT1000_HPH_PA_CTL2, + 0x10, 0x10); + } else { + snd_soc_component_update_bits(component, AQT1000_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, AQT1000_HPH_PA_CTL2, + 0x10, 0x00); + } +} + +static void aqt_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, + AQT1000_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, + AQT1000_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + snd_soc_component_update_bits(component, AQT1000_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); +} + +static void aqt_update_anc_state(struct snd_soc_component *component, + bool enable, int anc_num) +{ + if (enable) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0 + (20 * anc_num), + 0x10, 0x10); + else + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0 + (20 * anc_num), + 0x10, 0x00); +} + +static bool aqt_is_anc_on(struct wcd_mbhc *mbhc) +{ + bool anc_on = false; + u16 ancl, ancr; + + ancl = + (snd_soc_component_read32(mbhc->component, + AQT1000_CDC_RX1_RX_PATH_CFG0)) & 0x10; + ancr = + (snd_soc_component_read32(mbhc->component, + AQT1000_CDC_RX2_RX_PATH_CFG0)) & 0x10; + + anc_on = !!(ancl | ancr); + + return anc_on; +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = aqt_mbhc_request_irq, + .irq_control = aqt_mbhc_irq_control, + .free_irq = aqt_mbhc_free_irq, + .clk_setup = aqt_mbhc_clk_setup, + .map_btn_code_to_num = aqt_mbhc_btn_to_num, + .mbhc_bias = aqt_mbhc_mbhc_bias_control, + .set_btn_thr = aqt_mbhc_program_btn_thr, + .lock_sleep = aqt_mbhc_lock_sleep, + .register_notifier = aqt_mbhc_register_notifier, + .micbias_enable_status = aqt_mbhc_micb_en_status, + .hph_pa_on_status = aqt_mbhc_hph_pa_on_status, + .hph_pull_up_control_v2 = aqt_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = aqt_mbhc_request_micbias, + .mbhc_micb_ramp_control = aqt_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = aqt_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = aqt_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = aqt_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = aqt_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = aqt_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = aqt_mbhc_moisture_config, + .update_anc_state = aqt_update_anc_state, + .is_anc_on = aqt_is_anc_on, +}; + +static int aqt_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + struct aqt1000_mbhc *aqt_mbhc = aqt->mbhc; + struct wcd_mbhc *mbhc; + + if (!aqt_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + mbhc = &aqt_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 aqt_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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + struct aqt1000_mbhc *aqt_mbhc = aqt->mbhc; + + if (!aqt_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(&aqt_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, + aqt_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + aqt_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + aqt_hph_impedance_get, NULL), +}; + +/* + * aqt_mbhc_get_impedance: get impedance of headphone left and right channels + * @aqt_mbhc: handle to struct aqt_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 aqt_mbhc_get_impedance(struct aqt1000_mbhc *aqt_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (!aqt_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(&aqt_mbhc->wcd_mbhc, zl, zr); +} +EXPORT_SYMBOL(aqt_mbhc_get_impedance); + +/* + * aqt_mbhc_hs_detect: starts mbhc insertion/removal functionality + * @component: 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 aqt_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct aqt1000 *aqt; + struct aqt1000_mbhc *aqt_mbhc; + + if (!component) { + pr_err("%s: codec is NULL\n", __func__); + return -EINVAL; + } + + aqt = snd_soc_component_get_drvdata(component); + if (!aqt) { + pr_err("%s: aqt is NULL\n", __func__); + return -EINVAL; + } + + aqt_mbhc = aqt->mbhc; + if (!aqt_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + return wcd_mbhc_start(&aqt_mbhc->wcd_mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(aqt_mbhc_hs_detect); + +/* + * aqt_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void aqt_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct aqt1000 *aqt; + struct aqt1000_mbhc *aqt_mbhc; + + if (!component) { + pr_err("%s: codec is NULL\n", __func__); + return; + } + + aqt = snd_soc_component_get_drvdata(component); + if (!aqt) { + pr_err("%s: aqt is NULL\n", __func__); + return; + } + + aqt_mbhc = aqt->mbhc; + if (!aqt_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return; + } + wcd_mbhc_stop(&aqt_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL(aqt_mbhc_hs_detect_exit); + +/* + * aqt_mbhc_post_ssr_init: initialize mbhc for aqt post subsystem restart + * @mbhc: poniter to aqt_mbhc structure + * @component: handle to snd_soc_component * + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int aqt_mbhc_post_ssr_init(struct aqt1000_mbhc *mbhc, + struct snd_soc_component *component) +{ + int ret; + struct wcd_mbhc *wcd_mbhc; + + 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, AQT_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto done; + } + +done: + return ret; +} +EXPORT_SYMBOL(aqt_mbhc_post_ssr_init); + +/* + * aqt_mbhc_init: initialize mbhc for aqt + * @mbhc: poniter to aqt_mbhc struct pointer to store the configs + * @component: 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 aqt_mbhc_init(struct aqt1000_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + struct aqt1000_mbhc *aqt_mbhc; + struct wcd_mbhc *wcd_mbhc; + int ret; + + if (!component) { + pr_err("%s: codec is NULL\n", __func__); + return -EINVAL; + } + + aqt_mbhc = devm_kzalloc(component->dev, sizeof(struct aqt1000_mbhc), + GFP_KERNEL); + if (!aqt_mbhc) + return -ENOMEM; + + aqt_mbhc->aqt = dev_get_drvdata(component->dev); + aqt_mbhc->fw_data = fw_data; + BLOCKING_INIT_NOTIFIER_HEAD(&aqt_mbhc->notifier); + wcd_mbhc = &aqt_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, + AQT_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto err; + } + + (*mbhc) = aqt_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, aqt_mbhc); + return ret; +} +EXPORT_SYMBOL(aqt_mbhc_init); + +/* + * aqt_mbhc_deinit: deinitialize mbhc for aqt + * @component: handle to snd_soc_component * + */ +void aqt_mbhc_deinit(struct snd_soc_component *component) +{ + struct aqt1000 *aqt; + struct aqt1000_mbhc *aqt_mbhc; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + aqt = snd_soc_component_get_drvdata(component); + if (!aqt) { + pr_err("%s: aqt is NULL\n", __func__); + return; + } + + aqt_mbhc = aqt->mbhc; + if (aqt_mbhc) { + wcd_mbhc_deinit(&aqt_mbhc->wcd_mbhc); + devm_kfree(component->dev, aqt_mbhc); + } +} +EXPORT_SYMBOL(aqt_mbhc_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-mbhc.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-mbhc.h new file mode 100644 index 0000000000..770472c328 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-mbhc.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ +#ifndef __AQT1000_MBHC_H__ +#define __AQT1000_MBHC_H__ +#include + +struct aqt1000_mbhc { + struct wcd_mbhc wcd_mbhc; + struct blocking_notifier_head notifier; + struct aqt1000 *aqt; + struct fw_info *fw_data; + bool mbhc_started; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_AQT1000) +extern int aqt_mbhc_init(struct aqt1000_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data); +extern void aqt_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern int aqt_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void aqt_mbhc_deinit(struct snd_soc_component *component); +extern int aqt_mbhc_post_ssr_init(struct aqt1000_mbhc *mbhc, + struct snd_soc_component *component); +extern int aqt_mbhc_get_impedance(struct aqt1000_mbhc *aqt_mbhc, + uint32_t *zl, uint32_t *zr); +#else +static inline int aqt_mbhc_init(struct aqt1000_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + return 0; +} +static inline void aqt_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ +} +static inline int aqt_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void aqt_mbhc_deinit(struct snd_soc_component *component) +{ +} +static inline int aqt_mbhc_post_ssr_init(struct aqt1000_mbhc *mbhc, + struct snd_soc_component *component) +{ + return 0; +} + +static inline int aqt_mbhc_get_impedance(struct aqt1000_mbhc *aqt_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + +#endif /* __AQT1000_MBHC_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-reg-defaults.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-reg-defaults.h new file mode 100644 index 0000000000..760289bb63 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-reg-defaults.h @@ -0,0 +1,1608 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _AQT1000_REG_DEFAULTS_H +#define _AQT1000_REG_DEFAULTS_H + +#include +#include "aqt1000-registers.h" + +#define AQT1000_REG(reg) ((reg) & 0xFF) +#define AQT1000_PAGE_SIZE 256 + +enum { + AQT1000_PAGE_0 = 0, + AQT1000_PAGE_1, + AQT1000_PAGE_2, + AQT1000_PAGE_5 = 5, + AQT1000_PAGE_6, + AQT1000_PAGE_7, + AQT1000_PAGE_10 = 0xA, + AQT1000_PAGE_11, + AQT1000_PAGE_12, + AQT1000_PAGE_13, + AQT1000_PAGE_15 = 0xF, + AQT1000_PAGE_128, + AQT1000_PAGE_MAX, +}; + +enum { + AQT1000_WO = 0, + AQT1000_RO, + AQT1000_RW, +}; + +static const struct reg_default aqt1000_defaults[] = { + {AQT1000_CHIP_CFG1_PWR_MEM_SD, 0x07}, + {AQT1000_CHIP_CFG1_PWR_SYS_MEM_SD_RAM, 0x00}, + {AQT1000_CHIP_CFG1_PWR_SYS_MEM_SD_ROM, 0x00}, + {AQT1000_CHIP_CFG1_PWR_SYS_MEM_FORCE_DS_RAM, 0x00}, + {AQT1000_CHIP_CFG1_PWR_SYS_MEM_FORCE_DS_ROM, 0x00}, + {AQT1000_CHIP_CFG1_CLK_CFG_FLL, 0x20}, + {AQT1000_CHIP_CFG1_CLK_CFG_SPI_M, 0x01}, + {AQT1000_CHIP_CFG1_CLK_CFG_I2C_M, 0x01}, + {AQT1000_CHIP_CFG1_CLK_CFG_UART, 0x01}, + {AQT1000_CHIP_CFG1_RST_USB_SS, 0x0E}, + {AQT1000_CHIP_CFG1_RST_BLSP, 0x0F}, + {AQT1000_CHIP_CFG1_RST_BUS_MTRX, 0x00}, + {AQT1000_CHIP_CFG1_RST_MISC, 0x00}, + {AQT1000_CHIP_CFG1_ANA_WAIT_STATE_CTL, 0xCC}, + {AQT1000_PAGE1_PAGE_REGISTER, 0x00}, + {AQT1000_FLL_USER_CTL_0, 0x71}, + {AQT1000_FLL_USER_CTL_1, 0x34}, + {AQT1000_FLL_USER_CTL_2, 0x0B}, + {AQT1000_FLL_USER_CTL_3, 0x02}, + {AQT1000_FLL_USER_CTL_4, 0x04}, + {AQT1000_FLL_USER_CTL_5, 0x02}, + {AQT1000_FLL_USER_CTL_6, 0x6E}, + {AQT1000_FLL_USER_CTL_7, 0x00}, + {AQT1000_FLL_USER_CTL_8, 0x94}, + {AQT1000_FLL_USER_CTL_9, 0x70}, + {AQT1000_FLL_L_VAL_CTL_0, 0x34}, + {AQT1000_FLL_L_VAL_CTL_1, 0x00}, + {AQT1000_FLL_DSM_FRAC_CTL_0, 0x00}, + {AQT1000_FLL_DSM_FRAC_CTL_1, 0xFF}, + {AQT1000_FLL_CONFIG_CTL_0, 0x6B}, + {AQT1000_FLL_CONFIG_CTL_1, 0x05}, + {AQT1000_FLL_CONFIG_CTL_2, 0x08}, + {AQT1000_FLL_CONFIG_CTL_3, 0x00}, + {AQT1000_FLL_CONFIG_CTL_4, 0x10}, + {AQT1000_FLL_TEST_CTL_0, 0x80}, + {AQT1000_FLL_TEST_CTL_1, 0x00}, + {AQT1000_FLL_TEST_CTL_2, 0x00}, + {AQT1000_FLL_TEST_CTL_3, 0x00}, + {AQT1000_FLL_TEST_CTL_4, 0x00}, + {AQT1000_FLL_TEST_CTL_5, 0x00}, + {AQT1000_FLL_TEST_CTL_6, 0x04}, + {AQT1000_FLL_TEST_CTL_7, 0x33}, + {AQT1000_FLL_FREQ_CTL_0, 0x00}, + {AQT1000_FLL_FREQ_CTL_1, 0x00}, + {AQT1000_FLL_FREQ_CTL_2, 0x00}, + {AQT1000_FLL_FREQ_CTL_3, 0x00}, + {AQT1000_FLL_SSC_CTL_0, 0x00}, + {AQT1000_FLL_SSC_CTL_1, 0x00}, + {AQT1000_FLL_SSC_CTL_2, 0x00}, + {AQT1000_FLL_SSC_CTL_3, 0x00}, + {AQT1000_FLL_FLL_MODE, 0xA0}, + {AQT1000_FLL_STATUS_0, 0x00}, + {AQT1000_FLL_STATUS_1, 0x00}, + {AQT1000_FLL_STATUS_2, 0x00}, + {AQT1000_FLL_STATUS_3, 0x00}, + {AQT1000_PAGE2_PAGE_REGISTER, 0x00}, + {AQT1000_I2S_I2S_0_TX_CFG, 0x00}, + {AQT1000_I2S_I2S_0_RX_CFG, 0x00}, + {AQT1000_I2S_I2S_0_CTL, 0x0C}, + {AQT1000_I2S_I2S_CLKSRC_CTL, 0x01}, + {AQT1000_I2S_I2S_HS_CLK_CTL, 0x00}, + {AQT1000_I2S_I2S_0_RST, 0x00}, + {AQT1000_I2S_SHADOW_I2S_0_CTL, 0x00}, + {AQT1000_I2S_SHADOW_I2S_0_RX_CFG, 0x09}, + {AQT1000_PAGE5_PAGE_REGISTER, 0x00}, + {AQT1000_INTR_CTRL_MCU_INT_POLARITY, 0x00}, + {AQT1000_INTR_CTRL_INT_MASK_0, 0xFE}, + {AQT1000_INTR_CTRL_INT_MASK_1, 0xFF}, + {AQT1000_INTR_CTRL_INT_MASK_2, 0xFF}, + {AQT1000_INTR_CTRL_INT_MASK_3, 0xEF}, + {AQT1000_INTR_CTRL_INT_MASK_4, 0x3B}, + {AQT1000_INTR_CTRL_INT_MASK_5, 0xFF}, + {AQT1000_INTR_CTRL_INT_MASK_6, 0x3F}, + {AQT1000_INTR_CTRL_INT_STATUS_0, 0x00}, + {AQT1000_INTR_CTRL_INT_STATUS_1, 0x00}, + {AQT1000_INTR_CTRL_INT_STATUS_2, 0x00}, + {AQT1000_INTR_CTRL_INT_STATUS_3, 0x00}, + {AQT1000_INTR_CTRL_INT_STATUS_4, 0x00}, + {AQT1000_INTR_CTRL_INT_STATUS_5, 0x00}, + {AQT1000_INTR_CTRL_INT_STATUS_6, 0x00}, + {AQT1000_INTR_CTRL_INT_CLEAR_0, 0x00}, + {AQT1000_INTR_CTRL_INT_CLEAR_1, 0x00}, + {AQT1000_INTR_CTRL_INT_CLEAR_2, 0x00}, + {AQT1000_INTR_CTRL_INT_CLEAR_3, 0x00}, + {AQT1000_INTR_CTRL_INT_CLEAR_4, 0x00}, + {AQT1000_INTR_CTRL_INT_CLEAR_5, 0x00}, + {AQT1000_INTR_CTRL_INT_CLEAR_6, 0x00}, + {AQT1000_INTR_CTRL_INT_TYPE_0, 0xEF}, + {AQT1000_INTR_CTRL_INT_TYPE_1, 0x03}, + {AQT1000_INTR_CTRL_INT_TYPE_2, 0x00}, + {AQT1000_INTR_CTRL_INT_TYPE_3, 0x20}, + {AQT1000_INTR_CTRL_INT_TYPE_4, 0x44}, + {AQT1000_INTR_CTRL_INT_TYPE_5, 0x00}, + {AQT1000_INTR_CTRL_INT_TYPE_6, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_EN_0, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_EN_1, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_EN_2, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_EN_3, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_EN_4, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_EN_5, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_EN_6, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_VAL_0, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_VAL_1, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_VAL_2, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_VAL_3, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_VAL_4, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_VAL_5, 0x00}, + {AQT1000_INTR_CTRL_INT_TEST_VAL_6, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_0, 0x02}, + {AQT1000_INTR_CTRL_INT_DEST_1, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_2, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_3, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_4, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_5, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_6, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_7, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_8, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_9, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_10, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_11, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_12, 0x00}, + {AQT1000_INTR_CTRL_INT_DEST_13, 0x00}, + {AQT1000_INTR_CTRL_CLR_COMMIT, 0x00}, + {AQT1000_ANA_PAGE_REGISTER, 0x00}, + {AQT1000_ANA_BIAS, 0x00}, + {AQT1000_ANA_RX_SUPPLIES, 0x00}, + {AQT1000_ANA_HPH, 0x0C}, + {AQT1000_ANA_AMIC1, 0x20}, + {AQT1000_ANA_AMIC2, 0x00}, + {AQT1000_ANA_AMIC3, 0x20}, + {AQT1000_ANA_AMIC3_HPF, 0x00}, + {AQT1000_ANA_MBHC_MECH, 0x39}, + {AQT1000_ANA_MBHC_ELECT, 0x08}, + {AQT1000_ANA_MBHC_ZDET, 0x00}, + {AQT1000_ANA_MBHC_RESULT_1, 0x00}, + {AQT1000_ANA_MBHC_RESULT_2, 0x00}, + {AQT1000_ANA_MBHC_RESULT_3, 0x00}, + {AQT1000_ANA_MBHC_BTN0, 0x00}, + {AQT1000_ANA_MBHC_BTN1, 0x10}, + {AQT1000_ANA_MBHC_BTN2, 0x20}, + {AQT1000_ANA_MBHC_BTN3, 0x30}, + {AQT1000_ANA_MBHC_BTN4, 0x40}, + {AQT1000_ANA_MBHC_BTN5, 0x50}, + {AQT1000_ANA_MBHC_BTN6, 0x60}, + {AQT1000_ANA_MBHC_BTN7, 0x70}, + {AQT1000_ANA_MICB1, 0x10}, + {AQT1000_ANA_MICB1_RAMP, 0x00}, + {AQT1000_BIAS_CTL, 0x28}, + {AQT1000_BIAS_CCOMP_FINE_ADJ, 0x75}, + {AQT1000_LED_LED_MODE_SEL_R, 0x00}, + {AQT1000_LED_LED_MISC_R, 0x00}, + {AQT1000_LED_LED_MODE_SEL_G, 0x00}, + {AQT1000_LED_LED_MISC_G, 0x00}, + {AQT1000_LED_LED_MODE_SEL_B, 0x00}, + {AQT1000_LED_LED_MISC_B, 0x00}, + {AQT1000_LDOH_MODE, 0x1D}, + {AQT1000_LDOH_BIAS, 0x00}, + {AQT1000_LDOH_STB_LOADS, 0x00}, + {AQT1000_LDOH_MISC1, 0x00}, + {AQT1000_LDOL_VDDCX_ADJUST, 0x01}, + {AQT1000_LDOL_DISABLE_LDOL, 0x00}, + {AQT1000_BUCK_5V_EN_CTL, 0x03}, + {AQT1000_BUCK_5V_VOUT_SEL, 0x03}, + {AQT1000_BUCK_5V_CTRL_VCL_1, 0x03}, + {AQT1000_BUCK_5V_CTRL_VCL_2, 0x21}, + {AQT1000_BUCK_5V_CTRL_CCL_2, 0x20}, + {AQT1000_BUCK_5V_CTRL_CCL_1, 0xA1}, + {AQT1000_BUCK_5V_CTRL_CCL_3, 0x02}, + {AQT1000_BUCK_5V_CTRL_CCL_4, 0x05}, + {AQT1000_BUCK_5V_CTRL_CCL_5, 0x00}, + {AQT1000_BUCK_5V_IBIAS_CTL_1, 0x37}, + {AQT1000_BUCK_5V_IBIAS_CTL_2, 0x00}, + {AQT1000_BUCK_5V_IBIAS_CTL_3, 0x33}, + {AQT1000_BUCK_5V_IBIAS_CTL_4, 0x33}, + {AQT1000_BUCK_5V_IBIAS_CTL_5, 0x00}, + {AQT1000_BUCK_5V_ATEST_DTEST_CTL, 0x00}, + {AQT1000_PON_BG_CTRL, 0x80}, + {AQT1000_PON_TEST_CTRL, 0x00}, + {AQT1000_MBHC_CTL_CLK, 0x30}, + {AQT1000_MBHC_CTL_ANA, 0x00}, + {AQT1000_MBHC_CTL_SPARE_1, 0x00}, + {AQT1000_MBHC_CTL_SPARE_2, 0x00}, + {AQT1000_MBHC_CTL_BCS, 0x00}, + {AQT1000_MBHC_MOISTURE_DET_FSM_STATUS, 0x00}, + {AQT1000_MBHC_TEST_CTL, 0x00}, + {AQT1000_MICB1_TEST_CTL_1, 0x1A}, + {AQT1000_MICB1_TEST_CTL_2, 0x18}, + {AQT1000_MICB1_TEST_CTL_3, 0xA4}, + {AQT1000_MICB1_MISC_MICB1_INM_RES_BIAS, 0x00}, + {AQT1000_MICB1_MISC_MICB_MISC1, 0x00}, + {AQT1000_MICB1_MISC_MICB_MISC2, 0x00}, + {AQT1000_TX_COM_ADC_VCM, 0x39}, + {AQT1000_TX_COM_BIAS_ATEST, 0xC0}, + {AQT1000_TX_COM_ADC_INT1_IB, 0x6F}, + {AQT1000_TX_COM_ADC_INT2_IB, 0x4F}, + {AQT1000_TX_COM_TXFE_DIV_CTL, 0x2E}, + {AQT1000_TX_COM_TXFE_DIV_START, 0x00}, + {AQT1000_TX_COM_TXFE_DIV_STOP_9P6M, 0xC7}, + {AQT1000_TX_COM_TXFE_DIV_STOP_12P288M, 0xFF}, + {AQT1000_TX_1_2_TEST_EN, 0xCC}, + {AQT1000_TX_1_2_ADC_IB, 0x09}, + {AQT1000_TX_1_2_ATEST_REFCTL, 0x0A}, + {AQT1000_TX_1_2_TEST_CTL, 0x38}, + {AQT1000_TX_1_2_TEST_BLK_EN, 0xFF}, + {AQT1000_TX_1_2_TXFE_CLKDIV, 0x00}, + {AQT1000_TX_1_2_SAR1_ERR, 0x00}, + {AQT1000_TX_1_2_SAR2_ERR, 0x00}, + {AQT1000_TX_3_TEST_EN, 0xC0}, + {AQT1000_TX_3_ADC_IB, 0x09}, + {AQT1000_TX_3_ATEST_REFCTL, 0x0A}, + {AQT1000_TX_3_TEST_CTL, 0x38}, + {AQT1000_TX_3_TEST_BLK_EN, 0xFE}, + {AQT1000_TX_3_TXFE_CLKDIV, 0x00}, + {AQT1000_TX_3_SAR1_ERR, 0x00}, + {AQT1000_TX_3_SAR2_ERR, 0x00}, + {AQT1000_TX_ATEST1_2_SEL, 0x60}, + {AQT1000_CLASSH_MODE_1, 0x40}, + {AQT1000_CLASSH_MODE_2, 0x3A}, + {AQT1000_CLASSH_MODE_3, 0x00}, + {AQT1000_CLASSH_CTRL_VCL_1, 0x70}, + {AQT1000_CLASSH_CTRL_VCL_2, 0x82}, + {AQT1000_CLASSH_CTRL_CCL_1, 0x31}, + {AQT1000_CLASSH_CTRL_CCL_2, 0x80}, + {AQT1000_CLASSH_CTRL_CCL_3, 0x80}, + {AQT1000_CLASSH_CTRL_CCL_4, 0x51}, + {AQT1000_CLASSH_CTRL_CCL_5, 0x00}, + {AQT1000_CLASSH_BUCK_TMUX_A_D, 0x00}, + {AQT1000_CLASSH_BUCK_SW_DRV_CNTL, 0x77}, + {AQT1000_CLASSH_SPARE, 0x00}, + {AQT1000_FLYBACK_EN, 0x4E}, + {AQT1000_FLYBACK_VNEG_CTRL_1, 0x0B}, + {AQT1000_FLYBACK_VNEG_CTRL_2, 0x45}, + {AQT1000_FLYBACK_VNEG_CTRL_3, 0x74}, + {AQT1000_FLYBACK_VNEG_CTRL_4, 0x7F}, + {AQT1000_FLYBACK_VNEG_CTRL_5, 0x83}, + {AQT1000_FLYBACK_VNEG_CTRL_6, 0x98}, + {AQT1000_FLYBACK_VNEG_CTRL_7, 0xA9}, + {AQT1000_FLYBACK_VNEG_CTRL_8, 0x68}, + {AQT1000_FLYBACK_VNEG_CTRL_9, 0x64}, + {AQT1000_FLYBACK_VNEGDAC_CTRL_1, 0xED}, + {AQT1000_FLYBACK_VNEGDAC_CTRL_2, 0xF0}, + {AQT1000_FLYBACK_VNEGDAC_CTRL_3, 0xA6}, + {AQT1000_FLYBACK_CTRL_1, 0x65}, + {AQT1000_FLYBACK_TEST_CTL, 0x00}, + {AQT1000_RX_AUX_SW_CTL, 0x00}, + {AQT1000_RX_PA_AUX_IN_CONN, 0x00}, + {AQT1000_RX_TIMER_DIV, 0x32}, + {AQT1000_RX_OCP_CTL, 0x1F}, + {AQT1000_RX_OCP_COUNT, 0x77}, + {AQT1000_RX_BIAS_ATEST, 0x00}, + {AQT1000_RX_BIAS_MISC1, 0xAA}, + {AQT1000_RX_BIAS_HPH_LDO, 0xA9}, + {AQT1000_RX_BIAS_HPH_PA, 0xAA}, + {AQT1000_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A}, + {AQT1000_RX_BIAS_HPH_RDAC_LDO, 0x88}, + {AQT1000_RX_BIAS_HPH_CNP1, 0x82}, + {AQT1000_RX_BIAS_HPH_LOWPOWER, 0x82}, + {AQT1000_RX_BIAS_MISC2, 0x80}, + {AQT1000_RX_BIAS_MISC3, 0x88}, + {AQT1000_RX_BIAS_MISC4, 0x88}, + {AQT1000_RX_BIAS_MISC5, 0xA8}, + {AQT1000_RX_BIAS_BUCK_RST, 0x08}, + {AQT1000_RX_BIAS_BUCK_VREF_ERRAMP, 0x44}, + {AQT1000_RX_BIAS_FLYB_ERRAMP, 0x40}, + {AQT1000_RX_BIAS_FLYB_BUFF, 0xAA}, + {AQT1000_RX_BIAS_FLYB_MID_RST, 0x14}, + {AQT1000_HPH_L_STATUS, 0x04}, + {AQT1000_HPH_R_STATUS, 0x04}, + {AQT1000_HPH_CNP_EN, 0x80}, + {AQT1000_HPH_CNP_WG_CTL, 0x9A}, + {AQT1000_HPH_CNP_WG_TIME, 0x14}, + {AQT1000_HPH_OCP_CTL, 0x28}, + {AQT1000_HPH_AUTO_CHOP, 0x16}, + {AQT1000_HPH_CHOP_CTL, 0x83}, + {AQT1000_HPH_PA_CTL1, 0x46}, + {AQT1000_HPH_PA_CTL2, 0x50}, + {AQT1000_HPH_L_EN, 0x80}, + {AQT1000_HPH_L_TEST, 0xE0}, + {AQT1000_HPH_L_ATEST, 0x50}, + {AQT1000_HPH_R_EN, 0x80}, + {AQT1000_HPH_R_TEST, 0xE0}, + {AQT1000_HPH_R_ATEST, 0x54}, + {AQT1000_HPH_RDAC_CLK_CTL1, 0x99}, + {AQT1000_HPH_RDAC_CLK_CTL2, 0x9B}, + {AQT1000_HPH_RDAC_LDO_CTL, 0x33}, + {AQT1000_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00}, + {AQT1000_HPH_REFBUFF_UHQA_CTL, 0xA8}, + {AQT1000_HPH_REFBUFF_LP_CTL, 0x0E}, + {AQT1000_HPH_L_DAC_CTL, 0x00}, + {AQT1000_HPH_R_DAC_CTL, 0x00}, + {AQT1000_HPHLR_SURGE_COMP_SEL, 0x55}, + {AQT1000_HPHLR_SURGE_EN, 0x1D}, + {AQT1000_HPHLR_SURGE_MISC1, 0xA0}, + {AQT1000_HPHLR_SURGE_STATUS, 0x00}, + {AQT1000_ANA_NEW_PAGE_REGISTER, 0x00}, + {AQT1000_HPH_NEW_ANA_HPH2, 0x00}, + {AQT1000_HPH_NEW_ANA_HPH3, 0x00}, + {AQT1000_CLK_SYS_MCLK1_PRG, 0x09}, + {AQT1000_CLK_SYS_MCLK2_I2S_HS_CLK_PRG, 0x20}, + {AQT1000_CLK_SYS_XO_CAP_XTP, 0x3F}, + {AQT1000_CLK_SYS_XO_CAP_XTM, 0x3F}, + {AQT1000_CLK_SYS_PLL_ENABLES, 0x00}, + {AQT1000_CLK_SYS_PLL_PRESET, 0x00}, + {AQT1000_CLK_SYS_PLL_STATUS, 0x00}, + {AQT1000_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00}, + {AQT1000_MBHC_NEW_CTL_1, 0x02}, + {AQT1000_MBHC_NEW_CTL_2, 0x05}, + {AQT1000_MBHC_NEW_PLUG_DETECT_CTL, 0x29}, + {AQT1000_MBHC_NEW_ZDET_ANA_CTL, 0x0F}, + {AQT1000_MBHC_NEW_ZDET_RAMP_CTL, 0x00}, + {AQT1000_MBHC_NEW_FSM_STATUS, 0x00}, + {AQT1000_MBHC_NEW_ADC_RESULT, 0x00}, + {AQT1000_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40}, + {AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81}, + {AQT1000_HPH_NEW_INT_RDAC_VREF_CTL, 0x10}, + {AQT1000_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00}, + {AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81}, + {AQT1000_HPH_NEW_INT_PA_MISC1, 0x22}, + {AQT1000_HPH_NEW_INT_PA_MISC2, 0x00}, + {AQT1000_HPH_NEW_INT_PA_RDAC_MISC, 0x00}, + {AQT1000_HPH_NEW_INT_HPH_TIMER1, 0xFE}, + {AQT1000_HPH_NEW_INT_HPH_TIMER2, 0x02}, + {AQT1000_HPH_NEW_INT_HPH_TIMER3, 0x4E}, + {AQT1000_HPH_NEW_INT_HPH_TIMER4, 0x54}, + {AQT1000_HPH_NEW_INT_PA_RDAC_MISC2, 0x80}, + {AQT1000_HPH_NEW_INT_PA_RDAC_MISC3, 0x00}, + {AQT1000_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62}, + {AQT1000_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01}, + {AQT1000_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11}, + {AQT1000_CLK_SYS_INT_CLK_TEST1, 0x00}, + {AQT1000_CLK_SYS_INT_XO_TEST1, 0x98}, + {AQT1000_CLK_SYS_INT_XO_TEST2, 0x00}, + {AQT1000_CLK_SYS_INT_POST_DIV_REG0, 0x00}, + {AQT1000_CLK_SYS_INT_POST_DIV_REG1, 0x00}, + {AQT1000_CLK_SYS_INT_REF_DIV_REG0, 0x00}, + {AQT1000_CLK_SYS_INT_REF_DIV_REG1, 0x00}, + {AQT1000_CLK_SYS_INT_FILTER_REG0, 0x00}, + {AQT1000_CLK_SYS_INT_FILTER_REG1, 0x00}, + {AQT1000_CLK_SYS_INT_PLL_L_VAL, 0x00}, + {AQT1000_CLK_SYS_INT_PLL_M_VAL, 0x00}, + {AQT1000_CLK_SYS_INT_PLL_N_VAL, 0x00}, + {AQT1000_CLK_SYS_INT_TEST_REG0, 0x00}, + {AQT1000_CLK_SYS_INT_PFD_CP_DSM_PROG, 0x00}, + {AQT1000_CLK_SYS_INT_VCO_PROG, 0x00}, + {AQT1000_CLK_SYS_INT_TEST_REG1, 0x00}, + {AQT1000_CLK_SYS_INT_LDO_LOCK_CFG, 0x00}, + {AQT1000_CLK_SYS_INT_DIG_LOCK_DET_CFG, 0x00}, + {AQT1000_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57}, + {AQT1000_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01}, + {AQT1000_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00}, + {AQT1000_MBHC_NEW_INT_SPARE_2, 0x00}, + {AQT1000_PAGE10_PAGE_REGISTER, 0x00}, + {AQT1000_CDC_ANC0_CLK_RESET_CTL, 0x00}, + {AQT1000_CDC_ANC0_MODE_1_CTL, 0x00}, + {AQT1000_CDC_ANC0_MODE_2_CTL, 0x00}, + {AQT1000_CDC_ANC0_FF_SHIFT, 0x00}, + {AQT1000_CDC_ANC0_FB_SHIFT, 0x00}, + {AQT1000_CDC_ANC0_LPF_FF_A_CTL, 0x00}, + {AQT1000_CDC_ANC0_LPF_FF_B_CTL, 0x00}, + {AQT1000_CDC_ANC0_LPF_FB_CTL, 0x00}, + {AQT1000_CDC_ANC0_SMLPF_CTL, 0x00}, + {AQT1000_CDC_ANC0_DCFLT_SHIFT_CTL, 0x00}, + {AQT1000_CDC_ANC0_IIR_ADAPT_CTL, 0x00}, + {AQT1000_CDC_ANC0_IIR_COEFF_1_CTL, 0x00}, + {AQT1000_CDC_ANC0_IIR_COEFF_2_CTL, 0x00}, + {AQT1000_CDC_ANC0_FF_A_GAIN_CTL, 0x00}, + {AQT1000_CDC_ANC0_FF_B_GAIN_CTL, 0x00}, + {AQT1000_CDC_ANC0_FB_GAIN_CTL, 0x00}, + {AQT1000_CDC_ANC0_RC_COMMON_CTL, 0x00}, + {AQT1000_CDC_ANC0_FIFO_COMMON_CTL, 0x88}, + {AQT1000_CDC_ANC0_RC0_STATUS_FMIN_CNTR, 0x00}, + {AQT1000_CDC_ANC0_RC1_STATUS_FMIN_CNTR, 0x00}, + {AQT1000_CDC_ANC0_RC0_STATUS_FMAX_CNTR, 0x00}, + {AQT1000_CDC_ANC0_RC1_STATUS_FMAX_CNTR, 0x00}, + {AQT1000_CDC_ANC0_STATUS_FIFO, 0x00}, + {AQT1000_CDC_ANC1_CLK_RESET_CTL, 0x00}, + {AQT1000_CDC_ANC1_MODE_1_CTL, 0x00}, + {AQT1000_CDC_ANC1_MODE_2_CTL, 0x00}, + {AQT1000_CDC_ANC1_FF_SHIFT, 0x00}, + {AQT1000_CDC_ANC1_FB_SHIFT, 0x00}, + {AQT1000_CDC_ANC1_LPF_FF_A_CTL, 0x00}, + {AQT1000_CDC_ANC1_LPF_FF_B_CTL, 0x00}, + {AQT1000_CDC_ANC1_LPF_FB_CTL, 0x00}, + {AQT1000_CDC_ANC1_SMLPF_CTL, 0x00}, + {AQT1000_CDC_ANC1_DCFLT_SHIFT_CTL, 0x00}, + {AQT1000_CDC_ANC1_IIR_ADAPT_CTL, 0x00}, + {AQT1000_CDC_ANC1_IIR_COEFF_1_CTL, 0x00}, + {AQT1000_CDC_ANC1_IIR_COEFF_2_CTL, 0x00}, + {AQT1000_CDC_ANC1_FF_A_GAIN_CTL, 0x00}, + {AQT1000_CDC_ANC1_FF_B_GAIN_CTL, 0x00}, + {AQT1000_CDC_ANC1_FB_GAIN_CTL, 0x00}, + {AQT1000_CDC_ANC1_RC_COMMON_CTL, 0x00}, + {AQT1000_CDC_ANC1_FIFO_COMMON_CTL, 0x88}, + {AQT1000_CDC_ANC1_RC0_STATUS_FMIN_CNTR, 0x00}, + {AQT1000_CDC_ANC1_RC1_STATUS_FMIN_CNTR, 0x00}, + {AQT1000_CDC_ANC1_RC0_STATUS_FMAX_CNTR, 0x00}, + {AQT1000_CDC_ANC1_RC1_STATUS_FMAX_CNTR, 0x00}, + {AQT1000_CDC_ANC1_STATUS_FIFO, 0x00}, + {AQT1000_CDC_TX0_TX_PATH_CTL, 0x04}, + {AQT1000_CDC_TX0_TX_PATH_CFG0, 0x10}, + {AQT1000_CDC_TX0_TX_PATH_CFG1, 0x03}, + {AQT1000_CDC_TX0_TX_VOL_CTL, 0x00}, + {AQT1000_CDC_TX0_TX_PATH_SEC0, 0x00}, + {AQT1000_CDC_TX0_TX_PATH_SEC1, 0x00}, + {AQT1000_CDC_TX0_TX_PATH_SEC2, 0x01}, + {AQT1000_CDC_TX0_TX_PATH_SEC3, 0x3C}, + {AQT1000_CDC_TX0_TX_PATH_SEC4, 0x20}, + {AQT1000_CDC_TX0_TX_PATH_SEC5, 0x00}, + {AQT1000_CDC_TX0_TX_PATH_SEC6, 0x00}, + {AQT1000_CDC_TX1_TX_PATH_CTL, 0x04}, + {AQT1000_CDC_TX1_TX_PATH_CFG0, 0x10}, + {AQT1000_CDC_TX1_TX_PATH_CFG1, 0x03}, + {AQT1000_CDC_TX1_TX_VOL_CTL, 0x00}, + {AQT1000_CDC_TX1_TX_PATH_SEC0, 0x00}, + {AQT1000_CDC_TX1_TX_PATH_SEC1, 0x00}, + {AQT1000_CDC_TX1_TX_PATH_SEC2, 0x01}, + {AQT1000_CDC_TX1_TX_PATH_SEC3, 0x3C}, + {AQT1000_CDC_TX1_TX_PATH_SEC4, 0x20}, + {AQT1000_CDC_TX1_TX_PATH_SEC5, 0x00}, + {AQT1000_CDC_TX1_TX_PATH_SEC6, 0x00}, + {AQT1000_CDC_TX2_TX_PATH_CTL, 0x04}, + {AQT1000_CDC_TX2_TX_PATH_CFG0, 0x10}, + {AQT1000_CDC_TX2_TX_PATH_CFG1, 0x03}, + {AQT1000_CDC_TX2_TX_VOL_CTL, 0x00}, + {AQT1000_CDC_TX2_TX_PATH_SEC0, 0x00}, + {AQT1000_CDC_TX2_TX_PATH_SEC1, 0x00}, + {AQT1000_CDC_TX2_TX_PATH_SEC2, 0x01}, + {AQT1000_CDC_TX2_TX_PATH_SEC3, 0x3C}, + {AQT1000_CDC_TX2_TX_PATH_SEC4, 0x20}, + {AQT1000_CDC_TX2_TX_PATH_SEC5, 0x00}, + {AQT1000_CDC_TX2_TX_PATH_SEC6, 0x00}, + {AQT1000_CDC_TX2_TX_PATH_SEC7, 0x25}, + {AQT1000_PAGE11_PAGE_REGISTER, 0x00}, + {AQT1000_CDC_COMPANDER1_CTL0, 0x60}, + {AQT1000_CDC_COMPANDER1_CTL1, 0xDB}, + {AQT1000_CDC_COMPANDER1_CTL2, 0xFF}, + {AQT1000_CDC_COMPANDER1_CTL3, 0x35}, + {AQT1000_CDC_COMPANDER1_CTL4, 0xFF}, + {AQT1000_CDC_COMPANDER1_CTL5, 0x00}, + {AQT1000_CDC_COMPANDER1_CTL6, 0x01}, + {AQT1000_CDC_COMPANDER1_CTL7, 0x26}, + {AQT1000_CDC_COMPANDER2_CTL0, 0x60}, + {AQT1000_CDC_COMPANDER2_CTL1, 0xDB}, + {AQT1000_CDC_COMPANDER2_CTL2, 0xFF}, + {AQT1000_CDC_COMPANDER2_CTL3, 0x35}, + {AQT1000_CDC_COMPANDER2_CTL4, 0xFF}, + {AQT1000_CDC_COMPANDER2_CTL5, 0x00}, + {AQT1000_CDC_COMPANDER2_CTL6, 0x01}, + {AQT1000_CDC_COMPANDER2_CTL7, 0x26}, + {AQT1000_CDC_RX1_RX_PATH_CTL, 0x04}, + {AQT1000_CDC_RX1_RX_PATH_CFG0, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_CFG1, 0x64}, + {AQT1000_CDC_RX1_RX_PATH_CFG2, 0x8F}, + {AQT1000_CDC_RX1_RX_VOL_CTL, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_MIX_CTL, 0x04}, + {AQT1000_CDC_RX1_RX_PATH_MIX_CFG, 0x7E}, + {AQT1000_CDC_RX1_RX_VOL_MIX_CTL, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_SEC0, 0xFC}, + {AQT1000_CDC_RX1_RX_PATH_SEC1, 0x08}, + {AQT1000_CDC_RX1_RX_PATH_SEC2, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_SEC3, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_SEC4, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_SEC5, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_SEC6, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_SEC7, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_MIX_SEC0, 0x08}, + {AQT1000_CDC_RX1_RX_PATH_MIX_SEC1, 0x00}, + {AQT1000_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_CTL, 0x04}, + {AQT1000_CDC_RX2_RX_PATH_CFG0, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_CFG1, 0x64}, + {AQT1000_CDC_RX2_RX_PATH_CFG2, 0x8F}, + {AQT1000_CDC_RX2_RX_VOL_CTL, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_MIX_CTL, 0x04}, + {AQT1000_CDC_RX2_RX_PATH_MIX_CFG, 0x7E}, + {AQT1000_CDC_RX2_RX_VOL_MIX_CTL, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_SEC0, 0xFC}, + {AQT1000_CDC_RX2_RX_PATH_SEC1, 0x08}, + {AQT1000_CDC_RX2_RX_PATH_SEC2, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_SEC3, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_SEC4, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_SEC5, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_SEC6, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_SEC7, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_MIX_SEC0, 0x08}, + {AQT1000_CDC_RX2_RX_PATH_MIX_SEC1, 0x00}, + {AQT1000_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x00}, + {AQT1000_CDC_EQ_IIR0_PATH_CTL, 0x00}, + {AQT1000_CDC_EQ_IIR0_PATH_CFG0, 0x1F}, + {AQT1000_CDC_EQ_IIR0_PATH_CFG1, 0x00}, + {AQT1000_CDC_EQ_IIR0_PATH_CFG2, 0x00}, + {AQT1000_CDC_EQ_IIR0_PATH_CFG3, 0x00}, + {AQT1000_CDC_EQ_IIR0_COEF_CFG0, 0x00}, + {AQT1000_CDC_EQ_IIR0_COEF_CFG1, 0x00}, + {AQT1000_CDC_EQ_IIR1_PATH_CTL, 0x00}, + {AQT1000_CDC_EQ_IIR1_PATH_CFG0, 0x1F}, + {AQT1000_CDC_EQ_IIR1_PATH_CFG1, 0x00}, + {AQT1000_CDC_EQ_IIR1_PATH_CFG2, 0x00}, + {AQT1000_CDC_EQ_IIR1_PATH_CFG3, 0x00}, + {AQT1000_CDC_EQ_IIR1_COEF_CFG0, 0x00}, + {AQT1000_CDC_EQ_IIR1_COEF_CFG1, 0x00}, + {AQT1000_PAGE12_PAGE_REGISTER, 0x00}, + {AQT1000_CDC_CLSH_CRC, 0x00}, + {AQT1000_CDC_CLSH_DLY_CTRL, 0x03}, + {AQT1000_CDC_CLSH_DECAY_CTRL, 0x02}, + {AQT1000_CDC_CLSH_HPH_V_PA, 0x1C}, + {AQT1000_CDC_CLSH_EAR_V_PA, 0x39}, + {AQT1000_CDC_CLSH_HPH_V_HD, 0x0C}, + {AQT1000_CDC_CLSH_EAR_V_HD, 0x0C}, + {AQT1000_CDC_CLSH_K1_MSB, 0x01}, + {AQT1000_CDC_CLSH_K1_LSB, 0x00}, + {AQT1000_CDC_CLSH_K2_MSB, 0x00}, + {AQT1000_CDC_CLSH_K2_LSB, 0x80}, + {AQT1000_CDC_CLSH_IDLE_CTRL, 0x00}, + {AQT1000_CDC_CLSH_IDLE_HPH, 0x00}, + {AQT1000_CDC_CLSH_IDLE_EAR, 0x00}, + {AQT1000_CDC_CLSH_TEST0, 0x07}, + {AQT1000_CDC_CLSH_TEST1, 0x00}, + {AQT1000_CDC_CLSH_OVR_VREF, 0x00}, + {AQT1000_MIXING_ASRC0_CLK_RST_CTL, 0x00}, + {AQT1000_MIXING_ASRC0_CTL0, 0x00}, + {AQT1000_MIXING_ASRC0_CTL1, 0x00}, + {AQT1000_MIXING_ASRC0_FIFO_CTL, 0xA8}, + {AQT1000_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00}, + {AQT1000_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00}, + {AQT1000_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00}, + {AQT1000_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00}, + {AQT1000_MIXING_ASRC0_STATUS_FIFO, 0x00}, + {AQT1000_MIXING_ASRC1_CLK_RST_CTL, 0x00}, + {AQT1000_MIXING_ASRC1_CTL0, 0x00}, + {AQT1000_MIXING_ASRC1_CTL1, 0x00}, + {AQT1000_MIXING_ASRC1_FIFO_CTL, 0xA8}, + {AQT1000_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00}, + {AQT1000_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00}, + {AQT1000_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00}, + {AQT1000_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00}, + {AQT1000_MIXING_ASRC1_STATUS_FIFO, 0x00}, + {AQT1000_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04}, + {AQT1000_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00}, + {AQT1000_SIDETONE_ASRC0_CLK_RST_CTL, 0x00}, + {AQT1000_SIDETONE_ASRC0_CTL0, 0x00}, + {AQT1000_SIDETONE_ASRC0_CTL1, 0x00}, + {AQT1000_SIDETONE_ASRC0_FIFO_CTL, 0xA8}, + {AQT1000_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00}, + {AQT1000_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00}, + {AQT1000_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00}, + {AQT1000_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00}, + {AQT1000_SIDETONE_ASRC0_STATUS_FIFO, 0x00}, + {AQT1000_EC_REF_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, + {AQT1000_EC_REF_HQ0_EC_REF_HQ_CFG0, 0x01}, + {AQT1000_EC_REF_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, + {AQT1000_EC_REF_HQ1_EC_REF_HQ_CFG0, 0x01}, + {AQT1000_EC_ASRC0_CLK_RST_CTL, 0x00}, + {AQT1000_EC_ASRC0_CTL0, 0x00}, + {AQT1000_EC_ASRC0_CTL1, 0x00}, + {AQT1000_EC_ASRC0_FIFO_CTL, 0xA8}, + {AQT1000_EC_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00}, + {AQT1000_EC_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00}, + {AQT1000_EC_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00}, + {AQT1000_EC_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00}, + {AQT1000_EC_ASRC0_STATUS_FIFO, 0x00}, + {AQT1000_EC_ASRC1_CLK_RST_CTL, 0x00}, + {AQT1000_EC_ASRC1_CTL0, 0x00}, + {AQT1000_EC_ASRC1_CTL1, 0x00}, + {AQT1000_EC_ASRC1_FIFO_CTL, 0xA8}, + {AQT1000_EC_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00}, + {AQT1000_EC_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00}, + {AQT1000_EC_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00}, + {AQT1000_EC_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00}, + {AQT1000_EC_ASRC1_STATUS_FIFO, 0x00}, + {AQT1000_PAGE13_PAGE_REGISTER, 0x00}, + {AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00}, + {AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00}, + {AQT1000_CDC_RX_INP_MUX_EQ_IIR_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_DSD_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_RX_MIX_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_ANC_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 0x00}, + {AQT1000_CDC_RX_INP_MUX_EC_REF_HQ_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX10_CFG1, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX11_CFG1, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX12_CFG1, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0x00}, + {AQT1000_CDC_TX_INP_MUX_ADC_MUX13_CFG1, 0x00}, + {AQT1000_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00}, + {AQT1000_CDC_IF_ROUTER_TX_MUX_CFG0, 0x00}, + {AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + {AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + {AQT1000_CDC_CLK_RST_CTRL_DSD_CONTROL, 0x00}, + {AQT1000_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL, 0x0F}, + {AQT1000_CDC_CLK_RST_CTRL_GFM_CONTROL, 0x00}, + {AQT1000_CDC_CLK_RST_CTRL_I2S_CONTROL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_PATH_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_CTL, 0x40}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00}, + {AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00}, + {AQT1000_CDC_TOP_TOP_CFG0, 0x00}, + {AQT1000_CDC_TOP_HPHL_COMP_WR_LSB, 0x00}, + {AQT1000_CDC_TOP_HPHL_COMP_WR_MSB, 0x00}, + {AQT1000_CDC_TOP_HPHL_COMP_LUT, 0x00}, + {AQT1000_CDC_TOP_HPHL_COMP_RD_LSB, 0x00}, + {AQT1000_CDC_TOP_HPHL_COMP_RD_MSB, 0x00}, + {AQT1000_CDC_TOP_HPHR_COMP_WR_LSB, 0x00}, + {AQT1000_CDC_TOP_HPHR_COMP_WR_MSB, 0x00}, + {AQT1000_CDC_TOP_HPHR_COMP_LUT, 0x00}, + {AQT1000_CDC_TOP_HPHR_COMP_RD_LSB, 0x00}, + {AQT1000_CDC_TOP_HPHR_COMP_RD_MSB, 0x00}, + {AQT1000_CDC_DSD0_PATH_CTL, 0x00}, + {AQT1000_CDC_DSD0_CFG0, 0x00}, + {AQT1000_CDC_DSD0_CFG1, 0x00}, + {AQT1000_CDC_DSD0_CFG2, 0x42}, + {AQT1000_CDC_DSD0_CFG3, 0x00}, + {AQT1000_CDC_DSD0_CFG4, 0x02}, + {AQT1000_CDC_DSD0_CFG5, 0x00}, + {AQT1000_CDC_DSD1_PATH_CTL, 0x00}, + {AQT1000_CDC_DSD1_CFG0, 0x00}, + {AQT1000_CDC_DSD1_CFG1, 0x00}, + {AQT1000_CDC_DSD1_CFG2, 0x42}, + {AQT1000_CDC_DSD1_CFG3, 0x00}, + {AQT1000_CDC_DSD1_CFG4, 0x02}, + {AQT1000_CDC_DSD1_CFG5, 0x00}, + {AQT1000_CDC_RX_IDLE_DET_PATH_CTL, 0x00}, + {AQT1000_CDC_RX_IDLE_DET_CFG0, 0x07}, + {AQT1000_CDC_RX_IDLE_DET_CFG1, 0x3C}, + {AQT1000_CDC_RX_IDLE_DET_CFG2, 0x00}, + {AQT1000_CDC_RX_IDLE_DET_CFG3, 0x00}, + {AQT1000_CDC_DOP_DET_CTL, 0x00}, + {AQT1000_CDC_DOP_DET_CFG0, 0xFA}, + {AQT1000_CDC_DOP_DET_CFG1, 0x05}, + {AQT1000_CDC_DOP_DET_CFG2, 0x00}, + {AQT1000_CDC_DOP_DET_CFG3, 0x33}, + {AQT1000_CDC_DOP_DET_CFG4, 0x20}, + {AQT1000_CDC_DOP_DET_STATUS0, 0x00}, + {AQT1000_PAGE15_PAGE_REGISTER, 0x00}, + {AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG0, 0x1B}, + {AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG1, 0x24}, + {AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG2, 0x00}, + {AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG3, 0x08}, + {AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG0, 0x1B}, + {AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG1, 0x24}, + {AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG2, 0x00}, + {AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG3, 0x08}, + {AQT1000_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0, 0x00}, + {AQT1000_CDC_DEBUG_ANC0_RC0_FIFO_CTL, 0x4C}, + {AQT1000_CDC_DEBUG_ANC0_RC1_FIFO_CTL, 0x4C}, + {AQT1000_CDC_DEBUG_ANC1_RC0_FIFO_CTL, 0x4C}, + {AQT1000_CDC_DEBUG_ANC1_RC1_FIFO_CTL, 0x4C}, + {AQT1000_CDC_DEBUG_ANC_RC_RST_DBG_CNTR, 0x00}, + {AQT1000_PAGE128_PAGE_REGISTER, 0x00}, + {AQT1000_TLMM_SPI_CLK_PINCFG, 0x00}, + {AQT1000_TLMM_SPI_MOSI_PINCFG, 0x00}, + {AQT1000_TLMM_SPI_MISO_PINCFG, 0x00}, + {AQT1000_TLMM_SPI_CS_N_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO1_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO2_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO3_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO4_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO5_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO6_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO7_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO8_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO9_PINCFG, 0x00}, + {AQT1000_TLMM_GPIO10_PINCFG, 0x00}, + {AQT1000_PAD_CTRL_PAD_PDN_CTRL_0, 0x00}, + {AQT1000_PAD_CTRL_PAD_PDN_CTRL_1, 0x00}, + {AQT1000_PAD_CTRL_PAD_PU_CTRL_0, 0x00}, + {AQT1000_PAD_CTRL_PAD_PU_CTRL_1, 0x00}, + {AQT1000_PAD_CTRL_GPIO_CTL_0_OE, 0x00}, + {AQT1000_PAD_CTRL_GPIO_CTL_1_OE, 0x00}, + {AQT1000_PAD_CTRL_GPIO_CTL_0_DATA, 0x00}, + {AQT1000_PAD_CTRL_GPIO_CTL_1_DATA, 0x00}, + {AQT1000_PAD_CTRL_PAD_DRVCTL, 0x00}, + {AQT1000_PAD_CTRL_PIN_STATUS, 0x00}, + {AQT1000_PAD_CTRL_MEM_CTRL, 0x00}, + {AQT1000_PAD_CTRL_PAD_INP_DISABLE_0, 0x00}, + {AQT1000_PAD_CTRL_PAD_INP_DISABLE_1, 0x00}, + {AQT1000_PAD_CTRL_PIN_CTL_OE_0, 0x00}, + {AQT1000_PAD_CTRL_PIN_CTL_OE_1, 0x00}, + {AQT1000_PAD_CTRL_PIN_CTL_DATA_0, 0x00}, + {AQT1000_PAD_CTRL_PIN_CTL_DATA_1, 0x00}, + {AQT1000_PAD_CTRL_USB_PHY_CLK_DIV, 0x0F}, + {AQT1000_PAD_CTRL_DEBUG_BUS_CDC, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_BUS_SEL, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_EN_1, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_EN_2, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_EN_3, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_EN_4, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_EN_5, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_0, 0x00}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_1, 0x01}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_2, 0x02}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_3, 0x03}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_4, 0x04}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_5, 0x05}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_6, 0x06}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_7, 0x07}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_8, 0x08}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_9, 0x09}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_10, 0x0A}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_11, 0x0B}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_12, 0x0C}, + {AQT1000_PAD_CTRL_DEBUG_MUX_BIT_13, 0x0D}, + {AQT1000_PAD_CTRL_DEBUG_READ_0, 0x0D}, + {AQT1000_PAD_CTRL_DEBUG_READ_1, 0x0D}, + {AQT1000_PAD_CTRL_DEBUG_READ_2, 0x0D}, + {AQT1000_PAD_CTRL_DEBUG_READ_3, 0x0D}, + {AQT1000_PAD_CTRL_FPGA_CTL, 0x00}, +}; + +const u8 aqt1000_page0_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE0_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_CHIP_ID_BYTE0)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_CHIP_ID_BYTE1)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_CHIP_ID_BYTE2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_CHIP_ID_BYTE3)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_TEST0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_TEST1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT0)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT1)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT3)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT4)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT5)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT6)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT7)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT8)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT9)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT10)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT11)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT12)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT13)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT14)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_VAL_OUT15)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_I2C_SLAVE_ID_NONNEGO)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_I2C_SLAVE_ID_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_I2C_SLAVE_ID_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_I2C_SLAVE_ID_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_I2C_ACTIVE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_CLK_CFG_MCLK)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_CLK_CFG_MCLK2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_CLK_CTL_CDC_DIG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_RST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_TEST0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_TEST1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT0)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT1)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT3)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT4)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT5)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT6)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT7)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT8)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT9)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT10)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT11)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT12)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT13)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT14)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT15)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG0_EFUSE2_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CHIP_CFG1_PWR_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_BUS_MTRX_CFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_DMA_BUS_VOTE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_USB_BUS_VOTE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_BLSP_BUS_VOTE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_PWR_MEM_SD)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_PWR_SYS_MEM_SD_RAM)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_PWR_SYS_MEM_SD_ROM)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_PWR_SYS_MEM_FORCE_DS_RAM)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_PWR_SYS_MEM_FORCE_DS_ROM)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_CLK_CFG_FLL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_CLK_CFG_SPI_M)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_CLK_CFG_I2C_M)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_CLK_CFG_UART)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_RST_USB_SS)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_RST_BLSP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_RST_BUS_MTRX)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_RST_MISC)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CHIP_CFG1_ANA_WAIT_STATE_CTL)] = AQT1000_RW, +}; + +const u8 aqt1000_page1_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE1_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_8)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_USER_CTL_9)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_L_VAL_CTL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_L_VAL_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_DSM_FRAC_CTL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_DSM_FRAC_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_CONFIG_CTL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_CONFIG_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_CONFIG_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_CONFIG_CTL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_CONFIG_CTL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_TEST_CTL_7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_FREQ_CTL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_FREQ_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_FREQ_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_FREQ_CTL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_SSC_CTL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_SSC_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_SSC_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_SSC_CTL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_FLL_MODE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLL_STATUS_0)] = AQT1000_RO, + [AQT1000_REG(AQT1000_FLL_STATUS_1)] = AQT1000_RO, + [AQT1000_REG(AQT1000_FLL_STATUS_2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_FLL_STATUS_3)] = AQT1000_RO, +}; + +const u8 aqt1000_page2_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE2_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_I2S_0_TX_CFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_I2S_0_RX_CFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_I2S_0_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_I2S_CLKSRC_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_I2S_HS_CLK_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_I2S_0_RST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_SHADOW_I2S_0_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_I2S_SHADOW_I2S_0_RX_CFG)] = AQT1000_RW, +}; + +const u8 aqt1000_page5_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE5_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_MCU_INT_POLARITY)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_MASK_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_MASK_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_MASK_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_MASK_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_MASK_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_MASK_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_MASK_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_STATUS_0)] = AQT1000_RO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_STATUS_1)] = AQT1000_RO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_STATUS_2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_STATUS_3)] = AQT1000_RO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_STATUS_4)] = AQT1000_RO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_STATUS_5)] = AQT1000_RO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_STATUS_6)] = AQT1000_RO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_CLEAR_0)] = AQT1000_WO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_CLEAR_1)] = AQT1000_WO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_CLEAR_2)] = AQT1000_WO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_CLEAR_3)] = AQT1000_WO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_CLEAR_4)] = AQT1000_WO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_CLEAR_5)] = AQT1000_WO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_CLEAR_6)] = AQT1000_WO, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TYPE_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TYPE_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TYPE_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TYPE_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TYPE_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TYPE_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TYPE_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_EN_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_EN_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_EN_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_EN_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_EN_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_EN_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_EN_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_VAL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_VAL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_VAL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_VAL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_VAL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_VAL_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_TEST_VAL_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_8)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_9)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_10)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_11)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_12)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_INT_DEST_13)] = AQT1000_RW, + [AQT1000_REG(AQT1000_INTR_CTRL_CLR_COMMIT)] = AQT1000_WO, +}; + +const u8 aqt1000_page6_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_ANA_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_BIAS)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_RX_SUPPLIES)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_HPH)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_AMIC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_AMIC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_AMIC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_AMIC3_HPF)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_MECH)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_ELECT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_ZDET)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_RESULT_1)] = AQT1000_RO, + [AQT1000_REG(AQT1000_ANA_MBHC_RESULT_2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_ANA_MBHC_RESULT_3)] = AQT1000_RO, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MBHC_BTN7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MICB1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_ANA_MICB1_RAMP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BIAS_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BIAS_CCOMP_FINE_ADJ)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LED_LED_MODE_SEL_R)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LED_LED_MISC_R)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LED_LED_MODE_SEL_G)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LED_LED_MISC_G)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LED_LED_MODE_SEL_B)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LED_LED_MISC_B)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LDOH_MODE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LDOH_BIAS)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LDOH_STB_LOADS)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LDOH_MISC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LDOL_VDDCX_ADJUST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_LDOL_DISABLE_LDOL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_EN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_VOUT_SEL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_CTRL_VCL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_CTRL_VCL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_CTRL_CCL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_CTRL_CCL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_CTRL_CCL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_CTRL_CCL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_CTRL_CCL_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_IBIAS_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_IBIAS_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_IBIAS_CTL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_IBIAS_CTL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_IBIAS_CTL_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_BUCK_5V_ATEST_DTEST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PON_BG_CTRL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PON_TEST_CTRL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_CTL_CLK)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_CTL_ANA)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_CTL_SPARE_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_CTL_SPARE_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_CTL_BCS)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_MOISTURE_DET_FSM_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MBHC_TEST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MICB1_TEST_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MICB1_TEST_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MICB1_TEST_CTL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MICB1_MISC_MICB1_INM_RES_BIAS)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MICB1_MISC_MICB_MISC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MICB1_MISC_MICB_MISC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_ADC_VCM)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_BIAS_ATEST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_ADC_INT1_IB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_ADC_INT2_IB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_TXFE_DIV_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_TXFE_DIV_START)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_TXFE_DIV_STOP_9P6M)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_COM_TXFE_DIV_STOP_12P288M)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_1_2_TEST_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_1_2_ADC_IB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_1_2_ATEST_REFCTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_1_2_TEST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_1_2_TEST_BLK_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_1_2_TXFE_CLKDIV)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_1_2_SAR1_ERR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_TX_1_2_SAR2_ERR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_TX_3_TEST_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_3_ADC_IB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_3_ATEST_REFCTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_3_TEST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_3_TEST_BLK_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_3_TXFE_CLKDIV)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TX_3_SAR1_ERR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_TX_3_SAR2_ERR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_TX_ATEST1_2_SEL)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CLASSH_MODE_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_MODE_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_MODE_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_CTRL_VCL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_CTRL_VCL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_CTRL_CCL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_CTRL_CCL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_CTRL_CCL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_CTRL_CCL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_CTRL_CCL_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_BUCK_TMUX_A_D)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_BUCK_SW_DRV_CNTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLASSH_SPARE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_8)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEG_CTRL_9)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEGDAC_CTRL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEGDAC_CTRL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_VNEGDAC_CTRL_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_CTRL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_FLYBACK_TEST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_AUX_SW_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_PA_AUX_IN_CONN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_TIMER_DIV)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_OCP_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_OCP_COUNT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_ATEST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_MISC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_HPH_LDO)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_HPH_PA)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_HPH_RDACBUFF_CNP2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_HPH_RDAC_LDO)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_HPH_CNP1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_HPH_LOWPOWER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_MISC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_MISC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_MISC4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_MISC5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_BUCK_RST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_BUCK_VREF_ERRAMP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_FLYB_ERRAMP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_FLYB_BUFF)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_BIAS_FLYB_MID_RST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_L_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_HPH_R_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_HPH_CNP_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_CNP_WG_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_CNP_WG_TIME)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_OCP_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_AUTO_CHOP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_CHOP_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_PA_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_PA_CTL2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_L_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_L_TEST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_L_ATEST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_R_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_R_TEST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_R_ATEST)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_RDAC_CLK_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_RDAC_CLK_CTL2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_RDAC_LDO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_RDAC_CHOP_CLK_LP_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_REFBUFF_UHQA_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_REFBUFF_LP_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_L_DAC_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_R_DAC_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPHLR_SURGE_COMP_SEL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPHLR_SURGE_EN)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPHLR_SURGE_MISC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPHLR_SURGE_STATUS)] = AQT1000_RO, +}; + +const u8 aqt1000_page7_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_ANA_NEW_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_ANA_HPH2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_ANA_HPH3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_MCLK1_PRG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_MCLK2_I2S_HS_CLK_PRG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_XO_CAP_XTP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_XO_CAP_XTM)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_PLL_ENABLES)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_PLL_PRESET)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_PLL_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MBHC_NEW_ELECT_REM_CLAMP_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_CTL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_CTL_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_PLUG_DETECT_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_ZDET_ANA_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_ZDET_RAMP_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_FSM_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MBHC_NEW_ADC_RESULT)] = AQT1000_RO, + [AQT1000_REG(AQT1000_HPH_NEW_INT_RDAC_GAIN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_L)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_RDAC_VREF_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_R)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_PA_MISC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_PA_MISC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_PA_RDAC_MISC)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_HPH_TIMER1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_HPH_TIMER2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_HPH_TIMER3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_HPH_TIMER4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_PA_RDAC_MISC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_HPH_NEW_INT_PA_RDAC_MISC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_RX_NEW_INT_HPH_RDAC_LDO_LP)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_CLK_TEST1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_XO_TEST1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_XO_TEST2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_POST_DIV_REG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_POST_DIV_REG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_REF_DIV_REG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_REF_DIV_REG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_FILTER_REG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_FILTER_REG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_PLL_L_VAL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_PLL_M_VAL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_PLL_N_VAL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_TEST_REG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_PFD_CP_DSM_PROG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_VCO_PROG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_TEST_REG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_LDO_LOCK_CFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CLK_SYS_INT_DIG_LOCK_DET_CFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL)] = + AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_INT_MECH_DET_CURRENT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MBHC_NEW_INT_SPARE_2)] = AQT1000_RW, +}; + +const u8 aqt1000_page10_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE10_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_CLK_RESET_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_MODE_1_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_MODE_2_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_FF_SHIFT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_FB_SHIFT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_LPF_FF_A_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_LPF_FF_B_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_LPF_FB_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_SMLPF_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_DCFLT_SHIFT_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_IIR_ADAPT_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_IIR_COEFF_1_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_IIR_COEFF_2_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_FF_A_GAIN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_FF_B_GAIN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_FB_GAIN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_RC_COMMON_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_FIFO_COMMON_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC0_RC0_STATUS_FMIN_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC0_RC1_STATUS_FMIN_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC0_RC0_STATUS_FMAX_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC0_RC1_STATUS_FMAX_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC0_STATUS_FIFO)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC1_CLK_RESET_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_MODE_1_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_MODE_2_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_FF_SHIFT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_FB_SHIFT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_LPF_FF_A_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_LPF_FF_B_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_LPF_FB_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_SMLPF_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_DCFLT_SHIFT_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_IIR_ADAPT_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_IIR_COEFF_1_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_IIR_COEFF_2_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_FF_A_GAIN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_FF_B_GAIN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_FB_GAIN_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_RC_COMMON_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_FIFO_COMMON_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_ANC1_RC0_STATUS_FMIN_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC1_RC1_STATUS_FMIN_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC1_RC0_STATUS_FMAX_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC1_RC1_STATUS_FMAX_CNTR)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_ANC1_STATUS_FIFO)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_VOL_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_SEC0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_SEC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_SEC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_SEC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_SEC4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_SEC5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX0_TX_PATH_SEC6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_VOL_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_SEC0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_SEC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_SEC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_SEC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_SEC4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_SEC5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX1_TX_PATH_SEC6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_VOL_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX2_TX_PATH_SEC7)] = AQT1000_RW, +}; + +const u8 aqt1000_page11_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE11_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL6)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_COMPANDER1_CTL7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL6)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_COMPANDER2_CTL7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_VOL_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_MIX_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_MIX_CFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_VOL_MIX_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_SEC7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_MIX_SEC0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_MIX_SEC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX1_RX_PATH_DSMDEM_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_VOL_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_MIX_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_MIX_CFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_VOL_MIX_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_SEC7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_MIX_SEC0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_MIX_SEC1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX2_RX_PATH_DSMDEM_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR0_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR0_PATH_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR0_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR0_PATH_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR0_PATH_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR0_COEF_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR0_COEF_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR1_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR1_PATH_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR1_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR1_PATH_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR1_PATH_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR1_COEF_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_EQ_IIR1_COEF_CFG1)] = AQT1000_RW, +}; + +const u8 aqt1000_page12_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE12_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_CRC)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_DLY_CTRL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_DECAY_CTRL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_HPH_V_PA)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_EAR_V_PA)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_HPH_V_HD)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_EAR_V_HD)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_K1_MSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_K1_LSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_K2_MSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_K2_LSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_IDLE_CTRL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_IDLE_HPH)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_IDLE_EAR)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_TEST0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_TEST1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLSH_OVR_VREF)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC0_CLK_RST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC0_CTL0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC0_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC0_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC0_STATUS_FIFO)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC1_CLK_RST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC1_CTL0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC1_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC1_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_MIXING_ASRC1_STATUS_FIFO)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_CLK_RST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_CTL0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_SIDETONE_ASRC0_STATUS_FIFO)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_REF_HQ0_EC_REF_HQ_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_REF_HQ0_EC_REF_HQ_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_REF_HQ1_EC_REF_HQ_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_REF_HQ1_EC_REF_HQ_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC0_CLK_RST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC0_CTL0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC0_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC0_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC0_STATUS_FMIN_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC0_STATUS_FMIN_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC0_STATUS_FMAX_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC0_STATUS_FMAX_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC0_STATUS_FIFO)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC1_CLK_RST_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC1_CTL0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC1_CTL1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC1_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_EC_ASRC1_STATUS_FMIN_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC1_STATUS_FMIN_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC1_STATUS_FMAX_CNTR_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC1_STATUS_FMAX_CNTR_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_EC_ASRC1_STATUS_FIFO)] = AQT1000_RO, +}; + +const u8 aqt1000_page13_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE13_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_EQ_IIR_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_DSD_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_RX_MIX_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_ANC_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_INP_MUX_EC_REF_HQ_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX10_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX10_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX11_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX11_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX12_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX12_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX13_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TX_INP_MUX_ADC_MUX13_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0)] = + AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_IF_ROUTER_TX_MUX_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLK_RST_CTRL_DSD_CONTROL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLK_RST_CTRL_GFM_CONTROL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_CLK_RST_CTRL_I2S_CONTROL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = + AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_TOP_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_HPHL_COMP_WR_LSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_HPHL_COMP_WR_MSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_HPHL_COMP_LUT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_HPHL_COMP_RD_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_TOP_HPHL_COMP_RD_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_TOP_HPHR_COMP_WR_LSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_HPHR_COMP_WR_MSB)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_HPHR_COMP_LUT)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_TOP_HPHR_COMP_RD_LSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_TOP_HPHR_COMP_RD_MSB)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_DSD0_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD0_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD0_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD0_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD0_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD0_CFG4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD0_CFG5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD1_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD1_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD1_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD1_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD1_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD1_CFG4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DSD1_CFG5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_IDLE_DET_PATH_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_IDLE_DET_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_IDLE_DET_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_IDLE_DET_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_RX_IDLE_DET_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DOP_DET_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DOP_DET_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DOP_DET_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DOP_DET_CFG2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DOP_DET_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DOP_DET_CFG4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DOP_DET_STATUS0)] = AQT1000_RO, +}; + +const u8 aqt1000_page15_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE15_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_ANC0_RC0_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_ANC0_RC1_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_ANC1_RC0_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_ANC1_RC1_FIFO_CTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_CDC_DEBUG_ANC_RC_RST_DBG_CNTR)] = AQT1000_RW, +}; + +const u8 aqt1000_page128_reg_access[AQT1000_PAGE_SIZE] = { + [AQT1000_REG(AQT1000_PAGE128_PAGE_REGISTER)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_SPI_CLK_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_SPI_MOSI_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_SPI_MISO_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_SPI_CS_N_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO1_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO2_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO3_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO4_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO5_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO6_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO7_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO8_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO9_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_TLMM_GPIO10_PINCFG)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PAD_PDN_CTRL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PAD_PDN_CTRL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PAD_PU_CTRL_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PAD_PU_CTRL_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_GPIO_CTL_0_OE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_GPIO_CTL_1_OE)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_GPIO_CTL_0_DATA)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_GPIO_CTL_1_DATA)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PAD_DRVCTL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PIN_STATUS)] = AQT1000_RO, + [AQT1000_REG(AQT1000_PAD_CTRL_MEM_CTRL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PAD_INP_DISABLE_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PAD_INP_DISABLE_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PIN_CTL_OE_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PIN_CTL_OE_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PIN_CTL_DATA_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_PIN_CTL_DATA_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_USB_PHY_CLK_DIV)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_BUS_CDC)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_BUS_SEL)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_EN_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_EN_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_EN_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_EN_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_EN_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_0)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_1)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_2)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_3)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_4)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_5)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_6)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_7)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_8)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_9)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_10)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_11)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_12)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_MUX_BIT_13)] = AQT1000_RW, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_READ_0)] = AQT1000_RO, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_READ_1)] = AQT1000_RO, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_READ_2)] = AQT1000_RO, + [AQT1000_REG(AQT1000_PAD_CTRL_DEBUG_READ_3)] = AQT1000_RO, + [AQT1000_REG(AQT1000_PAD_CTRL_FPGA_CTL)] = AQT1000_RW, +}; + +const u8 * const aqt1000_reg[AQT1000_PAGE_MAX] = { + [AQT1000_PAGE_0] = aqt1000_page0_reg_access, + [AQT1000_PAGE_1] = aqt1000_page1_reg_access, + [AQT1000_PAGE_2] = aqt1000_page2_reg_access, + [AQT1000_PAGE_5] = aqt1000_page5_reg_access, + [AQT1000_PAGE_6] = aqt1000_page6_reg_access, + [AQT1000_PAGE_7] = aqt1000_page7_reg_access, + [AQT1000_PAGE_10] = aqt1000_page10_reg_access, + [AQT1000_PAGE_11] = aqt1000_page11_reg_access, + [AQT1000_PAGE_12] = aqt1000_page12_reg_access, + [AQT1000_PAGE_13] = aqt1000_page13_reg_access, + [AQT1000_PAGE_15] = aqt1000_page15_reg_access, + [AQT1000_PAGE_128] = aqt1000_page128_reg_access, +}; + +#endif /* _AQT1000_REG_DEFAULTS_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-registers.h new file mode 100644 index 0000000000..1ba388255f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-registers.h @@ -0,0 +1,873 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _AQT1000_REGISTERS_H +#define _AQT1000_REGISTERS_H + +#define AQT1000_PAGE0_BASE (0x00000000) +#define AQT1000_PAGE0_PAGE_REGISTER (0x00000000) +#define AQT1000_CHIP_CFG0_BASE (0x00000001) +#define AQT1000_CHIP_CFG0_CHIP_ID_BYTE0 (0x00000001) +#define AQT1000_CHIP_CFG0_CHIP_ID_BYTE1 (0x00000002) +#define AQT1000_CHIP_CFG0_CHIP_ID_BYTE2 (0x00000003) +#define AQT1000_CHIP_CFG0_CHIP_ID_BYTE3 (0x00000004) +#define AQT1000_CHIP_CFG0_EFUSE_CTL (0x00000005) +#define AQT1000_CHIP_CFG0_EFUSE_TEST0 (0x00000006) +#define AQT1000_CHIP_CFG0_EFUSE_TEST1 (0x00000007) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT0 (0x00000009) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT1 (0x0000000A) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT2 (0x0000000B) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT3 (0x0000000C) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT4 (0x0000000D) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT5 (0x0000000E) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT6 (0x0000000F) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT7 (0x00000010) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT8 (0x00000011) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT9 (0x00000012) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT10 (0x00000013) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT11 (0x00000014) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT12 (0x00000015) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT13 (0x00000016) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT14 (0x00000017) +#define AQT1000_CHIP_CFG0_EFUSE_VAL_OUT15 (0x00000018) +#define AQT1000_CHIP_CFG0_EFUSE_STATUS (0x00000019) +#define AQT1000_CHIP_CFG0_I2C_SLAVE_ID_NONNEGO (0x0000001A) +#define AQT1000_CHIP_CFG0_I2C_SLAVE_ID_1 (0x0000001B) +#define AQT1000_CHIP_CFG0_I2C_SLAVE_ID_2 (0x0000001C) +#define AQT1000_CHIP_CFG0_I2C_SLAVE_ID_3 (0x0000001D) +#define AQT1000_CHIP_CFG0_I2C_ACTIVE (0x00000020) +#define AQT1000_CHIP_CFG0_CLK_CFG_MCLK (0x00000021) +#define AQT1000_CHIP_CFG0_CLK_CFG_MCLK2 (0x00000022) +#define AQT1000_CHIP_CFG0_CLK_CTL_CDC_DIG (0x00000023) +#define AQT1000_CHIP_CFG0_RST_CTL (0x00000032) +#define AQT1000_CHIP_CFG0_EFUSE2_CTL (0x0000003D) +#define AQT1000_CHIP_CFG0_EFUSE2_TEST0 (0x0000003E) +#define AQT1000_CHIP_CFG0_EFUSE2_TEST1 (0x0000003F) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT0 (0x00000040) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT1 (0x00000041) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT2 (0x00000042) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT3 (0x00000043) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT4 (0x00000044) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT5 (0x00000045) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT6 (0x00000046) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT7 (0x00000047) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT8 (0x00000048) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT9 (0x00000049) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT10 (0x0000004A) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT11 (0x0000004B) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT12 (0x0000004C) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT13 (0x0000004D) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT14 (0x0000004E) +#define AQT1000_CHIP_CFG0_EFUSE2_VAL_OUT15 (0x0000004F) +#define AQT1000_CHIP_CFG0_EFUSE2_STATUS (0x00000050) +#define AQT1000_CHIP_CFG1_BASE (0x00000051) +#define AQT1000_CHIP_CFG1_PWR_CTL (0x00000051) +#define AQT1000_CHIP_CFG1_BUS_MTRX_CFG (0x00000052) +#define AQT1000_CHIP_CFG1_DMA_BUS_VOTE (0x00000053) +#define AQT1000_CHIP_CFG1_USB_BUS_VOTE (0x00000054) +#define AQT1000_CHIP_CFG1_BLSP_BUS_VOTE (0x00000055) +#define AQT1000_CHIP_CFG1_PWR_MEM_SD (0x00000059) +#define AQT1000_CHIP_CFG1_PWR_SYS_MEM_SD_RAM (0x0000005C) +#define AQT1000_CHIP_CFG1_PWR_SYS_MEM_SD_ROM (0x0000005D) +#define AQT1000_CHIP_CFG1_PWR_SYS_MEM_FORCE_DS_RAM (0x0000005E) +#define AQT1000_CHIP_CFG1_PWR_SYS_MEM_FORCE_DS_ROM (0x0000005F) +#define AQT1000_CHIP_CFG1_CLK_CFG_FLL (0x00000061) +#define AQT1000_CHIP_CFG1_CLK_CFG_SPI_M (0x00000062) +#define AQT1000_CHIP_CFG1_CLK_CFG_I2C_M (0x00000063) +#define AQT1000_CHIP_CFG1_CLK_CFG_UART (0x00000064) +#define AQT1000_CHIP_CFG1_RST_USB_SS (0x00000071) +#define AQT1000_CHIP_CFG1_RST_BLSP (0x00000072) +#define AQT1000_CHIP_CFG1_RST_BUS_MTRX (0x00000073) +#define AQT1000_CHIP_CFG1_RST_MISC (0x00000074) +#define AQT1000_CHIP_CFG1_ANA_WAIT_STATE_CTL (0x00000081) +#define AQT1000_PAGE1_BASE (0x00000100) +#define AQT1000_PAGE1_PAGE_REGISTER (0x00000100) +#define AQT1000_FLL_BASE (0x00000101) +#define AQT1000_FLL_USER_CTL_0 (0x00000101) +#define AQT1000_FLL_USER_CTL_1 (0x00000102) +#define AQT1000_FLL_USER_CTL_2 (0x00000103) +#define AQT1000_FLL_USER_CTL_3 (0x00000104) +#define AQT1000_FLL_USER_CTL_4 (0x00000105) +#define AQT1000_FLL_USER_CTL_5 (0x00000106) +#define AQT1000_FLL_USER_CTL_6 (0x00000107) +#define AQT1000_FLL_USER_CTL_7 (0x00000108) +#define AQT1000_FLL_USER_CTL_8 (0x00000109) +#define AQT1000_FLL_USER_CTL_9 (0x0000010A) +#define AQT1000_FLL_L_VAL_CTL_0 (0x0000010B) +#define AQT1000_FLL_L_VAL_CTL_1 (0x0000010C) +#define AQT1000_FLL_DSM_FRAC_CTL_0 (0x0000010D) +#define AQT1000_FLL_DSM_FRAC_CTL_1 (0x0000010E) +#define AQT1000_FLL_CONFIG_CTL_0 (0x0000010F) +#define AQT1000_FLL_CONFIG_CTL_1 (0x00000110) +#define AQT1000_FLL_CONFIG_CTL_2 (0x00000111) +#define AQT1000_FLL_CONFIG_CTL_3 (0x00000112) +#define AQT1000_FLL_CONFIG_CTL_4 (0x00000113) +#define AQT1000_FLL_TEST_CTL_0 (0x00000114) +#define AQT1000_FLL_TEST_CTL_1 (0x00000115) +#define AQT1000_FLL_TEST_CTL_2 (0x00000116) +#define AQT1000_FLL_TEST_CTL_3 (0x00000117) +#define AQT1000_FLL_TEST_CTL_4 (0x00000118) +#define AQT1000_FLL_TEST_CTL_5 (0x00000119) +#define AQT1000_FLL_TEST_CTL_6 (0x0000011A) +#define AQT1000_FLL_TEST_CTL_7 (0x0000011B) +#define AQT1000_FLL_FREQ_CTL_0 (0x0000011C) +#define AQT1000_FLL_FREQ_CTL_1 (0x0000011D) +#define AQT1000_FLL_FREQ_CTL_2 (0x0000011E) +#define AQT1000_FLL_FREQ_CTL_3 (0x0000011F) +#define AQT1000_FLL_SSC_CTL_0 (0x00000120) +#define AQT1000_FLL_SSC_CTL_1 (0x00000121) +#define AQT1000_FLL_SSC_CTL_2 (0x00000122) +#define AQT1000_FLL_SSC_CTL_3 (0x00000123) +#define AQT1000_FLL_FLL_MODE (0x00000124) +#define AQT1000_FLL_STATUS_0 (0x00000125) +#define AQT1000_FLL_STATUS_1 (0x00000126) +#define AQT1000_FLL_STATUS_2 (0x00000127) +#define AQT1000_FLL_STATUS_3 (0x00000128) +#define AQT1000_PAGE2_BASE (0x00000200) +#define AQT1000_PAGE2_PAGE_REGISTER (0x00000200) +#define AQT1000_I2S_BASE (0x00000201) +#define AQT1000_I2S_I2S_0_TX_CFG (0x00000201) +#define AQT1000_I2S_I2S_0_RX_CFG (0x00000202) +#define AQT1000_I2S_I2S_0_CTL (0x00000203) +#define AQT1000_I2S_I2S_CLKSRC_CTL (0x00000204) +#define AQT1000_I2S_I2S_HS_CLK_CTL (0x00000205) +#define AQT1000_I2S_I2S_0_RST (0x00000206) +#define AQT1000_I2S_SHADOW_I2S_0_CTL (0x00000207) +#define AQT1000_I2S_SHADOW_I2S_0_RX_CFG (0x00000208) +#define AQT1000_PAGE5_BASE (0x00000500) +#define AQT1000_PAGE5_PAGE_REGISTER (0x00000500) +#define AQT1000_INTR_CTRL_INTR_CTRL_BASE (0x00000501) +#define AQT1000_INTR_CTRL_MCU_INT_POLARITY (0x00000501) +#define AQT1000_INTR_CTRL_INT_MASK_0 (0x00000502) +#define AQT1000_INTR_CTRL_INT_MASK_1 (0x00000503) +#define AQT1000_INTR_CTRL_INT_MASK_2 (0x00000504) +#define AQT1000_INTR_CTRL_INT_MASK_3 (0x00000505) +#define AQT1000_INTR_CTRL_INT_MASK_4 (0x00000506) +#define AQT1000_INTR_CTRL_INT_MASK_5 (0x00000507) +#define AQT1000_INTR_CTRL_INT_MASK_6 (0x00000508) +#define AQT1000_INTR_CTRL_INT_STATUS_0 (0x00000509) +#define AQT1000_INTR_CTRL_INT_STATUS_1 (0x0000050A) +#define AQT1000_INTR_CTRL_INT_STATUS_2 (0x0000050B) +#define AQT1000_INTR_CTRL_INT_STATUS_3 (0x0000050C) +#define AQT1000_INTR_CTRL_INT_STATUS_4 (0x0000050D) +#define AQT1000_INTR_CTRL_INT_STATUS_5 (0x0000050E) +#define AQT1000_INTR_CTRL_INT_STATUS_6 (0x0000050F) +#define AQT1000_INTR_CTRL_INT_CLEAR_0 (0x00000510) +#define AQT1000_INTR_CTRL_INT_CLEAR_1 (0x00000511) +#define AQT1000_INTR_CTRL_INT_CLEAR_2 (0x00000512) +#define AQT1000_INTR_CTRL_INT_CLEAR_3 (0x00000513) +#define AQT1000_INTR_CTRL_INT_CLEAR_4 (0x00000514) +#define AQT1000_INTR_CTRL_INT_CLEAR_5 (0x00000515) +#define AQT1000_INTR_CTRL_INT_CLEAR_6 (0x00000516) +#define AQT1000_INTR_CTRL_INT_TYPE_0 (0x00000517) +#define AQT1000_INTR_CTRL_INT_TYPE_1 (0x00000518) +#define AQT1000_INTR_CTRL_INT_TYPE_2 (0x00000519) +#define AQT1000_INTR_CTRL_INT_TYPE_3 (0x0000051A) +#define AQT1000_INTR_CTRL_INT_TYPE_4 (0x0000051B) +#define AQT1000_INTR_CTRL_INT_TYPE_5 (0x0000051C) +#define AQT1000_INTR_CTRL_INT_TYPE_6 (0x0000051D) +#define AQT1000_INTR_CTRL_INT_TEST_EN_0 (0x0000051E) +#define AQT1000_INTR_CTRL_INT_TEST_EN_1 (0x0000051F) +#define AQT1000_INTR_CTRL_INT_TEST_EN_2 (0x00000520) +#define AQT1000_INTR_CTRL_INT_TEST_EN_3 (0x00000521) +#define AQT1000_INTR_CTRL_INT_TEST_EN_4 (0x00000522) +#define AQT1000_INTR_CTRL_INT_TEST_EN_5 (0x00000523) +#define AQT1000_INTR_CTRL_INT_TEST_EN_6 (0x00000524) +#define AQT1000_INTR_CTRL_INT_TEST_VAL_0 (0x00000525) +#define AQT1000_INTR_CTRL_INT_TEST_VAL_1 (0x00000526) +#define AQT1000_INTR_CTRL_INT_TEST_VAL_2 (0x00000527) +#define AQT1000_INTR_CTRL_INT_TEST_VAL_3 (0x00000528) +#define AQT1000_INTR_CTRL_INT_TEST_VAL_4 (0x00000529) +#define AQT1000_INTR_CTRL_INT_TEST_VAL_5 (0x0000052A) +#define AQT1000_INTR_CTRL_INT_TEST_VAL_6 (0x0000052B) +#define AQT1000_INTR_CTRL_INT_DEST_0 (0x0000052C) +#define AQT1000_INTR_CTRL_INT_DEST_1 (0x0000052D) +#define AQT1000_INTR_CTRL_INT_DEST_2 (0x0000052E) +#define AQT1000_INTR_CTRL_INT_DEST_3 (0x0000052F) +#define AQT1000_INTR_CTRL_INT_DEST_4 (0x00000530) +#define AQT1000_INTR_CTRL_INT_DEST_5 (0x00000531) +#define AQT1000_INTR_CTRL_INT_DEST_6 (0x00000532) +#define AQT1000_INTR_CTRL_INT_DEST_7 (0x00000533) +#define AQT1000_INTR_CTRL_INT_DEST_8 (0x00000534) +#define AQT1000_INTR_CTRL_INT_DEST_9 (0x00000535) +#define AQT1000_INTR_CTRL_INT_DEST_10 (0x00000536) +#define AQT1000_INTR_CTRL_INT_DEST_11 (0x00000537) +#define AQT1000_INTR_CTRL_INT_DEST_12 (0x00000538) +#define AQT1000_INTR_CTRL_INT_DEST_13 (0x00000539) +#define AQT1000_INTR_CTRL_CLR_COMMIT (0x000005E1) +#define AQT1000_ANA_BASE (0x00000600) +#define AQT1000_ANA_PAGE_REGISTER (0x00000600) +#define AQT1000_ANA_BIAS (0x00000601) +#define AQT1000_ANA_RX_SUPPLIES (0x00000608) +#define AQT1000_ANA_HPH (0x00000609) +#define AQT1000_ANA_AMIC1 (0x0000060E) +#define AQT1000_ANA_AMIC2 (0x0000060F) +#define AQT1000_ANA_AMIC3 (0x00000610) +#define AQT1000_ANA_AMIC3_HPF (0x00000611) +#define AQT1000_ANA_MBHC_MECH (0x00000614) +#define AQT1000_ANA_MBHC_ELECT (0x00000615) +#define AQT1000_ANA_MBHC_ZDET (0x00000616) +#define AQT1000_ANA_MBHC_RESULT_1 (0x00000617) +#define AQT1000_ANA_MBHC_RESULT_2 (0x00000618) +#define AQT1000_ANA_MBHC_RESULT_3 (0x00000619) +#define AQT1000_ANA_MBHC_BTN0 (0x0000061A) +#define AQT1000_ANA_MBHC_BTN1 (0x0000061B) +#define AQT1000_ANA_MBHC_BTN2 (0x0000061C) +#define AQT1000_ANA_MBHC_BTN3 (0x0000061D) +#define AQT1000_ANA_MBHC_BTN4 (0x0000061E) +#define AQT1000_ANA_MBHC_BTN5 (0x0000061F) +#define AQT1000_ANA_MBHC_BTN6 (0x00000620) +#define AQT1000_ANA_MBHC_BTN7 (0x00000621) +#define AQT1000_ANA_MICB1 (0x00000622) +#define AQT1000_ANA_MICB1_RAMP (0x00000624) +#define AQT1000_BIAS_BASE (0x00000628) +#define AQT1000_BIAS_CTL (0x00000628) +#define AQT1000_BIAS_CCOMP_FINE_ADJ (0x00000629) +#define AQT1000_LED_BASE (0x0000062E) +#define AQT1000_LED_LED_MODE_SEL_R (0x0000062E) +#define AQT1000_LED_LED_MISC_R (0x0000062F) +#define AQT1000_LED_LED_MODE_SEL_G (0x00000630) +#define AQT1000_LED_LED_MISC_G (0x00000631) +#define AQT1000_LED_LED_MODE_SEL_B (0x00000632) +#define AQT1000_LED_LED_MISC_B (0x00000633) +#define AQT1000_LDOH_BASE (0x0000063A) +#define AQT1000_LDOH_MODE (0x0000063A) +#define AQT1000_LDOH_BIAS (0x0000063B) +#define AQT1000_LDOH_STB_LOADS (0x0000063C) +#define AQT1000_LDOH_MISC1 (0x0000063D) +#define AQT1000_LDOL_BASE (0x00000640) +#define AQT1000_LDOL_VDDCX_ADJUST (0x00000640) +#define AQT1000_LDOL_DISABLE_LDOL (0x00000641) +#define AQT1000_BUCK_5V_BASE (0x00000644) +#define AQT1000_BUCK_5V_EN_CTL (0x00000644) +#define AQT1000_BUCK_5V_VOUT_SEL (0x00000645) +#define AQT1000_BUCK_5V_CTRL_VCL_1 (0x00000646) +#define AQT1000_BUCK_5V_CTRL_VCL_2 (0x00000647) +#define AQT1000_BUCK_5V_CTRL_CCL_2 (0x00000648) +#define AQT1000_BUCK_5V_CTRL_CCL_1 (0x00000649) +#define AQT1000_BUCK_5V_CTRL_CCL_3 (0x0000064A) +#define AQT1000_BUCK_5V_CTRL_CCL_4 (0x0000064B) +#define AQT1000_BUCK_5V_CTRL_CCL_5 (0x0000064C) +#define AQT1000_BUCK_5V_IBIAS_CTL_1 (0x0000064D) +#define AQT1000_BUCK_5V_IBIAS_CTL_2 (0x0000064E) +#define AQT1000_BUCK_5V_IBIAS_CTL_3 (0x0000064F) +#define AQT1000_BUCK_5V_IBIAS_CTL_4 (0x00000650) +#define AQT1000_BUCK_5V_IBIAS_CTL_5 (0x00000651) +#define AQT1000_BUCK_5V_ATEST_DTEST_CTL (0x00000652) +#define AQT1000_PON_BASE (0x00000653) +#define AQT1000_PON_BG_CTRL (0x00000653) +#define AQT1000_PON_TEST_CTRL (0x00000654) +#define AQT1000_MBHC_BASE (0x00000656) +#define AQT1000_MBHC_CTL_CLK (0x00000656) +#define AQT1000_MBHC_CTL_ANA (0x00000657) +#define AQT1000_MBHC_CTL_SPARE_1 (0x00000658) +#define AQT1000_MBHC_CTL_SPARE_2 (0x00000659) +#define AQT1000_MBHC_CTL_BCS (0x0000065A) +#define AQT1000_MBHC_MOISTURE_DET_FSM_STATUS (0x0000065B) +#define AQT1000_MBHC_TEST_CTL (0x0000065C) +#define AQT1000_MICB1_BASE (0x0000066B) +#define AQT1000_MICB1_TEST_CTL_1 (0x0000066B) +#define AQT1000_MICB1_TEST_CTL_2 (0x0000066C) +#define AQT1000_MICB1_TEST_CTL_3 (0x0000066D) +#define AQT1000_MICB1_MISC_BASE (0x0000066E) +#define AQT1000_MICB1_MISC_MICB1_INM_RES_BIAS (0x0000066E) +#define AQT1000_MICB1_MISC_MICB_MISC1 (0x0000066F) +#define AQT1000_MICB1_MISC_MICB_MISC2 (0x00000670) +#define AQT1000_TX_COM_BASE (0x00000677) +#define AQT1000_TX_COM_ADC_VCM (0x00000677) +#define AQT1000_TX_COM_BIAS_ATEST (0x00000678) +#define AQT1000_TX_COM_ADC_INT1_IB (0x00000679) +#define AQT1000_TX_COM_ADC_INT2_IB (0x0000067A) +#define AQT1000_TX_COM_TXFE_DIV_CTL (0x0000067B) +#define AQT1000_TX_COM_TXFE_DIV_START (0x0000067C) +#define AQT1000_TX_COM_TXFE_DIV_STOP_9P6M (0x0000067D) +#define AQT1000_TX_COM_TXFE_DIV_STOP_12P288M (0x0000067E) +#define AQT1000_TX_1_2_BASE (0x0000067F) +#define AQT1000_TX_1_2_TEST_EN (0x0000067F) +#define AQT1000_TX_1_2_ADC_IB (0x00000680) +#define AQT1000_TX_1_2_ATEST_REFCTL (0x00000681) +#define AQT1000_TX_1_2_TEST_CTL (0x00000682) +#define AQT1000_TX_1_2_TEST_BLK_EN (0x00000683) +#define AQT1000_TX_1_2_TXFE_CLKDIV (0x00000684) +#define AQT1000_TX_1_2_SAR1_ERR (0x00000685) +#define AQT1000_TX_1_2_SAR2_ERR (0x00000686) +#define AQT1000_TX_3_BASE (0x00000687) +#define AQT1000_TX_3_TEST_EN (0x00000687) +#define AQT1000_TX_3_ADC_IB (0x00000688) +#define AQT1000_TX_3_ATEST_REFCTL (0x00000689) +#define AQT1000_TX_3_TEST_CTL (0x0000068A) +#define AQT1000_TX_3_TEST_BLK_EN (0x0000068B) +#define AQT1000_TX_3_TXFE_CLKDIV (0x0000068C) +#define AQT1000_TX_3_SAR1_ERR (0x0000068D) +#define AQT1000_TX_3_SAR2_ERR (0x0000068E) +#define AQT1000_TX_BASE (0x0000068F) +#define AQT1000_TX_ATEST1_2_SEL (0x0000068F) +#define AQT1000_CLASSH_BASE (0x00000697) +#define AQT1000_CLASSH_MODE_1 (0x00000697) +#define AQT1000_CLASSH_MODE_2 (0x00000698) +#define AQT1000_CLASSH_MODE_3 (0x00000699) +#define AQT1000_CLASSH_CTRL_VCL_1 (0x0000069A) +#define AQT1000_CLASSH_CTRL_VCL_2 (0x0000069B) +#define AQT1000_CLASSH_CTRL_CCL_1 (0x0000069C) +#define AQT1000_CLASSH_CTRL_CCL_2 (0x0000069D) +#define AQT1000_CLASSH_CTRL_CCL_3 (0x0000069E) +#define AQT1000_CLASSH_CTRL_CCL_4 (0x0000069F) +#define AQT1000_CLASSH_CTRL_CCL_5 (0x000006A0) +#define AQT1000_CLASSH_BUCK_TMUX_A_D (0x000006A1) +#define AQT1000_CLASSH_BUCK_SW_DRV_CNTL (0x000006A2) +#define AQT1000_CLASSH_SPARE (0x000006A3) +#define AQT1000_FLYBACK_BASE (0x000006A4) +#define AQT1000_FLYBACK_EN (0x000006A4) +#define AQT1000_FLYBACK_VNEG_CTRL_1 (0x000006A5) +#define AQT1000_FLYBACK_VNEG_CTRL_2 (0x000006A6) +#define AQT1000_FLYBACK_VNEG_CTRL_3 (0x000006A7) +#define AQT1000_FLYBACK_VNEG_CTRL_4 (0x000006A8) +#define AQT1000_FLYBACK_VNEG_CTRL_5 (0x000006A9) +#define AQT1000_FLYBACK_VNEG_CTRL_6 (0x000006AA) +#define AQT1000_FLYBACK_VNEG_CTRL_7 (0x000006AB) +#define AQT1000_FLYBACK_VNEG_CTRL_8 (0x000006AC) +#define AQT1000_FLYBACK_VNEG_CTRL_9 (0x000006AD) +#define AQT1000_FLYBACK_VNEGDAC_CTRL_1 (0x000006AE) +#define AQT1000_FLYBACK_VNEGDAC_CTRL_2 (0x000006AF) +#define AQT1000_FLYBACK_VNEGDAC_CTRL_3 (0x000006B0) +#define AQT1000_FLYBACK_CTRL_1 (0x000006B1) +#define AQT1000_FLYBACK_TEST_CTL (0x000006B2) +#define AQT1000_RX_BASE (0x000006B3) +#define AQT1000_RX_AUX_SW_CTL (0x000006B3) +#define AQT1000_RX_PA_AUX_IN_CONN (0x000006B4) +#define AQT1000_RX_TIMER_DIV (0x000006B5) +#define AQT1000_RX_OCP_CTL (0x000006B6) +#define AQT1000_RX_OCP_COUNT (0x000006B7) +#define AQT1000_RX_BIAS_ATEST (0x000006B8) +#define AQT1000_RX_BIAS_MISC1 (0x000006B9) +#define AQT1000_RX_BIAS_HPH_LDO (0x000006BA) +#define AQT1000_RX_BIAS_HPH_PA (0x000006BB) +#define AQT1000_RX_BIAS_HPH_RDACBUFF_CNP2 (0x000006BC) +#define AQT1000_RX_BIAS_HPH_RDAC_LDO (0x000006BD) +#define AQT1000_RX_BIAS_HPH_CNP1 (0x000006BE) +#define AQT1000_RX_BIAS_HPH_LOWPOWER (0x000006BF) +#define AQT1000_RX_BIAS_MISC2 (0x000006C0) +#define AQT1000_RX_BIAS_MISC3 (0x000006C1) +#define AQT1000_RX_BIAS_MISC4 (0x000006C2) +#define AQT1000_RX_BIAS_MISC5 (0x000006C3) +#define AQT1000_RX_BIAS_BUCK_RST (0x000006C4) +#define AQT1000_RX_BIAS_BUCK_VREF_ERRAMP (0x000006C5) +#define AQT1000_RX_BIAS_FLYB_ERRAMP (0x000006C6) +#define AQT1000_RX_BIAS_FLYB_BUFF (0x000006C7) +#define AQT1000_RX_BIAS_FLYB_MID_RST (0x000006C8) +#define AQT1000_HPH_BASE (0x000006C9) +#define AQT1000_HPH_L_STATUS (0x000006C9) +#define AQT1000_HPH_R_STATUS (0x000006CA) +#define AQT1000_HPH_CNP_EN (0x000006CB) +#define AQT1000_HPH_CNP_WG_CTL (0x000006CC) +#define AQT1000_HPH_CNP_WG_TIME (0x000006CD) +#define AQT1000_HPH_OCP_CTL (0x000006CE) +#define AQT1000_HPH_AUTO_CHOP (0x000006CF) +#define AQT1000_HPH_CHOP_CTL (0x000006D0) +#define AQT1000_HPH_PA_CTL1 (0x000006D1) +#define AQT1000_HPH_PA_CTL2 (0x000006D2) +#define AQT1000_HPH_L_EN (0x000006D3) +#define AQT1000_HPH_L_TEST (0x000006D4) +#define AQT1000_HPH_L_ATEST (0x000006D5) +#define AQT1000_HPH_R_EN (0x000006D6) +#define AQT1000_HPH_R_TEST (0x000006D7) +#define AQT1000_HPH_R_ATEST (0x000006D8) +#define AQT1000_HPH_RDAC_CLK_CTL1 (0x000006D9) +#define AQT1000_HPH_RDAC_CLK_CTL2 (0x000006DA) +#define AQT1000_HPH_RDAC_LDO_CTL (0x000006DB) +#define AQT1000_HPH_RDAC_CHOP_CLK_LP_CTL (0x000006DC) +#define AQT1000_HPH_REFBUFF_UHQA_CTL (0x000006DD) +#define AQT1000_HPH_REFBUFF_LP_CTL (0x000006DE) +#define AQT1000_HPH_L_DAC_CTL (0x000006DF) +#define AQT1000_HPH_R_DAC_CTL (0x000006E0) +#define AQT1000_HPHLR_BASE (0x000006E1) +#define AQT1000_HPHLR_SURGE_COMP_SEL (0x000006E1) +#define AQT1000_HPHLR_SURGE_EN (0x000006E2) +#define AQT1000_HPHLR_SURGE_MISC1 (0x000006E3) +#define AQT1000_HPHLR_SURGE_STATUS (0x000006E4) +#define AQT1000_ANA_NEW_BASE (0x00000700) +#define AQT1000_ANA_NEW_PAGE_REGISTER (0x00000700) +#define AQT1000_HPH_NEW_BASE (0x00000701) +#define AQT1000_HPH_NEW_ANA_HPH2 (0x00000701) +#define AQT1000_HPH_NEW_ANA_HPH3 (0x00000702) +#define AQT1000_CLK_SYS_BASE (0x0000070E) +#define AQT1000_CLK_SYS_MCLK1_PRG (0x0000070E) +#define AQT1000_CLK_SYS_MCLK2_I2S_HS_CLK_PRG (0x0000070F) +#define AQT1000_CLK_SYS_XO_CAP_XTP (0x00000710) +#define AQT1000_CLK_SYS_XO_CAP_XTM (0x00000711) +#define AQT1000_CLK_SYS_PLL_ENABLES (0x00000712) +#define AQT1000_CLK_SYS_PLL_PRESET (0x00000713) +#define AQT1000_CLK_SYS_PLL_STATUS (0x00000714) +#define AQT1000_MBHC_NEW_BASE (0x0000071F) +#define AQT1000_MBHC_NEW_ELECT_REM_CLAMP_CTL (0x0000071F) +#define AQT1000_MBHC_NEW_CTL_1 (0x00000720) +#define AQT1000_MBHC_NEW_CTL_2 (0x00000721) +#define AQT1000_MBHC_NEW_PLUG_DETECT_CTL (0x00000722) +#define AQT1000_MBHC_NEW_ZDET_ANA_CTL (0x00000723) +#define AQT1000_MBHC_NEW_ZDET_RAMP_CTL (0x00000724) +#define AQT1000_MBHC_NEW_FSM_STATUS (0x00000725) +#define AQT1000_MBHC_NEW_ADC_RESULT (0x00000726) +#define AQT1000_HPH_NEW_INT_BASE (0x00000732) +#define AQT1000_HPH_NEW_INT_RDAC_GAIN_CTL (0x00000732) +#define AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_L (0x00000733) +#define AQT1000_HPH_NEW_INT_RDAC_VREF_CTL (0x00000734) +#define AQT1000_HPH_NEW_INT_RDAC_OVERRIDE_CTL (0x00000735) +#define AQT1000_HPH_NEW_INT_RDAC_HD2_CTL_R (0x00000736) +#define AQT1000_HPH_NEW_INT_PA_MISC1 (0x00000737) +#define AQT1000_HPH_NEW_INT_PA_MISC2 (0x00000738) +#define AQT1000_HPH_NEW_INT_PA_RDAC_MISC (0x00000739) +#define AQT1000_HPH_NEW_INT_HPH_TIMER1 (0x0000073A) +#define AQT1000_HPH_NEW_INT_HPH_TIMER2 (0x0000073B) +#define AQT1000_HPH_NEW_INT_HPH_TIMER3 (0x0000073C) +#define AQT1000_HPH_NEW_INT_HPH_TIMER4 (0x0000073D) +#define AQT1000_HPH_NEW_INT_PA_RDAC_MISC2 (0x0000073E) +#define AQT1000_HPH_NEW_INT_PA_RDAC_MISC3 (0x0000073F) +#define AQT1000_RX_NEW_INT_BASE (0x00000745) +#define AQT1000_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (0x00000745) +#define AQT1000_RX_NEW_INT_HPH_RDAC_BIAS_ULP (0x00000746) +#define AQT1000_RX_NEW_INT_HPH_RDAC_LDO_LP (0x00000747) +#define AQT1000_CLK_SYS_INT_BASE (0x0000076C) +#define AQT1000_CLK_SYS_INT_CLK_TEST1 (0x0000076C) +#define AQT1000_CLK_SYS_INT_XO_TEST1 (0x0000076D) +#define AQT1000_CLK_SYS_INT_XO_TEST2 (0x0000076E) +#define AQT1000_CLK_SYS_INT_POST_DIV_REG0 (0x0000076F) +#define AQT1000_CLK_SYS_INT_POST_DIV_REG1 (0x00000770) +#define AQT1000_CLK_SYS_INT_REF_DIV_REG0 (0x00000771) +#define AQT1000_CLK_SYS_INT_REF_DIV_REG1 (0x00000772) +#define AQT1000_CLK_SYS_INT_FILTER_REG0 (0x00000773) +#define AQT1000_CLK_SYS_INT_FILTER_REG1 (0x00000774) +#define AQT1000_CLK_SYS_INT_PLL_L_VAL (0x00000775) +#define AQT1000_CLK_SYS_INT_PLL_M_VAL (0x00000776) +#define AQT1000_CLK_SYS_INT_PLL_N_VAL (0x00000777) +#define AQT1000_CLK_SYS_INT_TEST_REG0 (0x00000778) +#define AQT1000_CLK_SYS_INT_PFD_CP_DSM_PROG (0x00000779) +#define AQT1000_CLK_SYS_INT_VCO_PROG (0x0000077A) +#define AQT1000_CLK_SYS_INT_TEST_REG1 (0x0000077B) +#define AQT1000_CLK_SYS_INT_LDO_LOCK_CFG (0x0000077C) +#define AQT1000_CLK_SYS_INT_DIG_LOCK_DET_CFG (0x0000077D) +#define AQT1000_MBHC_NEW_INT_BASE (0x000007AF) +#define AQT1000_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL (0x000007AF) +#define AQT1000_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL (0x000007B0) +#define AQT1000_MBHC_NEW_INT_MECH_DET_CURRENT (0x000007B1) +#define AQT1000_MBHC_NEW_INT_SPARE_2 (0x000007B2) +#define AQT1000_PAGE10_BASE (0x00000A00) +#define AQT1000_PAGE10_PAGE_REGISTER (0x00000A00) +#define AQT1000_CDC_ANC0_BASE (0x00000A01) +#define AQT1000_CDC_ANC0_CLK_RESET_CTL (0x00000A01) +#define AQT1000_CDC_ANC0_MODE_1_CTL (0x00000A02) +#define AQT1000_CDC_ANC0_MODE_2_CTL (0x00000A03) +#define AQT1000_CDC_ANC0_FF_SHIFT (0x00000A04) +#define AQT1000_CDC_ANC0_FB_SHIFT (0x00000A05) +#define AQT1000_CDC_ANC0_LPF_FF_A_CTL (0x00000A06) +#define AQT1000_CDC_ANC0_LPF_FF_B_CTL (0x00000A07) +#define AQT1000_CDC_ANC0_LPF_FB_CTL (0x00000A08) +#define AQT1000_CDC_ANC0_SMLPF_CTL (0x00000A09) +#define AQT1000_CDC_ANC0_DCFLT_SHIFT_CTL (0x00000A0A) +#define AQT1000_CDC_ANC0_IIR_ADAPT_CTL (0x00000A0B) +#define AQT1000_CDC_ANC0_IIR_COEFF_1_CTL (0x00000A0C) +#define AQT1000_CDC_ANC0_IIR_COEFF_2_CTL (0x00000A0D) +#define AQT1000_CDC_ANC0_FF_A_GAIN_CTL (0x00000A0E) +#define AQT1000_CDC_ANC0_FF_B_GAIN_CTL (0x00000A0F) +#define AQT1000_CDC_ANC0_FB_GAIN_CTL (0x00000A10) +#define AQT1000_CDC_ANC0_RC_COMMON_CTL (0x00000A11) +#define AQT1000_CDC_ANC0_FIFO_COMMON_CTL (0x00000A13) +#define AQT1000_CDC_ANC0_RC0_STATUS_FMIN_CNTR (0x00000A14) +#define AQT1000_CDC_ANC0_RC1_STATUS_FMIN_CNTR (0x00000A15) +#define AQT1000_CDC_ANC0_RC0_STATUS_FMAX_CNTR (0x00000A16) +#define AQT1000_CDC_ANC0_RC1_STATUS_FMAX_CNTR (0x00000A17) +#define AQT1000_CDC_ANC0_STATUS_FIFO (0x00000A18) +#define AQT1000_CDC_ANC1_BASE (0x00000A19) +#define AQT1000_CDC_ANC1_CLK_RESET_CTL (0x00000A19) +#define AQT1000_CDC_ANC1_MODE_1_CTL (0x00000A1A) +#define AQT1000_CDC_ANC1_MODE_2_CTL (0x00000A1B) +#define AQT1000_CDC_ANC1_FF_SHIFT (0x00000A1C) +#define AQT1000_CDC_ANC1_FB_SHIFT (0x00000A1D) +#define AQT1000_CDC_ANC1_LPF_FF_A_CTL (0x00000A1E) +#define AQT1000_CDC_ANC1_LPF_FF_B_CTL (0x00000A1F) +#define AQT1000_CDC_ANC1_LPF_FB_CTL (0x00000A20) +#define AQT1000_CDC_ANC1_SMLPF_CTL (0x00000A21) +#define AQT1000_CDC_ANC1_DCFLT_SHIFT_CTL (0x00000A22) +#define AQT1000_CDC_ANC1_IIR_ADAPT_CTL (0x00000A23) +#define AQT1000_CDC_ANC1_IIR_COEFF_1_CTL (0x00000A24) +#define AQT1000_CDC_ANC1_IIR_COEFF_2_CTL (0x00000A25) +#define AQT1000_CDC_ANC1_FF_A_GAIN_CTL (0x00000A26) +#define AQT1000_CDC_ANC1_FF_B_GAIN_CTL (0x00000A27) +#define AQT1000_CDC_ANC1_FB_GAIN_CTL (0x00000A28) +#define AQT1000_CDC_ANC1_RC_COMMON_CTL (0x00000A29) +#define AQT1000_CDC_ANC1_FIFO_COMMON_CTL (0x00000A2B) +#define AQT1000_CDC_ANC1_RC0_STATUS_FMIN_CNTR (0x00000A2C) +#define AQT1000_CDC_ANC1_RC1_STATUS_FMIN_CNTR (0x00000A2D) +#define AQT1000_CDC_ANC1_RC0_STATUS_FMAX_CNTR (0x00000A2E) +#define AQT1000_CDC_ANC1_RC1_STATUS_FMAX_CNTR (0x00000A2F) +#define AQT1000_CDC_ANC1_STATUS_FIFO (0x00000A30) +#define AQT1000_CDC_TX0_BASE (0x00000A31) +#define AQT1000_CDC_TX0_TX_PATH_CTL (0x00000A31) +#define AQT1000_CDC_TX0_TX_PATH_CFG0 (0x00000A32) +#define AQT1000_CDC_TX0_TX_PATH_CFG1 (0x00000A33) +#define AQT1000_CDC_TX0_TX_VOL_CTL (0x00000A34) +#define AQT1000_CDC_TX0_TX_PATH_SEC0 (0x00000A37) +#define AQT1000_CDC_TX0_TX_PATH_SEC1 (0x00000A38) +#define AQT1000_CDC_TX0_TX_PATH_SEC2 (0x00000A39) +#define AQT1000_CDC_TX0_TX_PATH_SEC3 (0x00000A3A) +#define AQT1000_CDC_TX0_TX_PATH_SEC4 (0x00000A3B) +#define AQT1000_CDC_TX0_TX_PATH_SEC5 (0x00000A3C) +#define AQT1000_CDC_TX0_TX_PATH_SEC6 (0x00000A3D) +#define AQT1000_CDC_TX1_BASE (0x00000A41) +#define AQT1000_CDC_TX1_TX_PATH_CTL (0x00000A41) +#define AQT1000_CDC_TX1_TX_PATH_CFG0 (0x00000A42) +#define AQT1000_CDC_TX1_TX_PATH_CFG1 (0x00000A43) +#define AQT1000_CDC_TX1_TX_VOL_CTL (0x00000A44) +#define AQT1000_CDC_TX1_TX_PATH_SEC0 (0x00000A47) +#define AQT1000_CDC_TX1_TX_PATH_SEC1 (0x00000A48) +#define AQT1000_CDC_TX1_TX_PATH_SEC2 (0x00000A49) +#define AQT1000_CDC_TX1_TX_PATH_SEC3 (0x00000A4A) +#define AQT1000_CDC_TX1_TX_PATH_SEC4 (0x00000A4B) +#define AQT1000_CDC_TX1_TX_PATH_SEC5 (0x00000A4C) +#define AQT1000_CDC_TX1_TX_PATH_SEC6 (0x00000A4D) +#define AQT1000_CDC_TX2_BASE (0x00000A51) +#define AQT1000_CDC_TX2_TX_PATH_CTL (0x00000A51) +#define AQT1000_CDC_TX2_TX_PATH_CFG0 (0x00000A52) +#define AQT1000_CDC_TX2_TX_PATH_CFG1 (0x00000A53) +#define AQT1000_CDC_TX2_TX_VOL_CTL (0x00000A54) +#define AQT1000_CDC_TX2_TX_PATH_SEC0 (0x00000A57) +#define AQT1000_CDC_TX2_TX_PATH_SEC1 (0x00000A58) +#define AQT1000_CDC_TX2_TX_PATH_SEC2 (0x00000A59) +#define AQT1000_CDC_TX2_TX_PATH_SEC3 (0x00000A5A) +#define AQT1000_CDC_TX2_TX_PATH_SEC4 (0x00000A5B) +#define AQT1000_CDC_TX2_TX_PATH_SEC5 (0x00000A5C) +#define AQT1000_CDC_TX2_TX_PATH_SEC6 (0x00000A5D) +#define AQT1000_CDC_TX2_TX_PATH_SEC7 (0x00000A5E) +#define AQT1000_PAGE11_BASE (0x00000B00) +#define AQT1000_PAGE11_PAGE_REGISTER (0x00000B00) +#define AQT1000_CDC_COMPANDER1_BASE (0x00000B01) +#define AQT1000_CDC_COMPANDER1_CTL0 (0x00000B01) +#define AQT1000_CDC_COMPANDER1_CTL1 (0x00000B02) +#define AQT1000_CDC_COMPANDER1_CTL2 (0x00000B03) +#define AQT1000_CDC_COMPANDER1_CTL3 (0x00000B04) +#define AQT1000_CDC_COMPANDER1_CTL4 (0x00000B05) +#define AQT1000_CDC_COMPANDER1_CTL5 (0x00000B06) +#define AQT1000_CDC_COMPANDER1_CTL6 (0x00000B07) +#define AQT1000_CDC_COMPANDER1_CTL7 (0x00000B08) +#define AQT1000_CDC_COMPANDER2_BASE (0x00000B09) +#define AQT1000_CDC_COMPANDER2_CTL0 (0x00000B09) +#define AQT1000_CDC_COMPANDER2_CTL1 (0x00000B0A) +#define AQT1000_CDC_COMPANDER2_CTL2 (0x00000B0B) +#define AQT1000_CDC_COMPANDER2_CTL3 (0x00000B0C) +#define AQT1000_CDC_COMPANDER2_CTL4 (0x00000B0D) +#define AQT1000_CDC_COMPANDER2_CTL5 (0x00000B0E) +#define AQT1000_CDC_COMPANDER2_CTL6 (0x00000B0F) +#define AQT1000_CDC_COMPANDER2_CTL7 (0x00000B10) +#define AQT1000_CDC_RX1_BASE (0x00000B55) +#define AQT1000_CDC_RX1_RX_PATH_CTL (0x00000B55) +#define AQT1000_CDC_RX1_RX_PATH_CFG0 (0x00000B56) +#define AQT1000_CDC_RX1_RX_PATH_CFG1 (0x00000B57) +#define AQT1000_CDC_RX1_RX_PATH_CFG2 (0x00000B58) +#define AQT1000_CDC_RX1_RX_VOL_CTL (0x00000B59) +#define AQT1000_CDC_RX1_RX_PATH_MIX_CTL (0x00000B5A) +#define AQT1000_CDC_RX1_RX_PATH_MIX_CFG (0x00000B5B) +#define AQT1000_CDC_RX1_RX_VOL_MIX_CTL (0x00000B5C) +#define AQT1000_CDC_RX1_RX_PATH_SEC0 (0x00000B5D) +#define AQT1000_CDC_RX1_RX_PATH_SEC1 (0x00000B5E) +#define AQT1000_CDC_RX1_RX_PATH_SEC2 (0x00000B5F) +#define AQT1000_CDC_RX1_RX_PATH_SEC3 (0x00000B60) +#define AQT1000_CDC_RX1_RX_PATH_SEC4 (0x00000B61) +#define AQT1000_CDC_RX1_RX_PATH_SEC5 (0x00000B62) +#define AQT1000_CDC_RX1_RX_PATH_SEC6 (0x00000B63) +#define AQT1000_CDC_RX1_RX_PATH_SEC7 (0x00000B64) +#define AQT1000_CDC_RX1_RX_PATH_MIX_SEC0 (0x00000B65) +#define AQT1000_CDC_RX1_RX_PATH_MIX_SEC1 (0x00000B66) +#define AQT1000_CDC_RX1_RX_PATH_DSMDEM_CTL (0x00000B67) +#define AQT1000_CDC_RX2_BASE (0x00000B69) +#define AQT1000_CDC_RX2_RX_PATH_CTL (0x00000B69) +#define AQT1000_CDC_RX2_RX_PATH_CFG0 (0x00000B6A) +#define AQT1000_CDC_RX2_RX_PATH_CFG1 (0x00000B6B) +#define AQT1000_CDC_RX2_RX_PATH_CFG2 (0x00000B6C) +#define AQT1000_CDC_RX2_RX_VOL_CTL (0x00000B6D) +#define AQT1000_CDC_RX2_RX_PATH_MIX_CTL (0x00000B6E) +#define AQT1000_CDC_RX2_RX_PATH_MIX_CFG (0x00000B6F) +#define AQT1000_CDC_RX2_RX_VOL_MIX_CTL (0x00000B70) +#define AQT1000_CDC_RX2_RX_PATH_SEC0 (0x00000B71) +#define AQT1000_CDC_RX2_RX_PATH_SEC1 (0x00000B72) +#define AQT1000_CDC_RX2_RX_PATH_SEC2 (0x00000B73) +#define AQT1000_CDC_RX2_RX_PATH_SEC3 (0x00000B74) +#define AQT1000_CDC_RX2_RX_PATH_SEC4 (0x00000B75) +#define AQT1000_CDC_RX2_RX_PATH_SEC5 (0x00000B76) +#define AQT1000_CDC_RX2_RX_PATH_SEC6 (0x00000B77) +#define AQT1000_CDC_RX2_RX_PATH_SEC7 (0x00000B78) +#define AQT1000_CDC_RX2_RX_PATH_MIX_SEC0 (0x00000B79) +#define AQT1000_CDC_RX2_RX_PATH_MIX_SEC1 (0x00000B7A) +#define AQT1000_CDC_RX2_RX_PATH_DSMDEM_CTL (0x00000B7B) +#define AQT1000_CDC_EQ_IIR0_BASE (0x00000BD1) +#define AQT1000_CDC_EQ_IIR0_PATH_CTL (0x00000BD1) +#define AQT1000_CDC_EQ_IIR0_PATH_CFG0 (0x00000BD2) +#define AQT1000_CDC_EQ_IIR0_PATH_CFG1 (0x00000BD3) +#define AQT1000_CDC_EQ_IIR0_PATH_CFG2 (0x00000BD4) +#define AQT1000_CDC_EQ_IIR0_PATH_CFG3 (0x00000BD5) +#define AQT1000_CDC_EQ_IIR0_COEF_CFG0 (0x00000BD6) +#define AQT1000_CDC_EQ_IIR0_COEF_CFG1 (0x00000BD7) +#define AQT1000_CDC_EQ_IIR1_BASE (0x00000BE1) +#define AQT1000_CDC_EQ_IIR1_PATH_CTL (0x00000BE1) +#define AQT1000_CDC_EQ_IIR1_PATH_CFG0 (0x00000BE2) +#define AQT1000_CDC_EQ_IIR1_PATH_CFG1 (0x00000BE3) +#define AQT1000_CDC_EQ_IIR1_PATH_CFG2 (0x00000BE4) +#define AQT1000_CDC_EQ_IIR1_PATH_CFG3 (0x00000BE5) +#define AQT1000_CDC_EQ_IIR1_COEF_CFG0 (0x00000BE6) +#define AQT1000_CDC_EQ_IIR1_COEF_CFG1 (0x00000BE7) +#define AQT1000_PAGE12_BASE (0x00000C00) +#define AQT1000_PAGE12_PAGE_REGISTER (0x00000C00) +#define AQT1000_CDC_CLSH_CDC_CLSH_BASE (0x00000C01) +#define AQT1000_CDC_CLSH_CRC (0x00000C01) +#define AQT1000_CDC_CLSH_DLY_CTRL (0x00000C02) +#define AQT1000_CDC_CLSH_DECAY_CTRL (0x00000C03) +#define AQT1000_CDC_CLSH_HPH_V_PA (0x00000C04) +#define AQT1000_CDC_CLSH_EAR_V_PA (0x00000C05) +#define AQT1000_CDC_CLSH_HPH_V_HD (0x00000C06) +#define AQT1000_CDC_CLSH_EAR_V_HD (0x00000C07) +#define AQT1000_CDC_CLSH_K1_MSB (0x00000C08) +#define AQT1000_CDC_CLSH_K1_LSB (0x00000C09) +#define AQT1000_CDC_CLSH_K2_MSB (0x00000C0A) +#define AQT1000_CDC_CLSH_K2_LSB (0x00000C0B) +#define AQT1000_CDC_CLSH_IDLE_CTRL (0x00000C0C) +#define AQT1000_CDC_CLSH_IDLE_HPH (0x00000C0D) +#define AQT1000_CDC_CLSH_IDLE_EAR (0x00000C0E) +#define AQT1000_CDC_CLSH_TEST0 (0x00000C0F) +#define AQT1000_CDC_CLSH_TEST1 (0x00000C10) +#define AQT1000_CDC_CLSH_OVR_VREF (0x00000C11) +#define AQT1000_MIXING_ASRC0_BASE (0x00000C55) +#define AQT1000_MIXING_ASRC0_CLK_RST_CTL (0x00000C55) +#define AQT1000_MIXING_ASRC0_CTL0 (0x00000C56) +#define AQT1000_MIXING_ASRC0_CTL1 (0x00000C57) +#define AQT1000_MIXING_ASRC0_FIFO_CTL (0x00000C58) +#define AQT1000_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB (0x00000C59) +#define AQT1000_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB (0x00000C5A) +#define AQT1000_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB (0x00000C5B) +#define AQT1000_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB (0x00000C5C) +#define AQT1000_MIXING_ASRC0_STATUS_FIFO (0x00000C5D) +#define AQT1000_MIXING_ASRC1_BASE (0x00000C61) +#define AQT1000_MIXING_ASRC1_CLK_RST_CTL (0x00000C61) +#define AQT1000_MIXING_ASRC1_CTL0 (0x00000C62) +#define AQT1000_MIXING_ASRC1_CTL1 (0x00000C63) +#define AQT1000_MIXING_ASRC1_FIFO_CTL (0x00000C64) +#define AQT1000_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB (0x00000C65) +#define AQT1000_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB (0x00000C66) +#define AQT1000_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB (0x00000C67) +#define AQT1000_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB (0x00000C68) +#define AQT1000_MIXING_ASRC1_STATUS_FIFO (0x00000C69) +#define AQT1000_CDC_SIDETONE_SRC0_BASE (0x00000CB5) +#define AQT1000_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL (0x00000CB5) +#define AQT1000_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1 (0x00000CB6) +#define AQT1000_SIDETONE_ASRC0_BASE (0x00000CBD) +#define AQT1000_SIDETONE_ASRC0_CLK_RST_CTL (0x00000CBD) +#define AQT1000_SIDETONE_ASRC0_CTL0 (0x00000CBE) +#define AQT1000_SIDETONE_ASRC0_CTL1 (0x00000CBF) +#define AQT1000_SIDETONE_ASRC0_FIFO_CTL (0x00000CC0) +#define AQT1000_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB (0x00000CC1) +#define AQT1000_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB (0x00000CC2) +#define AQT1000_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB (0x00000CC3) +#define AQT1000_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB (0x00000CC4) +#define AQT1000_SIDETONE_ASRC0_STATUS_FIFO (0x00000CC5) +#define AQT1000_EC_REF_HQ0_BASE (0x00000CD5) +#define AQT1000_EC_REF_HQ0_EC_REF_HQ_PATH_CTL (0x00000CD5) +#define AQT1000_EC_REF_HQ0_EC_REF_HQ_CFG0 (0x00000CD6) +#define AQT1000_EC_REF_HQ1_BASE (0x00000CDD) +#define AQT1000_EC_REF_HQ1_EC_REF_HQ_PATH_CTL (0x00000CDD) +#define AQT1000_EC_REF_HQ1_EC_REF_HQ_CFG0 (0x00000CDE) +#define AQT1000_EC_ASRC0_BASE (0x00000CE5) +#define AQT1000_EC_ASRC0_CLK_RST_CTL (0x00000CE5) +#define AQT1000_EC_ASRC0_CTL0 (0x00000CE6) +#define AQT1000_EC_ASRC0_CTL1 (0x00000CE7) +#define AQT1000_EC_ASRC0_FIFO_CTL (0x00000CE8) +#define AQT1000_EC_ASRC0_STATUS_FMIN_CNTR_LSB (0x00000CE9) +#define AQT1000_EC_ASRC0_STATUS_FMIN_CNTR_MSB (0x00000CEA) +#define AQT1000_EC_ASRC0_STATUS_FMAX_CNTR_LSB (0x00000CEB) +#define AQT1000_EC_ASRC0_STATUS_FMAX_CNTR_MSB (0x00000CEC) +#define AQT1000_EC_ASRC0_STATUS_FIFO (0x00000CED) +#define AQT1000_EC_ASRC1_BASE (0x00000CF1) +#define AQT1000_EC_ASRC1_CLK_RST_CTL (0x00000CF1) +#define AQT1000_EC_ASRC1_CTL0 (0x00000CF2) +#define AQT1000_EC_ASRC1_CTL1 (0x00000CF3) +#define AQT1000_EC_ASRC1_FIFO_CTL (0x00000CF4) +#define AQT1000_EC_ASRC1_STATUS_FMIN_CNTR_LSB (0x00000CF5) +#define AQT1000_EC_ASRC1_STATUS_FMIN_CNTR_MSB (0x00000CF6) +#define AQT1000_EC_ASRC1_STATUS_FMAX_CNTR_LSB (0x00000CF7) +#define AQT1000_EC_ASRC1_STATUS_FMAX_CNTR_MSB (0x00000CF8) +#define AQT1000_EC_ASRC1_STATUS_FIFO (0x00000CF9) +#define AQT1000_PAGE13_BASE (0x00000D00) +#define AQT1000_PAGE13_PAGE_REGISTER (0x00000D00) +#define AQT1000_CDC_RX_INP_MUX_CDC_RX_INP_MUX_BASE (0x00000D01) +#define AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG0 (0x00000D03) +#define AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG1 (0x00000D04) +#define AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG0 (0x00000D05) +#define AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG1 (0x00000D06) +#define AQT1000_CDC_RX_INP_MUX_EQ_IIR_CFG0 (0x00000D11) +#define AQT1000_CDC_RX_INP_MUX_DSD_CFG0 (0x00000D12) +#define AQT1000_CDC_RX_INP_MUX_RX_MIX_CFG0 (0x00000D13) +#define AQT1000_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0 (0x00000D18) +#define AQT1000_CDC_RX_INP_MUX_ANC_CFG0 (0x00000D1A) +#define AQT1000_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0 (0x00000D1B) +#define AQT1000_CDC_RX_INP_MUX_EC_REF_HQ_CFG0 (0x00000D1C) +#define AQT1000_CDC_TX_INP_MUX_CDC_TX_INP_MUX_BASE (0x00000D1D) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG0 (0x00000D1D) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG1 (0x00000D1E) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG0 (0x00000D1F) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG1 (0x00000D20) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG0 (0x00000D21) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG1 (0x00000D22) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX10_CFG0 (0x00000D29) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX10_CFG1 (0x00000D2A) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX11_CFG0 (0x00000D2B) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX11_CFG1 (0x00000D2C) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX12_CFG0 (0x00000D2D) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX12_CFG1 (0x00000D2E) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX13_CFG0 (0x00000D2F) +#define AQT1000_CDC_TX_INP_MUX_ADC_MUX13_CFG1 (0x00000D30) +#define AQT1000_CDC_SIDETONE_IIR_INP_MUX_CDC_SIDETONE_IIR_INP_MUX_BASE (0xD31) +#define AQT1000_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0 (0x00000D31) +#define AQT1000_CDC_IF_ROUTER_CDC_IF_ROUTER_BASE (0x00000D3D) +#define AQT1000_CDC_IF_ROUTER_TX_MUX_CFG0 (0x00000D3D) +#define AQT1000_CDC_CLK_RST_CTRL_CDC_CLK_RST_CTRL_BASE (0x00000D41) +#define AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL (0x00000D41) +#define AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL (0x00000D42) +#define AQT1000_CDC_CLK_RST_CTRL_DSD_CONTROL (0x00000D44) +#define AQT1000_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL (0x00000D45) +#define AQT1000_CDC_CLK_RST_CTRL_GFM_CONTROL (0x00000D46) +#define AQT1000_CDC_CLK_RST_CTRL_I2S_CONTROL (0x00000D47) +#define AQT1000_CDC_SIDETONE_IIR0_BASE (0x00000D55) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_PATH_CTL (0x00000D55) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL (0x00000D56) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL (0x00000D57) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL (0x00000D58) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL (0x00000D59) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL (0x00000D5A) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL (0x00000D5B) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL (0x00000D5C) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL (0x00000D5D) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_CTL (0x00000D5E) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL (0x00000D5F) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL (0x00000D60) +#define AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL (0x00000D61) +#define AQT1000_CDC_TOP_CDC_TOP_BASE (0x00000D81) +#define AQT1000_CDC_TOP_TOP_CFG0 (0x00000D81) +#define AQT1000_CDC_TOP_HPHL_COMP_WR_LSB (0x00000D89) +#define AQT1000_CDC_TOP_HPHL_COMP_WR_MSB (0x00000D8A) +#define AQT1000_CDC_TOP_HPHL_COMP_LUT (0x00000D8B) +#define AQT1000_CDC_TOP_HPHL_COMP_RD_LSB (0x00000D8C) +#define AQT1000_CDC_TOP_HPHL_COMP_RD_MSB (0x00000D8D) +#define AQT1000_CDC_TOP_HPHR_COMP_WR_LSB (0x00000D8E) +#define AQT1000_CDC_TOP_HPHR_COMP_WR_MSB (0x00000D8F) +#define AQT1000_CDC_TOP_HPHR_COMP_LUT (0x00000D90) +#define AQT1000_CDC_TOP_HPHR_COMP_RD_LSB (0x00000D91) +#define AQT1000_CDC_TOP_HPHR_COMP_RD_MSB (0x00000D92) +#define AQT1000_CDC_DSD0_BASE (0x00000DB1) +#define AQT1000_CDC_DSD0_PATH_CTL (0x00000DB1) +#define AQT1000_CDC_DSD0_CFG0 (0x00000DB2) +#define AQT1000_CDC_DSD0_CFG1 (0x00000DB3) +#define AQT1000_CDC_DSD0_CFG2 (0x00000DB4) +#define AQT1000_CDC_DSD0_CFG3 (0x00000DB5) +#define AQT1000_CDC_DSD0_CFG4 (0x00000DB6) +#define AQT1000_CDC_DSD0_CFG5 (0x00000DB7) +#define AQT1000_CDC_DSD1_BASE (0x00000DC1) +#define AQT1000_CDC_DSD1_PATH_CTL (0x00000DC1) +#define AQT1000_CDC_DSD1_CFG0 (0x00000DC2) +#define AQT1000_CDC_DSD1_CFG1 (0x00000DC3) +#define AQT1000_CDC_DSD1_CFG2 (0x00000DC4) +#define AQT1000_CDC_DSD1_CFG3 (0x00000DC5) +#define AQT1000_CDC_DSD1_CFG4 (0x00000DC6) +#define AQT1000_CDC_DSD1_CFG5 (0x00000DC7) +#define AQT1000_CDC_RX_IDLE_DET_CDC_RX_IDLE_DET_BASE (0x00000DD1) +#define AQT1000_CDC_RX_IDLE_DET_PATH_CTL (0x00000DD1) +#define AQT1000_CDC_RX_IDLE_DET_CFG0 (0x00000DD2) +#define AQT1000_CDC_RX_IDLE_DET_CFG1 (0x00000DD3) +#define AQT1000_CDC_RX_IDLE_DET_CFG2 (0x00000DD4) +#define AQT1000_CDC_RX_IDLE_DET_CFG3 (0x00000DD5) +#define AQT1000_CDC_DOP_DET_CDC_DOP_DET_BASE (0x00000DD9) +#define AQT1000_CDC_DOP_DET_CTL (0x00000DD9) +#define AQT1000_CDC_DOP_DET_CFG0 (0x00000DDA) +#define AQT1000_CDC_DOP_DET_CFG1 (0x00000DDB) +#define AQT1000_CDC_DOP_DET_CFG2 (0x00000DDC) +#define AQT1000_CDC_DOP_DET_CFG3 (0x00000DDD) +#define AQT1000_CDC_DOP_DET_CFG4 (0x00000DDE) +#define AQT1000_CDC_DOP_DET_STATUS0 (0x00000DE1) +#define AQT1000_PAGE15_BASE (0x00000F00) +#define AQT1000_PAGE15_PAGE_REGISTER (0x00000F00) +#define AQT1000_CDC_DEBUG_CDC_DEBUG_BASE (0x00000FA1) +#define AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG0 (0x00000FA1) +#define AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG1 (0x00000FA2) +#define AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG2 (0x00000FA3) +#define AQT1000_CDC_DEBUG_DSD0_DEBUG_CFG3 (0x00000FA4) +#define AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG0 (0x00000FA5) +#define AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG1 (0x00000FA6) +#define AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG2 (0x00000FA7) +#define AQT1000_CDC_DEBUG_DSD1_DEBUG_CFG3 (0x00000FA8) +#define AQT1000_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0 (0x00000FAB) +#define AQT1000_CDC_DEBUG_ANC0_RC0_FIFO_CTL (0x00000FAC) +#define AQT1000_CDC_DEBUG_ANC0_RC1_FIFO_CTL (0x00000FAD) +#define AQT1000_CDC_DEBUG_ANC1_RC0_FIFO_CTL (0x00000FAE) +#define AQT1000_CDC_DEBUG_ANC1_RC1_FIFO_CTL (0x00000FAF) +#define AQT1000_CDC_DEBUG_ANC_RC_RST_DBG_CNTR (0x00000FB0) +#define AQT1000_PAGE128_BASE (0x00008000) +#define AQT1000_PAGE128_PAGE_REGISTER (0x00008000) +#define AQT1000_TLMM_TLMM_BASE (0x00008001) +#define AQT1000_TLMM_SPI_CLK_PINCFG (0x00008001) +#define AQT1000_TLMM_SPI_MOSI_PINCFG (0x00008002) +#define AQT1000_TLMM_SPI_MISO_PINCFG (0x00008003) +#define AQT1000_TLMM_SPI_CS_N_PINCFG (0x00008004) +#define AQT1000_TLMM_GPIO1_PINCFG (0x00008005) +#define AQT1000_TLMM_GPIO2_PINCFG (0x00008006) +#define AQT1000_TLMM_GPIO3_PINCFG (0x00008007) +#define AQT1000_TLMM_GPIO4_PINCFG (0x00008008) +#define AQT1000_TLMM_GPIO5_PINCFG (0x00008009) +#define AQT1000_TLMM_GPIO6_PINCFG (0x0000800A) +#define AQT1000_TLMM_GPIO7_PINCFG (0x0000800B) +#define AQT1000_TLMM_GPIO8_PINCFG (0x0000800C) +#define AQT1000_TLMM_GPIO9_PINCFG (0x0000800D) +#define AQT1000_TLMM_GPIO10_PINCFG (0x0000800E) +#define AQT1000_PAD_CTRL_PAD_CTRL_BASE (0x00008031) +#define AQT1000_PAD_CTRL_PAD_PDN_CTRL_0 (0x00008031) +#define AQT1000_PAD_CTRL_PAD_PDN_CTRL_1 (0x00008032) +#define AQT1000_PAD_CTRL_PAD_PU_CTRL_0 (0x00008033) +#define AQT1000_PAD_CTRL_PAD_PU_CTRL_1 (0x00008034) +#define AQT1000_PAD_CTRL_GPIO_CTL_0_OE (0x00008036) +#define AQT1000_PAD_CTRL_GPIO_CTL_1_OE (0x00008037) +#define AQT1000_PAD_CTRL_GPIO_CTL_0_DATA (0x00008038) +#define AQT1000_PAD_CTRL_GPIO_CTL_1_DATA (0x00008039) +#define AQT1000_PAD_CTRL_PAD_DRVCTL (0x0000803A) +#define AQT1000_PAD_CTRL_PIN_STATUS (0x0000803B) +#define AQT1000_PAD_CTRL_MEM_CTRL (0x0000803C) +#define AQT1000_PAD_CTRL_PAD_INP_DISABLE_0 (0x0000803E) +#define AQT1000_PAD_CTRL_PAD_INP_DISABLE_1 (0x0000803F) +#define AQT1000_PAD_CTRL_PIN_CTL_OE_0 (0x00008040) +#define AQT1000_PAD_CTRL_PIN_CTL_OE_1 (0x00008041) +#define AQT1000_PAD_CTRL_PIN_CTL_DATA_0 (0x00008042) +#define AQT1000_PAD_CTRL_PIN_CTL_DATA_1 (0x00008043) +#define AQT1000_PAD_CTRL_USB_PHY_CLK_DIV (0x00008044) +#define AQT1000_PAD_CTRL_DEBUG_BUS_CDC (0x00008045) +#define AQT1000_PAD_CTRL_DEBUG_BUS_SEL (0x00008046) +#define AQT1000_PAD_CTRL_DEBUG_EN_1 (0x00008047) +#define AQT1000_PAD_CTRL_DEBUG_EN_2 (0x00008048) +#define AQT1000_PAD_CTRL_DEBUG_EN_3 (0x00008049) +#define AQT1000_PAD_CTRL_DEBUG_EN_4 (0x0000804A) +#define AQT1000_PAD_CTRL_DEBUG_EN_5 (0x0000804B) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_0 (0x0000804C) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_1 (0x0000804D) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_2 (0x0000804E) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_3 (0x0000804F) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_4 (0x00008050) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_5 (0x00008051) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_6 (0x00008052) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_7 (0x00008053) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_8 (0x00008054) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_9 (0x00008055) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_10 (0x00008056) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_11 (0x00008057) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_12 (0x00008058) +#define AQT1000_PAD_CTRL_DEBUG_MUX_BIT_13 (0x00008059) +#define AQT1000_PAD_CTRL_DEBUG_READ_0 (0x0000805A) +#define AQT1000_PAD_CTRL_DEBUG_READ_1 (0x0000805B) +#define AQT1000_PAD_CTRL_DEBUG_READ_2 (0x0000805C) +#define AQT1000_PAD_CTRL_DEBUG_READ_3 (0x0000805D) +#define AQT1000_PAD_CTRL_FPGA_CTL (0x00008061) +#define AQT1000_MAX_REGISTER (0x000080FF) + +#endif /*_AQT_REGISTERS_H*/ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-regmap.c new file mode 100644 index 0000000000..31002fa9e2 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-regmap.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "aqt1000-registers.h" +#include "aqt1000-reg-defaults.h" +#include "aqt1000-internal.h" + +static bool aqt1000_is_readable_register(struct device *dev, unsigned int reg) +{ + u8 pg_num, reg_offset; + const u8 *reg_tbl = NULL; + + /* + * Get the page number from MSB of codec register. If its 0x80, assign + * the corresponding page index PAGE_0x80. + */ + pg_num = reg >> 0x8; + if (pg_num == 0x80) + pg_num = AQT1000_PAGE_128; + else if (pg_num > 15) + return false; + + reg_tbl = aqt1000_reg[pg_num]; + reg_offset = reg & 0xFF; + + if (reg_tbl && reg_tbl[reg_offset]) + return true; + else + return false; +} + +static bool aqt1000_is_volatile_register(struct device *dev, unsigned int reg) +{ + u8 pg_num, reg_offset; + const u8 *reg_tbl = NULL; + + pg_num = reg >> 0x8; + if (pg_num == 0x80) + pg_num = AQT1000_PAGE_128; + else if (pg_num > 15) + return false; + + reg_tbl = aqt1000_reg[pg_num]; + reg_offset = reg & 0xFF; + + if (reg_tbl && reg_tbl[reg_offset] == AQT1000_RO) + return true; + + /* IIR Coeff registers are not cacheable */ + if ((reg >= AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL) && + (reg <= AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)) + return true; + + if ((reg >= AQT1000_CDC_ANC0_IIR_COEFF_1_CTL) && + (reg <= AQT1000_CDC_ANC0_FB_GAIN_CTL)) + return true; + + if ((reg >= AQT1000_CDC_ANC1_IIR_COEFF_1_CTL) && + (reg <= AQT1000_CDC_ANC1_FB_GAIN_CTL)) + return true; + + /* + * Need to mark volatile for registers that are writable but + * only few bits are read-only + */ + switch (reg) { + case AQT1000_BUCK_5V_CTRL_CCL_1: + case AQT1000_BIAS_CCOMP_FINE_ADJ: + case AQT1000_ANA_BIAS: + case AQT1000_BUCK_5V_IBIAS_CTL_4: + case AQT1000_BUCK_5V_CTRL_CCL_2: + case AQT1000_CHIP_CFG0_RST_CTL: + case AQT1000_CHIP_CFG0_CLK_CTL_CDC_DIG: + case AQT1000_CHIP_CFG0_CLK_CFG_MCLK: + case AQT1000_CHIP_CFG0_EFUSE_CTL: + case AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL: + case AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL: + case AQT1000_ANA_RX_SUPPLIES: + case AQT1000_ANA_MBHC_MECH: + case AQT1000_ANA_MBHC_ELECT: + case AQT1000_ANA_MBHC_ZDET: + case AQT1000_ANA_MICB1: + case AQT1000_BUCK_5V_EN_CTL: + return true; + } + + return false; +} + +struct regmap_config aqt1000_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = aqt1000_defaults, + .num_reg_defaults = ARRAY_SIZE(aqt1000_defaults), + .max_register = AQT1000_MAX_REGISTER, + .volatile_reg = aqt1000_is_volatile_register, + .readable_reg = aqt1000_is_readable_register, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-routing.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-routing.h new file mode 100644 index 0000000000..876f62278b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-routing.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ +#ifndef AQT1000_ROUTING_H +#define AQT1000_ROUTING_H + +#include + +const struct snd_soc_dapm_route aqt_audio_map[] = { + + /* CDC Tx interface */ + + {"AQT AIF1 CAP", NULL, "AQT AIF1 CAP Mixer"}, + {"AQT AIF1 CAP Mixer", "TX0", "AQT TX0_MUX"}, + {"AQT AIF1 CAP Mixer", "TX1", "AQT TX1_MUX"}, + + {"AQT TX0_MUX", "DEC_L", "AQT ADC0 MUX"}, + {"AQT TX0_MUX", "DEC_R", "AQT ADC1 MUX"}, + {"AQT TX0_MUX", "DEC_V", "AQT ADC2 MUX"}, + + {"AQT TX1_MUX", "DEC_L", "AQT ADC0 MUX"}, + {"AQT TX1_MUX", "DEC_R", "AQT ADC1 MUX"}, + {"AQT TX1_MUX", "DEC_V", "AQT ADC2 MUX"}, + + {"AQT ADC0 MUX", "AMIC", "AQT AMIC0_MUX"}, + {"AQT ADC0 MUX", "ANC_FB0", "AQT ANC_FB_TUNE0"}, + {"AQT ADC0 MUX", "ANC_FB1", "AQT ANC_FB_TUNE1"}, + + {"AQT ADC1 MUX", "AMIC", "AQT AMIC1_MUX"}, + {"AQT ADC1 MUX", "ANC_FB0", "AQT ANC_FB_TUNE0"}, + {"AQT ADC1 MUX", "ANC_FB1", "AQT ANC_FB_TUNE1"}, + + {"AQT ADC2 MUX", "AMIC", "AQT AMIC2_MUX"}, + {"AQT ADC2 MUX", "ANC_FB0", "AQT ANC_FB_TUNE0"}, + {"AQT ADC2 MUX", "ANC_FB1", "AQT ANC_FB_TUNE1"}, + + {"AQT AMIC0_MUX", "ADC_L", "AQT ADC_L"}, + {"AQT AMIC0_MUX", "ADC_R", "AQT ADC_R"}, + {"AQT AMIC0_MUX", "ADC_V", "AQT ADC_V"}, + + {"AQT AMIC1_MUX", "ADC_L", "AQT ADC_L"}, + {"AQT AMIC1_MUX", "ADC_R", "AQT ADC_R"}, + {"AQT AMIC1_MUX", "ADC_V", "AQT ADC_V"}, + + {"AQT AMIC2_MUX", "ADC_L", "AQT ADC_L"}, + {"AQT AMIC2_MUX", "ADC_R", "AQT ADC_R"}, + {"AQT AMIC2_MUX", "ADC_V", "AQT ADC_V"}, + + {"AQT ADC_L", NULL, "AQT AMIC1"}, + {"AQT ADC_R", NULL, "AQT AMIC2"}, + {"AQT ADC_V", NULL, "AQT AMIC3"}, + + {"AQT AMIC10_MUX", "ADC_L", "AQT ADC_L"}, + {"AQT AMIC10_MUX", "ADC_R", "AQT ADC_R"}, + {"AQT AMIC10_MUX", "ADC_V", "AQT ADC_V"}, + + {"AQT AMIC11_MUX", "ADC_L", "AQT ADC_L"}, + {"AQT AMIC11_MUX", "ADC_R", "AQT ADC_R"}, + {"AQT AMIC11_MUX", "ADC_V", "AQT ADC_V"}, + + {"AQT AMIC12_MUX", "ADC_L", "AQT ADC_L"}, + {"AQT AMIC12_MUX", "ADC_R", "AQT ADC_R"}, + {"AQT AMIC12_MUX", "ADC_V", "AQT ADC_V"}, + + {"AQT AMIC13_MUX", "ADC_L", "AQT ADC_L"}, + {"AQT AMIC13_MUX", "ADC_R", "AQT ADC_R"}, + {"AQT AMIC13_MUX", "ADC_V", "AQT ADC_V"}, + + {"AQT ANC OUT HPHL Enable", "Switch", "AQT AMIC10_MUX"}, + {"AQT ANC OUT HPHL Enable", "Switch", "AQT AMIC11_MUX"}, + {"AQT ANC OUT HPHR Enable", "Switch", "AQT AMIC12_MUX"}, + {"AQT ANC OUT HPHR Enable", "Switch", "AQT AMIC13_MUX"}, + + {"AQT RX INT1 MIX2", NULL, "AQT ANC OUT HPHL Enable"}, + {"AQT RX INT2 MIX2", NULL, "AQT ANC OUT HPHR Enable"}, + + {"AQT ANC0 FB MUX", "ANC_IN_HPHL", "AQT RX INT1 MIX2"}, + {"AQT ANC1 FB MUX", "ANC_IN_HPHR", "AQT RX INT2 MIX2"}, + + {"AQT I2S_L RX", NULL, "AQT AIF1 PB"}, + {"AQT I2S_R RX", NULL, "AQT AIF1 PB"}, + + {"AQT RX INT1_1 MUX", "I2S0_L", "AQT I2S_L RX"}, + {"AQT RX INT1_1 MUX", "I2S0_R", "AQT I2S_R RX"}, + {"AQT RX INT1_1 MUX", "DEC_L", "AQT ADC0 MUX"}, + {"AQT RX INT1_1 MUX", "DEC_R", "AQT ADC1 MUX"}, + {"AQT RX INT1_1 MUX", "DEC_V", "AQT ADC2 MUX"}, + + {"AQT RX INT2_1 MUX", "I2S0_L", "AQT I2S_L RX"}, + {"AQT RX INT2_1 MUX", "I2S0_R", "AQT I2S_R RX"}, + {"AQT RX INT2_1 MUX", "DEC_L", "AQT ADC0 MUX"}, + {"AQT RX INT2_1 MUX", "DEC_R", "AQT ADC1 MUX"}, + {"AQT RX INT2_1 MUX", "DEC_V", "AQT ADC2 MUX"}, + + {"AQT RX INT1_2 MUX", "I2S0_L", "AQT I2S_L RX"}, + {"AQT RX INT1_2 MUX", "I2S0_R", "AQT I2S_R RX"}, + {"AQT RX INT1_2 MUX", "DEC_L", "AQT ADC0 MUX"}, + {"AQT RX INT1_2 MUX", "DEC_R", "AQT ADC1 MUX"}, + {"AQT RX INT1_2 MUX", "DEC_V", "AQT ADC2 MUX"}, + {"AQT RX INT1_2 MUX", "IIR0", "AQT IIR0"}, + + {"AQT RX INT2_2 MUX", "I2S0_L", "AQT I2S_L RX"}, + {"AQT RX INT2_2 MUX", "I2S0_R", "AQT I2S_R RX"}, + {"AQT RX INT2_2 MUX", "DEC_L", "AQT ADC0 MUX"}, + {"AQT RX INT2_2 MUX", "DEC_R", "AQT ADC1 MUX"}, + {"AQT RX INT2_2 MUX", "DEC_V", "AQT ADC2 MUX"}, + {"AQT RX INT2_2 MUX", "IIR0", "AQT IIR0"}, + + {"AQT RX INT1_1 INTERP", NULL, "AQT RX INT1_1 MUX"}, + {"AQT RX INT1 MIX1", NULL, "AQT RX INT1_1 INTERP"}, + {"AQT RX INT1 MIX2", NULL, "AQT RX INT1 MIX1"}, + + {"AQT RX INT1_2 INTERP", NULL, "AQT RX INT1_2 MUX"}, + {"AQT RX INT1 MIX1", NULL, "AQT RX INT1_2 INTERP"}, + + {"AQT ASRC0 MUX", "ASRC_IN_HPHL", "AQT RX INT1_2 INTERP"}, + {"AQT RX INT1 MIX1", "HPHL Switch", "AQT ASRC0 MUX"}, + + {"AQT RX INT2_1 INTERP", NULL, "AQT RX INT2_1 MUX"}, + {"AQT RX INT2 MIX1", NULL, "AQT RX INT2_1 INTERP"}, + {"AQT RX INT2 MIX2", NULL, "AQT RX INT2 MIX1"}, + + {"AQT RX INT2_2 INTERP", NULL, "AQT RX INT2_2 MUX"}, + {"AQT RX INT2 MIX1", NULL, "AQT RX INT2_2 INTERP"}, + + {"AQT ASRC1 MUX", "ASRC_IN_HPHR", "AQT RX INT2_2 INTERP"}, + {"AQT RX INT2 MIX1", "HPHR Switch", "AQT ASRC1 MUX"}, + + {"AQT RX INT1 DEM MUX", "CLSH_DSM_OUT", "AQT RX INT1 MIX2"}, + {"AQT RX INT1 DAC", NULL, "AQT RX INT1 DEM MUX"}, + {"AQT RX INT1 DAC", NULL, "AQT RX_BIAS"}, + {"AQT RX_BIAS", NULL, "AQT MCLK"}, + {"AQT MIC BIAS1", NULL, "AQT MCLK"}, + {"AQT HPHL PA", NULL, "AQT RX INT1 DAC"}, + {"AQT HPHL", NULL, "AQT HPHL PA"}, + + {"AQT RX INT2 DEM MUX", "CLSH_DSM_OUT", "AQT RX INT2 MIX2"}, + {"AQT RX INT2 DAC", NULL, "AQT RX INT2 DEM MUX"}, + {"AQT RX INT2 DAC", NULL, "AQT RX_BIAS"}, + {"AQT HPHR PA", NULL, "AQT RX INT2 DAC"}, + {"AQT HPHR", NULL, "AQT HPHR PA"}, + + {"AQT ANC HPHL PA", NULL, "AQT RX INT1 DAC"}, + {"AQT ANC HPHL", NULL, "AQT ANC HPHL PA"}, + + {"AQT ANC HPHR PA", NULL, "AQT RX INT2 DAC"}, + {"AQT ANC HPHR", NULL, "AQT ANC HPHR PA"}, + + {"AQT IIR0", NULL, "AQT ADC2 MUX"}, + {"AQT SRC0", NULL, "AQT IIR0"}, + {"AQT RX ST MUX", "SRC0", "AQT SRC0"}, + + {"AQT RX INT1 MIX2", NULL, "AQT RX ST MUX"}, + {"AQT RX INT2 MIX2", NULL, "AQT RX ST MUX"}, + + /* Native clk main path routing */ + {"AQT RX INT1_1 NATIVE MUX", "ON", "AQT RX INT1_1 MUX"}, + {"AQT RX INT1_1 INTERP", NULL, "AQT RX INT1_1 NATIVE MUX"}, + {"AQT RX INT1_1 NATIVE MUX", NULL, "AQT RX INT1 NATIVE SUPPLY"}, + + {"AQT RX INT2_1 NATIVE MUX", "ON", "AQT RX INT2_1 MUX"}, + {"AQT RX INT2_1 INTERP", NULL, "AQT RX INT2_1 NATIVE MUX"}, + {"AQT RX INT2_1 NATIVE MUX", NULL, "AQT RX INT2 NATIVE SUPPLY"}, +}; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-utils.c b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-utils.c new file mode 100644 index 0000000000..078be0b942 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-utils.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "aqt1000.h" +#include "aqt1000-utils.h" + +#define REG_BYTES 2 +#define VAL_BYTES 1 +/* + * Page Register Address that APP Proc uses to + * access codec registers is identified as 0x00 + */ +#define PAGE_REG_ADDR 0x00 + +static int aqt_page_write(struct aqt1000 *aqt, unsigned short *reg) +{ + int ret = 0; + unsigned short c_reg, reg_addr; + u8 pg_num, prev_pg_num; + + c_reg = *reg; + pg_num = c_reg >> 8; + reg_addr = c_reg & 0xff; + if (aqt->prev_pg_valid) { + prev_pg_num = aqt->prev_pg; + if (prev_pg_num != pg_num) { + ret = aqt->write_dev( + aqt, PAGE_REG_ADDR, + (void *) &pg_num, 1); + if (ret < 0) + dev_err(aqt->dev, + "%s: page write error, pg_num: 0x%x\n", + __func__, pg_num); + else { + aqt->prev_pg = pg_num; + dev_dbg(aqt->dev, "%s: Page 0x%x Write to 0x00\n", + __func__, pg_num); + } + } + } else { + ret = aqt->write_dev( + aqt, PAGE_REG_ADDR, (void *) &pg_num, 1); + if (ret < 0) + dev_err(aqt->dev, + "%s: page write error, pg_num: 0x%x\n", + __func__, pg_num); + else { + aqt->prev_pg = pg_num; + aqt->prev_pg_valid = true; + dev_dbg(aqt->dev, "%s: Page 0x%x Write to 0x00\n", + __func__, pg_num); + } + } + *reg = reg_addr; + return ret; +} + +static int regmap_bus_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct aqt1000 *aqt = dev_get_drvdata(dev); + unsigned short c_reg, rreg; + int ret, i; + + if (!aqt) { + dev_err(dev, "%s: aqt is NULL\n", __func__); + return -EINVAL; + } + if (!reg || !val) { + dev_err(dev, "%s: reg or val is NULL\n", __func__); + return -EINVAL; + } + + if (reg_size != REG_BYTES) { + dev_err(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return -EINVAL; + } + + mutex_lock(&aqt->io_lock); + c_reg = *(u16 *)reg; + rreg = c_reg; + + ret = aqt_page_write(aqt, &c_reg); + if (ret) + goto err; + ret = aqt->read_dev(aqt, c_reg, val, val_size); + if (ret < 0) + dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n", + __func__, ret, rreg, val_size); + else { + for (i = 0; i < val_size; i++) + dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n", + __func__, ((u8 *)val)[i], rreg + i); + } +err: + mutex_unlock(&aqt->io_lock); + return ret; +} + +static int regmap_bus_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) +{ + struct device *dev = context; + struct aqt1000 *aqt = dev_get_drvdata(dev); + unsigned short c_reg, rreg; + int ret, i; + + if (!aqt) { + dev_err(dev, "%s: aqt is NULL\n", __func__); + return -EINVAL; + } + if (!reg || !val) { + dev_err(dev, "%s: reg or val is NULL\n", __func__); + return -EINVAL; + } + if (reg_size != REG_BYTES) { + dev_err(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return -EINVAL; + } + mutex_lock(&aqt->io_lock); + c_reg = *(u16 *)reg; + rreg = c_reg; + + ret = aqt_page_write(aqt, &c_reg); + if (ret) + goto err; + + for (i = 0; i < val_size; i++) + dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i], + rreg + i); + + ret = aqt->write_dev(aqt, c_reg, (void *) val, val_size); + if (ret < 0) + dev_err(dev, "%s: Codec write failed (%d), reg:0x%x, size:%zd\n", + __func__, ret, rreg, val_size); + +err: + mutex_unlock(&aqt->io_lock); + return ret; +} + +static int regmap_bus_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct aqt1000 *aqt = dev_get_drvdata(dev); + + if (!aqt) + return -EINVAL; + + WARN_ON(count < REG_BYTES); + + return regmap_bus_gather_write(context, data, REG_BYTES, + data + REG_BYTES, + count - REG_BYTES); +} + +static struct regmap_bus regmap_bus_config = { + .write = regmap_bus_write, + .gather_write = regmap_bus_gather_write, + .read = regmap_bus_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +/* + * aqt1000_regmap_init: + * Initialize aqt1000 register map + * + * @dev: pointer to wcd device + * @config: pointer to register map config + * + * Returns pointer to regmap structure for success + * or NULL in case of failure. + */ +struct regmap *aqt1000_regmap_init(struct device *dev, + const struct regmap_config *config) +{ + return devm_regmap_init(dev, ®map_bus_config, dev, config); +} +EXPORT_SYMBOL(aqt1000_regmap_init); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-utils.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-utils.h new file mode 100644 index 0000000000..72c8fcf396 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000-utils.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD9XXX_UTILS_H__ +#define __WCD9XXX_UTILS_H__ + +#include +#include +#include + +struct regmap *aqt1000_regmap_init(struct device *dev, + const struct regmap_config *config); +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000.c b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000.c new file mode 100644 index 0000000000..a92a1541c4 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000.c @@ -0,0 +1,3611 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include "aqt1000-registers.h" +#include "aqt1000.h" +#include "aqt1000-api.h" +#include "aqt1000-mbhc.h" +#include "aqt1000-routing.h" +#include "aqt1000-internal.h" + +#define DRV_NAME "aqt_codec" + +#define AQT1000_TX_UNMUTE_DELAY_MS 40 +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define AQT_VERSION_ENTRY_SIZE 17 +#define AQT_VOUT_CTL_TO_MICB(x) (1000 + x *50) + +static struct interp_sample_rate sr_val_tbl[] = { + {8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5}, + {192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA}, + {176400, 0xB}, {352800, 0xC}, +}; + +static int tx_unmute_delay = AQT1000_TX_UNMUTE_DELAY_MS; +module_param(tx_unmute_delay, int, 0664); +MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path"); + +static void aqt_codec_set_tx_hold(struct snd_soc_component *, u16, bool); + +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static const char * const rx_cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ", + "CF_NEG_3DB_0P48HZ" +}; + +struct aqt1000_anc_header { + u32 reserved[3]; + u32 num_anc_slots; +}; + +static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, AQT1000_CDC_TX0_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, AQT1000_CDC_TX1_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec2_enum, AQT1000_CDC_TX2_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int1_1_enum, AQT1000_CDC_RX1_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, AQT1000_CDC_RX1_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int2_1_enum, AQT1000_CDC_RX2_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, AQT1000_CDC_RX2_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const DECLARE_TLV_DB_SCALE(hph_gain, -3000, 150, 0); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +static int aqt_get_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = aqt->anc_slot; + return 0; +} + +static int aqt_put_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + aqt->anc_slot = ucontrol->value.integer.value[0]; + return 0; +} + +static int aqt_get_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (aqt->anc_func == true ? 1 : 0); + return 0; +} + +static int aqt_put_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + + mutex_lock(&aqt->codec_mutex); + aqt->anc_func = (!ucontrol->value.integer.value[0] ? false : true); + dev_dbg(component->dev, "%s: anc_func %x", __func__, aqt->anc_func); + + if (aqt->anc_func == true) { + snd_soc_dapm_enable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_disable_pin(dapm, "HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "HPHL"); + snd_soc_dapm_disable_pin(dapm, "HPHR"); + } else { + snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_enable_pin(dapm, "HPHL"); + snd_soc_dapm_enable_pin(dapm, "HPHR"); + snd_soc_dapm_enable_pin(dapm, "HPHL PA"); + snd_soc_dapm_enable_pin(dapm, "HPHR PA"); + } + mutex_unlock(&aqt->codec_mutex); + + snd_soc_dapm_sync(dapm); + return 0; +} + +static const char *const aqt_anc_func_text[] = {"OFF", "ON"}; +static const struct soc_enum aqt_anc_func_enum = + SOC_ENUM_SINGLE_EXT(2, aqt_anc_func_text); + +static int aqt_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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = aqt->hph_mode; + return 0; +} + +static int aqt_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 aqt1000 *aqt = 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_warn(component->dev, "%s:Invalid HPH Mode, default to Cls-H LOHiFi\n", + __func__); + mode_val = CLS_H_LOHIFI; + } + aqt->hph_mode = mode_val; + return 0; +} + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", + "CLS_H_ULP", "CLS_AB_HIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static int aqt_iir_enable_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = (snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_CTL) & + (1 << band_idx)) != 0; + + dev_dbg(component->dev, "%s: IIR0 band #%d enable %d\n", __func__, + band_idx, (uint32_t)ucontrol->value.integer.value[0]); + + return 0; +} + +static int aqt_iir_enable_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + bool iir_band_en_status; + int value = ucontrol->value.integer.value[0]; + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_component_update_bits(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_CTL, + (1 << band_idx), (value << band_idx)); + + iir_band_en_status = ((snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_CTL) & + (1 << band_idx)) != 0); + dev_dbg(component->dev, "%s: IIR0 band #%d enable %d\n", __func__, + band_idx, iir_band_en_status); + + return 0; +} + +static uint32_t aqt_get_iir_band_coeff(struct snd_soc_component *component, + int band_idx, int coeff_idx) +{ + uint32_t value = 0; + + /* Address does not automatically update if reading */ + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL); + + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL) << 8); + + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL) << 16); + + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL) + & 0x3F) << 24); + + return value; +} + +static int aqt_iir_band_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = + aqt_get_iir_band_coeff(component, band_idx, 0); + ucontrol->value.integer.value[1] = + aqt_get_iir_band_coeff(component, band_idx, 1); + ucontrol->value.integer.value[2] = + aqt_get_iir_band_coeff(component, band_idx, 2); + ucontrol->value.integer.value[3] = + aqt_get_iir_band_coeff(component, band_idx, 3); + ucontrol->value.integer.value[4] = + aqt_get_iir_band_coeff(component, band_idx, 4); + + dev_dbg(component->dev, "%s: IIR band #%d b0 = 0x%x\n" + "%s: IIR band #%d b1 = 0x%x\n" + "%s: IIR band #%d b2 = 0x%x\n" + "%s: IIR band #%d a1 = 0x%x\n" + "%s: IIR band #%d a2 = 0x%x\n", + __func__, band_idx, + (uint32_t)ucontrol->value.integer.value[0], + __func__, band_idx, + (uint32_t)ucontrol->value.integer.value[1], + __func__, band_idx, + (uint32_t)ucontrol->value.integer.value[2], + __func__, band_idx, + (uint32_t)ucontrol->value.integer.value[3], + __func__, band_idx, + (uint32_t)ucontrol->value.integer.value[4]); + + return 0; +} + +static void aqt_set_iir_band_coeff(struct snd_soc_component *component, + int band_idx, uint32_t value) +{ + snd_soc_component_write(component, + (AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL), + (value & 0xFF)); + + snd_soc_component_write(component, + (AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL), + (value >> 8) & 0xFF); + + snd_soc_component_write(component, + (AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_component_write(component, + (AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL), + (value >> 24) & 0x3F); +} + +static int aqt_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int coeff_idx; + + /* + * Mask top bit it is reserved + * Updates addr automatically for each B2 write + */ + snd_soc_component_write(component, + (AQT1000_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + for (coeff_idx = 0; coeff_idx < AQT1000_CDC_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + aqt_set_iir_band_coeff(component, band_idx, + ucontrol->value.integer.value[coeff_idx]); + } + + dev_dbg(component->dev, "%s: IIR band #%d b0 = 0x%x\n" + "%s: IIR band #%d b1 = 0x%x\n" + "%s: IIR band #%d b2 = 0x%x\n" + "%s: IIR band #%d a1 = 0x%x\n" + "%s: IIR band #%d a2 = 0x%x\n", + __func__, band_idx, + aqt_get_iir_band_coeff(component, band_idx, 0), + __func__, band_idx, + aqt_get_iir_band_coeff(component, band_idx, 1), + __func__, band_idx, + aqt_get_iir_band_coeff(component, band_idx, 2), + __func__, band_idx, + aqt_get_iir_band_coeff(component, band_idx, 3), + __func__, band_idx, + aqt_get_iir_band_coeff(component, band_idx, 4)); + + return 0; +} + +static int aqt_compander_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = aqt->comp_enabled[comp]; + return 0; +} + +static int aqt_compander_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, aqt->comp_enabled[comp], value); + aqt->comp_enabled[comp] = value; + + /* Any specific register configuration for compander */ + switch (comp) { + case COMPANDER_1: + /* Set Gain Source Select based on compander enable/disable */ + snd_soc_component_update_bits(component, + AQT1000_HPH_L_EN, 0x20, + (value ? 0x00 : 0x20)); + break; + case COMPANDER_2: + snd_soc_component_update_bits(component, + AQT1000_HPH_R_EN, 0x20, + (value ? 0x00 : 0x20)); + break; + default: + /* + * if compander is not enabled for any interpolator, + * it does not cause any audio failure, so do not + * return error in this case, but just print a log + */ + dev_warn(component->dev, "%s: unknown compander: %d\n", + __func__, comp); + }; + return 0; +} + +static int aqt_hph_asrc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int index = -EINVAL; + + if (!strcmp(kcontrol->id.name, "AQT ASRC0 Output Mode")) + index = ASRC0; + if (!strcmp(kcontrol->id.name, "AQT ASRC1 Output Mode")) + index = ASRC1; + + if (aqt && (index >= 0) && (index < ASRC_MAX)) + aqt->asrc_output_mode[index] = + ucontrol->value.integer.value[0]; + + return 0; +} + +static int aqt_hph_asrc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int val = 0; + int index = -EINVAL; + + if (!strcmp(kcontrol->id.name, "AQT ASRC0 Output Mode")) + index = ASRC0; + if (!strcmp(kcontrol->id.name, "AQT ASRC1 Output Mode")) + index = ASRC1; + + if (aqt && (index >= 0) && (index < ASRC_MAX)) + val = aqt->asrc_output_mode[index]; + + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static const char * const asrc_mode_text[] = { + "INT", "FRAC" +}; +static SOC_ENUM_SINGLE_EXT_DECL(asrc_mode_enum, asrc_mode_text); + +static int aqt_hph_idle_detect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int val = 0; + + if (aqt) + val = aqt->idle_det_cfg.hph_idle_detect_en; + + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int aqt_hph_idle_detect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + if (aqt) + aqt->idle_det_cfg.hph_idle_detect_en = + ucontrol->value.integer.value[0]; + + return 0; +} + +static const char * const hph_idle_detect_text[] = { + "OFF", "ON" +}; + +static SOC_ENUM_SINGLE_EXT_DECL(hph_idle_detect_enum, hph_idle_detect_text); + +static int aqt_amic_pwr_lvl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u16 amic_reg = 0; + + if (!strcmp(kcontrol->id.name, "AQT AMIC_1_2 PWR MODE")) + amic_reg = AQT1000_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AQT AMIC_3 PWR MODE")) + amic_reg = AQT1000_ANA_AMIC3; + + if (amic_reg) + ucontrol->value.integer.value[0] = + (snd_soc_component_read32(component, amic_reg) & + AQT1000_AMIC_PWR_LVL_MASK) >> + AQT1000_AMIC_PWR_LVL_SHIFT; + return 0; +} + +static int aqt_amic_pwr_lvl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 mode_val; + u16 amic_reg = 0; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: mode: %d\n", __func__, mode_val); + + if (!strcmp(kcontrol->id.name, "AQT AMIC_1_2 PWR MODE")) + amic_reg = AQT1000_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AQT AMIC_3 PWR MODE")) + amic_reg = AQT1000_ANA_AMIC3; + + if (amic_reg) + snd_soc_component_update_bits(component, amic_reg, + AQT1000_AMIC_PWR_LVL_MASK, + mode_val << AQT1000_AMIC_PWR_LVL_SHIFT); + return 0; +} + +static const char * const amic_pwr_lvl_text[] = { + "LOW_PWR", "DEFAULT", "HIGH_PERF", "HYBRID" +}; + +static SOC_ENUM_SINGLE_EXT_DECL(amic_pwr_lvl_enum, amic_pwr_lvl_text); + +static const struct snd_kcontrol_new aqt_snd_controls[] = { + SOC_SINGLE_TLV("AQT HPHL Volume", AQT1000_HPH_L_EN, 0, 24, 1, hph_gain), + SOC_SINGLE_TLV("AQT HPHR Volume", AQT1000_HPH_R_EN, 0, 24, 1, hph_gain), + SOC_SINGLE_TLV("AQT ADC1 Volume", AQT1000_ANA_AMIC1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("AQT ADC2 Volume", AQT1000_ANA_AMIC2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("AQT ADC3 Volume", AQT1000_ANA_AMIC3, 0, 20, 0, + analog_gain), + + SOC_SINGLE_SX_TLV("AQT RX1 Digital Volume", AQT1000_CDC_RX1_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("AQT RX2 Digital Volume", AQT1000_CDC_RX2_RX_VOL_CTL, + 0, -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("AQT DEC0 Volume", AQT1000_CDC_TX0_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("AQT DEC1 Volume", AQT1000_CDC_TX1_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("AQT DEC2 Volume", AQT1000_CDC_TX2_TX_VOL_CTL, 0, + -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("AQT IIR0 INP0 Volume", + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("AQT IIR0 INP1 Volume", + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("AQT IIR0 INP2 Volume", + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("AQT IIR0 INP3 Volume", + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_EXT("AQT ANC Slot", SND_SOC_NOPM, 0, 100, 0, + aqt_get_anc_slot, aqt_put_anc_slot), + SOC_ENUM_EXT("AQT ANC Function", aqt_anc_func_enum, aqt_get_anc_func, + aqt_put_anc_func), + + SOC_ENUM("AQT TX0 HPF cut off", cf_dec0_enum), + SOC_ENUM("AQT TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("AQT TX2 HPF cut off", cf_dec2_enum), + + SOC_ENUM("AQT RX INT1_1 HPF cut off", cf_int1_1_enum), + SOC_ENUM("AQT RX INT1_2 HPF cut off", cf_int1_2_enum), + SOC_ENUM("AQT RX INT2_1 HPF cut off", cf_int2_1_enum), + SOC_ENUM("AQT RX INT2_2 HPF cut off", cf_int2_2_enum), + + SOC_ENUM_EXT("AQT RX HPH Mode", rx_hph_mode_mux_enum, + aqt_rx_hph_mode_get, aqt_rx_hph_mode_put), + + SOC_SINGLE_EXT("AQT IIR0 Enable Band1", IIR0, BAND1, 1, 0, + aqt_iir_enable_audio_mixer_get, + aqt_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("AQT IIR0 Enable Band2", IIR0, BAND2, 1, 0, + aqt_iir_enable_audio_mixer_get, + aqt_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("AQT IIR0 Enable Band3", IIR0, BAND3, 1, 0, + aqt_iir_enable_audio_mixer_get, + aqt_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("AQT IIR0 Enable Band4", IIR0, BAND4, 1, 0, + aqt_iir_enable_audio_mixer_get, + aqt_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("AQT IIR0 Enable Band5", IIR0, BAND5, 1, 0, + aqt_iir_enable_audio_mixer_get, + aqt_iir_enable_audio_mixer_put), + + SOC_SINGLE_MULTI_EXT("AQT IIR0 Band1", IIR0, BAND1, 255, 0, 5, + aqt_iir_band_audio_mixer_get, aqt_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("AQT IIR0 Band2", IIR0, BAND2, 255, 0, 5, + aqt_iir_band_audio_mixer_get, aqt_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("AQT IIR0 Band3", IIR0, BAND3, 255, 0, 5, + aqt_iir_band_audio_mixer_get, aqt_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("AQT IIR0 Band4", IIR0, BAND4, 255, 0, 5, + aqt_iir_band_audio_mixer_get, aqt_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("AQT IIR0 Band5", IIR0, BAND5, 255, 0, 5, + aqt_iir_band_audio_mixer_get, aqt_iir_band_audio_mixer_put), + + SOC_SINGLE_EXT("AQT COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0, + aqt_compander_get, aqt_compander_put), + SOC_SINGLE_EXT("AQT COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0, + aqt_compander_get, aqt_compander_put), + + SOC_ENUM_EXT("AQT ASRC0 Output Mode", asrc_mode_enum, + aqt_hph_asrc_mode_get, aqt_hph_asrc_mode_put), + SOC_ENUM_EXT("AQT ASRC1 Output Mode", asrc_mode_enum, + aqt_hph_asrc_mode_get, aqt_hph_asrc_mode_put), + + SOC_ENUM_EXT("AQT HPH Idle Detect", hph_idle_detect_enum, + aqt_hph_idle_detect_get, aqt_hph_idle_detect_put), + + SOC_ENUM_EXT("AQT AMIC_1_2 PWR MODE", amic_pwr_lvl_enum, + aqt_amic_pwr_lvl_get, aqt_amic_pwr_lvl_put), + SOC_ENUM_EXT("AQT AMIC_3 PWR MODE", amic_pwr_lvl_enum, + aqt_amic_pwr_lvl_get, aqt_amic_pwr_lvl_put), +}; + +static int aqt_codec_enable_rx_bias(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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aqt->rx_bias_count++; + if (aqt->rx_bias_count == 1) { + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + 0x01, 0x01); + } + break; + case SND_SOC_DAPM_POST_PMD: + aqt->rx_bias_count--; + if (!aqt->rx_bias_count) + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, + 0x01, 0x00); + break; + }; + dev_dbg(component->dev, "%s: Current RX BIAS user count: %d\n", + __func__, aqt->rx_bias_count); + + return 0; +} + +/* + * aqt_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 aqt_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct aqt1000 *aqt; + int cur_vout_ctl, req_vout_ctl; + int micb_reg, micb_val, micb_en; + int ret = 0; + + if (!component) { + pr_err("%s: Invalid component pointer\n", __func__); + return -EINVAL; + } + + if (micb_num != MIC_BIAS_1) + return -EINVAL; + else + micb_reg = AQT1000_ANA_MICB1; + + aqt = snd_soc_component_get_drvdata(component); + mutex_lock(&aqt->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 = aqt_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, AQT_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(&aqt->micb_lock); + + return ret; +} +EXPORT_SYMBOL(aqt_mbhc_micb_adjust_voltage); + +/* + * aqt_micbias_control: enable/disable micbias + * @component: handle to snd_soc_component * + * @micb_num: micbias to be enabled/disabled, e.g. micbias1 or micbias2 + * @req: control requested, enable/disable or pullup enable/disable + * @is_dapm: triggered by dapm or not + * + * return 0 if control is success or error code in case of failure + */ +int aqt_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + 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; + int ret = 0; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = AQT1000_ANA_MICB1; + pre_off_event = AQT_EVENT_PRE_MICBIAS_1_OFF; + post_off_event = AQT_EVENT_POST_MICBIAS_1_OFF; + post_on_event = AQT_EVENT_POST_MICBIAS_1_ON; + post_dapm_on = AQT_EVENT_POST_DAPM_MICBIAS_1_ON; + post_dapm_off = AQT_EVENT_POST_DAPM_MICBIAS_1_OFF; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + mutex_lock(&aqt->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + aqt->pullup_ref++; + if ((aqt->pullup_ref == 1) && + (aqt->micb_ref == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + if (aqt->pullup_ref > 0) + aqt->pullup_ref--; + if ((aqt->pullup_ref == 0) && + (aqt->micb_ref == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + aqt->micb_ref++; + if (aqt->micb_ref == 1) { + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x40); + if (post_on_event && aqt->mbhc) + blocking_notifier_call_chain( + &aqt->mbhc->notifier, + post_on_event, + &aqt->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_on && aqt->mbhc) + blocking_notifier_call_chain(&aqt->mbhc->notifier, + post_dapm_on, &aqt->mbhc->wcd_mbhc); + break; + case MICB_DISABLE: + if (aqt->micb_ref > 0) + aqt->micb_ref--; + if ((aqt->micb_ref == 0) && + (aqt->pullup_ref > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((aqt->micb_ref == 0) && + (aqt->pullup_ref == 0)) { + if (pre_off_event && aqt->mbhc) + blocking_notifier_call_chain( + &aqt->mbhc->notifier, + pre_off_event, + &aqt->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + if (post_off_event && aqt->mbhc) + blocking_notifier_call_chain( + &aqt->mbhc->notifier, + post_off_event, + &aqt->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_off && aqt->mbhc) + blocking_notifier_call_chain(&aqt->mbhc->notifier, + post_dapm_off, &aqt->mbhc->wcd_mbhc); + break; + default: + dev_err(component->dev, "%s: Invalid micbias request: %d\n", + __func__, req); + ret = -EINVAL; + break; + }; + + if (!ret) + dev_dbg(component->dev, + "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, aqt->micb_ref, aqt->pullup_ref); + + mutex_unlock(&aqt->micb_lock); + + return ret; +} +EXPORT_SYMBOL(aqt_micbias_control); + +static int __aqt_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, "AQT MIC BIAS1", sizeof("AQT MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * MIC BIAS can also be requested by MBHC, + * so use ref count to handle micbias pullup + * and enable requests + */ + aqt_micbias_control(component, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* wait for cnp time */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + aqt_micbias_control(component, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int aqt_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return __aqt_codec_enable_micbias(w, event); +} + +static int aqt_codec_enable_i2s_block(struct snd_soc_component *component) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + mutex_lock(&aqt->i2s_lock); + if (++aqt->i2s_users == 1) + snd_soc_component_update_bits(component, AQT1000_I2S_I2S_0_CTL, + 0x01, 0x01); + mutex_unlock(&aqt->i2s_lock); + + return 0; +} + +static int aqt_codec_disable_i2s_block(struct snd_soc_component *component) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + mutex_lock(&aqt->i2s_lock); + if (--aqt->i2s_users == 0) + snd_soc_component_update_bits(component, AQT1000_I2S_I2S_0_CTL, + 0x01, 0x00); + + if (aqt->i2s_users < 0) + dev_warn(component->dev, "%s: i2s_users count (%d) < 0\n", + __func__, aqt->i2s_users); + mutex_unlock(&aqt->i2s_lock); + + return 0; +} + +static int aqt_codec_enable_i2s_tx(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aqt_codec_enable_i2s_block(component); + break; + case SND_SOC_DAPM_POST_PMD: + aqt_codec_disable_i2s_block(component); + break; + } + dev_dbg(component->dev, "%s: event: %d\n", __func__, event); + + return 0; +} + +static int aqt_codec_enable_i2s_rx(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aqt_codec_enable_i2s_block(component); + break; + case SND_SOC_DAPM_POST_PMD: + aqt_codec_disable_i2s_block(component); + break; + } + dev_dbg(component->dev, "%s: event: %d\n", __func__, event); + + return 0; +} + +static const char * const tx_mux_text[] = { + "ZERO", "DEC_L", "DEC_R", "DEC_V", +}; +AQT_DAPM_ENUM(tx0, AQT1000_CDC_IF_ROUTER_TX_MUX_CFG0, 0, tx_mux_text); +AQT_DAPM_ENUM(tx1, AQT1000_CDC_IF_ROUTER_TX_MUX_CFG0, 2, tx_mux_text); + +static const char * const tx_adc_mux_text[] = { + "AMIC", "ANC_FB0", "ANC_FB1", +}; +AQT_DAPM_ENUM(tx_adc0, AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, + tx_adc_mux_text); +AQT_DAPM_ENUM(tx_adc1, AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, + tx_adc_mux_text); +AQT_DAPM_ENUM(tx_adc2, AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, + tx_adc_mux_text); + +static int aqt_find_amic_input(struct snd_soc_component *component, + int adc_mux_n) +{ + u8 mask; + u16 adc_mux_in_reg = 0, amic_mux_sel_reg = 0; + bool is_amic; + + if (adc_mux_n > 2) + return 0; + + if (adc_mux_n < 3) { + adc_mux_in_reg = AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + adc_mux_n; + mask = 0x03; + amic_mux_sel_reg = AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + 2 * adc_mux_n; + } + is_amic = ( + ((snd_soc_component_read32(component, adc_mux_in_reg) + & mask)) == 0); + if (!is_amic) + return 0; + + return snd_soc_component_read32(component, amic_mux_sel_reg) & 0x07; +} + +static u16 aqt_codec_get_amic_pwlvl_reg( + struct snd_soc_component *component, int amic) +{ + u16 pwr_level_reg = 0; + + switch (amic) { + case 1: + case 2: + pwr_level_reg = AQT1000_ANA_AMIC1; + break; + case 3: + pwr_level_reg = AQT1000_ANA_AMIC3; + break; + default: + dev_dbg(component->dev, "%s: invalid amic: %d\n", + __func__, amic); + break; + } + + return pwr_level_reg; +} + +static void aqt_tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct aqt1000 *aqt; + struct snd_soc_component *component; + u16 dec_cfg_reg, amic_reg, go_bit_reg; + u8 hpf_cut_off_freq; + int amic_n; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + aqt = hpf_work->aqt; + component = aqt->component; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = AQT1000_CDC_TX0_TX_PATH_CFG0 + 16 * hpf_work->decimator; + go_bit_reg = dec_cfg_reg + 7; + + dev_dbg(component->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + amic_n = aqt_find_amic_input(component, hpf_work->decimator); + if (amic_n) { + amic_reg = AQT1000_ANA_AMIC1 + amic_n - 1; + aqt_codec_set_tx_hold(component, amic_reg, false); + } + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, go_bit_reg, 0x02, 0x02); + /* Minimum 1 clk cycle delay is required as per HW spec */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, go_bit_reg, 0x02, 0x00); +} + +static void aqt_tx_mute_update_callback(struct work_struct *work) +{ + struct tx_mute_work *tx_mute_dwork; + struct aqt1000 *aqt; + struct delayed_work *delayed_work; + struct snd_soc_component *component; + u16 tx_vol_ctl_reg, hpf_gate_reg; + + delayed_work = to_delayed_work(work); + tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork); + aqt = tx_mute_dwork->aqt; + component = aqt->component; + + tx_vol_ctl_reg = AQT1000_CDC_TX0_TX_PATH_CTL + + 16 * tx_mute_dwork->decimator; + hpf_gate_reg = AQT1000_CDC_TX0_TX_PATH_SEC2 + + 16 * tx_mute_dwork->decimator; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, 0x10, 0x00); +} + +static int aqt_codec_enable_dec(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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + char *widget_name = NULL; + char *dec = NULL; + unsigned int decimator = 0; + u8 amic_n = 0; + u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + int ret = 0; + u8 hpf_cut_off_freq; + + dev_dbg(component->dev, "%s: event: %d\n", __func__, event); + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + + dec = strpbrk(widget_name, "012"); + if (!dec) { + dev_err(component->dev, "%s: decimator index not found\n", + __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec, 10, &decimator); + if (ret < 0) { + dev_err(component->dev, "%s: Invalid decimator = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto out; + } + dev_dbg(component->dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = AQT1000_CDC_TX0_TX_PATH_CTL + 16 * decimator; + hpf_gate_reg = AQT1000_CDC_TX0_TX_PATH_SEC2 + 16 * decimator; + dec_cfg_reg = AQT1000_CDC_TX0_TX_PATH_CFG0 + 16 * decimator; + tx_gain_ctl_reg = AQT1000_CDC_TX0_TX_VOL_CTL + 16 * decimator; + + amic_n = aqt_find_amic_input(component, decimator); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (amic_n) + pwr_level_reg = aqt_codec_get_amic_pwlvl_reg(component, + amic_n); + if (pwr_level_reg) { + switch ((snd_soc_component_read32( + component, pwr_level_reg) & + AQT1000_AMIC_PWR_LVL_MASK) >> + AQT1000_AMIC_PWR_LVL_SHIFT) { + case AQT1000_AMIC_PWR_LEVEL_LP: + snd_soc_component_update_bits( + component, dec_cfg_reg, + AQT1000_DEC_PWR_LVL_MASK, + AQT1000_DEC_PWR_LVL_LP); + break; + + case AQT1000_AMIC_PWR_LEVEL_HP: + snd_soc_component_update_bits( + component, dec_cfg_reg, + AQT1000_DEC_PWR_LVL_MASK, + AQT1000_DEC_PWR_LVL_HP); + break; + case AQT1000_AMIC_PWR_LEVEL_DEFAULT: + default: + snd_soc_component_update_bits( + component, dec_cfg_reg, + AQT1000_DEC_PWR_LVL_MASK, + AQT1000_DEC_PWR_LVL_DF); + break; + } + } + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + hpf_cut_off_freq = (snd_soc_component_read32( + component, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + aqt->tx_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x02); + /* + * Minimum 1 clk cycle delay is required as per + * HW spec. + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x00); + } + /* schedule work queue to Remove Mute */ + schedule_delayed_work(&aqt->tx_mute_dwork[decimator].dwork, + msecs_to_jiffies(tx_unmute_delay)); + if (aqt->tx_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) + schedule_delayed_work( + &aqt->tx_hpf_work[decimator].dwork, + msecs_to_jiffies(300)); + /* apply gain after decimator is enabled */ + snd_soc_component_write(component, tx_gain_ctl_reg, + snd_soc_component_read32( + component, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + aqt->tx_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + if (cancel_delayed_work_sync( + &aqt->tx_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits( + component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits( + component, hpf_gate_reg, + 0x02, 0x02); + /* + * Minimum 1 clk cycle delay is required as per + * HW spec. + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits( + component, hpf_gate_reg, + 0x02, 0x00); + } + } + cancel_delayed_work_sync( + &aqt->tx_mute_dwork[decimator].dwork); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x00); + snd_soc_component_update_bits(component, dec_cfg_reg, + AQT1000_DEC_PWR_LVL_MASK, + AQT1000_DEC_PWR_LVL_DF); + break; + } + +out: + kfree(widget_name); + return ret; +} + +static const char * const tx_amic_text[] = { + "ZERO", "ADC_L", "ADC_R", "ADC_V", +}; +AQT_DAPM_ENUM(tx_amic0, AQT1000_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, tx_amic_text); +AQT_DAPM_ENUM(tx_amic1, AQT1000_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, tx_amic_text); +AQT_DAPM_ENUM(tx_amic2, AQT1000_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, tx_amic_text); + +AQT_DAPM_ENUM(tx_amic10, AQT1000_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0, + tx_amic_text); +AQT_DAPM_ENUM(tx_amic11, AQT1000_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0, + tx_amic_text); +AQT_DAPM_ENUM(tx_amic12, AQT1000_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0, + tx_amic_text); +AQT_DAPM_ENUM(tx_amic13, AQT1000_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0, + tx_amic_text); + +static int aqt_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); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aqt_codec_set_tx_hold(component, w->reg, true); + break; + default: + break; + } + + return 0; +} + +static const struct snd_kcontrol_new anc_hphl_pa_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_hphr_pa_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static int aqt_config_compander(struct snd_soc_component *component, + int interp_n, int event) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int comp; + u16 comp_ctl0_reg, rx_path_cfg0_reg; + + comp = interp_n; + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp, aqt->comp_enabled[comp]); + + if (!aqt->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = AQT1000_CDC_COMPANDER1_CTL0 + (comp * 8); + rx_path_cfg0_reg = AQT1000_CDC_RX1_RX_PATH_CFG0 + (comp * 20); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x01, 0x01); + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x02, 0x02); + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x02, 0x00); + snd_soc_component_update_bits( + component, rx_path_cfg0_reg, 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits( + component, rx_path_cfg0_reg, 0x02, 0x00); + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x04, 0x04); + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x02, 0x02); + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x02, 0x00); + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x01, 0x00); + snd_soc_component_update_bits( + component, comp_ctl0_reg, 0x04, 0x00); + } + + return 0; +} + +static void aqt_codec_idle_detect_control(struct snd_soc_component *component, + int interp, int event) +{ + int reg = 0, mask, val; + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + if (!aqt->idle_det_cfg.hph_idle_detect_en) + return; + + if (interp == INTERP_HPHL) { + reg = AQT1000_CDC_RX_IDLE_DET_PATH_CTL; + mask = 0x01; + val = 0x01; + } + if (interp == INTERP_HPHR) { + reg = AQT1000_CDC_RX_IDLE_DET_PATH_CTL; + mask = 0x02; + val = 0x02; + } + + if (reg && SND_SOC_DAPM_EVENT_ON(event)) + snd_soc_component_update_bits(component, reg, mask, val); + + if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, reg, mask, 0x00); + aqt->idle_det_cfg.hph_idle_thr = 0; + snd_soc_component_write(component, + AQT1000_CDC_RX_IDLE_DET_CFG3, 0x0); + } +} + +static void aqt_codec_hphdelay_lutbypass(struct snd_soc_component *component, + u16 interp_idx, int event) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + u8 hph_dly_mask; + u16 hph_lut_bypass_reg = 0; + u16 hph_comp_ctrl7 = 0; + + + switch (interp_idx) { + case INTERP_HPHL: + hph_dly_mask = 1; + hph_lut_bypass_reg = AQT1000_CDC_TOP_HPHL_COMP_LUT; + hph_comp_ctrl7 = AQT1000_CDC_COMPANDER1_CTL7; + break; + case INTERP_HPHR: + hph_dly_mask = 2; + hph_lut_bypass_reg = AQT1000_CDC_TOP_HPHR_COMP_LUT; + hph_comp_ctrl7 = AQT1000_CDC_COMPANDER2_CTL7; + break; + default: + break; + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, AQT1000_CDC_CLSH_TEST0, + hph_dly_mask, 0x0); + snd_soc_component_update_bits(component, hph_lut_bypass_reg, + 0x80, 0x80); + if (aqt->hph_mode == CLS_H_ULP) + snd_soc_component_update_bits(component, hph_comp_ctrl7, + 0x20, 0x20); + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, AQT1000_CDC_CLSH_TEST0, + hph_dly_mask, hph_dly_mask); + snd_soc_component_update_bits(component, hph_lut_bypass_reg, + 0x80, 0x00); + snd_soc_component_update_bits(component, hph_comp_ctrl7, + 0x20, 0x0); + } +} + +static int aqt_codec_enable_interp_clk(struct snd_soc_component *component, + int event, int interp_idx) +{ + struct aqt1000 *aqt; + u16 main_reg, dsm_reg; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + aqt = snd_soc_component_get_drvdata(component); + main_reg = AQT1000_CDC_RX1_RX_PATH_CTL + (interp_idx * 20); + dsm_reg = AQT1000_CDC_RX1_RX_PATH_DSMDEM_CTL + (interp_idx * 20); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (aqt->main_clk_users[interp_idx] == 0) { + /* Main path PGA mute enable */ + snd_soc_component_update_bits(component, main_reg, + 0x10, 0x10); + /* Clk enable */ + snd_soc_component_update_bits(component, dsm_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, main_reg, + 0x20, 0x20); + aqt_codec_idle_detect_control(component, interp_idx, + event); + aqt_codec_hphdelay_lutbypass(component, interp_idx, + event); + aqt_config_compander(component, interp_idx, event); + } + aqt->main_clk_users[interp_idx]++; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + aqt->main_clk_users[interp_idx]--; + if (aqt->main_clk_users[interp_idx] <= 0) { + aqt->main_clk_users[interp_idx] = 0; + aqt_config_compander(component, interp_idx, event); + aqt_codec_hphdelay_lutbypass(component, interp_idx, + event); + aqt_codec_idle_detect_control(component, interp_idx, + event); + /* Clk Disable */ + snd_soc_component_update_bits(component, main_reg, + 0x20, 0x00); + snd_soc_component_update_bits(component, dsm_reg, + 0x01, 0x00); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x00); + /* Reset rate to 48K*/ + snd_soc_component_update_bits(component, main_reg, + 0x0F, 0x04); + } + } + + dev_dbg(component->dev, "%s event %d main_clk_users %d\n", + __func__, event, aqt->main_clk_users[interp_idx]); + + return aqt->main_clk_users[interp_idx]; +} + +static int aqt_anc_out_switch_cb(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + aqt_codec_enable_interp_clk(component, event, w->shift); + + return 0; +} + +static const char * const anc0_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHL", +}; + +static const char * const anc1_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHR", +}; + +AQT_DAPM_ENUM(anc0_fb, AQT1000_CDC_RX_INP_MUX_ANC_CFG0, 0, anc0_fb_mux_text); +AQT_DAPM_ENUM(anc1_fb, AQT1000_CDC_RX_INP_MUX_ANC_CFG0, 3, anc1_fb_mux_text); + +static const char *const rx_int1_1_mux_text[] = { + "ZERO", "MAIN_DMA_L", "I2S0_L", "I2S0_R", "DEC_L", "DEC_R", "DEC_V", + "SHADOW_I2S0_L", "MAIN_DMA_R" +}; + +static const char *const rx_int1_2_mux_text[] = { + "ZERO", "MIX_DMA_L", "I2S0_L", "I2S0_R", "DEC_L", "DEC_R", "DEC_V", + "IIR0", "MIX_DMA_R" +}; + +static const char *const rx_int2_1_mux_text[] = { + "ZERO", "MAIN_DMA_R", "I2S0_L", "I2S0_R", "DEC_L", "DEC_R", "DEC_V", + "SHADOW_I2S0_R", "MAIN_DMA_L" +}; + +static const char *const rx_int2_2_mux_text[] = { + "ZERO", "MIX_DMA_R", "I2S0_L", "I2S0_R", "DEC_L", "DEC_R", "DEC_V", + "IIR0", "MIX_DMA_L" +}; + +AQT_DAPM_ENUM(rx_int1_1, AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, + rx_int1_1_mux_text); +AQT_DAPM_ENUM(rx_int1_2, AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, + rx_int1_2_mux_text); +AQT_DAPM_ENUM(rx_int2_1, AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, + rx_int2_1_mux_text); +AQT_DAPM_ENUM(rx_int2_2, AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, + rx_int2_2_mux_text); + +static int aqt_codec_set_idle_detect_thr(struct snd_soc_component *component, + int interp, int path_type) +{ + int port_id[4] = { 0, 0, 0, 0 }; + int *port_ptr, num_ports; + int bit_width = 0; + int mux_reg = 0, mux_reg_val = 0; + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int idle_thr; + + if ((interp != INTERP_HPHL) && (interp != INTERP_HPHR)) + return 0; + + if (!aqt->idle_det_cfg.hph_idle_detect_en) + return 0; + + port_ptr = &port_id[0]; + num_ports = 0; + + if (path_type == INTERP_MIX_PATH) { + if (interp == INTERP_HPHL) + mux_reg = AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG1; + else + mux_reg = AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG1; + } + + if (path_type == INTERP_MAIN_PATH) { + if (interp == INTERP_HPHL) + mux_reg = AQT1000_CDC_RX_INP_MUX_RX_INT1_CFG0; + else + mux_reg = AQT1000_CDC_RX_INP_MUX_RX_INT2_CFG0; + } + mux_reg_val = snd_soc_component_read32(component, mux_reg); + + /* Read bit width from I2S reg if mux is set to I2S0_L or I2S0_R */ + if (mux_reg_val == 0x02 || mux_reg_val == 0x03) + bit_width = ((snd_soc_component_read32( + component, AQT1000_I2S_I2S_0_CTL) & + 0x40) >> 6); + + switch (bit_width) { + case 1: /* 16 bit */ + idle_thr = 0xff; /* F16 */ + break; + case 0: /* 32 bit */ + default: + idle_thr = 0x03; /* F22 */ + break; + } + + dev_dbg(component->dev, "%s: (new) idle_thr: %d, (cur) idle_thr: %d\n", + __func__, idle_thr, aqt->idle_det_cfg.hph_idle_thr); + + if ((aqt->idle_det_cfg.hph_idle_thr == 0) || + (idle_thr < aqt->idle_det_cfg.hph_idle_thr)) { + snd_soc_component_write(component, AQT1000_CDC_RX_IDLE_DET_CFG3, + idle_thr); + aqt->idle_det_cfg.hph_idle_thr = idle_thr; + } + + return 0; +} + +static int aqt_codec_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg = 0; + int val = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (w->shift >= AQT1000_NUM_INTERPOLATORS) { + dev_err(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + }; + + gain_reg = AQT1000_CDC_RX1_RX_VOL_CTL + (w->shift * + AQT1000_RX_PATH_CTL_OFFSET); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aqt_codec_enable_interp_clk(component, event, w->shift); + break; + case SND_SOC_DAPM_POST_PMU: + aqt_codec_set_idle_detect_thr(component, w->shift, + INTERP_MAIN_PATH); + /* apply gain after int clk is enabled */ + val = snd_soc_component_read32(component, gain_reg); + snd_soc_component_write(component, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + aqt_codec_enable_interp_clk(component, event, w->shift); + break; + }; + + return 0; +} + +static int aqt_codec_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg = 0; + u16 mix_reg = 0; + + if (w->shift >= AQT1000_NUM_INTERPOLATORS) { + dev_err(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + }; + gain_reg = AQT1000_CDC_RX1_RX_VOL_MIX_CTL + + (w->shift * AQT1000_RX_PATH_CTL_OFFSET); + mix_reg = AQT1000_CDC_RX1_RX_PATH_MIX_CTL + + (w->shift * AQT1000_RX_PATH_CTL_OFFSET); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aqt_codec_enable_interp_clk(component, event, w->shift); + /* Clk enable */ + snd_soc_component_update_bits(component, mix_reg, 0x20, 0x20); + break; + case SND_SOC_DAPM_POST_PMU: + aqt_codec_set_idle_detect_thr(component, w->shift, + INTERP_MIX_PATH); + break; + case SND_SOC_DAPM_POST_PMD: + /* Clk Disable */ + snd_soc_component_update_bits(component, mix_reg, 0x20, 0x00); + aqt_codec_enable_interp_clk(component, event, w->shift); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x40); + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x00); + + break; + }; + dev_dbg(component->dev, "%s event %d name %s\n", __func__, + event, w->name); + + return 0; +} + +static const char * const rx_int1_1_interp_mux_text[] = { + "ZERO", "RX INT1_1 MUX", +}; + +static const char * const rx_int2_1_interp_mux_text[] = { + "ZERO", "RX INT2_1 MUX", +}; + +static const char * const rx_int1_2_interp_mux_text[] = { + "ZERO", "RX INT1_2 MUX", +}; + +static const char * const rx_int2_2_interp_mux_text[] = { + "ZERO", "RX INT2_2 MUX", +}; + +AQT_DAPM_ENUM(rx_int1_1_interp, SND_SOC_NOPM, 0, rx_int1_1_interp_mux_text); +AQT_DAPM_ENUM(rx_int2_1_interp, SND_SOC_NOPM, 0, rx_int2_1_interp_mux_text); + +AQT_DAPM_ENUM(rx_int1_2_interp, SND_SOC_NOPM, 0, rx_int1_2_interp_mux_text); +AQT_DAPM_ENUM(rx_int2_2_interp, SND_SOC_NOPM, 0, rx_int2_2_interp_mux_text); + +static const char * const asrc0_mux_text[] = { + "ZERO", "ASRC_IN_HPHL", +}; + +static const char * const asrc1_mux_text[] = { + "ZERO", "ASRC_IN_HPHR", +}; + +AQT_DAPM_ENUM(asrc0, AQT1000_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 0, + asrc0_mux_text); +AQT_DAPM_ENUM(asrc1, AQT1000_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 2, + asrc1_mux_text); + +static int aqt_get_asrc_mode(struct aqt1000 *aqt, int asrc, + u8 main_sr, u8 mix_sr) +{ + u8 asrc_output_mode; + int asrc_mode = CONV_88P2K_TO_384K; + + if ((asrc < 0) || (asrc >= ASRC_MAX)) + return 0; + + asrc_output_mode = aqt->asrc_output_mode[asrc]; + + if (asrc_output_mode) { + /* + * If Mix sample rate is < 96KHz, use 96K to 352.8K + * conversion, or else use 384K to 352.8K conversion + */ + if (mix_sr < 5) + asrc_mode = CONV_96K_TO_352P8K; + else + asrc_mode = CONV_384K_TO_352P8K; + } else { + /* Integer main and Fractional mix path */ + if (main_sr < 8 && mix_sr > 9) { + asrc_mode = CONV_352P8K_TO_384K; + } else if (main_sr > 8 && mix_sr < 8) { + /* Fractional main and Integer mix path */ + if (mix_sr < 5) + asrc_mode = CONV_96K_TO_352P8K; + else + asrc_mode = CONV_384K_TO_352P8K; + } else if (main_sr < 8 && mix_sr < 8) { + /* Integer main and Integer mix path */ + asrc_mode = CONV_96K_TO_384K; + } + } + + return asrc_mode; +} + +static int aqt_codec_enable_asrc_resampler(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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int asrc = 0, ret = 0; + u8 cfg; + u16 cfg_reg = 0; + u16 ctl_reg = 0; + u16 clk_reg = 0; + u16 asrc_ctl = 0; + u16 mix_ctl_reg = 0; + u16 paired_reg = 0; + u8 main_sr, mix_sr, asrc_mode = 0; + + cfg = snd_soc_component_read32(component, + AQT1000_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0); + if (!(cfg & 0xFF)) { + dev_err(component->dev, "%s: ASRC%u input not selected\n", + __func__, w->shift); + return -EINVAL; + } + + switch (w->shift) { + case ASRC0: + if ((cfg & 0x03) == 0x01) { + cfg_reg = AQT1000_CDC_RX1_RX_PATH_CFG0; + ctl_reg = AQT1000_CDC_RX1_RX_PATH_CTL; + clk_reg = AQT1000_MIXING_ASRC0_CLK_RST_CTL; + paired_reg = AQT1000_MIXING_ASRC1_CLK_RST_CTL; + asrc_ctl = AQT1000_MIXING_ASRC0_CTL1; + } + break; + case ASRC1: + if ((cfg & 0x0C) == 0x4) { + cfg_reg = AQT1000_CDC_RX2_RX_PATH_CFG0; + ctl_reg = AQT1000_CDC_RX2_RX_PATH_CTL; + clk_reg = AQT1000_MIXING_ASRC1_CLK_RST_CTL; + paired_reg = AQT1000_MIXING_ASRC0_CLK_RST_CTL; + asrc_ctl = AQT1000_MIXING_ASRC1_CTL1; + } + break; + default: + dev_err(component->dev, "%s: Invalid asrc:%u\n", __func__, + w->shift); + ret = -EINVAL; + break; + }; + + if ((cfg_reg == 0) || (ctl_reg == 0) || (clk_reg == 0) || + (asrc_ctl == 0) || ret) + goto done; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if ((snd_soc_component_read32(component, clk_reg) & 0x02) || + (snd_soc_component_read32(component, paired_reg) & 0x02)) { + snd_soc_component_update_bits(component, clk_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, paired_reg, + 0x02, 0x00); + } + snd_soc_component_update_bits(component, cfg_reg, 0x80, 0x80); + snd_soc_component_update_bits(component, clk_reg, 0x01, 0x01); + main_sr = snd_soc_component_read32(component, ctl_reg) & 0x0F; + mix_ctl_reg = ctl_reg + 5; + mix_sr = snd_soc_component_read32( + component, mix_ctl_reg) & 0x0F; + asrc_mode = aqt_get_asrc_mode(aqt, asrc, + main_sr, mix_sr); + dev_dbg(component->dev, "%s: main_sr:%d mix_sr:%d asrc_mode %d\n", + __func__, main_sr, mix_sr, asrc_mode); + snd_soc_component_update_bits( + component, asrc_ctl, 0x07, asrc_mode); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, asrc_ctl, 0x07, 0x00); + snd_soc_component_update_bits(component, cfg_reg, 0x80, 0x00); + snd_soc_component_update_bits(component, clk_reg, 0x03, 0x02); + break; + }; + +done: + return ret; +} + +static int aqt_codec_enable_anc(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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + const char *filename; + const struct firmware *fw; + int i; + int ret = 0; + int num_anc_slots; + struct aqt1000_anc_header *anc_head; + struct firmware_cal *hwdep_cal = NULL; + u32 anc_writes_size = 0; + u32 anc_cal_size = 0; + int anc_size_remaining; + u32 *anc_ptr; + u16 reg; + u8 mask, val; + size_t cal_size; + const void *data; + + if (!aqt->anc_func) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hwdep_cal = wcdcal_get_fw_cal(aqt->fw_data, WCD9XXX_ANC_CAL); + if (hwdep_cal) { + data = hwdep_cal->data; + cal_size = hwdep_cal->size; + dev_dbg(component->dev, "%s: using hwdep calibration, cal_size %zd", + __func__, cal_size); + } else { + filename = "AQT1000/AQT1000_anc.bin"; + ret = request_firmware(&fw, filename, component->dev); + if (ret < 0) { + dev_err(component->dev, "%s: Failed to acquire ANC data: %d\n", + __func__, ret); + return ret; + } + if (!fw) { + dev_err(component->dev, "%s: Failed to get anc fw\n", + __func__); + return -ENODEV; + } + data = fw->data; + cal_size = fw->size; + dev_dbg(component->dev, "%s: using request_firmware calibration\n", + __func__); + } + if (cal_size < sizeof(struct aqt1000_anc_header)) { + dev_err(component->dev, "%s: Invalid cal_size %zd\n", + __func__, cal_size); + ret = -EINVAL; + goto err; + } + /* First number is the number of register writes */ + anc_head = (struct aqt1000_anc_header *)(data); + anc_ptr = (u32 *)(data + sizeof(struct aqt1000_anc_header)); + anc_size_remaining = cal_size - + sizeof(struct aqt1000_anc_header); + num_anc_slots = anc_head->num_anc_slots; + + if (aqt->anc_slot >= num_anc_slots) { + dev_err(component->dev, "%s: Invalid ANC slot selected\n", + __func__); + ret = -EINVAL; + goto err; + } + for (i = 0; i < num_anc_slots; i++) { + if (anc_size_remaining < AQT1000_PACKED_REG_SIZE) { + dev_err(component->dev, "%s: Invalid register format\n", + __func__); + ret = -EINVAL; + goto err; + } + anc_writes_size = (u32)(*anc_ptr); + anc_size_remaining -= sizeof(u32); + anc_ptr += 1; + + if ((anc_writes_size * AQT1000_PACKED_REG_SIZE) > + anc_size_remaining) { + dev_err(component->dev, "%s: Invalid register format\n", + __func__); + ret = -EINVAL; + goto err; + } + + if (aqt->anc_slot == i) + break; + + anc_size_remaining -= (anc_writes_size * + AQT1000_PACKED_REG_SIZE); + anc_ptr += anc_writes_size; + } + if (i == num_anc_slots) { + dev_err(component->dev, "%s: Selected ANC slot not present\n", + __func__); + ret = -EINVAL; + goto err; + } + + i = 0; + anc_cal_size = anc_writes_size; + /* Rate converter clk enable and set bypass mode */ + if (!strcmp(w->name, "AQT RX INT1 DAC")) { + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_RC_COMMON_CTL, + 0x05, 0x05); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_FIFO_COMMON_CTL, + 0x66, 0x66); + anc_writes_size = anc_cal_size / 2; + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_CLK_RESET_CTL, 0x39, 0x39); + } else if (!strcmp(w->name, "AQT RX INT2 DAC")) { + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_RC_COMMON_CTL, + 0x05, 0x05); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_FIFO_COMMON_CTL, + 0x66, 0x66); + i = anc_cal_size / 2; + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_CLK_RESET_CTL, 0x39, 0x39); + } + + for (; i < anc_writes_size; i++) { + AQT1000_CODEC_UNPACK_ENTRY(anc_ptr[i], reg, mask, val); + snd_soc_component_write(component, reg, (val & mask)); + } + if (!strcmp(w->name, "AQT RX INT1 DAC")) + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08); + else if (!strcmp(w->name, "AQT RX INT2 DAC")) + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08); + + if (!hwdep_cal) + release_firmware(fw); + break; + + case SND_SOC_DAPM_POST_PMU: + /* Remove ANC Rx from reset */ + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_CLK_RESET_CTL, + 0x08, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_CLK_RESET_CTL, + 0x08, 0x00); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_RC_COMMON_CTL, + 0x05, 0x00); + if (!strcmp(w->name, "AQT ANC HPHL PA")) { + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_MODE_1_CTL, + 0x30, 0x00); + /* 50 msec sleep is needed to avoid click and pop as + * per HW requirement + */ + msleep(50); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_MODE_1_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_CLK_RESET_CTL, + 0x38, 0x38); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_CLK_RESET_CTL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC0_CLK_RESET_CTL, + 0x38, 0x00); + } else if (!strcmp(w->name, "AQT ANC HPHR PA")) { + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_MODE_1_CTL, + 0x30, 0x00); + /* 50 msec sleep is needed to avoid click and pop as + * per HW requirement + */ + msleep(50); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_MODE_1_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_CLK_RESET_CTL, + 0x38, 0x38); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_CLK_RESET_CTL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_ANC1_CLK_RESET_CTL, + 0x38, 0x00); + } + break; + } + + return 0; +err: + if (!hwdep_cal) + release_firmware(fw); + return ret; +} + +static void aqt_codec_override(struct snd_soc_component *component, int mode, + int event) +{ + if (mode == CLS_AB || mode == CLS_AB_HIFI) { + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, 0x02, 0x02); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + AQT1000_ANA_RX_SUPPLIES, 0x02, 0x00); + break; + } + } +} + +static void aqt_codec_set_tx_hold(struct snd_soc_component *component, + u16 amic_reg, bool set) +{ + u8 mask = 0x20; + u8 val; + + if (amic_reg == AQT1000_ANA_AMIC1 || + amic_reg == AQT1000_ANA_AMIC3) + mask = 0x40; + + val = set ? mask : 0x00; + + switch (amic_reg) { + case AQT1000_ANA_AMIC1: + case AQT1000_ANA_AMIC2: + snd_soc_component_update_bits(component, AQT1000_ANA_AMIC2, + mask, val); + break; + case AQT1000_ANA_AMIC3: + snd_soc_component_update_bits(component, AQT1000_ANA_AMIC3_HPF, + mask, val); + break; + default: + dev_dbg(component->dev, "%s: invalid amic: %d\n", + __func__, amic_reg); + break; + } +} + +static void aqt_codec_clear_anc_tx_hold(struct aqt1000 *aqt) +{ + if (test_and_clear_bit(ANC_MIC_AMIC1, &aqt->status_mask)) + aqt_codec_set_tx_hold(aqt->component, AQT1000_ANA_AMIC1, false); + if (test_and_clear_bit(ANC_MIC_AMIC2, &aqt->status_mask)) + aqt_codec_set_tx_hold(aqt->component, AQT1000_ANA_AMIC2, false); + if (test_and_clear_bit(ANC_MIC_AMIC3, &aqt->status_mask)) + aqt_codec_set_tx_hold(aqt->component, AQT1000_ANA_AMIC3, false); +} + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static int aqt_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + unsigned short look_ahead_dly_reg = AQT1000_CDC_RX1_RX_PATH_CFG0; + + val = ucontrol->value.enumerated.item[0]; + if (val >= e->items) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + if (e->reg == AQT1000_CDC_RX1_RX_PATH_SEC0) + look_ahead_dly_reg = AQT1000_CDC_RX1_RX_PATH_CFG0; + else if (e->reg == AQT1000_CDC_RX2_RX_PATH_SEC0) + look_ahead_dly_reg = AQT1000_CDC_RX2_RX_PATH_CFG0; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, look_ahead_dly_reg, + 0x08, (val ? 0x08 : 0x00)); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +AQT_DAPM_ENUM_EXT(rx_int1_dem, AQT1000_CDC_RX1_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + aqt_int_dem_inp_mux_put); +AQT_DAPM_ENUM_EXT(rx_int2_dem, AQT1000_CDC_RX2_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + aqt_int_dem_inp_mux_put); + +static int aqt_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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int hph_mode = aqt->hph_mode; + u8 dem_inp; + int ret = 0; + uint32_t impedl = 0; + uint32_t impedr = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d hph_mode: %d\n", + __func__, w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (aqt->anc_func) { + ret = aqt_codec_enable_anc(w, kcontrol, event); + /* 40 msec delay is needed to avoid click and pop */ + msleep(40); + } + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32( + component, AQT1000_CDC_RX1_RX_PATH_SEC0) & + 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + /* Disable AutoChop timer during power up */ + snd_soc_component_update_bits(component, + AQT1000_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + + aqt_clsh_fsm(component, &aqt->clsh_d, + AQT_CLSH_EVENT_PRE_DAC, + AQT_CLSH_STATE_HPHL, + hph_mode); + + if (aqt->anc_func) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0, + 0x10, 0x10); + + ret = aqt_mbhc_get_impedance(aqt->mbhc, + &impedl, &impedr); + if (!ret) { + aqt_clsh_imped_config(component, impedl, false); + set_bit(CLSH_Z_CONFIG, &aqt->status_mask); + } else { + dev_dbg(component->dev, "%s: Failed to get mbhc impedance %d\n", + __func__, ret); + ret = 0; + } + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + aqt_clsh_fsm(component, &aqt->clsh_d, + AQT_CLSH_EVENT_POST_PA, + AQT_CLSH_STATE_HPHL, + hph_mode); + if (test_bit(CLSH_Z_CONFIG, &aqt->status_mask)) { + aqt_clsh_imped_config(component, impedl, true); + clear_bit(CLSH_Z_CONFIG, &aqt->status_mask); + } + break; + default: + break; + }; + + return ret; +} + +static int aqt_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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int hph_mode = aqt->hph_mode; + u8 dem_inp; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d hph_mode: %d\n", + __func__, w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (aqt->anc_func) { + ret = aqt_codec_enable_anc(w, kcontrol, event); + /* 40 msec delay is needed to avoid click and pop */ + msleep(40); + } + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32( + component, AQT1000_CDC_RX2_RX_PATH_SEC0) & + 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + /* Disable AutoChop timer during power up */ + snd_soc_component_update_bits(component, + AQT1000_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + aqt_clsh_fsm(component, &aqt->clsh_d, + AQT_CLSH_EVENT_PRE_DAC, + AQT_CLSH_STATE_HPHR, + hph_mode); + if (aqt->anc_func) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CFG0, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + aqt_clsh_fsm(component, &aqt->clsh_d, + AQT_CLSH_EVENT_POST_PA, + AQT_CLSH_STATE_HPHR, + hph_mode); + break; + default: + break; + }; + + return 0; +} + +static int aqt_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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if ((!(strcmp(w->name, "AQT ANC HPHR PA"))) && + (test_bit(HPH_PA_DELAY, &aqt->status_mask))) + snd_soc_component_update_bits(component, + AQT1000_ANA_HPH, 0xC0, 0xC0); + + set_bit(HPH_PA_DELAY, &aqt->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if ((!(strcmp(w->name, "AQT ANC HPHR PA")))) { + if ((snd_soc_component_read32( + component, AQT1000_ANA_HPH) & 0xC0) + != 0xC0) + /* + * If PA_EN is not set (potentially in ANC case) + * then do nothing for POST_PMU and let left + * channel handle everything. + */ + break; + } + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is needed. + */ + if (test_bit(HPH_PA_DELAY, &aqt->status_mask)) { + if (!aqt->comp_enabled[COMPANDER_2]) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &aqt->status_mask); + } + if (aqt->anc_func) { + /* Clear Tx FE HOLD if both PAs are enabled */ + if ((snd_soc_component_read32( + aqt->component, AQT1000_ANA_HPH) & + 0xC0) == 0xC0) + aqt_codec_clear_anc_tx_hold(aqt); + } + + snd_soc_component_update_bits( + component, AQT1000_HPH_R_TEST, 0x01, 0x01); + + /* Remove mute */ + snd_soc_component_update_bits( + component, AQT1000_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + /* Enable GM3 boost */ + snd_soc_component_update_bits( + component, AQT1000_HPH_CNP_WG_CTL, + 0x80, 0x80); + /* Enable AutoChop timer at the end of power up */ + snd_soc_component_update_bits(component, + AQT1000_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32( + component, AQT1000_CDC_RX2_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + if (!(strcmp(w->name, "AQT ANC HPHR PA"))) { + dev_dbg(component->dev, + "%s:Do everything needed for left channel\n", + __func__); + /* Do everything needed for left channel */ + snd_soc_component_update_bits( + component, AQT1000_HPH_L_TEST, + 0x01, 0x01); + + /* Remove mute */ + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + AQT1000_CDC_RX1_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + + /* Remove ANC Rx from reset */ + ret = aqt_codec_enable_anc(w, kcontrol, event); + } + aqt_codec_override(component, aqt->hph_mode, event); + break; + case SND_SOC_DAPM_PRE_PMD: + blocking_notifier_call_chain(&aqt->mbhc->notifier, + AQT_EVENT_PRE_HPHR_PA_OFF, + &aqt->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, + AQT1000_HPH_R_TEST, 0x01, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x10); + if (!(strcmp(w->name, "AQT ANC HPHR PA"))) + snd_soc_component_update_bits(component, + AQT1000_ANA_HPH, 0x40, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA disable. If compander is + * disabled, then 20ms delay is needed after PA disable. + */ + if (!aqt->comp_enabled[COMPANDER_2]) + usleep_range(20000, 20100); + else + usleep_range(5000, 5100); + aqt_codec_override(component, aqt->hph_mode, event); + blocking_notifier_call_chain(&aqt->mbhc->notifier, + AQT_EVENT_POST_HPHR_PA_OFF, + &aqt->mbhc->wcd_mbhc); + if (!(strcmp(w->name, "AQT ANC HPHR PA"))) { + ret = aqt_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CFG0, + 0x10, 0x00); + } + break; + }; + + return ret; +} + +static int aqt_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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if ((!(strcmp(w->name, "AQT ANC HPHL PA"))) && + (test_bit(HPH_PA_DELAY, &aqt->status_mask))) + snd_soc_component_update_bits(component, + AQT1000_ANA_HPH, + 0xC0, 0xC0); + set_bit(HPH_PA_DELAY, &aqt->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if (!(strcmp(w->name, "AQT ANC HPHL PA"))) { + if ((snd_soc_component_read32( + component, AQT1000_ANA_HPH) & 0xC0) + != 0xC0) + /* + * If PA_EN is not set (potentially in ANC + * case) then do nothing for POST_PMU and + * let right channel handle everything. + */ + break; + } + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is needed. + */ + if (test_bit(HPH_PA_DELAY, &aqt->status_mask)) { + if (!aqt->comp_enabled[COMPANDER_1]) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &aqt->status_mask); + } + if (aqt->anc_func) { + /* Clear Tx FE HOLD if both PAs are enabled */ + if ((snd_soc_component_read32( + aqt->component, AQT1000_ANA_HPH) & + 0xC0) == 0xC0) + aqt_codec_clear_anc_tx_hold(aqt); + } + + snd_soc_component_update_bits(component, + AQT1000_HPH_L_TEST, 0x01, 0x01); + /* Remove Mute on primary path */ + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + /* Enable GM3 boost */ + snd_soc_component_update_bits(component, + AQT1000_HPH_CNP_WG_CTL, + 0x80, 0x80); + /* Enable AutoChop timer at the end of power up */ + snd_soc_component_update_bits(component, + AQT1000_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + AQT1000_CDC_RX1_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + if (!(strcmp(w->name, "AQT ANC HPHL PA"))) { + dev_dbg(component->dev, + "%s:Do everything needed for right channel\n", + __func__); + + /* Do everything needed for right channel */ + snd_soc_component_update_bits(component, + AQT1000_HPH_R_TEST, + 0x01, 0x01); + + /* Remove mute */ + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + AQT1000_CDC_RX2_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + /* Remove ANC Rx from reset */ + ret = aqt_codec_enable_anc(w, kcontrol, event); + } + aqt_codec_override(component, aqt->hph_mode, event); + break; + case SND_SOC_DAPM_PRE_PMD: + blocking_notifier_call_chain(&aqt->mbhc->notifier, + AQT_EVENT_PRE_HPHL_PA_OFF, + &aqt->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, + AQT1000_HPH_L_TEST, 0x01, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CTL, 0x10, 0x10); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_MIX_CTL, 0x10, 0x10); + if (!(strcmp(w->name, "AQT ANC HPHL PA"))) + snd_soc_component_update_bits(component, + AQT1000_ANA_HPH, 0x80, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA disable. If compander is + * disabled, then 20ms delay is needed after PA disable. + */ + if (!aqt->comp_enabled[COMPANDER_1]) + usleep_range(20000, 20100); + else + usleep_range(5000, 5100); + aqt_codec_override(component, aqt->hph_mode, event); + blocking_notifier_call_chain(&aqt->mbhc->notifier, + AQT_EVENT_POST_HPHL_PA_OFF, + &aqt->mbhc->wcd_mbhc); + if (!(strcmp(w->name, "AQT ANC HPHL PA"))) { + ret = aqt_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_CFG0, 0x10, 0x00); + } + break; + }; + + return ret; +} + +static int aqt_codec_set_iir_gain(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: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: /* fall through */ + case SND_SOC_DAPM_PRE_PMD: + if (strnstr(w->name, "AQT IIR0", sizeof("AQT IIR0"))) { + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, + snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, + snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, + snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)); + snd_soc_component_write(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, + snd_soc_component_read32(component, + AQT1000_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)); + } + break; + } + return 0; +} + +static int aqt_enable_native_supply(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 aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (++aqt->native_clk_users == 1) { + snd_soc_component_update_bits(component, + AQT1000_CLK_SYS_PLL_ENABLES, + 0x01, 0x01); + /* 100usec is needed as per HW requirement */ + usleep_range(100, 120); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x02); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x10, 0x10); + } + break; + case SND_SOC_DAPM_PRE_PMD: + if (aqt->native_clk_users && + (--aqt->native_clk_users == 0)) { + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CLK_SYS_PLL_ENABLES, + 0x01, 0x00); + } + break; + } + + dev_dbg(component->dev, "%s: native_clk_users: %d, event: %d\n", + __func__, aqt->native_clk_users, event); + + return 0; +} + +static const char * const native_mux_text[] = { + "OFF", "ON", +}; + +AQT_DAPM_ENUM(int1_1_native, SND_SOC_NOPM, 0, native_mux_text); +AQT_DAPM_ENUM(int2_1_native, SND_SOC_NOPM, 0, native_mux_text); + +static int aqt_mclk_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); + int ret = 0; + + dev_dbg(component->dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = aqt_cdc_mclk_enable(component, true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = aqt_cdc_mclk_enable(component, false); + break; + } + + return ret; +} + +static int aif_cap_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static int aif_cap_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static const struct snd_kcontrol_new aif1_cap_mixer[] = { + SOC_SINGLE_EXT("TX0", SND_SOC_NOPM, AQT_TX0, 1, 0, + aif_cap_mixer_get, aif_cap_mixer_put), + SOC_SINGLE_EXT("TX1", SND_SOC_NOPM, AQT_TX1, 1, 0, + aif_cap_mixer_get, aif_cap_mixer_put), +}; + +static const char * const rx_inp_st_mux_text[] = { + "ZERO", "SRC0", +}; +AQT_DAPM_ENUM(rx_inp_st, AQT1000_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, + rx_inp_st_mux_text); + +static const struct snd_soc_dapm_widget aqt_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY("AQT MCLK", SND_SOC_NOPM, 0, 0, aqt_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AQT AIF1 CAP", "AQT AIF1 Capture", 0, + SND_SOC_NOPM, AIF1_CAP, 0, aqt_codec_enable_i2s_tx, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("AQT AIF1 CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)), + + AQT_DAPM_MUX("AQT TX0_MUX", 0, tx0), + AQT_DAPM_MUX("AQT TX1_MUX", 0, tx1), + + SND_SOC_DAPM_MUX_E("AQT ADC0 MUX", AQT1000_CDC_TX0_TX_PATH_CTL, 5, 0, + &tx_adc0_mux, aqt_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("AQT ADC1 MUX", AQT1000_CDC_TX1_TX_PATH_CTL, 5, 0, + &tx_adc1_mux, aqt_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("AQT ADC2 MUX", AQT1000_CDC_TX2_TX_PATH_CTL, 5, 0, + &tx_adc2_mux, aqt_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + AQT_DAPM_MUX("AQT AMIC0_MUX", 0, tx_amic0), + AQT_DAPM_MUX("AQT AMIC1_MUX", 0, tx_amic1), + AQT_DAPM_MUX("AQT AMIC2_MUX", 0, tx_amic2), + + SND_SOC_DAPM_ADC_E("AQT ADC_L", NULL, AQT1000_ANA_AMIC1, 7, 0, + aqt_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("AQT ADC_R", NULL, AQT1000_ANA_AMIC2, 7, 0, + aqt_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("AQT ADC_V", NULL, AQT1000_ANA_AMIC3, 7, 0, + aqt_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + + AQT_DAPM_MUX("AQT AMIC10_MUX", 0, tx_amic10), + AQT_DAPM_MUX("AQT AMIC11_MUX", 0, tx_amic11), + AQT_DAPM_MUX("AQT AMIC12_MUX", 0, tx_amic12), + AQT_DAPM_MUX("AQT AMIC13_MUX", 0, tx_amic13), + + SND_SOC_DAPM_SWITCH_E("AQT ANC OUT HPHL Enable", SND_SOC_NOPM, + INTERP_HPHL, 0, &anc_hphl_pa_switch, aqt_anc_out_switch_cb, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SWITCH_E("AQT ANC OUT HPHR Enable", SND_SOC_NOPM, + INTERP_HPHR, 0, &anc_hphr_pa_switch, aqt_anc_out_switch_cb, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MIXER("AQT RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AQT RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + + AQT_DAPM_MUX("AQT ANC0 FB MUX", 0, anc0_fb), + AQT_DAPM_MUX("AQT ANC1 FB MUX", 0, anc1_fb), + + SND_SOC_DAPM_INPUT("AQT AMIC1"), + SND_SOC_DAPM_INPUT("AQT AMIC2"), + SND_SOC_DAPM_INPUT("AQT AMIC3"), + + SND_SOC_DAPM_MIXER("AQT I2S_L RX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AQT I2S_R RX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_AIF_IN_E("AQT AIF1 PB", "AQT AIF1 Playback", 0, + SND_SOC_NOPM, AIF1_PB, 0, aqt_codec_enable_i2s_rx, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("AQT RX INT1_1 MUX", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int1_1_mux, aqt_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("AQT RX INT2_1 MUX", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int2_1_mux, aqt_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("AQT RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int1_2_mux, aqt_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("AQT RX INT2_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int2_2_mux, aqt_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + AQT_DAPM_MUX("AQT RX INT1_1 INTERP", 0, rx_int1_1_interp), + AQT_DAPM_MUX("AQT RX INT1_2 INTERP", 0, rx_int1_2_interp), + AQT_DAPM_MUX("AQT RX INT2_1 INTERP", 0, rx_int2_1_interp), + AQT_DAPM_MUX("AQT RX INT2_2 INTERP", 0, rx_int2_2_interp), + + SND_SOC_DAPM_MIXER("AQT RX INT1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AQT RX INT2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("AQT ASRC0 MUX", SND_SOC_NOPM, ASRC0, 0, + &asrc0_mux, aqt_codec_enable_asrc_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("AQT ASRC1 MUX", SND_SOC_NOPM, ASRC1, 0, + &asrc1_mux, aqt_codec_enable_asrc_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + AQT_DAPM_MUX("AQT RX INT1 DEM MUX", 0, rx_int1_dem), + AQT_DAPM_MUX("AQT RX INT2 DEM MUX", 0, rx_int2_dem), + + SND_SOC_DAPM_DAC_E("AQT RX INT1 DAC", NULL, AQT1000_ANA_HPH, + 5, 0, aqt_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("AQT RX INT2 DAC", NULL, AQT1000_ANA_HPH, + 4, 0, aqt_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_PGA_E("AQT HPHL PA", AQT1000_ANA_HPH, 7, 0, NULL, 0, + aqt_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AQT HPHR PA", AQT1000_ANA_HPH, 6, 0, NULL, 0, + aqt_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AQT ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0, + aqt_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AQT ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0, + aqt_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_OUTPUT("AQT HPHL"), + SND_SOC_DAPM_OUTPUT("AQT HPHR"), + SND_SOC_DAPM_OUTPUT("AQT ANC HPHL"), + SND_SOC_DAPM_OUTPUT("AQT ANC HPHR"), + + SND_SOC_DAPM_MIXER_E("AQT IIR0", AQT1000_CDC_SIDETONE_IIR0_IIR_PATH_CTL, + 4, 0, NULL, 0, aqt_codec_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MIXER("AQT SRC0", + AQT1000_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + + SND_SOC_DAPM_MICBIAS_E("AQT MIC BIAS1", SND_SOC_NOPM, 0, 0, + aqt_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("AQT RX_BIAS", SND_SOC_NOPM, 0, 0, + aqt_codec_enable_rx_bias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("AQT RX INT1 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_HPHL, 0, aqt_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("AQT RX INT2 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_HPHR, 0, aqt_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + AQT_DAPM_MUX("AQT RX INT1_1 NATIVE MUX", 0, int1_1_native), + AQT_DAPM_MUX("AQT RX INT2_1 NATIVE MUX", 0, int2_1_native), + + SND_SOC_DAPM_MUX("AQT RX ST MUX", + AQT1000_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, 0, + &rx_inp_st_mux), +}; + +static int aqt_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + return 0; +} + +static void aqt_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); +} + +static int aqt_set_decimator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_component *component = dai->component; + u8 tx_fs_rate = 0; + u8 tx_mux_sel = 0, tx0_mux_sel = 0, tx1_mux_sel = 0; + u16 tx_path_ctl_reg = 0; + + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + default: + dev_err(component->dev, "%s: Invalid TX sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + + }; + + /* Find which decimator path is enabled */ + tx_mux_sel = snd_soc_component_read32(component, + AQT1000_CDC_IF_ROUTER_TX_MUX_CFG0); + tx0_mux_sel = (tx_mux_sel & 0x03); + tx1_mux_sel = (tx_mux_sel & 0xC0); + + if (tx0_mux_sel) { + tx_path_ctl_reg = AQT1000_CDC_TX0_TX_PATH_CTL + + ((tx0_mux_sel - 1) * 16); + snd_soc_component_update_bits(component, tx_path_ctl_reg, + 0x0F, tx_fs_rate); + } + + if (tx1_mux_sel) { + tx_path_ctl_reg = AQT1000_CDC_TX0_TX_PATH_CTL + + ((tx1_mux_sel - 1) * 16); + snd_soc_component_update_bits(component, tx_path_ctl_reg, + 0x0F, tx_fs_rate); + } + + return 0; +} + +static int aqt_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_component *component = dai->component; + int rate_val = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) { + if (sample_rate == sr_val_tbl[i].sample_rate) { + rate_val = sr_val_tbl[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) { + dev_err(component->dev, "%s: Unsupported sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + } + + /* TODO - Set the rate only to enabled path */ + /* Set Primary interpolator rate */ + snd_soc_component_update_bits(component, AQT1000_CDC_RX1_RX_PATH_CTL, + 0x0F, (u8)rate_val); + snd_soc_component_update_bits(component, AQT1000_CDC_RX2_RX_PATH_CTL, + 0x0F, (u8)rate_val); + + /* Set mixing path interpolator rate */ + snd_soc_component_update_bits(component, + AQT1000_CDC_RX1_RX_PATH_MIX_CTL, + 0x0F, (u8)rate_val); + snd_soc_component_update_bits(component, + AQT1000_CDC_RX2_RX_PATH_MIX_CTL, + 0x0F, (u8)rate_val); + + return 0; +} + +static int aqt_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + return 0; +} + +static int aqt_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(dai->component); + int ret = 0; + + dev_dbg(aqt->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", + __func__, dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = aqt_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(aqt->dev, "%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16: + aqt->dai[dai->id].bit_width = 16; + break; + case 24: + aqt->dai[dai->id].bit_width = 24; + break; + case 32: + aqt->dai[dai->id].bit_width = 32; + break; + default: + return -EINVAL; + } + aqt->dai[dai->id].rate = params_rate(params); + break; + case SNDRV_PCM_STREAM_CAPTURE: + ret = aqt_set_decimator_rate(dai, params_rate(params)); + if (ret) { + dev_err(aqt->dev, + "%s: cannot set TX Decimator rate: %d\n", + __func__, ret); + return ret; + } + switch (params_width(params)) { + case 16: + aqt->dai[dai->id].bit_width = 16; + break; + case 24: + aqt->dai[dai->id].bit_width = 24; + break; + default: + dev_err(aqt->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + }; + aqt->dai[dai->id].rate = params_rate(params); + break; + default: + dev_err(aqt->dev, "%s: Invalid stream type %d\n", __func__, + substream->stream); + return -EINVAL; + }; + + return 0; +} + +static struct snd_soc_dai_ops aqt_dai_ops = { + .startup = aqt_startup, + .shutdown = aqt_shutdown, + .hw_params = aqt_hw_params, + .prepare = aqt_prepare, +}; + +struct snd_soc_dai_driver aqt_dai[] = { + { + .name = "aqt_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AQT AIF1 Playback", + .rates = AQT1000_RATES_MASK | AQT1000_FRAC_RATES_MASK, + .formats = AQT1000_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &aqt_dai_ops, + }, + { + .name = "aqt_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AQT AIF1 Capture", + .rates = AQT1000_RATES_MASK, + .formats = AQT1000_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &aqt_dai_ops, + }, +}; + +static int aqt_enable_mclk(struct aqt1000 *aqt) +{ + struct snd_soc_component *component = aqt->component; + + /* Enable mclk requires master bias to be enabled first */ + if (aqt->master_bias_users <= 0) { + dev_err(aqt->dev, + "%s: Cannot turn on MCLK, BG is not enabled\n", + __func__); + return -EINVAL; + } + + if (++aqt->mclk_users == 1) { + /* Set clock div 2 */ + snd_soc_component_update_bits(component, + AQT1000_CLK_SYS_MCLK1_PRG, 0x0C, 0x04); + snd_soc_component_update_bits(component, + AQT1000_CLK_SYS_MCLK1_PRG, 0x10, 0x10); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + /* + * 10us sleep is required after clock is enabled + * as per HW requirement + */ + usleep_range(10, 15); + } + + dev_dbg(aqt->dev, "%s: mclk_users: %d\n", __func__, aqt->mclk_users); + + return 0; +} + +static int aqt_disable_mclk(struct aqt1000 *aqt) +{ + struct snd_soc_component *component = aqt->component; + + if (aqt->mclk_users <= 0) { + dev_err(aqt->dev, "%s: No mclk users, cannot disable mclk\n", + __func__); + return -EINVAL; + } + + if (--aqt->mclk_users == 0) { + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + AQT1000_CLK_SYS_MCLK1_PRG, 0x10, 0x00); + } + + dev_dbg(component->dev, "%s: mclk_users: %d\n", __func__, + aqt->mclk_users); + + return 0; +} + +static int aqt_enable_master_bias(struct aqt1000 *aqt) +{ + struct snd_soc_component *component = aqt->component; + + mutex_lock(&aqt->master_bias_lock); + + aqt->master_bias_users++; + if (aqt->master_bias_users == 1) { + snd_soc_component_update_bits(component, AQT1000_ANA_BIAS, + 0x80, 0x80); + snd_soc_component_update_bits(component, AQT1000_ANA_BIAS, + 0x40, 0x40); + /* + * 1ms delay is required after pre-charge is enabled + * as per HW requirement + */ + usleep_range(1000, 1100); + snd_soc_component_update_bits(component, AQT1000_ANA_BIAS, + 0x40, 0x00); + } + + mutex_unlock(&aqt->master_bias_lock); + + return 0; +} + +static int aqt_disable_master_bias(struct aqt1000 *aqt) +{ + struct snd_soc_component *component = aqt->component; + + mutex_lock(&aqt->master_bias_lock); + if (aqt->master_bias_users <= 0) { + mutex_unlock(&aqt->master_bias_lock); + return -EINVAL; + } + + aqt->master_bias_users--; + if (aqt->master_bias_users == 0) + snd_soc_component_update_bits(component, AQT1000_ANA_BIAS, + 0x80, 0x00); + mutex_unlock(&aqt->master_bias_lock); + + return 0; +} + +static int aqt_cdc_req_mclk_enable(struct aqt1000 *aqt, + bool enable) +{ + int ret = 0; + + if (enable) { + ret = clk_prepare_enable(aqt->ext_clk); + if (ret) { + dev_err(aqt->dev, "%s: ext clk enable failed\n", + __func__); + goto done; + } + /* Get BG */ + aqt_enable_master_bias(aqt); + /* Get MCLK */ + aqt_enable_mclk(aqt); + } else { + /* put MCLK */ + aqt_disable_mclk(aqt); + /* put BG */ + if (aqt_disable_master_bias(aqt)) + dev_err(aqt->dev, "%s: master bias disable failed\n", + __func__); + clk_disable_unprepare(aqt->ext_clk); + } + +done: + return ret; +} + +static int __aqt_cdc_mclk_enable_locked(struct aqt1000 *aqt, + bool enable) +{ + int ret = 0; + + dev_dbg(aqt->dev, "%s: mclk_enable = %u\n", __func__, enable); + + if (enable) + ret = aqt_cdc_req_mclk_enable(aqt, true); + else + aqt_cdc_req_mclk_enable(aqt, false); + + return ret; +} + +static int __aqt_cdc_mclk_enable(struct aqt1000 *aqt, + bool enable) +{ + int ret; + + mutex_lock(&aqt->cdc_bg_clk_lock); + ret = __aqt_cdc_mclk_enable_locked(aqt, enable); + mutex_unlock(&aqt->cdc_bg_clk_lock); + + return ret; +} + +/** + * aqt_cdc_mclk_enable - Enable/disable codec mclk + * + * @component: codec component instance + * @enable: Indicates clk enable or disable + * + * Returns 0 on Success and error on failure + */ +int aqt_cdc_mclk_enable(struct snd_soc_component *component, bool enable) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + return __aqt_cdc_mclk_enable(aqt, enable); +} +EXPORT_SYMBOL(aqt_cdc_mclk_enable); + +/* + * aqt_get_micb_vout_ctl_val: converts micbias from volts to register value + * @micb_mv: micbias in mv + * + * return register value converted + */ +int aqt_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(aqt_get_micb_vout_ctl_val); + +static int aqt_set_micbias(struct aqt1000 *aqt, + struct aqt1000_pdata *pdata) +{ + struct snd_soc_component *component = aqt->component; + int vout_ctl_1; + + if (!pdata) { + dev_err(component->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl_1 = aqt_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + if (vout_ctl_1 < 0) + return -EINVAL; + + snd_soc_component_update_bits(component, AQT1000_ANA_MICB1, + 0x3F, vout_ctl_1); + + return 0; +} + +static ssize_t aqt_codec_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + char buffer[AQT_VERSION_ENTRY_SIZE]; + int len = 0; + + len = snprintf(buffer, sizeof(buffer), "AQT1000_1_0\n"); + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static struct snd_info_entry_ops aqt_codec_info_ops = { + .read = aqt_codec_version_read, +}; + +/* + * aqt_codec_info_create_codec_entry - creates aqt1000 module + * @codec_root: The parent directory + * @component: Codec component instance + * + * Creates aqt1000 module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int aqt_codec_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct aqt1000 *aqt; + struct snd_soc_card *card; + + if (!codec_root || !component) + return -EINVAL; + + aqt = snd_soc_component_get_drvdata(component); + if (!aqt) { + dev_dbg(component->dev, "%s: aqt is NULL\n", __func__); + return -EINVAL; + } + card = component->card; + aqt->entry = snd_info_create_subdir(codec_root->module, + "aqt1000", codec_root); + if (!aqt->entry) { + dev_dbg(component->dev, "%s: failed to create aqt1000 entry\n", + __func__); + return -ENOMEM; + } + + version_entry = snd_info_create_card_entry(card->snd_card, + "version", + aqt->entry); + if (!version_entry) { + dev_dbg(component->dev, "%s: failed to create aqt1000 version entry\n", + __func__); + return -ENOMEM; + } + + version_entry->private_data = aqt; + version_entry->size = AQT_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &aqt_codec_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + return -ENOMEM; + } + aqt->version_entry = version_entry; + + return 0; +} +EXPORT_SYMBOL(aqt_codec_info_create_codec_entry); + +static const struct aqt_reg_mask_val aqt_codec_reg_init[] = { + {AQT1000_CHIP_CFG0_EFUSE_CTL, 0x01, 0x01}, +}; + +static const struct aqt_reg_mask_val aqt_codec_reg_update[] = { + {AQT1000_LDOH_MODE, 0x1F, 0x0B}, + {AQT1000_MICB1_TEST_CTL_2, 0x07, 0x01}, + {AQT1000_MICB1_MISC_MICB1_INM_RES_BIAS, 0x03, 0x02}, + {AQT1000_MICB1_MISC_MICB1_INM_RES_BIAS, 0x0C, 0x08}, + {AQT1000_MICB1_MISC_MICB1_INM_RES_BIAS, 0x30, 0x20}, + {AQT1000_CDC_TX0_TX_PATH_CFG1, 0x01, 0x00}, + {AQT1000_CDC_TX1_TX_PATH_CFG1, 0x01, 0x00}, + {AQT1000_CDC_TX2_TX_PATH_CFG1, 0x01, 0x00}, +}; + +static void aqt_codec_init_reg(struct aqt1000 *priv) +{ + struct snd_soc_component *component = priv->component; + u32 i; + + for (i = 0; i < ARRAY_SIZE(aqt_codec_reg_init); i++) + snd_soc_component_update_bits(component, + aqt_codec_reg_init[i].reg, + aqt_codec_reg_init[i].mask, + aqt_codec_reg_init[i].val); +} + +static void aqt_codec_update_reg(struct aqt1000 *priv) +{ + struct snd_soc_component *component = priv->component; + u32 i; + + for (i = 0; i < ARRAY_SIZE(aqt_codec_reg_update); i++) + snd_soc_component_update_bits(component, + aqt_codec_reg_update[i].reg, + aqt_codec_reg_update[i].mask, + aqt_codec_reg_update[i].val); + +} + +static int aqt_soc_codec_probe(struct snd_soc_component *component) +{ + struct aqt1000 *aqt; + struct aqt1000_pdata *pdata; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int i, ret = 0; + + dev_dbg(component->dev, "%s()\n", __func__); + aqt = snd_soc_component_get_drvdata(component); + + snd_soc_component_init_regmap(component, aqt->regmap); + + mutex_init(&aqt->codec_mutex); + mutex_init(&aqt->i2s_lock); + /* Class-H Init */ + aqt_clsh_init(&aqt->clsh_d); + /* Default HPH Mode to Class-H Low HiFi */ + aqt->hph_mode = CLS_H_LOHIFI; + + aqt->fw_data = devm_kzalloc(component->dev, sizeof(*(aqt->fw_data)), + GFP_KERNEL); + if (!aqt->fw_data) + goto err; + + set_bit(WCD9XXX_ANC_CAL, aqt->fw_data->cal_bit); + set_bit(WCD9XXX_MBHC_CAL, aqt->fw_data->cal_bit); + + /* Register for Clock */ + aqt->ext_clk = clk_get(aqt->dev, "aqt_clk"); + if (IS_ERR(aqt->ext_clk)) { + dev_err(aqt->dev, "%s: clk get %s failed\n", + __func__, "aqt_ext_clk"); + goto err_clk; + } + + ret = wcd_cal_create_hwdep(aqt->fw_data, + AQT1000_CODEC_HWDEP_NODE, component); + if (ret < 0) { + dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret); + goto err_hwdep; + } + + /* Initialize MBHC module */ + ret = aqt_mbhc_init(&aqt->mbhc, component, aqt->fw_data); + if (ret) { + pr_err("%s: mbhc initialization failed\n", __func__); + goto err_hwdep; + } + aqt->component = component; + for (i = 0; i < COMPANDER_MAX; i++) + aqt->comp_enabled[i] = 0; + + aqt_cdc_mclk_enable(component, true); + aqt_codec_init_reg(aqt); + aqt_cdc_mclk_enable(component, false); + + /* Add 100usec delay as per HW requirement */ + usleep_range(100, 110); + + aqt_codec_update_reg(aqt); + + pdata = dev_get_platdata(component->dev); + + /* If 1.8v is supplied externally, then disable internal 1.8v supply */ + for (i = 0; i < pdata->num_supplies; i++) { + if (!strcmp(pdata->regulator->name, "aqt_vdd1p8")) { + snd_soc_component_update_bits(component, + AQT1000_BUCK_5V_EN_CTL, + 0x03, 0x00); + dev_dbg(component->dev, "%s: Disabled internal supply\n", + __func__); + break; + } + } + + aqt_set_micbias(aqt, pdata); + + snd_soc_dapm_add_routes(dapm, aqt_audio_map, + ARRAY_SIZE(aqt_audio_map)); + + for (i = 0; i < NUM_CODEC_DAIS; i++) { + INIT_LIST_HEAD(&aqt->dai[i].ch_list); + init_waitqueue_head(&aqt->dai[i].dai_wait); + } + + for (i = 0; i < AQT1000_NUM_DECIMATORS; i++) { + aqt->tx_hpf_work[i].aqt = aqt; + aqt->tx_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&aqt->tx_hpf_work[i].dwork, + aqt_tx_hpf_corner_freq_callback); + + aqt->tx_mute_dwork[i].aqt = aqt; + aqt->tx_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&aqt->tx_mute_dwork[i].dwork, + aqt_tx_mute_update_callback); + } + + mutex_lock(&aqt->codec_mutex); + snd_soc_dapm_disable_pin(dapm, "AQT ANC HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "AQT ANC HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "AQT ANC HPHL"); + snd_soc_dapm_disable_pin(dapm, "AQT ANC HPHR"); + mutex_unlock(&aqt->codec_mutex); + + snd_soc_dapm_ignore_suspend(dapm, "AQT AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AQT AIF1 Capture"); + + snd_soc_dapm_sync(dapm); + + return ret; + +err_hwdep: + clk_put(aqt->ext_clk); +err_clk: + devm_kfree(component->dev, aqt->fw_data); + aqt->fw_data = NULL; +err: + mutex_destroy(&aqt->i2s_lock); + mutex_destroy(&aqt->codec_mutex); + return ret; +} + +static void aqt_soc_codec_remove(struct snd_soc_component *component) +{ + struct aqt1000 *aqt = snd_soc_component_get_drvdata(component); + + /* Deinitialize MBHC module */ + aqt_mbhc_deinit(component); + aqt->mbhc = NULL; + mutex_destroy(&aqt->i2s_lock); + mutex_destroy(&aqt->codec_mutex); + clk_put(aqt->ext_clk); + + return; +} + +static const struct snd_soc_component_driver snd_cdc_dev_aqt = { + .name = DRV_NAME, + .probe = aqt_soc_codec_probe, + .remove = aqt_soc_codec_remove, + .controls = aqt_snd_controls, + .num_controls = ARRAY_SIZE(aqt_snd_controls), + .dapm_widgets = aqt_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aqt_dapm_widgets), + .dapm_routes = aqt_audio_map, + .num_dapm_routes = ARRAY_SIZE(aqt_audio_map), +}; + +/* + * aqt_register_codec: Register the device to ASoC + * @dev: device + * + * return 0 success or error code in case of failure + */ +int aqt_register_codec(struct device *dev) +{ + return snd_soc_register_component(dev, &snd_cdc_dev_aqt, aqt_dai, + ARRAY_SIZE(aqt_dai)); +} +EXPORT_SYMBOL(aqt_register_codec); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000.h new file mode 100644 index 0000000000..ebc646050f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/aqt1000.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef AQT1000_H +#define AQT1000_H + +#include +#include +#include +#include +#include "pdata.h" +#include "aqt1000-clsh.h" + +#define AQT1000_MAX_MICBIAS 1 +#define AQT1000_NUM_INTERPOLATORS 2 +#define AQT1000_NUM_DECIMATORS 3 +#define AQT1000_VOUT_CTL_TO_MICB(v) (1000 + v * 50) +#define AQT1000_RX_PATH_CTL_OFFSET 20 + +#define AQT1000_CLK_24P576MHZ 24576000 +#define AQT1000_CLK_19P2MHZ 19200000 +#define AQT1000_CLK_12P288MHZ 12288000 +#define AQT1000_CLK_9P6MHZ 9600000 + +#define AQT1000_ST_IIR_COEFF_MAX 5 + +enum { + AQT1000_RX0 = 0, + AQT1000_RX1, + AQT1000_RX_MAX, +}; + +enum { + AQT_NONE, + AQT_MCLK, + AQT_RCO, +}; + +enum { + AQT_TX0 = 0, + AQT_TX1, +}; + +enum { + ASRC0, + ASRC1, + ASRC_MAX, +}; + +/* Each IIR has 5 Filter Stages */ +enum { + BAND1 = 0, + BAND2, + BAND3, + BAND4, + BAND5, + BAND_MAX, +}; + +enum { + AQT1000_TX0 = 0, + AQT1000_TX1, + AQT1000_TX2, + AQT1000_TX_MAX, +}; + +enum { + INTERP_HPHL, + INTERP_HPHR, + INTERP_MAX, +}; + +enum { + INTERP_MAIN_PATH, + INTERP_MIX_PATH, +}; + +enum { + COMPANDER_1, /* HPH_L */ + COMPANDER_2, /* HPH_R */ + COMPANDER_MAX, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + NUM_CODEC_DAIS, +}; + +struct aqt_codec_dai_data { + u32 rate; + u32 *ch_num; + u32 ch_act; + u32 ch_tot; +}; + +struct aqt_idle_detect_config { + u8 hph_idle_thr; + u8 hph_idle_detect_en; +}; + +struct aqt1000_i2c { + struct i2c_client *client; + struct i2c_msg xfer_msg[2]; + struct mutex xfer_lock; + int mod_id; +}; + +struct aqt1000_cdc_dai_data { + u32 rate; /* sample rate */ + u32 bit_width; /* sit width 16,24,32 */ + struct list_head ch_list; + wait_queue_head_t dai_wait; +}; + +struct tx_mute_work { + struct aqt1000 *aqt; + u8 decimator; + struct delayed_work dwork; +}; + +struct hpf_work { + struct aqt1000 *aqt; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +struct aqt1000 { + struct device *dev; + struct mutex io_lock; + struct mutex xfer_lock; + struct mutex reset_lock; + + struct device_node *aqt_rst_np; + + int (*read_dev)(struct aqt1000 *aqt, unsigned short reg, + void *dest, int bytes); + int (*write_dev)(struct aqt1000 *aqt, unsigned short reg, + void *src, int bytes); + + u32 num_of_supplies; + struct regulator_bulk_data *supplies; + + u32 mclk_rate; + struct regmap *regmap; + struct snd_soc_component *component; + bool dev_up; + bool prev_pg_valid; + u8 prev_pg; + + struct aqt1000_i2c i2c_dev; + + /* Codec params */ + + /* ANC related */ + u32 anc_slot; + bool anc_func; + + /* compander */ + int comp_enabled[COMPANDER_MAX]; + + /* class h specific data */ + struct aqt_clsh_cdc_data clsh_d; + + /* Interpolator Mode Select for HPH_L and HPH_R */ + u32 hph_mode; + + unsigned long status_mask; + + struct aqt1000_cdc_dai_data dai[NUM_CODEC_DAIS]; + + struct mutex micb_lock; + + struct clk *ext_clk; + + /* mbhc module */ + struct aqt1000_mbhc *mbhc; + + struct mutex codec_mutex; + + /* cal info for codec */ + struct fw_info *fw_data; + + int native_clk_users; + /* ASRC users count */ + int asrc_users[ASRC_MAX]; + int asrc_output_mode[ASRC_MAX]; + /* Main path clock users count */ + int main_clk_users[AQT1000_NUM_INTERPOLATORS]; + + struct aqt_idle_detect_config idle_det_cfg; + u32 rx_bias_count; + + s32 micb_ref; + s32 pullup_ref; + int master_bias_users; + int mclk_users; + int i2s_users; + + struct hpf_work tx_hpf_work[AQT1000_NUM_DECIMATORS]; + struct tx_mute_work tx_mute_dwork[AQT1000_NUM_DECIMATORS]; + + struct mutex master_bias_lock; + struct mutex cdc_bg_clk_lock; + struct mutex i2s_lock; + + /* Interrupt */ + struct regmap_irq_chip_data *irq_chip; + int num_irq_regs; + struct irq_domain *virq; + int irq; + int irq_base; + + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; +}; + +#endif /* AQT1000_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/pdata.h b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/pdata.h new file mode 100644 index 0000000000..ba9e68f79f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/pdata.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _AQT1000_PDATA_H_ +#define _AQT1000_PDATA_H_ + +#include +#include +#include + +struct aqt1000_micbias_setting { + u8 ldoh_v; + u32 cfilt1_mv; + u32 micb1_mv; + u8 bias1_cfilt_sel; +}; + +struct aqt1000_pdata { + unsigned int irq_gpio; + unsigned int irq_flags; + struct cdc_regulator *regulator; + int num_supplies; + struct aqt1000_micbias_setting micbias; + struct device_node *aqt_rst_np; + u32 mclk_rate; + u32 ext_clk_rate; + u32 ext_1p8v_supply; +}; + +#endif /* _AQT1000_PDATA_H_ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk-up.c b/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk-up.c new file mode 100644 index 0000000000..5c3a9a4571 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk-up.c @@ -0,0 +1,773 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_AUDIO_PRM +#include +#else +#include "audio-ext-clk-up.h" +#endif +enum { + AUDIO_EXT_CLK_PMI, + AUDIO_EXT_CLK_LNBB2, + AUDIO_EXT_CLK_LPASS, + AUDIO_EXT_CLK_LPASS2, + AUDIO_EXT_CLK_LPASS3, + AUDIO_EXT_CLK_LPASS4, + AUDIO_EXT_CLK_LPASS5, + AUDIO_EXT_CLK_LPASS6, + AUDIO_EXT_CLK_LPASS7, + AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE, + AUDIO_EXT_CLK_LPASS8, + AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE, + AUDIO_EXT_CLK_LPASS9, + AUDIO_EXT_CLK_LPASS10, + AUDIO_EXT_CLK_LPASS11, + AUDIO_EXT_CLK_LPASS12, + AUDIO_EXT_CLK_LPASS13, + AUDIO_EXT_CLK_LPASS14, + AUDIO_EXT_CLK_LPASS15, + AUDIO_EXT_CLK_LPASS16, + AUDIO_EXT_CLK_LPASS_MAX, + AUDIO_EXT_CLK_EXTERNAL_PLL = AUDIO_EXT_CLK_LPASS_MAX, + AUDIO_EXT_CLK_MAX, +}; + +struct pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *sleep; + struct pinctrl_state *active; + char __iomem *base; +}; + +struct audio_ext_clk { + struct pinctrl_info pnctrl_info; + struct clk_fixed_factor fact; +}; + +struct audio_ext_clk_priv { + struct device *dev; + int clk_src; + uint32_t enable; +#ifdef CONFIG_AUDIO_PRM + struct clk_cfg prm_clk_cfg; +#endif + struct audio_ext_clk audio_clk; + const char *clk_name; + uint32_t lpass_core_hwvote_client_handle; + uint32_t lpass_audio_hwvote_client_handle; +}; + +static inline struct audio_ext_clk_priv *to_audio_clk(struct clk_hw *hw) +{ + return container_of(hw, struct audio_ext_clk_priv, audio_clk.fact.hw); +} + +static int audio_ext_clk_prepare(struct clk_hw *hw) +{ + struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); + struct pinctrl_info *pnctrl_info = &clk_priv->audio_clk.pnctrl_info; + int ret; + static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); + + if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) && + (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX) && !clk_priv->enable) { +#ifdef CONFIG_AUDIO_PRM + pr_debug("%s: clk_id %x ", __func__, clk_priv->prm_clk_cfg.clk_id); + ret = audio_prm_set_lpass_clk_cfg(&clk_priv->prm_clk_cfg,1); +#else + pr_debug("%s: audio prm not enabled", __func__); + ret = -EPERM; +#endif + if (ret < 0) { + if (__ratelimit(&rtl)) + pr_err_ratelimited("%s prm set lpass clk failed\n", + __func__); + return ret; + } + clk_priv->enable = 1; + } + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + } + + if (pnctrl_info->base) + iowrite32(1, pnctrl_info->base); + return 0; +} + +static void audio_ext_clk_unprepare(struct clk_hw *hw) +{ + struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); + struct pinctrl_info *pnctrl_info = &clk_priv->audio_clk.pnctrl_info; + int ret; + static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); + + if (pnctrl_info->pinctrl) { + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return; + } + } + + if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) && + (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { + clk_priv->enable = 0; +#ifdef CONFIG_AUDIO_PRM + pr_debug("%s: clk_id %x", __func__, + clk_priv->prm_clk_cfg.clk_id); + ret = audio_prm_set_lpass_clk_cfg(&clk_priv->prm_clk_cfg, 0); +#else + pr_debug("%s: audio prm not enabled", __func__); + ret = -EPERM; +#endif + if (ret < 0) { + if (__ratelimit(&rtl)) + pr_err_ratelimited("%s: unset lpass clk cfg failed, ret = %d\n", + __func__, ret); + } + } + + if (pnctrl_info->base) + iowrite32(0, pnctrl_info->base); +} + +static u8 audio_ext_clk_get_parent(struct clk_hw *hw) +{ + struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); + int num_parents = clk_hw_get_num_parents(hw); + const char * const *parent_names = hw->init->parent_names; + u8 i = 0, ret = hw->init->num_parents + 1; + + if ((clk_priv->clk_src == AUDIO_EXT_CLK_PMI) && clk_priv->clk_name) { + for (i = 0; i < num_parents; i++) { + if (!strcmp(parent_names[i], clk_priv->clk_name)) + ret = i; + } + pr_debug("%s: parent index = %u\n", __func__, ret); + return ret; + } else + return 0; +} + +static int lpass_hw_vote_prepare(struct clk_hw *hw) +{ + struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); + int ret; + static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); + + if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) { +#ifdef CONFIG_AUDIO_PRM + pr_debug("%s: core vote clk_id %x \n", __func__, clk_priv->prm_clk_cfg.clk_id); + ret = audio_prm_set_lpass_hw_core_req(&clk_priv->prm_clk_cfg, + HW_CORE_ID_LPASS, 1); +#else + pr_debug("%s: audio prm not enabled", __func__); + ret = -EPERM; +#endif + if (ret < 0) { + if (__ratelimit(&rtl)) + pr_err("%s lpass core hw vote failed %d\n", + __func__, ret); + return ret; + } + } + + if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) { +#ifdef CONFIG_AUDIO_PRM + pr_debug("%s: audio vote clk_id %x \n", __func__, clk_priv->prm_clk_cfg.clk_id); + ret = audio_prm_set_lpass_hw_core_req(&clk_priv->prm_clk_cfg, + HW_CORE_ID_DCODEC, 1); +#else + pr_debug("%s: audio prm not enabled", __func__); + ret = -EPERM; +#endif + if (ret < 0) { + if (__ratelimit(&rtl)) + pr_err("%s lpass audio hw vote failed %d\n", + __func__, ret); + return ret; + } + } + + return 0; +} + +static void lpass_hw_vote_unprepare(struct clk_hw *hw) +{ + struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); + int ret = 0; + + if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) { +#ifdef CONFIG_AUDIO_PRM + pr_debug("%s: core vote clk_id %x \n", __func__, clk_priv->prm_clk_cfg.clk_id); + ret = audio_prm_set_lpass_hw_core_req(&clk_priv->prm_clk_cfg, + HW_CORE_ID_LPASS, 0); +#else + pr_debug("%s: audio prm not enabled", __func__); + ret = -EPERM; +#endif + if (ret < 0) { + pr_err("%s lpass core hw vote failed %d\n", + __func__, ret); + } + } + + if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) { + +#ifdef CONFIG_AUDIO_PRM + pr_debug("%s: audio vote clk_id %x \n", __func__, clk_priv->prm_clk_cfg.clk_id); + ret = audio_prm_set_lpass_hw_core_req(&clk_priv->prm_clk_cfg, + HW_CORE_ID_DCODEC, 0); +#else + pr_debug("%s: audio prm not enabled", __func__); + ret = -EPERM; +#endif + if (ret < 0) { + pr_err("%s lpass audio hw unvote failed %d\n", + __func__, ret); + } + } +} + +static const struct clk_ops audio_ext_clk_ops = { + .prepare = audio_ext_clk_prepare, + .unprepare = audio_ext_clk_unprepare, + .get_parent = audio_ext_clk_get_parent, +}; + +static const struct clk_ops lpass_hw_vote_ops = { + .prepare = lpass_hw_vote_prepare, + .unprepare = lpass_hw_vote_unprepare, +}; + +static const char * const audio_ext_pmi_div_clk[] = { + "qpnp_clkdiv_1", + "pms405_div_clk1", + "pm6150_div_clk1", + "pm6125_div_clk1", +}; + +static int audio_ext_clk_dummy_prepare(struct clk_hw *hw) +{ + return 0; +} + +static void audio_ext_clk_dummy_unprepare(struct clk_hw *hw) +{ + +} + +static const struct clk_ops audio_ext_clk_dummy_ops = { + .prepare = audio_ext_clk_dummy_prepare, + .unprepare = audio_ext_clk_dummy_unprepare, +}; + +static struct audio_ext_clk audio_clk_array[] = { + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ext_pmi_clk", + .parent_names = audio_ext_pmi_div_clk, + .num_parents = + ARRAY_SIZE(audio_ext_pmi_div_clk), + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_ext_pmi_lnbb_clk", + .parent_names = (const char *[]) + { "ln_bb_clk2" }, + .num_parents = 1, + .ops = &audio_ext_clk_dummy_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk2", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk3", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk4", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk5", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk6", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk7", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .hw.init = &(struct clk_init_data){ + .name = "lpass_hw_vote_clk", + .ops = &lpass_hw_vote_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk8", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .hw.init = &(struct clk_init_data){ + .name = "lpass_audio_hw_vote_clk", + .ops = &lpass_hw_vote_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk9", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk10", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk11", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk12", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk13", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk14", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk15", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_lpass_mclk16", + .ops = &audio_ext_clk_ops, + }, + }, + }, + { + .pnctrl_info = {NULL}, + .fact = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "audio_external_pll_clk", + .ops = &audio_ext_clk_ops, + }, + }, + }, +}; + +static int audio_get_pinctrl(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev); + struct pinctrl_info *pnctrl_info; + struct pinctrl *pinctrl; + int ret; + u32 reg; + + pnctrl_info = &clk_priv->audio_clk.pnctrl_info; + if (pnctrl_info->pinctrl) { + dev_err(dev, "%s: already requested before\n", + __func__); + return -EINVAL; + } + + pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(pinctrl)) { + dev_err(dev, "%s: Unable to get pinctrl handle\n", + __func__); + return -EINVAL; + } + pnctrl_info->pinctrl = pinctrl; + /* get all state handles from Device Tree */ + pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep"); + if (IS_ERR(pnctrl_info->sleep)) { + dev_err(dev, "%s: could not get sleep pinstate\n", + __func__); + goto err; + } + pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active"); + if (IS_ERR(pnctrl_info->active)) { + dev_err(dev, "%s: could not get active pinstate\n", + __func__); + goto err; + } + /* Reset the TLMM pins to a default state */ + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) { + dev_err(dev, "%s: Disable TLMM pins failed with %d\n", + __func__, ret); + goto err; + } + + ret = of_property_read_u32(dev->of_node, "qcom,mclk-clk-reg", ®); + if (ret < 0) { + dev_dbg(dev, "%s: miss mclk reg\n", __func__); + } else { + pnctrl_info->base = ioremap(reg, sizeof(u32)); + if (pnctrl_info->base == NULL) { + dev_err(dev, "%s ioremap failed\n", __func__); + goto err; + } + } + + return 0; + +err: + devm_pinctrl_put(pnctrl_info->pinctrl); + return -EINVAL; +} + +static int audio_put_pinctrl(struct platform_device *pdev) +{ + struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev); + struct pinctrl_info *pnctrl_info = NULL; + + pnctrl_info = &clk_priv->audio_clk.pnctrl_info; + if (pnctrl_info && pnctrl_info->pinctrl) { + devm_pinctrl_put(pnctrl_info->pinctrl); + pnctrl_info->pinctrl = NULL; + } + + return 0; +} + +static int audio_get_clk_data(struct platform_device *pdev) +{ + int ret; + struct clk *audio_clk; + struct clk_hw *clkhw; + struct clk_onecell_data *clk_data; + struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev); + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clk_num = 1; + clk_data->clks = devm_kzalloc(&pdev->dev, + sizeof(struct clk *), + GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clkhw = &clk_priv->audio_clk.fact.hw; + audio_clk = devm_clk_register(&pdev->dev, clkhw); + if (IS_ERR(audio_clk)) { + dev_err(&pdev->dev, + "%s: clock register failed for clk_src = %d\\n", + __func__, clk_priv->clk_src); + ret = PTR_ERR(audio_clk); + return ret; + } + clk_data->clks[0] = audio_clk; + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (ret) + dev_err(&pdev->dev, "%s: clock add failed for clk_src = %d\n", + __func__, clk_priv->clk_src); + + return ret; +} + +static int audio_ref_clk_probe(struct platform_device *pdev) +{ + int ret; + struct audio_ext_clk_priv *clk_priv; + u32 clk_freq = 0, clk_id = 0, clk_src = 0, use_pinctrl = 0; + + clk_priv = devm_kzalloc(&pdev->dev, sizeof(*clk_priv), GFP_KERNEL); + if (!clk_priv) + return -ENOMEM; + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,codec-ext-clk-src", + &clk_src); + if (ret) { + dev_err(&pdev->dev, "%s: could not get clk source, ret = %d\n", + __func__, ret); + return ret; + } + + if (clk_src >= AUDIO_EXT_CLK_MAX) { + dev_err(&pdev->dev, "%s: Invalid clk source = %d\n", + __func__, clk_src); + return -EINVAL; + } + clk_priv->clk_name = NULL; + clk_priv->clk_src = clk_src; + memcpy(&clk_priv->audio_clk, &audio_clk_array[clk_src], + sizeof(struct audio_ext_clk)); + +#ifdef CONFIG_AUDIO_PRM + /* Init prm clk cfg default values */ + clk_priv->prm_clk_cfg.clk_id = CLOCK_ID_QUI_MI2S_OSR; + clk_priv->prm_clk_cfg.clk_freq_in_hz = OSR_CLOCK_9_P600_MHZ; + clk_priv->prm_clk_cfg.clk_attri = CLOCK_ATTRIBUTE_COUPLE_NO; + clk_priv->prm_clk_cfg.clk_root = 0; +#endif + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,codec-lpass-ext-clk-freq", + &clk_freq); + if (!ret) { +#ifdef CONFIG_AUDIO_PRM + clk_priv->prm_clk_cfg.clk_freq_in_hz = clk_freq; +#endif + } + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,codec-lpass-clk-id", + &clk_id); + if (!ret) { +#ifdef CONFIG_AUDIO_PRM + clk_priv->prm_clk_cfg.clk_id = clk_id; + dev_dbg(&pdev->dev, "%s: PRM ext-clk freq: %d, lpass clk_id: %d, clk_src: %d\n", + __func__, clk_priv->prm_clk_cfg.clk_freq_in_hz, + clk_priv->prm_clk_cfg.clk_id, clk_priv->clk_src); +#endif + } + + dev_dbg(&pdev->dev, "%s: PRM2 ext-clk freq: %d, lpass clk_id: %d, clk_src: %d\n", + __func__, clk_priv->prm_clk_cfg.clk_freq_in_hz, + clk_priv->prm_clk_cfg.clk_id, clk_priv->clk_src); + + platform_set_drvdata(pdev, clk_priv); + + ret = of_property_read_string(pdev->dev.of_node, "pmic-clock-names", + &clk_priv->clk_name); + if (ret) + dev_dbg(&pdev->dev, "%s: could not find pmic clock names\n", + __func__); + /* + * property qcom,use-pinctrl to be defined in DTSI to val 1 + * for clock nodes using pinctrl + */ + of_property_read_u32(pdev->dev.of_node, "qcom,use-pinctrl", + &use_pinctrl); + dev_dbg(&pdev->dev, "%s: use-pinctrl : %d\n", + __func__, use_pinctrl); + + if (use_pinctrl) { + ret = audio_get_pinctrl(pdev); + if (ret) { + dev_err(&pdev->dev, "%s: Parsing PMI pinctrl failed\n", + __func__); + return ret; + } + } + + ret = audio_get_clk_data(pdev); + if (ret) { + dev_err(&pdev->dev, "%s: clk_init is failed\n", + __func__); + audio_put_pinctrl(pdev); + return ret; + } + return 0; +} + +static int audio_ref_clk_remove(struct platform_device *pdev) +{ + audio_put_pinctrl(pdev); + + return 0; +} + +static const struct of_device_id audio_ref_clk_match[] = { + {.compatible = "qcom,audio-ref-clk"}, + {} +}; +MODULE_DEVICE_TABLE(of, audio_ref_clk_match); + +static struct platform_driver audio_ref_clk_driver = { + .driver = { + .name = "audio-ref-clk", + .owner = THIS_MODULE, + .of_match_table = audio_ref_clk_match, + .suppress_bind_attrs = true, + }, + .probe = audio_ref_clk_probe, + .remove = audio_ref_clk_remove, +}; + +int audio_ref_clk_platform_init(void) +{ + return platform_driver_register(&audio_ref_clk_driver); +} + +void audio_ref_clk_platform_exit(void) +{ + platform_driver_unregister(&audio_ref_clk_driver); +} + +MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk-up.h b/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk-up.h new file mode 100644 index 0000000000..e7c195405e --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk-up.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef __AUDIO_EXT_CLK_UP_H_ +#define __AUDIO_EXT_CLK_UP_H_ + +int audio_ref_clk_platform_init(void); +void audio_ref_clk_platform_exit(void); + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk.c b/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk.c new file mode 100644 index 0000000000..adcd7a6ee6 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/audio-ext-clk.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2017, 2019 The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audio-ext-clk-up.h" + +struct pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *sleep; + struct pinctrl_state *active; +}; + +struct audio_ext_ap_clk { + bool enabled; + int gpio; + struct clk c; +}; + +struct audio_ext_pmi_clk { + int gpio; + struct clk c; +}; + +struct audio_ext_ap_clk2 { + bool enabled; + struct pinctrl_info pnctrl_info; + struct clk c; +}; + +static struct afe_clk_set clk2_config = { + Q6AFE_LPASS_CLK_CONFIG_API_VERSION, + Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR, + Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; + +static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk *clk) +{ + return container_of(clk, struct audio_ext_ap_clk, c); +} + +static int audio_ext_clk_prepare(struct clk *clk) +{ + struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(clk); + + pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio); + if (gpio_is_valid(audio_clk->gpio)) + return gpio_direction_output(audio_clk->gpio, 1); + return 0; +} + +static void audio_ext_clk_unprepare(struct clk *clk) +{ + struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(clk); + + pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio); + if (gpio_is_valid(audio_clk->gpio)) + gpio_direction_output(audio_clk->gpio, 0); +} + +static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk *clk) +{ + return container_of(clk, struct audio_ext_ap_clk2, c); +} + +static int audio_ext_clk2_prepare(struct clk *clk) +{ + struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(clk); + struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info; + int ret; + + + if (!pnctrl_info->pinctrl || !pnctrl_info->active) + return 0; + + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->active); + if (ret) { + pr_err("%s: active state select failed with %d\n", + __func__, ret); + return -EIO; + } + + clk2_config.enable = 1; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config); + if (ret < 0) { + pr_err("%s: failed to set clock, ret = %d\n", __func__, ret); + return -EINVAL; + } + + return 0; +} + +static void audio_ext_clk2_unprepare(struct clk *clk) +{ + struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(clk); + struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info; + int ret; + + if (!pnctrl_info->pinctrl || !pnctrl_info->sleep) + return; + + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) + pr_err("%s: sleep state select failed with %d\n", + __func__, ret); + + clk2_config.enable = 0; + ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config); + if (ret < 0) + pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret); +} + +static const struct clk_ops audio_ext_ap_clk_ops = { + .prepare = audio_ext_clk_prepare, + .unprepare = audio_ext_clk_unprepare, +}; + +static const struct clk_ops audio_ext_ap_clk2_ops = { + .prepare = audio_ext_clk2_prepare, + .unprepare = audio_ext_clk2_unprepare, +}; + +static struct audio_ext_pmi_clk audio_pmi_clk = { + .gpio = -EINVAL, + .c = { + .dbg_name = "audio_ext_pmi_clk", + .ops = &clk_ops_dummy, + CLK_INIT(audio_pmi_clk.c), + }, +}; + +static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = { + .gpio = -EINVAL, + .c = { + .dbg_name = "audio_ext_pmi_lnbb_clk", + .ops = &clk_ops_dummy, + CLK_INIT(audio_pmi_lnbb_clk.c), + }, +}; + +static struct audio_ext_ap_clk audio_ap_clk = { + .gpio = -EINVAL, + .c = { + .dbg_name = "audio_ext_ap_clk", + .ops = &audio_ext_ap_clk_ops, + CLK_INIT(audio_ap_clk.c), + }, +}; + +static struct audio_ext_ap_clk2 audio_ap_clk2 = { + .c = { + .dbg_name = "audio_ext_ap_clk2", + .ops = &audio_ext_ap_clk2_ops, + CLK_INIT(audio_ap_clk2.c), + }, +}; + +static struct clk_lookup audio_ref_clock[] = { + CLK_LIST(audio_ap_clk), + CLK_LIST(audio_pmi_clk), + CLK_LIST(audio_pmi_lnbb_clk), + CLK_LIST(audio_ap_clk2), +}; + +static int audio_get_pinctrl(struct platform_device *pdev) +{ + struct pinctrl_info *pnctrl_info; + struct pinctrl *pinctrl; + int ret; + + pnctrl_info = &audio_ap_clk2.pnctrl_info; + + if (pnctrl_info->pinctrl) { + dev_dbg(&pdev->dev, "%s: already requested before\n", + __func__); + return -EINVAL; + } + + pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n", + __func__); + return -EINVAL; + } + pnctrl_info->pinctrl = pinctrl; + /* get all state handles from Device Tree */ + pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep"); + if (IS_ERR(pnctrl_info->sleep)) { + dev_err(&pdev->dev, "%s: could not get sleep pinstate\n", + __func__); + goto err; + } + pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active"); + if (IS_ERR(pnctrl_info->active)) { + dev_err(&pdev->dev, "%s: could not get active pinstate\n", + __func__); + goto err; + } + /* Reset the TLMM pins to a default state */ + ret = pinctrl_select_state(pnctrl_info->pinctrl, + pnctrl_info->sleep); + if (ret) { + dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n", + __func__, ret); + goto err; + } + return 0; + +err: + devm_pinctrl_put(pnctrl_info->pinctrl); + return -EINVAL; +} + +static int audio_ref_clk_probe(struct platform_device *pdev) +{ + int clk_gpio; + int ret; + struct clk *audio_clk; + + clk_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,audio-ref-clk-gpio", 0); + if (clk_gpio > 0) { + ret = gpio_request(clk_gpio, "EXT_CLK"); + if (ret) { + dev_err(&pdev->dev, + "Request ext clk gpio failed %d, err:%d\n", + clk_gpio, ret); + goto err; + } + if (of_property_read_bool(pdev->dev.of_node, + "qcom,node_has_rpm_clock")) { + audio_clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(audio_clk)) { + dev_err(&pdev->dev, "Failed to get RPM div clk\n"); + ret = PTR_ERR(audio_clk); + goto err_gpio; + } + audio_pmi_clk.c.parent = audio_clk; + audio_pmi_clk.gpio = clk_gpio; + } else + audio_ap_clk.gpio = clk_gpio; + + } else { + if (of_property_read_bool(pdev->dev.of_node, + "qcom,node_has_rpm_clock")) { + audio_clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(audio_clk)) { + dev_err(&pdev->dev, "Failed to get lnbbclk2\n"); + ret = PTR_ERR(audio_clk); + goto err; + } + audio_pmi_lnbb_clk.c.parent = audio_clk; + audio_pmi_lnbb_clk.gpio = -EINVAL; + } + } + + ret = audio_get_pinctrl(pdev); + if (ret) + dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n", + __func__); + + ret = of_msm_clock_register(pdev->dev.of_node, audio_ref_clock, + ARRAY_SIZE(audio_ref_clock)); + if (ret) { + dev_err(&pdev->dev, "%s: audio ref clock register failed\n", + __func__); + goto err_gpio; + } + + return 0; + +err_gpio: + gpio_free(clk_gpio); + +err: + return ret; +} + +static int audio_ref_clk_remove(struct platform_device *pdev) +{ + struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info; + + if (audio_pmi_clk.gpio > 0) + gpio_free(audio_pmi_clk.gpio); + else if (audio_ap_clk.gpio > 0) + gpio_free(audio_ap_clk.gpio); + + if (pnctrl_info->pinctrl) { + devm_pinctrl_put(pnctrl_info->pinctrl); + pnctrl_info->pinctrl = NULL; + } + + return 0; +} + +static const struct of_device_id audio_ref_clk_match[] = { + {.compatible = "qcom,audio-ref-clk"}, + {} +}; +MODULE_DEVICE_TABLE(of, audio_ref_clk_match); + +static struct platform_driver audio_ref_clk_driver = { + .driver = { + .name = "audio-ref-clk", + .owner = THIS_MODULE, + .of_match_table = audio_ref_clk_match, + .suppress_bind_attrs = true, + }, + .probe = audio_ref_clk_probe, + .remove = audio_ref_clk_remove, +}; + +int audio_ref_clk_platform_init(void) +{ + return platform_driver_register(&audio_ref_clk_driver); +} + +void audio_ref_clk_platform_exit(void) +{ + platform_driver_unregister(&audio_ref_clk_driver); +} + +MODULE_DESCRIPTION("Audio Ref Clock module platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/bolero/Kbuild new file mode 100644 index 0000000000..b0e45e1391 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/Kbuild @@ -0,0 +1,163 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_TRINKET), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_HOLI), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_BLAIR), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_KHAJE), y) + include $(AUDIO_ROOT)/config/bengalauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h + endif + ifeq ($(CONFIG_ARCH_QCS405), y) + include $(AUDIO_ROOT)/config/qcs405auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/qcs405autoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ BOLERO ############ + +# for BOLERO Codec +ifdef CONFIG_SND_SOC_BOLERO + BOLERO_OBJS += bolero-cdc.o + BOLERO_OBJS += bolero-cdc-utils.o + BOLERO_OBJS += bolero-cdc-regmap.o + BOLERO_OBJS += bolero-cdc-tables.o + BOLERO_OBJS += bolero-clk-rsc.o +endif + +ifdef CONFIG_WSA_MACRO + WSA_OBJS += wsa-macro.o +endif + +ifdef CONFIG_VA_MACRO + VA_OBJS += va-macro.o +endif + +ifdef CONFIG_TX_MACRO + TX_OBJS += tx-macro.o +endif + +ifdef CONFIG_RX_MACRO + RX_OBJS += rx-macro.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 + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_BOLERO) += bolero_cdc_dlkm.o +bolero_cdc_dlkm-y := $(BOLERO_OBJS) + +obj-$(CONFIG_WSA_MACRO) += wsa_macro_dlkm.o +wsa_macro_dlkm-y := $(WSA_OBJS) + +obj-$(CONFIG_VA_MACRO) += va_macro_dlkm.o +va_macro_dlkm-y := $(VA_OBJS) + +obj-$(CONFIG_TX_MACRO) += tx_macro_dlkm.o +tx_macro_dlkm-y := $(TX_OBJS) + +obj-$(CONFIG_RX_MACRO) += rx_macro_dlkm.o +rx_macro_dlkm-y := $(RX_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/Makefile b/qcom/opensource/audio-kernel/asoc/codecs/bolero/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-registers.h new file mode 100644 index 0000000000..c1c9b13aa9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-registers.h @@ -0,0 +1,844 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _BOLERO_CDC_REGISTERS_H +#define _BOLERO_CDC_REGISTERS_H + +#define TX_START_OFFSET 0x0000 + +#define BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL (TX_START_OFFSET + 0x0000) +#define BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL (TX_START_OFFSET + 0x0004) +#define BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL (TX_START_OFFSET + 0x0008) +#define BOLERO_CDC_TX_TOP_CSR_TOP_CFG0 (TX_START_OFFSET + 0x0080) +#define BOLERO_CDC_TX_TOP_CSR_ANC_CFG (TX_START_OFFSET + 0x0084) +#define BOLERO_CDC_TX_TOP_CSR_SWR_CTRL (TX_START_OFFSET + 0x0088) +#define BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK (TX_START_OFFSET + 0x0090) +#define BOLERO_CDC_TX_TOP_CSR_DEBUG_BUS (TX_START_OFFSET + 0x0094) +#define BOLERO_CDC_TX_TOP_CSR_DEBUG_EN (TX_START_OFFSET + 0x0098) +#define BOLERO_CDC_TX_TOP_CSR_TX_I2S_CTL (TX_START_OFFSET + 0x00A4) +#define BOLERO_CDC_TX_TOP_CSR_I2S_CLK (TX_START_OFFSET + 0x00A8) +#define BOLERO_CDC_TX_TOP_CSR_I2S_RESET (TX_START_OFFSET + 0x00AC) +#define BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL (TX_START_OFFSET + 0x00C0) +#define BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL (TX_START_OFFSET + 0x00C4) +#define BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL (TX_START_OFFSET + 0x00C8) +#define BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL (TX_START_OFFSET + 0x00CC) +#define BOLERO_CDC_TX_TOP_CSR_SWR_AMIC0_CTL (TX_START_OFFSET + 0x00D0) +#define BOLERO_CDC_TX_TOP_CSR_SWR_AMIC1_CTL (TX_START_OFFSET + 0x00D4) +#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC2_CTL (TX_START_OFFSET + 0x00C0) +#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC3_CTL (TX_START_OFFSET + 0x00C4) +#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC4_CTL (TX_START_OFFSET + 0x00C8) +#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC5_CTL (TX_START_OFFSET + 0x00CC) +#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC0_CTL (TX_START_OFFSET + 0x00D0) +#define BOLERO_CDC_TX_TOP_CSR_SWR_MIC1_CTL (TX_START_OFFSET + 0x00D4) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 (TX_START_OFFSET + 0x0100) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 (TX_START_OFFSET + 0x0104) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0 (TX_START_OFFSET + 0x0108) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG1 (TX_START_OFFSET + 0x010C) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0 (TX_START_OFFSET + 0x0110) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG1 (TX_START_OFFSET + 0x0114) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0 (TX_START_OFFSET + 0x0118) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG1 (TX_START_OFFSET + 0x011C) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0 (TX_START_OFFSET + 0x0120) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG1 (TX_START_OFFSET + 0x0124) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0 (TX_START_OFFSET + 0x0128) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG1 (TX_START_OFFSET + 0x012C) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0 (TX_START_OFFSET + 0x0130) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG1 (TX_START_OFFSET + 0x0134) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0 (TX_START_OFFSET + 0x0138) +#define BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG1 (TX_START_OFFSET + 0x013C) +#define BOLERO_CDC_TX_ANC0_CLK_RESET_CTL (TX_START_OFFSET + 0x0200) +#define BOLERO_CDC_TX_ANC0_MODE_1_CTL (TX_START_OFFSET + 0x0204) +#define BOLERO_CDC_TX_ANC0_MODE_2_CTL (TX_START_OFFSET + 0x0208) +#define BOLERO_CDC_TX_ANC0_FF_SHIFT (TX_START_OFFSET + 0x020C) +#define BOLERO_CDC_TX_ANC0_FB_SHIFT (TX_START_OFFSET + 0x0210) +#define BOLERO_CDC_TX_ANC0_LPF_FF_A_CTL (TX_START_OFFSET + 0x0214) +#define BOLERO_CDC_TX_ANC0_LPF_FF_B_CTL (TX_START_OFFSET + 0x0218) +#define BOLERO_CDC_TX_ANC0_LPF_FB_CTL (TX_START_OFFSET + 0x021C) +#define BOLERO_CDC_TX_ANC0_SMLPF_CTL (TX_START_OFFSET + 0x0220) +#define BOLERO_CDC_TX_ANC0_DCFLT_SHIFT_CTL (TX_START_OFFSET + 0x0224) +#define BOLERO_CDC_TX_ANC0_IIR_ADAPT_CTL (TX_START_OFFSET + 0x0228) +#define BOLERO_CDC_TX_ANC0_IIR_COEFF_1_CTL (TX_START_OFFSET + 0x022C) +#define BOLERO_CDC_TX_ANC0_IIR_COEFF_2_CTL (TX_START_OFFSET + 0x0230) +#define BOLERO_CDC_TX_ANC0_FF_A_GAIN_CTL (TX_START_OFFSET + 0x0234) +#define BOLERO_CDC_TX_ANC0_FF_B_GAIN_CTL (TX_START_OFFSET + 0x0238) +#define BOLERO_CDC_TX_ANC0_FB_GAIN_CTL (TX_START_OFFSET + 0x023C) +#define BOLERO_CDC_TX0_TX_PATH_CTL (TX_START_OFFSET + 0x0400) +#define BOLERO_CDC_TX0_TX_PATH_CFG0 (TX_START_OFFSET + 0x0404) +#define BOLERO_CDC_TX0_TX_PATH_CFG1 (TX_START_OFFSET + 0x0408) +#define BOLERO_CDC_TX0_TX_VOL_CTL (TX_START_OFFSET + 0x040C) +#define BOLERO_CDC_TX0_TX_PATH_SEC0 (TX_START_OFFSET + 0x0410) +#define BOLERO_CDC_TX0_TX_PATH_SEC1 (TX_START_OFFSET + 0x0414) +#define BOLERO_CDC_TX0_TX_PATH_SEC2 (TX_START_OFFSET + 0x0418) +#define BOLERO_CDC_TX0_TX_PATH_SEC3 (TX_START_OFFSET + 0x041C) +#define BOLERO_CDC_TX0_TX_PATH_SEC4 (TX_START_OFFSET + 0x0420) +#define BOLERO_CDC_TX0_TX_PATH_SEC5 (TX_START_OFFSET + 0x0424) +#define BOLERO_CDC_TX0_TX_PATH_SEC6 (TX_START_OFFSET + 0x0428) +#define BOLERO_CDC_TX0_TX_PATH_SEC7 (TX_START_OFFSET + 0x042C) +#define BOLERO_CDC_TX1_TX_PATH_CTL (TX_START_OFFSET + 0x0480) +#define BOLERO_CDC_TX1_TX_PATH_CFG0 (TX_START_OFFSET + 0x0484) +#define BOLERO_CDC_TX1_TX_PATH_CFG1 (TX_START_OFFSET + 0x0488) +#define BOLERO_CDC_TX1_TX_VOL_CTL (TX_START_OFFSET + 0x048C) +#define BOLERO_CDC_TX1_TX_PATH_SEC0 (TX_START_OFFSET + 0x0490) +#define BOLERO_CDC_TX1_TX_PATH_SEC1 (TX_START_OFFSET + 0x0494) +#define BOLERO_CDC_TX1_TX_PATH_SEC2 (TX_START_OFFSET + 0x0498) +#define BOLERO_CDC_TX1_TX_PATH_SEC3 (TX_START_OFFSET + 0x049C) +#define BOLERO_CDC_TX1_TX_PATH_SEC4 (TX_START_OFFSET + 0x04A0) +#define BOLERO_CDC_TX1_TX_PATH_SEC5 (TX_START_OFFSET + 0x04A4) +#define BOLERO_CDC_TX1_TX_PATH_SEC6 (TX_START_OFFSET + 0x04A8) +#define BOLERO_CDC_TX2_TX_PATH_CTL (TX_START_OFFSET + 0x0500) +#define BOLERO_CDC_TX2_TX_PATH_CFG0 (TX_START_OFFSET + 0x0504) +#define BOLERO_CDC_TX2_TX_PATH_CFG1 (TX_START_OFFSET + 0x0508) +#define BOLERO_CDC_TX2_TX_VOL_CTL (TX_START_OFFSET + 0x050C) +#define BOLERO_CDC_TX2_TX_PATH_SEC0 (TX_START_OFFSET + 0x0510) +#define BOLERO_CDC_TX2_TX_PATH_SEC1 (TX_START_OFFSET + 0x0514) +#define BOLERO_CDC_TX2_TX_PATH_SEC2 (TX_START_OFFSET + 0x0518) +#define BOLERO_CDC_TX2_TX_PATH_SEC3 (TX_START_OFFSET + 0x051C) +#define BOLERO_CDC_TX2_TX_PATH_SEC4 (TX_START_OFFSET + 0x0520) +#define BOLERO_CDC_TX2_TX_PATH_SEC5 (TX_START_OFFSET + 0x0524) +#define BOLERO_CDC_TX2_TX_PATH_SEC6 (TX_START_OFFSET + 0x0528) +#define BOLERO_CDC_TX3_TX_PATH_CTL (TX_START_OFFSET + 0x0580) +#define BOLERO_CDC_TX3_TX_PATH_CFG0 (TX_START_OFFSET + 0x0584) +#define BOLERO_CDC_TX3_TX_PATH_CFG1 (TX_START_OFFSET + 0x0588) +#define BOLERO_CDC_TX3_TX_VOL_CTL (TX_START_OFFSET + 0x058C) +#define BOLERO_CDC_TX3_TX_PATH_SEC0 (TX_START_OFFSET + 0x0590) +#define BOLERO_CDC_TX3_TX_PATH_SEC1 (TX_START_OFFSET + 0x0594) +#define BOLERO_CDC_TX3_TX_PATH_SEC2 (TX_START_OFFSET + 0x0598) +#define BOLERO_CDC_TX3_TX_PATH_SEC3 (TX_START_OFFSET + 0x059C) +#define BOLERO_CDC_TX3_TX_PATH_SEC4 (TX_START_OFFSET + 0x05A0) +#define BOLERO_CDC_TX3_TX_PATH_SEC5 (TX_START_OFFSET + 0x05A4) +#define BOLERO_CDC_TX3_TX_PATH_SEC6 (TX_START_OFFSET + 0x05A8) +#define BOLERO_CDC_TX4_TX_PATH_CTL (TX_START_OFFSET + 0x0600) +#define BOLERO_CDC_TX4_TX_PATH_CFG0 (TX_START_OFFSET + 0x0604) +#define BOLERO_CDC_TX4_TX_PATH_CFG1 (TX_START_OFFSET + 0x0608) +#define BOLERO_CDC_TX4_TX_VOL_CTL (TX_START_OFFSET + 0x060C) +#define BOLERO_CDC_TX4_TX_PATH_SEC0 (TX_START_OFFSET + 0x0610) +#define BOLERO_CDC_TX4_TX_PATH_SEC1 (TX_START_OFFSET + 0x0614) +#define BOLERO_CDC_TX4_TX_PATH_SEC2 (TX_START_OFFSET + 0x0618) +#define BOLERO_CDC_TX4_TX_PATH_SEC3 (TX_START_OFFSET + 0x061C) +#define BOLERO_CDC_TX4_TX_PATH_SEC4 (TX_START_OFFSET + 0x0620) +#define BOLERO_CDC_TX4_TX_PATH_SEC5 (TX_START_OFFSET + 0x0624) +#define BOLERO_CDC_TX4_TX_PATH_SEC6 (TX_START_OFFSET + 0x0628) +#define BOLERO_CDC_TX5_TX_PATH_CTL (TX_START_OFFSET + 0x0680) +#define BOLERO_CDC_TX5_TX_PATH_CFG0 (TX_START_OFFSET + 0x0684) +#define BOLERO_CDC_TX5_TX_PATH_CFG1 (TX_START_OFFSET + 0x0688) +#define BOLERO_CDC_TX5_TX_VOL_CTL (TX_START_OFFSET + 0x068C) +#define BOLERO_CDC_TX5_TX_PATH_SEC0 (TX_START_OFFSET + 0x0690) +#define BOLERO_CDC_TX5_TX_PATH_SEC1 (TX_START_OFFSET + 0x0694) +#define BOLERO_CDC_TX5_TX_PATH_SEC2 (TX_START_OFFSET + 0x0698) +#define BOLERO_CDC_TX5_TX_PATH_SEC3 (TX_START_OFFSET + 0x069C) +#define BOLERO_CDC_TX5_TX_PATH_SEC4 (TX_START_OFFSET + 0x06A0) +#define BOLERO_CDC_TX5_TX_PATH_SEC5 (TX_START_OFFSET + 0x06A4) +#define BOLERO_CDC_TX5_TX_PATH_SEC6 (TX_START_OFFSET + 0x06A8) +#define BOLERO_CDC_TX6_TX_PATH_CTL (TX_START_OFFSET + 0x0700) +#define BOLERO_CDC_TX6_TX_PATH_CFG0 (TX_START_OFFSET + 0x0704) +#define BOLERO_CDC_TX6_TX_PATH_CFG1 (TX_START_OFFSET + 0x0708) +#define BOLERO_CDC_TX6_TX_VOL_CTL (TX_START_OFFSET + 0x070C) +#define BOLERO_CDC_TX6_TX_PATH_SEC0 (TX_START_OFFSET + 0x0710) +#define BOLERO_CDC_TX6_TX_PATH_SEC1 (TX_START_OFFSET + 0x0714) +#define BOLERO_CDC_TX6_TX_PATH_SEC2 (TX_START_OFFSET + 0x0718) +#define BOLERO_CDC_TX6_TX_PATH_SEC3 (TX_START_OFFSET + 0x071C) +#define BOLERO_CDC_TX6_TX_PATH_SEC4 (TX_START_OFFSET + 0x0720) +#define BOLERO_CDC_TX6_TX_PATH_SEC5 (TX_START_OFFSET + 0x0724) +#define BOLERO_CDC_TX6_TX_PATH_SEC6 (TX_START_OFFSET + 0x0728) +#define BOLERO_CDC_TX7_TX_PATH_CTL (TX_START_OFFSET + 0x0780) +#define BOLERO_CDC_TX7_TX_PATH_CFG0 (TX_START_OFFSET + 0x0784) +#define BOLERO_CDC_TX7_TX_PATH_CFG1 (TX_START_OFFSET + 0x0788) +#define BOLERO_CDC_TX7_TX_VOL_CTL (TX_START_OFFSET + 0x078C) +#define BOLERO_CDC_TX7_TX_PATH_SEC0 (TX_START_OFFSET + 0x0790) +#define BOLERO_CDC_TX7_TX_PATH_SEC1 (TX_START_OFFSET + 0x0794) +#define BOLERO_CDC_TX7_TX_PATH_SEC2 (TX_START_OFFSET + 0x0798) +#define BOLERO_CDC_TX7_TX_PATH_SEC3 (TX_START_OFFSET + 0x079C) +#define BOLERO_CDC_TX7_TX_PATH_SEC4 (TX_START_OFFSET + 0x07A0) +#define BOLERO_CDC_TX7_TX_PATH_SEC5 (TX_START_OFFSET + 0x07A4) +#define BOLERO_CDC_TX7_TX_PATH_SEC6 (TX_START_OFFSET + 0x07A8) +#define TX_MAX_OFFSET (TX_START_OFFSET + 0x07A8) + +#define BOLERO_CDC_TX_MACRO_MAX 0x1EB /* 7A8/4 = 1EA + 1 */ + +#define RX_START_OFFSET 0x1000 +#define BOLERO_CDC_RX_TOP_TOP_CFG0 (RX_START_OFFSET + 0x0000) +#define BOLERO_CDC_RX_TOP_SWR_CTRL (RX_START_OFFSET + 0x0008) +#define BOLERO_CDC_RX_TOP_DEBUG (RX_START_OFFSET + 0x000C) +#define BOLERO_CDC_RX_TOP_DEBUG_BUS (RX_START_OFFSET + 0x0010) +#define BOLERO_CDC_RX_TOP_DEBUG_EN0 (RX_START_OFFSET + 0x0014) +#define BOLERO_CDC_RX_TOP_DEBUG_EN1 (RX_START_OFFSET + 0x0018) +#define BOLERO_CDC_RX_TOP_DEBUG_EN2 (RX_START_OFFSET + 0x001C) +#define BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB (RX_START_OFFSET + 0x0020) +#define BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB (RX_START_OFFSET + 0x0024) +#define BOLERO_CDC_RX_TOP_HPHL_COMP_LUT (RX_START_OFFSET + 0x0028) +#define BOLERO_CDC_RX_TOP_HPHL_COMP_RD_LSB (RX_START_OFFSET + 0x002C) +#define BOLERO_CDC_RX_TOP_HPHL_COMP_RD_MSB (RX_START_OFFSET + 0x0030) +#define BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB (RX_START_OFFSET + 0x0034) +#define BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB (RX_START_OFFSET + 0x0038) +#define BOLERO_CDC_RX_TOP_HPHR_COMP_LUT (RX_START_OFFSET + 0x003C) +#define BOLERO_CDC_RX_TOP_HPHR_COMP_RD_LSB (RX_START_OFFSET + 0x0040) +#define BOLERO_CDC_RX_TOP_HPHR_COMP_RD_MSB (RX_START_OFFSET + 0x0044) +#define BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG0 (RX_START_OFFSET + 0x0070) +#define BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG1 (RX_START_OFFSET + 0x0074) +#define BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG2 (RX_START_OFFSET + 0x0078) +#define BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG3 (RX_START_OFFSET + 0x007C) +#define BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG0 (RX_START_OFFSET + 0x0080) +#define BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG1 (RX_START_OFFSET + 0x0084) +#define BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG2 (RX_START_OFFSET + 0x0088) +#define BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG3 (RX_START_OFFSET + 0x008C) +#define BOLERO_CDC_RX_TOP_RX_I2S_CTL (RX_START_OFFSET + 0x0090) +#define BOLERO_CDC_RX_TOP_TX_I2S2_CTL (RX_START_OFFSET + 0x0094) +#define BOLERO_CDC_RX_TOP_I2S_CLK (RX_START_OFFSET + 0x0098) +#define BOLERO_CDC_RX_TOP_I2S_RESET (RX_START_OFFSET + 0x009C) +#define BOLERO_CDC_RX_TOP_I2S_MUX (RX_START_OFFSET + 0x00A0) +#define BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL (RX_START_OFFSET + 0x0100) +#define BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL \ + (RX_START_OFFSET + 0x0104) +#define BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL (RX_START_OFFSET + 0x0108) +#define BOLERO_CDC_RX_CLK_RST_CTRL_DSD_CONTROL (RX_START_OFFSET + 0x010C) +#define BOLERO_CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL \ + (RX_START_OFFSET + 0x0110) +#define BOLERO_CDC_RX_SOFTCLIP_CRC (RX_START_OFFSET + 0x0140) +#define BOLERO_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL (RX_START_OFFSET + 0x0144) +#define BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0 (RX_START_OFFSET + 0x0180) +#define BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1 (RX_START_OFFSET + 0x0184) +#define BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG0 (RX_START_OFFSET + 0x0188) +#define BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG1 (RX_START_OFFSET + 0x018C) +#define BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG0 (RX_START_OFFSET + 0x0190) +#define BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG1 (RX_START_OFFSET + 0x0194) +#define BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG4 (RX_START_OFFSET + 0x0198) +#define BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG5 (RX_START_OFFSET + 0x019C) +#define BOLERO_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0 (RX_START_OFFSET + 0x01A0) +#define BOLERO_CDC_RX_CLSH_CRC (RX_START_OFFSET + 0x0200) +#define BOLERO_CDC_RX_CLSH_DLY_CTRL (RX_START_OFFSET + 0x0204) +#define BOLERO_CDC_RX_CLSH_DECAY_CTRL (RX_START_OFFSET + 0x0208) +#define BOLERO_CDC_RX_CLSH_HPH_V_PA (RX_START_OFFSET + 0x020C) +#define BOLERO_CDC_RX_CLSH_EAR_V_PA (RX_START_OFFSET + 0x0210) +#define BOLERO_CDC_RX_CLSH_HPH_V_HD (RX_START_OFFSET + 0x0214) +#define BOLERO_CDC_RX_CLSH_EAR_V_HD (RX_START_OFFSET + 0x0218) +#define BOLERO_CDC_RX_CLSH_K1_MSB (RX_START_OFFSET + 0x021C) +#define BOLERO_CDC_RX_CLSH_K1_LSB (RX_START_OFFSET + 0x0220) +#define BOLERO_CDC_RX_CLSH_K2_MSB (RX_START_OFFSET + 0x0224) +#define BOLERO_CDC_RX_CLSH_K2_LSB (RX_START_OFFSET + 0x0228) +#define BOLERO_CDC_RX_CLSH_IDLE_CTRL (RX_START_OFFSET + 0x022C) +#define BOLERO_CDC_RX_CLSH_IDLE_HPH (RX_START_OFFSET + 0x0230) +#define BOLERO_CDC_RX_CLSH_IDLE_EAR (RX_START_OFFSET + 0x0234) +#define BOLERO_CDC_RX_CLSH_TEST0 (RX_START_OFFSET + 0x0238) +#define BOLERO_CDC_RX_CLSH_TEST1 (RX_START_OFFSET + 0x023C) +#define BOLERO_CDC_RX_CLSH_OVR_VREF (RX_START_OFFSET + 0x0240) +#define BOLERO_CDC_RX_CLSH_CLSG_CTL (RX_START_OFFSET + 0x0244) +#define BOLERO_CDC_RX_CLSH_CLSG_CFG1 (RX_START_OFFSET + 0x0248) +#define BOLERO_CDC_RX_CLSH_CLSG_CFG2 (RX_START_OFFSET + 0x024C) +#define BOLERO_CDC_RX_BCL_VBAT_PATH_CTL (RX_START_OFFSET + 0x0280) +#define BOLERO_CDC_RX_BCL_VBAT_CFG (RX_START_OFFSET + 0x0284) +#define BOLERO_CDC_RX_BCL_VBAT_ADC_CAL1 (RX_START_OFFSET + 0x0288) +#define BOLERO_CDC_RX_BCL_VBAT_ADC_CAL2 (RX_START_OFFSET + 0x028C) +#define BOLERO_CDC_RX_BCL_VBAT_ADC_CAL3 (RX_START_OFFSET + 0x0290) +#define BOLERO_CDC_RX_BCL_VBAT_PK_EST1 (RX_START_OFFSET + 0x0294) +#define BOLERO_CDC_RX_BCL_VBAT_PK_EST2 (RX_START_OFFSET + 0x0298) +#define BOLERO_CDC_RX_BCL_VBAT_PK_EST3 (RX_START_OFFSET + 0x029C) +#define BOLERO_CDC_RX_BCL_VBAT_RF_PROC1 (RX_START_OFFSET + 0x02A0) +#define BOLERO_CDC_RX_BCL_VBAT_RF_PROC2 (RX_START_OFFSET + 0x02A4) +#define BOLERO_CDC_RX_BCL_VBAT_TAC1 (RX_START_OFFSET + 0x02A8) +#define BOLERO_CDC_RX_BCL_VBAT_TAC2 (RX_START_OFFSET + 0x02AC) +#define BOLERO_CDC_RX_BCL_VBAT_TAC3 (RX_START_OFFSET + 0x02B0) +#define BOLERO_CDC_RX_BCL_VBAT_TAC4 (RX_START_OFFSET + 0x02B4) +#define BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD1 (RX_START_OFFSET + 0x02B8) +#define BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD2 (RX_START_OFFSET + 0x02BC) +#define BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD3 (RX_START_OFFSET + 0x02C0) +#define BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD4 (RX_START_OFFSET + 0x02C4) +#define BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD5 (RX_START_OFFSET + 0x02C8) +#define BOLERO_CDC_RX_BCL_VBAT_DEBUG1 (RX_START_OFFSET + 0x02CC) +#define BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD_MON (RX_START_OFFSET + 0x02D0) +#define BOLERO_CDC_RX_BCL_VBAT_GAIN_MON_VAL (RX_START_OFFSET + 0x02D4) +#define BOLERO_CDC_RX_BCL_VBAT_BAN (RX_START_OFFSET + 0x02D8) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1 (RX_START_OFFSET + 0x02DC) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2 (RX_START_OFFSET + 0x02E0) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3 (RX_START_OFFSET + 0x02E4) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4 (RX_START_OFFSET + 0x02E8) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5 (RX_START_OFFSET + 0x02EC) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6 (RX_START_OFFSET + 0x02F0) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7 (RX_START_OFFSET + 0x02F4) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8 (RX_START_OFFSET + 0x02F8) +#define BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9 (RX_START_OFFSET + 0x02FC) +#define BOLERO_CDC_RX_BCL_VBAT_ATTN1 (RX_START_OFFSET + 0x0300) +#define BOLERO_CDC_RX_BCL_VBAT_ATTN2 (RX_START_OFFSET + 0x0304) +#define BOLERO_CDC_RX_BCL_VBAT_ATTN3 (RX_START_OFFSET + 0x0308) +#define BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL1 (RX_START_OFFSET + 0x030C) +#define BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL2 (RX_START_OFFSET + 0x0310) +#define BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG1 (RX_START_OFFSET + 0x0314) +#define BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG2 (RX_START_OFFSET + 0x0318) +#define BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG3 (RX_START_OFFSET + 0x031C) +#define BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG4 (RX_START_OFFSET + 0x0320) +#define BOLERO_CDC_RX_BCL_VBAT_DECODE_ST (RX_START_OFFSET + 0x0324) +#define BOLERO_CDC_RX_INTR_CTRL_CFG (RX_START_OFFSET + 0x0340) +#define BOLERO_CDC_RX_INTR_CTRL_CLR_COMMIT (RX_START_OFFSET + 0x0344) +#define BOLERO_CDC_RX_INTR_CTRL_PIN1_MASK0 (RX_START_OFFSET + 0x0360) +#define BOLERO_CDC_RX_INTR_CTRL_PIN1_STATUS0 (RX_START_OFFSET + 0x0368) +#define BOLERO_CDC_RX_INTR_CTRL_PIN1_CLEAR0 (RX_START_OFFSET + 0x0370) +#define BOLERO_CDC_RX_INTR_CTRL_PIN2_MASK0 (RX_START_OFFSET + 0x0380) +#define BOLERO_CDC_RX_INTR_CTRL_PIN2_STATUS0 (RX_START_OFFSET + 0x0388) +#define BOLERO_CDC_RX_INTR_CTRL_PIN2_CLEAR0 (RX_START_OFFSET + 0x0390) +#define BOLERO_CDC_RX_INTR_CTRL_LEVEL0 (RX_START_OFFSET + 0x03C0) +#define BOLERO_CDC_RX_INTR_CTRL_BYPASS0 (RX_START_OFFSET + 0x03C8) +#define BOLERO_CDC_RX_INTR_CTRL_SET0 (RX_START_OFFSET + 0x03D0) +#define BOLERO_CDC_RX_RX0_RX_PATH_CTL (RX_START_OFFSET + 0x0400) +#define BOLERO_CDC_RX_RX0_RX_PATH_CFG0 (RX_START_OFFSET + 0x0404) +#define BOLERO_CDC_RX_RX0_RX_PATH_CFG1 (RX_START_OFFSET + 0x0408) +#define BOLERO_CDC_RX_RX0_RX_PATH_CFG2 (RX_START_OFFSET + 0x040C) +#define BOLERO_CDC_RX_RX0_RX_PATH_CFG3 (RX_START_OFFSET + 0x0410) +#define BOLERO_CDC_RX_RX0_RX_VOL_CTL (RX_START_OFFSET + 0x0414) +#define BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x0418) +#define BOLERO_CDC_RX_RX0_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x041C) +#define BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x0420) +#define BOLERO_CDC_RX_RX0_RX_PATH_SEC1 (RX_START_OFFSET + 0x0424) +#define BOLERO_CDC_RX_RX0_RX_PATH_SEC2 (RX_START_OFFSET + 0x0428) +#define BOLERO_CDC_RX_RX0_RX_PATH_SEC3 (RX_START_OFFSET + 0x042C) +#define BOLERO_CDC_RX_RX0_RX_PATH_SEC4 (RX_START_OFFSET + 0x0430) +#define BOLERO_CDC_RX_RX0_RX_PATH_SEC7 (RX_START_OFFSET + 0x0434) +#define BOLERO_CDC_RX_RX0_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x0438) +#define BOLERO_CDC_RX_RX0_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x043C) +#define BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x0440) +#define BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA1 (RX_START_OFFSET + 0x0444) +#define BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA2 (RX_START_OFFSET + 0x0448) +#define BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA3 (RX_START_OFFSET + 0x044C) +#define BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA4 (RX_START_OFFSET + 0x0450) +#define BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA5 (RX_START_OFFSET + 0x0454) +#define BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA6 (RX_START_OFFSET + 0x0458) +#define BOLERO_CDC_RX_RX1_RX_PATH_CTL (RX_START_OFFSET + 0x0480) +#define BOLERO_CDC_RX_RX1_RX_PATH_CFG0 (RX_START_OFFSET + 0x0484) +#define BOLERO_CDC_RX_RX1_RX_PATH_CFG1 (RX_START_OFFSET + 0x0488) +#define BOLERO_CDC_RX_RX1_RX_PATH_CFG2 (RX_START_OFFSET + 0x048C) +#define BOLERO_CDC_RX_RX1_RX_PATH_CFG3 (RX_START_OFFSET + 0x0490) +#define BOLERO_CDC_RX_RX1_RX_VOL_CTL (RX_START_OFFSET + 0x0494) +#define BOLERO_CDC_RX_RX1_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x0498) +#define BOLERO_CDC_RX_RX1_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x049C) +#define BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x04A0) +#define BOLERO_CDC_RX_RX1_RX_PATH_SEC1 (RX_START_OFFSET + 0x04A4) +#define BOLERO_CDC_RX_RX1_RX_PATH_SEC2 (RX_START_OFFSET + 0x04A8) +#define BOLERO_CDC_RX_RX1_RX_PATH_SEC3 (RX_START_OFFSET + 0x04AC) +#define BOLERO_CDC_RX_RX1_RX_PATH_SEC4 (RX_START_OFFSET + 0x04B0) +#define BOLERO_CDC_RX_RX1_RX_PATH_SEC7 (RX_START_OFFSET + 0x04B4) +#define BOLERO_CDC_RX_RX1_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x04B8) +#define BOLERO_CDC_RX_RX1_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x04BC) +#define BOLERO_CDC_RX_RX1_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x04C0) +#define BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA1 (RX_START_OFFSET + 0x04C4) +#define BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA2 (RX_START_OFFSET + 0x04C8) +#define BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA3 (RX_START_OFFSET + 0x04CC) +#define BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA4 (RX_START_OFFSET + 0x04D0) +#define BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA5 (RX_START_OFFSET + 0x04D4) +#define BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA6 (RX_START_OFFSET + 0x04D8) +#define BOLERO_CDC_RX_RX2_RX_PATH_CTL (RX_START_OFFSET + 0x0500) +#define BOLERO_CDC_RX_RX2_RX_PATH_CFG0 (RX_START_OFFSET + 0x0504) +#define BOLERO_CDC_RX_RX2_RX_PATH_CFG1 (RX_START_OFFSET + 0x0508) +#define BOLERO_CDC_RX_RX2_RX_PATH_CFG2 (RX_START_OFFSET + 0x050C) +#define BOLERO_CDC_RX_RX2_RX_PATH_CFG3 (RX_START_OFFSET + 0x0510) +#define BOLERO_CDC_RX_RX2_RX_VOL_CTL (RX_START_OFFSET + 0x0514) +#define BOLERO_CDC_RX_RX2_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x0518) +#define BOLERO_CDC_RX_RX2_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x051C) +#define BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x0520) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC0 (RX_START_OFFSET + 0x0524) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC1 (RX_START_OFFSET + 0x0528) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC2 (RX_START_OFFSET + 0x052C) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC3 (RX_START_OFFSET + 0x0530) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC4 (RX_START_OFFSET + 0x0534) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC5 (RX_START_OFFSET + 0x0538) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC6 (RX_START_OFFSET + 0x053C) +#define BOLERO_CDC_RX_RX2_RX_PATH_SEC7 (RX_START_OFFSET + 0x0540) +#define BOLERO_CDC_RX_RX2_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x0544) +#define BOLERO_CDC_RX_RX2_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x0548) +#define BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x054C) +#define BOLERO_CDC_RX_IDLE_DETECT_PATH_CTL (RX_START_OFFSET + 0x0780) +#define BOLERO_CDC_RX_IDLE_DETECT_CFG0 (RX_START_OFFSET + 0x0784) +#define BOLERO_CDC_RX_IDLE_DETECT_CFG1 (RX_START_OFFSET + 0x0788) +#define BOLERO_CDC_RX_IDLE_DETECT_CFG2 (RX_START_OFFSET + 0x078C) +#define BOLERO_CDC_RX_IDLE_DETECT_CFG3 (RX_START_OFFSET + 0x0790) +#define BOLERO_CDC_RX_COMPANDER0_CTL0 (RX_START_OFFSET + 0x0800) +#define BOLERO_CDC_RX_COMPANDER0_CTL1 (RX_START_OFFSET + 0x0804) +#define BOLERO_CDC_RX_COMPANDER0_CTL2 (RX_START_OFFSET + 0x0808) +#define BOLERO_CDC_RX_COMPANDER0_CTL3 (RX_START_OFFSET + 0x080C) +#define BOLERO_CDC_RX_COMPANDER0_CTL4 (RX_START_OFFSET + 0x0810) +#define BOLERO_CDC_RX_COMPANDER0_CTL5 (RX_START_OFFSET + 0x0814) +#define BOLERO_CDC_RX_COMPANDER0_CTL6 (RX_START_OFFSET + 0x0818) +#define BOLERO_CDC_RX_COMPANDER0_CTL7 (RX_START_OFFSET + 0x081C) +#define BOLERO_CDC_RX_COMPANDER1_CTL0 (RX_START_OFFSET + 0x0840) +#define BOLERO_CDC_RX_COMPANDER1_CTL1 (RX_START_OFFSET + 0x0844) +#define BOLERO_CDC_RX_COMPANDER1_CTL2 (RX_START_OFFSET + 0x0848) +#define BOLERO_CDC_RX_COMPANDER1_CTL3 (RX_START_OFFSET + 0x084C) +#define BOLERO_CDC_RX_COMPANDER1_CTL4 (RX_START_OFFSET + 0x0850) +#define BOLERO_CDC_RX_COMPANDER1_CTL5 (RX_START_OFFSET + 0x0854) +#define BOLERO_CDC_RX_COMPANDER1_CTL6 (RX_START_OFFSET + 0x0858) +#define BOLERO_CDC_RX_COMPANDER1_CTL7 (RX_START_OFFSET + 0x085C) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL \ + (RX_START_OFFSET + 0x0A00) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL \ + (RX_START_OFFSET + 0x0A04) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL \ + (RX_START_OFFSET + 0x0A08) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL \ + (RX_START_OFFSET + 0x0A0C) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL \ + (RX_START_OFFSET + 0x0A10) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL \ + (RX_START_OFFSET + 0x0A14) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL \ + (RX_START_OFFSET + 0x0A18) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL \ + (RX_START_OFFSET + 0x0A1C) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL \ + (RX_START_OFFSET + 0x0A20) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_CTL (RX_START_OFFSET + 0x0A24) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL \ + (RX_START_OFFSET + 0x0A28) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL \ + (RX_START_OFFSET + 0x0A2C) +#define BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL \ + (RX_START_OFFSET + 0x0A30) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL \ + (RX_START_OFFSET + 0x0A80) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL \ + (RX_START_OFFSET + 0x0A84) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL \ + (RX_START_OFFSET + 0x0A88) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL \ + (RX_START_OFFSET + 0x0A8C) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL \ + (RX_START_OFFSET + 0x0A90) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL \ + (RX_START_OFFSET + 0x0A94) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL \ + (RX_START_OFFSET + 0x0A98) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL \ + (RX_START_OFFSET + 0x0A9C) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL \ + (RX_START_OFFSET + 0x0AA0) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_CTL (RX_START_OFFSET + 0x0AA4) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL \ + (RX_START_OFFSET + 0x0AA8) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL \ + (RX_START_OFFSET + 0x0AAC) +#define BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL \ + (RX_START_OFFSET + 0x0AB0) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0 (RX_START_OFFSET + 0x0B00) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1 (RX_START_OFFSET + 0x0B04) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2 (RX_START_OFFSET + 0x0B08) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3 (RX_START_OFFSET + 0x0B0C) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0 (RX_START_OFFSET + 0x0B10) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1 (RX_START_OFFSET + 0x0B14) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2 (RX_START_OFFSET + 0x0B18) +#define BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3 (RX_START_OFFSET + 0x0B1C) +#define BOLERO_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL \ + (RX_START_OFFSET + 0x0B40) +#define BOLERO_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1 \ + (RX_START_OFFSET + 0x0B44) +#define BOLERO_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL \ + (RX_START_OFFSET + 0x0B50) +#define BOLERO_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1 \ + (RX_START_OFFSET + 0x0B54) +#define BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL \ + (RX_START_OFFSET + 0x0C00) +#define BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0 (RX_START_OFFSET + 0x0C04) +#define BOLERO_CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL \ + (RX_START_OFFSET + 0x0C40) +#define BOLERO_CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0 (RX_START_OFFSET + 0x0C44) +#define BOLERO_CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL \ + (RX_START_OFFSET + 0x0C80) +#define BOLERO_CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0 (RX_START_OFFSET + 0x0C84) +#define BOLERO_CDC_RX_EC_ASRC0_CLK_RST_CTL (RX_START_OFFSET + 0x0D00) +#define BOLERO_CDC_RX_EC_ASRC0_CTL0 (RX_START_OFFSET + 0x0D04) +#define BOLERO_CDC_RX_EC_ASRC0_CTL1 (RX_START_OFFSET + 0x0D08) +#define BOLERO_CDC_RX_EC_ASRC0_FIFO_CTL (RX_START_OFFSET + 0x0D0C) +#define BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB \ + (RX_START_OFFSET + 0x0D10) +#define BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB \ + (RX_START_OFFSET + 0x0D14) +#define BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB \ + (RX_START_OFFSET + 0x0D18) +#define BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB \ + (RX_START_OFFSET + 0x0D1C) +#define BOLERO_CDC_RX_EC_ASRC0_STATUS_FIFO (RX_START_OFFSET + 0x0D20) +#define BOLERO_CDC_RX_EC_ASRC1_CLK_RST_CTL (RX_START_OFFSET + 0x0D40) +#define BOLERO_CDC_RX_EC_ASRC1_CTL0 (RX_START_OFFSET + 0x0D44) +#define BOLERO_CDC_RX_EC_ASRC1_CTL1 (RX_START_OFFSET + 0x0D48) +#define BOLERO_CDC_RX_EC_ASRC1_FIFO_CTL (RX_START_OFFSET + 0x0D4C) +#define BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB \ + (RX_START_OFFSET + 0x0D50) +#define BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB \ + (RX_START_OFFSET + 0x0D54) +#define BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB \ + (RX_START_OFFSET + 0x0D58) +#define BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB \ + (RX_START_OFFSET + 0x0D5C) +#define BOLERO_CDC_RX_EC_ASRC1_STATUS_FIFO (RX_START_OFFSET + 0x0D60) +#define BOLERO_CDC_RX_EC_ASRC2_CLK_RST_CTL (RX_START_OFFSET + 0x0D80) +#define BOLERO_CDC_RX_EC_ASRC2_CTL0 (RX_START_OFFSET + 0x0D84) +#define BOLERO_CDC_RX_EC_ASRC2_CTL1 (RX_START_OFFSET + 0x0D88) +#define BOLERO_CDC_RX_EC_ASRC2_FIFO_CTL (RX_START_OFFSET + 0x0D8C) +#define BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB \ + (RX_START_OFFSET + 0x0D90) +#define BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB \ + (RX_START_OFFSET + 0x0D94) +#define BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB \ + (RX_START_OFFSET + 0x0D98) +#define BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB \ + (RX_START_OFFSET + 0x0D9C) +#define BOLERO_CDC_RX_EC_ASRC2_STATUS_FIFO (RX_START_OFFSET + 0x0DA0) +#define BOLERO_CDC_RX_DSD0_PATH_CTL (RX_START_OFFSET + 0x0F00) +#define BOLERO_CDC_RX_DSD0_CFG0 (RX_START_OFFSET + 0x0F04) +#define BOLERO_CDC_RX_DSD0_CFG1 (RX_START_OFFSET + 0x0F08) +#define BOLERO_CDC_RX_DSD0_CFG2 (RX_START_OFFSET + 0x0F0C) +#define BOLERO_CDC_RX_DSD1_PATH_CTL (RX_START_OFFSET + 0x0F80) +#define BOLERO_CDC_RX_DSD1_CFG0 (RX_START_OFFSET + 0x0F84) +#define BOLERO_CDC_RX_DSD1_CFG1 (RX_START_OFFSET + 0x0F88) +#define BOLERO_CDC_RX_DSD1_CFG2 (RX_START_OFFSET + 0x0F8C) +#define RX_MAX_OFFSET (RX_START_OFFSET + 0x0F8C) + +#define BOLERO_CDC_RX_MACRO_MAX 0x3E4 /* F8C/4 = 3E3 + 1 */ + +/* WSA - macro#2 */ +#define WSA_START_OFFSET 0x2000 +#define BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL \ + (WSA_START_OFFSET + 0x0000) +#define BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL \ + (WSA_START_OFFSET + 0x0004) +#define BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL (WSA_START_OFFSET + 0x0008) +#define BOLERO_CDC_WSA_TOP_TOP_CFG0 (WSA_START_OFFSET + 0x0080) +#define BOLERO_CDC_WSA_TOP_TOP_CFG1 (WSA_START_OFFSET + 0x0084) +#define BOLERO_CDC_WSA_TOP_FREQ_MCLK (WSA_START_OFFSET + 0x0088) +#define BOLERO_CDC_WSA_TOP_DEBUG_BUS_SEL (WSA_START_OFFSET + 0x008C) +#define BOLERO_CDC_WSA_TOP_DEBUG_EN0 (WSA_START_OFFSET + 0x0090) +#define BOLERO_CDC_WSA_TOP_DEBUG_EN1 (WSA_START_OFFSET + 0x0094) +#define BOLERO_CDC_WSA_TOP_DEBUG_DSM_LB (WSA_START_OFFSET + 0x0098) +#define BOLERO_CDC_WSA_TOP_RX_I2S_CTL (WSA_START_OFFSET + 0x009C) +#define BOLERO_CDC_WSA_TOP_TX_I2S_CTL (WSA_START_OFFSET + 0x00A0) +#define BOLERO_CDC_WSA_TOP_I2S_CLK (WSA_START_OFFSET + 0x00A4) +#define BOLERO_CDC_WSA_TOP_I2S_RESET (WSA_START_OFFSET + 0x00A8) +#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (WSA_START_OFFSET + 0x0100) +#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (WSA_START_OFFSET + 0x0104) +#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (WSA_START_OFFSET + 0x0108) +#define BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (WSA_START_OFFSET + 0x010C) +#define BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (WSA_START_OFFSET + 0x0110) +#define BOLERO_CDC_WSA_RX_INP_MUX_RX_EC_CFG0 (WSA_START_OFFSET + 0x0114) +#define BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0 (WSA_START_OFFSET + 0x0118) +/* VBAT registers */ +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL (WSA_START_OFFSET + 0x0180) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG (WSA_START_OFFSET + 0x0184) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1 (WSA_START_OFFSET + 0x0188) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2 (WSA_START_OFFSET + 0x018C) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3 (WSA_START_OFFSET + 0x0190) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST1 (WSA_START_OFFSET + 0x0194) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST2 (WSA_START_OFFSET + 0x0198) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST3 (WSA_START_OFFSET + 0x019C) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1 (WSA_START_OFFSET + 0x01A0) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2 (WSA_START_OFFSET + 0x01A4) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC1 (WSA_START_OFFSET + 0x01A8) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC2 (WSA_START_OFFSET + 0x01AC) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC3 (WSA_START_OFFSET + 0x01B0) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC4 (WSA_START_OFFSET + 0x01B4) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1 (WSA_START_OFFSET + 0x01B8) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2 (WSA_START_OFFSET + 0x01BC) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3 (WSA_START_OFFSET + 0x01C0) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4 (WSA_START_OFFSET + 0x01C4) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5 (WSA_START_OFFSET + 0x01C8) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DEBUG1 (WSA_START_OFFSET + 0x01CC) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON \ + (WSA_START_OFFSET + 0x01D0) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL \ + (WSA_START_OFFSET + 0x01D4) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BAN (WSA_START_OFFSET + 0x01D8) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1 \ + (WSA_START_OFFSET + 0x01DC) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2 \ + (WSA_START_OFFSET + 0x01E0) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3 \ + (WSA_START_OFFSET + 0x01E4) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4 \ + (WSA_START_OFFSET + 0x01E8) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5 \ + (WSA_START_OFFSET + 0x01EC) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6 \ + (WSA_START_OFFSET + 0x01F0) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7 \ + (WSA_START_OFFSET + 0x01F4) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8 \ + (WSA_START_OFFSET + 0x01F8) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9 \ + (WSA_START_OFFSET + 0x01FC) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1 (WSA_START_OFFSET + 0x0200) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2 (WSA_START_OFFSET + 0x0204) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3 (WSA_START_OFFSET + 0x0208) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1 \ + (WSA_START_OFFSET + 0x020C) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL2 \ + (WSA_START_OFFSET + 0x0210) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1 \ + (WSA_START_OFFSET + 0x0214) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2 \ + (WSA_START_OFFSET + 0x0218) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3 \ + (WSA_START_OFFSET + 0x021C) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4 \ + (WSA_START_OFFSET + 0x0220) +#define BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST (WSA_START_OFFSET + 0x0224) +#define BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0244) +#define BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0248) +#define BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0264) +#define BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0268) +#define BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0284) +#define BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0288) +#define BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x02A4) +#define BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x02A8) +#define BOLERO_CDC_WSA_INTR_CTRL_CFG (WSA_START_OFFSET + 0x0340) +#define BOLERO_CDC_WSA_INTR_CTRL_CLR_COMMIT (WSA_START_OFFSET + 0x0344) +#define BOLERO_CDC_WSA_INTR_CTRL_PIN1_MASK0 (WSA_START_OFFSET + 0x0360) +#define BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0 (WSA_START_OFFSET + 0x0368) +#define BOLERO_CDC_WSA_INTR_CTRL_PIN1_CLEAR0 (WSA_START_OFFSET + 0x0370) +#define BOLERO_CDC_WSA_INTR_CTRL_PIN2_MASK0 (WSA_START_OFFSET + 0x0380) +#define BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0 (WSA_START_OFFSET + 0x0388) +#define BOLERO_CDC_WSA_INTR_CTRL_PIN2_CLEAR0 (WSA_START_OFFSET + 0x0390) +#define BOLERO_CDC_WSA_INTR_CTRL_LEVEL0 (WSA_START_OFFSET + 0x03C0) +#define BOLERO_CDC_WSA_INTR_CTRL_BYPASS0 (WSA_START_OFFSET + 0x03C8) +#define BOLERO_CDC_WSA_INTR_CTRL_SET0 (WSA_START_OFFSET + 0x03D0) +#define BOLERO_CDC_WSA_RX0_RX_PATH_CTL (WSA_START_OFFSET + 0x0400) +#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG0 (WSA_START_OFFSET + 0x0404) +#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG1 (WSA_START_OFFSET + 0x0408) +#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG2 (WSA_START_OFFSET + 0x040C) +#define BOLERO_CDC_WSA_RX0_RX_PATH_CFG3 (WSA_START_OFFSET + 0x0410) +#define BOLERO_CDC_WSA_RX0_RX_VOL_CTL (WSA_START_OFFSET + 0x0414) +#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL (WSA_START_OFFSET + 0x0418) +#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG (WSA_START_OFFSET + 0x041C) +#define BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL (WSA_START_OFFSET + 0x0420) +#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC0 (WSA_START_OFFSET + 0x0424) +#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC1 (WSA_START_OFFSET + 0x0428) +#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC2 (WSA_START_OFFSET + 0x042C) +#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC3 (WSA_START_OFFSET + 0x0430) +#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC5 (WSA_START_OFFSET + 0x0438) +#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC6 (WSA_START_OFFSET + 0x043C) +#define BOLERO_CDC_WSA_RX0_RX_PATH_SEC7 (WSA_START_OFFSET + 0x0440) +#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0 (WSA_START_OFFSET + 0x0444) +#define BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC1 (WSA_START_OFFSET + 0x0448) +#define BOLERO_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL (WSA_START_OFFSET + 0x044C) +#define BOLERO_CDC_WSA_RX1_RX_PATH_CTL (WSA_START_OFFSET + 0x0480) +#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG0 (WSA_START_OFFSET + 0x0484) +#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG1 (WSA_START_OFFSET + 0x0488) +#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG2 (WSA_START_OFFSET + 0x048C) +#define BOLERO_CDC_WSA_RX1_RX_PATH_CFG3 (WSA_START_OFFSET + 0x0490) +#define BOLERO_CDC_WSA_RX1_RX_VOL_CTL (WSA_START_OFFSET + 0x0494) +#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL (WSA_START_OFFSET + 0x0498) +#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG (WSA_START_OFFSET + 0x049C) +#define BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL (WSA_START_OFFSET + 0x04A0) +#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC0 (WSA_START_OFFSET + 0x04A4) +#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC1 (WSA_START_OFFSET + 0x04A8) +#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC2 (WSA_START_OFFSET + 0x04AC) +#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC3 (WSA_START_OFFSET + 0x04B0) +#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC5 (WSA_START_OFFSET + 0x04B8) +#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC6 (WSA_START_OFFSET + 0x04BC) +#define BOLERO_CDC_WSA_RX1_RX_PATH_SEC7 (WSA_START_OFFSET + 0x04C0) +#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0 (WSA_START_OFFSET + 0x04C4) +#define BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC1 (WSA_START_OFFSET + 0x04C8) +#define BOLERO_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL (WSA_START_OFFSET + 0x04CC) +#define BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL (WSA_START_OFFSET + 0x0500) +#define BOLERO_CDC_WSA_BOOST0_BOOST_CTL (WSA_START_OFFSET + 0x0504) +#define BOLERO_CDC_WSA_BOOST0_BOOST_CFG1 (WSA_START_OFFSET + 0x0508) +#define BOLERO_CDC_WSA_BOOST0_BOOST_CFG2 (WSA_START_OFFSET + 0x050C) +#define BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL (WSA_START_OFFSET + 0x0540) +#define BOLERO_CDC_WSA_BOOST1_BOOST_CTL (WSA_START_OFFSET + 0x0544) +#define BOLERO_CDC_WSA_BOOST1_BOOST_CFG1 (WSA_START_OFFSET + 0x0548) +#define BOLERO_CDC_WSA_BOOST1_BOOST_CFG2 (WSA_START_OFFSET + 0x054C) +#define BOLERO_CDC_WSA_COMPANDER0_CTL0 (WSA_START_OFFSET + 0x0580) +#define BOLERO_CDC_WSA_COMPANDER0_CTL1 (WSA_START_OFFSET + 0x0584) +#define BOLERO_CDC_WSA_COMPANDER0_CTL2 (WSA_START_OFFSET + 0x0588) +#define BOLERO_CDC_WSA_COMPANDER0_CTL3 (WSA_START_OFFSET + 0x058C) +#define BOLERO_CDC_WSA_COMPANDER0_CTL4 (WSA_START_OFFSET + 0x0590) +#define BOLERO_CDC_WSA_COMPANDER0_CTL5 (WSA_START_OFFSET + 0x0594) +#define BOLERO_CDC_WSA_COMPANDER0_CTL6 (WSA_START_OFFSET + 0x0598) +#define BOLERO_CDC_WSA_COMPANDER0_CTL7 (WSA_START_OFFSET + 0x059C) +#define BOLERO_CDC_WSA_COMPANDER1_CTL0 (WSA_START_OFFSET + 0x05C0) +#define BOLERO_CDC_WSA_COMPANDER1_CTL1 (WSA_START_OFFSET + 0x05C4) +#define BOLERO_CDC_WSA_COMPANDER1_CTL2 (WSA_START_OFFSET + 0x05C8) +#define BOLERO_CDC_WSA_COMPANDER1_CTL3 (WSA_START_OFFSET + 0x05CC) +#define BOLERO_CDC_WSA_COMPANDER1_CTL4 (WSA_START_OFFSET + 0x05D0) +#define BOLERO_CDC_WSA_COMPANDER1_CTL5 (WSA_START_OFFSET + 0x05D4) +#define BOLERO_CDC_WSA_COMPANDER1_CTL6 (WSA_START_OFFSET + 0x05D8) +#define BOLERO_CDC_WSA_COMPANDER1_CTL7 (WSA_START_OFFSET + 0x05DC) +#define BOLERO_CDC_WSA_SOFTCLIP0_CRC (WSA_START_OFFSET + 0x0600) +#define BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (WSA_START_OFFSET + 0x0604) +#define BOLERO_CDC_WSA_SOFTCLIP1_CRC (WSA_START_OFFSET + 0x0640) +#define BOLERO_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (WSA_START_OFFSET + 0x0644) +#define BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL \ + (WSA_START_OFFSET + 0x0680) +#define BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 (WSA_START_OFFSET + 0x0684) +#define BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL \ + (WSA_START_OFFSET + 0x06C0) +#define BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0 (WSA_START_OFFSET + 0x06C4) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL (WSA_START_OFFSET + 0x0700) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_CTL0 (WSA_START_OFFSET + 0x0704) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_CTL1 (WSA_START_OFFSET + 0x0708) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_FIFO_CTL (WSA_START_OFFSET + 0x070C) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB \ + (WSA_START_OFFSET + 0x0710) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB \ + (WSA_START_OFFSET + 0x0714) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB \ + (WSA_START_OFFSET + 0x0718) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB \ + (WSA_START_OFFSET + 0x071C) +#define BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO (WSA_START_OFFSET + 0x0720) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL (WSA_START_OFFSET + 0x0740) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_CTL0 (WSA_START_OFFSET + 0x0744) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_CTL1 (WSA_START_OFFSET + 0x0748) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_FIFO_CTL (WSA_START_OFFSET + 0x074C) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB \ + (WSA_START_OFFSET + 0x0750) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB \ + (WSA_START_OFFSET + 0x0754) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB \ + (WSA_START_OFFSET + 0x0758) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB \ + (WSA_START_OFFSET + 0x075C) +#define BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO (WSA_START_OFFSET + 0x0760) +#define WSA_MAX_OFFSET (WSA_START_OFFSET + 0x0760) + +#define BOLERO_CDC_WSA_MACRO_MAX 0x1D9 /* 0x760/4 = 0x1D8 + 1 registers */ + +/* VA macro registers */ +#define VA_START_OFFSET 0x3000 +#define BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL (VA_START_OFFSET + 0x0000) +#define BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL \ + (VA_START_OFFSET + 0x0004) +#define BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL (VA_START_OFFSET + 0x0008) +#define BOLERO_CDC_VA_TOP_CSR_TOP_CFG0 (VA_START_OFFSET + 0x0080) +#define BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL (VA_START_OFFSET + 0x0084) +#define BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL (VA_START_OFFSET + 0x0088) +#define BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL (VA_START_OFFSET + 0x008C) +#define BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL (VA_START_OFFSET + 0x0090) +#define BOLERO_CDC_VA_TOP_CSR_DMIC_CFG (VA_START_OFFSET + 0x0094) +#define BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS (VA_START_OFFSET + 0x009C) +#define BOLERO_CDC_VA_TOP_CSR_DEBUG_EN (VA_START_OFFSET + 0x00A0) +#define BOLERO_CDC_VA_TOP_CSR_TX_I2S_CTL (VA_START_OFFSET + 0x00A4) +#define BOLERO_CDC_VA_TOP_CSR_I2S_CLK (VA_START_OFFSET + 0x00A8) +#define BOLERO_CDC_VA_TOP_CSR_I2S_RESET (VA_START_OFFSET + 0x00AC) +#define BOLERO_CDC_VA_TOP_CSR_CORE_ID_0 (VA_START_OFFSET + 0x00C0) +#define BOLERO_CDC_VA_TOP_CSR_CORE_ID_1 (VA_START_OFFSET + 0x00C4) +#define BOLERO_CDC_VA_TOP_CSR_CORE_ID_2 (VA_START_OFFSET + 0x00C8) +#define BOLERO_CDC_VA_TOP_CSR_CORE_ID_3 (VA_START_OFFSET + 0x00CC) +#define VA_TOP_MAX_OFFSET (VA_START_OFFSET + 0x00CC) + +#define BOLERO_CDC_VA_MACRO_TOP_MAX 0x34 /* 0x0CC/4 = 0x33 + 1 = 0x34 */ + +#define BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0 (VA_START_OFFSET + 0x00D0) +#define BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1 (VA_START_OFFSET + 0x00D4) +#define BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2 (VA_START_OFFSET + 0x00D8) +#define BOLERO_CDC_VA_TOP_CSR_SWR_CTRL (VA_START_OFFSET + 0x00DC) + +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 (VA_START_OFFSET + 0x0100) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 (VA_START_OFFSET + 0x0104) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0 (VA_START_OFFSET + 0x0108) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1 (VA_START_OFFSET + 0x010C) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0 (VA_START_OFFSET + 0x0110) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG1 (VA_START_OFFSET + 0x0114) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0 (VA_START_OFFSET + 0x0118) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG1 (VA_START_OFFSET + 0x011C) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG0 (VA_START_OFFSET + 0x0120) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG1 (VA_START_OFFSET + 0x0124) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG0 (VA_START_OFFSET + 0x0128) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG1 (VA_START_OFFSET + 0x012C) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG0 (VA_START_OFFSET + 0x0130) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG1 (VA_START_OFFSET + 0x0134) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG0 (VA_START_OFFSET + 0x0138) +#define BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG1 (VA_START_OFFSET + 0x013C) + +#define BOLERO_CDC_VA_TX0_TX_PATH_CTL (VA_START_OFFSET + 0x0400) +#define BOLERO_CDC_VA_TX0_TX_PATH_CFG0 (VA_START_OFFSET + 0x0404) +#define BOLERO_CDC_VA_TX0_TX_PATH_CFG1 (VA_START_OFFSET + 0x0408) +#define BOLERO_CDC_VA_TX0_TX_VOL_CTL (VA_START_OFFSET + 0x040C) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC0 (VA_START_OFFSET + 0x0410) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC1 (VA_START_OFFSET + 0x0414) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC2 (VA_START_OFFSET + 0x0418) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC3 (VA_START_OFFSET + 0x041C) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC4 (VA_START_OFFSET + 0x0420) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC5 (VA_START_OFFSET + 0x0424) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC6 (VA_START_OFFSET + 0x0428) +#define BOLERO_CDC_VA_TX0_TX_PATH_SEC7 (VA_START_OFFSET + 0x042C) +#define BOLERO_CDC_VA_TX1_TX_PATH_CTL (VA_START_OFFSET + 0x0480) +#define BOLERO_CDC_VA_TX1_TX_PATH_CFG0 (VA_START_OFFSET + 0x0484) +#define BOLERO_CDC_VA_TX1_TX_PATH_CFG1 (VA_START_OFFSET + 0x0488) +#define BOLERO_CDC_VA_TX1_TX_VOL_CTL (VA_START_OFFSET + 0x048C) +#define BOLERO_CDC_VA_TX1_TX_PATH_SEC0 (VA_START_OFFSET + 0x0490) +#define BOLERO_CDC_VA_TX1_TX_PATH_SEC1 (VA_START_OFFSET + 0x0494) +#define BOLERO_CDC_VA_TX1_TX_PATH_SEC2 (VA_START_OFFSET + 0x0498) +#define BOLERO_CDC_VA_TX1_TX_PATH_SEC3 (VA_START_OFFSET + 0x049C) +#define BOLERO_CDC_VA_TX1_TX_PATH_SEC4 (VA_START_OFFSET + 0x04A0) +#define BOLERO_CDC_VA_TX1_TX_PATH_SEC5 (VA_START_OFFSET + 0x04A4) +#define BOLERO_CDC_VA_TX1_TX_PATH_SEC6 (VA_START_OFFSET + 0x04A8) +#define BOLERO_CDC_VA_TX2_TX_PATH_CTL (VA_START_OFFSET + 0x0500) +#define BOLERO_CDC_VA_TX2_TX_PATH_CFG0 (VA_START_OFFSET + 0x0504) +#define BOLERO_CDC_VA_TX2_TX_PATH_CFG1 (VA_START_OFFSET + 0x0508) +#define BOLERO_CDC_VA_TX2_TX_VOL_CTL (VA_START_OFFSET + 0x050C) +#define BOLERO_CDC_VA_TX2_TX_PATH_SEC0 (VA_START_OFFSET + 0x0510) +#define BOLERO_CDC_VA_TX2_TX_PATH_SEC1 (VA_START_OFFSET + 0x0514) +#define BOLERO_CDC_VA_TX2_TX_PATH_SEC2 (VA_START_OFFSET + 0x0518) +#define BOLERO_CDC_VA_TX2_TX_PATH_SEC3 (VA_START_OFFSET + 0x051C) +#define BOLERO_CDC_VA_TX2_TX_PATH_SEC4 (VA_START_OFFSET + 0x0520) +#define BOLERO_CDC_VA_TX2_TX_PATH_SEC5 (VA_START_OFFSET + 0x0524) +#define BOLERO_CDC_VA_TX2_TX_PATH_SEC6 (VA_START_OFFSET + 0x0528) +#define BOLERO_CDC_VA_TX3_TX_PATH_CTL (VA_START_OFFSET + 0x0580) +#define BOLERO_CDC_VA_TX3_TX_PATH_CFG0 (VA_START_OFFSET + 0x0584) +#define BOLERO_CDC_VA_TX3_TX_PATH_CFG1 (VA_START_OFFSET + 0x0588) +#define BOLERO_CDC_VA_TX3_TX_VOL_CTL (VA_START_OFFSET + 0x058C) +#define BOLERO_CDC_VA_TX3_TX_PATH_SEC0 (VA_START_OFFSET + 0x0590) +#define BOLERO_CDC_VA_TX3_TX_PATH_SEC1 (VA_START_OFFSET + 0x0594) +#define BOLERO_CDC_VA_TX3_TX_PATH_SEC2 (VA_START_OFFSET + 0x0598) +#define BOLERO_CDC_VA_TX3_TX_PATH_SEC3 (VA_START_OFFSET + 0x059C) +#define BOLERO_CDC_VA_TX3_TX_PATH_SEC4 (VA_START_OFFSET + 0x05A0) +#define BOLERO_CDC_VA_TX3_TX_PATH_SEC5 (VA_START_OFFSET + 0x05A4) +#define BOLERO_CDC_VA_TX3_TX_PATH_SEC6 (VA_START_OFFSET + 0x05A8) +#define BOLERO_CDC_VA_TX4_TX_PATH_CTL (VA_START_OFFSET + 0x0600) +#define BOLERO_CDC_VA_TX4_TX_PATH_CFG0 (VA_START_OFFSET + 0x0604) +#define BOLERO_CDC_VA_TX4_TX_PATH_CFG1 (VA_START_OFFSET + 0x0608) +#define BOLERO_CDC_VA_TX4_TX_VOL_CTL (VA_START_OFFSET + 0x060C) +#define BOLERO_CDC_VA_TX4_TX_PATH_SEC0 (VA_START_OFFSET + 0x0610) +#define BOLERO_CDC_VA_TX4_TX_PATH_SEC1 (VA_START_OFFSET + 0x0614) +#define BOLERO_CDC_VA_TX4_TX_PATH_SEC2 (VA_START_OFFSET + 0x0618) +#define BOLERO_CDC_VA_TX4_TX_PATH_SEC3 (VA_START_OFFSET + 0x061C) +#define BOLERO_CDC_VA_TX4_TX_PATH_SEC4 (VA_START_OFFSET + 0x0620) +#define BOLERO_CDC_VA_TX4_TX_PATH_SEC5 (VA_START_OFFSET + 0x0624) +#define BOLERO_CDC_VA_TX4_TX_PATH_SEC6 (VA_START_OFFSET + 0x0628) +#define BOLERO_CDC_VA_TX5_TX_PATH_CTL (VA_START_OFFSET + 0x0680) +#define BOLERO_CDC_VA_TX5_TX_PATH_CFG0 (VA_START_OFFSET + 0x0684) +#define BOLERO_CDC_VA_TX5_TX_PATH_CFG1 (VA_START_OFFSET + 0x0688) +#define BOLERO_CDC_VA_TX5_TX_VOL_CTL (VA_START_OFFSET + 0x068C) +#define BOLERO_CDC_VA_TX5_TX_PATH_SEC0 (VA_START_OFFSET + 0x0690) +#define BOLERO_CDC_VA_TX5_TX_PATH_SEC1 (VA_START_OFFSET + 0x0694) +#define BOLERO_CDC_VA_TX5_TX_PATH_SEC2 (VA_START_OFFSET + 0x0698) +#define BOLERO_CDC_VA_TX5_TX_PATH_SEC3 (VA_START_OFFSET + 0x069C) +#define BOLERO_CDC_VA_TX5_TX_PATH_SEC4 (VA_START_OFFSET + 0x06A0) +#define BOLERO_CDC_VA_TX5_TX_PATH_SEC5 (VA_START_OFFSET + 0x06A4) +#define BOLERO_CDC_VA_TX5_TX_PATH_SEC6 (VA_START_OFFSET + 0x06A8) +#define BOLERO_CDC_VA_TX6_TX_PATH_CTL (VA_START_OFFSET + 0x0700) +#define BOLERO_CDC_VA_TX6_TX_PATH_CFG0 (VA_START_OFFSET + 0x0704) +#define BOLERO_CDC_VA_TX6_TX_PATH_CFG1 (VA_START_OFFSET + 0x0708) +#define BOLERO_CDC_VA_TX6_TX_VOL_CTL (VA_START_OFFSET + 0x070C) +#define BOLERO_CDC_VA_TX6_TX_PATH_SEC0 (VA_START_OFFSET + 0x0710) +#define BOLERO_CDC_VA_TX6_TX_PATH_SEC1 (VA_START_OFFSET + 0x0714) +#define BOLERO_CDC_VA_TX6_TX_PATH_SEC2 (VA_START_OFFSET + 0x0718) +#define BOLERO_CDC_VA_TX6_TX_PATH_SEC3 (VA_START_OFFSET + 0x071C) +#define BOLERO_CDC_VA_TX6_TX_PATH_SEC4 (VA_START_OFFSET + 0x0720) +#define BOLERO_CDC_VA_TX6_TX_PATH_SEC5 (VA_START_OFFSET + 0x0724) +#define BOLERO_CDC_VA_TX6_TX_PATH_SEC6 (VA_START_OFFSET + 0x0728) +#define BOLERO_CDC_VA_TX7_TX_PATH_CTL (VA_START_OFFSET + 0x0780) +#define BOLERO_CDC_VA_TX7_TX_PATH_CFG0 (VA_START_OFFSET + 0x0784) +#define BOLERO_CDC_VA_TX7_TX_PATH_CFG1 (VA_START_OFFSET + 0x0788) +#define BOLERO_CDC_VA_TX7_TX_VOL_CTL (VA_START_OFFSET + 0x078C) +#define BOLERO_CDC_VA_TX7_TX_PATH_SEC0 (VA_START_OFFSET + 0x0790) +#define BOLERO_CDC_VA_TX7_TX_PATH_SEC1 (VA_START_OFFSET + 0x0794) +#define BOLERO_CDC_VA_TX7_TX_PATH_SEC2 (VA_START_OFFSET + 0x0798) +#define BOLERO_CDC_VA_TX7_TX_PATH_SEC3 (VA_START_OFFSET + 0x079C) +#define BOLERO_CDC_VA_TX7_TX_PATH_SEC4 (VA_START_OFFSET + 0x07A0) +#define BOLERO_CDC_VA_TX7_TX_PATH_SEC5 (VA_START_OFFSET + 0x07A4) +#define BOLERO_CDC_VA_TX7_TX_PATH_SEC6 (VA_START_OFFSET + 0x07A8) +#define VA_MAX_OFFSET (VA_START_OFFSET + 0x07A8) + +#define BOLERO_CDC_VA_MACRO_MAX 0x1EB /* 7A8/4 = 1EA + 1 = 1EB */ + +#define BOLERO_CDC_MAX_REGISTER VA_MAX_OFFSET + +#define BOLERO_REG(reg) (((reg) & 0x0FFF)/4) + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-regmap.c new file mode 100644 index 0000000000..3717d04b92 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-regmap.c @@ -0,0 +1,877 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + */ + +#include +#include "bolero-cdc.h" +#include "internal.h" + +static const struct reg_default bolero_defaults[] = { + /* TX Macro */ + { BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, 0x00 }, + { BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 }, + { BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_TOP_CFG0, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_ANC_CFG, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_DEBUG_BUS, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_DEBUG_EN, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_TX_I2S_CTL, 0x0C}, + { BOLERO_CDC_TX_TOP_CSR_I2S_CLK, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_I2S_RESET, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_SWR_AMIC0_CTL, 0x00}, + { BOLERO_CDC_TX_TOP_CSR_SWR_AMIC1_CTL, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG1, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG1, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG1, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0x00}, + { BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG1, 0x00}, + { BOLERO_CDC_TX_ANC0_CLK_RESET_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_MODE_1_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_MODE_2_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_FF_SHIFT, 0x00}, + { BOLERO_CDC_TX_ANC0_FB_SHIFT, 0x00}, + { BOLERO_CDC_TX_ANC0_LPF_FF_A_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_LPF_FF_B_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_LPF_FB_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_SMLPF_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_DCFLT_SHIFT_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_IIR_ADAPT_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_IIR_COEFF_1_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_IIR_COEFF_2_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_FF_A_GAIN_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_FF_B_GAIN_CTL, 0x00}, + { BOLERO_CDC_TX_ANC0_FB_GAIN_CTL, 0x00}, + { BOLERO_CDC_TX0_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX0_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX0_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX0_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX0_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX0_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX0_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX0_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX0_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX0_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX0_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_TX0_TX_PATH_SEC7, 0x25}, + { BOLERO_CDC_TX1_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX1_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX1_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX1_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX1_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX1_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX1_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX1_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX1_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX1_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX1_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_TX2_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX2_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX2_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX2_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX2_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX2_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX2_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX2_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX2_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX2_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX2_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_TX3_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX3_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX3_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX3_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX3_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX3_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX3_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX3_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX3_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX3_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX3_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_TX4_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX4_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX4_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX4_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX4_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX4_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX4_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX4_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX4_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX4_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX4_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_TX5_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX5_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX5_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX5_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX5_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX5_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX5_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX5_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX5_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX5_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX5_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_TX6_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX6_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX6_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX6_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX6_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX6_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX6_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX6_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX6_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX6_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX6_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_TX7_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_TX7_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_TX7_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_TX7_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_TX7_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_TX7_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_TX7_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_TX7_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_TX7_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_TX7_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_TX7_TX_PATH_SEC6, 0x00}, + + /* RX Macro */ + { BOLERO_CDC_RX_TOP_TOP_CFG0, 0x00}, + { BOLERO_CDC_RX_TOP_SWR_CTRL, 0x00}, + { BOLERO_CDC_RX_TOP_DEBUG, 0x00}, + { BOLERO_CDC_RX_TOP_DEBUG_BUS, 0x00}, + { BOLERO_CDC_RX_TOP_DEBUG_EN0, 0x00}, + { BOLERO_CDC_RX_TOP_DEBUG_EN1, 0x00}, + { BOLERO_CDC_RX_TOP_DEBUG_EN2, 0x00}, + { BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB, 0x00}, + { BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB, 0x00}, + { BOLERO_CDC_RX_TOP_HPHL_COMP_LUT, 0x00}, + { BOLERO_CDC_RX_TOP_HPHL_COMP_RD_LSB, 0x00}, + { BOLERO_CDC_RX_TOP_HPHL_COMP_RD_MSB, 0x00}, + { BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB, 0x00}, + { BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB, 0x00}, + { BOLERO_CDC_RX_TOP_HPHR_COMP_LUT, 0x00}, + { BOLERO_CDC_RX_TOP_HPHR_COMP_RD_LSB, 0x00}, + { BOLERO_CDC_RX_TOP_HPHR_COMP_RD_MSB, 0x00}, + { BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG0, 0x11}, + { BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG1, 0x20}, + { BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG2, 0x00}, + { BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG3, 0x00}, + { BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG0, 0x11}, + { BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG1, 0x20}, + { BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG2, 0x00}, + { BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG3, 0x00}, + { BOLERO_CDC_RX_TOP_RX_I2S_CTL, 0x0C}, + { BOLERO_CDC_RX_TOP_TX_I2S2_CTL, 0x0C}, + { BOLERO_CDC_RX_TOP_I2S_CLK, 0x0C}, + { BOLERO_CDC_RX_TOP_I2S_RESET, 0x00}, + { BOLERO_CDC_RX_TOP_I2S_MUX, 0x00}, + { BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { BOLERO_CDC_RX_CLK_RST_CTRL_DSD_CONTROL, 0x00}, + { BOLERO_CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL, 0x08}, + { BOLERO_CDC_RX_SOFTCLIP_CRC, 0x00}, + { BOLERO_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x38}, + { BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0, 0x00}, + { BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1, 0x00}, + { BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00}, + { BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00}, + { BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00}, + { BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00}, + { BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG4, 0x00}, + { BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG5, 0x00}, + { BOLERO_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00}, + { BOLERO_CDC_RX_CLSH_CRC, 0x00}, + { BOLERO_CDC_RX_CLSH_DLY_CTRL, 0x03}, + { BOLERO_CDC_RX_CLSH_DECAY_CTRL, 0x02}, + { BOLERO_CDC_RX_CLSH_HPH_V_PA, 0x1C}, + { BOLERO_CDC_RX_CLSH_EAR_V_PA, 0x39}, + { BOLERO_CDC_RX_CLSH_HPH_V_HD, 0x0C}, + { BOLERO_CDC_RX_CLSH_EAR_V_HD, 0x0C}, + { BOLERO_CDC_RX_CLSH_K1_MSB, 0x01}, + { BOLERO_CDC_RX_CLSH_K1_LSB, 0x00}, + { BOLERO_CDC_RX_CLSH_K2_MSB, 0x00}, + { BOLERO_CDC_RX_CLSH_K2_LSB, 0x80}, + { BOLERO_CDC_RX_CLSH_IDLE_CTRL, 0x00}, + { BOLERO_CDC_RX_CLSH_IDLE_HPH, 0x00}, + { BOLERO_CDC_RX_CLSH_IDLE_EAR, 0x00}, + { BOLERO_CDC_RX_CLSH_TEST0, 0x07}, + { BOLERO_CDC_RX_CLSH_TEST1, 0x00}, + { BOLERO_CDC_RX_CLSH_OVR_VREF, 0x00}, + { BOLERO_CDC_RX_CLSH_CLSG_CTL, 0x02}, + { BOLERO_CDC_RX_CLSH_CLSG_CFG1, 0x9A}, + { BOLERO_CDC_RX_CLSH_CLSG_CFG2, 0x10}, + { BOLERO_CDC_RX_BCL_VBAT_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_CFG, 0x10}, + { BOLERO_CDC_RX_BCL_VBAT_ADC_CAL1, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_ADC_CAL2, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_ADC_CAL3, 0x04}, + { BOLERO_CDC_RX_BCL_VBAT_PK_EST1, 0xE0}, + { BOLERO_CDC_RX_BCL_VBAT_PK_EST2, 0x01}, + { BOLERO_CDC_RX_BCL_VBAT_PK_EST3, 0x40}, + { BOLERO_CDC_RX_BCL_VBAT_RF_PROC1, 0x2A}, + { BOLERO_CDC_RX_BCL_VBAT_RF_PROC2, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_TAC1, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_TAC2, 0x18}, + { BOLERO_CDC_RX_BCL_VBAT_TAC3, 0x18}, + { BOLERO_CDC_RX_BCL_VBAT_TAC4, 0x03}, + { BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD1, 0x01}, + { BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD2, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD3, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD4, 0x64}, + { BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD5, 0x01}, + { BOLERO_CDC_RX_BCL_VBAT_DEBUG1, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD_MON, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_GAIN_MON_VAL, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_BAN, 0x0C}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, 0x77}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, 0x01}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, 0x4B}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, 0x01}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_ATTN1, 0x04}, + { BOLERO_CDC_RX_BCL_VBAT_ATTN2, 0x08}, + { BOLERO_CDC_RX_BCL_VBAT_ATTN3, 0x0C}, + { BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL1, 0xE0}, + { BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL2, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG1, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG2, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG3, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG4, 0x00}, + { BOLERO_CDC_RX_BCL_VBAT_DECODE_ST, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_CFG, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_CLR_COMMIT, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_PIN1_MASK0, 0xFF}, + { BOLERO_CDC_RX_INTR_CTRL_PIN1_STATUS0, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_PIN1_CLEAR0, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_PIN2_MASK0, 0xFF}, + { BOLERO_CDC_RX_INTR_CTRL_PIN2_STATUS0, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_PIN2_CLEAR0, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_LEVEL0, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_BYPASS0, 0x00}, + { BOLERO_CDC_RX_INTR_CTRL_SET0, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_CTL, 0x04}, + { BOLERO_CDC_RX_RX0_RX_PATH_CFG0, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_CFG1, 0x64}, + { BOLERO_CDC_RX_RX0_RX_PATH_CFG2, 0x8F}, + { BOLERO_CDC_RX_RX0_RX_PATH_CFG3, 0x00}, + { BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL, 0x04}, + { BOLERO_CDC_RX_RX0_RX_PATH_MIX_CFG, 0x7E}, + { BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x08}, + { BOLERO_CDC_RX_RX0_RX_PATH_SEC2, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_SEC3, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_SEC4, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_SEC7, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_MIX_SEC0, 0x08}, + { BOLERO_CDC_RX_RX0_RX_PATH_MIX_SEC1, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL, 0x08}, + { BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA1, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA2, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA3, 0x00}, + { BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA4, 0x55}, + { BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA5, 0x55}, + { BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA6, 0x55}, + { BOLERO_CDC_RX_RX1_RX_PATH_CTL, 0x04}, + { BOLERO_CDC_RX_RX1_RX_PATH_CFG0, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_CFG1, 0x64}, + { BOLERO_CDC_RX_RX1_RX_PATH_CFG2, 0x8F}, + { BOLERO_CDC_RX_RX1_RX_PATH_CFG3, 0x00}, + { BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04}, + { BOLERO_CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E}, + { BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x08}, + { BOLERO_CDC_RX_RX1_RX_PATH_SEC2, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_SEC3, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_SEC4, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_SEC7, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08}, + { BOLERO_CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08}, + { BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00}, + { BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55}, + { BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55}, + { BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55}, + { BOLERO_CDC_RX_RX2_RX_PATH_CTL, 0x04}, + { BOLERO_CDC_RX_RX2_RX_PATH_CFG0, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_CFG1, 0x64}, + { BOLERO_CDC_RX_RX2_RX_PATH_CFG2, 0x8F}, + { BOLERO_CDC_RX_RX2_RX_PATH_CFG3, 0x00}, + { BOLERO_CDC_RX_RX2_RX_VOL_CTL, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04}, + { BOLERO_CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E}, + { BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC0, 0x04}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC1, 0x08}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC2, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC3, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC4, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC5, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC6, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_SEC7, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08}, + { BOLERO_CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00}, + { BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00}, + { BOLERO_CDC_RX_IDLE_DETECT_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_IDLE_DETECT_CFG0, 0x07}, + { BOLERO_CDC_RX_IDLE_DETECT_CFG1, 0x3C}, + { BOLERO_CDC_RX_IDLE_DETECT_CFG2, 0x00}, + { BOLERO_CDC_RX_IDLE_DETECT_CFG3, 0x00}, + { BOLERO_CDC_RX_COMPANDER0_CTL0, 0x60}, + { BOLERO_CDC_RX_COMPANDER0_CTL1, 0xDB}, + { BOLERO_CDC_RX_COMPANDER0_CTL2, 0xFF}, + { BOLERO_CDC_RX_COMPANDER0_CTL3, 0x35}, + { BOLERO_CDC_RX_COMPANDER0_CTL4, 0xFF}, + { BOLERO_CDC_RX_COMPANDER0_CTL5, 0x00}, + { BOLERO_CDC_RX_COMPANDER0_CTL6, 0x01}, + { BOLERO_CDC_RX_COMPANDER0_CTL7, 0x28}, + { BOLERO_CDC_RX_COMPANDER1_CTL0, 0x60}, + { BOLERO_CDC_RX_COMPANDER1_CTL1, 0xDB}, + { BOLERO_CDC_RX_COMPANDER1_CTL2, 0xFF}, + { BOLERO_CDC_RX_COMPANDER1_CTL3, 0x35}, + { BOLERO_CDC_RX_COMPANDER1_CTL4, 0xFF}, + { BOLERO_CDC_RX_COMPANDER1_CTL5, 0x00}, + { BOLERO_CDC_RX_COMPANDER1_CTL6, 0x01}, + { BOLERO_CDC_RX_COMPANDER1_CTL7, 0x28}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_CTL, 0x40}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_CTL, 0x40}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL, 0x00}, + { BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00}, + { BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00}, + { BOLERO_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04}, + { BOLERO_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00}, + { BOLERO_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL, 0x04}, + { BOLERO_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1, 0x00}, + { BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0, 0x01}, + { BOLERO_CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0, 0x01}, + { BOLERO_CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0, 0x01}, + { BOLERO_CDC_RX_EC_ASRC0_CLK_RST_CTL, 0x00}, + { BOLERO_CDC_RX_EC_ASRC0_CTL0, 0x00}, + { BOLERO_CDC_RX_EC_ASRC0_CTL1, 0x00}, + { BOLERO_CDC_RX_EC_ASRC0_FIFO_CTL, 0xA8}, + { BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC0_STATUS_FIFO, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_CLK_RST_CTL, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_CTL0, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_CTL1, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_FIFO_CTL, 0xA8}, + { BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC1_STATUS_FIFO, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_CLK_RST_CTL, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_CTL0, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_CTL1, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_FIFO_CTL, 0xA8}, + { BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB, 0x00}, + { BOLERO_CDC_RX_EC_ASRC2_STATUS_FIFO, 0x00}, + { BOLERO_CDC_RX_DSD0_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_DSD0_CFG0, 0x00}, + { BOLERO_CDC_RX_DSD0_CFG1, 0x62}, + { BOLERO_CDC_RX_DSD0_CFG2, 0x96}, + { BOLERO_CDC_RX_DSD1_PATH_CTL, 0x00}, + { BOLERO_CDC_RX_DSD1_CFG0, 0x00}, + { BOLERO_CDC_RX_DSD1_CFG1, 0x62}, + { BOLERO_CDC_RX_DSD1_CFG2, 0x96}, + + /* WSA Macro */ + { BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { BOLERO_CDC_WSA_TOP_TOP_CFG0, 0x00}, + { BOLERO_CDC_WSA_TOP_TOP_CFG1, 0x00}, + { BOLERO_CDC_WSA_TOP_FREQ_MCLK, 0x00}, + { BOLERO_CDC_WSA_TOP_DEBUG_BUS_SEL, 0x00}, + { BOLERO_CDC_WSA_TOP_DEBUG_EN0, 0x00}, + { BOLERO_CDC_WSA_TOP_DEBUG_EN1, 0x00}, + { BOLERO_CDC_WSA_TOP_DEBUG_DSM_LB, 0x88}, + { BOLERO_CDC_WSA_TOP_RX_I2S_CTL, 0x0C}, + { BOLERO_CDC_WSA_TOP_TX_I2S_CTL, 0x0C}, + { BOLERO_CDC_WSA_TOP_I2S_CLK, 0x02}, + { BOLERO_CDC_WSA_TOP_I2S_RESET, 0x00}, + { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, 0x00}, + { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, 0x00}, + { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, 0x00}, + { BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, 0x00}, + { BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00}, + { BOLERO_CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00}, + { BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x10}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3, 0x04}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST1, 0xE0}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST2, 0x01}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST3, 0x40}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1, 0x2A}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC1, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC2, 0x18}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC3, 0x18}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC4, 0x03}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1, 0x01}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4, 0x64}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5, 0x01}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DEBUG1, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BAN, 0x0C}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2, 0x77}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3, 0x01}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5, 0x4B}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7, 0x01}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1, 0x04}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2, 0x08}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3, 0x0C}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1, 0xE0}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL2, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4, 0x00}, + { BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST, 0x00}, + { BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02}, + { BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00}, + { BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02}, + { BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00}, + { BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02}, + { BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00}, + { BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02}, + { BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_CFG, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF}, + { BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_PIN1_CLEAR0, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_PIN2_MASK0, 0xFF}, + { BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_PIN2_CLEAR0, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_LEVEL0, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_BYPASS0, 0x00}, + { BOLERO_CDC_WSA_INTR_CTRL_SET0, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_CTL, 0x04}, + { BOLERO_CDC_WSA_RX0_RX_PATH_CFG0, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 0x64}, + { BOLERO_CDC_WSA_RX0_RX_PATH_CFG2, 0x8F}, + { BOLERO_CDC_WSA_RX0_RX_PATH_CFG3, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_VOL_CTL, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL, 0x04}, + { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x7E}, + { BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_SEC0, 0x04}, + { BOLERO_CDC_WSA_RX0_RX_PATH_SEC1, 0x08}, + { BOLERO_CDC_WSA_RX0_RX_PATH_SEC2, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_SEC3, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_SEC5, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_SEC6, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_SEC7, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0, 0x08}, + { BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC1, 0x00}, + { BOLERO_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_CFG0, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_CFG1, 0x64}, + { BOLERO_CDC_WSA_RX1_RX_PATH_CFG2, 0x8F}, + { BOLERO_CDC_WSA_RX1_RX_PATH_CFG3, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_VOL_CTL, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL, 0x04}, + { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x7E}, + { BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_SEC0, 0x04}, + { BOLERO_CDC_WSA_RX1_RX_PATH_SEC1, 0x08}, + { BOLERO_CDC_WSA_RX1_RX_PATH_SEC2, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_SEC3, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_SEC5, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_SEC6, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_SEC7, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0, 0x08}, + { BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC1, 0x00}, + { BOLERO_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL, 0x00}, + { BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL, 0x00}, + { BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0xD0}, + { BOLERO_CDC_WSA_BOOST0_BOOST_CFG1, 0x89}, + { BOLERO_CDC_WSA_BOOST0_BOOST_CFG2, 0x04}, + { BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL, 0x00}, + { BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0xD0}, + { BOLERO_CDC_WSA_BOOST1_BOOST_CFG1, 0x89}, + { BOLERO_CDC_WSA_BOOST1_BOOST_CFG2, 0x04}, + { BOLERO_CDC_WSA_COMPANDER0_CTL0, 0x60}, + { BOLERO_CDC_WSA_COMPANDER0_CTL1, 0xDB}, + { BOLERO_CDC_WSA_COMPANDER0_CTL2, 0xFF}, + { BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x35}, + { BOLERO_CDC_WSA_COMPANDER0_CTL4, 0xFF}, + { BOLERO_CDC_WSA_COMPANDER0_CTL5, 0x00}, + { BOLERO_CDC_WSA_COMPANDER0_CTL6, 0x01}, + { BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x28}, + { BOLERO_CDC_WSA_COMPANDER1_CTL0, 0x60}, + { BOLERO_CDC_WSA_COMPANDER1_CTL1, 0xDB}, + { BOLERO_CDC_WSA_COMPANDER1_CTL2, 0xFF}, + { BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x35}, + { BOLERO_CDC_WSA_COMPANDER1_CTL4, 0xFF}, + { BOLERO_CDC_WSA_COMPANDER1_CTL5, 0x00}, + { BOLERO_CDC_WSA_COMPANDER1_CTL6, 0x01}, + { BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x28}, + { BOLERO_CDC_WSA_SOFTCLIP0_CRC, 0x00}, + { BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38}, + { BOLERO_CDC_WSA_SOFTCLIP1_CRC, 0x00}, + { BOLERO_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, + { BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, + { BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01}, + { BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, + { BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0, 0x01}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_CTL0, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_CTL1, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_FIFO_CTL, 0xA8}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_CTL0, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_CTL1, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_FIFO_CTL, 0xA8}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00}, + { BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00}, + + /* VA macro */ + { BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_TOP_CFG0, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, 0x80}, + { BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_DEBUG_EN, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_TX_I2S_CTL, 0x0C}, + { BOLERO_CDC_VA_TOP_CSR_I2S_CLK, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_I2S_RESET, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_CORE_ID_0, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_CORE_ID_1, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_CORE_ID_2, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_CORE_ID_3, 0x00}, + { BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE}, + { BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE}, + { BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE}, + { BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x06}, + + /* VA core */ + { BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG1, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG1, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG1, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG1, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG1, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG0, 0x00}, + { BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG1, 0x00}, + { BOLERO_CDC_VA_TX0_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX0_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX0_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX0_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_VA_TX0_TX_PATH_SEC7, 0x25}, + { BOLERO_CDC_VA_TX1_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX1_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX1_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX1_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX1_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX1_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX1_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX1_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX1_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX1_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX1_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_VA_TX2_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX2_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX2_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX2_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX2_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX2_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX2_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX2_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX2_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX2_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX2_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_VA_TX3_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX3_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX3_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX3_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX3_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX3_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX3_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX3_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX3_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX3_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX3_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_VA_TX4_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX4_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX4_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX4_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX4_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX4_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX4_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX4_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX4_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX4_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX4_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_VA_TX5_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX5_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX5_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX5_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX5_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX5_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX5_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX5_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX5_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX5_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX5_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_VA_TX6_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX6_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX6_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX6_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX6_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX6_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX6_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX6_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX6_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX6_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX6_TX_PATH_SEC6, 0x00}, + { BOLERO_CDC_VA_TX7_TX_PATH_CTL, 0x04}, + { BOLERO_CDC_VA_TX7_TX_PATH_CFG0, 0x10}, + { BOLERO_CDC_VA_TX7_TX_PATH_CFG1, 0x0B}, + { BOLERO_CDC_VA_TX7_TX_VOL_CTL, 0x00}, + { BOLERO_CDC_VA_TX7_TX_PATH_SEC0, 0x00}, + { BOLERO_CDC_VA_TX7_TX_PATH_SEC1, 0x00}, + { BOLERO_CDC_VA_TX7_TX_PATH_SEC2, 0x01}, + { BOLERO_CDC_VA_TX7_TX_PATH_SEC3, 0x3C}, + { BOLERO_CDC_VA_TX7_TX_PATH_SEC4, 0x20}, + { BOLERO_CDC_VA_TX7_TX_PATH_SEC5, 0x00}, + { BOLERO_CDC_VA_TX7_TX_PATH_SEC6, 0x00}, +}; + +static bool bolero_is_readable_register(struct device *dev, + unsigned int reg) +{ + struct bolero_priv *priv = dev_get_drvdata(dev); + u16 reg_offset; + int macro_id; + u8 *reg_tbl = NULL; + + if (!priv) + return false; + + macro_id = bolero_get_macro_id(priv->va_without_decimation, + reg); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return false; + + reg_tbl = bolero_reg_access[macro_id]; + reg_offset = (reg - macro_id_base_offset[macro_id])/4; + + if (reg_tbl) + return (reg_tbl[reg_offset] & RD_REG); + + return false; +} + +static bool bolero_is_writeable_register(struct device *dev, + unsigned int reg) +{ + struct bolero_priv *priv = dev_get_drvdata(dev); + u16 reg_offset; + int macro_id; + const u8 *reg_tbl = NULL; + + if (!priv) + return false; + + macro_id = bolero_get_macro_id(priv->va_without_decimation, + reg); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return false; + + reg_tbl = bolero_reg_access[macro_id]; + reg_offset = (reg - macro_id_base_offset[macro_id])/4; + + if (reg_tbl) + return (reg_tbl[reg_offset] & WR_REG); + + return false; +} + +static bool bolero_is_volatile_register(struct device *dev, + unsigned int reg) +{ + /* Update volatile list for rx/tx macros */ + switch (reg) { + case BOLERO_CDC_VA_TOP_CSR_CORE_ID_0: + case BOLERO_CDC_VA_TOP_CSR_CORE_ID_1: + case BOLERO_CDC_VA_TOP_CSR_CORE_ID_2: + case BOLERO_CDC_VA_TOP_CSR_CORE_ID_3: + case BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL: + case BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL: + case BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL: + case BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_MIC0_CTL: + case BOLERO_CDC_TX_TOP_CSR_SWR_MIC1_CTL: + case BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL: + case BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST: + case BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0: + case BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0: + case BOLERO_CDC_WSA_COMPANDER0_CTL6: + case BOLERO_CDC_WSA_COMPANDER1_CTL6: + case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB: + case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB: + case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB: + case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB: + case BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO: + case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB: + case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB: + case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB: + case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB: + case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO: + case BOLERO_CDC_RX_TOP_HPHL_COMP_RD_LSB: + case BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB: + case BOLERO_CDC_RX_TOP_HPHL_COMP_RD_MSB: + case BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB: + case BOLERO_CDC_RX_TOP_HPHR_COMP_RD_LSB: + case BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB: + case BOLERO_CDC_RX_TOP_HPHR_COMP_RD_MSB: + case BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB: + case BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG2: + case BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG2: + case BOLERO_CDC_RX_BCL_VBAT_GAIN_MON_VAL: + case BOLERO_CDC_RX_BCL_VBAT_DECODE_ST: + case BOLERO_CDC_RX_INTR_CTRL_PIN1_STATUS0: + case BOLERO_CDC_RX_INTR_CTRL_PIN2_STATUS0: + case BOLERO_CDC_RX_COMPANDER0_CTL6: + case BOLERO_CDC_RX_COMPANDER1_CTL6: + case BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB: + case BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB: + case BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB: + case BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB: + case BOLERO_CDC_RX_EC_ASRC0_STATUS_FIFO: + case BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB: + case BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB: + case BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB: + case BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB: + case BOLERO_CDC_RX_EC_ASRC1_STATUS_FIFO: + case BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB: + case BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB: + case BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB: + case BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB: + case BOLERO_CDC_RX_EC_ASRC2_STATUS_FIFO: + case BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL: + case BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL: + case BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL: + case BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL: + return true; + } + return false; +} + +const struct regmap_config bolero_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .reg_stride = 4, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = bolero_defaults, + .num_reg_defaults = ARRAY_SIZE(bolero_defaults), + .max_register = BOLERO_CDC_MAX_REGISTER, + .writeable_reg = bolero_is_writeable_register, + .volatile_reg = bolero_is_volatile_register, + .readable_reg = bolero_is_readable_register, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-tables.c new file mode 100644 index 0000000000..4d04767cc1 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-tables.c @@ -0,0 +1,982 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + */ + +#include +#include "bolero-cdc.h" +#include "internal.h" + +u8 bolero_tx_reg_access[BOLERO_CDC_TX_MACRO_MAX] = { + [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_ANC_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_I2S_CLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_I2S_RESET)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_AMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_AMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_CLK_RESET_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_MODE_1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_MODE_2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_SHIFT)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FB_SHIFT)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FF_A_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FF_B_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FB_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_SMLPF_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_DCFLT_SHIFT_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_ADAPT_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_COEFF_1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_COEFF_2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_A_GAIN_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_B_GAIN_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FB_GAIN_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX4_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX5_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX6_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC6)] = RD_WR_REG, +}; + +u8 bolero_tx_reg_access_v2[BOLERO_CDC_TX_MACRO_MAX] = { + [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_ANC_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_I2S_CLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_I2S_RESET)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_AMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_AMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_CLK_RESET_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_MODE_1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_MODE_2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_SHIFT)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FB_SHIFT)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FF_A_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FF_B_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FB_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_SMLPF_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_DCFLT_SHIFT_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_ADAPT_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_COEFF_1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_COEFF_2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_A_GAIN_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_B_GAIN_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_ANC0_FB_GAIN_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC6)] = RD_WR_REG, +}; + +u8 bolero_rx_reg_access[BOLERO_CDC_RX_MACRO_MAX] = { + [BOLERO_REG(BOLERO_CDC_RX_TOP_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_SWR_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DEBUG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DEBUG_BUS)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DEBUG_EN0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DEBUG_EN1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DEBUG_EN2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHL_COMP_LUT)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHL_COMP_RD_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHL_COMP_RD_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHR_COMP_LUT)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHR_COMP_RD_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_HPHR_COMP_RD_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG2)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG2)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_RX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_TX_I2S2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_I2S_CLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_I2S_RESET)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_TOP_I2S_MUX)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLK_RST_CTRL_DSD_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SOFTCLIP_CRC)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_CRC)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_DLY_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_DECAY_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_HPH_V_PA)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_EAR_V_PA)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_HPH_V_HD)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_EAR_V_HD)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_K1_MSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_K1_LSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_K2_MSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_K2_LSB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_IDLE_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_IDLE_HPH)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_IDLE_EAR)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_TEST0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_TEST1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_OVR_VREF)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_CLSG_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_CLSG_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_CLSH_CLSG_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_ADC_CAL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_ADC_CAL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_ADC_CAL3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_PK_EST1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_PK_EST2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_PK_EST3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_RF_PROC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_RF_PROC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_TAC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_TAC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_TAC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_TAC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DEBUG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_GAIN_UPD_MON)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_GAIN_MON_VAL)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BAN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_ATTN1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_ATTN2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_ATTN3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_BCL_VBAT_DECODE_ST)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_CLR_COMMIT)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_PIN1_MASK0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_PIN1_STATUS0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_PIN1_CLEAR0)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_PIN2_MASK0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_PIN2_STATUS0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_PIN2_CLEAR0)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_LEVEL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_BYPASS0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_INTR_CTRL_SET0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_MIX_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX0_RX_PATH_DSM_DATA6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_MIX_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_DSM_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX1_RX_PATH_DSM_DATA6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_MIX_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IDLE_DETECT_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IDLE_DETECT_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IDLE_DETECT_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IDLE_DETECT_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IDLE_DETECT_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL6)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER0_CTL7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL6)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_COMPANDER1_CTL7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = + RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] = + RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_CLK_RST_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_FIFO_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC0_STATUS_FIFO)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_CLK_RST_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_FIFO_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC1_STATUS_FIFO)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_CLK_RST_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_FIFO_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_EC_ASRC2_STATUS_FIFO)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD0_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD0_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD1_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_RX_DSD1_CFG2)] = RD_WR_REG, +}; + +u8 bolero_va_reg_access[BOLERO_CDC_VA_MACRO_MAX] = { + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_CLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_RESET)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_1)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_2)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX4_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX5_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX6_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX7_TX_PATH_SEC6)] = RD_WR_REG, +}; + +u8 bolero_va_top_reg_access[BOLERO_CDC_VA_MACRO_TOP_MAX] = { + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_1)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_2)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG, +}; + +u8 bolero_va_reg_access_v2[BOLERO_CDC_VA_MACRO_MAX] = { + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_CLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_RESET)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_1)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_2)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC6)] = RD_WR_REG, +}; + +u8 bolero_va_reg_access_v3[BOLERO_CDC_VA_MACRO_MAX] = { + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_CLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_RESET)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_1)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_2)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC6)] = RD_WR_REG, +}; + +u8 bolero_wsa_reg_access[BOLERO_CDC_WSA_MACRO_MAX] = { + [BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_TOP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_TOP_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_FREQ_MCLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_BUS_SEL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_EN0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_EN1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_DEBUG_DSM_LB)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_RX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_TX_I2S_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_I2S_CLK)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TOP_I2S_RESET)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_RX_EC_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_PK_EST3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_TAC4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DEBUG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BAN)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_CLR_COMMIT)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN1_MASK0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN1_CLEAR0)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN2_MASK0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN2_STATUS0)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_PIN2_CLEAR0)] = WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_LEVEL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_BYPASS0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_INTR_CTRL_SET0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_CFG3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_VOL_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC6)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_SEC7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST0_BOOST_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_CFG1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_BOOST1_BOOST_CFG2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL6)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER0_CTL7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL2)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL3)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL4)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL5)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL6)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_COMPANDER1_CTL7)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP0_CRC)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP1_CRC)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_FIFO_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC0_STATUS_FIFO)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_CTL0)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_CTL1)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_FIFO_CTL)] = RD_WR_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [BOLERO_REG(BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO)] = RD_REG, +}; + +u8 *bolero_reg_access[MAX_MACRO] = { + [TX_MACRO] = bolero_tx_reg_access, + [RX_MACRO] = bolero_rx_reg_access, + [WSA_MACRO] = bolero_wsa_reg_access, + [VA_MACRO] = bolero_va_reg_access, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-utils.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-utils.c new file mode 100644 index 0000000000..f2e4ec47f9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc-utils.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "bolero-cdc.h" +#include "internal.h" + +#define REG_BYTES 2 +#define VAL_BYTES 1 + +const u16 macro_id_base_offset[MAX_MACRO] = { + TX_START_OFFSET, + RX_START_OFFSET, + WSA_START_OFFSET, + VA_START_OFFSET, +}; + +int bolero_get_macro_id(bool va_no_dec_flag, u16 reg) +{ + if (reg >= TX_START_OFFSET + && reg <= TX_MAX_OFFSET) + return TX_MACRO; + if (reg >= RX_START_OFFSET + && reg <= RX_MAX_OFFSET) + return RX_MACRO; + if (reg >= WSA_START_OFFSET + && reg <= WSA_MAX_OFFSET) + return WSA_MACRO; + if (!va_no_dec_flag && + (reg >= VA_START_OFFSET && + reg <= VA_MAX_OFFSET)) + return VA_MACRO; + if (va_no_dec_flag && + (reg >= VA_START_OFFSET && + reg <= VA_TOP_MAX_OFFSET)) + return VA_MACRO; + + return -EINVAL; +} + +static int regmap_bus_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct bolero_priv *priv = dev_get_drvdata(dev); + u16 *reg_p; + u16 __reg; + int macro_id, i; + u8 temp = 0; + int ret = -EINVAL; + + if (!priv) { + dev_err(dev, "%s: priv is NULL\n", __func__); + return ret; + } + if (!reg || !val) { + dev_err(dev, "%s: reg or val is NULL\n", __func__); + return ret; + } + if (reg_size != REG_BYTES) { + dev_err(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return ret; + } + + reg_p = (u16 *)reg; + macro_id = bolero_get_macro_id(priv->va_without_decimation, + reg_p[0]); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return 0; + + mutex_lock(&priv->io_lock); + for (i = 0; i < val_size; i++) { + __reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id]; + ret = priv->read_dev(priv, macro_id, __reg, &temp); + if (ret < 0) { + dev_err_ratelimited(dev, + "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n", + __func__, ret, reg_p[0] + i * 4, val_size); + break; + } + ((u8 *)val)[i] = temp; + dev_dbg(dev, "%s: Read 0x%02x from reg 0x%x\n", + __func__, temp, reg_p[0] + i * 4); + } + mutex_unlock(&priv->io_lock); + + return ret; +} + +static int regmap_bus_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) +{ + struct device *dev = context; + struct bolero_priv *priv = dev_get_drvdata(dev); + u16 *reg_p; + u16 __reg; + int macro_id, i; + int ret = -EINVAL; + + if (!priv) { + dev_err(dev, "%s: priv is NULL\n", __func__); + return ret; + } + if (!reg || !val) { + dev_err(dev, "%s: reg or val is NULL\n", __func__); + return ret; + } + if (reg_size != REG_BYTES) { + dev_err(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return ret; + } + + reg_p = (u16 *)reg; + macro_id = bolero_get_macro_id(priv->va_without_decimation, + reg_p[0]); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return 0; + + mutex_lock(&priv->io_lock); + for (i = 0; i < val_size; i++) { + __reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id]; + ret = priv->write_dev(priv, macro_id, __reg, ((u8 *)val)[i]); + if (ret < 0) { + dev_err_ratelimited(dev, + "%s: Codec write failed (%d), reg:0x%x, size:%zd\n", + __func__, ret, reg_p[0] + i * 4, val_size); + break; + } + dev_dbg(dev, "Write %02x to reg 0x%x\n", ((u8 *)val)[i], + reg_p[0] + i * 4); + } + mutex_unlock(&priv->io_lock); + return ret; +} + +static int regmap_bus_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct bolero_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -EINVAL; + + if (count < REG_BYTES) { + dev_err(dev, "%s: count %zd bytes < %d, not supported\n", + __func__, count, REG_BYTES); + return -EINVAL; + } + + return regmap_bus_gather_write(context, data, REG_BYTES, + data + REG_BYTES, + count - REG_BYTES); +} + +static struct regmap_bus regmap_bus_config = { + .write = regmap_bus_write, + .gather_write = regmap_bus_gather_write, + .read = regmap_bus_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +struct regmap *bolero_regmap_init(struct device *dev, + const struct regmap_config *config) +{ + return devm_regmap_init(dev, ®map_bus_config, dev, config); +} diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc.c new file mode 100644 index 0000000000..e5aa94454c --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc.c @@ -0,0 +1,1621 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bolero-cdc.h" +#include "internal.h" +#include "bolero-clk-rsc.h" +#include "asoc/bolero-slave-internal.h" +#include + +#define DRV_NAME "bolero_codec" + +#define BOLERO_VERSION_ENTRY_SIZE 32 +#define BOLERO_CDC_STRING_LEN 80 + +static const struct snd_soc_component_driver bolero; + +/* pm runtime auto suspend timer in msecs */ +#define BOLERO_AUTO_SUSPEND_DELAY 100 /* delay in msec */ + +/* MCLK_MUX table for all macros */ +static u16 bolero_mclk_mux_tbl[MAX_MACRO][MCLK_MUX_MAX] = { + {TX_MACRO, VA_MACRO}, + {TX_MACRO, RX_MACRO}, + {TX_MACRO, WSA_MACRO}, + {TX_MACRO, VA_MACRO}, +}; + +static bool bolero_is_valid_codec_dev(struct device *dev); + +int bolero_set_port_map(struct snd_soc_component *component, + u32 size, void *data) +{ + struct bolero_priv *priv = NULL; + struct swr_mstr_port_map *map = NULL; + u16 idx; + + if (!component || (size == 0) || !data) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!bolero_is_valid_codec_dev(priv->dev)) { + dev_err(priv->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + map = (struct swr_mstr_port_map *)data; + + for (idx = 0; idx < size; idx++) { + if (priv->macro_params[map->id].set_port_map) + priv->macro_params[map->id].set_port_map(component, + map->uc, + SWR_MSTR_PORT_LEN, + map->swr_port_params); + map += 1; + } + + return 0; +} +EXPORT_SYMBOL(bolero_set_port_map); + +static void bolero_ahb_write_device(char __iomem *io_base, + u16 reg, u8 value) +{ + u32 temp = (u32)(value) & 0x000000FF; + + iowrite32(temp, io_base + reg); +} + +static void bolero_ahb_read_device(char __iomem *io_base, + u16 reg, u8 *value) +{ + u32 temp; + + temp = ioread32(io_base + reg); + *value = (u8)temp; +} + +static int __bolero_reg_read(struct bolero_priv *priv, + u16 macro_id, u16 reg, u8 *val) +{ + int ret = 0; + + mutex_lock(&priv->clk_lock); + if (!priv->dev_up) { + dev_dbg_ratelimited(priv->dev, + "%s: SSR in progress, exit\n", __func__); + ret = -EINVAL; + goto ssr_err; + } + + if (priv->macro_params[VA_MACRO].dev) { + pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev); + if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev)) + goto ssr_err; + } + + if (priv->version < BOLERO_VERSION_2_0) { + /* Request Clk before register access */ + ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + priv->macro_params[macro_id].default_clk_id, + priv->macro_params[macro_id].clk_id_req, + true); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: Failed to enable clock, ret:%d\n", + __func__, ret); + goto err; + } + } + + bolero_ahb_read_device( + priv->macro_params[macro_id].io_base, reg, val); + + if (priv->version < BOLERO_VERSION_2_0) + bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + priv->macro_params[macro_id].default_clk_id, + priv->macro_params[macro_id].clk_id_req, + false); + +err: + if (priv->macro_params[VA_MACRO].dev) { + pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev); + pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev); + } +ssr_err: + mutex_unlock(&priv->clk_lock); + return ret; +} + +static int __bolero_reg_write(struct bolero_priv *priv, + u16 macro_id, u16 reg, u8 val) +{ + int ret = 0; + + mutex_lock(&priv->clk_lock); + if (!priv->dev_up) { + dev_dbg_ratelimited(priv->dev, + "%s: SSR in progress, exit\n", __func__); + ret = -EINVAL; + goto ssr_err; + } + if (priv->macro_params[VA_MACRO].dev) { + pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev); + if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev)) + goto ssr_err; + } + + if (priv->version < BOLERO_VERSION_2_0) { + /* Request Clk before register access */ + ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + priv->macro_params[macro_id].default_clk_id, + priv->macro_params[macro_id].clk_id_req, + true); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: Failed to enable clock, ret:%d\n", + __func__, ret); + goto err; + } + } + + bolero_ahb_write_device( + priv->macro_params[macro_id].io_base, reg, val); + + if (priv->version < BOLERO_VERSION_2_0) + bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + priv->macro_params[macro_id].default_clk_id, + priv->macro_params[macro_id].clk_id_req, + false); + +err: + if (priv->macro_params[VA_MACRO].dev) { + pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev); + pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev); + } +ssr_err: + mutex_unlock(&priv->clk_lock); + return ret; +} + +static int bolero_cdc_update_wcd_event(void *handle, u16 event, u32 data) +{ + struct bolero_priv *priv = (struct bolero_priv *)handle; + + if (!priv) { + pr_err("%s:Invalid bolero priv handle\n", __func__); + return -EINVAL; + } + + switch (event) { + case SLV_BOLERO_EVT_RX_MUTE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_RX_MUTE, data); + break; + case SLV_BOLERO_EVT_IMPED_TRUE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_IMPED_TRUE, data); + break; + case SLV_BOLERO_EVT_IMPED_FALSE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_IMPED_FALSE, data); + break; + case SLV_BOLERO_EVT_RX_COMPANDER_SOFT_RST: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST, data); + break; + case SLV_BOLERO_EVT_BCS_CLK_OFF: + if (priv->macro_params[TX_MACRO].event_handler) + priv->macro_params[TX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_BCS_CLK_OFF, data); + break; + case SLV_BOLERO_EVT_RX_PA_GAIN_UPDATE: + /* Update PA Gain for bolero version 2.1 and 2.2*/ + if ((priv->version == BOLERO_VERSION_2_1) || + (priv->version == BOLERO_VERSION_2_2)) + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_RX_PA_GAIN_UPDATE, + data); + break; + case SLV_BOLERO_EVT_HPHL_HD2_ENABLE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_HPHL_HD2_ENABLE, data); + break; + case SLV_BOLERO_EVT_HPHR_HD2_ENABLE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + BOLERO_MACRO_EVT_HPHR_HD2_ENABLE, data); + break; + default: + dev_err(priv->dev, "%s: Invalid event %d trigger from wcd\n", + __func__, event); + return -EINVAL; + } + return 0; +} + +static int bolero_cdc_register_notifier(void *handle, + struct notifier_block *nblock, + bool enable) +{ + struct bolero_priv *priv = (struct bolero_priv *)handle; + + if (!priv) { + pr_err("%s: bolero priv is null\n", __func__); + return -EINVAL; + } + if (enable) + return blocking_notifier_chain_register(&priv->notifier, + nblock); + + return blocking_notifier_chain_unregister(&priv->notifier, + nblock); +} + +static void bolero_cdc_notifier_call(struct bolero_priv *priv, + u32 data) +{ + dev_dbg(priv->dev, "%s: notifier call, data:%d\n", __func__, data); + blocking_notifier_call_chain(&priv->notifier, + data, (void *)priv->wcd_dev); +} + +static bool bolero_is_valid_child_dev(struct device *dev) +{ + if (of_device_is_compatible(dev->parent->of_node, "qcom,bolero-codec")) + return true; + + return false; +} + +static bool bolero_is_valid_codec_dev(struct device *dev) +{ + if (of_device_is_compatible(dev->of_node, "qcom,bolero-codec")) + return true; + + return false; +} + +/** + * bolero_clear_amic_tx_hold - clears AMIC register on analog codec + * + * @dev: bolero device ptr. + * + */ +void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n) +{ + struct bolero_priv *priv; + u16 event; + u16 amic = 0; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + + if (!bolero_is_valid_codec_dev(dev)) { + pr_err("%s: invalid codec\n", __func__); + return; + } + priv = dev_get_drvdata(dev); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return; + } + event = BOLERO_SLV_EVT_TX_CH_HOLD_CLEAR; + if (adc_n == BOLERO_ADC0) + amic = 0x1; + else if (adc_n == BOLERO_ADC1) + amic = 0x2; + else if (adc_n == BOLERO_ADC2) + amic = 0x2; + else if (adc_n == BOLERO_ADC3) + amic = 0x3; + else + return; + + bolero_cdc_notifier_call(priv, (amic << 0x10 | event)); +} +EXPORT_SYMBOL(bolero_clear_amic_tx_hold); + +/** + * bolero_get_device_ptr - Get child or macro device ptr + * + * @dev: bolero device ptr. + * @macro_id: ID of macro calling this API. + * + * Returns dev ptr on success or NULL on error. + */ +struct device *bolero_get_device_ptr(struct device *dev, u16 macro_id) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return NULL; + } + + if (!bolero_is_valid_codec_dev(dev)) { + pr_err("%s: invalid codec\n", __func__); + return NULL; + } + priv = dev_get_drvdata(dev); + if (!priv || (macro_id >= MAX_MACRO)) { + dev_err(dev, "%s: priv is null or invalid macro\n", __func__); + return NULL; + } + + return priv->macro_params[macro_id].dev; +} +EXPORT_SYMBOL(bolero_get_device_ptr); + +/** + * bolero_get_rsc_clk_device_ptr - Get rsc clk device ptr + * + * @dev: bolero device ptr. + * + * Returns dev ptr on success or NULL on error. + */ +struct device *bolero_get_rsc_clk_device_ptr(struct device *dev) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return NULL; + } + + if (!bolero_is_valid_codec_dev(dev)) { + pr_err("%s: invalid codec\n", __func__); + return NULL; + } + priv = dev_get_drvdata(dev); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return NULL; + } + + return priv->clk_dev; +} +EXPORT_SYMBOL(bolero_get_rsc_clk_device_ptr); + +static int bolero_copy_dais_from_macro(struct bolero_priv *priv) +{ + struct snd_soc_dai_driver *dai_ptr; + u16 macro_idx; + + /* memcpy into bolero_dais all macro dais */ + if (!priv->bolero_dais) + priv->bolero_dais = devm_kzalloc(priv->dev, + priv->num_dais * + sizeof( + struct snd_soc_dai_driver), + GFP_KERNEL); + if (!priv->bolero_dais) + return -ENOMEM; + + dai_ptr = priv->bolero_dais; + + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (priv->macro_params[macro_idx].dai_ptr) { + memcpy(dai_ptr, + priv->macro_params[macro_idx].dai_ptr, + priv->macro_params[macro_idx].num_dais * + sizeof(struct snd_soc_dai_driver)); + dai_ptr += priv->macro_params[macro_idx].num_dais; + } + } + return 0; +} + +/** + * bolero_register_res_clk - Registers rsc clk driver to bolero + * + * @dev: rsc clk device ptr. + * @rsc_clk_cb: event handler callback for notifications like SSR + * + * Returns 0 on success or -EINVAL on error. + */ +int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t rsc_clk_cb) +{ + struct bolero_priv *priv; + + if (!dev || !rsc_clk_cb) { + pr_err("%s: dev or rsc_clk_cb is null\n", __func__); + return -EINVAL; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device :%pK not added yet\n", + __func__, dev); + return -EINVAL; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return -EINVAL; + } + + priv->clk_dev = dev; + priv->rsc_clk_cb = rsc_clk_cb; + + return 0; +} +EXPORT_SYMBOL(bolero_register_res_clk); + +/** + * bolero_unregister_res_clk - Unregisters rsc clk driver from bolero + * + * @dev: resource clk device ptr. + */ +void bolero_unregister_res_clk(struct device *dev) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is NULL\n", __func__); + return; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device :%pK not added\n", + __func__, dev); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return; + } + + priv->clk_dev = NULL; + priv->rsc_clk_cb = NULL; +} +EXPORT_SYMBOL(bolero_unregister_res_clk); + +static u8 bolero_dmic_clk_div_get(struct snd_soc_component *component, + int mode) +{ + struct bolero_priv* priv = snd_soc_component_get_drvdata(component); + int macro = (mode ? VA_MACRO : TX_MACRO); + int ret = 0; + + if (priv->macro_params[macro].clk_div_get) { + ret = priv->macro_params[macro].clk_div_get(component); + if (ret >= 0) + return ret; + } + + return 1; +} + +int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + struct bolero_priv* priv = snd_soc_component_get_drvdata(component); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg = 0; + s32 *dmic_clk_cnt = NULL; + u8 *dmic_clk_div = NULL; + u8 freq_change_mask = 0; + u8 clk_div = 0; + + dev_dbg(component->dev, "%s: enable: %d, tx_mode:%d, dmic: %d\n", + __func__, enable, tx_mode, dmic); + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(priv->dmic_0_1_clk_cnt); + dmic_clk_div = &(priv->dmic_0_1_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL; + freq_change_mask = 0x01; + break; + case 2: + case 3: + dmic_clk_cnt = &(priv->dmic_2_3_clk_cnt); + dmic_clk_div = &(priv->dmic_2_3_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL; + freq_change_mask = 0x02; + break; + case 4: + case 5: + dmic_clk_cnt = &(priv->dmic_4_5_clk_cnt); + dmic_clk_div = &(priv->dmic_4_5_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL; + freq_change_mask = 0x04; + break; + case 6: + case 7: + dmic_clk_cnt = &(priv->dmic_6_7_clk_cnt); + dmic_clk_div = &(priv->dmic_6_7_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL; + freq_change_mask = 0x08; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + dev_dbg(component->dev, "%s: DMIC%d dmic_clk_cnt %d\n", + __func__, dmic, *dmic_clk_cnt); + if (enable) { + clk_div = bolero_dmic_clk_div_get(component, tx_mode); + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } else { + if (*dmic_clk_div > clk_div) { + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } else { + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, 0); + clk_div = 0; + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + } else { + clk_div = bolero_dmic_clk_div_get(component, tx_mode); + if (*dmic_clk_div > clk_div) { + clk_div = bolero_dmic_clk_div_get(component, !tx_mode); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } + + return 0; +} +EXPORT_SYMBOL(bolero_dmic_clk_enable); + +bool bolero_is_va_macro_registered(struct device *dev) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return false; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device calling is not added yet\n", + __func__); + return false; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return false; + } + return priv->macros_supported[VA_MACRO]; +} +EXPORT_SYMBOL(bolero_is_va_macro_registered); + +/** + * bolero_register_macro - Registers macro to bolero + * + * @dev: macro device ptr. + * @macro_id: ID of macro calling this API. + * @ops: macro params to register. + * + * Returns 0 on success or -EINVAL on error. + */ +int bolero_register_macro(struct device *dev, u16 macro_id, + struct macro_ops *ops) +{ + struct bolero_priv *priv; + int ret = -EINVAL; + + if (!dev || !ops) { + pr_err("%s: dev or ops is null\n", __func__); + return -EINVAL; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device for macro:%d not added yet\n", + __func__, macro_id); + return -EINVAL; + } + priv = dev_get_drvdata(dev->parent); + if (!priv || (macro_id >= MAX_MACRO)) { + dev_err(dev, "%s: priv is null or invalid macro\n", __func__); + return -EINVAL; + } + + priv->macro_params[macro_id].clk_id_req = ops->clk_id_req; + priv->macro_params[macro_id].default_clk_id = ops->default_clk_id; + priv->macro_params[macro_id].init = ops->init; + priv->macro_params[macro_id].exit = ops->exit; + priv->macro_params[macro_id].io_base = ops->io_base; + priv->macro_params[macro_id].num_dais = ops->num_dais; + priv->macro_params[macro_id].dai_ptr = ops->dai_ptr; + priv->macro_params[macro_id].event_handler = ops->event_handler; + priv->macro_params[macro_id].set_port_map = ops->set_port_map; + priv->macro_params[macro_id].dev = dev; + priv->current_mclk_mux_macro[macro_id] = + bolero_mclk_mux_tbl[macro_id][MCLK_MUX0]; + if (macro_id == TX_MACRO) { + priv->macro_params[macro_id].reg_wake_irq = ops->reg_wake_irq; + priv->macro_params[macro_id].clk_switch = ops->clk_switch; + priv->macro_params[macro_id].reg_evt_listener = + ops->reg_evt_listener; + priv->macro_params[macro_id].clk_enable = ops->clk_enable; + } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = ops->clk_div_get; + + if ((priv->version == BOLERO_VERSION_2_1) || + (priv->version == BOLERO_VERSION_2_2)) { + if (macro_id == VA_MACRO) + priv->macro_params[macro_id].reg_wake_irq = + ops->reg_wake_irq; + } + priv->num_dais += ops->num_dais; + priv->num_macros_registered++; + priv->macros_supported[macro_id] = true; + + dev_info(dev, "%s: register macro successful:%d\n", __func__, macro_id); + + if (priv->num_macros_registered == priv->num_macros) { + ret = bolero_copy_dais_from_macro(priv); + if (ret < 0) { + dev_err(dev, "%s: copy_dais failed\n", __func__); + return ret; + } + if (priv->macros_supported[TX_MACRO] == false) { + bolero_mclk_mux_tbl[WSA_MACRO][MCLK_MUX0] = WSA_MACRO; + priv->current_mclk_mux_macro[WSA_MACRO] = WSA_MACRO; + bolero_mclk_mux_tbl[VA_MACRO][MCLK_MUX0] = VA_MACRO; + priv->current_mclk_mux_macro[VA_MACRO] = VA_MACRO; + } + ret = snd_soc_register_component(dev->parent, &bolero, + priv->bolero_dais, priv->num_dais); + if (ret < 0) { + dev_err(dev, "%s: register codec failed\n", __func__); + return ret; + } + } + return 0; +} +EXPORT_SYMBOL(bolero_register_macro); + +/** + * bolero_unregister_macro - De-Register macro from bolero + * + * @dev: macro device ptr. + * @macro_id: ID of macro calling this API. + * + */ +void bolero_unregister_macro(struct device *dev, u16 macro_id) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: macro:%d not in valid registered macro-list\n", + __func__, macro_id); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv || (macro_id >= MAX_MACRO)) { + dev_err(dev, "%s: priv is null or invalid macro\n", __func__); + return; + } + + priv->macro_params[macro_id].init = NULL; + priv->macro_params[macro_id].num_dais = 0; + priv->macro_params[macro_id].dai_ptr = NULL; + priv->macro_params[macro_id].event_handler = NULL; + priv->macro_params[macro_id].dev = NULL; + if (macro_id == TX_MACRO) { + priv->macro_params[macro_id].reg_wake_irq = NULL; + priv->macro_params[macro_id].clk_switch = NULL; + priv->macro_params[macro_id].reg_evt_listener = NULL; + priv->macro_params[macro_id].clk_enable = NULL; + } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = NULL; + + priv->num_dais -= priv->macro_params[macro_id].num_dais; + priv->num_macros_registered--; + + /* UNREGISTER CODEC HERE */ + if (priv->num_macros - 1 == priv->num_macros_registered) + snd_soc_unregister_component(dev->parent); +} +EXPORT_SYMBOL(bolero_unregister_macro); + +/** + * bolero_rx_pa_on - Send PA on event from RX macro to slave. + * + * @dev: macro device ptr. + */ +void bolero_rx_pa_on(struct device *dev) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: not a valid child dev\n", + __func__); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return; + } + + bolero_cdc_notifier_call(priv, BOLERO_SLV_EVT_RX_MACRO_PA_ON); +} +EXPORT_SYMBOL_GPL(bolero_rx_pa_on); + +void bolero_wsa_pa_on(struct device *dev, bool adie_lb) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: not a valid child dev\n", + __func__); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return; + } + if (adie_lb) + bolero_cdc_notifier_call(priv, + BOLERO_SLV_EVT_PA_ON_POST_FSCLK_ADIE_LB); + else + bolero_cdc_notifier_call(priv, + BOLERO_SLV_EVT_PA_ON_POST_FSCLK); +} +EXPORT_SYMBOL(bolero_wsa_pa_on); + +int bolero_get_version(struct device *dev) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return -EINVAL; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device for macro not added yet\n", + __func__); + return -EINVAL; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return -EINVAL; + } + return priv->version; +} +EXPORT_SYMBOL(bolero_get_version); + +static ssize_t bolero_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct bolero_priv *priv; + char buffer[BOLERO_VERSION_ENTRY_SIZE]; + int len = 0; + + priv = (struct bolero_priv *) entry->private_data; + if (!priv) { + pr_err("%s: bolero priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->version) { + case BOLERO_VERSION_1_0: + len = snprintf(buffer, sizeof(buffer), "BOLERO_1_0\n"); + break; + case BOLERO_VERSION_1_1: + len = snprintf(buffer, sizeof(buffer), "BOLERO_1_1\n"); + break; + case BOLERO_VERSION_1_2: + len = snprintf(buffer, sizeof(buffer), "BOLERO_1_2\n"); + break; + case BOLERO_VERSION_2_0: + len = snprintf(buffer, sizeof(buffer), "BOLERO_2_0\n"); + break; + case BOLERO_VERSION_2_1: + len = snprintf(buffer, sizeof(buffer), "BOLERO_2_1\n"); + break; + default: + len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + } + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static int bolero_ssr_enable(struct device *dev, void *data) +{ + struct bolero_priv *priv = data; + int macro_idx; + + if (priv->initial_boot) { + priv->initial_boot = false; + return 0; + } + + if (priv->rsc_clk_cb) + priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_UP); + + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (priv->macro_params[macro_idx].event_handler) + priv->macro_params[macro_idx].event_handler( + priv->component, + BOLERO_MACRO_EVT_CLK_RESET, 0x0); + } + + if (priv->rsc_clk_cb) + priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_GFMUX_UP); + + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler( + priv->component, + BOLERO_MACRO_EVT_PRE_SSR_UP, 0x0); + } + + regcache_cache_only(priv->regmap, false); + mutex_lock(&priv->clk_lock); + priv->dev_up = true; + mutex_unlock(&priv->clk_lock); + regcache_mark_dirty(priv->regmap); + bolero_clk_rsc_enable_all_clocks(priv->clk_dev, true); + regcache_sync(priv->regmap); + /* Add a 100usec sleep to ensure last register write is done */ + usleep_range(100,110); + bolero_clk_rsc_enable_all_clocks(priv->clk_dev, false); + /* call ssr event for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler( + priv->component, + BOLERO_MACRO_EVT_SSR_UP, 0x0); + } + bolero_cdc_notifier_call(priv, BOLERO_SLV_EVT_SSR_UP); + return 0; +} + +static void bolero_ssr_disable(struct device *dev, void *data) +{ + struct bolero_priv *priv = data; + int macro_idx; + + if (!priv->dev_up) { + dev_err_ratelimited(priv->dev, + "%s: already disabled\n", __func__); + return; + } + + bolero_cdc_notifier_call(priv, BOLERO_SLV_EVT_PA_OFF_PRE_SSR); + regcache_cache_only(priv->regmap, true); + + mutex_lock(&priv->clk_lock); + priv->dev_up = false; + mutex_unlock(&priv->clk_lock); + if (priv->rsc_clk_cb) + priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_DOWN); + /* call ssr event for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler( + priv->component, + BOLERO_MACRO_EVT_SSR_DOWN, 0x0); + } + bolero_cdc_notifier_call(priv, BOLERO_SLV_EVT_SSR_DOWN); +} + +static struct snd_info_entry_ops bolero_info_ops = { + .read = bolero_version_read, +}; + +static const struct snd_event_ops bolero_ssr_ops = { + .enable = bolero_ssr_enable, + .disable = bolero_ssr_disable, +}; + +/* + * bolero_info_create_codec_entry - creates bolero module + * @codec_root: The parent directory + * @component: Codec component instance + * + * Creates bolero module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int bolero_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct bolero_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:bolero module already created\n", __func__); + return 0; + } + card = component->card; + priv->entry = snd_info_create_module_entry(codec_root->module, + "bolero", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create bolero entry\n", + __func__); + return -ENOMEM; + } + priv->entry->mode = S_IFDIR | 0555; + if (snd_info_register(priv->entry) < 0) { + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + version_entry = snd_info_create_card_entry(card->snd_card, + "version", + priv->entry); + if (!version_entry) { + dev_err(component->dev, "%s: failed to create bolero version entry\n", + __func__); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + version_entry->private_data = priv; + version_entry->size = BOLERO_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &bolero_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->version_entry = version_entry; + + return 0; +} +EXPORT_SYMBOL(bolero_info_create_codec_entry); + +/** + * bolero_register_wake_irq - Register wake irq of Tx macro + * + * @component: codec component ptr. + * @ipc_wakeup: bool to identify ipc_wakeup to be used or HW interrupt line. + * + * Return: 0 on success or negative error code on failure. + */ +int bolero_register_wake_irq(struct snd_soc_component *component, + u32 ipc_wakeup) +{ + struct bolero_priv *priv = NULL; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!bolero_is_valid_codec_dev(priv->dev)) { + dev_err(component->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + + if ((priv->version == BOLERO_VERSION_2_1) || + (priv->version == BOLERO_VERSION_2_2)) { + if (priv->macro_params[VA_MACRO].reg_wake_irq) + priv->macro_params[VA_MACRO].reg_wake_irq( + component, ipc_wakeup); + } else { + if (priv->macro_params[TX_MACRO].reg_wake_irq) + priv->macro_params[TX_MACRO].reg_wake_irq( + component, ipc_wakeup); + } + + return 0; +} +EXPORT_SYMBOL(bolero_register_wake_irq); + +/** + * bolero_tx_clk_switch - Switch tx macro clock + * + * @component: pointer to codec component instance. + * + * @clk_src: clk source + * + * Returns 0 on success or -EINVAL on error. + */ +int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src) +{ + struct bolero_priv *priv = NULL; + int ret = 0; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!bolero_is_valid_codec_dev(priv->dev)) { + dev_err(component->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + + if (priv->macro_params[TX_MACRO].clk_switch) + ret = priv->macro_params[TX_MACRO].clk_switch(component, + clk_src); + + return ret; +} +EXPORT_SYMBOL(bolero_tx_clk_switch); + +/** + * bolero_tx_mclk_enable - Enable/Disable TX Macro mclk + * + * @component: pointer to codec component instance. + * @enable: set true to enable, otherwise false. + * + * Returns 0 on success or -EINVAL on error. + */ +int bolero_tx_mclk_enable(struct snd_soc_component *component, + bool enable) +{ + struct bolero_priv *priv = NULL; + int ret = 0; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!bolero_is_valid_codec_dev(priv->dev)) { + dev_err(component->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + + if (priv->macro_params[TX_MACRO].clk_enable) + ret = priv->macro_params[TX_MACRO].clk_enable(component, + enable); + + return ret; +} +EXPORT_SYMBOL(bolero_tx_mclk_enable); + +/** + * bolero_register_event_listener - Register/Deregister to event listener + * + * @component: pointer to codec component instance. + * @enable: when set to 1 registers to event listener otherwise, derigisters + * from the event listener + * + * Returns 0 on success or -EINVAL on error. + */ +int bolero_register_event_listener(struct snd_soc_component *component, + bool enable) +{ + struct bolero_priv *priv = NULL; + int ret = 0; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!bolero_is_valid_codec_dev(priv->dev)) { + dev_err(component->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + + if (priv->macro_params[TX_MACRO].reg_evt_listener) + ret = priv->macro_params[TX_MACRO].reg_evt_listener(component, + enable); + + return ret; +} +EXPORT_SYMBOL(bolero_register_event_listener); + +static int bolero_soc_codec_probe(struct snd_soc_component *component) +{ + struct bolero_priv *priv = dev_get_drvdata(component->dev); + int macro_idx, ret = 0; + u8 core_id_0 = 0, core_id_1 = 0, core_id_2 = 0; + + snd_soc_component_init_regmap(component, priv->regmap); + + if (!priv->version) { + /* + * In order for the ADIE RTC to differentiate between targets + * version info is used. + * Assign 1.0 for target with only one macro + * Assign 1.1 for target with two macros + * Assign 1.2 for target with more than two macros + */ + if (priv->num_macros_registered == 1) + priv->version = BOLERO_VERSION_1_0; + else if (priv->num_macros_registered == 2) + priv->version = BOLERO_VERSION_1_1; + else if (priv->num_macros_registered > 2) + priv->version = BOLERO_VERSION_1_2; + } + + /* Assign bolero version */ + core_id_0 = snd_soc_component_read(component, + BOLERO_CDC_VA_TOP_CSR_CORE_ID_0); + core_id_1 = snd_soc_component_read(component, + BOLERO_CDC_VA_TOP_CSR_CORE_ID_1); + core_id_2 = snd_soc_component_read(component, + BOLERO_CDC_VA_TOP_CSR_CORE_ID_2); + if ((core_id_0 == 0x01) && (core_id_1 == 0x0F)) + priv->version = BOLERO_VERSION_2_0; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0E)) { + if (core_id_2 == 0x20) + priv->version = BOLERO_VERSION_2_2; + else + priv->version = BOLERO_VERSION_2_1; + } + + /* call init for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (priv->macro_params[macro_idx].init) { + ret = priv->macro_params[macro_idx].init(component); + if (ret < 0) { + dev_err(component->dev, + "%s: init for macro %d failed\n", + __func__, macro_idx); + goto err; + } + } + } + priv->component = component; + + ret = snd_event_client_register(priv->dev, &bolero_ssr_ops, priv); + if (!ret) { + snd_event_notify(priv->dev, SND_EVENT_UP); + } else { + dev_err(component->dev, + "%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + goto err; + } + + dev_dbg(component->dev, "%s: bolero soc codec probe success\n", + __func__); +err: + return ret; +} + +static void bolero_soc_codec_remove(struct snd_soc_component *component) +{ + struct bolero_priv *priv = dev_get_drvdata(component->dev); + int macro_idx; + + snd_event_client_deregister(priv->dev); + /* call exit for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) + if (priv->macro_params[macro_idx].exit) + priv->macro_params[macro_idx].exit(component); + + return; +} + +static const struct snd_soc_component_driver bolero = { + .name = DRV_NAME, + .probe = bolero_soc_codec_probe, + .remove = bolero_soc_codec_remove, +}; + +static void bolero_add_child_devices(struct work_struct *work) +{ + struct bolero_priv *priv; + bool split_codec = false; + struct platform_device *pdev; + struct device_node *node; + int ret = 0, count = 0; + struct wcd_ctrl_platform_data *platdata = NULL; + char plat_dev_name[BOLERO_CDC_STRING_LEN] = ""; + + priv = container_of(work, struct bolero_priv, + bolero_add_child_devices_work); + if (!priv) { + pr_err("%s: Memory for bolero priv does not exist\n", + __func__); + return; + } + if (!priv->dev || !priv->dev->of_node) { + dev_err(priv->dev, "%s: DT node for bolero does not exist\n", + __func__); + return; + } + + platdata = &priv->plat_data; + priv->child_count = 0; + + for_each_available_child_of_node(priv->dev->of_node, node) { + split_codec = false; + if (of_find_property(node, "qcom,split-codec", NULL)) { + split_codec = true; + dev_dbg(priv->dev, "%s: split codec slave exists\n", + __func__); + } + + strlcpy(plat_dev_name, node->name, + (BOLERO_CDC_STRING_LEN - 1)); + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = priv->dev; + pdev->dev.of_node = node; + + priv->dev->platform_data = platdata; + if (split_codec) + priv->wcd_dev = &pdev->dev; + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + platform_device_put(pdev); + goto fail_pdev_add; + } + + if (priv->child_count < BOLERO_CDC_CHILD_DEVICES_MAX) + priv->pdev_child_devices[priv->child_count++] = pdev; + else + goto err; + } + return; +fail_pdev_add: + for (count = 0; count < priv->child_count; count++) + platform_device_put(priv->pdev_child_devices[count]); +err: + return; +} + +static int bolero_probe(struct platform_device *pdev) +{ + struct bolero_priv *priv; + u32 num_macros = 0; + int ret; + struct clk *lpass_core_hw_vote = NULL; + struct clk *lpass_audio_hw_vote = NULL; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct bolero_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-macros", + &num_macros); + if (ret) { + dev_err(&pdev->dev, + "%s:num-macros property not found\n", + __func__); + return ret; + } + priv->num_macros = num_macros; + if (priv->num_macros > MAX_MACRO) { + dev_err(&pdev->dev, + "%s:num_macros(%d) > MAX_MACRO(%d) than supported\n", + __func__, priv->num_macros, MAX_MACRO); + return -EINVAL; + } + priv->va_without_decimation = of_property_read_bool(pdev->dev.of_node, + "qcom,va-without-decimation"); + if (priv->va_without_decimation) + bolero_reg_access[VA_MACRO] = bolero_va_top_reg_access; + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,bolero-version", &priv->version); + if (ret) { + dev_dbg(&pdev->dev, "%s:bolero version not specified\n", + __func__); + ret = 0; + } + if ((priv->version == BOLERO_VERSION_2_1) || + (priv->version == BOLERO_VERSION_2_2)) { + bolero_reg_access[TX_MACRO] = bolero_tx_reg_access_v2; + bolero_reg_access[VA_MACRO] = bolero_va_reg_access_v2; + } else if (priv->version == BOLERO_VERSION_2_0) { + bolero_reg_access[VA_MACRO] = bolero_va_reg_access_v3; + } + + BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier); + priv->dev = &pdev->dev; + priv->dev_up = true; + priv->initial_boot = true; + priv->regmap = bolero_regmap_init(priv->dev, + &bolero_regmap_config); + if (IS_ERR_OR_NULL((void *)(priv->regmap))) { + dev_err(&pdev->dev, "%s:regmap init failed\n", __func__); + return -EINVAL; + } + + devm_regmap_qti_debugfs_register(priv->dev, priv->regmap); + + priv->read_dev = __bolero_reg_read; + priv->write_dev = __bolero_reg_write; + + priv->plat_data.handle = (void *) priv; + priv->plat_data.update_wcd_event = bolero_cdc_update_wcd_event; + priv->plat_data.register_notifier = bolero_cdc_register_notifier; + + priv->core_hw_vote_count = 0; + priv->core_audio_vote_count = 0; + + dev_set_drvdata(&pdev->dev, priv); + mutex_init(&priv->io_lock); + mutex_init(&priv->clk_lock); + mutex_init(&priv->vote_lock); + INIT_WORK(&priv->bolero_add_child_devices_work, + bolero_add_child_devices); + + /* Register LPASS core hw vote */ + lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote"); + if (IS_ERR(lpass_core_hw_vote)) { + ret = PTR_ERR(lpass_core_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_core_hw_vote", ret); + lpass_core_hw_vote = NULL; + ret = 0; + } + priv->lpass_core_hw_vote = lpass_core_hw_vote; + + /* Register LPASS audio hw vote */ + lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); + if (IS_ERR(lpass_audio_hw_vote)) { + ret = PTR_ERR(lpass_audio_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_audio_hw_vote", ret); + lpass_audio_hw_vote = NULL; + ret = 0; + } + priv->lpass_audio_hw_vote = lpass_audio_hw_vote; + schedule_work(&priv->bolero_add_child_devices_work); + return 0; +} + +static int bolero_remove(struct platform_device *pdev) +{ + struct bolero_priv *priv = dev_get_drvdata(&pdev->dev); + + if (!priv) + return -EINVAL; + + of_platform_depopulate(&pdev->dev); + mutex_destroy(&priv->io_lock); + mutex_destroy(&priv->clk_lock); + mutex_destroy(&priv->vote_lock); + return 0; +} + +#ifdef CONFIG_PM +int bolero_runtime_resume(struct device *dev) +{ + struct bolero_priv *priv = dev_get_drvdata(dev->parent); + int ret = 0; + static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); + + mutex_lock(&priv->vote_lock); + if (priv->lpass_core_hw_vote == NULL) { + dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__); + goto audio_vote; + } + + if (priv->core_hw_vote_count == 0) { + ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_core_hw_vote, dev); + if (ret < 0) { + dev_err(dev, "%s:lpass core hw enable failed\n", + __func__); + goto audio_vote; + } + } + priv->core_hw_vote_count++; + +audio_vote: + if (priv->lpass_audio_hw_vote == NULL) { + dev_dbg(dev, "%s: Invalid lpass audio hw node\n", __func__); + goto done; + } + + if (priv->core_audio_vote_count == 0) { + ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_audio_hw_vote, dev); + if (ret < 0) { + if (__ratelimit(&rtl)) + dev_err(dev, "%s:lpass audio hw enable failed\n", + __func__); + goto done; + } + } + priv->core_audio_vote_count++; + +done: + mutex_unlock(&priv->vote_lock); + pm_runtime_set_autosuspend_delay(priv->dev, BOLERO_AUTO_SUSPEND_DELAY); + return 0; +} +EXPORT_SYMBOL(bolero_runtime_resume); + +int bolero_runtime_suspend(struct device *dev) +{ + struct bolero_priv *priv = dev_get_drvdata(dev->parent); + + mutex_lock(&priv->vote_lock); + if (priv->lpass_core_hw_vote != NULL) { + if (--priv->core_hw_vote_count == 0) + digital_cdc_rsc_mgr_hw_vote_disable( + priv->lpass_core_hw_vote, dev); + if (priv->core_hw_vote_count < 0) + priv->core_hw_vote_count = 0; + } else { + dev_dbg(dev, "%s: Invalid lpass core hw node\n", + __func__); + } + + if (priv->lpass_audio_hw_vote != NULL) { + if (--priv->core_audio_vote_count == 0) + digital_cdc_rsc_mgr_hw_vote_disable( + priv->lpass_audio_hw_vote, dev); + if (priv->core_audio_vote_count < 0) + priv->core_audio_vote_count = 0; + } else { + dev_dbg(dev, "%s: Invalid lpass audio hw node\n", + __func__); + } + + mutex_unlock(&priv->vote_lock); + return 0; +} +EXPORT_SYMBOL(bolero_runtime_suspend); +#endif /* CONFIG_PM */ + +bool bolero_check_core_votes(struct device *dev) +{ + struct bolero_priv *priv = dev_get_drvdata(dev->parent); + bool ret = true; + + mutex_lock(&priv->vote_lock); + if ((priv->lpass_core_hw_vote && !priv->core_hw_vote_count) || + (priv->lpass_audio_hw_vote && !priv->core_audio_vote_count)) + ret = false; + mutex_unlock(&priv->vote_lock); + + return ret; +} +EXPORT_SYMBOL(bolero_check_core_votes); + +static const struct of_device_id bolero_dt_match[] = { + {.compatible = "qcom,bolero-codec"}, + {} +}; +MODULE_DEVICE_TABLE(of, bolero_dt_match); + +static struct platform_driver bolero_drv = { + .driver = { + .name = "bolero-codec", + .owner = THIS_MODULE, + .of_match_table = bolero_dt_match, + .suppress_bind_attrs = true, + }, + .probe = bolero_probe, + .remove = bolero_remove, +}; + +static int bolero_drv_init(void) +{ + return platform_driver_register(&bolero_drv); +} + +static void bolero_drv_exit(void) +{ + platform_driver_unregister(&bolero_drv); +} + +static int __init bolero_init(void) +{ + bolero_drv_init(); + bolero_clk_rsc_mgr_init(); + return 0; +} +module_init(bolero_init); + +static void __exit bolero_exit(void) +{ + bolero_clk_rsc_mgr_exit(); + bolero_drv_exit(); +} +module_exit(bolero_exit); + +MODULE_DESCRIPTION("Bolero driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc.h b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc.h new file mode 100644 index 0000000000..b8196f9407 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-cdc.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef BOLERO_CDC_H +#define BOLERO_CDC_H + +#include +#include + +#define BOLERO_VERSION_1_0 0x0001 +#define BOLERO_VERSION_1_1 0x0002 +#define BOLERO_VERSION_1_2 0x0003 +#define BOLERO_VERSION_2_0 0x0004 +#define BOLERO_VERSION_2_1 0x0005 +#define BOLERO_VERSION_2_2 0x0006 + +enum { + START_MACRO, + TX_MACRO = START_MACRO, + RX_MACRO, + WSA_MACRO, + VA_MACRO, + MAX_MACRO +}; + +enum mclk_mux { + MCLK_MUX0, + MCLK_MUX1, + MCLK_MUX_MAX +}; + +enum { + BOLERO_ADC0 = 1, + BOLERO_ADC1, + BOLERO_ADC2, + BOLERO_ADC3, + BOLERO_ADC_MAX +}; + +enum { + CLK_SRC_TX_RCG = 0, + CLK_SRC_VA_RCG, +}; + +enum { + BOLERO_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */ + BOLERO_MACRO_EVT_IMPED_TRUE, /* for imped true */ + BOLERO_MACRO_EVT_IMPED_FALSE, /* for imped false */ + BOLERO_MACRO_EVT_SSR_DOWN, + BOLERO_MACRO_EVT_SSR_UP, + BOLERO_MACRO_EVT_WAIT_VA_CLK_RESET, + BOLERO_MACRO_EVT_CLK_RESET, + BOLERO_MACRO_EVT_REG_WAKE_IRQ, + BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST, + BOLERO_MACRO_EVT_BCS_CLK_OFF, + BOLERO_MACRO_EVT_SSR_GFMUX_UP, + BOLERO_MACRO_EVT_PRE_SSR_UP, + BOLERO_MACRO_EVT_RX_PA_GAIN_UPDATE, + BOLERO_MACRO_EVT_HPHL_HD2_ENABLE, /* Enable HD2 cfg for HPHL */ + BOLERO_MACRO_EVT_HPHR_HD2_ENABLE, /* Enable HD2 cfg for HPHR */ +}; + +enum { + DMIC_TX = 0, + DMIC_VA = 1, + +}; + +struct macro_ops { + int (*init)(struct snd_soc_component *component); + int (*exit)(struct snd_soc_component *component); + u16 num_dais; + struct device *dev; + struct snd_soc_dai_driver *dai_ptr; + int (*mclk_fn)(struct device *dev, bool enable); + int (*event_handler)(struct snd_soc_component *component, u16 event, + u32 data); + int (*reg_wake_irq)(struct snd_soc_component *component, u32 data); + int (*set_port_map)(struct snd_soc_component *component, u32 uc, + u32 size, void *data); + int (*clk_div_get)(struct snd_soc_component *component); + int (*clk_switch)(struct snd_soc_component *component, int clk_src); + int (*reg_evt_listener)(struct snd_soc_component *component, bool en); + int (*clk_enable)(struct snd_soc_component *c, bool en); + char __iomem *io_base; + u16 clk_id_req; + u16 default_clk_id; +}; + +typedef int (*rsc_clk_cb_t)(struct device *dev, u16 event); + +#if IS_ENABLED(CONFIG_SND_SOC_BOLERO) +int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb); +void bolero_unregister_res_clk(struct device *dev); +bool bolero_is_va_macro_registered(struct device *dev); +int bolero_register_macro(struct device *dev, u16 macro_id, + struct macro_ops *ops); +void bolero_unregister_macro(struct device *dev, u16 macro_id); +struct device *bolero_get_device_ptr(struct device *dev, u16 macro_id); +struct device *bolero_get_rsc_clk_device_ptr(struct device *dev); +int bolero_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component); +int bolero_register_wake_irq(struct snd_soc_component *component, u32 data); +void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n); +int bolero_runtime_resume(struct device *dev); +int bolero_runtime_suspend(struct device *dev); +int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data); +int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src); +int bolero_register_event_listener(struct snd_soc_component *component, + bool enable); +void bolero_wsa_pa_on(struct device *dev, bool adie_lb); +bool bolero_check_core_votes(struct device *dev); +int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable); +int bolero_get_version(struct device *dev); +int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable); +void bolero_rx_pa_on(struct device *dev); +#else +static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb) +{ + return 0; +} +static inline void bolero_unregister_res_clk(struct device *dev) +{ +} + +static bool bolero_is_va_macro_registered(struct device *dev) +{ + return false; +} + +static inline int bolero_register_macro(struct device *dev, + u16 macro_id, + struct macro_ops *ops) +{ + return 0; +} + +static inline void bolero_unregister_macro(struct device *dev, u16 macro_id) +{ +} + +static inline struct device *bolero_get_device_ptr(struct device *dev, + u16 macro_id) +{ + return NULL; +} + +static int bolero_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} + +static inline void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n) +{ +} + +static inline int bolero_register_wake_irq(struct snd_soc_component *component, + u32 data) +{ + return 0; +} + +static inline int bolero_runtime_resume(struct device *dev) +{ + return 0; +} + +static int bolero_runtime_suspend(struct device *dev) +{ + return 0; +} + +static inline int bolero_set_port_map(struct snd_soc_component *component, + u32 size, void *data) +{ + return 0; +} + +static inline int bolero_tx_clk_switch(struct snd_soc_component *component, + int clk_src) +{ + return 0; +} + +static inline int bolero_register_event_listener( + struct snd_soc_component *component, + bool enable) +{ + return 0; +} + +static void bolero_wsa_pa_on(struct device *dev, bool adie_lb) +{ +} + +static inline bool bolero_check_core_votes(struct device *dev) +{ + return false; +} + +static int bolero_get_version(struct device *dev) +{ + return 0; +} + +static int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + return 0; +} +static int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable) +{ + return 0; +} + +static inline void bolero_rx_pa_on(struct device *dev) +{ + return 0; +} + +#endif /* CONFIG_SND_SOC_BOLERO */ +#endif /* BOLERO_CDC_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-clk-rsc.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-clk-rsc.c new file mode 100644 index 0000000000..126b5e35dd --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-clk-rsc.c @@ -0,0 +1,768 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bolero-cdc.h" +#include "bolero-clk-rsc.h" + +#define DRV_NAME "bolero-clk-rsc" +#define BOLERO_CLK_NAME_LENGTH 30 +#define NPL_CLK_OFFSET (TX_NPL_CLK - TX_CORE_CLK) + +static char clk_src_name[MAX_CLK][BOLERO_CLK_NAME_LENGTH] = { + "tx_core_clk", + "rx_core_clk", + "wsa_core_clk", + "va_core_clk", + "tx_npl_clk", + "rx_npl_clk", + "wsa_npl_clk", + "va_npl_clk", +}; + +struct bolero_clk_rsc { + struct device *dev; + struct mutex rsc_clk_lock; + struct mutex fs_gen_lock; + struct clk *clk[MAX_CLK]; + int clk_cnt[MAX_CLK]; + int reg_seq_en_cnt; + int va_tx_clk_cnt; + bool dev_up; + bool dev_up_gfmux; + u32 num_fs_reg; + u32 *fs_gen_seq; + int default_clk_id[MAX_CLK]; + struct regmap *regmap; + char __iomem *rx_clk_muxsel; + char __iomem *wsa_clk_muxsel; + char __iomem *va_clk_muxsel; +}; + +static int bolero_clk_rsc_cb(struct device *dev, u16 event) +{ + struct bolero_clk_rsc *priv; + + if (!dev) { + pr_err("%s: Invalid device pointer\n", + __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(dev); + if (!priv) { + pr_err("%s: Invalid clk rsc priviate data\n", + __func__); + return -EINVAL; + } + + mutex_lock(&priv->rsc_clk_lock); + if (event == BOLERO_MACRO_EVT_SSR_UP) { + priv->dev_up = true; + } else if (event == BOLERO_MACRO_EVT_SSR_DOWN) { + priv->dev_up = false; + priv->dev_up_gfmux = false; + } else if (event == BOLERO_MACRO_EVT_SSR_GFMUX_UP) { + priv->dev_up_gfmux = true; + } + mutex_unlock(&priv->rsc_clk_lock); + + return 0; +} + +static char __iomem *bolero_clk_rsc_get_clk_muxsel(struct bolero_clk_rsc *priv, + int clk_id) +{ + switch (clk_id) { + case RX_CORE_CLK: + return priv->rx_clk_muxsel; + case WSA_CORE_CLK: + return priv->wsa_clk_muxsel; + case VA_CORE_CLK: + return priv->va_clk_muxsel; + case TX_CORE_CLK: + default: + dev_err_ratelimited(priv->dev, "%s: Invalid case\n", __func__); + break; + } + + return NULL; +} + +int bolero_rsc_clk_reset(struct device *dev, int clk_id) +{ + struct device *clk_dev = NULL; + struct bolero_clk_rsc *priv = NULL; + int count = 0; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return -EINVAL; + } + + if (clk_id < 0 || clk_id >= MAX_CLK - NPL_CLK_OFFSET) { + pr_err("%s: Invalid clk_id: %d\n", + __func__, clk_id); + return -EINVAL; + } + + clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk priviate data\n", __func__); + return -EINVAL; + } + mutex_lock(&priv->rsc_clk_lock); + while (__clk_is_enabled(priv->clk[clk_id])) { + clk_disable_unprepare(priv->clk[clk_id + NPL_CLK_OFFSET]); + clk_disable_unprepare(priv->clk[clk_id]); + count++; + } + dev_dbg(priv->dev, + "%s: clock reset after ssr, count %d\n", __func__, count); + + while (count--) { + clk_prepare_enable(priv->clk[clk_id]); + clk_prepare_enable(priv->clk[clk_id + NPL_CLK_OFFSET]); + } + mutex_unlock(&priv->rsc_clk_lock); + return 0; +} +EXPORT_SYMBOL(bolero_rsc_clk_reset); + +void bolero_clk_rsc_enable_all_clocks(struct device *dev, bool enable) +{ + struct device *clk_dev = NULL; + struct bolero_clk_rsc *priv = NULL; + int i = 0; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + + clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return; + } + + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk private data\n", __func__); + return; + } + mutex_lock(&priv->rsc_clk_lock); + for (i = 0; i < MAX_CLK - NPL_CLK_OFFSET; i++) { + if (enable) { + if (priv->clk[i]) + clk_prepare_enable(priv->clk[i]); + if (priv->clk[i + NPL_CLK_OFFSET]) + clk_prepare_enable( + priv->clk[i + NPL_CLK_OFFSET]); + } else { + if (priv->clk[i + NPL_CLK_OFFSET]) + clk_disable_unprepare( + priv->clk[i + NPL_CLK_OFFSET]); + if (priv->clk[i]) + clk_disable_unprepare(priv->clk[i]); + } + } + mutex_unlock(&priv->rsc_clk_lock); + return; +} +EXPORT_SYMBOL(bolero_clk_rsc_enable_all_clocks); + +static int bolero_clk_rsc_mux0_clk_request(struct bolero_clk_rsc *priv, + int clk_id, + bool enable) +{ + int ret = 0; + static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); + + if (enable) { + /* Enable Requested Core clk */ + if (priv->clk_cnt[clk_id] == 0) { + ret = clk_prepare_enable(priv->clk[clk_id]); + if (ret < 0) { + if (__ratelimit(&rtl)) + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, clk_id); + goto done; + } + if (priv->clk[clk_id + NPL_CLK_OFFSET]) { + ret = clk_prepare_enable( + priv->clk[clk_id + NPL_CLK_OFFSET]); + if (ret < 0) { + if (__ratelimit(&rtl)) + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, + clk_id + NPL_CLK_OFFSET); + goto err; + } + } + } + priv->clk_cnt[clk_id]++; + } else { + if (priv->clk_cnt[clk_id] <= 0) { + dev_err_ratelimited(priv->dev, "%s: clk_id: %d is already disabled\n", + __func__, clk_id); + priv->clk_cnt[clk_id] = 0; + goto done; + } + priv->clk_cnt[clk_id]--; + if (priv->clk_cnt[clk_id] == 0) { + if (priv->clk[clk_id + NPL_CLK_OFFSET]) + clk_disable_unprepare( + priv->clk[clk_id + NPL_CLK_OFFSET]); + clk_disable_unprepare(priv->clk[clk_id]); + } + } + return ret; + +err: + clk_disable_unprepare(priv->clk[clk_id]); +done: + return ret; +} + +static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv, + int clk_id, + bool enable) +{ + char __iomem *clk_muxsel = NULL; + int ret = 0; + int default_clk_id = priv->default_clk_id[clk_id]; + u32 muxsel = 0; + static DEFINE_RATELIMIT_STATE(rtl, 1 * HZ, 1); + + clk_muxsel = bolero_clk_rsc_get_clk_muxsel(priv, clk_id); + if (!clk_muxsel) { + ret = -EINVAL; + goto done; + } + + if (enable) { + if (priv->clk_cnt[clk_id] == 0) { + if (clk_id != VA_CORE_CLK) { + ret = bolero_clk_rsc_mux0_clk_request(priv, + default_clk_id, + true); + if (ret < 0) + goto done; + } + + ret = clk_prepare_enable(priv->clk[clk_id]); + if (ret < 0) { + if (__ratelimit(&rtl)) + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, clk_id); + goto err_clk; + } + if (priv->clk[clk_id + NPL_CLK_OFFSET]) { + ret = clk_prepare_enable( + priv->clk[clk_id + NPL_CLK_OFFSET]); + if (ret < 0) { + if (__ratelimit(&rtl)) + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, + clk_id + NPL_CLK_OFFSET); + goto err_npl_clk; + } + } + + /* + * Temp SW workaround to address a glitch issue of + * VA GFMux instance responsible for switching from + * TX MCLK to VA MCLK. This configuration would be taken + * care in DSP itself + */ + if (clk_id != VA_CORE_CLK) { + if (priv->dev_up_gfmux) { + iowrite32(0x1, clk_muxsel); + muxsel = ioread32(clk_muxsel); + } + bolero_clk_rsc_mux0_clk_request(priv, + default_clk_id, + false); + } + } + priv->clk_cnt[clk_id]++; + } else { + if (priv->clk_cnt[clk_id] <= 0) { + dev_err_ratelimited(priv->dev, "%s: clk_id: %d is already disabled\n", + __func__, clk_id); + priv->clk_cnt[clk_id] = 0; + goto done; + } + priv->clk_cnt[clk_id]--; + if (priv->clk_cnt[clk_id] == 0) { + if (clk_id != VA_CORE_CLK) { + ret = bolero_clk_rsc_mux0_clk_request(priv, + default_clk_id, true); + + if (!ret) { + /* + * Temp SW workaround to address a glitch issue + * of VA GFMux instance responsible for + * switching from TX MCLK to VA MCLK. + * This configuration would be taken + * care in DSP itself. + */ + if (priv->dev_up_gfmux) { + iowrite32(0x0, clk_muxsel); + muxsel = ioread32(clk_muxsel); + } + } + } + if (priv->clk[clk_id + NPL_CLK_OFFSET]) + clk_disable_unprepare( + priv->clk[clk_id + NPL_CLK_OFFSET]); + clk_disable_unprepare(priv->clk[clk_id]); + + if (clk_id != VA_CORE_CLK) { + if (!ret) + bolero_clk_rsc_mux0_clk_request(priv, + default_clk_id, false); + } + } + } + return ret; + +err_npl_clk: + clk_disable_unprepare(priv->clk[clk_id]); + +err_clk: + if (clk_id != VA_CORE_CLK) + bolero_clk_rsc_mux0_clk_request(priv, default_clk_id, false); +done: + return ret; +} + +static int bolero_clk_rsc_check_and_update_va_clk(struct bolero_clk_rsc *priv, + bool mux_switch, + int clk_id, + bool enable) +{ + int ret = 0; + + if (enable) { + if (clk_id == VA_CORE_CLK && mux_switch) { + /* + * Handle the following usecase scenarios during enable + * 1. VA only, Active clk is VA_CORE_CLK + * 2. record -> record + VA, Active clk is TX_CORE_CLK + */ + if (priv->clk_cnt[TX_CORE_CLK] == 0) { + ret = bolero_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, enable); + if (ret < 0) + goto err; + } else { + ret = bolero_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, enable); + if (ret < 0) + goto err; + priv->va_tx_clk_cnt++; + } + } else if ((priv->clk_cnt[TX_CORE_CLK] > 0) && + (priv->clk_cnt[VA_CORE_CLK] > 0)) { + /* + * Handle following concurrency scenario during enable + * 1. VA-> Record+VA, Increment TX CLK and Disable VA + * 2. VA-> Playback+VA, Increment TX CLK and Disable VA + */ + while (priv->clk_cnt[VA_CORE_CLK] > 0) { + ret = bolero_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, true); + if (ret < 0) + goto err; + + bolero_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, false); + priv->va_tx_clk_cnt++; + } + } + } else { + if (clk_id == VA_CORE_CLK && mux_switch) { + /* + * Handle the following usecase scenarios during disable + * 1. VA only, disable VA_CORE_CLK + * 2. Record + VA -> Record, decrement TX CLK count + */ + if (priv->clk_cnt[VA_CORE_CLK]) { + bolero_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, enable); + } else if (priv->va_tx_clk_cnt) { + bolero_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, enable); + priv->va_tx_clk_cnt--; + } + } else if (priv->va_tx_clk_cnt == priv->clk_cnt[TX_CORE_CLK]) { + /* + * Handle the following usecase scenarios during disable + * Record+VA-> VA: enable VA CLK, decrement TX CLK count + */ + while (priv->va_tx_clk_cnt) { + ret = bolero_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, true); + if (ret < 0) + goto err; + + bolero_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, false); + priv->va_tx_clk_cnt--; + } + } + } + +err: + return ret; +} + +/** + * bolero_clk_rsc_fs_gen_request - request to enable/disable fs generation + * sequence + * + * @dev: Macro device pointer + * @enable: enable or disable flag + */ +void bolero_clk_rsc_fs_gen_request(struct device *dev, bool enable) +{ + int i; + struct regmap *regmap; + struct device *clk_dev = NULL; + struct bolero_clk_rsc *priv = NULL; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return; + } + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk priviate data\n", __func__); + return; + } + regmap = dev_get_regmap(priv->dev->parent, NULL); + if (!regmap) { + pr_err("%s: regmap is null\n", __func__); + return; + } + mutex_lock(&priv->fs_gen_lock); + if (enable) { + if (priv->reg_seq_en_cnt++ == 0) { + for (i = 0; i < (priv->num_fs_reg * 3); i += 3) { + dev_dbg(priv->dev, "%s: Register: %d, mask: %d, value %d\n", + __func__, priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1], + priv->fs_gen_seq[i + 2]); + regmap_update_bits(regmap, + priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1], + priv->fs_gen_seq[i + 2]); + } + } + } else { + if (priv->reg_seq_en_cnt <= 0) { + dev_err_ratelimited(priv->dev, "%s: req_seq_cnt: %d is already disabled\n", + __func__, priv->reg_seq_en_cnt); + priv->reg_seq_en_cnt = 0; + mutex_unlock(&priv->fs_gen_lock); + return; + } + if (--priv->reg_seq_en_cnt == 0) { + for (i = ((priv->num_fs_reg - 1) * 3); i >= 0; i -= 3) { + dev_dbg(priv->dev, "%s: Register: %d, mask: %d\n", + __func__, priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1]); + regmap_update_bits(regmap, priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1], 0x0); + } + } + } + mutex_unlock(&priv->fs_gen_lock); +} +EXPORT_SYMBOL(bolero_clk_rsc_fs_gen_request); + +/** + * bolero_clk_rsc_request_clock - request for clock to + * enable/disable + * + * @dev: Macro device pointer. + * @default_clk_id: mux0 Core clock ID input. + * @clk_id_req: Core clock ID requested to enable/disable + * @enable: enable or disable clock flag + * + * Returns 0 on success or -EINVAL on error. + */ +int bolero_clk_rsc_request_clock(struct device *dev, + int default_clk_id, + int clk_id_req, + bool enable) +{ + int ret = 0; + struct device *clk_dev = NULL; + struct bolero_clk_rsc *priv = NULL; + bool mux_switch = false; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return -EINVAL; + } + if ((clk_id_req < 0 || clk_id_req >= MAX_CLK) && + (default_clk_id < 0 || default_clk_id >= MAX_CLK)) { + pr_err("%s: Invalid clk_id_req: %d or default_clk_id: %d\n", + __func__, clk_id_req, default_clk_id); + return -EINVAL; + } + clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return -EINVAL; + } + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk priviate data\n", __func__); + return -EINVAL; + } + + mutex_lock(&priv->rsc_clk_lock); + if (!priv->dev_up && enable) { + dev_err_ratelimited(priv->dev, "%s: SSR is in progress..\n", + __func__); + ret = -EINVAL; + goto err; + } + priv->default_clk_id[clk_id_req] = default_clk_id; + if (default_clk_id != clk_id_req) + mux_switch = true; + + if (mux_switch) { + if (clk_id_req != VA_CORE_CLK) { + ret = bolero_clk_rsc_mux1_clk_request(priv, clk_id_req, + enable); + if (ret < 0) + goto err; + } + } else { + ret = bolero_clk_rsc_mux0_clk_request(priv, clk_id_req, enable); + if (ret < 0) + goto err; + } + + ret = bolero_clk_rsc_check_and_update_va_clk(priv, mux_switch, + clk_id_req, + enable); + if (ret < 0) + goto err; + + dev_dbg(priv->dev, "%s: clk_cnt: %d for requested clk: %d, enable: %d\n", + __func__, priv->clk_cnt[clk_id_req], clk_id_req, + enable); + + mutex_unlock(&priv->rsc_clk_lock); + + return 0; + +err: + mutex_unlock(&priv->rsc_clk_lock); + return ret; +} +EXPORT_SYMBOL(bolero_clk_rsc_request_clock); + + +static int bolero_clk_rsc_probe(struct platform_device *pdev) +{ + int ret = 0, fs_gen_size, i, j; + const char **clk_name_array; + int clk_cnt; + struct clk *clk; + struct bolero_clk_rsc *priv = NULL; + u32 muxsel = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct bolero_clk_rsc), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Get clk fs gen sequence from device tree */ + if (!of_find_property(pdev->dev.of_node, "qcom,fs-gen-sequence", + &fs_gen_size)) { + dev_err(&pdev->dev, "%s: unable to find qcom,fs-gen-sequence property\n", + __func__); + ret = -EINVAL; + goto err; + } + priv->num_fs_reg = fs_gen_size/(3 * sizeof(u32)); + priv->fs_gen_seq = devm_kzalloc(&pdev->dev, fs_gen_size, GFP_KERNEL); + if (!priv->fs_gen_seq) { + ret = -ENOMEM; + goto err; + } + dev_dbg(&pdev->dev, "%s: num_fs_reg %d\n", __func__, priv->num_fs_reg); + /* Parse fs-gen-sequence */ + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,fs-gen-sequence", + priv->fs_gen_seq, + priv->num_fs_reg * 3); + if (ret < 0) { + dev_err(&pdev->dev, "%s: unable to parse fs-gen-sequence, ret = %d\n", + __func__, ret); + goto err; + } + + /* Get clk details from device tree */ + clk_cnt = of_property_count_strings(pdev->dev.of_node, "clock-names"); + if (clk_cnt <= 0 || clk_cnt > MAX_CLK) { + dev_err(&pdev->dev, "%s: Invalid number of clocks %d", + __func__, clk_cnt); + ret = -EINVAL; + goto err; + } + clk_name_array = devm_kzalloc(&pdev->dev, clk_cnt * sizeof(char *), + GFP_KERNEL); + if (!clk_name_array) { + ret = -ENOMEM; + goto err; + } + + ret = of_property_read_string_array(pdev->dev.of_node, "clock-names", + clk_name_array, clk_cnt); + + for (i = 0; i < MAX_CLK; i++) { + priv->clk[i] = NULL; + for (j = 0; j < clk_cnt; j++) { + if (!strcmp(clk_src_name[i], clk_name_array[j])) { + clk = devm_clk_get(&pdev->dev, clk_src_name[i]); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(&pdev->dev, "%s: clk get failed for %s with ret %d\n", + __func__, clk_src_name[i], ret); + goto err; + } + priv->clk[i] = clk; + dev_dbg(&pdev->dev, "%s: clk get success for clk name %s\n", + __func__, clk_src_name[i]); + } + } + } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,rx_mclk_mode_muxsel", &muxsel); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find qcom,rx_mclk_mode_muxsel entry in dt\n", + __func__); + } else { + priv->rx_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!priv->rx_clk_muxsel) { + dev_err(&pdev->dev, "%s: ioremap failed for rx muxsel\n", + __func__); + return -ENOMEM; + } + } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,wsa_mclk_mode_muxsel", &muxsel); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find qcom,wsa_mclk_mode_muxsel entry in dt\n", + __func__); + } else { + priv->wsa_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!priv->wsa_clk_muxsel) { + dev_err(&pdev->dev, "%s: ioremap failed for wsa muxsel\n", + __func__); + return -ENOMEM; + } + } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,va_mclk_mode_muxsel", &muxsel); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find qcom,va_mclk_mode_muxsel entry in dt\n", + __func__); + } else { + priv->va_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!priv->va_clk_muxsel) { + dev_err(&pdev->dev, "%s: ioremap failed for va muxsel\n", + __func__); + return -ENOMEM; + } + } + + ret = bolero_register_res_clk(&pdev->dev, bolero_clk_rsc_cb); + if (ret < 0) { + dev_err(&pdev->dev, "%s: Failed to register cb %d", + __func__, ret); + goto err; + } + priv->dev = &pdev->dev; + priv->dev_up = true; + priv->dev_up_gfmux = true; + mutex_init(&priv->rsc_clk_lock); + mutex_init(&priv->fs_gen_lock); + dev_set_drvdata(&pdev->dev, priv); + +err: + return ret; +} + +static int bolero_clk_rsc_remove(struct platform_device *pdev) +{ + struct bolero_clk_rsc *priv = dev_get_drvdata(&pdev->dev); + + bolero_unregister_res_clk(&pdev->dev); + of_platform_depopulate(&pdev->dev); + if (!priv) + return -EINVAL; + mutex_destroy(&priv->rsc_clk_lock); + mutex_destroy(&priv->fs_gen_lock); + + return 0; +} + +static const struct of_device_id bolero_clk_rsc_dt_match[] = { + {.compatible = "qcom,bolero-clk-rsc-mngr"}, + {} +}; +MODULE_DEVICE_TABLE(of, bolero_clk_rsc_dt_match); + +static struct platform_driver bolero_clk_rsc_mgr = { + .driver = { + .name = "bolero-clk-rsc-mngr", + .owner = THIS_MODULE, + .of_match_table = bolero_clk_rsc_dt_match, + .suppress_bind_attrs = true, + }, + .probe = bolero_clk_rsc_probe, + .remove = bolero_clk_rsc_remove, +}; + +int bolero_clk_rsc_mgr_init(void) +{ + return platform_driver_register(&bolero_clk_rsc_mgr); +} + +void bolero_clk_rsc_mgr_exit(void) +{ + platform_driver_unregister(&bolero_clk_rsc_mgr); +} +MODULE_DESCRIPTION("Bolero clock resource manager driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-clk-rsc.h b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-clk-rsc.h new file mode 100644 index 0000000000..9a8a1209ed --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/bolero-clk-rsc.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef BOLERO_CLK_RSC_H +#define BOLERO_CLK_RSC_H + +#include +#include + +#if IS_ENABLED(CONFIG_SND_SOC_BOLERO) +int bolero_clk_rsc_mgr_init(void); +void bolero_clk_rsc_mgr_exit(void); +void bolero_clk_rsc_fs_gen_request(struct device *dev, + bool enable); +int bolero_clk_rsc_request_clock(struct device *dev, + int default_clk_id, + int clk_id_req, + bool enable); +int bolero_rsc_clk_reset(struct device *dev, int clk_id); +void bolero_clk_rsc_enable_all_clocks(struct device *dev, bool enable); +#else +static inline void bolero_clk_rsc_fs_gen_request(struct device *dev, + bool enable) +{ +} +static inline int bolero_clk_rsc_mgr_init(void) +{ + return 0; +} +static inline void bolero_clk_rsc_mgr_exit(void) +{ +} +static inline int bolero_clk_rsc_request_clock(struct device *dev, + int default_clk_id, + int clk_id_req, + bool enable) +{ + return 0; +} +static inline int bolero_rsc_clk_reset(struct device *dev, int clk_id) +{ + return 0; +} +static inline void bolero_clk_rsc_enable_all_clocks(struct device *dev, + bool enable) +{ + return; +} +#endif /* CONFIG_SND_SOC_BOLERO */ +#endif /* BOLERO_CLK_RSC_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/internal.h b/qcom/opensource/audio-kernel/asoc/codecs/bolero/internal.h new file mode 100644 index 0000000000..69e7dd458e --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/internal.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _BOLERO_INTERNAL_H +#define _BOLERO_INTERNAL_H + +#include "bolero-cdc-registers.h" + +#define BOLERO_CDC_CHILD_DEVICES_MAX 6 + +enum { + REG_NO_ACCESS, + RD_REG, + WR_REG, + RD_WR_REG +}; + +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); +}; + +struct bolero_priv { + struct device *dev; + struct snd_soc_component *component; + struct regmap *regmap; + struct mutex io_lock; + struct mutex clk_lock; + struct mutex vote_lock; + bool va_without_decimation; + bool macros_supported[MAX_MACRO]; + bool dev_up; + bool initial_boot; + struct macro_ops macro_params[MAX_MACRO]; + struct snd_soc_dai_driver *bolero_dais; + u16 num_dais; + u16 num_macros_registered; + u16 num_macros; + u16 current_mclk_mux_macro[MAX_MACRO]; + struct work_struct bolero_add_child_devices_work; + u32 version; + struct clk *lpass_core_hw_vote; + struct clk *lpass_audio_hw_vote; + int core_hw_vote_count; + int core_audio_vote_count; + + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + + int (*read_dev)(struct bolero_priv *priv, + u16 macro_id, u16 reg, u8 *val); + int (*write_dev)(struct bolero_priv *priv, + u16 macro_id, u16 reg, u8 val); + struct platform_device *pdev_child_devices + [BOLERO_CDC_CHILD_DEVICES_MAX]; + u16 child_count; + struct wcd_ctrl_platform_data plat_data; + struct device *wcd_dev; + struct blocking_notifier_head notifier; + struct device *clk_dev; + rsc_clk_cb_t rsc_clk_cb; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + s32 dmic_6_7_clk_cnt; + u8 dmic_0_1_clk_div; + u8 dmic_2_3_clk_div; + u8 dmic_4_5_clk_div; + u8 dmic_6_7_clk_div; +}; + +struct regmap *bolero_regmap_init(struct device *dev, + const struct regmap_config *config); +int bolero_get_macro_id(bool va_no_dec_flag, u16 reg); + +extern const struct regmap_config bolero_regmap_config; +extern u8 *bolero_reg_access[MAX_MACRO]; +extern u8 bolero_va_top_reg_access[BOLERO_CDC_VA_MACRO_TOP_MAX]; +extern u8 bolero_va_reg_access_v2[BOLERO_CDC_VA_MACRO_MAX]; +extern u8 bolero_va_reg_access_v3[BOLERO_CDC_VA_MACRO_MAX]; +extern u8 bolero_tx_reg_access_v2[BOLERO_CDC_TX_MACRO_MAX]; +extern const u16 macro_id_base_offset[MAX_MACRO]; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/rx-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/rx-macro.c new file mode 100644 index 0000000000..2643311e09 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/rx-macro.c @@ -0,0 +1,4310 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "bolero-cdc.h" +#include "bolero-cdc-registers.h" +#include "bolero-clk-rsc.h" + +#define AUTO_SUSPEND_DELAY 50 /* delay in msec */ +#define RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define RX_MACRO_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define RX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define RX_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_48000) +#define RX_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define SAMPLING_RATE_44P1KHZ 44100 +#define SAMPLING_RATE_88P2KHZ 88200 +#define SAMPLING_RATE_176P4KHZ 176400 +#define SAMPLING_RATE_352P8KHZ 352800 + +#define RX_MACRO_MAX_OFFSET 0x1000 + +#define RX_MACRO_MAX_DMA_CH_PER_PORT 2 +#define RX_SWR_STRING_LEN 80 +#define RX_MACRO_CHILD_DEVICES_MAX 3 + +#define RX_MACRO_INTERP_MUX_NUM_INPUTS 3 +#define RX_MACRO_SIDETONE_IIR_COEFF_MAX 5 + +#define STRING(name) #name +#define RX_MACRO_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define RX_MACRO_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define RX_MACRO_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +#define RX_MACRO_RX_PATH_OFFSET 0x80 +#define RX_MACRO_COMP_OFFSET 0x40 + +#define MAX_IMPED_PARAMS 6 + +#define RX_MACRO_EC_MIX_TX0_MASK 0xf0 +#define RX_MACRO_EC_MIX_TX1_MASK 0x0f +#define RX_MACRO_EC_MIX_TX2_MASK 0x0f + +#define RX_MACRO_GAIN_MAX_VAL 0x28 +#define RX_MACRO_GAIN_VAL_UNITY 0x0 +/* Define macros to increase PA Gain by half */ +#define RX_MACRO_MOD_GAIN (RX_MACRO_GAIN_VAL_UNITY + 6) + +#define COMP_MAX_COEFF 25 + +struct wcd_imped_val { + u32 imped_val; + u8 index; +}; + +static const struct wcd_imped_val imped_index[] = { + {4, 0}, + {5, 1}, + {6, 2}, + {7, 3}, + {8, 4}, + {9, 5}, + {10, 6}, + {11, 7}, + {12, 8}, + {13, 9}, +}; + +struct comp_coeff_val { + u8 lsb; + u8 msb; +}; + +enum { + HPH_ULP, + HPH_LOHIFI, + HPH_MODE_MAX, +}; + +static const struct comp_coeff_val + comp_coeff_table [HPH_MODE_MAX][COMP_MAX_COEFF] = { + { + {0x40, 0x00}, + {0x4C, 0x00}, + {0x5A, 0x00}, + {0x6B, 0x00}, + {0x7F, 0x00}, + {0x97, 0x00}, + {0xB3, 0x00}, + {0xD5, 0x00}, + {0xFD, 0x00}, + {0x2D, 0x01}, + {0x66, 0x01}, + {0xA7, 0x01}, + {0xF8, 0x01}, + {0x57, 0x02}, + {0xC7, 0x02}, + {0x4B, 0x03}, + {0xE9, 0x03}, + {0xA3, 0x04}, + {0x7D, 0x05}, + {0x90, 0x06}, + {0xD1, 0x07}, + {0x49, 0x09}, + {0x00, 0x0B}, + {0x01, 0x0D}, + {0x59, 0x0F}, + }, + { + {0x40, 0x00}, + {0x4C, 0x00}, + {0x5A, 0x00}, + {0x6B, 0x00}, + {0x80, 0x00}, + {0x98, 0x00}, + {0xB4, 0x00}, + {0xD5, 0x00}, + {0xFE, 0x00}, + {0x2E, 0x01}, + {0x66, 0x01}, + {0xA9, 0x01}, + {0xF8, 0x01}, + {0x56, 0x02}, + {0xC4, 0x02}, + {0x4F, 0x03}, + {0xF0, 0x03}, + {0xAE, 0x04}, + {0x8B, 0x05}, + {0x8E, 0x06}, + {0xBC, 0x07}, + {0x56, 0x09}, + {0x0F, 0x0B}, + {0x13, 0x0D}, + {0x6F, 0x0F}, + }, +}; + +struct rx_macro_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static const struct rx_macro_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = { + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf2}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf2}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf4}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf4}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf7}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x01}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf7}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf9}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf9}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfa}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfa}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfb}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfb}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfc}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfc}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x01}, + {BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x01}, + }, +}; + +enum { + INTERP_HPHL, + INTERP_HPHR, + INTERP_AUX, + INTERP_MAX +}; + +enum { + RX_MACRO_RX0, + RX_MACRO_RX1, + RX_MACRO_RX2, + RX_MACRO_RX3, + RX_MACRO_RX4, + RX_MACRO_RX5, + RX_MACRO_PORTS_MAX +}; + +enum { + RX_MACRO_COMP1, /* HPH_L */ + RX_MACRO_COMP2, /* HPH_R */ + RX_MACRO_COMP_MAX +}; + +enum { + RX_MACRO_EC0_MUX = 0, + RX_MACRO_EC1_MUX, + RX_MACRO_EC2_MUX, + RX_MACRO_EC_MUX_MAX, +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, + INTn_1_INP_SEL_IIR0, + INTn_1_INP_SEL_IIR1, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_RX4, + INTn_1_INP_SEL_RX5, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, +}; + +enum { + INTERP_MAIN_PATH, + INTERP_MIX_PATH, +}; + +/* Codec supports 2 IIR filters */ +enum { + IIR0 = 0, + IIR1, + IIR_MAX, +}; + +/* Each IIR has 5 Filter Stages */ +enum { + BAND1 = 0, + BAND2, + BAND3, + BAND4, + BAND5, + BAND_MAX, +}; + +struct rx_macro_idle_detect_config { + u8 hph_idle_thr; + u8 hph_idle_detect_en; +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +static struct interp_sample_rate sr_val_tbl[] = { + {8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5}, + {192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA}, + {176400, 0xB}, {352800, 0xC}, +}; + +struct rx_macro_bcl_pmic_params { + u8 id; + u8 sid; + u8 ppid; +}; + +static int rx_macro_core_vote(void *handle, bool enable); +static int rx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +static int rx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); +static int rx_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream); +static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rx_macro_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rx_macro_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int rx_macro_enable_interp_clk(struct snd_soc_component *component, + int event, int interp_idx); + +/* Hold instance to soundwire platform device */ +struct rx_swr_ctrl_data { + struct platform_device *rx_swr_pdev; +}; + +struct rx_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +enum { + RX_MACRO_AIF_INVALID = 0, + RX_MACRO_AIF1_PB, + RX_MACRO_AIF2_PB, + RX_MACRO_AIF3_PB, + RX_MACRO_AIF4_PB, + RX_MACRO_AIF_ECHO, + RX_MACRO_AIF5_PB, + RX_MACRO_AIF6_PB, + RX_MACRO_MAX_DAIS, +}; + +enum { + RX_MACRO_AIF1_CAP = 0, + RX_MACRO_AIF2_CAP, + RX_MACRO_AIF3_CAP, + RX_MACRO_MAX_AIF_CAP_DAIS +}; +/* + * @dev: rx macro device pointer + * @comp_enabled: compander enable mixer value set + * @prim_int_users: Users of interpolator + * @rx_mclk_users: RX MCLK users count + * @vi_feed_value: VI sense mask + * @swr_clk_lock: to lock swr master clock operations + * @swr_ctrl_data: SoundWire data structure + * @swr_plat_data: Soundwire platform data + * @rx_macro_add_child_devices_work: work for adding child devices + * @rx_swr_gpio_p: used by pinctrl API + * @component: codec handle + */ +struct rx_macro_priv { + struct device *dev; + int comp_enabled[RX_MACRO_COMP_MAX]; + /* Main path clock users count */ + int main_clk_users[INTERP_MAX]; + int rx_port_value[RX_MACRO_PORTS_MAX]; + u16 prim_int_users[INTERP_MAX]; + int rx_mclk_users; + int swr_clk_users; + bool dapm_mclk_enable; + bool reset_swr; + int clsh_users; + int rx_mclk_cnt; + bool is_native_on; + bool is_ear_mode_on; + bool dev_up; + bool hph_pwr_mode; + bool hph_hd2_mode; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct rx_swr_ctrl_data *swr_ctrl_data; + struct rx_swr_ctrl_platform_data swr_plat_data; + struct work_struct rx_macro_add_child_devices_work; + struct device_node *rx_swr_gpio_p; + struct snd_soc_component *component; + unsigned long active_ch_mask[RX_MACRO_MAX_DAIS]; + u16 bit_width[RX_MACRO_MAX_DAIS]; + char __iomem *rx_io_base; + char __iomem *rx_mclk_mode_muxsel; + struct rx_macro_idle_detect_config idle_det_cfg; + u8 sidetone_coeff_array[IIR_MAX][BAND_MAX] + [RX_MACRO_SIDETONE_IIR_COEFF_MAX * 4]; + + struct platform_device *pdev_child_devices + [RX_MACRO_CHILD_DEVICES_MAX]; + int child_count; + int is_softclip_on; + int is_aux_hpf_on; + int softclip_clk_users; + struct rx_macro_bcl_pmic_params bcl_pmic_params; + u16 clk_id; + u16 default_clk_id; + int8_t rx0_gain_val; + int8_t rx1_gain_val; + u32 rx_macro_wsa_slv; +}; + +static struct snd_soc_dai_driver rx_macro_dai[]; +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5" +}; + +static const char * const rx_sidetone_mix_text[] = { + "ZERO", "SRC0", "SRC1", "SRC_SUM" +}; + +static const char * const iir_inp_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", + "RX0", "RX1", "RX2", "RX3", "RX4", "RX5" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_1_interp_mux_text[] = { + "ZERO", "RX INT0_1 MIX1", +}; + +static const char * const rx_int1_1_interp_mux_text[] = { + "ZERO", "RX INT1_1 MIX1", +}; + +static const char * const rx_int2_1_interp_mux_text[] = { + "ZERO", "RX INT2_1 MIX1", +}; + +static const char * const rx_int0_2_interp_mux_text[] = { + "ZERO", "RX INT0_2 MUX", +}; + +static const char * const rx_int1_2_interp_mux_text[] = { + "ZERO", "RX INT1_2 MUX", +}; + +static const char * const rx_int2_2_interp_mux_text[] = { + "ZERO", "RX INT2_2 MUX", +}; + +static const char *const rx_macro_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB" +}; + +static const char *const rx_macro_ear_mode_text[] = {"OFF", "ON"}; +static const struct soc_enum rx_macro_ear_mode_enum = + SOC_ENUM_SINGLE_EXT(2, rx_macro_ear_mode_text); + +static const char *const rx_macro_hph_hd2_mode_text[] = {"OFF", "ON"}; +static const struct soc_enum rx_macro_hph_hd2_mode_enum = + SOC_ENUM_SINGLE_EXT(2, rx_macro_hph_hd2_mode_text); + +static const char *const rx_macro_hph_pwr_mode_text[] = {"ULP", "LOHIFI"}; +static const struct soc_enum rx_macro_hph_pwr_mode_enum = + SOC_ENUM_SINGLE_EXT(2, rx_macro_hph_pwr_mode_text); + +static const char * const rx_macro_vbat_bcl_gsm_mode_text[] = {"OFF", "ON"}; +static const struct soc_enum rx_macro_vbat_bcl_gsm_mode_enum = + SOC_ENUM_SINGLE_EXT(2, rx_macro_vbat_bcl_gsm_mode_text); + +static const struct snd_kcontrol_new rx_int2_1_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("RX AUX VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const char * const hph_idle_detect_text[] = {"OFF", "ON"}; + +static SOC_ENUM_SINGLE_EXT_DECL(hph_idle_detect_enum, hph_idle_detect_text); + +RX_MACRO_DAPM_ENUM(rx_int0_2, BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, + rx_int_mix_mux_text); +RX_MACRO_DAPM_ENUM(rx_int1_2, BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, + rx_int_mix_mux_text); +RX_MACRO_DAPM_ENUM(rx_int2_2, BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, + rx_int_mix_mux_text); + + +RX_MACRO_DAPM_ENUM(rx_int0_1_mix_inp0, BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int0_1_mix_inp1, BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int0_1_mix_inp2, BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int1_1_mix_inp0, BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int1_1_mix_inp1, BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int1_1_mix_inp2, BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int2_1_mix_inp0, BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int2_1_mix_inp1, BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, + rx_prim_mix_text); +RX_MACRO_DAPM_ENUM(rx_int2_1_mix_inp2, BOLERO_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, + rx_prim_mix_text); + +RX_MACRO_DAPM_ENUM(rx_int0_mix2_inp, BOLERO_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, + rx_sidetone_mix_text); +RX_MACRO_DAPM_ENUM(rx_int1_mix2_inp, BOLERO_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, + rx_sidetone_mix_text); +RX_MACRO_DAPM_ENUM(rx_int2_mix2_inp, BOLERO_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6, + rx_sidetone_mix_text); + +RX_MACRO_DAPM_ENUM(iir0_inp0, BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0, + iir_inp_mux_text); +RX_MACRO_DAPM_ENUM(iir0_inp1, BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0, + iir_inp_mux_text); +RX_MACRO_DAPM_ENUM(iir0_inp2, BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0, + iir_inp_mux_text); +RX_MACRO_DAPM_ENUM(iir0_inp3, BOLERO_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0, + iir_inp_mux_text); +RX_MACRO_DAPM_ENUM(iir1_inp0, BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0, + iir_inp_mux_text); +RX_MACRO_DAPM_ENUM(iir1_inp1, BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0, + iir_inp_mux_text); +RX_MACRO_DAPM_ENUM(iir1_inp2, BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0, + iir_inp_mux_text); +RX_MACRO_DAPM_ENUM(iir1_inp3, BOLERO_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0, + iir_inp_mux_text); + +RX_MACRO_DAPM_ENUM(rx_int0_1_interp, SND_SOC_NOPM, 0, + rx_int0_1_interp_mux_text); +RX_MACRO_DAPM_ENUM(rx_int1_1_interp, SND_SOC_NOPM, 0, + rx_int1_1_interp_mux_text); +RX_MACRO_DAPM_ENUM(rx_int2_1_interp, SND_SOC_NOPM, 0, + rx_int2_1_interp_mux_text); + +RX_MACRO_DAPM_ENUM(rx_int0_2_interp, SND_SOC_NOPM, 0, + rx_int0_2_interp_mux_text); +RX_MACRO_DAPM_ENUM(rx_int1_2_interp, SND_SOC_NOPM, 0, + rx_int1_2_interp_mux_text); +RX_MACRO_DAPM_ENUM(rx_int2_2_interp, SND_SOC_NOPM, 0, + rx_int2_2_interp_mux_text); + +RX_MACRO_DAPM_ENUM_EXT(rx_int0_dem_inp, BOLERO_CDC_RX_RX0_RX_PATH_CFG1, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + rx_macro_int_dem_inp_mux_put); +RX_MACRO_DAPM_ENUM_EXT(rx_int1_dem_inp, BOLERO_CDC_RX_RX1_RX_PATH_CFG1, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + rx_macro_int_dem_inp_mux_put); + +RX_MACRO_DAPM_ENUM_EXT(rx_macro_rx0, SND_SOC_NOPM, 0, rx_macro_mux_text, + rx_macro_mux_get, rx_macro_mux_put); +RX_MACRO_DAPM_ENUM_EXT(rx_macro_rx1, SND_SOC_NOPM, 0, rx_macro_mux_text, + rx_macro_mux_get, rx_macro_mux_put); +RX_MACRO_DAPM_ENUM_EXT(rx_macro_rx2, SND_SOC_NOPM, 0, rx_macro_mux_text, + rx_macro_mux_get, rx_macro_mux_put); +RX_MACRO_DAPM_ENUM_EXT(rx_macro_rx3, SND_SOC_NOPM, 0, rx_macro_mux_text, + rx_macro_mux_get, rx_macro_mux_put); +RX_MACRO_DAPM_ENUM_EXT(rx_macro_rx4, SND_SOC_NOPM, 0, rx_macro_mux_text, + rx_macro_mux_get, rx_macro_mux_put); +RX_MACRO_DAPM_ENUM_EXT(rx_macro_rx5, SND_SOC_NOPM, 0, rx_macro_mux_text, + rx_macro_mux_get, rx_macro_mux_put); + +static const char * const rx_echo_mux_text[] = { + "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2" +}; + +static const struct soc_enum rx_mix_tx2_mux_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG5, 0, 4, + rx_echo_mux_text); + +static const struct snd_kcontrol_new rx_mix_tx2_mux = + SOC_DAPM_ENUM("RX MIX TX2_MUX Mux", rx_mix_tx2_mux_enum); + +static const struct soc_enum rx_mix_tx1_mux_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG4, 0, 4, + rx_echo_mux_text); + +static const struct snd_kcontrol_new rx_mix_tx1_mux = + SOC_DAPM_ENUM("RX MIX TX1_MUX Mux", rx_mix_tx1_mux_enum); + +static const struct soc_enum rx_mix_tx0_mux_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG4, 4, 4, + rx_echo_mux_text); + +static const struct snd_kcontrol_new rx_mix_tx0_mux = + SOC_DAPM_ENUM("RX MIX TX0_MUX Mux", rx_mix_tx0_mux_enum); + +static struct snd_soc_dai_ops rx_macro_dai_ops = { + .hw_params = rx_macro_hw_params, + .get_channel_map = rx_macro_get_channel_map, + .mute_stream = rx_macro_mute_stream, +}; + +static struct snd_soc_dai_driver rx_macro_dai[] = { + { + .name = "rx_macro_rx1", + .id = RX_MACRO_AIF1_PB, + .playback = { + .stream_name = "RX_MACRO_AIF1 Playback", + .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES, + .formats = RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx2", + .id = RX_MACRO_AIF2_PB, + .playback = { + .stream_name = "RX_MACRO_AIF2 Playback", + .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES, + .formats = RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx3", + .id = RX_MACRO_AIF3_PB, + .playback = { + .stream_name = "RX_MACRO_AIF3 Playback", + .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES, + .formats = RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx4", + .id = RX_MACRO_AIF4_PB, + .playback = { + .stream_name = "RX_MACRO_AIF4 Playback", + .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES, + .formats = RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &rx_macro_dai_ops, + }, + { + .name = "rx_macro_echo", + .id = RX_MACRO_AIF_ECHO, + .capture = { + .stream_name = "RX_AIF_ECHO Capture", + .rates = RX_MACRO_ECHO_RATES, + .formats = RX_MACRO_ECHO_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 3, + }, + .ops = &rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx5", + .id = RX_MACRO_AIF5_PB, + .playback = { + .stream_name = "RX_MACRO_AIF5 Playback", + .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES, + .formats = RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx6", + .id = RX_MACRO_AIF6_PB, + .playback = { + .stream_name = "RX_MACRO_AIF6 Playback", + .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES, + .formats = RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &rx_macro_dai_ops, + }, +}; + +static int get_impedance_index(int imped) +{ + int i = 0; + + if (imped < imped_index[i].imped_val) { + pr_debug("%s, detected impedance is less than %d Ohm\n", + __func__, imped_index[i].imped_val); + i = 0; + goto ret; + } + if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) { + pr_debug("%s, detected impedance is greater than %d Ohm\n", + __func__, + imped_index[ARRAY_SIZE(imped_index) - 1].imped_val); + i = ARRAY_SIZE(imped_index) - 1; + goto ret; + } + for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) { + if (imped >= imped_index[i].imped_val && + imped < imped_index[i + 1].imped_val) + break; + } +ret: + pr_debug("%s: selected impedance index = %d\n", + __func__, imped_index[i].index); + return imped_index[i].index; +} + +/* + * rx_macro_wcd_clsh_imped_config - + * This function updates HPHL and HPHR gain settings + * according to the impedance value. + * + * @component: codec pointer handle + * @imped: impedance value of HPHL/R + * @reset: bool variable to reset registers when teardown + */ +static void rx_macro_wcd_clsh_imped_config(struct snd_soc_component *component, + int imped, bool reset) +{ + int i; + int index = 0; + int table_size; + + static const struct rx_macro_reg_mask_val + (*imped_table_ptr)[MAX_IMPED_PARAMS]; + + table_size = ARRAY_SIZE(imped_table); + imped_table_ptr = imped_table; + /* reset = 1, which means request is to reset the register values */ + if (reset) { + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, 0); + return; + } + index = get_impedance_index(imped); + if (index >= (ARRAY_SIZE(imped_index) - 1)) { + pr_debug("%s, impedance not in range = %d\n", __func__, imped); + return; + } + if (index >= table_size) { + pr_debug("%s, impedance index not in range = %d\n", __func__, + index); + return; + } + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, + imped_table_ptr[index][i].val); +} + +static bool rx_macro_get_data(struct snd_soc_component *component, + struct device **rx_dev, + struct rx_macro_priv **rx_priv, + const char *func_name) +{ + *rx_dev = bolero_get_device_ptr(component->dev, RX_MACRO); + + if (!(*rx_dev)) { + dev_err(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + + *rx_priv = dev_get_drvdata((*rx_dev)); + if (!(*rx_priv)) { + dev_err(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + + if (!(*rx_priv)->component) { + dev_err(component->dev, + "%s: rx_priv component is not initialized!\n", func_name); + return false; + } + + return true; +} + +static int rx_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (rx_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val = 0; + unsigned short look_ahead_dly_reg = + BOLERO_CDC_RX_RX0_RX_PATH_CFG0; + + val = ucontrol->value.enumerated.item[0]; + if (val >= e->items) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + if (e->reg == BOLERO_CDC_RX_RX0_RX_PATH_CFG1) + look_ahead_dly_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0; + else if (e->reg == BOLERO_CDC_RX_RX1_RX_PATH_CFG1) + look_ahead_dly_reg = BOLERO_CDC_RX_RX1_RX_PATH_CFG0; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, look_ahead_dly_reg, + 0x08, (val ? 0x08 : 0x00)); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp = 0; + u32 j = 0, port = 0; + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u16 int_fs_reg = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 inp0_sel = 0, inp1_sel = 0, inp2_sel = 0; + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + for_each_set_bit(port, &rx_priv->active_ch_mask[dai->id], + RX_MACRO_PORTS_MAX) { + int_1_mix1_inp = port; + if ((int_1_mix1_inp < RX_MACRO_RX0) || + (int_1_mix1_inp > RX_MACRO_PORTS_MAX)) { + pr_err("%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg0 = BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the rx port + * is connected + */ + for (j = 0; j < INTERP_MAX; j++) { + int_mux_cfg1 = int_mux_cfg0 + 4; + + int_mux_cfg0_val = snd_soc_component_read( + component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read( + component, int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & 0x0F; + inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F; + inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F; + if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { + int_fs_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + + 0x80 * j; + pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + pr_debug("%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + /* sample_rate is in Hz */ + snd_soc_component_update_bits(component, + int_fs_reg, + 0x0F, rate_reg_val); + } + int_mux_cfg0 += 8; + } + } + + return 0; +} + +static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp = 0; + u32 j = 0, port = 0; + u16 int_mux_cfg1 = 0, int_fs_reg = 0; + u8 int_mux_cfg1_val = 0; + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + for_each_set_bit(port, &rx_priv->active_ch_mask[dai->id], + RX_MACRO_PORTS_MAX) { + int_2_inp = port; + if ((int_2_inp < RX_MACRO_RX0) || + (int_2_inp > RX_MACRO_PORTS_MAX)) { + pr_err("%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg1 = BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < INTERP_MAX; j++) { + int_mux_cfg1_val = snd_soc_component_read( + component, int_mux_cfg1) & + 0x0F; + if (int_mux_cfg1_val == int_2_inp + + INTn_2_INP_SEL_RX0) { + int_fs_reg = BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL + + 0x80 * j; + pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + pr_debug("%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits( + component, int_fs_reg, + 0x0F, rate_reg_val); + } + int_mux_cfg1 += 8; + } + } + return 0; +} + +static bool rx_macro_is_fractional_sample_rate(u32 sample_rate) +{ + switch (sample_rate) { + case SAMPLING_RATE_44P1KHZ: + case SAMPLING_RATE_88P2KHZ: + case SAMPLING_RATE_176P4KHZ: + case SAMPLING_RATE_352P8KHZ: + return true; + default: + return false; + } + return false; +} + +static int rx_macro_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_component *component = dai->component; + int rate_val = 0; + int i = 0, ret = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + + for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) { + if (sample_rate == sr_val_tbl[i].sample_rate) { + rate_val = sr_val_tbl[i].rate_val; + if (rx_macro_is_fractional_sample_rate(sample_rate)) + rx_priv->is_native_on = true; + else + rx_priv->is_native_on = false; + break; + } + } + if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) { + dev_err(component->dev, "%s: Unsupported sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + } + + ret = rx_macro_set_prim_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + ret = rx_macro_set_mix_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + + return ret; +} + +static int rx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = rx_macro_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + pr_err("%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + rx_priv->bit_width[dai->id] = params_width(params); + break; + case SNDRV_PCM_STREAM_CAPTURE: + default: + break; + } + return 0; +} + +static int rx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + unsigned int temp = 0, ch_mask = 0; + u16 val = 0, mask = 0, cnt = 0, i = 0; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case RX_MACRO_AIF1_PB: + case RX_MACRO_AIF2_PB: + case RX_MACRO_AIF3_PB: + case RX_MACRO_AIF4_PB: + for_each_set_bit(temp, &rx_priv->active_ch_mask[dai->id], + RX_MACRO_PORTS_MAX) { + ch_mask |= (1 << temp); + if (++i == RX_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + /* + * CDC_DMA_RX_0 port drives RX0/RX1 -- ch_mask 0x1/0x2/0x3 + * CDC_DMA_RX_1 port drives RX2/RX3 -- ch_mask 0x1/0x2/0x3 + * CDC_DMA_RX_2 port drives RX4 -- ch_mask 0x1 + * CDC_DMA_RX_3 port drives RX5 -- ch_mask 0x1 + * AIFn can pair to any CDC_DMA_RX_n port. + * In general, below convention is used:: + * CDC_DMA_RX_0(AIF1)/CDC_DMA_RX_1(AIF2)/ + * CDC_DMA_RX_2(AIF3)/CDC_DMA_RX_3(AIF4) + * Above is reflected in machine driver BE dailink + */ + if (ch_mask & 0x0C) + ch_mask = ch_mask >> 2; + if ((ch_mask & 0x10) || (ch_mask & 0x20)) + ch_mask = 0x1; + *rx_slot = ch_mask; + *rx_num = hweight_long(ch_mask); + dev_dbg(rx_priv->dev, + "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d active_mask: 0x%x\n", + __func__, dai->id, *rx_slot, *rx_num, rx_priv->active_ch_mask[dai->id]); + break; + case RX_MACRO_AIF5_PB: + *rx_slot = 0x1; + *rx_num = 0x01; + dev_dbg(rx_priv->dev, + "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d\n", + __func__, dai->id, *rx_slot, *rx_num); + break; + case RX_MACRO_AIF6_PB: + *rx_slot = 0x1; + *rx_num = 0x01; + dev_dbg(rx_priv->dev, + "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d\n", + __func__, dai->id, *rx_slot, *rx_num); + break; + case RX_MACRO_AIF_ECHO: + val = snd_soc_component_read(component, + BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG4); + if (val & RX_MACRO_EC_MIX_TX0_MASK) { + mask |= 0x1; + cnt++; + } + if (val & RX_MACRO_EC_MIX_TX1_MASK) { + mask |= 0x2; + cnt++; + } + val = snd_soc_component_read(component, + BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG5); + if (val & RX_MACRO_EC_MIX_TX2_MASK) { + mask |= 0x4; + cnt++; + } + *tx_slot = mask; + *tx_num = cnt; + break; + default: + dev_err(rx_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static int rx_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + uint16_t j = 0, reg = 0, mix_reg = 0, dsm_reg = 0; + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + + if (mute) + return 0; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case RX_MACRO_AIF1_PB: + case RX_MACRO_AIF2_PB: + case RX_MACRO_AIF3_PB: + case RX_MACRO_AIF4_PB: + for (j = 0; j < INTERP_MAX; j++) { + reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + + (j * RX_MACRO_RX_PATH_OFFSET); + mix_reg = BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL + + (j * RX_MACRO_RX_PATH_OFFSET); + dsm_reg = BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL + + (j * RX_MACRO_RX_PATH_OFFSET); + if (j == INTERP_AUX) + dsm_reg = BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL; + int_mux_cfg0 = BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1); + if (snd_soc_component_read(component, dsm_reg) & 0x01) { + if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0)) + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + if (int_mux_cfg1_val & 0x0F) { + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + snd_soc_component_update_bits(component, + mix_reg, 0x20, 0x20); + } + } + } + + if (rx_priv->rx_macro_wsa_slv) + bolero_rx_pa_on(rx_dev); + break; + + default: + break; + } + return 0; +} + +static int rx_macro_mclk_enable(struct rx_macro_priv *rx_priv, + bool mclk_enable, bool dapm) +{ + struct regmap *regmap = dev_get_regmap(rx_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(rx_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(rx_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n", + __func__, mclk_enable, dapm, rx_priv->rx_mclk_users); + + mutex_lock(&rx_priv->mclk_lock); + if (mclk_enable) { + if (rx_priv->rx_mclk_users == 0) { + if (rx_priv->is_native_on) + rx_priv->clk_id = RX_CORE_CLK; + rx_macro_core_vote(rx_priv, true); + ret = bolero_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + rx_priv->clk_id, + true); + rx_macro_core_vote(rx_priv, false); + if (ret < 0) { + dev_err(rx_priv->dev, + "%s: rx request clock enable failed\n", + __func__); + goto exit; + } + bolero_clk_rsc_fs_gen_request(rx_priv->dev, + true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + RX_START_OFFSET, + RX_MAX_OFFSET); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x00); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + rx_priv->rx_mclk_users++; + } else { + if (rx_priv->rx_mclk_users <= 0) { + dev_err(rx_priv->dev, "%s: clock already disabled\n", + __func__); + rx_priv->rx_mclk_users = 0; + goto exit; + } + rx_priv->rx_mclk_users--; + if (rx_priv->rx_mclk_users == 0) { + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x00); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + bolero_clk_rsc_fs_gen_request(rx_priv->dev, + false); + rx_macro_core_vote(rx_priv, true); + bolero_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + rx_priv->clk_id, + false); + rx_macro_core_vote(rx_priv, false); + rx_priv->clk_id = rx_priv->default_clk_id; + } + } +exit: + mutex_unlock(&rx_priv->mclk_lock); + return ret; +} + +static int rx_macro_mclk_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); + int ret = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + int mclk_freq = MCLK_FREQ; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(rx_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (rx_priv->is_native_on) + mclk_freq = MCLK_FREQ_NATIVE; + if (rx_priv->swr_ctrl_data) + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_CLK_FREQ, &mclk_freq); + ret = rx_macro_mclk_enable(rx_priv, 1, true); + if (ret) + rx_priv->dapm_mclk_enable = false; + else + rx_priv->dapm_mclk_enable = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (rx_priv->dapm_mclk_enable) + ret = rx_macro_mclk_enable(rx_priv, 0, true); + break; + default: + dev_err(rx_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int rx_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + u16 reg = 0, reg_mix = 0, rx_idx = 0, mute = 0x0, val = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + int ret = 0; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (event) { + case BOLERO_MACRO_EVT_RX_MUTE: + rx_idx = data >> 0x10; + mute = data & 0xffff; + val = mute ? 0x10 : 0x00; + reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + (rx_idx * + RX_MACRO_RX_PATH_OFFSET); + reg_mix = BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL + (rx_idx * + RX_MACRO_RX_PATH_OFFSET); + snd_soc_component_update_bits(component, reg, + 0x10, val); + snd_soc_component_update_bits(component, reg_mix, + 0x10, val); + break; + case BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST: + rx_idx = data >> 0x10; + if (rx_idx == INTERP_AUX) + goto done; + reg = BOLERO_CDC_RX_COMPANDER0_CTL0 + + (rx_idx * RX_MACRO_COMP_OFFSET); + snd_soc_component_write(component, reg, + snd_soc_component_read(component, reg)); + break; + case BOLERO_MACRO_EVT_IMPED_TRUE: + rx_macro_wcd_clsh_imped_config(component, data, true); + break; + case BOLERO_MACRO_EVT_IMPED_FALSE: + rx_macro_wcd_clsh_imped_config(component, data, false); + break; + case BOLERO_MACRO_EVT_SSR_DOWN: + rx_priv->dev_up = false; + if (rx_priv->swr_ctrl_data) { + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(rx_dev) || + !pm_runtime_suspended(rx_dev))) { + ret = bolero_runtime_suspend(rx_dev); + if (!ret) { + pm_runtime_disable(rx_dev); + pm_runtime_set_suspended(rx_dev); + pm_runtime_enable(rx_dev); + } + } + break; + case BOLERO_MACRO_EVT_PRE_SSR_UP: + rx_macro_core_vote(rx_priv, true); + /* enable&disable RX_CORE_CLK to reset GFMUX reg */ + ret = bolero_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + RX_CORE_CLK, true); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, + "%s, failed to enable clk, ret:%d\n", + __func__, ret); + } else { + bolero_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + RX_CORE_CLK, false); + } + rx_macro_core_vote(rx_priv, false); + break; + case BOLERO_MACRO_EVT_SSR_UP: + rx_priv->dev_up = true; + /* reset swr after ssr/pdr */ + rx_priv->reset_swr = true; + + if (rx_priv->swr_ctrl_data) + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case BOLERO_MACRO_EVT_CLK_RESET: + bolero_rsc_clk_reset(rx_dev, RX_CORE_CLK); + break; + case BOLERO_MACRO_EVT_RX_PA_GAIN_UPDATE: + rx_priv->rx0_gain_val = snd_soc_component_read(component, + BOLERO_CDC_RX_RX0_RX_VOL_CTL); + rx_priv->rx1_gain_val = snd_soc_component_read(component, + BOLERO_CDC_RX_RX1_RX_VOL_CTL); + if (data) { + /* Reduce gain by half only if its greater than -6DB */ + if ((rx_priv->rx0_gain_val >= RX_MACRO_GAIN_VAL_UNITY) + && (rx_priv->rx0_gain_val <= RX_MACRO_GAIN_MAX_VAL)) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xFF, + (rx_priv->rx0_gain_val - + RX_MACRO_MOD_GAIN)); + if ((rx_priv->rx1_gain_val >= RX_MACRO_GAIN_VAL_UNITY) + && (rx_priv->rx1_gain_val <= RX_MACRO_GAIN_MAX_VAL)) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xFF, + (rx_priv->rx1_gain_val - + RX_MACRO_MOD_GAIN)); + } + else { + /* Reset gain value to default */ + if ((rx_priv->rx0_gain_val >= + (RX_MACRO_GAIN_VAL_UNITY - RX_MACRO_MOD_GAIN)) && + (rx_priv->rx0_gain_val <= (RX_MACRO_GAIN_MAX_VAL - + RX_MACRO_MOD_GAIN))) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_VOL_CTL, 0xFF, + (rx_priv->rx0_gain_val + + RX_MACRO_MOD_GAIN)); + if ((rx_priv->rx1_gain_val >= + (RX_MACRO_GAIN_VAL_UNITY - RX_MACRO_MOD_GAIN)) && + (rx_priv->rx1_gain_val <= (RX_MACRO_GAIN_MAX_VAL - + RX_MACRO_MOD_GAIN))) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX1_RX_VOL_CTL, 0xFF, + (rx_priv->rx1_gain_val + + RX_MACRO_MOD_GAIN)); + } + break; + case BOLERO_MACRO_EVT_HPHL_HD2_ENABLE: + /* Enable hd2 config for hphl*/ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_PATH_CFG0, 0x04, data); + break; + case BOLERO_MACRO_EVT_HPHR_HD2_ENABLE: + /* Enable hd2 config for hphr*/ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX1_RX_PATH_CFG0, 0x04, data); + break; + } +done: + return ret; +} + +static int rx_macro_find_playback_dai_id_for_port(int port_id, + struct rx_macro_priv *rx_priv) +{ + int i = 0; + + for (i = RX_MACRO_AIF1_PB; i < RX_MACRO_MAX_DAIS; i++) { + if (test_bit(port_id, &rx_priv->active_ch_mask[i])) + return i; + } + + return -EINVAL; +} + +static int rx_macro_set_idle_detect_thr(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + int interp, int path_type) +{ + int port_id[4] = { 0, 0, 0, 0 }; + int *port_ptr = NULL; + int num_ports = 0; + int bit_width = 0, i = 0; + int mux_reg = 0, mux_reg_val = 0; + int dai_id = 0, idle_thr = 0; + + if ((interp != INTERP_HPHL) && (interp != INTERP_HPHR)) + return 0; + + if (!rx_priv->idle_det_cfg.hph_idle_detect_en) + return 0; + + port_ptr = &port_id[0]; + num_ports = 0; + + /* + * Read interpolator MUX input registers and find + * which cdc_dma port is connected and store the port + * numbers in port_id array. + */ + if (path_type == INTERP_MIX_PATH) { + mux_reg = BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG1 + + 2 * interp; + mux_reg_val = snd_soc_component_read(component, mux_reg) & + 0x0f; + + if ((mux_reg_val >= INTn_2_INP_SEL_RX0) && + (mux_reg_val <= INTn_2_INP_SEL_RX5)) { + *port_ptr++ = mux_reg_val - 1; + num_ports++; + } + } + + if (path_type == INTERP_MAIN_PATH) { + mux_reg = BOLERO_CDC_RX_INP_MUX_RX_INT1_CFG0 + + 2 * (interp - 1); + mux_reg_val = snd_soc_component_read(component, mux_reg) & + 0x0f; + i = RX_MACRO_INTERP_MUX_NUM_INPUTS; + + while (i) { + if ((mux_reg_val >= INTn_1_INP_SEL_RX0) && + (mux_reg_val <= INTn_1_INP_SEL_RX5)) { + *port_ptr++ = mux_reg_val - + INTn_1_INP_SEL_RX0; + num_ports++; + } + mux_reg_val = + (snd_soc_component_read(component, mux_reg) & + 0xf0) >> 4; + mux_reg += 1; + i--; + } + } + + dev_dbg(component->dev, "%s: num_ports: %d, ports[%d %d %d %d]\n", + __func__, num_ports, port_id[0], port_id[1], + port_id[2], port_id[3]); + + i = 0; + while (num_ports) { + dai_id = rx_macro_find_playback_dai_id_for_port(port_id[i++], + rx_priv); + + if ((dai_id >= 0) && (dai_id < RX_MACRO_MAX_DAIS)) { + dev_dbg(component->dev, "%s: dai_id: %d bit_width: %d\n", + __func__, dai_id, + rx_priv->bit_width[dai_id]); + + if (rx_priv->bit_width[dai_id] > bit_width) + bit_width = rx_priv->bit_width[dai_id]; + } + num_ports--; + } + + switch (bit_width) { + case 16: + idle_thr = 0xff; /* F16 */ + break; + case 24: + case 32: + idle_thr = 0x03; /* F22 */ + break; + default: + idle_thr = 0x00; + break; + } + + dev_dbg(component->dev, "%s: (new) idle_thr: %d, (cur) idle_thr: %d\n", + __func__, idle_thr, rx_priv->idle_det_cfg.hph_idle_thr); + + if ((rx_priv->idle_det_cfg.hph_idle_thr == 0) || + (idle_thr < rx_priv->idle_det_cfg.hph_idle_thr)) { + snd_soc_component_write(component, + BOLERO_CDC_RX_IDLE_DETECT_CFG3, idle_thr); + rx_priv->idle_det_cfg.hph_idle_thr = idle_thr; + } + + return 0; +} + +static int rx_macro_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg = 0, mix_reg = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + if (w->shift >= INTERP_MAX) { + dev_err(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + } + + gain_reg = BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL + + (w->shift * RX_MACRO_RX_PATH_OFFSET); + mix_reg = BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL + + (w->shift * RX_MACRO_RX_PATH_OFFSET); + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + rx_macro_set_idle_detect_thr(component, rx_priv, w->shift, + INTERP_MIX_PATH); + rx_macro_enable_interp_clk(component, event, w->shift); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write(component, gain_reg, + snd_soc_component_read(component, gain_reg)); + break; + case SND_SOC_DAPM_POST_PMD: + /* Clk Disable */ + snd_soc_component_update_bits(component, mix_reg, 0x20, 0x00); + rx_macro_enable_interp_clk(component, event, w->shift); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x40); + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x00); + break; + } + + return 0; +} + +static bool rx_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0; + + int_mux_cfg0 = BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || + int_n_inp0 == INTn_1_INP_SEL_DEC1 || + int_n_inp0 == INTn_1_INP_SEL_IIR0 || + int_n_inp0 == INTn_1_INP_SEL_IIR1) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || + int_n_inp1 == INTn_1_INP_SEL_DEC1 || + int_n_inp1 == INTn_1_INP_SEL_IIR0 || + int_n_inp1 == INTn_1_INP_SEL_IIR1) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || + int_n_inp2 == INTn_1_INP_SEL_DEC1 || + int_n_inp2 == INTn_1_INP_SEL_IIR0 || + int_n_inp2 == INTn_1_INP_SEL_IIR1) + return true; + + return false; +} + +static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg = 0; + u16 reg = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (w->shift >= INTERP_MAX) { + dev_err(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + } + + reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + (w->shift * + RX_MACRO_RX_PATH_OFFSET); + gain_reg = BOLERO_CDC_RX_RX0_RX_VOL_CTL + (w->shift * + RX_MACRO_RX_PATH_OFFSET); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + rx_macro_set_idle_detect_thr(component, rx_priv, w->shift, + INTERP_MAIN_PATH); + rx_macro_enable_interp_clk(component, event, w->shift); + if (rx_macro_adie_lb(component, w->shift)) + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write(component, gain_reg, + snd_soc_component_read(component, gain_reg)); + break; + case SND_SOC_DAPM_POST_PMD: + rx_macro_enable_interp_clk(component, event, w->shift); + break; + } + + return 0; +} + +static int rx_macro_config_compander(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + int interp_n, int event) +{ + int comp = 0; + u16 comp_ctl0_reg = 0, rx_path_cfg0_reg = 0, rx_path_cfg3_reg = 0; + u16 rx0_path_ctl_reg = 0; + u8 pcm_rate = 0, val = 0; + + /* AUX does not have compander */ + if (interp_n == INTERP_AUX) + return 0; + + comp = interp_n; + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, rx_priv->comp_enabled[comp]); + + rx_path_cfg3_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG3 + + (comp * RX_MACRO_RX_PATH_OFFSET); + rx0_path_ctl_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + + (comp * RX_MACRO_RX_PATH_OFFSET); + pcm_rate = (snd_soc_component_read(component, rx0_path_ctl_reg) + & 0x0F); + if (pcm_rate < 0x06) + val = 0x03; + else if (pcm_rate < 0x08) + val = 0x01; + else if (pcm_rate < 0x0B) + val = 0x02; + else + val = 0x00; + + if (SND_SOC_DAPM_EVENT_ON(event)) + snd_soc_component_update_bits(component, rx_path_cfg3_reg, + 0x03, val); + if (SND_SOC_DAPM_EVENT_OFF(event)) + snd_soc_component_update_bits(component, rx_path_cfg3_reg, + 0x03, 0x03); + if (!rx_priv->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = BOLERO_CDC_RX_COMPANDER0_CTL0 + + (comp * RX_MACRO_COMP_OFFSET); + rx_path_cfg0_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0 + + (comp * RX_MACRO_RX_PATH_OFFSET); + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x04); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x00); + } + + return 0; +} + +static int rx_macro_load_compander_coeff(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + int interp_n, int event) +{ + int comp = 0; + u16 comp_coeff_lsb_reg = 0, comp_coeff_msb_reg = 0; + int i = 0; + int hph_pwr_mode = HPH_LOHIFI; + + if (!rx_priv->comp_enabled[comp]) + return 0; + + if (interp_n == INTERP_HPHL) { + comp_coeff_lsb_reg = BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB; + comp_coeff_msb_reg = BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB; + } else if (interp_n == INTERP_HPHR) { + comp_coeff_lsb_reg = BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB; + comp_coeff_msb_reg = BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB; + } else { + /* compander coefficients are loaded only for hph path */ + return 0; + } + + comp = interp_n; + hph_pwr_mode = rx_priv->hph_pwr_mode; + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, rx_priv->comp_enabled[comp]); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Load Compander Coeff */ + for (i = 0; i < COMP_MAX_COEFF; i++) { + snd_soc_component_write(component, comp_coeff_lsb_reg, + comp_coeff_table[hph_pwr_mode][i].lsb); + snd_soc_component_write(component, comp_coeff_msb_reg, + comp_coeff_table[hph_pwr_mode][i].msb); + } + } + + return 0; +} + +static void rx_macro_enable_softclip_clk(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + bool enable) +{ + if (enable) { + if (rx_priv->softclip_clk_users == 0) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_SOFTCLIP_CRC, + 0x01, 0x01); + rx_priv->softclip_clk_users++; + } else { + rx_priv->softclip_clk_users--; + if (rx_priv->softclip_clk_users == 0) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_SOFTCLIP_CRC, + 0x01, 0x00); + } +} + +static int rx_macro_config_softclip(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + int event) +{ + dev_dbg(component->dev, "%s: event %d, enabled %d\n", + __func__, event, rx_priv->is_softclip_on); + + if (!rx_priv->is_softclip_on) + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Softclip clock */ + rx_macro_enable_softclip_clk(component, rx_priv, true); + /* Enable Softclip control */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x01, 0x01); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x01, 0x00); + rx_macro_enable_softclip_clk(component, rx_priv, false); + } + + return 0; +} + +static int rx_macro_config_aux_hpf(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + int event) +{ + dev_dbg(component->dev, "%s: event %d, enabled %d\n", + __func__, event, rx_priv->is_aux_hpf_on); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Update Aux HPF control */ + if (!rx_priv->is_aux_hpf_on) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x00); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + /* Reset to default (HPF=ON) */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x04); + } + + return 0; +} + + +static inline void +rx_macro_enable_clsh_block(struct rx_macro_priv *rx_priv, bool enable) +{ + if ((enable && ++rx_priv->clsh_users == 1) || + (!enable && --rx_priv->clsh_users == 0)) + snd_soc_component_update_bits(rx_priv->component, + BOLERO_CDC_RX_CLSH_CRC, 0x01, + (u8) enable); + if (rx_priv->clsh_users < 0) + rx_priv->clsh_users = 0; + dev_dbg(rx_priv->dev, "%s: clsh_users %d, enable %d", __func__, + rx_priv->clsh_users, enable); +} + +static int rx_macro_config_classh(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + int interp_n, int event) +{ + if (SND_SOC_DAPM_EVENT_OFF(event)) { + rx_macro_enable_clsh_block(rx_priv, false); + return 0; + } + + if (!SND_SOC_DAPM_EVENT_ON(event)) + return 0; + + rx_macro_enable_clsh_block(rx_priv, true); + if (interp_n == INTERP_HPHL || + interp_n == INTERP_HPHR) { + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_K1_LSB, + 0xFF, 0xC0); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_K1_MSB, + 0x0F, 0x00); + } + switch (interp_n) { + case INTERP_HPHL: + if (rx_priv->is_ear_mode_on) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x39); + else + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x1C); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_DECAY_CTRL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_PATH_CFG0, + 0x40, 0x40); + break; + case INTERP_HPHR: + if (rx_priv->is_ear_mode_on) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x39); + else + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x1C); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_DECAY_CTRL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX1_RX_PATH_CFG0, + 0x40, 0x40); + break; + case INTERP_AUX: + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG0, + 0x08, 0x08); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG0, + 0x10, 0x10); + break; + } + + return 0; +} + +static void rx_macro_hd2_control(struct snd_soc_component *component, + u16 interp_idx, int event) +{ + u16 hd2_scale_reg = 0; + u16 hd2_enable_reg = 0; + + switch (interp_idx) { + case INTERP_HPHL: + hd2_scale_reg = BOLERO_CDC_RX_RX0_RX_PATH_SEC3; + hd2_enable_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0; + break; + case INTERP_HPHR: + hd2_scale_reg = BOLERO_CDC_RX_RX1_RX_PATH_SEC3; + hd2_enable_reg = BOLERO_CDC_RX_RX1_RX_PATH_CFG0; + break; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x14); + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x00); + } +} + +static int rx_macro_hph_idle_detect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rx_macro_priv *rx_priv = NULL; + struct device *rx_dev = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + rx_priv->idle_det_cfg.hph_idle_detect_en; + + return 0; +} + +static int rx_macro_hph_idle_detect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rx_macro_priv *rx_priv = NULL; + struct device *rx_dev = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->idle_det_cfg.hph_idle_detect_en = + ucontrol->value.integer.value[0]; + + return 0; +} + +static int rx_macro_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->comp_enabled[comp]; + return 0; +} + +static int rx_macro_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, rx_priv->comp_enabled[comp], value); + rx_priv->comp_enabled[comp] = value; + + return 0; +} + +static int rx_macro_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + rx_priv->rx_port_value[widget->shift]; + return 0; +} + +static int rx_macro_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 rx_port_value = ucontrol->value.integer.value[0]; + u32 aif_rst = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + aif_rst = rx_priv->rx_port_value[widget->shift]; + if (!rx_port_value) { + if (aif_rst == 0) { + dev_err(rx_dev, "%s:AIF reset already\n", __func__); + return 0; + } + if (aif_rst > RX_MACRO_AIF4_PB) { + dev_err(rx_dev, "%s: Invalid AIF reset\n", __func__); + return 0; + } + } + rx_priv->rx_port_value[widget->shift] = rx_port_value; + + dev_dbg(rx_dev, "%s: mux input: %d, mux output: %d, aif_rst: %d\n", + __func__, rx_port_value, widget->shift, aif_rst); + + switch (rx_port_value) { + case 0: + clear_bit(widget->shift, &rx_priv->active_ch_mask[aif_rst]); + break; + case 1: + case 2: + case 3: + case 4: + set_bit(widget->shift, + &rx_priv->active_ch_mask[rx_port_value]); + break; + default: + dev_err(component->dev, + "%s:Invalid AIF_ID for RX_MACRO MUX %d\n", + __func__, rx_port_value); + goto err; + } + + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + return 0; +err: + return -EINVAL; +} + +static int rx_macro_get_ear_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->is_ear_mode_on; + return 0; +} + +static int rx_macro_put_ear_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_ear_mode_on = + (!ucontrol->value.integer.value[0] ? false : true); + return 0; +} + +static int rx_macro_get_hph_hd2_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->hph_hd2_mode; + return 0; +} + +static int rx_macro_put_hph_hd2_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->hph_hd2_mode = ucontrol->value.integer.value[0]; + return 0; +} + +static int rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->hph_pwr_mode; + return 0; +} + +static int rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->hph_pwr_mode = ucontrol->value.integer.value[0]; + return 0; +} + +static int rx_macro_vbat_bcl_gsm_mode_func_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ucontrol->value.integer.value[0] = + ((snd_soc_component_read( + component, BOLERO_CDC_RX_BCL_VBAT_CFG) & 0x04) ? + 1 : 0); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int rx_macro_vbat_bcl_gsm_mode_func_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + /* Set Vbat register configuration for GSM mode bit based on value */ + if (ucontrol->value.integer.value[0]) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_CFG, + 0x04, 0x04); + else + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_CFG, + 0x04, 0x00); + + return 0; +} + +static int rx_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->is_softclip_on; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int rx_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_softclip_on = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: soft clip enable = %d\n", __func__, + rx_priv->is_softclip_on); + + return 0; +} + +static int rx_macro_aux_hpf_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->is_aux_hpf_on; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int rx_macro_aux_hpf_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_aux_hpf_on = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: aux hpf enable = %d\n", __func__, + rx_priv->is_aux_hpf_on); + + return 0; +} + + +static int rx_macro_enable_vbat(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 device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable clock for VBAT block */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_PATH_CTL, 0x10, 0x10); + /* Enable VBAT block */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_CFG, 0x01, 0x01); + /* Update interpolator with 384K path */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG1, 0x80, 0x80); + /* Update DSM FS rate */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_SEC7, 0x02, 0x02); + /* Use attenuation mode */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_CFG, 0x02, 0x00); + /* BCL block needs softclip clock to be enabled */ + rx_macro_enable_softclip_clk(component, rx_priv, true); + /* Enable VBAT at channel level */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG1, 0x02, 0x02); + /* Set the ATTK1 gain */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + /* Set the ATTK2 gain */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + /* Set the ATTK3 gain */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG1, + 0x80, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_SEC7, + 0x02, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_CFG, + 0x02, 0x02); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX2_RX_PATH_CFG1, + 0x02, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + rx_macro_enable_softclip_clk(component, rx_priv, false); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_CFG, 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_PATH_CTL, 0x10, 0x00); + break; + default: + dev_err(rx_dev, "%s: Invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static void rx_macro_idle_detect_control(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + int interp, int event) +{ + int reg = 0, mask = 0, val = 0; + + if (!rx_priv->idle_det_cfg.hph_idle_detect_en) + return; + + if (interp == INTERP_HPHL) { + reg = BOLERO_CDC_RX_IDLE_DETECT_PATH_CTL; + mask = 0x01; + val = 0x01; + } + if (interp == INTERP_HPHR) { + reg = BOLERO_CDC_RX_IDLE_DETECT_PATH_CTL; + mask = 0x02; + val = 0x02; + } + + if (reg && SND_SOC_DAPM_EVENT_ON(event)) + snd_soc_component_update_bits(component, reg, mask, val); + + if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, reg, mask, 0x00); + rx_priv->idle_det_cfg.hph_idle_thr = 0; + snd_soc_component_write(component, + BOLERO_CDC_RX_IDLE_DETECT_CFG3, 0x0); + } +} + +static void rx_macro_hphdelay_lutbypass(struct snd_soc_component *component, + struct rx_macro_priv *rx_priv, + u16 interp_idx, int event) +{ + u16 hph_lut_bypass_reg = 0; + u16 hph_comp_ctrl7 = 0; + + switch (interp_idx) { + case INTERP_HPHL: + hph_lut_bypass_reg = BOLERO_CDC_RX_TOP_HPHL_COMP_LUT; + hph_comp_ctrl7 = BOLERO_CDC_RX_COMPANDER0_CTL7; + break; + case INTERP_HPHR: + hph_lut_bypass_reg = BOLERO_CDC_RX_TOP_HPHR_COMP_LUT; + hph_comp_ctrl7 = BOLERO_CDC_RX_COMPANDER1_CTL7; + break; + default: + break; + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) { + if (interp_idx == INTERP_HPHL) { + if (rx_priv->is_ear_mode_on) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_PATH_CFG1, + 0x02, 0x02); + else + snd_soc_component_update_bits(component, + hph_lut_bypass_reg, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, + hph_lut_bypass_reg, + 0x80, 0x80); + } + if (rx_priv->hph_pwr_mode) + snd_soc_component_update_bits(component, + hph_comp_ctrl7, + 0x20, 0x00); + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_RX0_RX_PATH_CFG1, + 0x02, 0x00); + snd_soc_component_update_bits(component, hph_lut_bypass_reg, + 0x80, 0x00); + snd_soc_component_update_bits(component, hph_comp_ctrl7, + 0x20, 0x20); + } +} + +static int rx_macro_enable_interp_clk(struct snd_soc_component *component, + int event, int interp_idx) +{ + u16 main_reg = 0, dsm_reg = 0, rx_cfg2_reg = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + main_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + + (interp_idx * RX_MACRO_RX_PATH_OFFSET); + dsm_reg = BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL + + (interp_idx * RX_MACRO_RX_PATH_OFFSET); + if (interp_idx == INTERP_AUX) + dsm_reg = BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL; + rx_cfg2_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG2 + + (interp_idx * RX_MACRO_RX_PATH_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (rx_priv->main_clk_users[interp_idx] == 0) { + /* Main path PGA mute enable */ + snd_soc_component_update_bits(component, main_reg, + 0x10, 0x10); + snd_soc_component_update_bits(component, dsm_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, rx_cfg2_reg, + 0x03, 0x03); + rx_macro_load_compander_coeff(component, rx_priv, + interp_idx, event); + rx_macro_idle_detect_control(component, rx_priv, + interp_idx, event); + if (rx_priv->hph_hd2_mode) + rx_macro_hd2_control( + component, interp_idx, event); + rx_macro_hphdelay_lutbypass(component, rx_priv, + interp_idx, event); + rx_macro_config_compander(component, rx_priv, + interp_idx, event); + if (interp_idx == INTERP_AUX) { + rx_macro_config_softclip(component, rx_priv, + event); + rx_macro_config_aux_hpf(component, rx_priv, + event); + } + rx_macro_config_classh(component, rx_priv, + interp_idx, event); + } + rx_priv->main_clk_users[interp_idx]++; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + rx_priv->main_clk_users[interp_idx]--; + if (rx_priv->main_clk_users[interp_idx] <= 0) { + rx_priv->main_clk_users[interp_idx] = 0; + /* Main path PGA mute enable */ + snd_soc_component_update_bits(component, main_reg, + 0x10, 0x10); + /* Clk Disable */ + snd_soc_component_update_bits(component, dsm_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, main_reg, + 0x20, 0x00); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x00); + /* Reset rate to 48K*/ + snd_soc_component_update_bits(component, main_reg, + 0x0F, 0x04); + snd_soc_component_update_bits(component, rx_cfg2_reg, + 0x03, 0x00); + rx_macro_config_classh(component, rx_priv, + interp_idx, event); + rx_macro_config_compander(component, rx_priv, + interp_idx, event); + if (interp_idx == INTERP_AUX) { + rx_macro_config_softclip(component, rx_priv, + event); + rx_macro_config_aux_hpf(component, rx_priv, + event); + } + rx_macro_hphdelay_lutbypass(component, rx_priv, + interp_idx, event); + if (rx_priv->hph_hd2_mode) + rx_macro_hd2_control(component, interp_idx, + event); + rx_macro_idle_detect_control(component, rx_priv, + interp_idx, event); + } + } + + dev_dbg(component->dev, "%s event %d main_clk_users %d\n", + __func__, event, rx_priv->main_clk_users[interp_idx]); + + return rx_priv->main_clk_users[interp_idx]; +} + +static int rx_macro_enable_rx_path_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 sidetone_reg = 0, fs_reg = 0; + + dev_dbg(component->dev, "%s %d %d\n", __func__, event, w->shift); + sidetone_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG1 + + RX_MACRO_RX_PATH_OFFSET * (w->shift); + fs_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + + RX_MACRO_RX_PATH_OFFSET * (w->shift); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + rx_macro_enable_interp_clk(component, event, w->shift); + snd_soc_component_update_bits(component, sidetone_reg, + 0x10, 0x10); + snd_soc_component_update_bits(component, fs_reg, + 0x20, 0x20); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, sidetone_reg, + 0x10, 0x00); + rx_macro_enable_interp_clk(component, event, w->shift); + break; + default: + break; + }; + return 0; +} + +static void rx_macro_restore_iir_coeff(struct rx_macro_priv *rx_priv, int iir_idx, + int band_idx) +{ + u16 reg_add = 0, coeff_idx = 0, idx = 0; + struct regmap *regmap = dev_get_regmap(rx_priv->dev->parent, NULL); + + if (regmap == NULL) { + dev_err(rx_priv->dev, "%s: regmap is NULL\n", __func__); + return; + } + + regmap_write(regmap, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + reg_add = BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx; + + /* 5 coefficients per band and 4 writes per coefficient */ + for (coeff_idx = 0; coeff_idx < RX_MACRO_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + /* Four 8 bit values(one 32 bit) per coefficient */ + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + } +} + +static int rx_macro_iir_enable_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + /* IIR filter band registers are at integer multiples of 0x80 */ + u16 iir_reg = BOLERO_CDC_RX_SIDETONE_IIR0_IIR_CTL + 0x80 * iir_idx; + + ucontrol->value.integer.value[0] = ( + snd_soc_component_read(component, iir_reg) & + (1 << band_idx)) != 0; + + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0]); + return 0; +} + +static int rx_macro_iir_enable_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + bool iir_band_en_status = 0; + int value = ucontrol->value.integer.value[0]; + u16 iir_reg = BOLERO_CDC_RX_SIDETONE_IIR0_IIR_CTL + 0x80 * iir_idx; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_macro_restore_iir_coeff(rx_priv, iir_idx, band_idx); + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_component_update_bits(component, iir_reg, (1 << band_idx), + (value << band_idx)); + + iir_band_en_status = ((snd_soc_component_read(component, iir_reg) & + (1 << band_idx)) != 0); + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, iir_band_en_status); + return 0; +} + +static uint32_t get_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + int coeff_idx) +{ + uint32_t value = 0; + + /* Address does not automatically update if reading */ + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_component_read(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx)); + + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_component_read(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 0x80 * iir_idx)) << 8); + + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_component_read(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 0x80 * iir_idx)) << 16); + + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_component_read(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 0x80 * iir_idx)) & 0x3F) << 24); + + return value; +} + +static int rx_macro_iir_band_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = + get_iir_band_coeff(component, iir_idx, band_idx, 0); + ucontrol->value.integer.value[1] = + get_iir_band_coeff(component, iir_idx, band_idx, 1); + ucontrol->value.integer.value[2] = + get_iir_band_coeff(component, iir_idx, band_idx, 2); + ucontrol->value.integer.value[3] = + get_iir_band_coeff(component, iir_idx, band_idx, 3); + ucontrol->value.integer.value[4] = + get_iir_band_coeff(component, iir_idx, band_idx, 4); + + dev_dbg(component->dev, "%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[1], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[2], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[3], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[4]); + return 0; +} + +static void set_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + uint32_t value) +{ + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value & 0xFF)); + + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value >> 8) & 0xFF); + + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value >> 24) & 0x3F); +} + +static int rx_macro_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int coeff_idx, idx = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + /* + * Mask top bit it is reserved + * Updates addr automatically for each B2 write + */ + snd_soc_component_write(component, + (BOLERO_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + /* Store the coefficients in sidetone coeff array */ + for (coeff_idx = 0; coeff_idx < RX_MACRO_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + uint32_t value = ucontrol->value.integer.value[coeff_idx]; + + set_iir_band_coeff(component, iir_idx, band_idx, value); + + /* Four 8 bit values(one 32 bit) per coefficient */ + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value & 0xFF); + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 8) & 0xFF; + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 16) & 0xFF; + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 24) & 0xFF; + } + + pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 0), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 1), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 2), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 3), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 4)); + return 0; +} + +static int rx_macro_set_iir_gain(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: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: /* fall through */ + case SND_SOC_DAPM_PRE_PMD: + if (strnstr(w->name, "IIR0", sizeof("IIR0"))) { + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL)); + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL)); + } else { + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL)); + snd_soc_component_write(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, + snd_soc_component_read(component, + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL)); + } + break; + } + return 0; +} + +static const struct snd_kcontrol_new rx_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", + BOLERO_CDC_RX_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", + BOLERO_CDC_RX_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", + BOLERO_CDC_RX_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", + BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", + BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", + BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + + SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0, + rx_macro_get_compander, rx_macro_set_compander), + SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0, + rx_macro_get_compander, rx_macro_set_compander), + + SOC_ENUM_EXT("HPH Idle Detect", hph_idle_detect_enum, + rx_macro_hph_idle_detect_get, rx_macro_hph_idle_detect_put), + + SOC_ENUM_EXT("RX_EAR Mode", rx_macro_ear_mode_enum, + rx_macro_get_ear_mode, rx_macro_put_ear_mode), + + SOC_ENUM_EXT("RX_HPH HD2 Mode", rx_macro_hph_hd2_mode_enum, + rx_macro_get_hph_hd2_mode, rx_macro_put_hph_hd2_mode), + + SOC_ENUM_EXT("RX_HPH_PWR_MODE", rx_macro_hph_pwr_mode_enum, + rx_macro_get_hph_pwr_mode, rx_macro_put_hph_pwr_mode), + + SOC_ENUM_EXT("RX_GSM mode Enable", rx_macro_vbat_bcl_gsm_mode_enum, + rx_macro_vbat_bcl_gsm_mode_func_get, + rx_macro_vbat_bcl_gsm_mode_func_put), + SOC_SINGLE_EXT("RX_Softclip Enable", SND_SOC_NOPM, 0, 1, 0, + rx_macro_soft_clip_enable_get, + rx_macro_soft_clip_enable_put), + SOC_SINGLE_EXT("AUX_HPF Enable", SND_SOC_NOPM, 0, 1, 0, + rx_macro_aux_hpf_mode_get, + rx_macro_aux_hpf_mode_put), + + SOC_SINGLE_S8_TLV("IIR0 INP0 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP1 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP2 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP3 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP0 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40, + digital_gain), + + SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band2", IIR0, BAND2, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band3", IIR0, BAND3, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band4", IIR0, BAND4, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band5", IIR0, BAND5, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0, + rx_macro_iir_enable_audio_mixer_get, + rx_macro_iir_enable_audio_mixer_put), + + SOC_SINGLE_MULTI_EXT("IIR0 Band1", IIR0, BAND1, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band2", IIR0, BAND2, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band3", IIR0, BAND3, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band4", IIR0, BAND4, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band5", IIR0, BAND5, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5, + rx_macro_iir_band_audio_mixer_get, + rx_macro_iir_band_audio_mixer_put), +}; + +static int rx_macro_enable_echo(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 device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + u16 val = 0, ec_hq_reg = 0; + int ec_tx = 0; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(rx_dev, "%s %d %s\n", __func__, event, w->name); + + val = snd_soc_component_read(component, + BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG4); + if (!(strcmp(w->name, "RX MIX TX0 MUX"))) + ec_tx = ((val & 0xf0) >> 0x4) - 1; + else if (!(strcmp(w->name, "RX MIX TX1 MUX"))) + ec_tx = (val & 0x0f) - 1; + + val = snd_soc_component_read(component, + BOLERO_CDC_RX_INP_MUX_RX_MIX_CFG5); + if (!(strcmp(w->name, "RX MIX TX2 MUX"))) + ec_tx = (val & 0x0f) - 1; + + if (ec_tx < 0 || (ec_tx >= RX_MACRO_EC_MUX_MAX)) { + dev_err(rx_dev, "%s: EC mix control not set correctly\n", + __func__); + return -EINVAL; + } + ec_hq_reg = BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL + + 0x40 * ec_tx; + snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01); + ec_hq_reg = BOLERO_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0 + + 0x40 * ec_tx; + /* default set to 48k */ + snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08); + + return 0; +} + +static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX AIF1 PB", "RX_MACRO_AIF1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF2 PB", "RX_MACRO_AIF2 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF3 PB", "RX_MACRO_AIF3 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF4 PB", "RX_MACRO_AIF4 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("RX AIF_ECHO", "RX_AIF_ECHO Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF5 PB", "RX_MACRO_AIF5 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF6 PB", "RX_MACRO_AIF6 Playback", 0, + SND_SOC_NOPM, 0, 0), + + RX_MACRO_DAPM_MUX("RX_MACRO RX0 MUX", RX_MACRO_RX0, rx_macro_rx0), + RX_MACRO_DAPM_MUX("RX_MACRO RX1 MUX", RX_MACRO_RX1, rx_macro_rx1), + RX_MACRO_DAPM_MUX("RX_MACRO RX2 MUX", RX_MACRO_RX2, rx_macro_rx2), + RX_MACRO_DAPM_MUX("RX_MACRO RX3 MUX", RX_MACRO_RX3, rx_macro_rx3), + RX_MACRO_DAPM_MUX("RX_MACRO RX4 MUX", RX_MACRO_RX4, rx_macro_rx4), + RX_MACRO_DAPM_MUX("RX_MACRO RX5 MUX", RX_MACRO_RX5, rx_macro_rx5), + + SND_SOC_DAPM_MIXER("RX_RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + + RX_MACRO_DAPM_MUX("IIR0 INP0 MUX", 0, iir0_inp0), + RX_MACRO_DAPM_MUX("IIR0 INP1 MUX", 0, iir0_inp1), + RX_MACRO_DAPM_MUX("IIR0 INP2 MUX", 0, iir0_inp2), + RX_MACRO_DAPM_MUX("IIR0 INP3 MUX", 0, iir0_inp3), + RX_MACRO_DAPM_MUX("IIR1 INP0 MUX", 0, iir1_inp0), + RX_MACRO_DAPM_MUX("IIR1 INP1 MUX", 0, iir1_inp1), + RX_MACRO_DAPM_MUX("IIR1 INP2 MUX", 0, iir1_inp2), + RX_MACRO_DAPM_MUX("IIR1 INP3 MUX", 0, iir1_inp3), + + SND_SOC_DAPM_MUX_E("RX MIX TX0 MUX", SND_SOC_NOPM, + RX_MACRO_EC0_MUX, 0, + &rx_mix_tx0_mux, rx_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX MIX TX1 MUX", SND_SOC_NOPM, + RX_MACRO_EC1_MUX, 0, + &rx_mix_tx1_mux, rx_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX MIX TX2 MUX", SND_SOC_NOPM, + RX_MACRO_EC2_MUX, 0, + &rx_mix_tx2_mux, rx_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("IIR0", BOLERO_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL, + 4, 0, NULL, 0, rx_macro_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER_E("IIR1", BOLERO_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL, + 4, 0, NULL, 0, rx_macro_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER("SRC0", BOLERO_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SRC1", BOLERO_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + + RX_MACRO_DAPM_MUX("RX INT0 DEM MUX", 0, rx_int0_dem_inp), + RX_MACRO_DAPM_MUX("RX INT1 DEM MUX", 0, rx_int1_dem_inp), + + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int0_2_mux, rx_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int1_2_mux, rx_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", SND_SOC_NOPM, INTERP_AUX, 0, + &rx_int2_2_mux, rx_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + RX_MACRO_DAPM_MUX("RX INT0_1 MIX1 INP0", 0, rx_int0_1_mix_inp0), + RX_MACRO_DAPM_MUX("RX INT0_1 MIX1 INP1", 0, rx_int0_1_mix_inp1), + RX_MACRO_DAPM_MUX("RX INT0_1 MIX1 INP2", 0, rx_int0_1_mix_inp2), + RX_MACRO_DAPM_MUX("RX INT1_1 MIX1 INP0", 0, rx_int1_1_mix_inp0), + RX_MACRO_DAPM_MUX("RX INT1_1 MIX1 INP1", 0, rx_int1_1_mix_inp1), + RX_MACRO_DAPM_MUX("RX INT1_1 MIX1 INP2", 0, rx_int1_1_mix_inp2), + RX_MACRO_DAPM_MUX("RX INT2_1 MIX1 INP0", 0, rx_int2_1_mix_inp0), + RX_MACRO_DAPM_MUX("RX INT2_1 MIX1 INP1", 0, rx_int2_1_mix_inp1), + RX_MACRO_DAPM_MUX("RX INT2_1 MIX1 INP2", 0, rx_int2_1_mix_inp2), + + SND_SOC_DAPM_MUX_E("RX INT0_1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int0_1_interp_mux, rx_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1_1 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int1_1_interp_mux, rx_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2_1 INTERP", SND_SOC_NOPM, INTERP_AUX, 0, + &rx_int2_1_interp_mux, rx_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + RX_MACRO_DAPM_MUX("RX INT0_2 INTERP", 0, rx_int0_2_interp), + RX_MACRO_DAPM_MUX("RX INT1_2 INTERP", 0, rx_int1_2_interp), + RX_MACRO_DAPM_MUX("RX INT2_2 INTERP", 0, rx_int2_2_interp), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", SND_SOC_NOPM, INTERP_HPHL, + 0, &rx_int0_mix2_inp_mux, rx_macro_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", SND_SOC_NOPM, INTERP_HPHR, + 0, &rx_int1_mix2_inp_mux, rx_macro_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", SND_SOC_NOPM, INTERP_AUX, + 0, &rx_int2_mix2_inp_mux, rx_macro_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("RX INT2_1 VBAT", SND_SOC_NOPM, + 0, 0, rx_int2_1_vbat_mix_switch, + ARRAY_SIZE(rx_int2_1_vbat_mix_switch), + rx_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("HPHL_OUT"), + SND_SOC_DAPM_OUTPUT("HPHR_OUT"), + SND_SOC_DAPM_OUTPUT("AUX_OUT"), + SND_SOC_DAPM_OUTPUT("PCM_OUT"), + + SND_SOC_DAPM_INPUT("RX_TX DEC0_INP"), + SND_SOC_DAPM_INPUT("RX_TX DEC1_INP"), + SND_SOC_DAPM_INPUT("RX_TX DEC2_INP"), + SND_SOC_DAPM_INPUT("RX_TX DEC3_INP"), + + SND_SOC_DAPM_SUPPLY_S("RX_MCLK", 0, SND_SOC_NOPM, 0, 0, + rx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route rx_audio_map[] = { + {"RX AIF1 PB", NULL, "RX_MCLK"}, + {"RX AIF2 PB", NULL, "RX_MCLK"}, + {"RX AIF3 PB", NULL, "RX_MCLK"}, + {"RX AIF4 PB", NULL, "RX_MCLK"}, + + {"RX AIF6 PB", NULL, "RX_MCLK"}, + {"PCM_OUT", NULL, "RX AIF6 PB"}, + + {"RX_MACRO RX0 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX1 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX2 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX3 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX4 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX5 MUX", "AIF1_PB", "RX AIF1 PB"}, + + {"RX_MACRO RX0 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX1 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX2 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX3 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX4 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX5 MUX", "AIF2_PB", "RX AIF2 PB"}, + + {"RX_MACRO RX0 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX1 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX2 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX3 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX4 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX5 MUX", "AIF3_PB", "RX AIF3 PB"}, + + {"RX_MACRO RX0 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX1 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX2 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX3 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX4 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX5 MUX", "AIF4_PB", "RX AIF4 PB"}, + + {"RX_RX0", NULL, "RX_MACRO RX0 MUX"}, + {"RX_RX1", NULL, "RX_MACRO RX1 MUX"}, + {"RX_RX2", NULL, "RX_MACRO RX2 MUX"}, + {"RX_RX3", NULL, "RX_MACRO RX3 MUX"}, + {"RX_RX4", NULL, "RX_MACRO RX4 MUX"}, + {"RX_RX5", NULL, "RX_MACRO RX5 MUX"}, + + {"RX INT0_1 MIX1 INP0", "RX0", "RX_RX0"}, + {"RX INT0_1 MIX1 INP0", "RX1", "RX_RX1"}, + {"RX INT0_1 MIX1 INP0", "RX2", "RX_RX2"}, + {"RX INT0_1 MIX1 INP0", "RX3", "RX_RX3"}, + {"RX INT0_1 MIX1 INP0", "RX4", "RX_RX4"}, + {"RX INT0_1 MIX1 INP0", "RX5", "RX_RX5"}, + {"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT0_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT0_1 MIX1 INP1", "RX0", "RX_RX0"}, + {"RX INT0_1 MIX1 INP1", "RX1", "RX_RX1"}, + {"RX INT0_1 MIX1 INP1", "RX2", "RX_RX2"}, + {"RX INT0_1 MIX1 INP1", "RX3", "RX_RX3"}, + {"RX INT0_1 MIX1 INP1", "RX4", "RX_RX4"}, + {"RX INT0_1 MIX1 INP1", "RX5", "RX_RX5"}, + {"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT0_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT0_1 MIX1 INP2", "RX0", "RX_RX0"}, + {"RX INT0_1 MIX1 INP2", "RX1", "RX_RX1"}, + {"RX INT0_1 MIX1 INP2", "RX2", "RX_RX2"}, + {"RX INT0_1 MIX1 INP2", "RX3", "RX_RX3"}, + {"RX INT0_1 MIX1 INP2", "RX4", "RX_RX4"}, + {"RX INT0_1 MIX1 INP2", "RX5", "RX_RX5"}, + {"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT0_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"}, + + {"RX INT1_1 MIX1 INP0", "RX0", "RX_RX0"}, + {"RX INT1_1 MIX1 INP0", "RX1", "RX_RX1"}, + {"RX INT1_1 MIX1 INP0", "RX2", "RX_RX2"}, + {"RX INT1_1 MIX1 INP0", "RX3", "RX_RX3"}, + {"RX INT1_1 MIX1 INP0", "RX4", "RX_RX4"}, + {"RX INT1_1 MIX1 INP0", "RX5", "RX_RX5"}, + {"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT1_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT1_1 MIX1 INP1", "RX0", "RX_RX0"}, + {"RX INT1_1 MIX1 INP1", "RX1", "RX_RX1"}, + {"RX INT1_1 MIX1 INP1", "RX2", "RX_RX2"}, + {"RX INT1_1 MIX1 INP1", "RX3", "RX_RX3"}, + {"RX INT1_1 MIX1 INP1", "RX4", "RX_RX4"}, + {"RX INT1_1 MIX1 INP1", "RX5", "RX_RX5"}, + {"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT1_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT1_1 MIX1 INP2", "RX0", "RX_RX0"}, + {"RX INT1_1 MIX1 INP2", "RX1", "RX_RX1"}, + {"RX INT1_1 MIX1 INP2", "RX2", "RX_RX2"}, + {"RX INT1_1 MIX1 INP2", "RX3", "RX_RX3"}, + {"RX INT1_1 MIX1 INP2", "RX4", "RX_RX4"}, + {"RX INT1_1 MIX1 INP2", "RX5", "RX_RX5"}, + {"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT1_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"}, + + {"RX INT2_1 MIX1 INP0", "RX0", "RX_RX0"}, + {"RX INT2_1 MIX1 INP0", "RX1", "RX_RX1"}, + {"RX INT2_1 MIX1 INP0", "RX2", "RX_RX2"}, + {"RX INT2_1 MIX1 INP0", "RX3", "RX_RX3"}, + {"RX INT2_1 MIX1 INP0", "RX4", "RX_RX4"}, + {"RX INT2_1 MIX1 INP0", "RX5", "RX_RX5"}, + {"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT2_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT2_1 MIX1 INP1", "RX0", "RX_RX0"}, + {"RX INT2_1 MIX1 INP1", "RX1", "RX_RX1"}, + {"RX INT2_1 MIX1 INP1", "RX2", "RX_RX2"}, + {"RX INT2_1 MIX1 INP1", "RX3", "RX_RX3"}, + {"RX INT2_1 MIX1 INP1", "RX4", "RX_RX4"}, + {"RX INT2_1 MIX1 INP1", "RX5", "RX_RX5"}, + {"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT2_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT2_1 MIX1 INP2", "RX0", "RX_RX0"}, + {"RX INT2_1 MIX1 INP2", "RX1", "RX_RX1"}, + {"RX INT2_1 MIX1 INP2", "RX2", "RX_RX2"}, + {"RX INT2_1 MIX1 INP2", "RX3", "RX_RX3"}, + {"RX INT2_1 MIX1 INP2", "RX4", "RX_RX4"}, + {"RX INT2_1 MIX1 INP2", "RX5", "RX_RX5"}, + {"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT2_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"}, + + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"}, + + {"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX AIF_ECHO", NULL, "RX MIX TX0 MUX"}, + {"RX AIF_ECHO", NULL, "RX MIX TX1 MUX"}, + {"RX AIF_ECHO", NULL, "RX MIX TX2 MUX"}, + {"RX AIF_ECHO", NULL, "RX_MCLK"}, + + /* Mixing path INT0 */ + {"RX INT0_2 MUX", "RX0", "RX_RX0"}, + {"RX INT0_2 MUX", "RX1", "RX_RX1"}, + {"RX INT0_2 MUX", "RX2", "RX_RX2"}, + {"RX INT0_2 MUX", "RX3", "RX_RX3"}, + {"RX INT0_2 MUX", "RX4", "RX_RX4"}, + {"RX INT0_2 MUX", "RX5", "RX_RX5"}, + {"RX INT0_2 INTERP", NULL, "RX INT0_2 MUX"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_2 INTERP"}, + + /* Mixing path INT1 */ + {"RX INT1_2 MUX", "RX0", "RX_RX0"}, + {"RX INT1_2 MUX", "RX1", "RX_RX1"}, + {"RX INT1_2 MUX", "RX2", "RX_RX2"}, + {"RX INT1_2 MUX", "RX3", "RX_RX3"}, + {"RX INT1_2 MUX", "RX4", "RX_RX4"}, + {"RX INT1_2 MUX", "RX5", "RX_RX5"}, + {"RX INT1_2 INTERP", NULL, "RX INT1_2 MUX"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_2 INTERP"}, + + /* Mixing path INT2 */ + {"RX INT2_2 MUX", "RX0", "RX_RX0"}, + {"RX INT2_2 MUX", "RX1", "RX_RX1"}, + {"RX INT2_2 MUX", "RX2", "RX_RX2"}, + {"RX INT2_2 MUX", "RX3", "RX_RX3"}, + {"RX INT2_2 MUX", "RX4", "RX_RX4"}, + {"RX INT2_2 MUX", "RX5", "RX_RX5"}, + {"RX INT2_2 INTERP", NULL, "RX INT2_2 MUX"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_2 INTERP"}, + + {"RX INT0_1 INTERP", NULL, "RX INT0_1 MIX1"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_1 INTERP"}, + {"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"}, + {"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"}, + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 MIX2"}, + {"HPHL_OUT", NULL, "RX INT0 DEM MUX"}, + {"HPHL_OUT", NULL, "RX_MCLK"}, + + {"RX INT1_1 INTERP", NULL, "RX INT1_1 MIX1"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_1 INTERP"}, + {"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"}, + {"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"}, + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 MIX2"}, + {"HPHR_OUT", NULL, "RX INT1 DEM MUX"}, + {"HPHR_OUT", NULL, "RX_MCLK"}, + + {"RX INT2_1 INTERP", NULL, "RX INT2_1 MIX1"}, + + {"RX INT2_1 VBAT", "RX AUX VBAT Enable", "RX INT2_1 INTERP"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_1 VBAT"}, + + {"RX INT2 SEC MIX", NULL, "RX INT2_1 INTERP"}, + {"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"}, + {"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"}, + {"AUX_OUT", NULL, "RX INT2 MIX2"}, + {"AUX_OUT", NULL, "RX_MCLK"}, + + {"IIR0", NULL, "RX_MCLK"}, + {"IIR0", NULL, "IIR0 INP0 MUX"}, + {"IIR0 INP0 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP0 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP0 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP0 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP0 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP0 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP0 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP0 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP0 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP0 MUX", "RX5", "RX_RX5"}, + {"IIR0", NULL, "IIR0 INP1 MUX"}, + {"IIR0 INP1 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP1 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP1 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP1 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP1 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP1 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP1 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP1 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP1 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP1 MUX", "RX5", "RX_RX5"}, + {"IIR0", NULL, "IIR0 INP2 MUX"}, + {"IIR0 INP2 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP2 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP2 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP2 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP2 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP2 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP2 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP2 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP2 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP2 MUX", "RX5", "RX_RX5"}, + {"IIR0", NULL, "IIR0 INP3 MUX"}, + {"IIR0 INP3 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP3 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP3 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP3 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP3 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP3 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP3 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP3 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP3 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP3 MUX", "RX5", "RX_RX5"}, + + {"IIR1", NULL, "RX_MCLK"}, + {"IIR1", NULL, "IIR1 INP0 MUX"}, + {"IIR1 INP0 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP0 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP0 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP0 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP0 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP0 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP0 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP0 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP0 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP0 MUX", "RX5", "RX_RX5"}, + {"IIR1", NULL, "IIR1 INP1 MUX"}, + {"IIR1 INP1 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP1 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP1 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP1 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP1 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP1 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP1 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP1 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP1 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP1 MUX", "RX5", "RX_RX5"}, + {"IIR1", NULL, "IIR1 INP2 MUX"}, + {"IIR1 INP2 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP2 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP2 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP2 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP2 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP2 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP2 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP2 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP2 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP2 MUX", "RX5", "RX_RX5"}, + {"IIR1", NULL, "IIR1 INP3 MUX"}, + {"IIR1 INP3 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP3 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP3 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP3 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP3 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP3 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP3 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP3 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP3 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP3 MUX", "RX5", "RX_RX5"}, + + {"SRC0", NULL, "IIR0"}, + {"SRC1", NULL, "IIR1"}, + {"RX INT0 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT0 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT1 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT1 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT2 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT2 MIX2 INP", "SRC1", "SRC1"}, +}; + +static int rx_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle; + + if (rx_priv == NULL) { + pr_err("%s: rx priv data is NULL\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(rx_priv->dev); + if (bolero_check_core_votes(rx_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(rx_priv->dev); + pm_runtime_mark_last_busy(rx_priv->dev); + } + return rc; +} + +static int rx_swrm_clock(void *handle, bool enable) +{ + struct rx_macro_priv *rx_priv = (struct rx_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(rx_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(rx_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&rx_priv->swr_clk_lock); + + dev_dbg(rx_priv->dev, "%s: swrm clock %s\n", + __func__, (enable ? "enable" : "disable")); + if (enable) { + pm_runtime_get_sync(rx_priv->dev); + if (rx_priv->swr_clk_users == 0) { + ret = msm_cdc_pinctrl_select_active_state( + rx_priv->rx_swr_gpio_p); + if (ret < 0) { + dev_err(rx_priv->dev, + "%s: rx swr pinctrl enable failed\n", + __func__); + pm_runtime_mark_last_busy(rx_priv->dev); + pm_runtime_put_autosuspend(rx_priv->dev); + goto exit; + } + ret = rx_macro_mclk_enable(rx_priv, 1, true); + if (ret < 0) { + msm_cdc_pinctrl_select_sleep_state( + rx_priv->rx_swr_gpio_p); + dev_err(rx_priv->dev, + "%s: rx request clock enable failed\n", + __func__); + pm_runtime_mark_last_busy(rx_priv->dev); + pm_runtime_put_autosuspend(rx_priv->dev); + goto exit; + } + if (rx_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (rx_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + rx_priv->reset_swr = false; + } + pm_runtime_mark_last_busy(rx_priv->dev); + pm_runtime_put_autosuspend(rx_priv->dev); + rx_priv->swr_clk_users++; + } else { + if (rx_priv->swr_clk_users <= 0) { + dev_err(rx_priv->dev, + "%s: rx swrm clock users already reset\n", + __func__); + rx_priv->swr_clk_users = 0; + goto exit; + } + rx_priv->swr_clk_users--; + if (rx_priv->swr_clk_users == 0) { + regmap_update_bits(regmap, + BOLERO_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + rx_macro_mclk_enable(rx_priv, 0, true); + ret = msm_cdc_pinctrl_select_sleep_state( + rx_priv->rx_swr_gpio_p); + if (ret < 0) { + dev_err(rx_priv->dev, + "%s: rx swr pinctrl disable failed\n", + __func__); + goto exit; + } + } + } + dev_dbg(rx_priv->dev, "%s: swrm clock users %d\n", + __func__, rx_priv->swr_clk_users); +exit: + mutex_unlock(&rx_priv->swr_clk_lock); + return ret; +} + +static const struct rx_macro_reg_mask_val rx_macro_reg_init[] = { + {BOLERO_CDC_RX_RX0_RX_PATH_SEC7, 0x07, 0x02}, + {BOLERO_CDC_RX_RX1_RX_PATH_SEC7, 0x07, 0x02}, + {BOLERO_CDC_RX_RX2_RX_PATH_SEC7, 0x07, 0x02}, + {BOLERO_CDC_RX_RX0_RX_PATH_CFG3, 0x03, 0x02}, + {BOLERO_CDC_RX_RX1_RX_PATH_CFG3, 0x03, 0x02}, + {BOLERO_CDC_RX_RX2_RX_PATH_CFG3, 0x03, 0x02}, +}; + +static void rx_macro_init_bcl_pmic_reg(struct snd_soc_component *component) +{ + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err("%s: NULL component pointer!\n", __func__); + return; + } + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return; + + switch (rx_priv->bcl_pmic_params.id) { + case 0: + /* Enable ID0 to listen to respective PMIC group interrupts */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL1, 0x02, 0x02); + /* Update MC_SID0 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG1, 0x0F, + rx_priv->bcl_pmic_params.sid); + /* Update MC_PPID0 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG2, 0xFF, + rx_priv->bcl_pmic_params.ppid); + break; + case 1: + /* Enable ID1 to listen to respective PMIC group interrupts */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_DECODE_CTL1, 0x01, 0x01); + /* Update MC_SID1 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG3, 0x0F, + rx_priv->bcl_pmic_params.sid); + /* Update MC_PPID1 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_BCL_VBAT_DECODE_CFG1, 0xFF, + rx_priv->bcl_pmic_params.ppid); + break; + default: + dev_err(rx_dev, "%s: PMIC ID is invalid %d\n", + __func__, rx_priv->bcl_pmic_params.id); + break; + } +} + +static int rx_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = 0; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + int i; + + rx_dev = bolero_get_device_ptr(component->dev, RX_MACRO); + if (!rx_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + rx_priv = dev_get_drvdata(rx_dev); + if (!rx_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + + ret = snd_soc_dapm_new_controls(dapm, rx_macro_dapm_widgets, + ARRAY_SIZE(rx_macro_dapm_widgets)); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add controls\n", __func__); + return ret; + } + ret = snd_soc_dapm_add_routes(dapm, rx_audio_map, + ARRAY_SIZE(rx_audio_map)); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add routes\n", __func__); + return ret; + } + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add widgets\n", __func__); + return ret; + } + ret = snd_soc_add_component_controls(component, rx_macro_snd_controls, + ARRAY_SIZE(rx_macro_snd_controls)); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add snd_ctls\n", __func__); + return ret; + } + rx_priv->dev_up = true; + rx_priv->rx0_gain_val = 0; + rx_priv->rx1_gain_val = 0; + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF2 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF3 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF4 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF5 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF6 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "AUX_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "PCM_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC1_INP"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC2_INP"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC3_INP"); + snd_soc_dapm_sync(dapm); + + for (i = 0; i < ARRAY_SIZE(rx_macro_reg_init); i++) + snd_soc_component_update_bits(component, + rx_macro_reg_init[i].reg, + rx_macro_reg_init[i].mask, + rx_macro_reg_init[i].val); + + rx_priv->component = component; + rx_macro_init_bcl_pmic_reg(component); + + return 0; +} + +static int rx_macro_deinit(struct snd_soc_component *component) +{ + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->component = NULL; + + return 0; +} + +static void rx_macro_add_child_devices(struct work_struct *work) +{ + struct rx_macro_priv *rx_priv = NULL; + struct platform_device *pdev = NULL; + struct device_node *node = NULL; + struct rx_swr_ctrl_data *swr_ctrl_data = NULL, *temp = NULL; + int ret = 0; + u16 count = 0, ctrl_num = 0; + struct rx_swr_ctrl_platform_data *platdata = NULL; + char plat_dev_name[RX_SWR_STRING_LEN] = ""; + bool rx_swr_master_node = false; + + rx_priv = container_of(work, struct rx_macro_priv, + rx_macro_add_child_devices_work); + if (!rx_priv) { + pr_err("%s: Memory for rx_priv does not exist\n", + __func__); + return; + } + + if (!rx_priv->dev) { + pr_err("%s: RX device does not exist\n", __func__); + return; + } + + if(!rx_priv->dev->of_node) { + dev_err(rx_priv->dev, + "%s: DT node for RX dev does not exist\n", __func__); + return; + } + + platdata = &rx_priv->swr_plat_data; + rx_priv->child_count = 0; + + for_each_available_child_of_node(rx_priv->dev->of_node, node) { + rx_swr_master_node = false; + if (strnstr(node->name, "rx_swr_master", + strlen("rx_swr_master")) != NULL) + rx_swr_master_node = true; + + if(rx_swr_master_node) + strlcpy(plat_dev_name, "rx_swr_ctrl", + (RX_SWR_STRING_LEN - 1)); + else + strlcpy(plat_dev_name, node->name, + (RX_SWR_STRING_LEN - 1)); + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(rx_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = rx_priv->dev; + pdev->dev.of_node = node; + + if (rx_swr_master_node) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct rx_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].rx_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + rx_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (rx_priv->child_count < RX_MACRO_CHILD_DEVICES_MAX) + rx_priv->pdev_child_devices[ + rx_priv->child_count++] = pdev; + else + goto err; + } + return; +fail_pdev_add: + for (count = 0; count < rx_priv->child_count; count++) + platform_device_put(rx_priv->pdev_child_devices[count]); +err: + return; +} + +static void rx_macro_init_ops(struct macro_ops *ops, char __iomem *rx_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->init = rx_macro_init; + ops->exit = rx_macro_deinit; + ops->io_base = rx_io_base; + ops->dai_ptr = rx_macro_dai; + ops->num_dais = ARRAY_SIZE(rx_macro_dai); + ops->event_handler = rx_macro_event_handler; + ops->set_port_map = rx_macro_set_port_map; +} + +static int rx_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops = {0}; + struct rx_macro_priv *rx_priv = NULL; + u32 rx_base_addr = 0, muxsel = 0; + char __iomem *rx_io_base = NULL, *muxsel_io = NULL; + int ret = 0, val = 0; + u8 bcl_pmic_params[3]; + u32 default_clk_id = 0; + u32 is_used_rx_swr_gpio = 1; + const char *is_used_rx_swr_gpio_dt = "qcom,is-used-swr-gpio"; + + if (!bolero_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + + rx_priv = devm_kzalloc(&pdev->dev, sizeof(struct rx_macro_priv), + GFP_KERNEL); + if (!rx_priv) + return -ENOMEM; + + rx_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &rx_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, "qcom,rx_mclk_mode_muxsel", + &muxsel); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,rx-wsa-enable", &val); + if (ret == 0) { + rx_priv->rx_macro_wsa_slv = (val == 1) ? 1 : 0; + dev_info(&pdev->dev, "RX macro wsa slave is %s\n", + (val == 1) ? "connected" : "not connected"); + } + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id", + &default_clk_id); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,default-clk-id"); + default_clk_id = RX_CORE_CLK; + } + if (of_find_property(pdev->dev.of_node, is_used_rx_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_rx_swr_gpio_dt, + &is_used_rx_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_rx_swr_gpio_dt); + is_used_rx_swr_gpio = 1; + } + } + rx_priv->rx_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,rx-swr-gpios", 0); + if (!rx_priv->rx_swr_gpio_p && is_used_rx_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if (msm_cdc_pinctrl_get_state(rx_priv->rx_swr_gpio_p) < 0 && + is_used_rx_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + msm_cdc_pinctrl_set_wakeup_capable( + rx_priv->rx_swr_gpio_p, false); + + rx_io_base = devm_ioremap(&pdev->dev, rx_base_addr, + RX_MACRO_MAX_OFFSET); + if (!rx_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -ENOMEM; + } + rx_priv->rx_io_base = rx_io_base; + muxsel_io = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!muxsel_io) { + dev_err(&pdev->dev, "%s: ioremap failed for muxsel\n", + __func__); + return -ENOMEM; + } + rx_priv->rx_mclk_mode_muxsel = muxsel_io; + rx_priv->reset_swr = true; + INIT_WORK(&rx_priv->rx_macro_add_child_devices_work, + rx_macro_add_child_devices); + rx_priv->swr_plat_data.handle = (void *) rx_priv; + rx_priv->swr_plat_data.read = NULL; + rx_priv->swr_plat_data.write = NULL; + rx_priv->swr_plat_data.bulk_write = NULL; + rx_priv->swr_plat_data.clk = rx_swrm_clock; + rx_priv->swr_plat_data.core_vote = rx_macro_core_vote; + rx_priv->swr_plat_data.handle_irq = NULL; + + ret = of_property_read_u8_array(pdev->dev.of_node, + "qcom,rx-bcl-pmic-params", bcl_pmic_params, + sizeof(bcl_pmic_params)); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,rx-bcl-pmic-params"); + } else { + rx_priv->bcl_pmic_params.id = bcl_pmic_params[0]; + rx_priv->bcl_pmic_params.sid = bcl_pmic_params[1]; + rx_priv->bcl_pmic_params.ppid = bcl_pmic_params[2]; + } + rx_priv->clk_id = default_clk_id; + rx_priv->default_clk_id = default_clk_id; + ops.clk_id_req = rx_priv->clk_id; + ops.default_clk_id = default_clk_id; + + rx_priv->is_aux_hpf_on = 1; + + dev_set_drvdata(&pdev->dev, rx_priv); + mutex_init(&rx_priv->mclk_lock); + mutex_init(&rx_priv->swr_clk_lock); + rx_macro_init_ops(&ops, rx_io_base); + + ret = bolero_register_macro(&pdev->dev, RX_MACRO, &ops); + if (ret) { + dev_err(&pdev->dev, + "%s: register macro failed\n", __func__); + goto err_reg_macro; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + schedule_work(&rx_priv->rx_macro_add_child_devices_work); + return 0; + +err_reg_macro: + mutex_destroy(&rx_priv->mclk_lock); + mutex_destroy(&rx_priv->swr_clk_lock); + return ret; +} + +static int rx_macro_remove(struct platform_device *pdev) +{ + struct rx_macro_priv *rx_priv = NULL; + u16 count = 0; + + rx_priv = dev_get_drvdata(&pdev->dev); + + if (!rx_priv) + return -EINVAL; + + for (count = 0; count < rx_priv->child_count && + count < RX_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister(rx_priv->pdev_child_devices[count]); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + bolero_unregister_macro(&pdev->dev, RX_MACRO); + mutex_destroy(&rx_priv->mclk_lock); + mutex_destroy(&rx_priv->swr_clk_lock); + kfree(rx_priv->swr_ctrl_data); + return 0; +} + +static const struct of_device_id rx_macro_dt_match[] = { + {.compatible = "qcom,rx-macro"}, + {} +}; + +static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + bolero_runtime_suspend, + bolero_runtime_resume, + NULL + ) +}; + +static struct platform_driver rx_macro_driver = { + .driver = { + .name = "rx_macro", + .owner = THIS_MODULE, + .pm = &bolero_dev_pm_ops, + .of_match_table = rx_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = rx_macro_probe, + .remove = rx_macro_remove, +}; + +module_platform_driver(rx_macro_driver); + +MODULE_DESCRIPTION("RX macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/tx-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/tx-macro.c new file mode 100644 index 0000000000..a619642274 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/tx-macro.c @@ -0,0 +1,3807 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bolero-cdc.h" +#include "bolero-cdc-registers.h" +#include "bolero-clk-rsc.h" + +#define AUTO_SUSPEND_DELAY 50 /* delay in msec */ +#define TX_MACRO_MAX_OFFSET 0x1000 + +#define NUM_DECIMATORS 8 + +#define TX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define TX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED 0 +#define TX_MACRO_MCLK_FREQ 9600000 +#define TX_MACRO_TX_PATH_OFFSET 0x80 +#define TX_MACRO_SWR_MIC_MUX_SEL_MASK 0xF +#define TX_MACRO_ADC_MUX_CFG_OFFSET 0x8 +#define TX_MACRO_ADC_MODE_CFG0_SHIFT 1 + +#define TX_MACRO_DMIC_UNMUTE_DELAY_MS 40 +#define TX_MACRO_AMIC_UNMUTE_DELAY_MS 100 +#define TX_MACRO_DMIC_HPF_DELAY_MS 300 +#define TX_MACRO_AMIC_HPF_DELAY_MS 300 + +static int tx_unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS; +module_param(tx_unmute_delay, int, 0664); +MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path"); + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +static int tx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +static int tx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); + +#define TX_MACRO_SWR_STRING_LEN 80 +#define TX_MACRO_CHILD_DEVICES_MAX 3 + +/* Hold instance to soundwire platform device */ +struct tx_macro_swr_ctrl_data { + struct platform_device *tx_swr_pdev; +}; + +struct tx_macro_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +enum { + TX_MACRO_AIF_INVALID = 0, + TX_MACRO_AIF1_CAP, + TX_MACRO_AIF2_CAP, + TX_MACRO_AIF3_CAP, + TX_MACRO_MAX_DAIS +}; + +enum { + TX_MACRO_DEC0, + TX_MACRO_DEC1, + TX_MACRO_DEC2, + TX_MACRO_DEC3, + TX_MACRO_DEC4, + TX_MACRO_DEC5, + TX_MACRO_DEC6, + TX_MACRO_DEC7, + TX_MACRO_DEC_MAX, +}; + +enum { + TX_MACRO_CLK_DIV_2, + TX_MACRO_CLK_DIV_3, + TX_MACRO_CLK_DIV_4, + TX_MACRO_CLK_DIV_6, + TX_MACRO_CLK_DIV_8, + TX_MACRO_CLK_DIV_16, +}; + +enum { + MSM_DMIC, + SWR_MIC, + ANC_FB_TUNE1 +}; + +enum { + TX_MCLK, + VA_MCLK, +}; + +struct tx_macro_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +struct tx_mute_work { + struct tx_macro_priv *tx_priv; + u32 decimator; + struct delayed_work dwork; +}; + +struct hpf_work { + struct tx_macro_priv *tx_priv; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +struct tx_macro_priv { + struct device *dev; + bool dec_active[NUM_DECIMATORS]; + int tx_mclk_users; + int swr_clk_users; + bool dapm_mclk_enable; + bool reset_swr; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct snd_soc_component *component; + struct device_node *tx_swr_gpio_p; + struct tx_macro_swr_ctrl_data *swr_ctrl_data; + struct tx_macro_swr_ctrl_platform_data swr_plat_data; + struct work_struct tx_macro_add_child_devices_work; + struct hpf_work tx_hpf_work[NUM_DECIMATORS]; + struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS]; + u16 dmic_clk_div; + u32 version; + u32 is_used_tx_swr_gpio; + unsigned long active_ch_mask[TX_MACRO_MAX_DAIS]; + char __iomem *tx_io_base; + struct platform_device *pdev_child_devices + [TX_MACRO_CHILD_DEVICES_MAX]; + int child_count; + int tx_swr_clk_cnt; + int va_swr_clk_cnt; + int va_clk_status; + int tx_clk_status; + bool bcs_enable; + int dec_mode[NUM_DECIMATORS]; + int bcs_ch; + bool bcs_clk_en; + bool hs_slow_insert_complete; + int pcm_rate[NUM_DECIMATORS]; + bool lpi_enable; + bool register_event_listener; + u16 current_clk_id; + int disable_afe_wakeup_event_listener; +}; + +static bool tx_macro_get_data(struct snd_soc_component *component, + struct device **tx_dev, + struct tx_macro_priv **tx_priv, + const char *func_name) +{ + *tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO); + if (!(*tx_dev)) { + dev_err(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + + *tx_priv = dev_get_drvdata((*tx_dev)); + if (!(*tx_priv)) { + dev_err(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + + if (!(*tx_priv)->component) { + dev_err(component->dev, + "%s: tx_priv->component not initialized!\n", func_name); + return false; + } + + return true; +} + +static int tx_macro_mclk_enable(struct tx_macro_priv *tx_priv, + bool mclk_enable) +{ + struct regmap *regmap = dev_get_regmap(tx_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(tx_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(tx_priv->dev, "%s: mclk_enable = %u,clk_users= %d\n", + __func__, mclk_enable, tx_priv->tx_mclk_users); + + mutex_lock(&tx_priv->mclk_lock); + if (mclk_enable) { + ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + if (ret < 0) { + dev_err_ratelimited(tx_priv->dev, + "%s: request clock enable failed\n", + __func__); + goto exit; + } + bolero_clk_rsc_fs_gen_request(tx_priv->dev, + true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + TX_START_OFFSET, + TX_MAX_OFFSET); + if (tx_priv->tx_mclk_users == 0) { + /* 9.6MHz MCLK, set value 0x00 if other frequency */ + regmap_update_bits(regmap, + BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK, 0x01, 0x01); + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + tx_priv->tx_mclk_users++; + } else { + if (tx_priv->tx_mclk_users <= 0) { + dev_err(tx_priv->dev, "%s: clock already disabled\n", + __func__); + tx_priv->tx_mclk_users = 0; + goto exit; + } + tx_priv->tx_mclk_users--; + if (tx_priv->tx_mclk_users == 0) { + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + } + + bolero_clk_rsc_fs_gen_request(tx_priv->dev, + false); + bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + } +exit: + mutex_unlock(&tx_priv->mclk_lock); + return ret; +} + +static int __tx_macro_mclk_enable(struct snd_soc_component *component, + bool enable) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + return tx_macro_mclk_enable(tx_priv, enable); +} + +static int tx_macro_va_swr_clk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (SND_SOC_DAPM_EVENT_ON(event)) + ++tx_priv->va_swr_clk_cnt; + if (SND_SOC_DAPM_EVENT_OFF(event)) + --tx_priv->va_swr_clk_cnt; + + return 0; +} + +static int tx_macro_tx_swr_clk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (SND_SOC_DAPM_EVENT_ON(event)) + ++tx_priv->tx_swr_clk_cnt; + if (SND_SOC_DAPM_EVENT_OFF(event)) + --tx_priv->tx_swr_clk_cnt; + + return 0; +} + +static int tx_macro_swr_pwr_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); + int ret = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + dev_dbg(tx_dev, "%s: event = %d, lpi_enable = %d\n", + __func__, event, tx_priv->lpi_enable); + + if (!tx_priv->lpi_enable) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tx_priv->lpi_enable) { + bolero_register_event_listener(component, true); + tx_priv->register_event_listener = true; + } + break; + case SND_SOC_DAPM_POST_PMD: + if (tx_priv->register_event_listener) { + tx_priv->register_event_listener = false; + bolero_register_event_listener(component, false); + } + break; + default: + dev_err(tx_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int tx_macro_mclk_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); + int ret = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + dev_dbg(tx_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = tx_macro_mclk_enable(tx_priv, 1); + if (ret) + tx_priv->dapm_mclk_enable = false; + else + tx_priv->dapm_mclk_enable = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (tx_priv->dapm_mclk_enable) + ret = tx_macro_mclk_enable(tx_priv, 0); + break; + default: + dev_err(tx_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int tx_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + int ret = 0; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + switch (event) { + case BOLERO_MACRO_EVT_SSR_DOWN: + if (tx_priv->swr_ctrl_data) { + swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(tx_dev) || + !pm_runtime_suspended(tx_dev))) { + ret = bolero_runtime_suspend(tx_dev); + if (!ret) { + pm_runtime_disable(tx_dev); + pm_runtime_set_suspended(tx_dev); + pm_runtime_enable(tx_dev); + } + } + break; + case BOLERO_MACRO_EVT_SSR_UP: + /* reset swr after ssr/pdr */ + tx_priv->reset_swr = true; + if (tx_priv->swr_ctrl_data) + swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case BOLERO_MACRO_EVT_CLK_RESET: + bolero_rsc_clk_reset(tx_dev, TX_CORE_CLK); + break; + case BOLERO_MACRO_EVT_BCS_CLK_OFF: + if (tx_priv->bcs_clk_en) + snd_soc_component_update_bits(component, + BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40, data << 6); + if (data) + tx_priv->hs_slow_insert_complete = true; + else + tx_priv->hs_slow_insert_complete = false; + break; + default: + pr_debug("%s Invalid Event\n", __func__); + break; + } + return 0; +} + +static int tx_macro_reg_wake_irq(struct snd_soc_component *component, + u32 data) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + u32 ipc_wakeup = data; + int ret = 0; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (tx_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_REGISTER_WAKE_IRQ, &ipc_wakeup); + + return ret; +} + +static bool is_amic_enabled(struct snd_soc_component *component, int decimator) +{ + u16 adc_mux_reg = 0, adc_reg = 0; + u16 adc_n = BOLERO_ADC_MAX; + bool ret = false; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return ret; + + adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) { + if (tx_priv->version == BOLERO_VERSION_2_1) + return true; + adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + adc_n = snd_soc_component_read(component, adc_reg) & + TX_MACRO_SWR_MIC_MUX_SEL_MASK; + if (adc_n < BOLERO_ADC_MAX) + return true; + } + + return ret; +} + +static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work = NULL; + struct hpf_work *hpf_work = NULL; + struct tx_macro_priv *tx_priv = NULL; + struct snd_soc_component *component = NULL; + u16 dec_cfg_reg = 0, hpf_gate_reg = 0; + u8 hpf_cut_off_freq = 0; + u16 adc_reg = 0, adc_n = 0; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + tx_priv = hpf_work->tx_priv; + component = tx_priv->component; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = BOLERO_CDC_TX0_TX_PATH_CFG0 + + TX_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + hpf_gate_reg = BOLERO_CDC_TX0_TX_PATH_SEC2 + + TX_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + + dev_dbg(component->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + if (is_amic_enabled(component, hpf_work->decimator)) { + adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + TX_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator; + adc_n = snd_soc_component_read(component, adc_reg) & + TX_MACRO_SWR_MIC_MUX_SEL_MASK; + /* analog mic clear TX hold */ + bolero_clear_amic_tx_hold(component->dev, adc_n); + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x02); + /* Add delay between toggle hpf gate based on sample rate */ + switch (tx_priv->pcm_rate[hpf_work->decimator]) { + case 0: + usleep_range(125, 130); + break; + case 1: + usleep_range(62, 65); + break; + case 3: + usleep_range(31, 32); + break; + case 4: + usleep_range(20, 21); + break; + case 5: + usleep_range(10, 11); + break; + case 6: + usleep_range(5, 6); + break; + default: + usleep_range(125, 130); + } + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x01); + } else { + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x02); + /* Minimum 1 clk cycle delay is required as per HW spec */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x00); + } +} + +static void tx_macro_mute_update_callback(struct work_struct *work) +{ + struct tx_mute_work *tx_mute_dwork = NULL; + struct snd_soc_component *component = NULL; + struct tx_macro_priv *tx_priv = NULL; + struct delayed_work *delayed_work = NULL; + u16 tx_vol_ctl_reg = 0; + u8 decimator = 0; + + delayed_work = to_delayed_work(work); + tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork); + tx_priv = tx_mute_dwork->tx_priv; + component = tx_priv->component; + decimator = tx_mute_dwork->decimator; + + tx_vol_ctl_reg = + BOLERO_CDC_TX0_TX_PATH_CTL + + TX_MACRO_TX_PATH_OFFSET * decimator; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, 0x10, 0x00); + dev_dbg(tx_priv->dev, "%s: decimator %u unmute\n", + __func__, decimator); +} + +static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val = 0; + u16 mic_sel_reg = 0; + u16 dmic_clk_reg = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0: + mic_sel_reg = BOLERO_CDC_TX0_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0: + mic_sel_reg = BOLERO_CDC_TX1_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0: + mic_sel_reg = BOLERO_CDC_TX2_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0: + mic_sel_reg = BOLERO_CDC_TX3_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0: + mic_sel_reg = BOLERO_CDC_TX4_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0: + mic_sel_reg = BOLERO_CDC_TX5_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0: + mic_sel_reg = BOLERO_CDC_TX6_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0: + mic_sel_reg = BOLERO_CDC_TX7_TX_PATH_CFG0; + break; + default: + dev_err(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + if (strnstr(widget->name, "SMIC", strlen(widget->name))) { + if (val != 0) { + if (val < 5) { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x0 << 7); + } else { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x1 << 7); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + dmic_clk_reg = + BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL + + ((val - 5)/2) * 4; + snd_soc_component_update_bits(component, + dmic_clk_reg, + 0x0E, tx_priv->dmic_clk_div << 0x1); + } + } + } else { + /* DMIC selected */ + if (val != 0) + snd_soc_component_update_bits(component, mic_sel_reg, + 1 << 7, 1 << 7); + } + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int tx_macro_put_dec_enum_v2(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val = 0; + u16 mic_sel_reg = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0: + mic_sel_reg = BOLERO_CDC_TX0_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0: + mic_sel_reg = BOLERO_CDC_TX1_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0: + mic_sel_reg = BOLERO_CDC_TX2_TX_PATH_CFG0; + break; + case BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0: + mic_sel_reg = BOLERO_CDC_TX3_TX_PATH_CFG0; + break; + default: + dev_err(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + + if (strnstr(widget->name, "SMIC", strlen(widget->name))) { + if (val != 0) { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x0 << 7); + } + } else { + /* DMIC selected */ + if (val != 0) + snd_soc_component_update_bits(component, mic_sel_reg, + 1 << 7, 1 << 7); + } + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int tx_macro_put_pcm_in_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s\n", __func__, widget->name); + + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_I2S_CLK, + 0x1, val); + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int tx_macro_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (test_bit(dec_id, &tx_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + return 0; +} + +static int tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (enable) + set_bit(dec_id, &tx_priv->active_ch_mask[dai_id]); + else + clear_bit(dec_id, &tx_priv->active_ch_mask[dai_id]); + + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static inline int tx_macro_path_get(const char *wname, + unsigned int *path_num) +{ + int ret = 0; + char *widget_name = NULL; + char *w_name = NULL; + char *path_num_char = NULL; + char *path_name = NULL; + + widget_name = kstrndup(wname, 10, GFP_KERNEL); + if (!widget_name) + return -EINVAL; + + w_name = widget_name; + + path_name = strsep(&widget_name, " "); + if (!path_name) { + pr_err("%s: Invalid widget name = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto err; + } + path_num_char = strpbrk(path_name, "01234567"); + if (!path_num_char) { + pr_err("%s: tx path index not found\n", + __func__); + ret = -EINVAL; + goto err; + } + ret = kstrtouint(path_num_char, 10, path_num); + if (ret < 0) + pr_err("%s: Invalid tx path = %s\n", + __func__, w_name); + +err: + kfree(w_name); + return ret; +} + +static int tx_macro_dec_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int ret = 0; + int path = 0; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ret = tx_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = tx_priv->dec_mode[path]; + + return 0; +} + +static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = ucontrol->value.integer.value[0]; + int ret = 0; + int path = 0; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ret = tx_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + tx_priv->dec_mode[path] = value; + + return 0; +} + +static int tx_macro_lpi_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = tx_priv->lpi_enable; + + return 0; +} + +static int tx_macro_lpi_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->lpi_enable = ucontrol->value.integer.value[0]; + + return 0; +} + +static int tx_macro_bcs_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ucontrol->value.enumerated.item[0] = tx_priv->bcs_ch; + + return 0; +} + +static int tx_macro_bcs_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = ucontrol->value.enumerated.item[0]; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->bcs_ch = value; + + return 0; +} + +static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = tx_priv->bcs_enable; + + return 0; +} + +static int tx_macro_set_bcs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = ucontrol->value.integer.value[0]; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->bcs_enable = value; + + return 0; +} + +static const char * const bcs_ch_sel_mux_text[] = { + "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3", + "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7", + "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11", +}; + +static const struct soc_enum bcs_ch_sel_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(bcs_ch_sel_mux_text), + bcs_ch_sel_mux_text); + +static int tx_macro_get_bcs_ch_sel(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = 0; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if ((tx_priv->version == BOLERO_VERSION_2_1) || + (tx_priv->version == BOLERO_VERSION_2_2)) + value = (snd_soc_component_read(component, + BOLERO_CDC_VA_TOP_CSR_SWR_CTRL)) & 0x0F; + else if (tx_priv->version == BOLERO_VERSION_2_0) + value = (snd_soc_component_read(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL)) & 0x0F; + + ucontrol->value.integer.value[0] = value; + return 0; +} + +static int tx_macro_put_bcs_ch_sel(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > ARRAY_SIZE(bcs_ch_sel_mux_text)) + return -EINVAL; + + value = ucontrol->value.integer.value[0]; + if ((tx_priv->version == BOLERO_VERSION_2_1) || + (tx_priv->version == BOLERO_VERSION_2_2)) + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, value); + else if (tx_priv->version == BOLERO_VERSION_2_0) + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, 0x0F, value); + + return 0; +} + +static int tx_macro_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); + unsigned int dmic = 0; + int ret = 0; + char *wname = NULL; + + wname = strpbrk(w->name, "01234567"); + 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: event %d DMIC%d\n", + __func__, event, dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + bolero_dmic_clk_enable(component, dmic, DMIC_TX, true); + break; + case SND_SOC_DAPM_POST_PMD: + bolero_dmic_clk_enable(component, dmic, DMIC_TX, false); + break; + } + + return 0; +} + +static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + unsigned int decimator = 0; + u16 tx_vol_ctl_reg = 0; + u16 dec_cfg_reg = 0; + u16 hpf_gate_reg = 0; + u16 tx_gain_ctl_reg = 0; + u16 tx_fs_reg = 0; + u8 hpf_cut_off_freq = 0; + u16 adc_mux_reg = 0; + int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS; + int unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + decimator = w->shift; + + dev_dbg(component->dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = BOLERO_CDC_TX0_TX_PATH_CTL + + TX_MACRO_TX_PATH_OFFSET * decimator; + hpf_gate_reg = BOLERO_CDC_TX0_TX_PATH_SEC2 + + TX_MACRO_TX_PATH_OFFSET * decimator; + dec_cfg_reg = BOLERO_CDC_TX0_TX_PATH_CFG0 + + TX_MACRO_TX_PATH_OFFSET * decimator; + tx_gain_ctl_reg = BOLERO_CDC_TX0_TX_VOL_CTL + + TX_MACRO_TX_PATH_OFFSET * decimator; + adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + tx_fs_reg = BOLERO_CDC_TX0_TX_PATH_CTL + + TX_MACRO_TX_PATH_OFFSET * decimator; + + tx_priv->pcm_rate[decimator] = (snd_soc_component_read(component, + tx_fs_reg) & 0x0F); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + dec_cfg_reg, 0x06, tx_priv->dec_mode[decimator] << + TX_MACRO_ADC_MODE_CFG0_SHIFT); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x20, 0x20); + if (!is_amic_enabled(component, decimator)) { + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x01, 0x00); + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + } + hpf_cut_off_freq = ( + snd_soc_component_read(component, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + + if (is_amic_enabled(component, decimator)) { + hpf_delay = TX_MACRO_AMIC_HPF_DELAY_MS; + unmute_delay = TX_MACRO_AMIC_UNMUTE_DELAY_MS; + } + if (tx_unmute_delay < unmute_delay) + tx_unmute_delay = unmute_delay; + /* schedule work queue to Remove Mute */ + queue_delayed_work(system_freezable_wq, + &tx_priv->tx_mute_dwork[decimator].dwork, + msecs_to_jiffies(tx_unmute_delay)); + if (tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) { + queue_delayed_work(system_freezable_wq, + &tx_priv->tx_hpf_work[decimator].dwork, + msecs_to_jiffies(hpf_delay)); + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x02); + if (!is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x00); + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x01); + /* + * 6ms delay is required as per HW spec + */ + usleep_range(6000, 6010); + } + /* apply gain after decimator is enabled */ + snd_soc_component_write(component, tx_gain_ctl_reg, + snd_soc_component_read(component, + tx_gain_ctl_reg)); + if (tx_priv->bcs_enable) { + if ((tx_priv->version == BOLERO_VERSION_2_1) || + (tx_priv->version == BOLERO_VERSION_2_2)) + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, + tx_priv->bcs_ch); + else if (tx_priv->version == BOLERO_VERSION_2_0) + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, 0xF0, + (tx_priv->bcs_ch << 4)); + + snd_soc_component_update_bits(component, dec_cfg_reg, + 0x01, 0x01); + tx_priv->bcs_clk_en = true; + if (tx_priv->hs_slow_insert_complete) + snd_soc_component_update_bits(component, + BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40, + 0x40); + } + if (tx_priv->version == BOLERO_VERSION_2_0) { + if (snd_soc_component_read(component, adc_mux_reg) + & SWR_MIC) { + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, + 0x01, 0x01); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC0_CTL, + 0x0E, 0x0C); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC1_CTL, + 0x0E, 0x0C); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC2_CTL, + 0x0E, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC3_CTL, + 0x0E, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC4_CTL, + 0x0E, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC5_CTL, + 0x0E, 0x00); + } + } + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x10, 0x10); + if (cancel_delayed_work_sync( + &tx_priv->tx_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits( + component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + if (is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x02); + else + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x03); + + /* + * Minimum 1 clk cycle delay is required + * as per HW spec + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x01); + } + } + cancel_delayed_work_sync( + &tx_priv->tx_mute_dwork[decimator].dwork); + + if (tx_priv->version == BOLERO_VERSION_2_0) { + if (snd_soc_component_read(component, adc_mux_reg) + & SWR_MIC) + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, + 0x01, 0x00); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x20, 0x00); + snd_soc_component_update_bits(component, + dec_cfg_reg, 0x06, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x00); + if (tx_priv->bcs_enable) { + snd_soc_component_update_bits(component, dec_cfg_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40, 0x00); + tx_priv->bcs_clk_en = false; + if ((tx_priv->version == BOLERO_VERSION_2_1) || + (tx_priv->version == BOLERO_VERSION_2_2)) + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, + 0x00); + else if (tx_priv->version == BOLERO_VERSION_2_0) + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, 0xF0, + 0x00); + } + break; + } + return 0; +} + +static int tx_macro_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return 0; +} + +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, BOLERO_CDC_TX0_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, BOLERO_CDC_TX1_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec2_enum, BOLERO_CDC_TX2_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec3_enum, BOLERO_CDC_TX3_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec4_enum, BOLERO_CDC_TX4_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec5_enum, BOLERO_CDC_TX5_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec6_enum, BOLERO_CDC_TX6_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec7_enum, BOLERO_CDC_TX7_TX_PATH_CFG0, 5, + cf_text); + +static int tx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int tx_fs_rate = -EINVAL; + struct snd_soc_component *component = dai->component; + u32 decimator = 0; + u32 sample_rate = 0; + u16 tx_fs_reg = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + sample_rate = params_rate(params); + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err(component->dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + } + for_each_set_bit(decimator, &tx_priv->active_ch_mask[dai->id], + TX_MACRO_DEC_MAX) { + if (decimator >= 0) { + tx_fs_reg = BOLERO_CDC_TX0_TX_PATH_CTL + + TX_MACRO_TX_PATH_OFFSET * decimator; + dev_dbg(component->dev, "%s: set DEC%u rate to %u\n", + __func__, decimator, sample_rate); + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, tx_fs_rate); + } else { + dev_err(component->dev, + "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int tx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case TX_MACRO_AIF1_CAP: + case TX_MACRO_AIF2_CAP: + case TX_MACRO_AIF3_CAP: + *tx_slot = tx_priv->active_ch_mask[dai->id]; + *tx_num = hweight_long(tx_priv->active_ch_mask[dai->id]); + break; + default: + dev_err(tx_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static struct snd_soc_dai_ops tx_macro_dai_ops = { + .hw_params = tx_macro_hw_params, + .get_channel_map = tx_macro_get_channel_map, +}; + +static struct snd_soc_dai_driver tx_macro_dai[] = { + { + .name = "tx_macro_tx1", + .id = TX_MACRO_AIF1_CAP, + .capture = { + .stream_name = "TX_AIF1 Capture", + .rates = TX_MACRO_RATES, + .formats = TX_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &tx_macro_dai_ops, + }, + { + .name = "tx_macro_tx2", + .id = TX_MACRO_AIF2_CAP, + .capture = { + .stream_name = "TX_AIF2 Capture", + .rates = TX_MACRO_RATES, + .formats = TX_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &tx_macro_dai_ops, + }, + { + .name = "tx_macro_tx3", + .id = TX_MACRO_AIF3_CAP, + .capture = { + .stream_name = "TX_AIF3 Capture", + .rates = TX_MACRO_RATES, + .formats = TX_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &tx_macro_dai_ops, + }, +}; + +#define STRING(name) #name +#define TX_MACRO_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define TX_MACRO_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define TX_MACRO_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +static const char * const adc_mux_text[] = { + "MSM_DMIC", "SWR_MIC", "ANC_FB_TUNE1" +}; + +TX_MACRO_DAPM_ENUM(tx_dec0, BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1, + 0, adc_mux_text); +TX_MACRO_DAPM_ENUM(tx_dec1, BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG1, + 0, adc_mux_text); +TX_MACRO_DAPM_ENUM(tx_dec2, BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG1, + 0, adc_mux_text); +TX_MACRO_DAPM_ENUM(tx_dec3, BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG1, + 0, adc_mux_text); +TX_MACRO_DAPM_ENUM(tx_dec4, BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG1, + 0, adc_mux_text); +TX_MACRO_DAPM_ENUM(tx_dec5, BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG1, + 0, adc_mux_text); +TX_MACRO_DAPM_ENUM(tx_dec6, BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG1, + 0, adc_mux_text); +TX_MACRO_DAPM_ENUM(tx_dec7, BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG1, + 0, adc_mux_text); + + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", + "DMIC4", "DMIC5", "DMIC6", "DMIC7" +}; + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic0, BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic1, BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic2, BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic3, BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic4, BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic5, BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic6, BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_dmic7, BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +static const char * const smic_mux_text[] = { + "ZERO", "ADC0", "ADC1", "ADC2", "ADC3", "SWR_DMIC0", + "SWR_DMIC1", "SWR_DMIC2", "SWR_DMIC3", "SWR_DMIC4", + "SWR_DMIC5", "SWR_DMIC6", "SWR_DMIC7" +}; + +TX_MACRO_DAPM_ENUM_EXT(tx_smic0, BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic1, BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic2, BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic3, BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic4, BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic5, BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic6, BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic7, BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +static const char * const smic_mux_text_v2[] = { + "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3", + "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7", + "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11" +}; + +TX_MACRO_DAPM_ENUM_EXT(tx_smic0_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic1_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic2_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic3_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic4_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic5_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic6_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic7_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic0_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum_v2); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic1_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum_v2); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic2_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum_v2); + +TX_MACRO_DAPM_ENUM_EXT(tx_smic3_v4, BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + tx_macro_put_dec_enum_v2); + +static const char * const pcm_in0_mux_text[] = { + "SWR_MIC", "RX_SWR_TX_PCM_IN0", +}; + +static const char * const pcm_in1_mux_text[] = { + "SWR_MIC", "RX_SWR_TX_PCM_IN1", +}; + +TX_MACRO_DAPM_ENUM_EXT(rx_swr_tx_pcm_in0, SND_SOC_NOPM, + 0, pcm_in0_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_pcm_in_enum); + +TX_MACRO_DAPM_ENUM_EXT(rx_swr_tx_pcm_in1, SND_SOC_NOPM, + 0, pcm_in1_mux_text, snd_soc_dapm_get_enum_double, + tx_macro_put_pcm_in_enum); + +static const char * const dec_mode_mux_text[] = { + "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF", +}; + +static const struct soc_enum dec_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text); + +static const char * const bcs_ch_enum_text[] = { + "CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8", "CH9", + "CH10", "CH11", +}; + +static const struct soc_enum bcs_ch_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(bcs_ch_enum_text), + bcs_ch_enum_text); + +static const struct snd_kcontrol_new tx_aif1_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new tx_aif2_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new tx_aif3_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, TX_MACRO_DEC4, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, TX_MACRO_DEC5, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, TX_MACRO_DEC6, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, TX_MACRO_DEC7, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new tx_aif1_cap_mixer_v2[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new tx_aif2_cap_mixer_v2[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new tx_aif3_cap_mixer_v2[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0, + tx_macro_tx_mixer_get, tx_macro_tx_mixer_put), +}; + +static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_common[] = { + SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0, + SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("TX_AIF2 CAP", "TX_AIF2 Capture", 0, + SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("TX_AIF3 CAP", "TX_AIF3 Capture", 0, + SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0), + + TX_MACRO_DAPM_MUX("TX DMIC MUX0", 0, tx_dmic0), + TX_MACRO_DAPM_MUX("TX DMIC MUX1", 0, tx_dmic1), + TX_MACRO_DAPM_MUX("TX DMIC MUX2", 0, tx_dmic2), + TX_MACRO_DAPM_MUX("TX DMIC MUX3", 0, tx_dmic3), + + SND_SOC_DAPM_SUPPLY("TX MIC BIAS1", SND_SOC_NOPM, 0, 0, + tx_macro_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC0", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC1", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC2", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC3", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC4", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC5", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC6", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC7", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("TX SWR_INPUT"), + + SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM, + TX_MACRO_DEC0, 0, + &tx_dec0_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC1 MUX", SND_SOC_NOPM, + TX_MACRO_DEC1, 0, + &tx_dec1_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC2 MUX", SND_SOC_NOPM, + TX_MACRO_DEC2, 0, + &tx_dec2_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC3 MUX", SND_SOC_NOPM, + TX_MACRO_DEC3, 0, + &tx_dec3_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0, + tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TX_SWR_PWR", -1, SND_SOC_NOPM, 0, 0, + tx_macro_swr_pwr_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v2[] = { + SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF1_CAP, 0, + tx_aif1_cap_mixer_v2, ARRAY_SIZE(tx_aif1_cap_mixer_v2)), + + SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF2_CAP, 0, + tx_aif2_cap_mixer_v2, ARRAY_SIZE(tx_aif2_cap_mixer_v2)), + + SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF3_CAP, 0, + tx_aif3_cap_mixer_v2, ARRAY_SIZE(tx_aif3_cap_mixer_v2)), + + TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v2), + TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v2), + TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v2), + TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v2), + +}; + +static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v3[] = { + SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF1_CAP, 0, + tx_aif1_cap_mixer, ARRAY_SIZE(tx_aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF2_CAP, 0, + tx_aif2_cap_mixer, ARRAY_SIZE(tx_aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF3_CAP, 0, + tx_aif3_cap_mixer, ARRAY_SIZE(tx_aif3_cap_mixer)), + + TX_MACRO_DAPM_MUX("TX DMIC MUX4", 0, tx_dmic4), + TX_MACRO_DAPM_MUX("TX DMIC MUX5", 0, tx_dmic5), + TX_MACRO_DAPM_MUX("TX DMIC MUX6", 0, tx_dmic6), + TX_MACRO_DAPM_MUX("TX DMIC MUX7", 0, tx_dmic7), + + TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v2), + TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v2), + TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v2), + TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v2), + TX_MACRO_DAPM_MUX("TX SMIC MUX4", 0, tx_smic4_v3), + TX_MACRO_DAPM_MUX("TX SMIC MUX5", 0, tx_smic5_v3), + TX_MACRO_DAPM_MUX("TX SMIC MUX6", 0, tx_smic6_v3), + TX_MACRO_DAPM_MUX("TX SMIC MUX7", 0, tx_smic7_v3), + + SND_SOC_DAPM_MUX_E("TX DEC4 MUX", SND_SOC_NOPM, + TX_MACRO_DEC4, 0, + &tx_dec4_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC5 MUX", SND_SOC_NOPM, + TX_MACRO_DEC5, 0, + &tx_dec5_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC6 MUX", SND_SOC_NOPM, + TX_MACRO_DEC6, 0, + &tx_dec6_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC7 MUX", SND_SOC_NOPM, + TX_MACRO_DEC7, 0, + &tx_dec7_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TX_SWR_CLK", -1, SND_SOC_NOPM, 0, 0, + tx_macro_tx_swr_clk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", -1, SND_SOC_NOPM, 0, 0, + tx_macro_va_swr_clk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v4[] = { + SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF1_CAP, 0, + tx_aif1_cap_mixer_v2, ARRAY_SIZE(tx_aif1_cap_mixer_v2)), + + SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF2_CAP, 0, + tx_aif2_cap_mixer_v2, ARRAY_SIZE(tx_aif2_cap_mixer_v2)), + + SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, + TX_MACRO_AIF3_CAP, 0, + tx_aif3_cap_mixer_v2, ARRAY_SIZE(tx_aif3_cap_mixer_v2)), + + TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v4), + TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v4), + TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v4), + TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v4), + + TX_MACRO_DAPM_MUX("RX SWR TX MUX0", 0, rx_swr_tx_pcm_in0), + TX_MACRO_DAPM_MUX("RX SWR TX MUX1", 0, rx_swr_tx_pcm_in1), + + SND_SOC_DAPM_INPUT("RX_SWR_TX_PCM_IN0"), + SND_SOC_DAPM_INPUT("RX_SWR_TX_PCM_IN1"), +}; + +static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0, + SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("TX_AIF2 CAP", "TX_AIF2 Capture", 0, + SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("TX_AIF3 CAP", "TX_AIF3 Capture", 0, + SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0), + + SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0, + tx_aif1_cap_mixer, ARRAY_SIZE(tx_aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0, + tx_aif2_cap_mixer, ARRAY_SIZE(tx_aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0, + tx_aif3_cap_mixer, ARRAY_SIZE(tx_aif3_cap_mixer)), + + + TX_MACRO_DAPM_MUX("TX DMIC MUX0", 0, tx_dmic0), + TX_MACRO_DAPM_MUX("TX DMIC MUX1", 0, tx_dmic1), + TX_MACRO_DAPM_MUX("TX DMIC MUX2", 0, tx_dmic2), + TX_MACRO_DAPM_MUX("TX DMIC MUX3", 0, tx_dmic3), + TX_MACRO_DAPM_MUX("TX DMIC MUX4", 0, tx_dmic4), + TX_MACRO_DAPM_MUX("TX DMIC MUX5", 0, tx_dmic5), + TX_MACRO_DAPM_MUX("TX DMIC MUX6", 0, tx_dmic6), + TX_MACRO_DAPM_MUX("TX DMIC MUX7", 0, tx_dmic7), + + TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0), + TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1), + TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2), + TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3), + TX_MACRO_DAPM_MUX("TX SMIC MUX4", 0, tx_smic4), + TX_MACRO_DAPM_MUX("TX SMIC MUX5", 0, tx_smic5), + TX_MACRO_DAPM_MUX("TX SMIC MUX6", 0, tx_smic6), + TX_MACRO_DAPM_MUX("TX SMIC MUX7", 0, tx_smic7), + + SND_SOC_DAPM_SUPPLY("TX MIC BIAS1", SND_SOC_NOPM, 0, 0, + tx_macro_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("TX DMIC0", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC1", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC2", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC3", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC4", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC5", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC6", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("TX DMIC7", NULL, SND_SOC_NOPM, 0, 0, + tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("TX SWR_ADC0"), + SND_SOC_DAPM_INPUT("TX SWR_ADC1"), + SND_SOC_DAPM_INPUT("TX SWR_ADC2"), + SND_SOC_DAPM_INPUT("TX SWR_ADC3"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC0"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC1"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC2"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC3"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC4"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC5"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC6"), + SND_SOC_DAPM_INPUT("TX SWR_DMIC7"), + + SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM, + TX_MACRO_DEC0, 0, + &tx_dec0_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC1 MUX", SND_SOC_NOPM, + TX_MACRO_DEC1, 0, + &tx_dec1_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC2 MUX", SND_SOC_NOPM, + TX_MACRO_DEC2, 0, + &tx_dec2_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC3 MUX", SND_SOC_NOPM, + TX_MACRO_DEC3, 0, + &tx_dec3_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC4 MUX", SND_SOC_NOPM, + TX_MACRO_DEC4, 0, + &tx_dec4_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC5 MUX", SND_SOC_NOPM, + TX_MACRO_DEC5, 0, + &tx_dec5_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC6 MUX", SND_SOC_NOPM, + TX_MACRO_DEC6, 0, + &tx_dec6_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC7 MUX", SND_SOC_NOPM, + TX_MACRO_DEC7, 0, + &tx_dec7_mux, tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0, + tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TX_SWR_CLK", 0, SND_SOC_NOPM, 0, 0, + tx_macro_tx_swr_clk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", 0, SND_SOC_NOPM, 0, 0, + tx_macro_va_swr_clk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route tx_audio_map_common[] = { + {"TX_AIF1 CAP", NULL, "TX_MCLK"}, + {"TX_AIF2 CAP", NULL, "TX_MCLK"}, + {"TX_AIF3 CAP", NULL, "TX_MCLK"}, + + {"TX_AIF1 CAP", NULL, "TX_AIF1_CAP Mixer"}, + {"TX_AIF2 CAP", NULL, "TX_AIF2_CAP Mixer"}, + {"TX_AIF3 CAP", NULL, "TX_AIF3_CAP Mixer"}, + + {"TX_AIF1_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + + {"TX_AIF2_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + + {"TX_AIF3_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + + {"TX DEC0 MUX", NULL, "TX_MCLK"}, + {"TX DEC1 MUX", NULL, "TX_MCLK"}, + {"TX DEC2 MUX", NULL, "TX_MCLK"}, + {"TX DEC3 MUX", NULL, "TX_MCLK"}, + + {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"}, + {"TX DMIC MUX0", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX0", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX0", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX0", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX0", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX0", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX0", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX0", "DMIC7", "TX DMIC7"}, + + {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"}, + {"TX SMIC MUX0", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC9", "TX SWR_INPUT"}, + + {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"}, + {"TX DMIC MUX1", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX1", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX1", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX1", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX1", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX1", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX1", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX1", "DMIC7", "TX DMIC7"}, + + {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"}, + {"TX SMIC MUX1", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC9", "TX SWR_INPUT"}, + + {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"}, + {"TX DMIC MUX2", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX2", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX2", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX2", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX2", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX2", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX2", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX2", "DMIC7", "TX DMIC7"}, + + {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"}, + {"TX SMIC MUX2", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC9", "TX SWR_INPUT"}, + + {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"}, + {"TX DMIC MUX3", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX3", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX3", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX3", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX3", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX3", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX3", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX3", "DMIC7", "TX DMIC7"}, + + {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"}, + {"TX SMIC MUX3", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC9", "TX SWR_INPUT"}, +}; + +static const struct snd_soc_dapm_route tx_audio_map_v2[] = { + {"TX SMIC MUX0", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX SMIC MUX1", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX SMIC MUX2", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX SMIC MUX3", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC11", "TX SWR_INPUT"}, +}; + +static const struct snd_soc_dapm_route tx_audio_map_v3[] = { + {"TX SMIC MUX0", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX SMIC MUX1", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX SMIC MUX2", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX SMIC MUX3", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX_AIF1_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX_AIF2_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX_AIF3_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX DEC4 MUX", NULL, "TX_MCLK"}, + {"TX DEC5 MUX", NULL, "TX_MCLK"}, + {"TX DEC6 MUX", NULL, "TX_MCLK"}, + {"TX DEC7 MUX", NULL, "TX_MCLK"}, + + {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"}, + {"TX DMIC MUX4", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX4", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX4", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX4", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX4", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX4", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX4", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX4", "DMIC7", "TX DMIC7"}, + + {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"}, + {"TX SMIC MUX4", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"}, + {"TX DMIC MUX5", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX5", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX5", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX5", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX5", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX5", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX5", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX5", "DMIC7", "TX DMIC7"}, + + {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"}, + {"TX SMIC MUX5", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"}, + {"TX DMIC MUX6", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX6", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX6", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX6", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX6", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX6", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX6", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX6", "DMIC7", "TX DMIC7"}, + + {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"}, + {"TX SMIC MUX6", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"}, + {"TX DMIC MUX7", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX7", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX7", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX7", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX7", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX7", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX7", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX7", "DMIC7", "TX DMIC7"}, + + {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"}, + {"TX SMIC MUX7", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX SMIC MUX0", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX1", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX2", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX3", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX4", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX5", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX6", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX7", NULL, "TX_SWR_CLK"}, + + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, + {"TX SWR_INPUT", NULL, "TX_SWR_PWR"}, +}; + +static const struct snd_soc_dapm_route tx_audio_map_v4[] = { + {"TX SMIC MUX0", "SWR_MIC10", "RX SWR TX MUX0"}, + {"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"}, + {"TX SMIC MUX0", "SWR_MIC11", "RX SWR TX MUX1"}, + {"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"}, + + {"TX SMIC MUX1", "SWR_MIC10", "RX SWR TX MUX0"}, + {"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"}, + {"TX SMIC MUX1", "SWR_MIC11", "RX SWR TX MUX1"}, + {"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"}, + + {"TX SMIC MUX2", "SWR_MIC10", "RX SWR TX MUX0"}, + {"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"}, + {"TX SMIC MUX2", "SWR_MIC11", "RX SWR TX MUX1"}, + {"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"}, + + {"TX SMIC MUX3", "SWR_MIC10", "RX SWR TX MUX0"}, + {"RX SWR TX MUX0", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX0", "RX_SWR_TX_PCM_IN0", "RX_SWR_TX_PCM_IN0"}, + {"TX SMIC MUX3", "SWR_MIC11", "RX SWR TX MUX1"}, + {"RX SWR TX MUX1", "SWR_MIC", "TX SWR_INPUT"}, + {"RX SWR TX MUX1", "RX_SWR_TX_PCM_IN1", "RX_SWR_TX_PCM_IN1"}, + + {"RX SWR TX MUX0", NULL, "TX_MCLK"}, + {"RX SWR TX MUX1", NULL, "TX_MCLK"}, +}; + +static const struct snd_soc_dapm_route tx_audio_map[] = { + {"TX_AIF1 CAP", NULL, "TX_MCLK"}, + {"TX_AIF2 CAP", NULL, "TX_MCLK"}, + {"TX_AIF3 CAP", NULL, "TX_MCLK"}, + + {"TX_AIF1 CAP", NULL, "TX_AIF1_CAP Mixer"}, + {"TX_AIF2 CAP", NULL, "TX_AIF2_CAP Mixer"}, + {"TX_AIF3 CAP", NULL, "TX_AIF3_CAP Mixer"}, + + {"TX_AIF1_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX_AIF2_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX_AIF3_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX DEC0 MUX", NULL, "TX_MCLK"}, + {"TX DEC1 MUX", NULL, "TX_MCLK"}, + {"TX DEC2 MUX", NULL, "TX_MCLK"}, + {"TX DEC3 MUX", NULL, "TX_MCLK"}, + {"TX DEC4 MUX", NULL, "TX_MCLK"}, + {"TX DEC5 MUX", NULL, "TX_MCLK"}, + {"TX DEC6 MUX", NULL, "TX_MCLK"}, + {"TX DEC7 MUX", NULL, "TX_MCLK"}, + + {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"}, + {"TX DMIC MUX0", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX0", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX0", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX0", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX0", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX0", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX0", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX0", "DMIC7", "TX DMIC7"}, + + {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"}, + {"TX SMIC MUX0", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX0", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX0", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX0", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX0", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX0", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX0", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX0", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX0", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX0", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"}, + + {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"}, + {"TX DMIC MUX1", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX1", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX1", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX1", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX1", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX1", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX1", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX1", "DMIC7", "TX DMIC7"}, + + {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"}, + {"TX SMIC MUX1", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX1", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX1", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX1", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX1", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX1", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX1", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX1", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX1", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX1", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"}, + + {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"}, + {"TX DMIC MUX2", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX2", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX2", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX2", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX2", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX2", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX2", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX2", "DMIC7", "TX DMIC7"}, + + {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"}, + {"TX SMIC MUX2", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX2", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX2", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX2", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX2", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX2", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX2", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX2", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX2", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX2", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"}, + + {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"}, + {"TX DMIC MUX3", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX3", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX3", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX3", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX3", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX3", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX3", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX3", "DMIC7", "TX DMIC7"}, + + {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"}, + {"TX SMIC MUX3", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX3", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX3", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX3", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX3", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX3", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX3", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX3", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX3", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX3", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"}, + + {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"}, + {"TX DMIC MUX4", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX4", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX4", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX4", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX4", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX4", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX4", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX4", "DMIC7", "TX DMIC7"}, + + {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"}, + {"TX SMIC MUX4", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX4", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX4", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX4", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX4", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX4", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX4", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX4", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX4", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX4", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"}, + + {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"}, + {"TX DMIC MUX5", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX5", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX5", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX5", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX5", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX5", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX5", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX5", "DMIC7", "TX DMIC7"}, + + {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"}, + {"TX SMIC MUX5", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX5", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX5", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX5", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX5", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX5", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX5", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX5", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX5", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX5", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"}, + + {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"}, + {"TX DMIC MUX6", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX6", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX6", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX6", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX6", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX6", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX6", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX6", "DMIC7", "TX DMIC7"}, + + {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"}, + {"TX SMIC MUX6", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX6", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX6", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX6", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX6", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX6", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX6", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX6", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX6", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX6", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"}, + + {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"}, + {"TX DMIC MUX7", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX7", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX7", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX7", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX7", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX7", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX7", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX7", "DMIC7", "TX DMIC7"}, + + {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"}, + {"TX SMIC MUX7", NULL, "TX_SWR_CLK"}, + {"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"}, + {"TX SMIC MUX7", "ADC1", "TX SWR_ADC1"}, + {"TX SMIC MUX7", "ADC2", "TX SWR_ADC2"}, + {"TX SMIC MUX7", "ADC3", "TX SWR_ADC3"}, + {"TX SMIC MUX7", "SWR_DMIC0", "TX SWR_DMIC0"}, + {"TX SMIC MUX7", "SWR_DMIC1", "TX SWR_DMIC1"}, + {"TX SMIC MUX7", "SWR_DMIC2", "TX SWR_DMIC2"}, + {"TX SMIC MUX7", "SWR_DMIC3", "TX SWR_DMIC3"}, + {"TX SMIC MUX7", "SWR_DMIC4", "TX SWR_DMIC4"}, + {"TX SMIC MUX7", "SWR_DMIC5", "TX SWR_DMIC5"}, + {"TX SMIC MUX7", "SWR_DMIC6", "TX SWR_DMIC6"}, + {"TX SMIC MUX7", "SWR_DMIC7", "TX SWR_DMIC7"}, +}; + +static const struct snd_kcontrol_new tx_macro_snd_controls_common[] = { + SOC_SINGLE_S8_TLV("TX_DEC0 Volume", + BOLERO_CDC_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC1 Volume", + BOLERO_CDC_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC2 Volume", + BOLERO_CDC_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC3 Volume", + BOLERO_CDC_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + + SOC_SINGLE_EXT("TX LPI Enable", 0, 0, 1, 0, + tx_macro_lpi_get, tx_macro_lpi_put), + + SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0, + tx_macro_get_bcs, tx_macro_set_bcs), + + SOC_ENUM_EXT("BCS Channel", bcs_ch_enum, + tx_macro_bcs_ch_get, tx_macro_bcs_ch_put), + + SOC_ENUM_EXT("BCS CH_SEL", bcs_ch_sel_mux_enum, + tx_macro_get_bcs_ch_sel, tx_macro_put_bcs_ch_sel), +}; + +static const struct snd_kcontrol_new tx_macro_snd_controls_v3[] = { + SOC_SINGLE_S8_TLV("TX_DEC4 Volume", + BOLERO_CDC_TX4_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC5 Volume", + BOLERO_CDC_TX5_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC6 Volume", + BOLERO_CDC_TX6_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC7 Volume", + BOLERO_CDC_TX7_TX_VOL_CTL, + -84, 40, digital_gain), + + SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), +}; + +static const struct snd_kcontrol_new tx_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("TX_DEC0 Volume", + BOLERO_CDC_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC1 Volume", + BOLERO_CDC_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC2 Volume", + BOLERO_CDC_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC3 Volume", + BOLERO_CDC_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC4 Volume", + BOLERO_CDC_TX4_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC5 Volume", + BOLERO_CDC_TX5_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC6 Volume", + BOLERO_CDC_TX6_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC7 Volume", + BOLERO_CDC_TX7_TX_VOL_CTL, + -84, 40, digital_gain), + + SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum, + tx_macro_dec_mode_get, tx_macro_dec_mode_put), + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + + SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0, + tx_macro_get_bcs, tx_macro_set_bcs), +}; + +static int tx_macro_register_event_listener(struct snd_soc_component *component, + bool enable) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + int ret = 0; + + if (!component) + return -EINVAL; + + tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO); + if (!tx_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + tx_priv = dev_get_drvdata(tx_dev); + if (!tx_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + if (tx_priv->swr_ctrl_data && + (!tx_priv->tx_swr_clk_cnt || !tx_priv->va_swr_clk_cnt)) { + if (enable) { + if (!tx_priv->disable_afe_wakeup_event_listener) + ret = swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_REGISTER_WAKEUP, NULL); + } else { + if (!tx_priv->disable_afe_wakeup_event_listener) + ret = swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_DEREGISTER_WAKEUP, NULL); + } + } + + return ret; +} + +static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv, + struct regmap *regmap, int clk_type, + bool enable) +{ + int ret = 0, clk_tx_ret = 0; + + dev_dbg(tx_priv->dev, + "%s: clock type %s, enable: %s tx_mclk_users: %d\n", + __func__, (clk_type ? "VA_MCLK" : "TX_MCLK"), + (enable ? "enable" : "disable"), tx_priv->tx_mclk_users); + + if (enable) { + if (tx_priv->swr_clk_users == 0) { + ret = msm_cdc_pinctrl_select_active_state( + tx_priv->tx_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(tx_priv->dev, + "%s: tx swr pinctrl enable failed\n", + __func__); + goto exit; + } + msm_cdc_pinctrl_set_wakeup_capable( + tx_priv->tx_swr_gpio_p, false); + } + + clk_tx_ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + if (clk_type == TX_MCLK) { + ret = tx_macro_mclk_enable(tx_priv, 1); + if (ret < 0) { + if (tx_priv->swr_clk_users == 0) + msm_cdc_pinctrl_select_sleep_state( + tx_priv->tx_swr_gpio_p); + dev_err_ratelimited(tx_priv->dev, + "%s: request clock enable failed\n", + __func__); + goto done; + } + } + if (clk_type == VA_MCLK) { + ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + VA_CORE_CLK, + true); + if (ret < 0) { + if (tx_priv->swr_clk_users == 0) + msm_cdc_pinctrl_select_sleep_state( + tx_priv->tx_swr_gpio_p); + dev_err_ratelimited(tx_priv->dev, + "%s: swr request clk failed\n", + __func__); + goto done; + } + bolero_clk_rsc_fs_gen_request(tx_priv->dev, + true); + mutex_lock(&tx_priv->mclk_lock); + if (tx_priv->tx_mclk_users == 0) { + regmap_update_bits(regmap, + BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK, + 0x01, 0x01); + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + tx_priv->tx_mclk_users++; + mutex_unlock(&tx_priv->mclk_lock); + } + if (tx_priv->swr_clk_users == 0) { + dev_dbg(tx_priv->dev, "%s: reset_swr: %d\n", + __func__, tx_priv->reset_swr); + if (tx_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (tx_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + tx_priv->reset_swr = false; + } + if (!clk_tx_ret) + ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + tx_priv->swr_clk_users++; + } else { + if (tx_priv->swr_clk_users <= 0) { + dev_err_ratelimited(tx_priv->dev, + "tx swrm clock users already 0\n"); + tx_priv->swr_clk_users = 0; + return 0; + } + clk_tx_ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + tx_priv->swr_clk_users--; + if (tx_priv->swr_clk_users == 0) + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + if (clk_type == TX_MCLK) + tx_macro_mclk_enable(tx_priv, 0); + if (clk_type == VA_MCLK) { + mutex_lock(&tx_priv->mclk_lock); + if (tx_priv->tx_mclk_users <= 0) { + dev_err(tx_priv->dev, "%s: clock already disabled\n", + __func__); + tx_priv->tx_mclk_users = 0; + mutex_unlock(&tx_priv->mclk_lock); + goto tx_clk; + } + tx_priv->tx_mclk_users--; + if (tx_priv->tx_mclk_users == 0) { + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + } + mutex_unlock(&tx_priv->mclk_lock); + bolero_clk_rsc_fs_gen_request(tx_priv->dev, + false); + ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + VA_CORE_CLK, + false); + if (ret < 0) { + dev_err_ratelimited(tx_priv->dev, + "%s: swr request clk failed\n", + __func__); + goto done; + } + } +tx_clk: + if (!clk_tx_ret) + ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + if (tx_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_set_wakeup_capable( + tx_priv->tx_swr_gpio_p, true); + ret = msm_cdc_pinctrl_select_sleep_state( + tx_priv->tx_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(tx_priv->dev, + "%s: tx swr pinctrl disable failed\n", + __func__); + goto exit; + } + } + } + return 0; + +done: + if (!clk_tx_ret) + bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); +exit: + return ret; +} + +static int tx_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + return tx_priv->dmic_clk_div; +} + +static int tx_macro_clk_switch(struct snd_soc_component *component, int clk_src) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + int ret = 0; + + if (!component) + return -EINVAL; + + tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO); + if (!tx_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + tx_priv = dev_get_drvdata(tx_dev); + if (!tx_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + dev_dbg(component->dev, + "%s: va_swr_clk_cnt %d, tx_swr_clk_cnt %d, tx_clk_status %d\n", + __func__, tx_priv->va_swr_clk_cnt, + tx_priv->tx_swr_clk_cnt, tx_priv->tx_clk_status); + if (tx_priv->current_clk_id == clk_src) { + dev_dbg(component->dev, + "%s: requested clk %d is same as current\n", + __func__, clk_src); + return 0; + } else if (tx_priv->va_swr_clk_cnt != 0 && tx_priv->tx_clk_status) { + ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + clk_src, + true); + if (ret) { + dev_dbg(component->dev, + "%s: request clock %d enable failed\n", + __func__, clk_src); + goto ret; + } + ret = bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + tx_priv->current_clk_id, + false); + if (ret) { + dev_dbg(component->dev, + "%s: request clock disable failed\n", + __func__); + bolero_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + clk_src, + false); + goto ret; + } + tx_priv->current_clk_id = clk_src; + } else { + ret = -EBUSY; + } + +ret: + return ret; +} + +static int tx_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle; + + if (tx_priv == NULL) { + pr_err("%s: tx priv data is NULL\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(tx_priv->dev); + if (bolero_check_core_votes(tx_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(tx_priv->dev); + pm_runtime_mark_last_busy(tx_priv->dev); + } + return rc; +} + +static int tx_macro_swrm_clock(void *handle, bool enable) +{ + struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(tx_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(tx_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&tx_priv->swr_clk_lock); + dev_dbg(tx_priv->dev, + "%s: swrm clock %s tx_swr_clk_cnt: %d va_swr_clk_cnt: %d\n", + __func__, (enable ? "enable" : "disable"), + tx_priv->tx_swr_clk_cnt, tx_priv->va_swr_clk_cnt); + + if (enable) { + pm_runtime_get_sync(tx_priv->dev); + if (tx_priv->va_swr_clk_cnt && !tx_priv->tx_swr_clk_cnt) { + ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap, + VA_MCLK, enable); + if (ret) { + pm_runtime_mark_last_busy(tx_priv->dev); + pm_runtime_put_autosuspend(tx_priv->dev); + goto done; + } + tx_priv->va_clk_status++; + } else { + ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap, + TX_MCLK, enable); + if (ret) { + pm_runtime_mark_last_busy(tx_priv->dev); + pm_runtime_put_autosuspend(tx_priv->dev); + goto done; + } + tx_priv->tx_clk_status++; + } + pm_runtime_mark_last_busy(tx_priv->dev); + pm_runtime_put_autosuspend(tx_priv->dev); + } else { + if (tx_priv->va_clk_status && !tx_priv->tx_clk_status) { + ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap, + VA_MCLK, enable); + if (ret) + goto done; + --tx_priv->va_clk_status; + } else if (!tx_priv->va_clk_status && tx_priv->tx_clk_status) { + ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap, + TX_MCLK, enable); + if (ret) + goto done; + --tx_priv->tx_clk_status; + } else if (tx_priv->va_clk_status && tx_priv->tx_clk_status) { + if (!tx_priv->va_swr_clk_cnt && tx_priv->tx_swr_clk_cnt) { + ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap, + VA_MCLK, enable); + if (ret) + goto done; + --tx_priv->va_clk_status; + } else { + ret = tx_macro_tx_va_mclk_enable(tx_priv, regmap, + TX_MCLK, enable); + if (ret) + goto done; + --tx_priv->tx_clk_status; + } + + } else { + dev_dbg(tx_priv->dev, + "%s: Both clocks are disabled\n", __func__); + } + } + + dev_dbg(tx_priv->dev, + "%s: swrm clock users %d tx_clk_sts_cnt: %d va_clk_sts_cnt: %d\n", + __func__, tx_priv->swr_clk_users, tx_priv->tx_clk_status, + tx_priv->va_clk_status); +done: + mutex_unlock(&tx_priv->swr_clk_lock); + return ret; +} + +static int tx_macro_validate_dmic_sample_rate(u32 dmic_sample_rate, + struct tx_macro_priv *tx_priv) +{ + u32 div_factor = TX_MACRO_CLK_DIV_2; + u32 mclk_rate = TX_MACRO_MCLK_FREQ; + + if (dmic_sample_rate == TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED || + mclk_rate % dmic_sample_rate != 0) + goto undefined_rate; + + div_factor = mclk_rate / dmic_sample_rate; + + switch (div_factor) { + case 2: + tx_priv->dmic_clk_div = TX_MACRO_CLK_DIV_2; + break; + case 3: + tx_priv->dmic_clk_div = TX_MACRO_CLK_DIV_3; + break; + case 4: + tx_priv->dmic_clk_div = TX_MACRO_CLK_DIV_4; + break; + case 6: + tx_priv->dmic_clk_div = TX_MACRO_CLK_DIV_6; + break; + case 8: + tx_priv->dmic_clk_div = TX_MACRO_CLK_DIV_8; + break; + case 16: + tx_priv->dmic_clk_div = TX_MACRO_CLK_DIV_16; + break; + default: + /* Any other DIV factor is invalid */ + goto undefined_rate; + } + + /* Valid dmic DIV factors */ + dev_dbg(tx_priv->dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n", + __func__, div_factor, mclk_rate); + + return dmic_sample_rate; + +undefined_rate: + dev_dbg(tx_priv->dev, "%s: Invalid rate %d, for mclk %d\n", + __func__, dmic_sample_rate, mclk_rate); + dmic_sample_rate = TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED; + + return dmic_sample_rate; +} + +static const struct tx_macro_reg_mask_val tx_macro_reg_init[] = { + {BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x0A}, +}; + +static int tx_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = 0, i = 0; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO); + if (!tx_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + tx_priv = dev_get_drvdata(tx_dev); + if (!tx_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + tx_priv->lpi_enable = false; + tx_priv->register_event_listener = false; + tx_priv->version = bolero_get_version(tx_dev); + if (tx_priv->version >= BOLERO_VERSION_2_0) { + ret = snd_soc_dapm_new_controls(dapm, + tx_macro_dapm_widgets_common, + ARRAY_SIZE(tx_macro_dapm_widgets_common)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + if (tx_priv->version == BOLERO_VERSION_2_1) + ret = snd_soc_dapm_new_controls(dapm, + tx_macro_dapm_widgets_v2, + ARRAY_SIZE(tx_macro_dapm_widgets_v2)); + else if (tx_priv->version == BOLERO_VERSION_2_0) + ret = snd_soc_dapm_new_controls(dapm, + tx_macro_dapm_widgets_v3, + ARRAY_SIZE(tx_macro_dapm_widgets_v3)); + else if (tx_priv->version == BOLERO_VERSION_2_2) + ret = snd_soc_dapm_new_controls(dapm, + tx_macro_dapm_widgets_v4, + ARRAY_SIZE(tx_macro_dapm_widgets_v4)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + } else { + ret = snd_soc_dapm_new_controls(dapm, tx_macro_dapm_widgets, + ARRAY_SIZE(tx_macro_dapm_widgets)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + } + + if (tx_priv->version >= BOLERO_VERSION_2_0) { + ret = snd_soc_dapm_add_routes(dapm, + tx_audio_map_common, + ARRAY_SIZE(tx_audio_map_common)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + if (tx_priv->version == BOLERO_VERSION_2_1) + ret = snd_soc_dapm_add_routes(dapm, + tx_audio_map_v2, + ARRAY_SIZE(tx_audio_map_v2)); + if (tx_priv->version == BOLERO_VERSION_2_0) + ret = snd_soc_dapm_add_routes(dapm, + tx_audio_map_v3, + ARRAY_SIZE(tx_audio_map_v3)); + if (tx_priv->version == BOLERO_VERSION_2_2) + ret = snd_soc_dapm_add_routes(dapm, + tx_audio_map_v4, + ARRAY_SIZE(tx_audio_map_v4)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + } else { + ret = snd_soc_dapm_add_routes(dapm, tx_audio_map, + ARRAY_SIZE(tx_audio_map)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + } + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add widgets\n", __func__); + return ret; + } + + if (tx_priv->version >= BOLERO_VERSION_2_0) { + ret = snd_soc_add_component_controls(component, + tx_macro_snd_controls_common, + ARRAY_SIZE(tx_macro_snd_controls_common)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + if (tx_priv->version == BOLERO_VERSION_2_0) + ret = snd_soc_add_component_controls(component, + tx_macro_snd_controls_v3, + ARRAY_SIZE(tx_macro_snd_controls_v3)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + } else { + ret = snd_soc_add_component_controls(component, + tx_macro_snd_controls, + ARRAY_SIZE(tx_macro_snd_controls)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + } + + snd_soc_dapm_ignore_suspend(dapm, "TX_AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "TX_AIF2 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "TX_AIF3 Capture"); + if (tx_priv->version >= BOLERO_VERSION_2_0) { + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_INPUT"); + } else { + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC0"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC1"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC2"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC3"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC0"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC4"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC5"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC6"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC7"); + } + snd_soc_dapm_sync(dapm); + + for (i = 0; i < NUM_DECIMATORS; i++) { + tx_priv->tx_hpf_work[i].tx_priv = tx_priv; + tx_priv->tx_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&tx_priv->tx_hpf_work[i].dwork, + tx_macro_tx_hpf_corner_freq_callback); + } + + for (i = 0; i < NUM_DECIMATORS; i++) { + tx_priv->tx_mute_dwork[i].tx_priv = tx_priv; + tx_priv->tx_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&tx_priv->tx_mute_dwork[i].dwork, + tx_macro_mute_update_callback); + } + tx_priv->component = component; + + for (i = 0; i < ARRAY_SIZE(tx_macro_reg_init); i++) + snd_soc_component_update_bits(component, + tx_macro_reg_init[i].reg, + tx_macro_reg_init[i].mask, + tx_macro_reg_init[i].val); + + return 0; +} + +static int tx_macro_deinit(struct snd_soc_component *component) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->component = NULL; + return 0; +} + +static void tx_macro_add_child_devices(struct work_struct *work) +{ + struct tx_macro_priv *tx_priv = NULL; + struct platform_device *pdev = NULL; + struct device_node *node = NULL; + struct tx_macro_swr_ctrl_data *swr_ctrl_data = NULL, *temp = NULL; + int ret = 0; + u16 count = 0, ctrl_num = 0; + struct tx_macro_swr_ctrl_platform_data *platdata = NULL; + char plat_dev_name[TX_MACRO_SWR_STRING_LEN] = ""; + bool tx_swr_master_node = false; + + tx_priv = container_of(work, struct tx_macro_priv, + tx_macro_add_child_devices_work); + if (!tx_priv) { + pr_err("%s: Memory for tx_priv does not exist\n", + __func__); + return; + } + + if (!tx_priv->dev) { + pr_err("%s: tx dev does not exist\n", __func__); + return; + } + + if (!tx_priv->dev->of_node) { + dev_err(tx_priv->dev, + "%s: DT node for tx_priv does not exist\n", __func__); + return; + } + + platdata = &tx_priv->swr_plat_data; + tx_priv->child_count = 0; + + for_each_available_child_of_node(tx_priv->dev->of_node, node) { + tx_swr_master_node = false; + if (strnstr(node->name, "tx_swr_master", + strlen("tx_swr_master")) != NULL) + tx_swr_master_node = true; + + if (tx_swr_master_node) + strlcpy(plat_dev_name, "tx_swr_ctrl", + (TX_MACRO_SWR_STRING_LEN - 1)); + else + strlcpy(plat_dev_name, node->name, + (TX_MACRO_SWR_STRING_LEN - 1)); + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(tx_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = tx_priv->dev; + pdev->dev.of_node = node; + + if (tx_swr_master_node) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct tx_macro_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].tx_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + tx_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (tx_priv->child_count < TX_MACRO_CHILD_DEVICES_MAX) + tx_priv->pdev_child_devices[ + tx_priv->child_count++] = pdev; + else + goto err; + } + return; +fail_pdev_add: + for (count = 0; count < tx_priv->child_count; count++) + platform_device_put(tx_priv->pdev_child_devices[count]); +err: + return; +} + +static int tx_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (tx_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +static void tx_macro_init_ops(struct macro_ops *ops, + char __iomem *tx_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->init = tx_macro_init; + ops->exit = tx_macro_deinit; + ops->io_base = tx_io_base; + ops->dai_ptr = tx_macro_dai; + ops->num_dais = ARRAY_SIZE(tx_macro_dai); + ops->event_handler = tx_macro_event_handler; + ops->reg_wake_irq = tx_macro_reg_wake_irq; + ops->set_port_map = tx_macro_set_port_map; + ops->clk_div_get = tx_macro_clk_div_get; + ops->clk_switch = tx_macro_clk_switch; + ops->reg_evt_listener = tx_macro_register_event_listener; + ops->clk_enable = __tx_macro_mclk_enable; +} + +static int tx_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops = {0}; + struct tx_macro_priv *tx_priv = NULL; + u32 tx_base_addr = 0, sample_rate = 0; + char __iomem *tx_io_base = NULL; + int ret = 0; + const char *dmic_sample_rate = "qcom,tx-dmic-sample-rate"; + u32 is_used_tx_swr_gpio = 1; + const char *is_used_tx_swr_gpio_dt = "qcom,is-used-swr-gpio"; + u32 disable_afe_wakeup_event_listener = 0; + const char *disable_afe_wakeup_event_listener_dt = + "qcom,disable-afe-wakeup-event-listener"; + + if (!bolero_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + + tx_priv = devm_kzalloc(&pdev->dev, sizeof(struct tx_macro_priv), + GFP_KERNEL); + if (!tx_priv) + return -ENOMEM; + platform_set_drvdata(pdev, tx_priv); + + tx_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &tx_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + dev_set_drvdata(&pdev->dev, tx_priv); + if (of_find_property(pdev->dev.of_node, is_used_tx_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_tx_swr_gpio_dt, + &is_used_tx_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_tx_swr_gpio_dt); + is_used_tx_swr_gpio = 1; + } + } + tx_priv->tx_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,tx-swr-gpios", 0); + if (!tx_priv->tx_swr_gpio_p && is_used_tx_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if (msm_cdc_pinctrl_get_state(tx_priv->tx_swr_gpio_p) < 0 && + is_used_tx_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + + tx_io_base = devm_ioremap(&pdev->dev, + tx_base_addr, TX_MACRO_MAX_OFFSET); + if (!tx_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -ENOMEM; + } + tx_priv->tx_io_base = tx_io_base; + ret = of_property_read_u32(pdev->dev.of_node, dmic_sample_rate, + &sample_rate); + if (ret) { + dev_err(&pdev->dev, + "%s: could not find sample_rate entry in dt\n", + __func__); + tx_priv->dmic_clk_div = TX_MACRO_CLK_DIV_2; + } else { + if (tx_macro_validate_dmic_sample_rate( + sample_rate, tx_priv) == TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED) + return -EINVAL; + } + + if (of_find_property(pdev->dev.of_node, + disable_afe_wakeup_event_listener_dt, NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + disable_afe_wakeup_event_listener_dt, + &disable_afe_wakeup_event_listener); + if (ret) + dev_dbg(&pdev->dev, "%s: error reading %s in dt\n", + __func__, disable_afe_wakeup_event_listener_dt); + } + tx_priv->disable_afe_wakeup_event_listener = + disable_afe_wakeup_event_listener; + + if (is_used_tx_swr_gpio) { + tx_priv->reset_swr = true; + INIT_WORK(&tx_priv->tx_macro_add_child_devices_work, + tx_macro_add_child_devices); + tx_priv->swr_plat_data.handle = (void *) tx_priv; + tx_priv->swr_plat_data.read = NULL; + tx_priv->swr_plat_data.write = NULL; + tx_priv->swr_plat_data.bulk_write = NULL; + tx_priv->swr_plat_data.clk = tx_macro_swrm_clock; + tx_priv->swr_plat_data.core_vote = tx_macro_core_vote; + tx_priv->swr_plat_data.handle_irq = NULL; + mutex_init(&tx_priv->swr_clk_lock); + } + tx_priv->is_used_tx_swr_gpio = is_used_tx_swr_gpio; + mutex_init(&tx_priv->mclk_lock); + tx_macro_init_ops(&ops, tx_io_base); + ops.clk_id_req = TX_CORE_CLK; + ops.default_clk_id = TX_CORE_CLK; + tx_priv->current_clk_id = TX_CORE_CLK; + ret = bolero_register_macro(&pdev->dev, TX_MACRO, &ops); + if (ret) { + dev_err(&pdev->dev, + "%s: register macro failed\n", __func__); + goto err_reg_macro; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + if (is_used_tx_swr_gpio) + schedule_work(&tx_priv->tx_macro_add_child_devices_work); + + return 0; +err_reg_macro: + mutex_destroy(&tx_priv->mclk_lock); + if (is_used_tx_swr_gpio) + mutex_destroy(&tx_priv->swr_clk_lock); + return ret; +} + +static int tx_macro_remove(struct platform_device *pdev) +{ + struct tx_macro_priv *tx_priv = NULL; + u16 count = 0; + + tx_priv = platform_get_drvdata(pdev); + + if (!tx_priv) + return -EINVAL; + + if (tx_priv->is_used_tx_swr_gpio) { + if (tx_priv->swr_ctrl_data) + kfree(tx_priv->swr_ctrl_data); + for (count = 0; count < tx_priv->child_count && + count < TX_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister( + tx_priv->pdev_child_devices[count]); + } + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + mutex_destroy(&tx_priv->mclk_lock); + if (tx_priv->is_used_tx_swr_gpio) + mutex_destroy(&tx_priv->swr_clk_lock); + bolero_unregister_macro(&pdev->dev, TX_MACRO); + return 0; +} + + +static const struct of_device_id tx_macro_dt_match[] = { + {.compatible = "qcom,tx-macro"}, + {} +}; + +static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + bolero_runtime_suspend, + bolero_runtime_resume, + NULL + ) +}; + +static struct platform_driver tx_macro_driver = { + .driver = { + .name = "tx_macro", + .owner = THIS_MODULE, + .pm = &bolero_dev_pm_ops, + .of_match_table = tx_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = tx_macro_probe, + .remove = tx_macro_remove, +}; + +module_platform_driver(tx_macro_driver); + +MODULE_DESCRIPTION("TX macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/va-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/va-macro.c new file mode 100644 index 0000000000..97608ba812 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/va-macro.c @@ -0,0 +1,3324 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bolero-cdc.h" +#include "bolero-cdc-registers.h" +#include "bolero-clk-rsc.h" + +/* pm runtime auto suspend timer in msecs */ +#define VA_AUTO_SUSPEND_DELAY 100 /* delay in msec */ +#define VA_MACRO_MAX_OFFSET 0x1000 + +#define VA_MACRO_NUM_DECIMATORS 8 + +#define VA_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define VA_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED 0 +#define VA_MACRO_MCLK_FREQ 9600000 +#define VA_MACRO_TX_PATH_OFFSET 0x80 +#define VA_MACRO_TX_DMIC_CLK_DIV_MASK 0x0E +#define VA_MACRO_TX_DMIC_CLK_DIV_SHFT 0x01 +#define VA_MACRO_SWR_MIC_MUX_SEL_MASK 0xF +#define VA_MACRO_ADC_MUX_CFG_OFFSET 0x8 +#define VA_MACRO_ADC_MODE_CFG0_SHIFT 1 + +#define BOLERO_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS 40 +#define BOLERO_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS 100 +#define BOLERO_CDC_VA_TX_DMIC_HPF_DELAY_MS 300 +#define BOLERO_CDC_VA_TX_AMIC_HPF_DELAY_MS 300 +#define MAX_RETRY_ATTEMPTS 500 +#define VA_MACRO_SWR_STRING_LEN 80 +#define VA_MACRO_CHILD_DEVICES_MAX 3 + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static int va_tx_unmute_delay = BOLERO_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS; +module_param(va_tx_unmute_delay, int, 0664); +MODULE_PARM_DESC(va_tx_unmute_delay, "delay to unmute the tx path"); + +static int va_macro_core_vote(void *handle, bool enable); + +enum { + VA_MACRO_AIF_INVALID = 0, + VA_MACRO_AIF1_CAP, + VA_MACRO_AIF2_CAP, + VA_MACRO_AIF3_CAP, + VA_MACRO_MAX_DAIS, +}; + +enum { + VA_MACRO_DEC0, + VA_MACRO_DEC1, + VA_MACRO_DEC2, + VA_MACRO_DEC3, + VA_MACRO_DEC4, + VA_MACRO_DEC5, + VA_MACRO_DEC6, + VA_MACRO_DEC7, + VA_MACRO_DEC_MAX, +}; + +enum { + VA_MACRO_CLK_DIV_2, + VA_MACRO_CLK_DIV_3, + VA_MACRO_CLK_DIV_4, + VA_MACRO_CLK_DIV_6, + VA_MACRO_CLK_DIV_8, + VA_MACRO_CLK_DIV_16, +}; + +enum { + MSM_DMIC, + SWR_MIC, +}; + +enum { + TX_MCLK, + VA_MCLK, +}; + +struct va_mute_work { + struct va_macro_priv *va_priv; + u32 decimator; + struct delayed_work dwork; +}; + +struct hpf_work { + struct va_macro_priv *va_priv; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +/* Hold instance to soundwire platform device */ +struct va_macro_swr_ctrl_data { + struct platform_device *va_swr_pdev; +}; + +struct va_macro_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +struct va_macro_priv { + struct device *dev; + bool dec_active[VA_MACRO_NUM_DECIMATORS]; + bool va_without_decimation; + struct clk *lpass_audio_hw_vote; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct snd_soc_component *component; + struct hpf_work va_hpf_work[VA_MACRO_NUM_DECIMATORS]; + struct va_mute_work va_mute_dwork[VA_MACRO_NUM_DECIMATORS]; + unsigned long active_ch_mask[VA_MACRO_MAX_DAIS]; + u16 dmic_clk_div; + u16 va_mclk_users; + int swr_clk_users; + bool reset_swr; + struct device_node *va_swr_gpio_p; + struct va_macro_swr_ctrl_data *swr_ctrl_data; + struct va_macro_swr_ctrl_platform_data swr_plat_data; + struct work_struct va_macro_add_child_devices_work; + int child_count; + u16 mclk_mux_sel; + char __iomem *va_io_base; + char __iomem *va_island_mode_muxsel; + struct platform_device *pdev_child_devices + [VA_MACRO_CHILD_DEVICES_MAX]; + struct regulator *micb_supply; + u32 micb_voltage; + u32 micb_current; + u32 version; + u32 is_used_va_swr_gpio; + int micb_users; + u16 default_clk_id; + u16 clk_id; + int tx_swr_clk_cnt; + int va_swr_clk_cnt; + int va_clk_status; + int tx_clk_status; + int dapm_tx_clk_status; + bool lpi_enable; + bool register_event_listener; + bool clk_div_switch; + int dec_mode[VA_MACRO_NUM_DECIMATORS]; + u16 current_clk_id; + int pcm_rate[VA_MACRO_NUM_DECIMATORS]; + bool dev_up; +}; + +static bool va_macro_get_data(struct snd_soc_component *component, + struct device **va_dev, + struct va_macro_priv **va_priv, + const char *func_name) +{ + *va_dev = bolero_get_device_ptr(component->dev, VA_MACRO); + if (!(*va_dev)) { + dev_err(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + *va_priv = dev_get_drvdata((*va_dev)); + if (!(*va_priv) || !(*va_priv)->component) { + dev_err(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + return true; +} + +static int va_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + if ((va_priv->version >= BOLERO_VERSION_2_0) + && va_priv->clk_div_switch + && (va_priv->dmic_clk_div == VA_MACRO_CLK_DIV_16)) + return VA_MACRO_CLK_DIV_8; + + return va_priv->dmic_clk_div; +} + +static int va_macro_mclk_enable(struct va_macro_priv *va_priv, + bool mclk_enable, bool dapm) +{ + struct regmap *regmap = dev_get_regmap(va_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(va_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(va_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n", + __func__, mclk_enable, dapm, va_priv->va_mclk_users); + + mutex_lock(&va_priv->mclk_lock); + if (mclk_enable) { + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, + true); + if (ret < 0) { + dev_err(va_priv->dev, + "%s: va request clock en failed\n", + __func__); + goto exit; + } + bolero_clk_rsc_fs_gen_request(va_priv->dev, + true); + if (va_priv->va_mclk_users == 0) { + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + VA_START_OFFSET, + VA_MAX_OFFSET); + } + va_priv->va_mclk_users++; + } else { + if (va_priv->va_mclk_users <= 0) { + dev_err(va_priv->dev, "%s: clock already disabled\n", + __func__); + va_priv->va_mclk_users = 0; + goto exit; + } + va_priv->va_mclk_users--; + bolero_clk_rsc_fs_gen_request(va_priv->dev, + false); + bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, + false); + } +exit: + mutex_unlock(&va_priv->mclk_lock); + return ret; +} + +static int va_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + int retry_cnt = MAX_RETRY_ATTEMPTS; + int ret = 0; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + switch (event) { + case BOLERO_MACRO_EVT_WAIT_VA_CLK_RESET: + while ((va_priv->va_mclk_users != 0) && (retry_cnt != 0)) { + dev_dbg_ratelimited(va_dev, "%s:retry_cnt: %d\n", + __func__, retry_cnt); + /* + * Userspace takes 10 seconds to close + * the session when pcm_start fails due to concurrency + * with PDR/SSR. Loop and check every 20ms till 10 + * seconds for va_mclk user count to get reset to 0 + * which ensures userspace teardown is done and SSR + * powerup seq can proceed. + */ + msleep(20); + retry_cnt--; + } + if (retry_cnt == 0) + dev_err(va_dev, + "%s: va_mclk_users is non-zero still, audio SSR fail!!\n", + __func__); + break; + case BOLERO_MACRO_EVT_PRE_SSR_UP: + /* enable&disable VA_CORE_CLK to reset GFMUX reg */ + va_macro_core_vote(va_priv, true); + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, true); + if (ret < 0) + dev_err_ratelimited(va_priv->dev, + "%s, failed to enable clk, ret:%d\n", + __func__, ret); + else + bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, false); + va_macro_core_vote(va_priv, false); + break; + case BOLERO_MACRO_EVT_SSR_UP: + /* reset swr after ssr/pdr */ + va_priv->reset_swr = true; + va_priv->dev_up = true; + if (va_priv->swr_ctrl_data) + swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case BOLERO_MACRO_EVT_CLK_RESET: + bolero_rsc_clk_reset(va_dev, VA_CORE_CLK); + break; + case BOLERO_MACRO_EVT_SSR_DOWN: + va_priv->dev_up = false; + if (va_priv->swr_ctrl_data) { + swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(va_dev) || + !pm_runtime_suspended(va_dev))) { + ret = bolero_runtime_suspend(va_dev); + if (!ret) { + pm_runtime_disable(va_dev); + pm_runtime_set_suspended(va_dev); + pm_runtime_enable(va_dev); + } + } + break; + default: + break; + } + return 0; +} + +static int va_macro_swr_clk_event_v2(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 device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + va_priv->va_swr_clk_cnt++; + break; + case SND_SOC_DAPM_POST_PMD: + va_priv->va_swr_clk_cnt--; + break; + default: + break; + } + return 0; +} + +static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n", + __func__, event, va_priv->lpi_enable); + + if (!va_priv->lpi_enable) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dev_dbg(component->dev, + "%s: va_swr_clk_cnt %d, tx_swr_clk_cnt %d, tx_clk_status %d\n", + __func__, va_priv->va_swr_clk_cnt, + va_priv->tx_swr_clk_cnt, va_priv->tx_clk_status); + if (va_priv->current_clk_id == VA_CORE_CLK) { + return 0; + } else if ( va_priv->va_swr_clk_cnt != 0 && + va_priv->tx_clk_status) { + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, + true); + if (ret) { + dev_dbg(component->dev, + "%s: request clock VA_CLK enable failed\n", + __func__); + break; + } + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + false); + if (ret) { + dev_dbg(component->dev, + "%s: request clock TX_CLK enable failed\n", + __func__); + bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, + false); + break; + } + va_priv->current_clk_id = VA_CORE_CLK; + } + break; + case SND_SOC_DAPM_POST_PMD: + if (va_priv->current_clk_id == VA_CORE_CLK) { + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + true); + if (ret) { + dev_err(component->dev, + "%s: request clock TX_CLK enable failed\n", + __func__); + if (va_priv->dev_up) + break; + } + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, + false); + if (ret) { + dev_err(component->dev, + "%s: request clock VA_CLK disable failed\n", + __func__); + if (va_priv->dev_up) + bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + break; + } + va_priv->current_clk_id = TX_CORE_CLK; + } + break; + default: + dev_err(va_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int va_macro_swr_pwr_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); + int ret = 0; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n", + __func__, event, va_priv->lpi_enable); + + if (!va_priv->lpi_enable) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (va_priv->lpass_audio_hw_vote) { + ret = digital_cdc_rsc_mgr_hw_vote_enable( + va_priv->lpass_audio_hw_vote, va_dev); + if (ret) + dev_err(va_dev, + "%s: lpass audio hw enable failed\n", + __func__); + } + if (!ret) { + if (bolero_tx_clk_switch(component, VA_CORE_CLK)) + dev_dbg(va_dev, "%s: clock switch failed\n", + __func__); + } + if (va_priv->lpi_enable) { + bolero_register_event_listener(component, true); + va_priv->register_event_listener = true; + } + break; + case SND_SOC_DAPM_POST_PMD: + if (va_priv->register_event_listener) { + va_priv->register_event_listener = false; + bolero_register_event_listener(component, false); + } + if (bolero_tx_clk_switch(component, TX_CORE_CLK)) + dev_dbg(va_dev, "%s: clock switch failed\n",__func__); + if (va_priv->lpass_audio_hw_vote) + digital_cdc_rsc_mgr_hw_vote_disable( + va_priv->lpass_audio_hw_vote, va_dev); + break; + default: + dev_err(va_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int va_macro_tx_swr_clk_event_v2(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + if (SND_SOC_DAPM_EVENT_ON(event)) + ++va_priv->tx_swr_clk_cnt; + if (SND_SOC_DAPM_EVENT_OFF(event)) + --va_priv->tx_swr_clk_cnt; + + return 0; +} + +static int va_macro_mclk_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); + int ret = 0; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + true); + if (!ret) + va_priv->dapm_tx_clk_status++; + + if (va_priv->lpi_enable) + ret = va_macro_mclk_enable(va_priv, 1, true); + else + ret = bolero_tx_mclk_enable(component, 1); + break; + case SND_SOC_DAPM_POST_PMD: + if (va_priv->lpi_enable) { + va_macro_mclk_enable(va_priv, 0, true); + } else { + bolero_tx_mclk_enable(component, 0); + } + + if (va_priv->dapm_tx_clk_status > 0) { + bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + false); + va_priv->dapm_tx_clk_status--; + } + break; + default: + dev_err(va_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int va_macro_tx_va_mclk_enable(struct va_macro_priv *va_priv, + struct regmap *regmap, int clk_type, + bool enable) +{ + int ret = 0, clk_tx_ret = 0; + + dev_dbg(va_priv->dev, + "%s: clock type %s, enable: %s tx_mclk_users: %d\n", + __func__, (clk_type ? "VA_MCLK" : "TX_MCLK"), + (enable ? "enable" : "disable"), va_priv->va_mclk_users); + + if (enable) { + if (va_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_select_active_state( + va_priv->va_swr_gpio_p); + msm_cdc_pinctrl_set_wakeup_capable( + va_priv->va_swr_gpio_p, false); + } + clk_tx_ret = bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + if (clk_type == TX_MCLK) { + ret = bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + if (ret < 0) { + if (va_priv->swr_clk_users == 0) + msm_cdc_pinctrl_select_sleep_state( + va_priv->va_swr_gpio_p); + dev_err_ratelimited(va_priv->dev, + "%s: swr request clk failed\n", + __func__); + goto done; + } + bolero_clk_rsc_fs_gen_request(va_priv->dev, + true); + } + if (clk_type == VA_MCLK) { + ret = va_macro_mclk_enable(va_priv, 1, true); + if (ret < 0) { + if (va_priv->swr_clk_users == 0) + msm_cdc_pinctrl_select_sleep_state( + va_priv->va_swr_gpio_p); + dev_err_ratelimited(va_priv->dev, + "%s: request clock enable failed\n", + __func__); + goto done; + } + } + if (va_priv->swr_clk_users == 0) { + dev_dbg(va_priv->dev, "%s: reset_swr: %d\n", + __func__, va_priv->reset_swr); + if (va_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (va_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + va_priv->reset_swr = false; + } + if (!clk_tx_ret) + ret = bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + va_priv->swr_clk_users++; + } else { + if (va_priv->swr_clk_users <= 0) { + dev_err_ratelimited(va_priv->dev, + "va swrm clock users already 0\n"); + va_priv->swr_clk_users = 0; + return 0; + } + clk_tx_ret = bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + va_priv->swr_clk_users--; + if (va_priv->swr_clk_users == 0) + regmap_update_bits(regmap, + BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + if (clk_type == VA_MCLK) + va_macro_mclk_enable(va_priv, 0, true); + if (clk_type == TX_MCLK) { + bolero_clk_rsc_fs_gen_request(va_priv->dev, + false); + ret = bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + if (ret < 0) { + dev_err_ratelimited(va_priv->dev, + "%s: swr request clk failed\n", + __func__); + goto done; + } + } + if (!clk_tx_ret) + ret = bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + if (va_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_set_wakeup_capable( + va_priv->va_swr_gpio_p, true); + msm_cdc_pinctrl_select_sleep_state( + va_priv->va_swr_gpio_p); + } + } + return 0; + +done: + if (!clk_tx_ret) + bolero_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + return ret; +} + +static int va_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct va_macro_priv *va_priv = (struct va_macro_priv *) handle; + + if (va_priv == NULL) { + pr_err("%s: va priv data is NULL\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(va_priv->dev); + if (bolero_check_core_votes(va_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(va_priv->dev); + pm_runtime_mark_last_busy(va_priv->dev); + } + return rc; +} + +static int va_macro_swrm_clock(void *handle, bool enable) +{ + struct va_macro_priv *va_priv = (struct va_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(va_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(va_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&va_priv->swr_clk_lock); + dev_dbg(va_priv->dev, + "%s: swrm clock %s tx_swr_clk_cnt: %d va_swr_clk_cnt: %d\n", + __func__, (enable ? "enable" : "disable"), + va_priv->tx_swr_clk_cnt, va_priv->va_swr_clk_cnt); + + if (enable) { + pm_runtime_get_sync(va_priv->dev); + if (va_priv->va_swr_clk_cnt && !va_priv->tx_swr_clk_cnt) { + ret = va_macro_tx_va_mclk_enable(va_priv, regmap, + VA_MCLK, enable); + if (ret) { + pm_runtime_mark_last_busy(va_priv->dev); + pm_runtime_put_autosuspend(va_priv->dev); + goto done; + } + va_priv->va_clk_status++; + } else { + ret = va_macro_tx_va_mclk_enable(va_priv, regmap, + TX_MCLK, enable); + if (ret) { + pm_runtime_mark_last_busy(va_priv->dev); + pm_runtime_put_autosuspend(va_priv->dev); + goto done; + } + va_priv->tx_clk_status++; + } + pm_runtime_mark_last_busy(va_priv->dev); + pm_runtime_put_autosuspend(va_priv->dev); + } else { + if (va_priv->va_clk_status && !va_priv->tx_clk_status) { + ret = va_macro_tx_va_mclk_enable(va_priv, regmap, + VA_MCLK, enable); + if (ret) + goto done; + --va_priv->va_clk_status; + } else if (!va_priv->va_clk_status && va_priv->tx_clk_status) { + ret = va_macro_tx_va_mclk_enable(va_priv, regmap, + TX_MCLK, enable); + if (ret) + goto done; + --va_priv->tx_clk_status; + } else if (va_priv->va_clk_status && va_priv->tx_clk_status) { + if (!va_priv->va_swr_clk_cnt && va_priv->tx_swr_clk_cnt) { + ret = va_macro_tx_va_mclk_enable(va_priv, regmap, + VA_MCLK, enable); + if (ret) + goto done; + --va_priv->va_clk_status; + } else { + ret = va_macro_tx_va_mclk_enable(va_priv, regmap, + TX_MCLK, enable); + if (ret) + goto done; + --va_priv->tx_clk_status; + } + + } else { + dev_dbg(va_priv->dev, + "%s: Both clocks are disabled\n", __func__); + } + } + dev_dbg(va_priv->dev, + "%s: swrm clock users %d tx_clk_sts_cnt: %d va_clk_sts_cnt: %d\n", + __func__, va_priv->swr_clk_users, va_priv->tx_clk_status, + va_priv->va_clk_status); +done: + mutex_unlock(&va_priv->swr_clk_lock); + return ret; +} + +static bool is_amic_enabled(struct snd_soc_component *component, int decimator) +{ + u16 adc_mux_reg = 0, adc_reg = 0; + u16 adc_n = BOLERO_ADC_MAX; + bool ret = false; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return ret; + + adc_mux_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 + + VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; + if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) { + if (va_priv->version == BOLERO_VERSION_2_1) + return true; + adc_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 + + VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; + adc_n = snd_soc_component_read(component, adc_reg) & + VA_MACRO_SWR_MIC_MUX_SEL_MASK; + if (adc_n < BOLERO_ADC_MAX) + return true; + } + + return ret; +} + +static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct va_macro_priv *va_priv; + struct snd_soc_component *component; + u16 dec_cfg_reg, hpf_gate_reg; + u8 hpf_cut_off_freq; + u16 adc_reg = 0, adc_n = 0; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + va_priv = hpf_work->va_priv; + component = va_priv->component; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = BOLERO_CDC_VA_TX0_TX_PATH_CFG0 + + VA_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + hpf_gate_reg = BOLERO_CDC_VA_TX0_TX_PATH_SEC2 + + VA_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + + dev_dbg(va_priv->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + if (is_amic_enabled(component, hpf_work->decimator)) { + adc_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 + + VA_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator; + adc_n = snd_soc_component_read(component, adc_reg) & + VA_MACRO_SWR_MIC_MUX_SEL_MASK; + /* analog mic clear TX hold */ + bolero_clear_amic_tx_hold(component->dev, adc_n); + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x02); + /* Add delay between toggle hpf gate based on sample rate */ + switch (va_priv->pcm_rate[hpf_work->decimator]) { + case 0: + usleep_range(125, 130); + break; + case 1: + usleep_range(62, 65); + break; + case 3: + usleep_range(31, 32); + break; + case 4: + usleep_range(20, 21); + break; + case 5: + usleep_range(10, 11); + break; + case 6: + usleep_range(5, 6); + break; + default: + usleep_range(125, 130); + } + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x01); + } else { + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x02); + /* Minimum 1 clk cycle delay is required as per HW spec */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x00); + } +} + +static void va_macro_mute_update_callback(struct work_struct *work) +{ + struct va_mute_work *va_mute_dwork; + struct snd_soc_component *component = NULL; + struct va_macro_priv *va_priv; + struct delayed_work *delayed_work; + u16 tx_vol_ctl_reg, decimator; + + delayed_work = to_delayed_work(work); + va_mute_dwork = container_of(delayed_work, struct va_mute_work, dwork); + va_priv = va_mute_dwork->va_priv; + component = va_priv->component; + decimator = va_mute_dwork->decimator; + + tx_vol_ctl_reg = + BOLERO_CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, 0x10, 0x00); + dev_dbg(va_priv->dev, "%s: decimator %u unmute\n", + __func__, decimator); +} + +static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + u16 mic_sel_reg, dmic_clk_reg; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX0_TX_PATH_CFG0; + break; + case BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX1_TX_PATH_CFG0; + break; + case BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX2_TX_PATH_CFG0; + break; + case BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX3_TX_PATH_CFG0; + break; + case BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX4_TX_PATH_CFG0; + break; + case BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX5_TX_PATH_CFG0; + break; + case BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX6_TX_PATH_CFG0; + break; + case BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG0: + mic_sel_reg = BOLERO_CDC_VA_TX7_TX_PATH_CFG0; + break; + default: + dev_err(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + if (strnstr(widget->name, "SMIC", strlen(widget->name))) { + if (val != 0) { + if (val < 5) { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x0 << 7); + } else { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x1 << 7); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + dmic_clk_reg = + BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL + + ((val - 5)/2) * 4; + snd_soc_component_update_bits(component, + dmic_clk_reg, + 0x0E, va_priv->dmic_clk_div << 0x1); + } + } + } else { + /* DMIC selected */ + if (val != 0) + snd_soc_component_update_bits(component, mic_sel_reg, + 1 << 7, 1 << 7); + } + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int va_macro_lpi_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = va_priv->lpi_enable; + + return 0; +} + +static int va_macro_lpi_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + va_priv->lpi_enable = ucontrol->value.integer.value[0]; + + return 0; +} + +static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + if (test_bit(dec_id, &va_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + return 0; +} + +static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + if (enable) + set_bit(dec_id, &va_priv->active_ch_mask[dai_id]); + else + clear_bit(dec_id, &va_priv->active_ch_mask[dai_id]); + + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static int va_macro_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); + unsigned int dmic = 0; + int ret = 0; + char *wname; + + wname = strpbrk(w->name, "01234567"); + 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: event %d DMIC%d\n", + __func__, event, dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + bolero_dmic_clk_enable(component, dmic, DMIC_VA, true); + break; + case SND_SOC_DAPM_POST_PMD: + bolero_dmic_clk_enable(component, dmic, DMIC_VA, false); + break; + } + + return 0; +} + +static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + unsigned int decimator; + u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + u8 hpf_cut_off_freq; + u16 adc_mux_reg = 0; + u16 tx_fs_reg = 0; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + int hpf_delay = BOLERO_CDC_VA_TX_DMIC_HPF_DELAY_MS; + int unmute_delay = BOLERO_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + decimator = w->shift; + + dev_dbg(va_dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = BOLERO_CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + hpf_gate_reg = BOLERO_CDC_VA_TX0_TX_PATH_SEC2 + + VA_MACRO_TX_PATH_OFFSET * decimator; + dec_cfg_reg = BOLERO_CDC_VA_TX0_TX_PATH_CFG0 + + VA_MACRO_TX_PATH_OFFSET * decimator; + tx_gain_ctl_reg = BOLERO_CDC_VA_TX0_TX_VOL_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + adc_mux_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 + + VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; + tx_fs_reg = BOLERO_CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + va_priv->pcm_rate[decimator] = (snd_soc_component_read(component, + tx_fs_reg) & 0x0F); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + dec_cfg_reg, 0x06, va_priv->dec_mode[decimator] << + VA_MACRO_ADC_MODE_CFG0_SHIFT); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + /* Enable TX CLK */ + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x20, 0x20); + if (!is_amic_enabled(component, decimator)) { + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x01, 0x00); + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + } + hpf_cut_off_freq = (snd_soc_component_read( + component, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + va_priv->va_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + } + if (is_amic_enabled(component, decimator) < BOLERO_ADC_MAX) { + hpf_delay = BOLERO_CDC_VA_TX_AMIC_HPF_DELAY_MS; + unmute_delay = BOLERO_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS; + if (va_tx_unmute_delay < unmute_delay) + va_tx_unmute_delay = unmute_delay; + } + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x02); + if (!is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x00); + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x01); + /* + * 6ms delay is required as per HW spec + */ + usleep_range(6000, 6010); + /* schedule work queue to Remove Mute */ + queue_delayed_work(system_freezable_wq, + &va_priv->va_mute_dwork[decimator].dwork, + msecs_to_jiffies(va_tx_unmute_delay)); + if (va_priv->va_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) + queue_delayed_work(system_freezable_wq, + &va_priv->va_hpf_work[decimator].dwork, + msecs_to_jiffies(hpf_delay)); + /* apply gain after decimator is enabled */ + snd_soc_component_write(component, tx_gain_ctl_reg, + snd_soc_component_read(component, tx_gain_ctl_reg)); + if (va_priv->version == BOLERO_VERSION_2_0) { + if (snd_soc_component_read(component, adc_mux_reg) + & SWR_MIC) { + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, + 0x01, 0x01); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC0_CTL, + 0x0E, 0x0C); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC1_CTL, + 0x0E, 0x0C); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC2_CTL, + 0x0E, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC3_CTL, + 0x0E, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC4_CTL, + 0x0E, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_MIC5_CTL, + 0x0E, 0x00); + } + } + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + va_priv->va_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + if (cancel_delayed_work_sync( + &va_priv->va_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(component, + dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + if (is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x02); + else + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x03); + /* + * Minimum 1 clk cycle delay is required + * as per HW spec + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x01); + } + } + cancel_delayed_work_sync( + &va_priv->va_mute_dwork[decimator].dwork); + if (va_priv->version == BOLERO_VERSION_2_0) { + if (snd_soc_component_read(component, adc_mux_reg) + & SWR_MIC) + snd_soc_component_update_bits(component, + BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, + 0x01, 0x00); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* Disable TX CLK */ + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x20, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x00); + break; + } + return 0; +} + +static int va_macro_enable_tx(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 device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + int ret = 0; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (va_priv->dapm_tx_clk_status > 0) { + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + false); + va_priv->dapm_tx_clk_status--; + } + break; + case SND_SOC_DAPM_PRE_PMD: + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + true); + if (!ret) + va_priv->dapm_tx_clk_status++; + break; + default: + dev_err(va_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + break; + } + + return ret; +} + +static int va_macro_enable_micbias(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 device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + int ret = 0; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + if (!va_priv->micb_supply) { + dev_err(va_dev, + "%s:regulator not provided in dtsi\n", __func__); + return -EINVAL; + } + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (va_priv->micb_users++ > 0) + return 0; + ret = regulator_set_voltage(va_priv->micb_supply, + va_priv->micb_voltage, + va_priv->micb_voltage); + if (ret) { + dev_err(va_dev, "%s: Setting voltage failed, err = %d\n", + __func__, ret); + return ret; + } + ret = regulator_set_load(va_priv->micb_supply, + va_priv->micb_current); + if (ret) { + dev_err(va_dev, "%s: Setting current failed, err = %d\n", + __func__, ret); + return ret; + } + ret = regulator_enable(va_priv->micb_supply); + if (ret) { + dev_err(va_dev, "%s: regulator enable failed, err = %d\n", + __func__, ret); + return ret; + } + break; + case SND_SOC_DAPM_POST_PMD: + if (--va_priv->micb_users > 0) + return 0; + if (va_priv->micb_users < 0) { + va_priv->micb_users = 0; + dev_dbg(va_dev, "%s: regulator already disabled\n", + __func__); + return 0; + } + ret = regulator_disable(va_priv->micb_supply); + if (ret) { + dev_err(va_dev, "%s: regulator disable failed, err = %d\n", + __func__, ret); + return ret; + } + regulator_set_voltage(va_priv->micb_supply, 0, + va_priv->micb_voltage); + regulator_set_load(va_priv->micb_supply, 0); + break; + } + return 0; +} + +static inline int va_macro_path_get(const char *wname, + unsigned int *path_num) +{ + int ret = 0; + char *widget_name = NULL; + char *w_name = NULL; + char *path_num_char = NULL; + char *path_name = NULL; + + widget_name = kstrndup(wname, 10, GFP_KERNEL); + if (!widget_name) + return -EINVAL; + + w_name = widget_name; + + path_name = strsep(&widget_name, " "); + if (!path_name) { + pr_err("%s: Invalid widget name = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto err; + } + path_num_char = strpbrk(path_name, "01234567"); + if (!path_num_char) { + pr_err("%s: va path index not found\n", + __func__); + ret = -EINVAL; + goto err; + } + ret = kstrtouint(path_num_char, 10, path_num); + if (ret < 0) + pr_err("%s: Invalid tx path = %s\n", + __func__, w_name); + +err: + kfree(w_name); + return ret; +} + +static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct va_macro_priv *priv = NULL; + struct device *va_dev = NULL; + int ret = 0; + int path = 0; + + if (!va_macro_get_data(component, &va_dev, &priv, __func__)) + return -EINVAL; + + ret = va_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = priv->dec_mode[path]; + + return 0; +} + +static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct va_macro_priv *priv = NULL; + struct device *va_dev = NULL; + int value = ucontrol->value.integer.value[0]; + int ret = 0; + int path = 0; + + if (!va_macro_get_data(component, &va_dev, &priv, __func__)) + return -EINVAL; + + ret = va_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + priv->dec_mode[path] = value; + + return 0; +} + +static int va_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int tx_fs_rate = -EINVAL; + struct snd_soc_component *component = dai->component; + u32 decimator, sample_rate; + u16 tx_fs_reg = 0; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + sample_rate = params_rate(params); + if (sample_rate > 16000) + va_priv->clk_div_switch = true; + else + va_priv->clk_div_switch = false; + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err(va_dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + } + for_each_set_bit(decimator, &va_priv->active_ch_mask[dai->id], + VA_MACRO_DEC_MAX) { + if (decimator >= 0) { + tx_fs_reg = BOLERO_CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + dev_dbg(va_dev, "%s: set DEC%u rate to %u\n", + __func__, decimator, sample_rate); + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, tx_fs_rate); + } else { + dev_err(va_dev, + "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int va_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case VA_MACRO_AIF1_CAP: + case VA_MACRO_AIF2_CAP: + case VA_MACRO_AIF3_CAP: + *tx_slot = va_priv->active_ch_mask[dai->id]; + *tx_num = hweight_long(va_priv->active_ch_mask[dai->id]); + break; + default: + dev_err(va_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static struct snd_soc_dai_ops va_macro_dai_ops = { + .hw_params = va_macro_hw_params, + .get_channel_map = va_macro_get_channel_map, +}; + +static struct snd_soc_dai_driver va_macro_dai[] = { + { + .name = "va_macro_tx1", + .id = VA_MACRO_AIF1_CAP, + .capture = { + .stream_name = "VA_AIF1 Capture", + .rates = VA_MACRO_RATES, + .formats = VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &va_macro_dai_ops, + }, + { + .name = "va_macro_tx2", + .id = VA_MACRO_AIF2_CAP, + .capture = { + .stream_name = "VA_AIF2 Capture", + .rates = VA_MACRO_RATES, + .formats = VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &va_macro_dai_ops, + }, + { + .name = "va_macro_tx3", + .id = VA_MACRO_AIF3_CAP, + .capture = { + .stream_name = "VA_AIF3 Capture", + .rates = VA_MACRO_RATES, + .formats = VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &va_macro_dai_ops, + }, +}; + +#define STRING(name) #name +#define VA_MACRO_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define VA_MACRO_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define VA_MACRO_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +static const char * const adc_mux_text[] = { + "MSM_DMIC", "SWR_MIC" +}; + +VA_MACRO_DAPM_ENUM(va_dec0, BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1, + 0, adc_mux_text); +VA_MACRO_DAPM_ENUM(va_dec1, BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1, + 0, adc_mux_text); +VA_MACRO_DAPM_ENUM(va_dec2, BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG1, + 0, adc_mux_text); +VA_MACRO_DAPM_ENUM(va_dec3, BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG1, + 0, adc_mux_text); +VA_MACRO_DAPM_ENUM(va_dec4, BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG1, + 0, adc_mux_text); +VA_MACRO_DAPM_ENUM(va_dec5, BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG1, + 0, adc_mux_text); +VA_MACRO_DAPM_ENUM(va_dec6, BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG1, + 0, adc_mux_text); +VA_MACRO_DAPM_ENUM(va_dec7, BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG1, + 0, adc_mux_text); + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", + "DMIC4", "DMIC5", "DMIC6", "DMIC7" +}; + +VA_MACRO_DAPM_ENUM_EXT(va_dmic0, BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_dmic1, BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_dmic2, BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_dmic3, BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_dmic4, BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_dmic5, BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_dmic6, BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_dmic7, BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const char * const smic_mux_text[] = { + "ZERO", "ADC0", "ADC1", "ADC2", "ADC3", + "SWR_DMIC0", "SWR_DMIC1", "SWR_DMIC2", "SWR_DMIC3", + "SWR_DMIC4", "SWR_DMIC5", "SWR_DMIC6", "SWR_DMIC7" +}; + +VA_MACRO_DAPM_ENUM_EXT(va_smic0, BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic1, BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic2, BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic3, BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic4, BOLERO_CDC_VA_INP_MUX_ADC_MUX4_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic5, BOLERO_CDC_VA_INP_MUX_ADC_MUX5_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic6, BOLERO_CDC_VA_INP_MUX_ADC_MUX6_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic7, BOLERO_CDC_VA_INP_MUX_ADC_MUX7_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const char * const smic_mux_text_v2[] = { + "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3", + "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7", + "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11" +}; + +VA_MACRO_DAPM_ENUM_EXT(va_smic0_v2, BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic1_v2, BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic2_v3, BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +VA_MACRO_DAPM_ENUM_EXT(va_smic3_v3, BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_aif1_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif2_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif3_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif1_cap_mixer_v2[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif2_cap_mixer_v2[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif3_cap_mixer_v2[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif1_cap_mixer_v3[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif2_cap_mixer_v3[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif3_cap_mixer_v3[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_soc_dapm_widget va_macro_dapm_widgets_common[] = { + SND_SOC_DAPM_AIF_OUT_E("VA_AIF1 CAP", "VA_AIF1 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0, + va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT_E("VA_AIF2 CAP", "VA_AIF2 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0, + va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT_E("VA_AIF3 CAP", "VA_AIF3 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0, + va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + VA_MACRO_DAPM_MUX("VA DMIC MUX0", 0, va_dmic0), + VA_MACRO_DAPM_MUX("VA DMIC MUX1", 0, va_dmic1), + + VA_MACRO_DAPM_MUX("VA SMIC MUX0", 0, va_smic0_v2), + VA_MACRO_DAPM_MUX("VA SMIC MUX1", 0, va_smic1_v2), + + SND_SOC_DAPM_INPUT("VA SWR_INPUT"), + + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + va_macro_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC0", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC1", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC2", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC3", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC4", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC5", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC6", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC7", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, VA_MACRO_DEC0, 0, + &va_dec0_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC1 MUX", SND_SOC_NOPM, VA_MACRO_DEC1, 0, + &va_dec1_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0, + va_macro_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v2[] = { + SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF1_CAP, 0, + va_aif1_cap_mixer_v2, ARRAY_SIZE(va_aif1_cap_mixer_v2)), + + SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF2_CAP, 0, + va_aif2_cap_mixer_v2, ARRAY_SIZE(va_aif2_cap_mixer_v2)), + + SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF3_CAP, 0, + va_aif3_cap_mixer_v2, ARRAY_SIZE(va_aif3_cap_mixer_v2)), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", 0, SND_SOC_NOPM, 0, 0, + va_macro_swr_pwr_event_v2, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_TX_SWR_CLK", -1, SND_SOC_NOPM, 0, 0, + va_macro_tx_swr_clk_event_v2, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", -1, SND_SOC_NOPM, 0, 0, + va_macro_swr_clk_event_v2, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v3[] = { + SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF1_CAP, 0, + va_aif1_cap_mixer_v3, ARRAY_SIZE(va_aif1_cap_mixer_v3)), + + SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF2_CAP, 0, + va_aif2_cap_mixer_v3, ARRAY_SIZE(va_aif2_cap_mixer_v3)), + + SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF3_CAP, 0, + va_aif3_cap_mixer_v3, ARRAY_SIZE(va_aif3_cap_mixer_v3)), + + VA_MACRO_DAPM_MUX("VA DMIC MUX2", 0, va_dmic2), + VA_MACRO_DAPM_MUX("VA DMIC MUX3", 0, va_dmic3), + + VA_MACRO_DAPM_MUX("VA SMIC MUX2", 0, va_smic2_v3), + VA_MACRO_DAPM_MUX("VA SMIC MUX3", 0, va_smic3_v3), + + SND_SOC_DAPM_MUX_E("VA DEC2 MUX", SND_SOC_NOPM, VA_MACRO_DEC2, 0, + &va_dec2_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC3 MUX", SND_SOC_NOPM, VA_MACRO_DEC3, 0, + &va_dec3_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", 0, SND_SOC_NOPM, 0, 0, + va_macro_swr_pwr_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT_E("VA_AIF1 CAP", "VA_AIF1 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0, + va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT_E("VA_AIF2 CAP", "VA_AIF2 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0, + va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT_E("VA_AIF3 CAP", "VA_AIF3 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0, + va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF1_CAP, 0, + va_aif1_cap_mixer, ARRAY_SIZE(va_aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF2_CAP, 0, + va_aif2_cap_mixer, ARRAY_SIZE(va_aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF3_CAP, 0, + va_aif3_cap_mixer, ARRAY_SIZE(va_aif3_cap_mixer)), + + VA_MACRO_DAPM_MUX("VA DMIC MUX0", 0, va_dmic0), + VA_MACRO_DAPM_MUX("VA DMIC MUX1", 0, va_dmic1), + VA_MACRO_DAPM_MUX("VA DMIC MUX2", 0, va_dmic2), + VA_MACRO_DAPM_MUX("VA DMIC MUX3", 0, va_dmic3), + VA_MACRO_DAPM_MUX("VA DMIC MUX4", 0, va_dmic4), + VA_MACRO_DAPM_MUX("VA DMIC MUX5", 0, va_dmic5), + VA_MACRO_DAPM_MUX("VA DMIC MUX6", 0, va_dmic6), + VA_MACRO_DAPM_MUX("VA DMIC MUX7", 0, va_dmic7), + + VA_MACRO_DAPM_MUX("VA SMIC MUX0", 0, va_smic0), + VA_MACRO_DAPM_MUX("VA SMIC MUX1", 0, va_smic1), + VA_MACRO_DAPM_MUX("VA SMIC MUX2", 0, va_smic2), + VA_MACRO_DAPM_MUX("VA SMIC MUX3", 0, va_smic3), + VA_MACRO_DAPM_MUX("VA SMIC MUX4", 0, va_smic4), + VA_MACRO_DAPM_MUX("VA SMIC MUX5", 0, va_smic5), + VA_MACRO_DAPM_MUX("VA SMIC MUX6", 0, va_smic6), + VA_MACRO_DAPM_MUX("VA SMIC MUX7", 0, va_smic7), + + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + va_macro_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC0", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC1", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC2", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC3", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC4", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC5", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC6", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC7", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("VA SWR_ADC0"), + SND_SOC_DAPM_INPUT("VA SWR_ADC1"), + SND_SOC_DAPM_INPUT("VA SWR_ADC2"), + SND_SOC_DAPM_INPUT("VA SWR_ADC3"), + SND_SOC_DAPM_INPUT("VA SWR_MIC0"), + SND_SOC_DAPM_INPUT("VA SWR_MIC1"), + SND_SOC_DAPM_INPUT("VA SWR_MIC2"), + SND_SOC_DAPM_INPUT("VA SWR_MIC3"), + SND_SOC_DAPM_INPUT("VA SWR_MIC4"), + SND_SOC_DAPM_INPUT("VA SWR_MIC5"), + SND_SOC_DAPM_INPUT("VA SWR_MIC6"), + SND_SOC_DAPM_INPUT("VA SWR_MIC7"), + + SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, VA_MACRO_DEC0, 0, + &va_dec0_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC1 MUX", SND_SOC_NOPM, VA_MACRO_DEC1, 0, + &va_dec1_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC2 MUX", SND_SOC_NOPM, VA_MACRO_DEC2, 0, + &va_dec2_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC3 MUX", SND_SOC_NOPM, VA_MACRO_DEC3, 0, + &va_dec3_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC4 MUX", SND_SOC_NOPM, VA_MACRO_DEC4, 0, + &va_dec4_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC5 MUX", SND_SOC_NOPM, VA_MACRO_DEC5, 0, + &va_dec5_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC6 MUX", SND_SOC_NOPM, VA_MACRO_DEC6, 0, + &va_dec6_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC7 MUX", SND_SOC_NOPM, VA_MACRO_DEC7, 0, + &va_dec7_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", -1, SND_SOC_NOPM, 0, 0, + va_macro_swr_pwr_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0, + va_macro_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget va_macro_wod_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0, + va_macro_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route va_audio_map_common[] = { + {"VA_AIF1 CAP", NULL, "VA_MCLK"}, + {"VA_AIF2 CAP", NULL, "VA_MCLK"}, + {"VA_AIF3 CAP", NULL, "VA_MCLK"}, + + {"VA_AIF1 CAP", NULL, "VA_AIF1_CAP Mixer"}, + {"VA_AIF2 CAP", NULL, "VA_AIF2_CAP Mixer"}, + {"VA_AIF3 CAP", NULL, "VA_AIF3_CAP Mixer"}, + + {"VA_AIF1_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + + {"VA_AIF2_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + + {"VA_AIF3_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + + {"VA DEC0 MUX", "MSM_DMIC", "VA DMIC MUX0"}, + {"VA DMIC MUX0", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX0", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX0", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX0", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX0", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX0", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX0", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX0", "DMIC7", "VA DMIC7"}, + + {"VA DEC0 MUX", "SWR_MIC", "VA SMIC MUX0"}, + {"VA SMIC MUX0", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC11", "VA SWR_INPUT"}, + + {"VA DEC1 MUX", "MSM_DMIC", "VA DMIC MUX1"}, + {"VA DMIC MUX1", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX1", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX1", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX1", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX1", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX1", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX1", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX1", "DMIC7", "VA DMIC7"}, + + {"VA DEC1 MUX", "SWR_MIC", "VA SMIC MUX1"}, + {"VA SMIC MUX1", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC11", "VA SWR_INPUT"}, + + {"VA SWR_INPUT", NULL, "VA_SWR_PWR"}, +}; + +static const struct snd_soc_dapm_route va_audio_map_v3[] = { + {"VA_AIF1_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA_AIF2_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA_AIF3_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA DEC2 MUX", "MSM_DMIC", "VA DMIC MUX2"}, + {"VA DMIC MUX2", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX2", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX2", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX2", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX2", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX2", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX2", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX2", "DMIC7", "VA DMIC7"}, + + {"VA DEC2 MUX", "SWR_MIC", "VA SMIC MUX2"}, + {"VA SMIC MUX2", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC11", "VA SWR_INPUT"}, + + {"VA DEC3 MUX", "MSM_DMIC", "VA DMIC MUX3"}, + {"VA DMIC MUX3", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX3", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX3", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX3", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX3", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX3", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX3", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX3", "DMIC7", "VA DMIC7"}, + + {"VA DEC3 MUX", "SWR_MIC", "VA SMIC MUX3"}, + {"VA SMIC MUX3", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC11", "VA SWR_INPUT"}, +}; + +static const struct snd_soc_dapm_route va_audio_map_v2[] = { + {"VA SWR_INPUT", NULL, "VA_SWR_CLK"}, +}; + +static const struct snd_soc_dapm_route va_audio_map[] = { + {"VA_AIF1 CAP", NULL, "VA_MCLK"}, + {"VA_AIF2 CAP", NULL, "VA_MCLK"}, + {"VA_AIF3 CAP", NULL, "VA_MCLK"}, + + {"VA_AIF1 CAP", NULL, "VA_AIF1_CAP Mixer"}, + {"VA_AIF2 CAP", NULL, "VA_AIF2_CAP Mixer"}, + {"VA_AIF3 CAP", NULL, "VA_AIF3_CAP Mixer"}, + + {"VA_AIF1_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC4", "VA DEC4 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC5", "VA DEC5 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC6", "VA DEC6 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC7", "VA DEC7 MUX"}, + + {"VA_AIF2_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC4", "VA DEC4 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC5", "VA DEC5 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC6", "VA DEC6 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC7", "VA DEC7 MUX"}, + + {"VA_AIF3_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC4", "VA DEC4 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC5", "VA DEC5 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC6", "VA DEC6 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC7", "VA DEC7 MUX"}, + + {"VA DEC0 MUX", "MSM_DMIC", "VA DMIC MUX0"}, + {"VA DMIC MUX0", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX0", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX0", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX0", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX0", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX0", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX0", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX0", "DMIC7", "VA DMIC7"}, + + {"VA DEC0 MUX", "SWR_MIC", "VA SMIC MUX0"}, + {"VA SMIC MUX0", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX0", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX0", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX0", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX0", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX0", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX0", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX0", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX0", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX0", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX0", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX0", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA DEC1 MUX", "MSM_DMIC", "VA DMIC MUX1"}, + {"VA DMIC MUX1", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX1", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX1", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX1", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX1", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX1", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX1", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX1", "DMIC7", "VA DMIC7"}, + + {"VA DEC1 MUX", "SWR_MIC", "VA SMIC MUX1"}, + {"VA SMIC MUX1", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX1", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX1", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX1", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX1", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX1", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX1", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX1", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX1", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX1", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX1", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX1", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA DEC2 MUX", "MSM_DMIC", "VA DMIC MUX2"}, + {"VA DMIC MUX2", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX2", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX2", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX2", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX2", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX2", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX2", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX2", "DMIC7", "VA DMIC7"}, + + {"VA DEC2 MUX", "SWR_MIC", "VA SMIC MUX2"}, + {"VA SMIC MUX2", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX2", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX2", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX2", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX2", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX2", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX2", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX2", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX2", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX2", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX2", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX2", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA DEC3 MUX", "MSM_DMIC", "VA DMIC MUX3"}, + {"VA DMIC MUX3", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX3", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX3", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX3", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX3", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX3", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX3", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX3", "DMIC7", "VA DMIC7"}, + + {"VA DEC3 MUX", "SWR_MIC", "VA SMIC MUX3"}, + {"VA SMIC MUX3", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX3", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX3", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX3", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX3", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX3", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX3", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX3", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX3", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX3", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX3", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX3", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA DEC4 MUX", "MSM_DMIC", "VA DMIC MUX4"}, + {"VA DMIC MUX4", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX4", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX4", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX4", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX4", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX4", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX4", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX4", "DMIC7", "VA DMIC7"}, + + {"VA DEC4 MUX", "SWR_MIC", "VA SMIC MUX4"}, + {"VA SMIC MUX4", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX4", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX4", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX4", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX4", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX4", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX4", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX4", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX4", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX4", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX4", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX4", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA DEC5 MUX", "MSM_DMIC", "VA DMIC MUX5"}, + {"VA DMIC MUX5", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX5", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX5", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX5", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX5", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX5", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX5", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX5", "DMIC7", "VA DMIC7"}, + + {"VA DEC5 MUX", "SWR_MIC", "VA SMIC MUX5"}, + {"VA SMIC MUX5", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX5", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX5", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX5", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX5", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX5", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX5", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX5", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX5", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX5", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX5", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX5", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA DEC6 MUX", "MSM_DMIC", "VA DMIC MUX6"}, + {"VA DMIC MUX6", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX6", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX6", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX6", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX6", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX6", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX6", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX6", "DMIC7", "VA DMIC7"}, + + {"VA DEC6 MUX", "SWR_MIC", "VA SMIC MUX6"}, + {"VA SMIC MUX6", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX6", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX6", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX6", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX6", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX6", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX6", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX6", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX6", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX6", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX6", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX6", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA DEC7 MUX", "MSM_DMIC", "VA DMIC MUX7"}, + {"VA DMIC MUX7", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX7", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX7", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX7", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX7", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX7", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX7", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX7", "DMIC7", "VA DMIC7"}, + + {"VA DEC7 MUX", "SWR_MIC", "VA SMIC MUX7"}, + {"VA SMIC MUX7", "ADC0", "VA SWR_ADC0"}, + {"VA SMIC MUX7", "ADC1", "VA SWR_ADC1"}, + {"VA SMIC MUX7", "ADC2", "VA SWR_ADC2"}, + {"VA SMIC MUX7", "ADC3", "VA SWR_ADC3"}, + {"VA SMIC MUX7", "SWR_DMIC0", "VA SWR_MIC0"}, + {"VA SMIC MUX7", "SWR_DMIC1", "VA SWR_MIC1"}, + {"VA SMIC MUX7", "SWR_DMIC2", "VA SWR_MIC2"}, + {"VA SMIC MUX7", "SWR_DMIC3", "VA SWR_MIC3"}, + {"VA SMIC MUX7", "SWR_DMIC4", "VA SWR_MIC4"}, + {"VA SMIC MUX7", "SWR_DMIC5", "VA SWR_MIC5"}, + {"VA SMIC MUX7", "SWR_DMIC6", "VA SWR_MIC6"}, + {"VA SMIC MUX7", "SWR_DMIC7", "VA SWR_MIC7"}, + + {"VA SWR_ADC0", NULL, "VA_SWR_PWR"}, + {"VA SWR_ADC1", NULL, "VA_SWR_PWR"}, + {"VA SWR_ADC2", NULL, "VA_SWR_PWR"}, + {"VA SWR_ADC3", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC0", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC1", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC2", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC3", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC4", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC5", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC6", NULL, "VA_SWR_PWR"}, + {"VA SWR_MIC7", NULL, "VA_SWR_PWR"}, +}; + +static const char * const dec_mode_mux_text[] = { + "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF", +}; + +static const struct soc_enum dec_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text); + +static const struct snd_kcontrol_new va_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("VA_DEC0 Volume", + BOLERO_CDC_VA_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC1 Volume", + BOLERO_CDC_VA_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC2 Volume", + BOLERO_CDC_VA_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC3 Volume", + BOLERO_CDC_VA_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC4 Volume", + BOLERO_CDC_VA_TX4_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC5 Volume", + BOLERO_CDC_VA_TX5_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC6 Volume", + BOLERO_CDC_VA_TX6_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC7 Volume", + BOLERO_CDC_VA_TX7_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0, + va_macro_lpi_get, va_macro_lpi_put), + + SOC_ENUM_EXT("VA_DEC0 MODE", dec_mode_mux_enum, + va_macro_dec_mode_get, va_macro_dec_mode_put), + + SOC_ENUM_EXT("VA_DEC1 MODE", dec_mode_mux_enum, + va_macro_dec_mode_get, va_macro_dec_mode_put), + + SOC_ENUM_EXT("VA_DEC2 MODE", dec_mode_mux_enum, + va_macro_dec_mode_get, va_macro_dec_mode_put), + + SOC_ENUM_EXT("VA_DEC3 MODE", dec_mode_mux_enum, + va_macro_dec_mode_get, va_macro_dec_mode_put), +}; + +static const struct snd_kcontrol_new va_macro_snd_controls_common[] = { + SOC_SINGLE_S8_TLV("VA_DEC0 Volume", + BOLERO_CDC_VA_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC1 Volume", + BOLERO_CDC_VA_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0, + va_macro_lpi_get, va_macro_lpi_put), +}; + +static const struct snd_kcontrol_new va_macro_snd_controls_v3[] = { + SOC_SINGLE_S8_TLV("VA_DEC2 Volume", + BOLERO_CDC_VA_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC3 Volume", + BOLERO_CDC_VA_TX3_TX_VOL_CTL, + -84, 40, digital_gain), +}; + +static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate, + struct va_macro_priv *va_priv) +{ + u32 div_factor; + u32 mclk_rate = VA_MACRO_MCLK_FREQ; + + if (dmic_sample_rate == VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED || + mclk_rate % dmic_sample_rate != 0) + goto undefined_rate; + + div_factor = mclk_rate / dmic_sample_rate; + + switch (div_factor) { + case 2: + va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_2; + break; + case 3: + va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_3; + break; + case 4: + va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_4; + break; + case 6: + va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_6; + break; + case 8: + va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_8; + break; + case 16: + va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_16; + break; + default: + /* Any other DIV factor is invalid */ + goto undefined_rate; + } + + /* Valid dmic DIV factors */ + dev_dbg(va_priv->dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n", + __func__, div_factor, mclk_rate); + + return dmic_sample_rate; + +undefined_rate: + dev_dbg(va_priv->dev, "%s: Invalid rate %d, for mclk %d\n", + __func__, dmic_sample_rate, mclk_rate); + dmic_sample_rate = VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED; + + return dmic_sample_rate; +} + +static int va_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret, i; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + va_dev = bolero_get_device_ptr(component->dev, VA_MACRO); + if (!va_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + va_priv = dev_get_drvdata(va_dev); + if (!va_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + + va_priv->lpi_enable = false; + va_priv->register_event_listener = false; + + if (va_priv->va_without_decimation) { + ret = snd_soc_dapm_new_controls(dapm, va_macro_wod_dapm_widgets, + ARRAY_SIZE(va_macro_wod_dapm_widgets)); + if (ret < 0) { + dev_err(va_dev, + "%s: Failed to add without dec controls\n", + __func__); + return ret; + } + va_priv->component = component; + return 0; + } + + va_priv->version = bolero_get_version(va_dev); + if (va_priv->version >= BOLERO_VERSION_2_0) { + ret = snd_soc_dapm_new_controls(dapm, + va_macro_dapm_widgets_common, + ARRAY_SIZE(va_macro_dapm_widgets_common)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + if ((va_priv->version == BOLERO_VERSION_2_1) || + (va_priv->version == BOLERO_VERSION_2_2)) + ret = snd_soc_dapm_new_controls(dapm, + va_macro_dapm_widgets_v2, + ARRAY_SIZE(va_macro_dapm_widgets_v2)); + else if (va_priv->version == BOLERO_VERSION_2_0) + ret = snd_soc_dapm_new_controls(dapm, + va_macro_dapm_widgets_v3, + ARRAY_SIZE(va_macro_dapm_widgets_v3)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + } else { + ret = snd_soc_dapm_new_controls(dapm, va_macro_dapm_widgets, + ARRAY_SIZE(va_macro_dapm_widgets)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + } + + if (va_priv->version >= BOLERO_VERSION_2_0) { + ret = snd_soc_dapm_add_routes(dapm, + va_audio_map_common, + ARRAY_SIZE(va_audio_map_common)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + if (va_priv->version == BOLERO_VERSION_2_0) { + ret = snd_soc_dapm_add_routes(dapm, + va_audio_map_v3, + ARRAY_SIZE(va_audio_map_v3)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + } + if ((va_priv->version == BOLERO_VERSION_2_1) || + (va_priv->version == BOLERO_VERSION_2_2)) { + ret = snd_soc_dapm_add_routes(dapm, + va_audio_map_v2, + ARRAY_SIZE(va_audio_map_v2)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + } + } else { + ret = snd_soc_dapm_add_routes(dapm, va_audio_map, + ARRAY_SIZE(va_audio_map)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + } + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add widgets\n", __func__); + return ret; + } + if (va_priv->version >= BOLERO_VERSION_2_0) { + ret = snd_soc_add_component_controls(component, + va_macro_snd_controls_common, + ARRAY_SIZE(va_macro_snd_controls_common)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + if (va_priv->version == BOLERO_VERSION_2_0) + ret = snd_soc_add_component_controls(component, + va_macro_snd_controls_v3, + ARRAY_SIZE(va_macro_snd_controls_v3)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + } else { + ret = snd_soc_add_component_controls(component, + va_macro_snd_controls, + ARRAY_SIZE(va_macro_snd_controls)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + } + + snd_soc_dapm_ignore_suspend(dapm, "VA_AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "VA_AIF2 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "VA_AIF3 Capture"); + if (va_priv->version >= BOLERO_VERSION_2_0) { + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_INPUT"); + } else { + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC0"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC1"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC2"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC3"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC0"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC1"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC2"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC3"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC4"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC5"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC6"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC7"); + } + snd_soc_dapm_sync(dapm); + + va_priv->dev_up = true; + + for (i = 0; i < VA_MACRO_NUM_DECIMATORS; i++) { + va_priv->va_hpf_work[i].va_priv = va_priv; + va_priv->va_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&va_priv->va_hpf_work[i].dwork, + va_macro_tx_hpf_corner_freq_callback); + } + + for (i = 0; i < VA_MACRO_NUM_DECIMATORS; i++) { + va_priv->va_mute_dwork[i].va_priv = va_priv; + va_priv->va_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&va_priv->va_mute_dwork[i].dwork, + va_macro_mute_update_callback); + } + va_priv->component = component; + + if ((va_priv->version == BOLERO_VERSION_2_1) || + (va_priv->version == BOLERO_VERSION_2_2)) { + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE, 0xCC); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE, 0xCC); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE, 0xCC); + } + + return 0; +} + +static int va_macro_deinit(struct snd_soc_component *component) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + va_priv->component = NULL; + return 0; +} + +static void va_macro_add_child_devices(struct work_struct *work) +{ + struct va_macro_priv *va_priv = NULL; + struct platform_device *pdev = NULL; + struct device_node *node = NULL; + struct va_macro_swr_ctrl_data *swr_ctrl_data = NULL, *temp = NULL; + int ret = 0; + u16 count = 0, ctrl_num = 0; + struct va_macro_swr_ctrl_platform_data *platdata = NULL; + char plat_dev_name[VA_MACRO_SWR_STRING_LEN] = ""; + bool va_swr_master_node = false; + + va_priv = container_of(work, struct va_macro_priv, + va_macro_add_child_devices_work); + if (!va_priv) { + pr_err("%s: Memory for va_priv does not exist\n", + __func__); + return; + } + + if (!va_priv->dev) { + pr_err("%s: VA dev does not exist\n", __func__); + return; + } + + if (!va_priv->dev->of_node) { + dev_err(va_priv->dev, + "%s: DT node for va_priv does not exist\n", __func__); + return; + } + + platdata = &va_priv->swr_plat_data; + va_priv->child_count = 0; + + for_each_available_child_of_node(va_priv->dev->of_node, node) { + va_swr_master_node = false; + if (strnstr(node->name, "va_swr_master", + strlen("va_swr_master")) != NULL) + va_swr_master_node = true; + + if (va_swr_master_node) + strlcpy(plat_dev_name, "va_swr_ctrl", + (VA_MACRO_SWR_STRING_LEN - 1)); + else + strlcpy(plat_dev_name, node->name, + (VA_MACRO_SWR_STRING_LEN - 1)); + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(va_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = va_priv->dev; + pdev->dev.of_node = node; + + if (va_swr_master_node) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct va_macro_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].va_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + va_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (va_priv->child_count < VA_MACRO_CHILD_DEVICES_MAX) + va_priv->pdev_child_devices[ + va_priv->child_count++] = pdev; + else + goto err; + } + return; +fail_pdev_add: + for (count = 0; count < va_priv->child_count; count++) + platform_device_put(va_priv->pdev_child_devices[count]); +err: + return; +} + +static int va_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (va_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +static int va_macro_reg_wake_irq(struct snd_soc_component *component, + u32 data) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + u32 ipc_wakeup = data; + int ret = 0; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + if (va_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_REGISTER_WAKE_IRQ, &ipc_wakeup); + + return ret; +} + +static void va_macro_init_ops(struct macro_ops *ops, + char __iomem *va_io_base, + bool va_without_decimation) +{ + memset(ops, 0, sizeof(struct macro_ops)); + if (!va_without_decimation) { + ops->dai_ptr = va_macro_dai; + ops->num_dais = ARRAY_SIZE(va_macro_dai); + } else { + ops->dai_ptr = NULL; + ops->num_dais = 0; + } + ops->init = va_macro_init; + ops->exit = va_macro_deinit; + ops->io_base = va_io_base; + ops->event_handler = va_macro_event_handler; + ops->set_port_map = va_macro_set_port_map; + ops->reg_wake_irq = va_macro_reg_wake_irq; + ops->clk_div_get = va_macro_clk_div_get; +} + +static int va_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops; + struct va_macro_priv *va_priv; + u32 va_base_addr, sample_rate = 0; + char __iomem *va_io_base; + bool va_without_decimation = false; + const char *micb_supply_str = "va-vdd-micb-supply"; + const char *micb_supply_str1 = "va-vdd-micb"; + const char *micb_voltage_str = "qcom,va-vdd-micb-voltage"; + const char *micb_current_str = "qcom,va-vdd-micb-current"; + int ret = 0; + const char *dmic_sample_rate = "qcom,va-dmic-sample-rate"; + u32 default_clk_id = 0; + struct clk *lpass_audio_hw_vote = NULL; + u32 is_used_va_swr_gpio = 0; + const char *is_used_va_swr_gpio_dt = "qcom,is-used-swr-gpio"; + + va_priv = devm_kzalloc(&pdev->dev, sizeof(struct va_macro_priv), + GFP_KERNEL); + if (!va_priv) + return -ENOMEM; + + va_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &va_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + va_without_decimation = of_property_read_bool(pdev->dev.parent->of_node, + "qcom,va-without-decimation"); + + va_priv->va_without_decimation = va_without_decimation; + ret = of_property_read_u32(pdev->dev.of_node, dmic_sample_rate, + &sample_rate); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %d entry in dt\n", + __func__, sample_rate); + va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_2; + } else { + if (va_macro_validate_dmic_sample_rate( + sample_rate, va_priv) == VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED) + return -EINVAL; + } + + if (of_find_property(pdev->dev.of_node, is_used_va_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_va_swr_gpio_dt, + &is_used_va_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_va_swr_gpio_dt); + is_used_va_swr_gpio = 0; + } + } + + va_priv->va_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,va-swr-gpios", 0); + if (!va_priv->va_swr_gpio_p && is_used_va_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if ((msm_cdc_pinctrl_get_state(va_priv->va_swr_gpio_p) < 0) && + is_used_va_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + + va_io_base = devm_ioremap(&pdev->dev, va_base_addr, + VA_MACRO_MAX_OFFSET); + if (!va_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -EINVAL; + } + va_priv->va_io_base = va_io_base; + + lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); + if (IS_ERR(lpass_audio_hw_vote)) { + ret = PTR_ERR(lpass_audio_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_audio_hw_vote", ret); + lpass_audio_hw_vote = NULL; + ret = 0; + } + va_priv->lpass_audio_hw_vote = lpass_audio_hw_vote; + + if (of_parse_phandle(pdev->dev.of_node, micb_supply_str, 0)) { + va_priv->micb_supply = devm_regulator_get(&pdev->dev, + micb_supply_str1); + if (IS_ERR(va_priv->micb_supply)) { + ret = PTR_ERR(va_priv->micb_supply); + dev_err(&pdev->dev, + "%s:Failed to get micbias supply for VA Mic %d\n", + __func__, ret); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, + micb_voltage_str, + &va_priv->micb_voltage); + if (ret) { + dev_err(&pdev->dev, + "%s:Looking up %s property in node %s failed\n", + __func__, micb_voltage_str, + pdev->dev.of_node->full_name); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, + micb_current_str, + &va_priv->micb_current); + if (ret) { + dev_err(&pdev->dev, + "%s:Looking up %s property in node %s failed\n", + __func__, micb_current_str, + pdev->dev.of_node->full_name); + return ret; + } + } + ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id", + &default_clk_id); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,default-clk-id"); + default_clk_id = VA_CORE_CLK; + } + va_priv->clk_id = VA_CORE_CLK; + va_priv->default_clk_id = default_clk_id; + va_priv->current_clk_id = TX_CORE_CLK; + + if (is_used_va_swr_gpio) { + va_priv->reset_swr = true; + INIT_WORK(&va_priv->va_macro_add_child_devices_work, + va_macro_add_child_devices); + va_priv->swr_plat_data.handle = (void *) va_priv; + va_priv->swr_plat_data.read = NULL; + va_priv->swr_plat_data.write = NULL; + va_priv->swr_plat_data.bulk_write = NULL; + va_priv->swr_plat_data.clk = va_macro_swrm_clock; + va_priv->swr_plat_data.core_vote = va_macro_core_vote; + va_priv->swr_plat_data.handle_irq = NULL; + mutex_init(&va_priv->swr_clk_lock); + } + va_priv->is_used_va_swr_gpio = is_used_va_swr_gpio; + + mutex_init(&va_priv->mclk_lock); + dev_set_drvdata(&pdev->dev, va_priv); + va_macro_init_ops(&ops, va_io_base, va_without_decimation); + ops.clk_id_req = va_priv->default_clk_id; + ops.default_clk_id = va_priv->default_clk_id; + ret = bolero_register_macro(&pdev->dev, VA_MACRO, &ops); + if (ret < 0) { + dev_err(&pdev->dev, "%s: register macro failed\n", __func__); + goto reg_macro_fail; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, VA_AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + if (is_used_va_swr_gpio) + schedule_work(&va_priv->va_macro_add_child_devices_work); + return ret; + +reg_macro_fail: + mutex_destroy(&va_priv->mclk_lock); + if (is_used_va_swr_gpio) + mutex_destroy(&va_priv->swr_clk_lock); + return ret; +} + +static int va_macro_remove(struct platform_device *pdev) +{ + struct va_macro_priv *va_priv; + int count = 0; + + va_priv = dev_get_drvdata(&pdev->dev); + + if (!va_priv) + return -EINVAL; + if (va_priv->is_used_va_swr_gpio) { + if (va_priv->swr_ctrl_data) + kfree(va_priv->swr_ctrl_data); + for (count = 0; count < va_priv->child_count && + count < VA_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister( + va_priv->pdev_child_devices[count]); + } + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + bolero_unregister_macro(&pdev->dev, VA_MACRO); + mutex_destroy(&va_priv->mclk_lock); + if (va_priv->is_used_va_swr_gpio) + mutex_destroy(&va_priv->swr_clk_lock); + return 0; +} + + +static const struct of_device_id va_macro_dt_match[] = { + {.compatible = "qcom,va-macro"}, + {} +}; + +static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + bolero_runtime_suspend, + bolero_runtime_resume, + NULL + ) +}; + +static struct platform_driver va_macro_driver = { + .driver = { + .name = "va_macro", + .owner = THIS_MODULE, + .pm = &bolero_dev_pm_ops, + .of_match_table = va_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = va_macro_probe, + .remove = va_macro_remove, +}; + +module_platform_driver(va_macro_driver); + +MODULE_DESCRIPTION("VA macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/wsa-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/bolero/wsa-macro.c new file mode 100644 index 0000000000..2257303706 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/wsa-macro.c @@ -0,0 +1,3362 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "bolero-cdc.h" +#include "bolero-cdc-registers.h" +#include "wsa-macro.h" +#include "bolero-clk-rsc.h" + +#define AUTO_SUSPEND_DELAY 50 /* delay in msec */ +#define WSA_MACRO_MAX_OFFSET 0x1000 + +#define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define WSA_MACRO_RX_MIX_RATES (SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define WSA_MACRO_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define WSA_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_48000) +#define WSA_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define NUM_INTERPOLATORS 2 + +#define WSA_MACRO_MUX_INP_SHFT 0x3 +#define WSA_MACRO_MUX_INP_MASK1 0x07 +#define WSA_MACRO_MUX_INP_MASK2 0x38 +#define WSA_MACRO_MUX_CFG_OFFSET 0x8 +#define WSA_MACRO_MUX_CFG1_OFFSET 0x4 +#define WSA_MACRO_RX_COMP_OFFSET 0x40 +#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40 +#define WSA_MACRO_RX_PATH_OFFSET 0x80 +#define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10 +#define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C +#define WSA_MACRO_FS_RATE_MASK 0x0F +#define WSA_MACRO_EC_MIX_TX0_MASK 0x03 +#define WSA_MACRO_EC_MIX_TX1_MASK 0x18 + +#define WSA_MACRO_MAX_DMA_CH_PER_PORT 0x2 + +enum { + WSA_MACRO_RX0 = 0, + WSA_MACRO_RX1, + WSA_MACRO_RX_MIX, + WSA_MACRO_RX_MIX0 = WSA_MACRO_RX_MIX, + WSA_MACRO_RX_MIX1, + WSA_MACRO_RX_MAX, +}; + +enum { + WSA_MACRO_TX0 = 0, + WSA_MACRO_TX1, + WSA_MACRO_TX_MAX, +}; + +enum { + WSA_MACRO_EC0_MUX = 0, + WSA_MACRO_EC1_MUX, + WSA_MACRO_EC_MUX_MAX, +}; + +enum { + WSA_MACRO_COMP1, /* SPK_L */ + WSA_MACRO_COMP2, /* SPK_R */ + WSA_MACRO_COMP_MAX +}; + +enum { + WSA_MACRO_SOFTCLIP0, /* RX0 */ + WSA_MACRO_SOFTCLIP1, /* RX1 */ + WSA_MACRO_SOFTCLIP_MAX +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +/* + * Structure used to update codec + * register defaults after reset + */ +struct wsa_macro_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static struct interp_sample_rate int_prim_sample_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +static struct interp_sample_rate int_mix_sample_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +#define WSA_MACRO_SWR_STRING_LEN 80 + +static int wsa_macro_core_vote(void *handle, bool enable); +static int wsa_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); +static int wsa_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream); +/* Hold instance to soundwire platform device */ +struct wsa_macro_swr_ctrl_data { + struct platform_device *wsa_swr_pdev; +}; + +struct wsa_macro_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +struct wsa_macro_bcl_pmic_params { + u8 id; + u8 sid; + u8 ppid; +}; + +enum { + WSA_MACRO_AIF_INVALID = 0, + WSA_MACRO_AIF1_PB, + WSA_MACRO_AIF_MIX1_PB, + WSA_MACRO_AIF_VI, + WSA_MACRO_AIF_ECHO, + WSA_MACRO_MAX_DAIS, +}; + +#define WSA_MACRO_CHILD_DEVICES_MAX 3 + +/* + * @dev: wsa macro device pointer + * @comp_enabled: compander enable mixer value set + * @ec_hq: echo HQ enable mixer value set + * @prim_int_users: Users of interpolator + * @wsa_mclk_users: WSA MCLK users count + * @swr_clk_users: SWR clk users count + * @vi_feed_value: VI sense mask + * @mclk_lock: to lock mclk operations + * @swr_clk_lock: to lock swr master clock operations + * @swr_ctrl_data: SoundWire data structure + * @swr_plat_data: Soundwire platform data + * @wsa_macro_add_child_devices_work: work for adding child devices + * @wsa_swr_gpio_p: used by pinctrl API + * @component: codec handle + * @rx_0_count: RX0 interpolation users + * @rx_1_count: RX1 interpolation users + * @active_ch_mask: channel mask for all AIF DAIs + * @rx_port_value: mixer ctl value of WSA RX MUXes + * @wsa_io_base: Base address of WSA macro addr space + */ +struct wsa_macro_priv { + struct device *dev; + int comp_enabled[WSA_MACRO_COMP_MAX]; + int ec_hq[WSA_MACRO_RX1 + 1]; + u16 prim_int_users[WSA_MACRO_RX1 + 1]; + u16 wsa_mclk_users; + u16 swr_clk_users; + bool dapm_mclk_enable; + bool reset_swr; + unsigned int vi_feed_value; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct wsa_macro_swr_ctrl_data *swr_ctrl_data; + struct wsa_macro_swr_ctrl_platform_data swr_plat_data; + struct work_struct wsa_macro_add_child_devices_work; + struct device_node *wsa_swr_gpio_p; + struct snd_soc_component *component; + int rx_0_count; + int rx_1_count; + unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS]; + int rx_port_value[WSA_MACRO_RX_MAX]; + char __iomem *wsa_io_base; + struct platform_device *pdev_child_devices + [WSA_MACRO_CHILD_DEVICES_MAX]; + int child_count; + int ear_spkr_gain; + int wsa_spkrrecv; + int spkr_gain_offset; + int spkr_mode; + int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX]; + int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX]; + struct wsa_macro_bcl_pmic_params bcl_pmic_params; + char __iomem *mclk_mode_muxsel; + u16 default_clk_id; + u32 pcm_rate_vi; + int wsa_digital_mute_status[WSA_MACRO_RX_MAX]; +}; + +static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component, + struct wsa_macro_priv *wsa_priv, + int event, int gain_reg); +static struct snd_soc_dai_driver wsa_macro_dai[]; +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +static const char *const rx_text[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1" +}; + +static const char *const rx_mix_text[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1" +}; + +static const char *const rx_mix_ec_text[] = { + "ZERO", "RX_MIX_TX0", "RX_MIX_TX1" +}; + +static const char *const rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF_MIX1_PB" +}; + +static const char *const rx_sidetone_mix_text[] = { + "ZERO", "SRC0" +}; + +static const char * const wsa_macro_ear_spkr_pa_gain_text[] = { + "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB", + "G_4_DB", "G_5_DB", "G_6_DB" +}; + +static const char * const wsa_macro_speaker_boost_stage_text[] = { + "NO_MAX_STATE", "MAX_STATE_1", "MAX_STATE_2" +}; + +static const char * const wsa_macro_vbat_bcl_gsm_mode_text[] = { + "OFF", "ON" +}; + +static const struct snd_kcontrol_new wsa_int0_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("WSA RX0 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new wsa_int1_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("WSA RX1 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const char *const wsa_macro_ear_spkrrecv_text[] = { + "OFF", "ON" +}; +static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkrrecv_enum, + wsa_macro_ear_spkrrecv_text); +static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum, + wsa_macro_ear_spkr_pa_gain_text); +static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_spkr_boost_stage_enum, + wsa_macro_speaker_boost_stage_text); +static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_vbat_bcl_gsm_mode_enum, + wsa_macro_vbat_bcl_gsm_mode_text); + +/* RX INT0 */ +static const struct soc_enum rx0_prim_inp0_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 0, 7, rx_text); + +static const struct soc_enum rx0_prim_inp1_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 3, 7, rx_text); + +static const struct soc_enum rx0_prim_inp2_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 3, 7, rx_text); + +static const struct soc_enum rx0_mix_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 0, 5, rx_mix_text); + +static const struct soc_enum rx0_sidetone_mix_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text); + +static const struct snd_kcontrol_new rx0_prim_inp0_mux = + SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum); + +static const struct snd_kcontrol_new rx0_prim_inp1_mux = + SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum); + +static const struct snd_kcontrol_new rx0_prim_inp2_mux = + SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum); + +static const struct snd_kcontrol_new rx0_mix_mux = + SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum); + +static const struct snd_kcontrol_new rx0_sidetone_mix_mux = + SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum); + +/* RX INT1 */ +static const struct soc_enum rx1_prim_inp0_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 0, 7, rx_text); + +static const struct soc_enum rx1_prim_inp1_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 3, 7, rx_text); + +static const struct soc_enum rx1_prim_inp2_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 3, 7, rx_text); + +static const struct soc_enum rx1_mix_chain_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 0, 5, rx_mix_text); + +static const struct snd_kcontrol_new rx1_prim_inp0_mux = + SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum); + +static const struct snd_kcontrol_new rx1_prim_inp1_mux = + SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum); + +static const struct snd_kcontrol_new rx1_prim_inp2_mux = + SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum); + +static const struct snd_kcontrol_new rx1_mix_mux = + SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum); + +static const struct soc_enum rx_mix_ec0_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 0, 3, rx_mix_ec_text); + +static const struct soc_enum rx_mix_ec1_enum = + SOC_ENUM_SINGLE(BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 3, 3, rx_mix_ec_text); + +static const struct snd_kcontrol_new rx_mix_ec0_mux = + SOC_DAPM_ENUM("WSA RX_MIX EC0_Mux", rx_mix_ec0_enum); + +static const struct snd_kcontrol_new rx_mix_ec1_mux = + SOC_DAPM_ENUM("WSA RX_MIX EC1_Mux", rx_mix_ec1_enum); + +static struct snd_soc_dai_ops wsa_macro_dai_ops = { + .hw_params = wsa_macro_hw_params, + .get_channel_map = wsa_macro_get_channel_map, + .mute_stream = wsa_macro_mute_stream, +}; + +static struct snd_soc_dai_driver wsa_macro_dai[] = { + { + .name = "wsa_macro_rx1", + .id = WSA_MACRO_AIF1_PB, + .playback = { + .stream_name = "WSA_AIF1 Playback", + .rates = WSA_MACRO_RX_RATES, + .formats = WSA_MACRO_RX_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_rx_mix", + .id = WSA_MACRO_AIF_MIX1_PB, + .playback = { + .stream_name = "WSA_AIF_MIX1 Playback", + .rates = WSA_MACRO_RX_MIX_RATES, + .formats = WSA_MACRO_RX_FORMATS, + .rate_max = 192000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_vifeedback", + .id = WSA_MACRO_AIF_VI, + .capture = { + .stream_name = "WSA_AIF_VI Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000, + .formats = WSA_MACRO_RX_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_echo", + .id = WSA_MACRO_AIF_ECHO, + .capture = { + .stream_name = "WSA_AIF_ECHO Capture", + .rates = WSA_MACRO_ECHO_RATES, + .formats = WSA_MACRO_ECHO_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wsa_macro_dai_ops, + }, +}; + +static const struct wsa_macro_reg_mask_val wsa_macro_spkr_default[] = { + {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80}, + {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80}, + {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01}, + {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01}, + {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58}, + {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58}, +}; + +static const struct wsa_macro_reg_mask_val wsa_macro_spkr_mode1[] = { + {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00}, + {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00}, + {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00}, + {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00}, + {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44}, + {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44}, +}; + +static bool wsa_macro_get_data(struct snd_soc_component *component, + struct device **wsa_dev, + struct wsa_macro_priv **wsa_priv, + const char *func_name) +{ + *wsa_dev = bolero_get_device_ptr(component->dev, WSA_MACRO); + if (!(*wsa_dev)) { + dev_err(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + *wsa_priv = dev_get_drvdata((*wsa_dev)); + if (!(*wsa_priv) || !(*wsa_priv)->component) { + dev_err(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + return true; +} + +static int wsa_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (wsa_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +/** + * wsa_macro_set_spkr_gain_offset - offset the speaker path + * gain with the given offset value. + * + * @component: codec instance + * @offset: Indicates speaker path gain offset value. + * + * Returns 0 on success or -EINVAL on error. + */ +int wsa_macro_set_spkr_gain_offset(struct snd_soc_component *component, + int offset) +{ + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!component) { + pr_err("%s: NULL component pointer!\n", __func__); + return -EINVAL; + } + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->spkr_gain_offset = offset; + return 0; +} +EXPORT_SYMBOL(wsa_macro_set_spkr_gain_offset); + +/** + * wsa_macro_set_spkr_mode - Configures speaker compander and smartboost + * settings based on speaker mode. + * + * @component: codec instance + * @mode: Indicates speaker configuration mode. + * + * Returns 0 on success or -EINVAL on error. + */ +int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode) +{ + int i; + const struct wsa_macro_reg_mask_val *regs; + int size; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!component) { + pr_err("%s: NULL codec pointer!\n", __func__); + return -EINVAL; + } + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (mode) { + case WSA_MACRO_SPKR_MODE_1: + regs = wsa_macro_spkr_mode1; + size = ARRAY_SIZE(wsa_macro_spkr_mode1); + break; + default: + regs = wsa_macro_spkr_default; + size = ARRAY_SIZE(wsa_macro_spkr_default); + break; + } + + wsa_priv->spkr_mode = mode; + for (i = 0; i < size; i++) + snd_soc_component_update_bits(component, regs[i].reg, + regs[i].mask, regs[i].val); + return 0; +} +EXPORT_SYMBOL(wsa_macro_set_spkr_mode); + +static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 int_prim_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp; + u32 j, port; + u16 int_mux_cfg0, int_mux_cfg1; + u16 int_fs_reg; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 inp0_sel, inp1_sel, inp2_sel; + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + for_each_set_bit(port, &wsa_priv->active_ch_mask[dai->id], + WSA_MACRO_RX_MAX) { + int_1_mix1_inp = port; + if ((int_1_mix1_inp < WSA_MACRO_RX0) || + (int_1_mix1_inp > WSA_MACRO_RX_MIX1)) { + dev_err(wsa_dev, + "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the cdc_dma rx port + * is connected + */ + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET; + + int_mux_cfg0_val = snd_soc_component_read(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1; + inp1_sel = (int_mux_cfg0_val >> + WSA_MACRO_MUX_INP_SHFT) & + WSA_MACRO_MUX_INP_MASK1; + inp2_sel = (int_mux_cfg1_val >> + WSA_MACRO_MUX_INP_SHFT) & + WSA_MACRO_MUX_INP_MASK1; + if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { + int_fs_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL + + WSA_MACRO_RX_PATH_OFFSET * j; + dev_dbg(wsa_dev, + "%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + dev_dbg(wsa_dev, + "%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + /* sample_rate is in Hz */ + snd_soc_component_update_bits(component, + int_fs_reg, + WSA_MACRO_FS_RATE_MASK, + int_prim_fs_rate_reg_val); + } + int_mux_cfg0 += WSA_MACRO_MUX_CFG_OFFSET; + } + } + + return 0; +} + +static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 int_mix_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp; + u32 j, port; + u16 int_mux_cfg1, int_fs_reg; + u8 int_mux_cfg1_val; + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + + for_each_set_bit(port, &wsa_priv->active_ch_mask[dai->id], + WSA_MACRO_RX_MAX) { + int_2_inp = port; + if ((int_2_inp < WSA_MACRO_RX0) || + (int_2_inp > WSA_MACRO_RX_MIX1)) { + dev_err(wsa_dev, + "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg1 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1) & + WSA_MACRO_MUX_INP_MASK1; + if (int_mux_cfg1_val == int_2_inp + + INTn_2_INP_SEL_RX0) { + int_fs_reg = + BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL + + WSA_MACRO_RX_PATH_OFFSET * j; + + dev_dbg(wsa_dev, + "%s: AIF_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + dev_dbg(wsa_dev, + "%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits(component, + int_fs_reg, + WSA_MACRO_FS_RATE_MASK, + int_mix_fs_rate_reg_val); + } + int_mux_cfg1 += WSA_MACRO_MUX_CFG_OFFSET; + } + } + return 0; +} + +static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + int rate_val = 0; + int i, ret; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) { + if (sample_rate == + int_mix_sample_rate_val[i].sample_rate) { + rate_val = + int_mix_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) || + (rate_val < 0)) + goto prim_rate; + ret = wsa_macro_set_mix_interpolator_rate(dai, + (u8) rate_val, sample_rate); +prim_rate: + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) { + if (sample_rate == + int_prim_sample_rate_val[i].sample_rate) { + rate_val = + int_prim_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) || + (rate_val < 0)) + return -EINVAL; + ret = wsa_macro_set_prim_interpolator_rate(dai, + (u8) rate_val, sample_rate); + return ret; +} + +static int wsa_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv = dev_get_drvdata(wsa_dev); + if (!wsa_priv) + return -EINVAL; + + dev_dbg(component->dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = wsa_macro_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(component->dev, + "%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + break; + case SNDRV_PCM_STREAM_CAPTURE: + if (dai->id == WSA_MACRO_AIF_VI) + wsa_priv->pcm_rate_vi = params_rate(params); + default: + break; + } + return 0; +} + +static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + u16 val = 0, mask = 0, cnt = 0, temp = 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv = dev_get_drvdata(wsa_dev); + if (!wsa_priv) + return -EINVAL; + + switch (dai->id) { + case WSA_MACRO_AIF_VI: + *tx_slot = wsa_priv->active_ch_mask[dai->id]; + *tx_num = hweight_long(wsa_priv->active_ch_mask[dai->id]); + break; + case WSA_MACRO_AIF1_PB: + case WSA_MACRO_AIF_MIX1_PB: + for_each_set_bit(temp, &wsa_priv->active_ch_mask[dai->id], + WSA_MACRO_RX_MAX) { + mask |= (1 << temp); + if (++cnt == WSA_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + if (mask & 0x0C) + mask = mask >> 0x2; + *rx_slot = mask; + *rx_num = cnt; + break; + case WSA_MACRO_AIF_ECHO: + val = snd_soc_component_read(component, + BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0); + if (val & WSA_MACRO_EC_MIX_TX1_MASK) { + mask |= 0x2; + cnt++; + } + if (val & WSA_MACRO_EC_MIX_TX0_MASK) { + mask |= 0x1; + cnt++; + } + *tx_slot = mask; + *tx_num = cnt; + break; + default: + dev_err(wsa_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static int wsa_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + uint16_t j = 0, reg = 0, mix_reg = 0, dsm_reg = 0; + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + bool adie_lb = false; + + if (mute) + return 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case WSA_MACRO_AIF1_PB: + case WSA_MACRO_AIF_MIX1_PB: + for (j = 0; j < NUM_INTERPOLATORS; j++) { + reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL + + (j * WSA_MACRO_RX_PATH_OFFSET); + mix_reg = BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL + + (j * WSA_MACRO_RX_PATH_OFFSET); + dsm_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL + + (j * WSA_MACRO_RX_PATH_OFFSET) + + WSA_MACRO_RX_PATH_DSMDEM_OFFSET; + int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + j * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1); + if (snd_soc_component_read(component, dsm_reg) & 0x01) { + if (int_mux_cfg0_val || (int_mux_cfg1_val & 0x38)) + snd_soc_component_update_bits(component, reg, + 0x20, 0x20); + if (int_mux_cfg1_val & 0x07) { + snd_soc_component_update_bits(component, reg, + 0x20, 0x20); + snd_soc_component_update_bits(component, + mix_reg, 0x20, 0x20); + } + } + } + bolero_wsa_pa_on(wsa_dev, adie_lb); + break; + default: + break; + } + return 0; +} +static int wsa_macro_mclk_enable(struct wsa_macro_priv *wsa_priv, + bool mclk_enable, bool dapm) +{ + struct regmap *regmap = dev_get_regmap(wsa_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(wsa_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(wsa_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n", + __func__, mclk_enable, dapm, wsa_priv->wsa_mclk_users); + + mutex_lock(&wsa_priv->mclk_lock); + if (mclk_enable) { + if (wsa_priv->wsa_mclk_users == 0) { + ret = bolero_clk_rsc_request_clock(wsa_priv->dev, + wsa_priv->default_clk_id, + wsa_priv->default_clk_id, + true); + if (ret < 0) { + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa request clock enable failed\n", + __func__); + goto exit; + } + bolero_clk_rsc_fs_gen_request(wsa_priv->dev, + true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + WSA_START_OFFSET, + WSA_MAX_OFFSET); + /* 9.6MHz MCLK, set value 0x00 if other frequency */ + regmap_update_bits(regmap, + BOLERO_CDC_WSA_TOP_FREQ_MCLK, 0x01, 0x01); + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + wsa_priv->wsa_mclk_users++; + } else { + if (wsa_priv->wsa_mclk_users <= 0) { + dev_err(wsa_priv->dev, "%s: clock already disabled\n", + __func__); + wsa_priv->wsa_mclk_users = 0; + goto exit; + } + wsa_priv->wsa_mclk_users--; + if (wsa_priv->wsa_mclk_users == 0) { + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + bolero_clk_rsc_fs_gen_request(wsa_priv->dev, + false); + + bolero_clk_rsc_request_clock(wsa_priv->dev, + wsa_priv->default_clk_id, + wsa_priv->default_clk_id, + false); + } + } +exit: + mutex_unlock(&wsa_priv->mclk_lock); + return ret; +} + +static int wsa_macro_mclk_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); + int ret = 0; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = wsa_macro_mclk_enable(wsa_priv, 1, true); + if (ret) + wsa_priv->dapm_mclk_enable = false; + else + wsa_priv->dapm_mclk_enable = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (wsa_priv->dapm_mclk_enable) + wsa_macro_mclk_enable(wsa_priv, 0, true); + break; + default: + dev_err(wsa_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int wsa_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + int ret = 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (event) { + case BOLERO_MACRO_EVT_SSR_DOWN: + if (wsa_priv->swr_ctrl_data) { + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(wsa_dev) || + !pm_runtime_suspended(wsa_dev))) { + ret = bolero_runtime_suspend(wsa_dev); + if (!ret) { + pm_runtime_disable(wsa_dev); + pm_runtime_set_suspended(wsa_dev); + pm_runtime_enable(wsa_dev); + } + } + break; + case BOLERO_MACRO_EVT_PRE_SSR_UP: + /* enable&disable WSA_CORE_CLK to reset GFMUX reg */ + wsa_macro_core_vote(wsa_priv, true); + ret = bolero_clk_rsc_request_clock(wsa_priv->dev, + wsa_priv->default_clk_id, + WSA_CORE_CLK, true); + if (ret < 0) + dev_err_ratelimited(wsa_priv->dev, + "%s, failed to enable clk, ret:%d\n", + __func__, ret); + else + bolero_clk_rsc_request_clock(wsa_priv->dev, + wsa_priv->default_clk_id, + WSA_CORE_CLK, false); + wsa_macro_core_vote(wsa_priv, false); + break; + case BOLERO_MACRO_EVT_SSR_UP: + /* reset swr after ssr/pdr */ + wsa_priv->reset_swr = true; + if (wsa_priv->swr_ctrl_data) + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case BOLERO_MACRO_EVT_CLK_RESET: + bolero_rsc_clk_reset(wsa_dev, WSA_CORE_CLK); + break; + } + return 0; +} + +static int wsa_macro_enable_vi_feedback(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 device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + u8 val = 0x0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (wsa_priv->pcm_rate_vi) { + case 48000: + val = 0x04; + break; + case 24000: + val = 0x02; + break; + case 8000: + default: + val = 0x00; + break; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (test_bit(WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + dev_dbg(wsa_dev, "%s: spkr1 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + if (test_bit(WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + dev_dbg(wsa_dev, "%s: spkr2 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (test_bit(WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + /* Disable V&I sensing */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + dev_dbg(wsa_dev, "%s: spkr1 disabled\n", __func__); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + } + if (test_bit(WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + /* Disable V&I sensing */ + dev_dbg(wsa_dev, "%s: spkr2 disabled\n", __func__); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + } + break; + } + + return 0; +} + +static void wsa_macro_hd2_control(struct snd_soc_component *component, + u16 reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (reg == BOLERO_CDC_WSA_RX0_RX_PATH_CTL) { + hd2_scale_reg = BOLERO_CDC_WSA_RX0_RX_PATH_SEC3; + hd2_enable_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CFG0; + } + if (reg == BOLERO_CDC_WSA_RX1_RX_PATH_CTL) { + hd2_scale_reg = BOLERO_CDC_WSA_RX1_RX_PATH_SEC3; + hd2_enable_reg = BOLERO_CDC_WSA_RX1_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x10); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x01); + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x00); + } +} + +static int wsa_macro_enable_swr(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ch_cnt; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!(strnstr(w->name, "RX0", sizeof("WSA_RX0"))) && + !wsa_priv->rx_0_count) + wsa_priv->rx_0_count++; + if (!(strnstr(w->name, "RX1", sizeof("WSA_RX1"))) && + !wsa_priv->rx_1_count) + wsa_priv->rx_1_count++; + ch_cnt = wsa_priv->rx_0_count + wsa_priv->rx_1_count; + + if (wsa_priv->swr_ctrl_data) { + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_UP, NULL); + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (!(strnstr(w->name, "RX0", sizeof("WSA_RX0"))) && + wsa_priv->rx_0_count) + wsa_priv->rx_0_count--; + if (!(strnstr(w->name, "RX1", sizeof("WSA_RX1"))) && + wsa_priv->rx_1_count) + wsa_priv->rx_1_count--; + ch_cnt = wsa_priv->rx_0_count + wsa_priv->rx_1_count; + + if (wsa_priv->swr_ctrl_data) + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + break; + } + dev_dbg(wsa_priv->dev, "%s: current swr ch cnt: %d\n", + __func__, wsa_priv->rx_0_count + wsa_priv->rx_1_count); + + return 0; +} + +static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int offset_val = 0; + int val = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "WSA_RX0 MIX INP"))) { + gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL; + } else if (!(strcmp(w->name, "WSA_RX1 MIX INP"))) { + gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL; + } else { + dev_err(component->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wsa_macro_enable_swr(w, kcontrol, event); + val = snd_soc_component_read(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + w->reg, 0x20, 0x00); + wsa_macro_enable_swr(w, kcontrol, event); + break; + } + + return 0; +} + +static int wsa_macro_config_compander(struct snd_soc_component *component, + int comp, int event) +{ + u16 comp_ctl0_reg, rx_path_cfg0_reg; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, wsa_priv->comp_enabled[comp]); + + if (!wsa_priv->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = BOLERO_CDC_WSA_COMPANDER0_CTL0 + + (comp * WSA_MACRO_RX_COMP_OFFSET); + rx_path_cfg0_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CFG0 + + (comp * WSA_MACRO_RX_PATH_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x04); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x00); + } + + return 0; +} + +static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component, + struct wsa_macro_priv *wsa_priv, + int path, + bool enable) +{ + u16 softclip_clk_reg = BOLERO_CDC_WSA_SOFTCLIP0_CRC + + (path * WSA_MACRO_RX_SOFTCLIP_OFFSET); + u8 softclip_mux_mask = (1 << path); + u8 softclip_mux_value = (1 << path); + + dev_dbg(component->dev, "%s: path %d, enable %d\n", + __func__, path, enable); + if (enable) { + if (wsa_priv->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, 0x01, 0x01); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, softclip_mux_value); + } + wsa_priv->softclip_clk_users[path]++; + } else { + wsa_priv->softclip_clk_users[path]--; + if (wsa_priv->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, 0x00); + } + } +} + +static int wsa_macro_config_softclip(struct snd_soc_component *component, + int path, int event) +{ + u16 softclip_ctrl_reg = 0; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + int softclip_path = 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (path == WSA_MACRO_COMP1) + softclip_path = WSA_MACRO_SOFTCLIP0; + else if (path == WSA_MACRO_COMP2) + softclip_path = WSA_MACRO_SOFTCLIP1; + + dev_dbg(component->dev, "%s: event %d path %d, enabled %d\n", + __func__, event, softclip_path, + wsa_priv->is_softclip_on[softclip_path]); + + if (!wsa_priv->is_softclip_on[softclip_path]) + return 0; + + softclip_ctrl_reg = BOLERO_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL + + (softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Softclip clock and mux */ + wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, true); + /* Enable Softclip control */ + snd_soc_component_update_bits(component, softclip_ctrl_reg, + 0x01, 0x01); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, softclip_ctrl_reg, + 0x01, 0x00); + wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, false); + } + + return 0; +} + +static bool wsa_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0; + + int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || + int_n_inp0 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || + int_n_inp1 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || + int_n_inp2 == INTn_1_INP_SEL_DEC1) + return true; + + return false; +} + +static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 reg = 0; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + bool adie_lb = false; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + + reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL + + WSA_MACRO_RX_PATH_OFFSET * w->shift; + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wsa_macro_adie_lb(component, w->shift)) { + adie_lb = true; + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + bolero_wsa_pa_on(wsa_dev, adie_lb); + } + break; + default: + break; + } + return 0; +} + +static int wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = 0; + + switch (reg) { + case BOLERO_CDC_WSA_RX0_RX_PATH_CTL: + case BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL: + prim_int_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL; + *ind = 0; + break; + case BOLERO_CDC_WSA_RX1_RX_PATH_CTL: + case BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL: + prim_int_reg = BOLERO_CDC_WSA_RX1_RX_PATH_CTL; + *ind = 1; + break; + } + + return prim_int_reg; +} + +static int wsa_macro_enable_prim_interpolator( + struct snd_soc_component *component, + u16 reg, int event) +{ + u16 prim_int_reg; + u16 ind = 0; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + prim_int_reg = wsa_macro_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wsa_priv->prim_int_users[ind]++; + if (wsa_priv->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(component, + prim_int_reg + WSA_MACRO_RX_PATH_CFG3_OFFSET, + 0x03, 0x03); + snd_soc_component_update_bits(component, prim_int_reg, + 0x10, 0x10); + wsa_macro_hd2_control(component, prim_int_reg, event); + snd_soc_component_update_bits(component, + prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET, + 0x1, 0x1); + } + if ((reg != prim_int_reg) && + ((snd_soc_component_read( + component, prim_int_reg)) & 0x10)) + snd_soc_component_update_bits(component, reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + wsa_priv->prim_int_users[ind]--; + if (wsa_priv->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(component, prim_int_reg, + 1 << 0x5, 0 << 0x5); + snd_soc_component_update_bits(component, + prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET, + 0x1, 0x0); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x00); + wsa_macro_hd2_control(component, prim_int_reg, event); + } + break; + } + + dev_dbg(component->dev, "%s: primary interpolator: INT%d, users: %d\n", + __func__, ind, wsa_priv->prim_int_users[ind]); + return 0; +} + +static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "WSA_RX INT0 INTERP"))) { + reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL; + gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_CTL; + } else if (!(strcmp(w->name, "WSA_RX INT1 INTERP"))) { + reg = BOLERO_CDC_WSA_RX1_RX_PATH_CTL; + gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_CTL; + } else { + dev_err(component->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + wsa_macro_enable_prim_interpolator(component, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + wsa_macro_config_compander(component, w->shift, event); + wsa_macro_config_softclip(component, w->shift, event); + /* apply gain after int clk is enabled */ + if ((wsa_priv->spkr_gain_offset == + WSA_MACRO_GAIN_OFFSET_M1P5_DB) && + (wsa_priv->comp_enabled[WSA_MACRO_COMP1] || + wsa_priv->comp_enabled[WSA_MACRO_COMP2]) && + (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL || + gain_reg == BOLERO_CDC_WSA_RX1_RX_VOL_CTL)) { + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0, + 0x01, 0x01); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX1_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0, + 0x01, 0x01); + offset_val = -2; + } + val = snd_soc_component_read(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + wsa_macro_config_ear_spkr_gain(component, wsa_priv, + event, gain_reg); + break; + case SND_SOC_DAPM_POST_PMD: + wsa_macro_config_compander(component, w->shift, event); + wsa_macro_config_softclip(component, w->shift, event); + wsa_macro_enable_prim_interpolator(component, reg, event); + if ((wsa_priv->spkr_gain_offset == + WSA_MACRO_GAIN_OFFSET_M1P5_DB) && + (wsa_priv->comp_enabled[WSA_MACRO_COMP1] || + wsa_priv->comp_enabled[WSA_MACRO_COMP2]) && + (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL || + gain_reg == BOLERO_CDC_WSA_RX1_RX_VOL_CTL)) { + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_MIX_SEC0, + 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX1_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX1_RX_PATH_MIX_SEC0, + 0x01, 0x00); + offset_val = 2; + val = snd_soc_component_read(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + } + wsa_macro_config_ear_spkr_gain(component, wsa_priv, + event, gain_reg); + break; + } + + return 0; +} + +static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component, + struct wsa_macro_priv *wsa_priv, + int event, int gain_reg) +{ + int comp_gain_offset, val; + + switch (wsa_priv->spkr_mode) { + /* Compander gain in WSA_MACRO_SPKR_MODE1 case is 12 dB */ + case WSA_MACRO_SPKR_MODE_1: + comp_gain_offset = -12; + break; + /* Default case compander gain is 15 dB */ + default: + comp_gain_offset = -15; + break; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Apply ear spkr gain only if compander is enabled */ + if (wsa_priv->comp_enabled[WSA_MACRO_COMP1] && + (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL) && + (wsa_priv->ear_spkr_gain != 0)) { + /* For example, val is -8(-12+5-1) for 4dB of gain */ + val = comp_gain_offset + wsa_priv->ear_spkr_gain - 1; + snd_soc_component_write(component, gain_reg, val); + + dev_dbg(wsa_priv->dev, "%s: RX0 Volume %d dB\n", + __func__, val); + } + if(wsa_priv->wsa_spkrrecv) { + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x00); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* + * Reset RX0 volume to 0 dB if compander is enabled and + * ear_spkr_gain is non-zero. + */ + if (wsa_priv->comp_enabled[WSA_MACRO_COMP1] && + (gain_reg == BOLERO_CDC_WSA_RX0_RX_VOL_CTL) && + (wsa_priv->ear_spkr_gain != 0)) { + snd_soc_component_write(component, gain_reg, 0x0); + + dev_dbg(wsa_priv->dev, "%s: Reset RX0 Volume to 0 dB\n", + __func__); + } + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00); + break; + } + + return 0; +} + +static int wsa_macro_spk_boost_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); + u16 boost_path_ctl, boost_path_cfg1; + u16 reg, reg_mix; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) { + boost_path_ctl = BOLERO_CDC_WSA_BOOST0_BOOST_PATH_CTL; + boost_path_cfg1 = BOLERO_CDC_WSA_RX0_RX_PATH_CFG1; + reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL; + reg_mix = BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL; + } else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) { + boost_path_ctl = BOLERO_CDC_WSA_BOOST1_BOOST_PATH_CTL; + boost_path_cfg1 = BOLERO_CDC_WSA_RX1_RX_PATH_CFG1; + reg = BOLERO_CDC_WSA_RX1_RX_PATH_CTL; + reg_mix = BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL; + } else { + dev_err(component->dev, "%s: unknown widget: %s\n", + __func__, w->name); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x01); + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x10); + if ((snd_soc_component_read(component, reg_mix)) & 0x10) + snd_soc_component_update_bits(component, reg_mix, + 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, reg, 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x00); + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x00); + break; + } + + return 0; +} + + +static int wsa_macro_enable_vbat(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 device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + u16 vbat_path_cfg = 0; + int softclip_path = 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + if (!strcmp(w->name, "WSA_RX INT0 VBAT")) { + vbat_path_cfg = BOLERO_CDC_WSA_RX0_RX_PATH_CFG1; + softclip_path = WSA_MACRO_SOFTCLIP0; + } else if (!strcmp(w->name, "WSA_RX INT1 VBAT")) { + vbat_path_cfg = BOLERO_CDC_WSA_RX1_RX_PATH_CFG1; + softclip_path = WSA_MACRO_SOFTCLIP1; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable clock for VBAT block */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x10); + /* Enable VBAT block */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x01, 0x01); + /* Update interpolator with 384K path */ + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x80, 0x80); + /* Use attenuation mode */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x02, 0x00); + /* + * BCL block needs softclip clock and mux config to be enabled + */ + wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, true); + /* Enable VBAT at channel level */ + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x02); + /* Set the ATTK1 gain */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + /* Set the ATTK2 gain */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + /* Set the ATTK3 gain */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x80, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, + 0x02, 0x02); + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, false); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x01, 0x00); + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x00); + break; + default: + dev_err(wsa_dev, "%s: Invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static int wsa_macro_enable_echo(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 device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + u16 val, ec_tx = 0, ec_hq_reg; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa_dev, "%s %d %s\n", __func__, event, w->name); + + val = snd_soc_component_read(component, + BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0); + if (!(strcmp(w->name, "WSA RX_MIX EC0_MUX"))) + ec_tx = (val & 0x07) - 1; + else + ec_tx = ((val & 0x38) >> 0x3) - 1; + + if (ec_tx < 0 || ec_tx >= (WSA_MACRO_RX1 + 1)) { + dev_err(wsa_dev, "%s: EC mix control not set correctly\n", + __func__); + return -EINVAL; + } + if (wsa_priv->ec_hq[ec_tx]) { + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 0x1 << ec_tx, 0x1 << ec_tx); + ec_hq_reg = BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL + + 0x40 * ec_tx; + snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01); + ec_hq_reg = BOLERO_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 + + 0x40 * ec_tx; + /* default set to 48k */ + snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08); + } + + return 0; +} + +static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->ec_hq[ec_tx]; + return 0; +} + +static int wsa_macro_set_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa_dev, "%s: enable current %d, new %d\n", + __func__, wsa_priv->ec_hq[ec_tx], value); + wsa_priv->ec_hq[ec_tx] = value; + + return 0; +} + +static int wsa_macro_get_rx_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + int wsa_rx_shift = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + wsa_priv->wsa_digital_mute_status[wsa_rx_shift]; + return 0; +} + +static int wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + int value = ucontrol->value.integer.value[0]; + int wsa_rx_shift = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int ret = 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + pm_runtime_get_sync(wsa_priv->dev); + switch (wsa_rx_shift) { + case 0: + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_CTL, + 0x10, value << 4); + break; + case 1: + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX1_RX_PATH_CTL, + 0x10, value << 4); + break; + case 2: + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL, + 0x10, value << 4); + break; + case 3: + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL, + 0x10, value << 4); + break; + default: + pr_err("%s: invalid argument rx_shift = %d\n", __func__, + wsa_rx_shift); + ret = -EINVAL; + } + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + + dev_dbg(component->dev, "%s: WSA Digital Mute RX %d Enable %d\n", + __func__, wsa_rx_shift, value); + wsa_priv->wsa_digital_mute_status[wsa_rx_shift] = value; + + return ret; +} + +static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->comp_enabled[comp]; + return 0; +} + +static int wsa_macro_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, wsa_priv->comp_enabled[comp], value); + wsa_priv->comp_enabled[comp] = value; + + return 0; +} + +static int wsa_macro_ear_spkrrecv_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->wsa_spkrrecv; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int wsa_macro_ear_spkrrecv_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + wsa_priv->wsa_spkrrecv = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s:spkrrecv status = %d\n", + __func__, wsa_priv->wsa_spkrrecv); + + return 0; +} + +static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->ear_spkr_gain; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->ear_spkr_gain = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: gain = %d\n", __func__, + wsa_priv->ear_spkr_gain); + + return 0; +} + +static int wsa_macro_spkr_left_boost_stage_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + bst_state_max = snd_soc_component_read(component, + BOLERO_CDC_WSA_BOOST0_BOOST_CTL); + bst_state_max = (bst_state_max & 0x0c) >> 2; + ucontrol->value.integer.value[0] = bst_state_max; + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int wsa_macro_spkr_left_boost_stage_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + bst_state_max = ucontrol->value.integer.value[0] << 2; + /* bolero does not need to limit the boost levels */ + + return 0; +} + +static int wsa_macro_spkr_right_boost_stage_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + bst_state_max = snd_soc_component_read(component, + BOLERO_CDC_WSA_BOOST1_BOOST_CTL); + bst_state_max = (bst_state_max & 0x0c) >> 2; + ucontrol->value.integer.value[0] = bst_state_max; + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int wsa_macro_spkr_right_boost_stage_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + bst_state_max = ucontrol->value.integer.value[0] << 2; + /* bolero does not need to limit the boost levels */ + + return 0; +} + +static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + wsa_priv->rx_port_value[widget->shift]; + return 0; +} + +static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 rx_port_value = ucontrol->value.integer.value[0]; + u32 bit_input = 0; + u32 aif_rst; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + aif_rst = wsa_priv->rx_port_value[widget->shift]; + if (!rx_port_value) { + if (aif_rst == 0) { + dev_err(wsa_dev, "%s: AIF reset already\n", __func__); + return 0; + } + if (aif_rst >= WSA_MACRO_RX_MAX) { + dev_err(wsa_dev, "%s: Invalid AIF reset\n", __func__); + return 0; + } + } + wsa_priv->rx_port_value[widget->shift] = rx_port_value; + + bit_input = widget->shift; + + dev_dbg(wsa_dev, + "%s: mux input: %d, mux output: %d, bit: %d\n", + __func__, rx_port_value, widget->shift, bit_input); + + switch (rx_port_value) { + case 0: + clear_bit(bit_input, + &wsa_priv->active_ch_mask[aif_rst]); + break; + case 1: + case 2: + set_bit(bit_input, + &wsa_priv->active_ch_mask[rx_port_value]); + break; + default: + dev_err(wsa_dev, + "%s: Invalid AIF_ID for WSA RX MUX %d\n", + __func__, rx_port_value); + return -EINVAL; + } + + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + return 0; +} + +static int wsa_macro_vbat_bcl_gsm_mode_func_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ucontrol->value.integer.value[0] = + ((snd_soc_component_read( + component, BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG) & 0x04) ? + 1 : 0); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int wsa_macro_vbat_bcl_gsm_mode_func_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + /* Set Vbat register configuration for GSM mode bit based on value */ + if (ucontrol->value.integer.value[0]) + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, + 0x04, 0x04); + else + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_CFG, + 0x04, 0x00); + + return 0; +} + +static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + int path = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->is_softclip_on[path]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int wsa_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + int path = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->is_softclip_on[path] = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: soft clip enable for %d: %d\n", __func__, + path, wsa_priv->is_softclip_on[path]); + + return 0; +} + +static const struct snd_kcontrol_new wsa_macro_snd_controls[] = { + SOC_ENUM_EXT("WSA SPKRRECV", wsa_macro_ear_spkrrecv_enum, + wsa_macro_ear_spkrrecv_get, + wsa_macro_ear_spkrrecv_put), + SOC_ENUM_EXT("EAR SPKR PA Gain", wsa_macro_ear_spkr_pa_gain_enum, + wsa_macro_ear_spkr_pa_gain_get, + wsa_macro_ear_spkr_pa_gain_put), + SOC_ENUM_EXT("SPKR Left Boost Max State", + wsa_macro_spkr_boost_stage_enum, + wsa_macro_spkr_left_boost_stage_get, + wsa_macro_spkr_left_boost_stage_put), + SOC_ENUM_EXT("SPKR Right Boost Max State", + wsa_macro_spkr_boost_stage_enum, + wsa_macro_spkr_right_boost_stage_get, + wsa_macro_spkr_right_boost_stage_put), + SOC_ENUM_EXT("GSM mode Enable", wsa_macro_vbat_bcl_gsm_mode_enum, + wsa_macro_vbat_bcl_gsm_mode_func_get, + wsa_macro_vbat_bcl_gsm_mode_func_put), + SOC_SINGLE_EXT("WSA_Softclip0 Enable", SND_SOC_NOPM, + WSA_MACRO_SOFTCLIP0, 1, 0, + wsa_macro_soft_clip_enable_get, + wsa_macro_soft_clip_enable_put), + SOC_SINGLE_EXT("WSA_Softclip1 Enable", SND_SOC_NOPM, + WSA_MACRO_SOFTCLIP1, 1, 0, + wsa_macro_soft_clip_enable_get, + wsa_macro_soft_clip_enable_put), + SOC_SINGLE_S8_TLV("WSA_RX0 Digital Volume", + BOLERO_CDC_WSA_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume", + BOLERO_CDC_WSA_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_EXT("WSA_RX0 Digital Mute", SND_SOC_NOPM, WSA_MACRO_RX0, 1, + 0, wsa_macro_get_rx_mute_status, + wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_RX1 Digital Mute", SND_SOC_NOPM, WSA_MACRO_RX1, 1, + 0, wsa_macro_get_rx_mute_status, + wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_RX0_MIX Digital Mute", SND_SOC_NOPM, + WSA_MACRO_RX_MIX0, 1, 0, wsa_macro_get_rx_mute_status, + wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_RX1_MIX Digital Mute", SND_SOC_NOPM, + WSA_MACRO_RX_MIX1, 1, 0, wsa_macro_get_rx_mute_status, + wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_COMP1 Switch", SND_SOC_NOPM, WSA_MACRO_COMP1, 1, 0, + wsa_macro_get_compander, wsa_macro_set_compander), + SOC_SINGLE_EXT("WSA_COMP2 Switch", SND_SOC_NOPM, WSA_MACRO_COMP2, 1, 0, + wsa_macro_get_compander, wsa_macro_set_compander), + SOC_SINGLE_EXT("WSA_RX0 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX0, + 1, 0, wsa_macro_get_ec_hq, wsa_macro_set_ec_hq), + SOC_SINGLE_EXT("WSA_RX1 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX1, + 1, 0, wsa_macro_get_ec_hq, wsa_macro_set_ec_hq), +}; + +static const struct soc_enum rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_mux_text), rx_mux_text); + +static const struct snd_kcontrol_new rx_mux[WSA_MACRO_RX_MAX] = { + SOC_DAPM_ENUM_EXT("WSA RX0 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX1 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX_MIX0 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX_MIX1 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), +}; + +static int wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 spk_tx_id = mixer->shift; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (test_bit(spk_tx_id, &wsa_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 spk_tx_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->vi_feed_value = ucontrol->value.integer.value[0]; + + if (enable) { + if (spk_tx_id == WSA_MACRO_TX0 && + !test_bit(WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + set_bit(WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]); + } + if (spk_tx_id == WSA_MACRO_TX1 && + !test_bit(WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + set_bit(WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]); + } + } else { + if (spk_tx_id == WSA_MACRO_TX0 && + test_bit(WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + clear_bit(WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]); + } + if (spk_tx_id == WSA_MACRO_TX1 && + test_bit(WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI])) { + clear_bit(WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[WSA_MACRO_AIF_VI]); + } + } + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +static const struct snd_kcontrol_new aif_vi_mixer[] = { + SOC_SINGLE_EXT("WSA_SPKR_VI_1", SND_SOC_NOPM, WSA_MACRO_TX0, 1, 0, + wsa_macro_vi_feed_mixer_get, + wsa_macro_vi_feed_mixer_put), + SOC_SINGLE_EXT("WSA_SPKR_VI_2", SND_SOC_NOPM, WSA_MACRO_TX1, 1, 0, + wsa_macro_vi_feed_mixer_get, + wsa_macro_vi_feed_mixer_put), +}; + +static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("WSA AIF1 PB", "WSA_AIF1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("WSA AIF_MIX1 PB", "WSA_AIF_MIX1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT_E("WSA AIF_VI", "WSA_AIF_VI Capture", 0, + SND_SOC_NOPM, WSA_MACRO_AIF_VI, 0, + wsa_macro_enable_vi_feedback, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT("WSA AIF_ECHO", "WSA_AIF_ECHO Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER("WSA_AIF_VI Mixer", SND_SOC_NOPM, WSA_MACRO_AIF_VI, + 0, aif_vi_mixer, ARRAY_SIZE(aif_vi_mixer)), + SND_SOC_DAPM_MUX_E("WSA RX_MIX EC0_MUX", SND_SOC_NOPM, + WSA_MACRO_EC0_MUX, 0, + &rx_mix_ec0_mux, wsa_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA RX_MIX EC1_MUX", SND_SOC_NOPM, + WSA_MACRO_EC1_MUX, 0, + &rx_mix_ec1_mux, wsa_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("WSA RX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX0, 0, + &rx_mux[WSA_MACRO_RX0]), + SND_SOC_DAPM_MUX("WSA RX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX1, 0, + &rx_mux[WSA_MACRO_RX1]), + SND_SOC_DAPM_MUX("WSA RX_MIX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, 0, + &rx_mux[WSA_MACRO_RX_MIX0]), + SND_SOC_DAPM_MUX("WSA RX_MIX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, 0, + &rx_mux[WSA_MACRO_RX_MIX1]), + + SND_SOC_DAPM_MIXER("WSA RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp0_mux, wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp1_mux, wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp2_mux, wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, + 0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp0_mux, wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp1_mux, wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp2_mux, wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, + 0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("WSA_RX INT0 MIX", SND_SOC_NOPM, + 0, 0, NULL, 0, wsa_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_E("WSA_RX INT1 MIX", SND_SOC_NOPM, + 1, 0, NULL, 0, wsa_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("WSA_RX0 INT0 SIDETONE MIX", + BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 4, 0, + &rx0_sidetone_mix_mux, wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_INPUT("WSA SRC0_INP"), + + SND_SOC_DAPM_INPUT("WSA_TX DEC0_INP"), + SND_SOC_DAPM_INPUT("WSA_TX DEC1_INP"), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 INTERP", SND_SOC_NOPM, + WSA_MACRO_COMP1, 0, NULL, 0, wsa_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 INTERP", SND_SOC_NOPM, + WSA_MACRO_COMP2, 0, NULL, 0, wsa_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, wsa_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, wsa_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 VBAT", SND_SOC_NOPM, + 0, 0, wsa_int0_vbat_mix_switch, + ARRAY_SIZE(wsa_int0_vbat_mix_switch), + wsa_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 VBAT", SND_SOC_NOPM, + 0, 0, wsa_int1_vbat_mix_switch, + ARRAY_SIZE(wsa_int1_vbat_mix_switch), + wsa_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("VIINPUT_WSA"), + + SND_SOC_DAPM_OUTPUT("WSA_SPK1 OUT"), + SND_SOC_DAPM_OUTPUT("WSA_SPK2 OUT"), + + SND_SOC_DAPM_SUPPLY_S("WSA_MCLK", 0, SND_SOC_NOPM, 0, 0, + wsa_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route wsa_audio_map[] = { + /* VI Feedback */ + {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"}, + {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_2", "VIINPUT_WSA"}, + {"WSA AIF_VI", NULL, "WSA_AIF_VI Mixer"}, + {"WSA AIF_VI", NULL, "WSA_MCLK"}, + + {"WSA RX_MIX EC0_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"}, + {"WSA RX_MIX EC1_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"}, + {"WSA RX_MIX EC0_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"}, + {"WSA RX_MIX EC1_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"}, + {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC0_MUX"}, + {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC1_MUX"}, + {"WSA AIF_ECHO", NULL, "WSA_MCLK"}, + + {"WSA AIF1 PB", NULL, "WSA_MCLK"}, + {"WSA AIF_MIX1 PB", NULL, "WSA_MCLK"}, + + {"WSA RX0 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX1 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX_MIX0 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX_MIX1 MUX", "AIF1_PB", "WSA AIF1 PB"}, + + {"WSA RX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX_MIX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX_MIX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + + {"WSA RX0", NULL, "WSA RX0 MUX"}, + {"WSA RX1", NULL, "WSA RX1 MUX"}, + {"WSA RX_MIX0", NULL, "WSA RX_MIX0 MUX"}, + {"WSA RX_MIX1", NULL, "WSA RX_MIX1 MUX"}, + + {"WSA_RX0 INP0", "RX0", "WSA RX0"}, + {"WSA_RX0 INP0", "RX1", "WSA RX1"}, + {"WSA_RX0 INP0", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP0", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP0", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP0", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP0"}, + + {"WSA_RX0 INP1", "RX0", "WSA RX0"}, + {"WSA_RX0 INP1", "RX1", "WSA RX1"}, + {"WSA_RX0 INP1", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP1", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP1", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP1", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP1"}, + + {"WSA_RX0 INP2", "RX0", "WSA RX0"}, + {"WSA_RX0 INP2", "RX1", "WSA RX1"}, + {"WSA_RX0 INP2", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP2", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP2", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP2", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP2"}, + + {"WSA_RX0 MIX INP", "RX0", "WSA RX0"}, + {"WSA_RX0 MIX INP", "RX1", "WSA RX1"}, + {"WSA_RX0 MIX INP", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 MIX INP", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX0 MIX INP"}, + + {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX INT0 MIX"}, + {"WSA_RX INT0 INTERP", NULL, "WSA_RX INT0 SEC MIX"}, + {"WSA_RX0 INT0 SIDETONE MIX", "SRC0", "WSA SRC0_INP"}, + {"WSA_RX INT0 INTERP", NULL, "WSA_RX0 INT0 SIDETONE MIX"}, + {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 INTERP"}, + + {"WSA_RX INT0 VBAT", "WSA RX0 VBAT Enable", "WSA_RX INT0 INTERP"}, + {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 VBAT"}, + + {"WSA_SPK1 OUT", NULL, "WSA_RX INT0 CHAIN"}, + {"WSA_SPK1 OUT", NULL, "WSA_MCLK"}, + + {"WSA_RX1 INP0", "RX0", "WSA RX0"}, + {"WSA_RX1 INP0", "RX1", "WSA RX1"}, + {"WSA_RX1 INP0", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP0", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP0", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP0", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP0"}, + + {"WSA_RX1 INP1", "RX0", "WSA RX0"}, + {"WSA_RX1 INP1", "RX1", "WSA RX1"}, + {"WSA_RX1 INP1", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP1", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP1", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP1", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP1"}, + + {"WSA_RX1 INP2", "RX0", "WSA RX0"}, + {"WSA_RX1 INP2", "RX1", "WSA RX1"}, + {"WSA_RX1 INP2", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP2", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP2", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP2", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP2"}, + + {"WSA_RX1 MIX INP", "RX0", "WSA RX0"}, + {"WSA_RX1 MIX INP", "RX1", "WSA RX1"}, + {"WSA_RX1 MIX INP", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 MIX INP", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX1 MIX INP"}, + + {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX INT1 MIX"}, + {"WSA_RX INT1 INTERP", NULL, "WSA_RX INT1 SEC MIX"}, + + {"WSA_RX INT1 VBAT", "WSA RX1 VBAT Enable", "WSA_RX INT1 INTERP"}, + {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 VBAT"}, + + {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 INTERP"}, + {"WSA_SPK2 OUT", NULL, "WSA_RX INT1 CHAIN"}, + {"WSA_SPK2 OUT", NULL, "WSA_MCLK"}, +}; + +static const struct wsa_macro_reg_mask_val wsa_macro_reg_init[] = { + {BOLERO_CDC_WSA_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {BOLERO_CDC_WSA_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x1E, 0x18}, + {BOLERO_CDC_WSA_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {BOLERO_CDC_WSA_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x1E, 0x18}, + {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x70, 0x58}, + {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x70, 0x58}, + {BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08}, + {BOLERO_CDC_WSA_RX1_RX_PATH_CFG1, 0x08, 0x08}, + {BOLERO_CDC_WSA_TOP_TOP_CFG1, 0x02, 0x02}, + {BOLERO_CDC_WSA_TOP_TOP_CFG1, 0x01, 0x01}, + {BOLERO_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01}, + {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01}, + {BOLERO_CDC_WSA_RX0_RX_PATH_CFG0, 0x01, 0x01}, + {BOLERO_CDC_WSA_RX1_RX_PATH_CFG0, 0x01, 0x01}, + {BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, +}; + +static void wsa_macro_init_bcl_pmic_reg(struct snd_soc_component *component) +{ + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!component) { + pr_err("%s: NULL component pointer!\n", __func__); + return; + } + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return; + + switch (wsa_priv->bcl_pmic_params.id) { + case 0: + /* Enable ID0 to listen to respective PMIC group interrupts */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1, 0x02, 0x02); + /* Update MC_SID0 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG1, 0x0F, + wsa_priv->bcl_pmic_params.sid); + /* Update MC_PPID0 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG2, 0xFF, + wsa_priv->bcl_pmic_params.ppid); + break; + case 1: + /* Enable ID1 to listen to respective PMIC group interrupts */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CTL1, 0x01, 0x01); + /* Update MC_SID1 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG3, 0x0F, + wsa_priv->bcl_pmic_params.sid); + /* Update MC_PPID1 */ + snd_soc_component_update_bits(component, + BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_CFG4, 0xFF, + wsa_priv->bcl_pmic_params.ppid); + break; + default: + dev_err(wsa_dev, "%s: PMIC ID is invalid %d\n", + __func__, wsa_priv->bcl_pmic_params.id); + break; + } +} + +static void wsa_macro_init_reg(struct snd_soc_component *component) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wsa_macro_reg_init); i++) + snd_soc_component_update_bits(component, + wsa_macro_reg_init[i].reg, + wsa_macro_reg_init[i].mask, + wsa_macro_reg_init[i].val); + + wsa_macro_init_bcl_pmic_reg(component); +} + +static int wsa_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle; + + if (wsa_priv == NULL) { + pr_err("%s: wsa priv data is NULL\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(wsa_priv->dev); + if (bolero_check_core_votes(wsa_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(wsa_priv->dev); + pm_runtime_mark_last_busy(wsa_priv->dev); + } + return rc; +} + +static int wsa_swrm_clock(void *handle, bool enable) +{ + struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(wsa_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err(wsa_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&wsa_priv->swr_clk_lock); + + dev_dbg(wsa_priv->dev, "%s: swrm clock %s\n", + __func__, (enable ? "enable" : "disable")); + if (enable) { + pm_runtime_get_sync(wsa_priv->dev); + if (wsa_priv->swr_clk_users == 0) { + ret = msm_cdc_pinctrl_select_active_state( + wsa_priv->wsa_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa swr pinctrl enable failed\n", + __func__); + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + goto exit; + } + ret = wsa_macro_mclk_enable(wsa_priv, 1, true); + if (ret < 0) { + msm_cdc_pinctrl_select_sleep_state( + wsa_priv->wsa_swr_gpio_p); + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa request clock enable failed\n", + __func__); + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + goto exit; + } + if (wsa_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (wsa_priv->reset_swr) + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + wsa_priv->reset_swr = false; + } + wsa_priv->swr_clk_users++; + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + } else { + if (wsa_priv->swr_clk_users <= 0) { + dev_err(wsa_priv->dev, "%s: clock already disabled\n", + __func__); + wsa_priv->swr_clk_users = 0; + goto exit; + } + wsa_priv->swr_clk_users--; + if (wsa_priv->swr_clk_users == 0) { + regmap_update_bits(regmap, + BOLERO_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + wsa_macro_mclk_enable(wsa_priv, 0, true); + ret = msm_cdc_pinctrl_select_sleep_state( + wsa_priv->wsa_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa swr pinctrl disable failed\n", + __func__); + goto exit; + } + } + } + dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n", + __func__, wsa_priv->swr_clk_users); +exit: + mutex_unlock(&wsa_priv->swr_clk_lock); + return ret; +} + +static int wsa_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + wsa_dev = bolero_get_device_ptr(component->dev, WSA_MACRO); + if (!wsa_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + wsa_priv = dev_get_drvdata(wsa_dev); + if (!wsa_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + + ret = snd_soc_dapm_new_controls(dapm, wsa_macro_dapm_widgets, + ARRAY_SIZE(wsa_macro_dapm_widgets)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add controls\n", __func__); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, wsa_audio_map, + ARRAY_SIZE(wsa_audio_map)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add routes\n", __func__); + return ret; + } + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add widgets\n", __func__); + return ret; + } + + ret = snd_soc_add_component_controls(component, wsa_macro_snd_controls, + ARRAY_SIZE(wsa_macro_snd_controls)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add snd_ctls\n", __func__); + return ret; + } + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_MIX1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_VI Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_ECHO Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK1 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK2 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_WSA"); + snd_soc_dapm_ignore_suspend(dapm, "WSA SRC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_TX DEC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_TX DEC1_INP"); + snd_soc_dapm_sync(dapm); + + wsa_priv->component = component; + wsa_priv->spkr_gain_offset = WSA_MACRO_GAIN_OFFSET_0_DB; + wsa_macro_init_reg(component); + + return 0; +} + +static int wsa_macro_deinit(struct snd_soc_component *component) +{ + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->component = NULL; + + return 0; +} + +static void wsa_macro_add_child_devices(struct work_struct *work) +{ + struct wsa_macro_priv *wsa_priv; + struct platform_device *pdev; + struct device_node *node; + struct wsa_macro_swr_ctrl_data *swr_ctrl_data = NULL, *temp; + int ret; + u16 count = 0, ctrl_num = 0; + struct wsa_macro_swr_ctrl_platform_data *platdata; + char plat_dev_name[WSA_MACRO_SWR_STRING_LEN]; + + wsa_priv = container_of(work, struct wsa_macro_priv, + wsa_macro_add_child_devices_work); + if (!wsa_priv) { + pr_err("%s: Memory for wsa_priv does not exist\n", + __func__); + return; + } + if (!wsa_priv->dev || !wsa_priv->dev->of_node) { + dev_err(wsa_priv->dev, + "%s: DT node for wsa_priv does not exist\n", __func__); + return; + } + + platdata = &wsa_priv->swr_plat_data; + wsa_priv->child_count = 0; + + for_each_available_child_of_node(wsa_priv->dev->of_node, node) { + if (strnstr(node->name, "wsa_swr_master", + strlen("wsa_swr_master")) != NULL) + strlcpy(plat_dev_name, "wsa_swr_ctrl", + (WSA_MACRO_SWR_STRING_LEN - 1)); + else if (strnstr(node->name, "msm_cdc_pinctrl", + strlen("msm_cdc_pinctrl")) != NULL) + strlcpy(plat_dev_name, node->name, + (WSA_MACRO_SWR_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(wsa_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = wsa_priv->dev; + pdev->dev.of_node = node; + + if (strnstr(node->name, "wsa_swr_master", + strlen("wsa_swr_master")) != NULL) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct wsa_macro_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(&pdev->dev, "out of memory\n"); + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].wsa_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + wsa_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (wsa_priv->child_count < WSA_MACRO_CHILD_DEVICES_MAX) + wsa_priv->pdev_child_devices[ + wsa_priv->child_count++] = pdev; + else + goto err; + } + + return; +fail_pdev_add: + for (count = 0; count < wsa_priv->child_count; count++) + platform_device_put(wsa_priv->pdev_child_devices[count]); +err: + return; +} + +static void wsa_macro_init_ops(struct macro_ops *ops, + char __iomem *wsa_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->init = wsa_macro_init; + ops->exit = wsa_macro_deinit; + ops->io_base = wsa_io_base; + ops->dai_ptr = wsa_macro_dai; + ops->num_dais = ARRAY_SIZE(wsa_macro_dai); + ops->event_handler = wsa_macro_event_handler; + ops->set_port_map = wsa_macro_set_port_map; +} + +static int wsa_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops; + struct wsa_macro_priv *wsa_priv; + u32 wsa_base_addr, default_clk_id; + char __iomem *wsa_io_base; + int ret = 0; + u8 bcl_pmic_params[3]; + u32 is_used_wsa_swr_gpio = 1; + const char *is_used_wsa_swr_gpio_dt = "qcom,is-used-swr-gpio"; + + if (!bolero_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + + wsa_priv = devm_kzalloc(&pdev->dev, sizeof(struct wsa_macro_priv), + GFP_KERNEL); + if (!wsa_priv) + return -ENOMEM; + + wsa_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &wsa_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + if (of_find_property(pdev->dev.of_node, is_used_wsa_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_wsa_swr_gpio_dt, + &is_used_wsa_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_wsa_swr_gpio_dt); + is_used_wsa_swr_gpio = 1; + } + } + wsa_priv->wsa_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,wsa-swr-gpios", 0); + if (!wsa_priv->wsa_swr_gpio_p && is_used_wsa_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if (msm_cdc_pinctrl_get_state(wsa_priv->wsa_swr_gpio_p) < 0 && + is_used_wsa_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + msm_cdc_pinctrl_set_wakeup_capable( + wsa_priv->wsa_swr_gpio_p, false); + + wsa_io_base = devm_ioremap(&pdev->dev, + wsa_base_addr, WSA_MACRO_MAX_OFFSET); + if (!wsa_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -EINVAL; + } + wsa_priv->wsa_io_base = wsa_io_base; + wsa_priv->reset_swr = true; + INIT_WORK(&wsa_priv->wsa_macro_add_child_devices_work, + wsa_macro_add_child_devices); + wsa_priv->swr_plat_data.handle = (void *) wsa_priv; + wsa_priv->swr_plat_data.read = NULL; + wsa_priv->swr_plat_data.write = NULL; + wsa_priv->swr_plat_data.bulk_write = NULL; + wsa_priv->swr_plat_data.clk = wsa_swrm_clock; + wsa_priv->swr_plat_data.core_vote = wsa_macro_core_vote; + wsa_priv->swr_plat_data.handle_irq = NULL; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id", + &default_clk_id); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,mux0-clk-id"); + default_clk_id = WSA_CORE_CLK; + } + + ret = of_property_read_u8_array(pdev->dev.of_node, + "qcom,wsa-bcl-pmic-params", bcl_pmic_params, + sizeof(bcl_pmic_params)); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,wsa-bcl-pmic-params"); + } else { + wsa_priv->bcl_pmic_params.id = bcl_pmic_params[0]; + wsa_priv->bcl_pmic_params.sid = bcl_pmic_params[1]; + wsa_priv->bcl_pmic_params.ppid = bcl_pmic_params[2]; + } + wsa_priv->default_clk_id = default_clk_id; + + dev_set_drvdata(&pdev->dev, wsa_priv); + mutex_init(&wsa_priv->mclk_lock); + mutex_init(&wsa_priv->swr_clk_lock); + wsa_macro_init_ops(&ops, wsa_io_base); + ops.clk_id_req = wsa_priv->default_clk_id; + ops.default_clk_id = wsa_priv->default_clk_id; + + ret = bolero_register_macro(&pdev->dev, WSA_MACRO, &ops); + if (ret < 0) { + dev_err(&pdev->dev, "%s: register macro failed\n", __func__); + goto reg_macro_fail; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + schedule_work(&wsa_priv->wsa_macro_add_child_devices_work); + return ret; +reg_macro_fail: + mutex_destroy(&wsa_priv->mclk_lock); + mutex_destroy(&wsa_priv->swr_clk_lock); + return ret; +} + +static int wsa_macro_remove(struct platform_device *pdev) +{ + struct wsa_macro_priv *wsa_priv; + u16 count = 0; + + wsa_priv = dev_get_drvdata(&pdev->dev); + + if (!wsa_priv) + return -EINVAL; + + for (count = 0; count < wsa_priv->child_count && + count < WSA_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister(wsa_priv->pdev_child_devices[count]); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + bolero_unregister_macro(&pdev->dev, WSA_MACRO); + mutex_destroy(&wsa_priv->mclk_lock); + mutex_destroy(&wsa_priv->swr_clk_lock); + return 0; +} + +static const struct of_device_id wsa_macro_dt_match[] = { + {.compatible = "qcom,wsa-macro"}, + {} +}; + +static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + bolero_runtime_suspend, + bolero_runtime_resume, + NULL + ) +}; + +static struct platform_driver wsa_macro_driver = { + .driver = { + .name = "wsa_macro", + .owner = THIS_MODULE, + .pm = &bolero_dev_pm_ops, + .of_match_table = wsa_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = wsa_macro_probe, + .remove = wsa_macro_remove, +}; + +module_platform_driver(wsa_macro_driver); + +MODULE_DESCRIPTION("WSA macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/bolero/wsa-macro.h b/qcom/opensource/audio-kernel/asoc/codecs/bolero/wsa-macro.h new file mode 100644 index 0000000000..fa5147631a --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/bolero/wsa-macro.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ +#ifndef WSA_MACRO_H +#define WSA_MACRO_H + +/* + * Selects compander and smart boost settings + * for a given speaker mode + */ +enum { + WSA_MACRO_SPKR_MODE_DEFAULT, + WSA_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */ +}; + +/* Rx path gain offsets */ +enum { + WSA_MACRO_GAIN_OFFSET_M1P5_DB, + WSA_MACRO_GAIN_OFFSET_0_DB, +}; + + +#if IS_ENABLED(CONFIG_WSA_MACRO) +extern int wsa_macro_set_spkr_mode(struct snd_soc_component *component, + int mode); +extern int wsa_macro_set_spkr_gain_offset(struct snd_soc_component *component, + int offset); +#else /* CONFIG_WSA_MACRO */ +static inline int wsa_macro_set_spkr_mode(struct snd_soc_component *component, + int mode) +{ + return 0; +} +static inline int wsa_macro_set_spkr_gain_offset( + struct snd_soc_component *component, + int offset) +{ + return 0; +} +#endif /* CONFIG_WSA_MACRO */ +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/cpe_cmi.h b/qcom/opensource/audio-kernel/asoc/codecs/cpe_cmi.h new file mode 100644 index 0000000000..cd94c71826 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/cpe_cmi.h @@ -0,0 +1,484 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + */ + +#ifndef __CPE_CMI_H__ +#define __CPE_CMI_H__ + +#include + +#define CPE_AFE_PORT_1_TX 1 +#define CPE_AFE_PORT_3_TX 3 +#define CPE_AFE_PORT_ID_2_OUT 0x02 +#define CMI_INBAND_MESSAGE_SIZE 127 + +/* + * Multiple mad types can be supported at once. + * these values can be OR'ed to form the set of + * supported mad types + */ +#define MAD_TYPE_AUDIO (1 << 0) +#define MAD_TYPE_BEACON (1 << 1) +#define MAD_TYPE_ULTRASND (1 << 2) + +/* Core service command opcodes */ +#define CPE_CORE_SVC_CMD_SHARED_MEM_ALLOC (0x3001) +#define CPE_CORE_SVC_CMDRSP_SHARED_MEM_ALLOC (0x3002) +#define CPE_CORE_SVC_CMD_SHARED_MEM_DEALLOC (0x3003) +#define CPE_CORE_SVC_CMD_DRAM_ACCESS_REQ (0x3004) +#define CPE_CORE_SVC_EVENT_SYSTEM_BOOT (0x3005) +/* core service command opcodes for WCD9335 */ +#define CPE_CORE_SVC_CMD_CFG_CLK_PLAN (0x3006) +#define CPE_CORE_SVC_CMD_CLK_FREQ_REQUEST (0x3007) + +#define CPE_BOOT_SUCCESS 0x00 +#define CPE_BOOT_FAILED 0x01 + +#define CPE_CORE_VERSION_SYSTEM_BOOT_EVENT 0x01 + +/* LSM Service command opcodes */ +#define CPE_LSM_SESSION_CMD_OPEN_TX (0x2000) +#define CPE_LSM_SESSION_CMD_SET_PARAMS (0x2001) +#define CPE_LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x2002) +#define CPE_LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x2003) +#define CPE_LSM_SESSION_CMD_START (0x2004) +#define CPE_LSM_SESSION_CMD_STOP (0x2005) +#define CPE_LSM_SESSION_EVENT_DETECTION_STATUS_V2 (0x2006) +#define CPE_LSM_SESSION_CMD_CLOSE_TX (0x2007) +#define CPE_LSM_SESSION_CMD_SHARED_MEM_ALLOC (0x2008) +#define CPE_LSM_SESSION_CMDRSP_SHARED_MEM_ALLOC (0x2009) +#define CPE_LSM_SESSION_CMD_SHARED_MEM_DEALLOC (0x200A) +#define CPE_LSM_SESSION_CMD_TX_BUFF_OUTPUT_CONFIG (0x200f) +#define CPE_LSM_SESSION_CMD_OPEN_TX_V2 (0x200D) +#define CPE_LSM_SESSION_CMD_SET_PARAMS_V2 (0x200E) + +/* LSM Service module and param IDs */ +#define CPE_LSM_MODULE_ID_VOICE_WAKEUP (0x00012C00) +#define CPE_LSM_MODULE_ID_VOICE_WAKEUP_V2 (0x00012C0D) +#define CPE_LSM_MODULE_FRAMEWORK (0x00012C0E) + +#define CPE_LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01) +#define CPE_LSM_PARAM_ID_OPERATION_MODE (0x00012C02) +#define CPE_LSM_PARAM_ID_GAIN (0x00012C03) +#define CPE_LSM_PARAM_ID_CONNECT_TO_PORT (0x00012C04) +#define CPE_LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS (0x00012C07) + +/* LSM LAB command opcodes */ +#define CPE_LSM_SESSION_CMD_EOB 0x0000200B +#define CPE_LSM_MODULE_ID_LAB 0x00012C08 +/* used for enable/disable lab*/ +#define CPE_LSM_PARAM_ID_LAB_ENABLE 0x00012C09 +/* used for T in LAB config DSP internal buffer*/ +#define CPE_LSM_PARAM_ID_LAB_CONFIG 0x00012C0A +#define CPE_LSM_PARAM_ID_REGISTER_SOUND_MODEL (0x00012C14) +#define CPE_LSM_PARAM_ID_DEREGISTER_SOUND_MODEL (0x00012C15) +#define CPE_LSM_PARAM_ID_MEDIA_FMT (0x00012C1E) + +/* AFE Service command opcodes */ +#define CPE_AFE_PORT_CMD_START (0x1001) +#define CPE_AFE_PORT_CMD_STOP (0x1002) +#define CPE_AFE_PORT_CMD_SUSPEND (0x1003) +#define CPE_AFE_PORT_CMD_RESUME (0x1004) +#define CPE_AFE_PORT_CMD_SHARED_MEM_ALLOC (0x1005) +#define CPE_AFE_PORT_CMDRSP_SHARED_MEM_ALLOC (0x1006) +#define CPE_AFE_PORT_CMD_SHARED_MEM_DEALLOC (0x1007) +#define CPE_AFE_PORT_CMD_GENERIC_CONFIG (0x1008) +#define CPE_AFE_SVC_CMD_LAB_MODE (0x1009) + +/* AFE Service module and param IDs */ +#define CPE_AFE_CMD_SET_PARAM (0x1000) +#define CPE_AFE_MODULE_ID_SW_MAD (0x0001022D) +#define CPE_AFE_PARAM_ID_SW_MAD_CFG (0x0001022E) +#define CPE_AFE_PARAM_ID_SVM_MODEL (0x0001022F) + +#define CPE_AFE_MODULE_HW_MAD (0x00010230) +#define CPE_AFE_PARAM_ID_HW_MAD_CTL (0x00010232) +#define CPE_AFE_PARAM_ID_HW_MAD_CFG (0x00010231) + +#define CPE_AFE_MODULE_AUDIO_DEV_INTERFACE (0x0001020C) +#define CPE_AFE_PARAM_ID_GENERIC_PORT_CONFIG (0x00010253) + +#define CPE_CMI_BASIC_RSP_OPCODE (0x0001) +#define CPE_HDR_MAX_PLD_SIZE (0x7F) + +#define CMI_OBM_FLAG_IN_BAND 0 +#define CMI_OBM_FLAG_OUT_BAND 1 + +#define CMI_SHMEM_ALLOC_FAILED 0xff + +/* + * Future Service ID's can be added one line + * before the CMI_CPE_SERVICE_ID_MAX + */ +enum { + CMI_CPE_SERVICE_ID_MIN = 0, + CMI_CPE_CORE_SERVICE_ID, + CMI_CPE_AFE_SERVICE_ID, + CMI_CPE_LSM_SERVICE_ID, + CMI_CPE_SERVICE_ID_MAX, +}; + +#define CPE_LSM_SESSION_ID_MAX 2 + +#define IS_VALID_SESSION_ID(s_id) \ + (s_id <= CPE_LSM_SESSION_ID_MAX) + +#define IS_VALID_SERVICE_ID(s_id) \ + (s_id > CMI_CPE_SERVICE_ID_MIN && \ + s_id < CMI_CPE_SERVICE_ID_MAX) + +#define IS_VALID_PLD_SIZE(p_size) \ + (p_size <= CPE_HDR_MAX_PLD_SIZE) + +#define CMI_HDR_SET_OPCODE(hdr, cmd) (hdr->opcode = cmd) + + +#define CMI_HDR_SET(hdr_info, mask, shift, value) \ + (hdr_info = (((hdr_info) & ~(mask)) | \ + ((value << shift) & mask))) + +#define SVC_ID_SHIFT 4 +#define SVC_ID_MASK (0x07 << SVC_ID_SHIFT) + +#define SESSION_ID_SHIFT 0 +#define SESSION_ID_MASK (0x0F << SESSION_ID_SHIFT) + +#define PAYLD_SIZE_SHIFT 0 +#define PAYLD_SIZE_MASK (0x7F << PAYLD_SIZE_SHIFT) + +#define OBM_FLAG_SHIFT 7 +#define OBM_FLAG_MASK (1 << OBM_FLAG_SHIFT) + +#define VERSION_SHIFT 7 +#define VERSION_MASK (1 << VERSION_SHIFT) + +#define CMI_HDR_SET_SERVICE(hdr, s_id) \ + CMI_HDR_SET(hdr->hdr_info, SVC_ID_MASK,\ + SVC_ID_SHIFT, s_id) +#define CMI_HDR_GET_SERVICE(hdr) \ + ((hdr->hdr_info >> SVC_ID_SHIFT) & \ + (SVC_ID_MASK >> SVC_ID_SHIFT)) + + +#define CMI_HDR_SET_SESSION(hdr, s_id) \ + CMI_HDR_SET(hdr->hdr_info, SESSION_ID_MASK,\ + SESSION_ID_SHIFT, s_id) + +#define CMI_HDR_GET_SESSION_ID(hdr) \ + ((hdr->hdr_info >> SESSION_ID_SHIFT) & \ + (SESSION_ID_MASK >> SESSION_ID_SHIFT)) + +#define CMI_GET_HEADER(msg) ((struct cmi_hdr *)(msg)) +#define CMI_GET_PAYLOAD(msg) ((void *)(CMI_GET_HEADER(msg) + 1)) +#define CMI_GET_OPCODE(msg) (CMI_GET_HEADER(msg)->opcode) + +#define CMI_HDR_SET_VERSION(hdr, ver) \ + CMI_HDR_SET(hdr->hdr_info, VERSION_MASK, \ + VERSION_SHIFT, ver) + +#define CMI_HDR_SET_PAYLOAD_SIZE(hdr, p_size) \ + CMI_HDR_SET(hdr->pld_info, PAYLD_SIZE_MASK, \ + PAYLD_SIZE_SHIFT, p_size) + +#define CMI_HDR_GET_PAYLOAD_SIZE(hdr) \ + ((hdr->pld_info >> PAYLD_SIZE_SHIFT) & \ + (PAYLD_SIZE_MASK >> PAYLD_SIZE_SHIFT)) + +#define CMI_HDR_SET_OBM(hdr, obm_flag) \ + CMI_HDR_SET(hdr->pld_info, OBM_FLAG_MASK, \ + OBM_FLAG_SHIFT, obm_flag) + +#define CMI_HDR_GET_OBM_FLAG(hdr) \ + ((hdr->pld_info >> OBM_FLAG_SHIFT) & \ + (OBM_FLAG_MASK >> OBM_FLAG_SHIFT)) + +struct cmi_hdr { + /* + * bits 0:3 is session id + * bits 4:6 is service id + * bit 7 is the version flag + */ + u8 hdr_info; + + /* + * bits 0:6 is payload size in case of in-band message + * bits 0:6 is size (OBM message size) + * bit 7 is the OBM flag + */ + u8 pld_info; + + /* 16 bit command opcode */ + u16 opcode; +} __packed; + +union cpe_addr { + u64 msw_lsw; + void *kvaddr; +} __packed; + +struct cmi_obm { + u32 version; + u32 size; + union cpe_addr data_ptr; + u32 mem_handle; +} __packed; + +struct cmi_obm_msg { + struct cmi_hdr hdr; + struct cmi_obm pld; +} __packed; + +struct cmi_core_svc_event_system_boot { + u8 status; + u8 version; + u16 sfr_buff_size; + u32 sfr_buff_address; +} __packed; + +struct cmi_core_svc_cmd_shared_mem_alloc { + u32 size; +} __packed; + +struct cmi_core_svc_cmdrsp_shared_mem_alloc { + u32 addr; +} __packed; + +struct cmi_core_svc_cmd_clk_freq_request { + u32 clk_freq; +} __packed; + +struct cmi_msg_transport { + u32 size; + u32 addr; +} __packed; + +struct cmi_basic_rsp_result { + u8 status; +} __packed; + +struct cpe_lsm_cmd_open_tx { + struct cmi_hdr hdr; + u16 app_id; + u16 reserved; + u32 sampling_rate; +} __packed; + +struct cpe_lsm_cmd_open_tx_v2 { + struct cmi_hdr hdr; + u32 topology_id; +} __packed; + +struct cpe_cmd_shmem_alloc { + struct cmi_hdr hdr; + u32 size; +} __packed; + +struct cpe_cmdrsp_shmem_alloc { + struct cmi_hdr hdr; + u32 addr; +} __packed; + +struct cpe_cmd_shmem_dealloc { + struct cmi_hdr hdr; + u32 addr; +} __packed; + +struct cpe_lsm_event_detect_v2 { + struct cmi_hdr hdr; + u8 detection_status; + u8 size; + u8 payload[0]; +} __packed; + +struct cpe_lsm_psize_res { + u16 param_size; + u16 reserved; +} __packed; + +union cpe_lsm_param_size { + u32 param_size; + struct cpe_lsm_psize_res sr; +} __packed; + +struct cpe_param_data { + u32 module_id; + u32 param_id; + union cpe_lsm_param_size p_size; +} __packed; + +struct cpe_lsm_param_epd_thres { + struct cmi_hdr hdr; + struct cpe_param_data param; + u32 minor_version; + u32 epd_begin; + u32 epd_end; +} __packed; + +struct cpe_lsm_param_gain { + struct cmi_hdr hdr; + struct cpe_param_data param; + u32 minor_version; + u16 gain; + u16 reserved; +} __packed; + +struct cpe_afe_hw_mad_ctrl { + struct cpe_param_data param; + u32 minor_version; + u16 mad_type; + u16 mad_enable; +} __packed; + +struct cpe_afe_port_cfg { + struct cpe_param_data param; + u32 minor_version; + u16 bit_width; + u16 num_channels; + u32 sample_rate; +} __packed; + +struct cpe_afe_cmd_port_cfg { + struct cmi_hdr hdr; + u8 bit_width; + u8 num_channels; + u16 buffer_size; + u32 sample_rate; +} __packed; + +struct cpe_afe_params { + struct cmi_hdr hdr; + struct cpe_afe_hw_mad_ctrl hw_mad_ctrl; + struct cpe_afe_port_cfg port_cfg; +} __packed; + +struct cpe_afe_svc_cmd_mode { + struct cmi_hdr hdr; + u8 mode; +} __packed; + +struct cpe_lsm_param_opmode { + struct cmi_hdr hdr; + struct cpe_param_data param; + u32 minor_version; + u16 mode; + u16 reserved; +} __packed; + +struct cpe_lsm_param_connectport { + struct cmi_hdr hdr; + struct cpe_param_data param; + u32 minor_version; + u16 afe_port_id; + u16 reserved; +} __packed; + +/* + * This cannot be sent to CPE as is, + * need to append the conf_levels dynamically + */ +struct cpe_lsm_conf_level { + struct cmi_hdr hdr; + struct cpe_param_data param; + u8 num_active_models; +} __packed; + +struct cpe_lsm_output_format_cfg { + struct cmi_hdr hdr; + u8 format; + u8 packing; + u8 data_path_events; +} __packed; + +struct cpe_lsm_lab_enable { + struct cpe_param_data param; + u16 enable; + u16 reserved; +} __packed; + +struct cpe_lsm_control_lab { + struct cmi_hdr hdr; + struct cpe_lsm_lab_enable lab_enable; +} __packed; + +struct cpe_lsm_lab_config { + struct cpe_param_data param; + u32 minor_ver; + u32 latency; +} __packed; + +struct cpe_lsm_lab_latency_config { + struct cmi_hdr hdr; + struct cpe_lsm_lab_config latency_cfg; +} __packed; + +struct cpe_lsm_media_fmt_param { + struct cmi_hdr hdr; + struct cpe_param_data param; + u32 minor_version; + u32 sample_rate; + u16 num_channels; + u16 bit_width; +} __packed; + + +#define CPE_PARAM_LSM_LAB_LATENCY_SIZE (\ + sizeof(struct cpe_lsm_lab_latency_config) - \ + sizeof(struct cmi_hdr)) +#define PARAM_SIZE_LSM_LATENCY_SIZE (\ + sizeof(struct cpe_lsm_lab_config) - \ + sizeof(struct cpe_param_data)) +#define CPE_PARAM_SIZE_LSM_LAB_CONTROL (\ + sizeof(struct cpe_lsm_control_lab) - \ + sizeof(struct cmi_hdr)) +#define PARAM_SIZE_LSM_CONTROL_SIZE (sizeof(struct cpe_lsm_lab_enable) - \ + sizeof(struct cpe_param_data)) +#define PARAM_SIZE_AFE_HW_MAD_CTRL (sizeof(struct cpe_afe_hw_mad_ctrl) - \ + sizeof(struct cpe_param_data)) +#define PARAM_SIZE_AFE_PORT_CFG (sizeof(struct cpe_afe_port_cfg) - \ + sizeof(struct cpe_param_data)) +#define CPE_AFE_PARAM_PAYLOAD_SIZE (sizeof(struct cpe_afe_params) - \ + sizeof(struct cmi_hdr)) + +#define OPEN_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx) - \ + sizeof(struct cmi_hdr)) +#define OPEN_V2_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx_v2) - \ + sizeof(struct cmi_hdr)) +#define SHMEM_ALLOC_CMD_PLD_SIZE (sizeof(struct cpe_cmd_shmem_alloc) - \ + sizeof(struct cmi_hdr)) + +#define SHMEM_DEALLOC_CMD_PLD_SIZE (sizeof(struct cpe_cmd_shmem_dealloc) - \ + sizeof(struct cmi_hdr)) +#define OUT_FMT_CFG_CMD_PAYLOAD_SIZE ( \ + sizeof(struct cpe_lsm_output_format_cfg) - \ + sizeof(struct cmi_hdr)) + +#define CPE_AFE_CMD_PORT_CFG_PAYLOAD_SIZE \ + (sizeof(struct cpe_afe_cmd_port_cfg) - \ + sizeof(struct cmi_hdr)) + +#define CPE_AFE_CMD_MODE_PAYLOAD_SIZE \ + (sizeof(struct cpe_afe_svc_cmd_mode) - \ + sizeof(struct cmi_hdr)) +#define CPE_CMD_EPD_THRES_PLD_SIZE (sizeof(struct cpe_lsm_param_epd_thres) - \ + sizeof(struct cmi_hdr)) +#define CPE_EPD_THRES_PARAM_SIZE ((CPE_CMD_EPD_THRES_PLD_SIZE) - \ + sizeof(struct cpe_param_data)) +#define CPE_CMD_OPMODE_PLD_SIZE (sizeof(struct cpe_lsm_param_opmode) - \ + sizeof(struct cmi_hdr)) +#define CPE_OPMODE_PARAM_SIZE ((CPE_CMD_OPMODE_PLD_SIZE) -\ + sizeof(struct cpe_param_data)) +#define CPE_CMD_CONNECTPORT_PLD_SIZE \ + (sizeof(struct cpe_lsm_param_connectport) - \ + sizeof(struct cmi_hdr)) +#define CPE_CONNECTPORT_PARAM_SIZE ((CPE_CMD_CONNECTPORT_PLD_SIZE) - \ + sizeof(struct cpe_param_data)) +#define CPE_CMD_GAIN_PLD_SIZE (sizeof(struct cpe_lsm_param_gain) - \ + sizeof(struct cmi_hdr)) +#define CPE_GAIN_PARAM_SIZE ((CPE_CMD_GAIN_PLD_SIZE) - \ + sizeof(struct cpe_param_data)) +#define CPE_MEDIA_FMT_PLD_SIZE (sizeof(struct cpe_lsm_media_fmt_param) - \ + sizeof(struct cmi_hdr)) +#define CPE_MEDIA_FMT_PARAM_SIZE ((CPE_MEDIA_FMT_PLD_SIZE) - \ + sizeof(struct cpe_param_data)) +#endif /* __CPE_CMI_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/cpe_err.h b/qcom/opensource/audio-kernel/asoc/codecs/cpe_err.h new file mode 100644 index 0000000000..29ea922926 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/cpe_err.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef __CPE_ERR__ +#define __CPE_ERR__ + +#include + +/* ERROR CODES */ +/* Success. The operation completed with no errors. */ +#define CPE_EOK 0x00000000 +/* General failure. */ +#define CPE_EFAILED 0x00000001 +/* Bad operation parameter. */ +#define CPE_EBADPARAM 0x00000002 +/* Unsupported routine or operation. */ +#define CPE_EUNSUPPORTED 0x00000003 +/* Unsupported version. */ +#define CPE_EVERSION 0x00000004 +/* Unexpected problem encountered. */ +#define CPE_EUNEXPECTED 0x00000005 +/* Unhandled problem occurred. */ +#define CPE_EPANIC 0x00000006 +/* Unable to allocate resource. */ +#define CPE_ENORESOURCE 0x00000007 +/* Invalid handle. */ +#define CPE_EHANDLE 0x00000008 +/* Operation is already processed. */ +#define CPE_EALREADY 0x00000009 +/* Operation is not ready to be processed. */ +#define CPE_ENOTREADY 0x0000000A +/* Operation is pending completion. */ +#define CPE_EPENDING 0x0000000B +/* Operation could not be accepted or processed. */ +#define CPE_EBUSY 0x0000000C +/* Operation aborted due to an error. */ +#define CPE_EABORTED 0x0000000D +/* Operation preempted by a higher priority. */ +#define CPE_EPREEMPTED 0x0000000E +/* Operation requests intervention to complete. */ +#define CPE_ECONTINUE 0x0000000F +/* Operation requests immediate intervention to complete. */ +#define CPE_EIMMEDIATE 0x00000010 +/* Operation is not implemented. */ +#define CPE_ENOTIMPL 0x00000011 +/* Operation needs more data or resources. */ +#define CPE_ENEEDMORE 0x00000012 +/* Operation does not have memory. */ +#define CPE_ENOMEMORY 0x00000014 +/* Item does not exist. */ +#define CPE_ENOTEXIST 0x00000015 +/* Operation is finished. */ +#define CPE_ETERMINATED 0x00000016 +/* Max count for adsp error code sent to HLOS*/ +#define CPE_ERR_MAX (CPE_ETERMINATED + 1) + + +/* ERROR STRING */ +/* Success. The operation completed with no errors. */ +#define CPE_EOK_STR "CPE_EOK" +/* General failure. */ +#define CPE_EFAILED_STR "CPE_EFAILED" +/* Bad operation parameter. */ +#define CPE_EBADPARAM_STR "CPE_EBADPARAM" +/* Unsupported routine or operation. */ +#define CPE_EUNSUPPORTED_STR "CPE_EUNSUPPORTED" +/* Unsupported version. */ +#define CPE_EVERSION_STR "CPE_EVERSION" +/* Unexpected problem encountered. */ +#define CPE_EUNEXPECTED_STR "CPE_EUNEXPECTED" +/* Unhandled problem occurred. */ +#define CPE_EPANIC_STR "CPE_EPANIC" +/* Unable to allocate resource. */ +#define CPE_ENORESOURCE_STR "CPE_ENORESOURCE" +/* Invalid handle. */ +#define CPE_EHANDLE_STR "CPE_EHANDLE" +/* Operation is already processed. */ +#define CPE_EALREADY_STR "CPE_EALREADY" +/* Operation is not ready to be processed. */ +#define CPE_ENOTREADY_STR "CPE_ENOTREADY" +/* Operation is pending completion. */ +#define CPE_EPENDING_STR "CPE_EPENDING" +/* Operation could not be accepted or processed. */ +#define CPE_EBUSY_STR "CPE_EBUSY" +/* Operation aborted due to an error. */ +#define CPE_EABORTED_STR "CPE_EABORTED" +/* Operation preempted by a higher priority. */ +#define CPE_EPREEMPTED_STR "CPE_EPREEMPTED" +/* Operation requests intervention to complete. */ +#define CPE_ECONTINUE_STR "CPE_ECONTINUE" +/* Operation requests immediate intervention to complete. */ +#define CPE_EIMMEDIATE_STR "CPE_EIMMEDIATE" +/* Operation is not implemented. */ +#define CPE_ENOTIMPL_STR "CPE_ENOTIMPL" +/* Operation needs more data or resources. */ +#define CPE_ENEEDMORE_STR "CPE_ENEEDMORE" +/* Operation does not have memory. */ +#define CPE_ENOMEMORY_STR "CPE_ENOMEMORY" +/* Item does not exist. */ +#define CPE_ENOTEXIST_STR "CPE_ENOTEXIST" +/* Operation is finished. */ +#define CPE_ETERMINATED_STR "CPE_ETERMINATED" +/* Unexpected error code. */ +#define CPE_ERR_MAX_STR "CPE_ERR_MAX" + + +struct cpe_err_code { + int lnx_err_code; + char *cpe_err_str; +}; + + +static struct cpe_err_code cpe_err_code_info[CPE_ERR_MAX+1] = { + { 0, CPE_EOK_STR}, + { -ENOTRECOVERABLE, CPE_EFAILED_STR}, + { -EINVAL, CPE_EBADPARAM_STR}, + { -EOPNOTSUPP, CPE_EUNSUPPORTED_STR}, + { -ENOPROTOOPT, CPE_EVERSION_STR}, + { -ENOTRECOVERABLE, CPE_EUNEXPECTED_STR}, + { -ENOTRECOVERABLE, CPE_EPANIC_STR}, + { -ENOSPC, CPE_ENORESOURCE_STR}, + { -EBADR, CPE_EHANDLE_STR}, + { -EALREADY, CPE_EALREADY_STR}, + { -EPERM, CPE_ENOTREADY_STR}, + { -EINPROGRESS, CPE_EPENDING_STR}, + { -EBUSY, CPE_EBUSY_STR}, + { -ECANCELED, CPE_EABORTED_STR}, + { -EAGAIN, CPE_EPREEMPTED_STR}, + { -EAGAIN, CPE_ECONTINUE_STR}, + { -EAGAIN, CPE_EIMMEDIATE_STR}, + { -EAGAIN, CPE_ENOTIMPL_STR}, + { -ENODATA, CPE_ENEEDMORE_STR}, + { -EADV, CPE_ERR_MAX_STR}, + { -ENOMEM, CPE_ENOMEMORY_STR}, + { -ENODEV, CPE_ENOTEXIST_STR}, + { -EADV, CPE_ETERMINATED_STR}, + { -EADV, CPE_ERR_MAX_STR}, +}; + +static inline int cpe_err_get_lnx_err_code(u32 cpe_error) +{ + if (cpe_error > CPE_ERR_MAX) + return cpe_err_code_info[CPE_ERR_MAX].lnx_err_code; + else + return cpe_err_code_info[cpe_error].lnx_err_code; +} + +static inline char *cpe_err_get_err_str(u32 cpe_error) +{ + if (cpe_error > CPE_ERR_MAX) + return cpe_err_code_info[CPE_ERR_MAX].cpe_err_str; + else + return cpe_err_code_info[cpe_error].cpe_err_str; +} + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/Kbuild new file mode 100644 index 0000000000..61463e7a0f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/Kbuild @@ -0,0 +1,105 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_QCS405), y) + include $(AUDIO_ROOT)/config/qcs405auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/qcs405autoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ CSRA66X0 ############ + +# for CSRA66X0 Codec +ifdef CONFIG_SND_SOC_CSRA66X0 + CSRA66X0_OBJS += csra66x0.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +#EXTRA_CFLAGS += $(INCS) +ccflags-y += $(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 +ccflags-y += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +#EXTRA_CFLAGS += -Wheader-guard +ccflags-y += -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_CSRA66X0) += csra66x0_dlkm.o +csra66x0_dlkm-y := $(CSRA66X0_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/csra66x0.c b/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/csra66x0.c new file mode 100644 index 0000000000..9cdbbdaaab --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/csra66x0.c @@ -0,0 +1,1525 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "csra66x0.h" + +#define DRV_NAME "csra66x0_codec" +#define CSRA66X0_SYSFS_ENTRY_MAX_LEN 64 + +/* CSRA66X0 register default values */ +static struct reg_default csra66x0_reg_defaults[] = { + {CSRA66X0_AUDIO_IF_RX_CONFIG1, 0x00}, + {CSRA66X0_AUDIO_IF_RX_CONFIG2, 0x0B}, + {CSRA66X0_AUDIO_IF_RX_CONFIG3, 0x0F}, + {CSRA66X0_AUDIO_IF_TX_EN, 0x00}, + {CSRA66X0_AUDIO_IF_TX_CONFIG1, 0x6B}, + {CSRA66X0_AUDIO_IF_TX_CONFIG2, 0x02}, + {CSRA66X0_I2C_DEVICE_ADDRESS, 0x0D}, + {CSRA66X0_CHIP_ID_FA, 0x39}, + {CSRA66X0_ROM_VER_FA, 0x08}, + {CSRA66X0_CHIP_REV_0_FA, 0x05}, + {CSRA66X0_CHIP_REV_1_FA, 0x03}, + {CSRA66X0_CH1_MIX_SEL, 0x01}, + {CSRA66X0_CH2_MIX_SEL, 0x10}, + {CSRA66X0_CH1_SAMPLE1_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE1_SCALE_1, 0x20}, + {CSRA66X0_CH1_SAMPLE3_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE3_SCALE_1, 0x20}, + {CSRA66X0_CH1_SAMPLE5_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE5_SCALE_1, 0x20}, + {CSRA66X0_CH1_SAMPLE7_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE7_SCALE_1, 0x20}, + {CSRA66X0_CH1_SAMPLE2_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE2_SCALE_1, 0x20}, + {CSRA66X0_CH1_SAMPLE4_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE4_SCALE_1, 0x20}, + {CSRA66X0_CH1_SAMPLE6_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE6_SCALE_1, 0x20}, + {CSRA66X0_CH1_SAMPLE8_SCALE_0, 0x00}, + {CSRA66X0_CH1_SAMPLE8_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE1_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE1_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE3_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE3_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE5_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE5_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE7_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE7_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE2_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE2_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE4_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE4_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE6_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE6_SCALE_1, 0x20}, + {CSRA66X0_CH2_SAMPLE8_SCALE_0, 0x00}, + {CSRA66X0_CH2_SAMPLE8_SCALE_1, 0x20}, + {CSRA66X0_VOLUME_CONFIG_FA, 0x26}, + {CSRA66X0_STARTUP_DELAY_FA, 0x00}, + {CSRA66X0_CH1_VOLUME_0_FA, 0x19}, + {CSRA66X0_CH1_VOLUME_1_FA, 0x01}, + {CSRA66X0_CH2_VOLUME_0_FA, 0x19}, + {CSRA66X0_CH2_VOLUME_1_FA, 0x01}, + {CSRA66X0_QUAD_ENC_COUNT_0_FA, 0x00}, + {CSRA66X0_QUAD_ENC_COUNT_1_FA, 0x00}, + {CSRA66X0_SOFT_CLIP_CONFIG, 0x00}, + {CSRA66X0_CH1_HARD_CLIP_THRESH, 0x00}, + {CSRA66X0_CH2_HARD_CLIP_THRESH, 0x00}, + {CSRA66X0_SOFT_CLIP_THRESH, 0x00}, + {CSRA66X0_DS_ENABLE_THRESH_0, 0x05}, + {CSRA66X0_DS_ENABLE_THRESH_1, 0x00}, + {CSRA66X0_DS_TARGET_COUNT_0, 0x00}, + {CSRA66X0_DS_TARGET_COUNT_1, 0xFF}, + {CSRA66X0_DS_TARGET_COUNT_2, 0xFF}, + {CSRA66X0_DS_DISABLE_THRESH_0, 0x0F}, + {CSRA66X0_DS_DISABLE_THRESH_1, 0x00}, + {CSRA66X0_DCA_CTRL, 0x07}, + {CSRA66X0_CH1_DCA_THRESH, 0x40}, + {CSRA66X0_CH2_DCA_THRESH, 0x40}, + {CSRA66X0_DCA_ATTACK_RATE, 0x00}, + {CSRA66X0_DCA_RELEASE_RATE, 0x00}, + {CSRA66X0_CH1_OUTPUT_INVERT_EN, 0x00}, + {CSRA66X0_CH2_OUTPUT_INVERT_EN, 0x00}, + {CSRA66X0_CH1_176P4K_DELAY, 0x00}, + {CSRA66X0_CH2_176P4K_DELAY, 0x00}, + {CSRA66X0_CH1_192K_DELAY, 0x00}, + {CSRA66X0_CH2_192K_DELAY, 0x00}, + {CSRA66X0_DEEMP_CONFIG_FA, 0x00}, + {CSRA66X0_CH1_TREBLE_GAIN_CTRL_FA, 0x00}, + {CSRA66X0_CH2_TREBLE_GAIN_CTRL_FA, 0x00}, + {CSRA66X0_CH1_TREBLE_FC_CTRL_FA, 0x00}, + {CSRA66X0_CH2_TREBLE_FC_CTRL_FA, 0x00}, + {CSRA66X0_CH1_BASS_GAIN_CTRL_FA, 0x00}, + {CSRA66X0_CH2_BASS_GAIN_CTRL_FA, 0x00}, + {CSRA66X0_CH1_BASS_FC_CTRL_FA, 0x00}, + {CSRA66X0_CH2_BASS_FC_CTRL_FA, 0x00}, + {CSRA66X0_FILTER_SEL_8K, 0x00}, + {CSRA66X0_FILTER_SEL_11P025K, 0x00}, + {CSRA66X0_FILTER_SEL_16K, 0x00}, + {CSRA66X0_FILTER_SEL_22P05K, 0x00}, + {CSRA66X0_FILTER_SEL_32K, 0x00}, + {CSRA66X0_FILTER_SEL_44P1K_48K, 0x00}, + {CSRA66X0_FILTER_SEL_88P2K_96K, 0x00}, + {CSRA66X0_FILTER_SEL_176P4K_192K, 0x00}, + /* RESERVED */ + {CSRA66X0_USER_DSP_CTRL, 0x00}, + {CSRA66X0_TEST_TONE_CTRL, 0x00}, + {CSRA66X0_TEST_TONE_FREQ_0, 0x00}, + {CSRA66X0_TEST_TONE_FREQ_1, 0x00}, + {CSRA66X0_TEST_TONE_FREQ_2, 0x00}, + {CSRA66X0_AUDIO_RATE_CTRL_FA, 0x08}, + {CSRA66X0_MODULATION_INDEX_CTRL, 0x3F}, + {CSRA66X0_MODULATION_INDEX_COUNT, 0x10}, + {CSRA66X0_MIN_MODULATION_PULSE_WIDTH, 0x7A}, + {CSRA66X0_DEAD_TIME_CTRL, 0x00}, + {CSRA66X0_DEAD_TIME_THRESHOLD_0, 0xE7}, + {CSRA66X0_DEAD_TIME_THRESHOLD_1, 0x26}, + {CSRA66X0_DEAD_TIME_THRESHOLD_2, 0x40}, + {CSRA66X0_CH1_LOW_SIDE_DLY, 0x00}, + {CSRA66X0_CH2_LOW_SIDE_DLY, 0x00}, + {CSRA66X0_SPECTRUM_CTRL, 0x00}, + /* RESERVED */ + {CSRA66X0_SPECTRUM_SPREAD_CTRL, 0x0C}, + /* RESERVED */ + {CSRA66X0_EXT_PA_PROTECT_POLARITY, 0x03}, + {CSRA66X0_TEMP0_BACKOFF_COMP_VALUE, 0x98}, + {CSRA66X0_TEMP0_SHUTDOWN_COMP_VALUE, 0xA3}, + {CSRA66X0_TEMP1_BACKOFF_COMP_VALUE, 0x98}, + {CSRA66X0_TEMP1_SHUTDOWN_COMP_VALUE, 0xA3}, + {CSRA66X0_TEMP_PROT_BACKOFF, 0x00}, + {CSRA66X0_TEMP_READ0_FA, 0x00}, + {CSRA66X0_TEMP_READ1_FA, 0x00}, + {CSRA66X0_CHIP_STATE_CTRL_FA, 0x02}, + /* RESERVED */ + {CSRA66X0_PWM_OUTPUT_CONFIG, 0x00}, + {CSRA66X0_MISC_CONTROL_STATUS_0, 0x08}, + {CSRA66X0_MISC_CONTROL_STATUS_1_FA, 0x40}, + {CSRA66X0_PIO0_SELECT, 0x00}, + {CSRA66X0_PIO1_SELECT, 0x00}, + {CSRA66X0_PIO2_SELECT, 0x00}, + {CSRA66X0_PIO3_SELECT, 0x00}, + {CSRA66X0_PIO4_SELECT, 0x00}, + {CSRA66X0_PIO5_SELECT, 0x00}, + {CSRA66X0_PIO6_SELECT, 0x00}, + {CSRA66X0_PIO7_SELECT, 0x00}, + {CSRA66X0_PIO8_SELECT, 0x00}, + {CSRA66X0_PIO_DIRN0, 0xFF}, + {CSRA66X0_PIO_DIRN1, 0x01}, + {CSRA66X0_PIO_PULL_EN0, 0xFF}, + {CSRA66X0_PIO_PULL_EN1, 0x01}, + {CSRA66X0_PIO_PULL_DIR0, 0x00}, + {CSRA66X0_PIO_PULL_DIR1, 0x00}, + {CSRA66X0_PIO_DRIVE_OUT0_FA, 0x00}, + {CSRA66X0_PIO_DRIVE_OUT1_FA, 0x00}, + {CSRA66X0_PIO_STATUS_IN0_FA, 0x00}, + {CSRA66X0_PIO_STATUS_IN1_FA, 0x00}, + /* RESERVED */ + {CSRA66X0_IRQ_OUTPUT_ENABLE, 0x00}, + {CSRA66X0_IRQ_OUTPUT_POLARITY, 0x01}, + {CSRA66X0_IRQ_OUTPUT_STATUS_FA, 0x00}, + {CSRA66X0_CLIP_DCA_STATUS_FA, 0x00}, + {CSRA66X0_CHIP_STATE_STATUS_FA, 0x02}, + {CSRA66X0_FAULT_STATUS_FA, 0x00}, + {CSRA66X0_OTP_STATUS_FA, 0x00}, + {CSRA66X0_AUDIO_IF_STATUS_FA, 0x00}, + /* RESERVED */ + {CSRA66X0_DSP_SATURATION_STATUS_FA, 0x00}, + {CSRA66X0_AUDIO_RATE_STATUS_FA, 0x00}, + /* RESERVED */ + {CSRA66X0_DISABLE_PWM_OUTPUT, 0x00}, + /* RESERVED */ + {CSRA66X0_OTP_VER_FA, 0x03}, + {CSRA66X0_RAM_VER_FA, 0x02}, + /* RESERVED */ + {CSRA66X0_AUDIO_SATURATION_FLAGS_FA, 0x00}, + {CSRA66X0_DCOFFSET_CHAN_1_01_FA, 0x00}, + {CSRA66X0_DCOFFSET_CHAN_1_02_FA, 0x00}, + {CSRA66X0_DCOFFSET_CHAN_1_03_FA, 0x00}, + {CSRA66X0_DCOFFSET_CHAN_2_01_FA, 0x00}, + {CSRA66X0_DCOFFSET_CHAN_2_02_FA, 0x00}, + {CSRA66X0_DCOFFSET_CHAN_2_03_FA, 0x00}, + {CSRA66X0_FORCED_PA_SWITCHING_CTRL, 0x90}, + {CSRA66X0_PA_FORCE_PULSE_WIDTH, 0x07}, + {CSRA66X0_PA_HIGH_MODULATION_CTRL_CH1, 0x00}, + /* RESERVED */ + {CSRA66X0_HIGH_MODULATION_THRESHOLD_LOW, 0xD4}, + {CSRA66X0_HIGH_MODULATION_THRESHOLD_HIGH, 0x78}, + /* RESERVED */ + {CSRA66X0_PA_FREEZE_CTRL, 0x00}, + {CSRA66X0_DCA_FREEZE_CTRL, 0x3C}, + /* RESERVED */ +}; + +static bool csra66x0_addr_is_in_range(unsigned int addr, + unsigned int addr_min, unsigned int addr_max) +{ + if ((addr >= addr_min) + && (addr <= addr_max)) + return true; + else + return false; +} + +static bool csra66x0_volatile_register(struct device *dev, unsigned int reg) +{ + /* coeff registers */ + if (csra66x0_addr_is_in_range(reg, CSRA66X0_COEFF_BASE, + CSRA66X0_MAX_COEFF_ADDR)) + return true; + + /* control registers */ + switch (reg) { + case CSRA66X0_CHIP_ID_FA: + case CSRA66X0_ROM_VER_FA: + case CSRA66X0_CHIP_REV_0_FA: + case CSRA66X0_CHIP_REV_1_FA: + case CSRA66X0_TEMP_READ0_FA: + case CSRA66X0_TEMP_READ1_FA: + case CSRA66X0_CHIP_STATE_CTRL_FA: + case CSRA66X0_MISC_CONTROL_STATUS_1_FA: + case CSRA66X0_IRQ_OUTPUT_STATUS_FA: + case CSRA66X0_CLIP_DCA_STATUS_FA: + case CSRA66X0_CHIP_STATE_STATUS_FA: + case CSRA66X0_FAULT_STATUS_FA: + case CSRA66X0_OTP_STATUS_FA: + case CSRA66X0_AUDIO_IF_STATUS_FA: + case CSRA66X0_DSP_SATURATION_STATUS_FA: + case CSRA66X0_AUDIO_RATE_STATUS_FA: + case CSRA66X0_CH1_MIX_SEL: + case CSRA66X0_CH2_MIX_SEL: + case CSRA66X0_CH1_SAMPLE1_SCALE_0: + case CSRA66X0_CH1_SAMPLE1_SCALE_1: + case CSRA66X0_CH1_SAMPLE3_SCALE_0: + case CSRA66X0_CH1_SAMPLE3_SCALE_1: + case CSRA66X0_CH1_SAMPLE5_SCALE_0: + case CSRA66X0_CH1_SAMPLE5_SCALE_1: + case CSRA66X0_CH1_SAMPLE7_SCALE_0: + case CSRA66X0_CH1_SAMPLE7_SCALE_1: + case CSRA66X0_CH1_SAMPLE2_SCALE_0: + case CSRA66X0_CH1_SAMPLE2_SCALE_1: + case CSRA66X0_CH1_SAMPLE4_SCALE_0: + case CSRA66X0_CH1_SAMPLE4_SCALE_1: + case CSRA66X0_CH1_SAMPLE6_SCALE_0: + case CSRA66X0_CH1_SAMPLE6_SCALE_1: + case CSRA66X0_CH1_SAMPLE8_SCALE_0: + case CSRA66X0_CH1_SAMPLE8_SCALE_1: + case CSRA66X0_CH2_SAMPLE1_SCALE_0: + case CSRA66X0_CH2_SAMPLE1_SCALE_1: + case CSRA66X0_CH2_SAMPLE3_SCALE_0: + case CSRA66X0_CH2_SAMPLE3_SCALE_1: + case CSRA66X0_CH2_SAMPLE5_SCALE_0: + case CSRA66X0_CH2_SAMPLE5_SCALE_1: + case CSRA66X0_CH2_SAMPLE7_SCALE_0: + case CSRA66X0_CH2_SAMPLE7_SCALE_1: + case CSRA66X0_CH2_SAMPLE2_SCALE_0: + case CSRA66X0_CH2_SAMPLE2_SCALE_1: + case CSRA66X0_CH2_SAMPLE4_SCALE_0: + case CSRA66X0_CH2_SAMPLE4_SCALE_1: + case CSRA66X0_CH2_SAMPLE6_SCALE_0: + case CSRA66X0_CH2_SAMPLE6_SCALE_1: + case CSRA66X0_CH2_SAMPLE8_SCALE_0: + case CSRA66X0_CH2_SAMPLE8_SCALE_1: + case CSRA66X0_RAM_VER_FA: + return true; + default: + return false; + } +} + +static bool csra66x0_writeable_registers(struct device *dev, unsigned int reg) +{ + if (csra66x0_addr_is_in_range(reg, CSRA66X0_BASE, + CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg, CSRA66X0_COEFF_BASE, + CSRA66X0_MAX_COEFF_ADDR)) + return true; + else + return false; +} + +static bool csra66x0_readable_registers(struct device *dev, unsigned int reg) +{ + if (csra66x0_addr_is_in_range(reg, CSRA66X0_BASE, + CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg, CSRA66X0_COEFF_BASE, + CSRA66X0_MAX_COEFF_ADDR)) + return true; + else + return false; +} + +/* codec private data */ +struct csra66x0_priv { + struct regmap *regmap; + struct snd_soc_component *component; + int spk_volume_ch1; + int spk_volume_ch2; + int irq; + int vreg_gpio; + u32 irq_active_low; + u32 in_cluster; + u32 is_master; + bool is_probed; + u32 max_num_cluster_devices; + u32 num_cluster_devices; + u32 sysfs_reg_addr; +#if IS_ENABLED(CONFIG_DEBUG_FS) + struct dentry *debugfs_dir; + struct dentry *debugfs_file_wo; + struct dentry *debugfs_file_ro; +#endif /* CONFIG_DEBUG_FS */ +}; + +struct csra66x0_cluster_device { + struct csra66x0_priv *csra66x0_ptr; + const char *csra66x0_prefix; +}; + +struct csra66x0_cluster_device csra_clust_dev_tbl[] = { + {NULL, "CSRA_12"}, + {NULL, "CSRA_34"}, + {NULL, "CSRA_56"}, + {NULL, "CSRA_78"}, + {NULL, "CSRA_9A"}, + {NULL, "CSRA_BC"}, + {NULL, "CSRA_DE"}, + {NULL, "CSRA_F0"} +}; + +static int sysfs_get_param(char *buf, u32 *param, int num_of_par) +{ + char *token; + int base, cnt; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static int debugfs_codec_open_op(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t debugfs_codec_write_op(struct file *filp, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + struct csra66x0_priv *csra66x0 = + (struct csra66x0_priv *) filp->private_data; + struct snd_soc_component *component = csra66x0->component; + char lbuf[32]; + int rc; + u32 param[2]; + + if (!filp || !ppos || !ubuf || !component) + return -EINVAL; + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + lbuf[cnt] = '\0'; + rc = sysfs_get_param(lbuf, param, 2); + + if (!(csra66x0_addr_is_in_range(param[0], + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(param[0], + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { + dev_err(component->dev, "%s: register address 0x%04X out of range\n", + __func__, param[0]); + return -EINVAL; + } + if ((param[1] < 0) || (param[1] > 255)) { + dev_err(component->dev, "%s: register data 0x%02X out of range\n", + __func__, param[1]); + return -EINVAL; + } + if (rc == 0) + { + rc = cnt; + dev_info(component->dev, "%s: reg[0x%04X]=0x%02X\n", + __func__, param[0], param[1]); + snd_soc_component_write(component, param[0], param[1]); + } else { + dev_err(component->dev, "%s: write to register addr=0x%04X failed\n", + __func__, param[0]); + } + return rc; +} + +static ssize_t debugfs_csra66x0_reg_show(struct csra66x0_priv *csra66x0, + char __user *ubuf, size_t count, loff_t *ppos) +{ + int i, reg_val, len; + int addr_min, addr_max; + ssize_t total = 0; + char tmp_buf[20]; + struct snd_soc_component *component = csra66x0->component; + + if (!ubuf || !ppos || !component || *ppos < 0) + return -EINVAL; + + if (csra66x0_addr_is_in_range(csra66x0->sysfs_reg_addr, + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR)) { + addr_min = CSRA66X0_COEFF_BASE; + addr_max = CSRA66X0_MAX_COEFF_ADDR; + csra66x0->sysfs_reg_addr = CSRA66X0_BASE; + } else { + addr_min = CSRA66X0_BASE; + addr_max = CSRA66X0_MAX_REGISTER_ADDR; + } + + for (i = ((int) *ppos + addr_min); + i <= addr_max; i++) { + reg_val = snd_soc_component_read32(component, i); + len = snprintf(tmp_buf, 20, "0x%04X: 0x%02X\n", i, (reg_val & 0xFF)); + if ((total + len) >= count - 1) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + dev_err(component->dev, "%s: fail to copy reg dump\n", + __func__); + total = -EFAULT; + goto copy_err; + } + *ppos += len; + total += len; + } + +copy_err: + return total; +} + +static ssize_t debugfs_codec_read_op(struct file *filp, + char __user *ubuf, size_t cnt, loff_t *ppos) +{ + struct csra66x0_priv *csra66x0 = + (struct csra66x0_priv *) filp->private_data; + ssize_t ret_cnt; + + if (!filp || !ppos || !ubuf || *ppos < 0) + return -EINVAL; + ret_cnt = debugfs_csra66x0_reg_show(csra66x0, ubuf, cnt, ppos); + return ret_cnt; +} + +static const struct file_operations debugfs_codec_ops = { + .open = debugfs_codec_open_op, + .write = debugfs_codec_write_op, + .read = debugfs_codec_read_op, +}; +#endif /* CONFIG_DEBUG_FS */ + +/* + * CSRA66X0 Controls + */ +static const DECLARE_TLV_DB_SCALE(csra66x0_volume_tlv, -9000, 25, 0); +static const DECLARE_TLV_DB_RANGE(csra66x0_bass_treble_tlv, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), + 16, 30, TLV_DB_SCALE_ITEM(100, 100, 0) +); + +static int csra66x0_get_volume(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + unsigned int reg_l = mc->reg; + unsigned int reg_r = mc->rreg; + unsigned int val_l, val_r; + + val_l = (snd_soc_component_read32(component, reg_l) & 0xff) | + ((snd_soc_component_read32(component, + CSRA66X0_CH1_VOLUME_1_FA) & (0x01)) << 8); + val_r = (snd_soc_component_read32(component, reg_r) & 0xff) | + ((snd_soc_component_read32(component, + CSRA66X0_CH2_VOLUME_1_FA) & (0x01)) << 8); + ucontrol->value.integer.value[0] = val_l; + ucontrol->value.integer.value[1] = val_r; + return 0; +} + +static int csra66x0_set_volume(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct csra66x0_priv *csra66x0 = + snd_soc_component_get_drvdata(component); + unsigned int reg_l = mc->reg; + unsigned int reg_r = mc->rreg; + unsigned int val_l[2]; + unsigned int val_r[2]; + + csra66x0->spk_volume_ch1 = (ucontrol->value.integer.value[0]); + csra66x0->spk_volume_ch2 = (ucontrol->value.integer.value[1]); + val_l[0] = csra66x0->spk_volume_ch1 & SPK_VOLUME_LSB_MSK; + val_l[1] = (csra66x0->spk_volume_ch1 & SPK_VOLUME_MSB_MSK) ? 1 : 0; + val_r[0] = csra66x0->spk_volume_ch2 & SPK_VOLUME_LSB_MSK; + val_r[1] = (csra66x0->spk_volume_ch2 & SPK_VOLUME_MSB_MSK) ? 1 : 0; + snd_soc_component_write(component, reg_l, val_l[0]); + snd_soc_component_write(component, reg_r, val_r[0]); + snd_soc_component_write(component, CSRA66X0_CH1_VOLUME_1_FA, val_l[1]); + snd_soc_component_write(component, CSRA66X0_CH2_VOLUME_1_FA, val_r[1]); + return 0; +} + +/* enumerated controls */ +static const char * const csra66x0_mute_output_text[] = {"PLAY", "MUTE"}; +static const char * const csra66x0_output_invert_text[] = { + "UNCHANGED", "INVERTED"}; +static const char * const csra66x0_deemp_config_text[] = { + "DISABLED", "ENABLED"}; + +SOC_ENUM_SINGLE_DECL(csra66x0_mute_output_enum, + CSRA66X0_MISC_CONTROL_STATUS_1_FA, 2, + csra66x0_mute_output_text); +SOC_ENUM_SINGLE_DECL(csra66x0_ch1_output_invert_enum, + CSRA66X0_CH1_OUTPUT_INVERT_EN, 0, + csra66x0_output_invert_text); +SOC_ENUM_SINGLE_DECL(csra66x0_ch2_output_invert_enum, + CSRA66X0_CH2_OUTPUT_INVERT_EN, 0, + csra66x0_output_invert_text); +SOC_ENUM_DOUBLE_DECL(csra66x0_deemp_config_enum, + CSRA66X0_DEEMP_CONFIG_FA, 0, 1, + csra66x0_deemp_config_text); + +static const struct snd_kcontrol_new csra66x0_snd_controls[] = { + /* volume */ + SOC_DOUBLE_R_EXT_TLV("PA VOLUME", CSRA66X0_CH1_VOLUME_0_FA, + CSRA66X0_CH2_VOLUME_0_FA, 0, 0x1C9, 0, + csra66x0_get_volume, csra66x0_set_volume, + csra66x0_volume_tlv), + + /* bass treble */ + SOC_DOUBLE_R_TLV("PA BASS GAIN", CSRA66X0_CH1_BASS_GAIN_CTRL_FA, + CSRA66X0_CH2_BASS_GAIN_CTRL_FA, 0, 0x1E, 0, + csra66x0_bass_treble_tlv), + SOC_DOUBLE_R_TLV("PA TREBLE GAIN", CSRA66X0_CH1_TREBLE_GAIN_CTRL_FA, + CSRA66X0_CH2_TREBLE_GAIN_CTRL_FA, 0, 0x1E, 0, + csra66x0_bass_treble_tlv), + SOC_DOUBLE_R("PA BASS_XOVER FREQ", CSRA66X0_CH1_BASS_FC_CTRL_FA, + CSRA66X0_CH2_BASS_FC_CTRL_FA, 0, 2, 0), + SOC_DOUBLE_R("PA TREBLE_XOVER FREQ", CSRA66X0_CH1_TREBLE_FC_CTRL_FA, + CSRA66X0_CH2_TREBLE_FC_CTRL_FA, 0, 2, 0), + + /* switch */ + SOC_ENUM("PA MUTE_OUTPUT SWITCH", csra66x0_mute_output_enum), + SOC_ENUM("PA DE-EMPHASIS SWITCH", csra66x0_deemp_config_enum), +}; + +static const struct snd_kcontrol_new csra_mix_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_soc_dapm_widget csra66x0_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN"), + SND_SOC_DAPM_MIXER("MIXER", SND_SOC_NOPM, 0, 0, + csra_mix_switch, ARRAY_SIZE(csra_mix_switch)), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("SPKR"), +}; + +static const struct snd_soc_dapm_route csra66x0_dapm_routes[] = { + {"MIXER", "Switch", "IN"}, + {"DAC", NULL, "MIXER"}, + {"PGA", NULL, "DAC"}, + {"SPKR", NULL, "PGA"}, +}; +/* + * csra66x0_hw_free_mute - Update csra66x0 mute register + * + * @component - csra66x0 component + * + */ +void csra66x0_hw_free_mute(struct snd_soc_component *component) +{ + int val = 0; + + if (component == NULL) + return; + + val = snd_soc_component_read32(component, + CSRA66X0_MISC_CONTROL_STATUS_1_FA); + snd_soc_component_write(component, CSRA66X0_MISC_CONTROL_STATUS_1_FA, + val | 0x04); +} +EXPORT_SYMBOL(csra66x0_hw_free_mute); + +static int csra66x0_wait_for_config_state(struct snd_soc_component *component) +{ + u16 val; + int cntdwn = WAIT_FOR_CONFIG_STATE_TIMEOUT_MS; + + do { + /* wait >= 100ms to check if HW has moved to config state */ + msleep(100); + val = snd_soc_component_read32(component, + CSRA66X0_CHIP_STATE_STATUS_FA); + if (val == CONFIG_STATE_ID) + break; + + cntdwn = cntdwn - 100; + } while (cntdwn > 0); + if (cntdwn <= 0) + return -EFAULT; + + return 0; +} + +static int csra66x0_allow_run(struct csra66x0_priv *csra66x0) +{ + struct snd_soc_component *component = csra66x0->component; + int i; + + /* csra66x0 is not in cluster */ + if (!csra66x0->in_cluster) { + /* enable interrupts */ + if (csra66x0->irq) { + snd_soc_component_write(component, + CSRA66X0_PIO0_SELECT, 0x1); + if (csra66x0->irq_active_low) + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, 0x0); + else + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, 0x1); + + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x01); + } else { + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x00); + } + /* allow run */ + snd_soc_component_write(component, + CSRA66X0_CHIP_STATE_CTRL_FA, SET_RUN_STATE); + return 0; + } + + /* csra66x0 is part of cluster */ + /* get number of probed cluster devices */ + csra66x0->num_cluster_devices = 0; + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_probed) + csra66x0->num_cluster_devices++; + } + + /* check if all cluster devices are probed */ + if (csra66x0->num_cluster_devices + == component->card->num_aux_devs) { + /* allow run of all slave components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + continue; + snd_soc_component_write( + csra_clust_dev_tbl[i].csra66x0_ptr->component, + CSRA66X0_CHIP_STATE_CTRL_FA, SET_RUN_STATE); + } + /* allow run of all master components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (!csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + continue; + + /* enable interrupts */ + if (csra66x0->irq) { + snd_soc_component_write(component, + CSRA66X0_PIO0_SELECT, 0x1); + if (csra66x0->irq_active_low) + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, + 0x0); + else + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, + 0x1); + + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x01); + } else { + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x00); + } + /* allow run */ + snd_soc_component_write( + csra_clust_dev_tbl[i].csra66x0_ptr->component, + CSRA66X0_CHIP_STATE_CTRL_FA, SET_RUN_STATE); + } + } + return 0; +} + +static int csra66x0_init(struct csra66x0_priv *csra66x0) +{ + struct snd_soc_component *component = csra66x0->component; + int ret; + + dev_dbg(component->dev, "%s: initialize %s\n", + __func__, component->name); + csra66x0->sysfs_reg_addr = CSRA66X0_BASE; + /* config */ + snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, + SET_CONFIG_STATE); + /* wait until HW is in config state before proceeding */ + ret = csra66x0_wait_for_config_state(component); + if (ret) { + dev_err(component->dev, "%s: timeout while %s is waiting for config state\n", + __func__, component->name); + } + + /* setup */ + snd_soc_component_write(component, CSRA66X0_MISC_CONTROL_STATUS_0, + 0x09); + snd_soc_component_write(component, CSRA66X0_TEMP_PROT_BACKOFF, 0x0C); + snd_soc_component_write(component, CSRA66X0_EXT_PA_PROTECT_POLARITY, + 0x03); + snd_soc_component_write(component, CSRA66X0_PWM_OUTPUT_CONFIG, 0xC8); + csra66x0->spk_volume_ch1 = SPK_VOLUME_M20DB; + csra66x0->spk_volume_ch2 = SPK_VOLUME_M20DB; + snd_soc_component_write(component, CSRA66X0_CH1_VOLUME_0_FA, + SPK_VOLUME_M20DB_LSB); + snd_soc_component_write(component, CSRA66X0_CH2_VOLUME_0_FA, + SPK_VOLUME_M20DB_LSB); + snd_soc_component_write(component, CSRA66X0_CH1_VOLUME_1_FA, + SPK_VOLUME_M20DB_MSB); + snd_soc_component_write(component, CSRA66X0_CH2_VOLUME_1_FA, + SPK_VOLUME_M20DB_MSB); + + /* disable volume ramping */ + snd_soc_component_write(component, CSRA66X0_VOLUME_CONFIG_FA, 0x27); + + snd_soc_component_write(component, CSRA66X0_DEAD_TIME_CTRL, 0x0); + snd_soc_component_write(component, CSRA66X0_DEAD_TIME_THRESHOLD_0, + 0xE7); + snd_soc_component_write(component, CSRA66X0_DEAD_TIME_THRESHOLD_1, + 0x26); + snd_soc_component_write(component, CSRA66X0_DEAD_TIME_THRESHOLD_2, + 0x40); + + snd_soc_component_write(component, CSRA66X0_MIN_MODULATION_PULSE_WIDTH, + 0x7A); + snd_soc_component_write(component, CSRA66X0_CH1_HARD_CLIP_THRESH, 0x00); + snd_soc_component_write(component, CSRA66X0_CH2_HARD_CLIP_THRESH, 0x00); + + snd_soc_component_write(component, CSRA66X0_CH1_DCA_THRESH, 0x40); + snd_soc_component_write(component, CSRA66X0_CH2_DCA_THRESH, 0x40); + snd_soc_component_write(component, CSRA66X0_DCA_ATTACK_RATE, 0x00); + snd_soc_component_write(component, CSRA66X0_DCA_RELEASE_RATE, 0x00); + + csra66x0_allow_run(csra66x0); + return 0; +} + +static int csra66x0_reset(struct csra66x0_priv *csra66x0) +{ + struct snd_soc_component *component = csra66x0->component; + u16 val; + + val = snd_soc_component_read32(component, CSRA66X0_FAULT_STATUS_FA); + if (val & FAULT_STATUS_INTERNAL) + dev_dbg(component->dev, "%s: FAULT_STATUS_INTERNAL 0x%X\n", + __func__, val); + if (val & FAULT_STATUS_OTP_INTEGRITY) + dev_dbg(component->dev, "%s: FAULT_STATUS_OTP_INTEGRITY 0x%X\n", + __func__, val); + if (val & FAULT_STATUS_PADS2) + dev_dbg(component->dev, "%s: FAULT_STATUS_PADS2 0x%X\n", + __func__, val); + if (val & FAULT_STATUS_SMPS) + dev_dbg(component->dev, "%s: FAULT_STATUS_SMPS 0x%X\n", + __func__, val); + if (val & FAULT_STATUS_TEMP) + dev_dbg(component->dev, "%s: FAULT_STATUS_TEMP 0x%X\n", + __func__, val); + if (val & FAULT_STATUS_PROTECT) + dev_dbg(component->dev, "%s: FAULT_STATUS_PROTECT 0x%X\n", + __func__, val); + + dev_dbg(component->dev, "%s: reset %s\n", + __func__, component->name); + /* clear fault state and re-init */ + snd_soc_component_write(component, CSRA66X0_FAULT_STATUS_FA, 0x00); + snd_soc_component_write(component, CSRA66X0_IRQ_OUTPUT_STATUS_FA, 0x00); + /* apply reset to CSRA66X0 */ + val = snd_soc_component_read32(component, + CSRA66X0_MISC_CONTROL_STATUS_1_FA); + snd_soc_component_write(component, CSRA66X0_MISC_CONTROL_STATUS_1_FA, + val | 0x08); + /* wait 500ms after reset to recover CSRA66X0 */ + msleep(500); + return 0; +} + +static int csra66x0_msconfig(struct csra66x0_priv *csra66x0) +{ + struct snd_soc_component *component = csra66x0->component; + int ret; + + dev_dbg(component->dev, "%s: configure %s\n", + __func__, component->name); + /* config */ + snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, + SET_CONFIG_STATE); + /* wait until HW is in config state before proceeding */ + ret = csra66x0_wait_for_config_state(component); + if (ret) { + dev_err(component->dev, "%s: timeout while %s is waiting for config state\n", + __func__, component->name); + return ret; + } + snd_soc_component_write(component, CSRA66X0_PIO7_SELECT, 0x04); + snd_soc_component_write(component, CSRA66X0_PIO8_SELECT, 0x04); + if (csra66x0->is_master) { + /* Master specific config */ + snd_soc_component_write(component, + CSRA66X0_PIO_PULL_EN0, 0xFF); + snd_soc_component_write(component, + CSRA66X0_PIO_PULL_DIR0, 0x80); + snd_soc_component_write(component, + CSRA66X0_PIO_PULL_EN1, 0x01); + snd_soc_component_write(component, + CSRA66X0_PIO_PULL_DIR1, 0x01); + } else { + /* Slave specific config */ + snd_soc_component_write(component, + CSRA66X0_PIO_PULL_EN0, 0x7F); + snd_soc_component_write(component, + CSRA66X0_PIO_PULL_EN1, 0x00); + } + snd_soc_component_write(component, CSRA66X0_DCA_CTRL, 0x05); + return 0; +} + +static int csra66x0_soc_probe(struct snd_soc_component *component) +{ + struct csra66x0_priv *csra66x0 = + snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm; + char name[50]; + unsigned int i; + + csra66x0->component = component; + if (csra66x0->in_cluster) { + dapm = snd_soc_component_get_dapm(component); + dev_dbg(component->dev, "%s: assign prefix %s to component device %s\n", + __func__, component->name_prefix, + component->name); + + /* add device to cluster table */ + csra66x0->max_num_cluster_devices = + ARRAY_SIZE(csra_clust_dev_tbl); + for (i = 0; i < csra66x0->max_num_cluster_devices; i++) { + if (!strncmp(component->name_prefix, + csra_clust_dev_tbl[i].csra66x0_prefix, + strnlen( + csra_clust_dev_tbl[i].csra66x0_prefix, + sizeof( + csra_clust_dev_tbl[i].csra66x0_prefix)))) { + csra_clust_dev_tbl[i].csra66x0_ptr = csra66x0; + break; + } + if (i == csra66x0->max_num_cluster_devices - 1) + dev_warn(component->dev, + "%s: Unknown prefix %s of cluster device %s\n", + __func__, component->name_prefix, + component->name); + } + + /* master slave config */ + csra66x0_msconfig(csra66x0); + if (dapm->component) { + strlcpy(name, dapm->component->name_prefix, + sizeof(name)); + strlcat(name, " IN", sizeof(name)); + snd_soc_dapm_ignore_suspend(dapm, name); + strlcpy(name, dapm->component->name_prefix, + sizeof(name)); + strlcat(name, " SPKR", sizeof(name)); + snd_soc_dapm_ignore_suspend(dapm, name); + } + } + + /* common initialization */ + csra66x0->is_probed = 1; + csra66x0_init(csra66x0); + return 0; +} + +static void csra66x0_soc_remove(struct snd_soc_component *component) +{ + snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, + SET_STDBY_STATE); + return; +} + +static const struct snd_soc_component_driver soc_codec_drv_csra66x0 = { + .name = DRV_NAME, + .probe = csra66x0_soc_probe, + .remove = csra66x0_soc_remove, + .controls = csra66x0_snd_controls, + .num_controls = ARRAY_SIZE(csra66x0_snd_controls), + .dapm_widgets = csra66x0_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(csra66x0_dapm_widgets), + .dapm_routes = csra66x0_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(csra66x0_dapm_routes), +}; + +static struct regmap_config csra66x0_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = csra66x0_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(csra66x0_reg_defaults), + .max_register = CSRA66X0_MAX_COEFF_ADDR, + .volatile_reg = csra66x0_volatile_register, + .writeable_reg = csra66x0_writeable_registers, + .readable_reg = csra66x0_readable_registers, +}; + +static irqreturn_t csra66x0_irq(int irq, void *data) +{ + struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) data; + struct snd_soc_component *component = csra66x0->component; + u16 val; + unsigned int i; + + /* Treat interrupt before component is initialized as spurious */ + if (component == NULL) + return IRQ_NONE; + + dev_dbg(component->dev, "%s: csra66x0_interrupt triggered by %s\n", + __func__, component->name); + + /* fault indication */ + val = snd_soc_component_read32(component, CSRA66X0_IRQ_OUTPUT_STATUS_FA) + & 0x1; + if (!val) + return IRQ_HANDLED; + + if (csra66x0->in_cluster) { + /* reset all slave components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + continue; + csra66x0_reset(csra_clust_dev_tbl[i].csra66x0_ptr); + } + /* reset all master components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + csra66x0_reset( + csra_clust_dev_tbl[i].csra66x0_ptr); + } + /* recover all components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + csra66x0_msconfig(csra_clust_dev_tbl[i].csra66x0_ptr); + csra66x0_init(csra_clust_dev_tbl[i].csra66x0_ptr); + } + } else { + csra66x0_reset(csra66x0); + csra66x0_init(csra66x0); + } + return IRQ_HANDLED; +}; + +static const struct of_device_id csra66x0_of_match[] = { + { .compatible = "qcom,csra66x0", }, + { } +}; +MODULE_DEVICE_TABLE(of, csra66x0_of_match); + +static ssize_t csra66x0_sysfs_write2reg_addr_value(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + u32 param[2]; /*reg_addr, reg_value */ + char lbuf[CSRA66X0_SYSFS_ENTRY_MAX_LEN]; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + struct snd_soc_component *component = csra66x0->component; + + if (!csra66x0) { + dev_err(component->dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + if (count > sizeof(lbuf) - 1) + return -EINVAL; + + ret = strlcpy(lbuf, buf, count); + if (ret != count) { + dev_err(component->dev, "%s: copy input from user space failed. ret=%d\n", + __func__, ret); + ret = -EFAULT; + goto end; + } + + lbuf[count] = '\0'; + ret = sysfs_get_param(lbuf, param, 2); + if (ret) { + dev_err(component->dev, "%s: get sysfs parameter failed. ret=%d\n", + __func__, ret); + goto end; + } + + if (!(csra66x0_addr_is_in_range(param[0], + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(param[0], + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { + dev_err(component->dev, "%s: register address 0x%04X out of range\n", + __func__, param[0]); + ret = -EINVAL; + goto end; + } + + if ((param[1] < 0) || (param[1] > 255)) { + dev_err(component->dev, "%s: register data 0x%02X out of range\n", + __func__, param[1]); + ret = -EINVAL; + goto end; + } + + snd_soccomponent_component_write(component, param[0], param[1]); + ret = count; + +end: + return ret; +} + +static ssize_t csra66x0_sysfs_read2reg_addr_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + u32 reg_addr; + char lbuf[CSRA66X0_SYSFS_ENTRY_MAX_LEN]; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + if (count > sizeof(lbuf) - 1) + return -EINVAL; + + ret = strlcpy(lbuf, buf, count); + if (ret != count) { + dev_err(dev, "%s: copy input from user space failed. ret=%d\n", + __func__, ret); + ret = -EFAULT; + goto end; + } + + lbuf[count] = '\0'; + ret = sysfs_get_param(lbuf, ®_addr, 1); + if (ret) { + dev_err(dev, "%s: get sysfs parameter failed. ret=%d\n", + __func__, ret); + goto end; + } + + if (!(csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { + dev_err(dev, "%s: register address 0x%04X out of range\n", + __func__, reg_addr); + ret = -EINVAL; + goto end; + } + + csra66x0->sysfs_reg_addr = reg_addr; + ret = count; + +end: + return ret; +} + +static ssize_t csra66x0_sysfs_read2reg_addr_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + u32 reg_addr; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + reg_addr = csra66x0->sysfs_reg_addr; + + ret = snprintf(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN, + "0x%04X\n", reg_addr); + pr_debug("%s: 0x%04X\n", __func__, reg_addr); + + return ret; +} + +static ssize_t csra66x0_sysfs_read2reg_value(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + u32 reg_val, reg_addr; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + struct snd_soc_component *component = csra66x0->component; + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + reg_addr = csra66x0->sysfs_reg_addr; + if (!(csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { + pr_debug("%s: 0x%04X: register address out of range\n", + __func__, reg_addr); + ret = snprintf(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN, + "0x%04X: register address out of range\n", reg_addr); + goto end; + } + + reg_val = snd_soc_component_read32(component, csra66x0->sysfs_reg_addr); + ret = snprintf(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN, + "0x%04X: 0x%02X\n", csra66x0->sysfs_reg_addr, reg_val); + pr_debug("%s: 0x%04X: 0x%02X\n", __func__, + csra66x0->sysfs_reg_addr, reg_val); + +end: + return ret; +} + +static ssize_t csra66x0_sysfs_reset(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int val, rc; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + struct snd_soc_component *component = csra66x0->component; + unsigned int i; + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if (val != SYSFS_RESET) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + pr_debug("%s: reset device\n", __func__); + if (csra66x0->in_cluster) { + /* reset all slave components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + continue; + csra66x0_reset(csra_clust_dev_tbl[i].csra66x0_ptr); + } + /* reset all master components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + csra66x0_reset( + csra_clust_dev_tbl[i].csra66x0_ptr); + } + /* recover all components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + csra66x0_msconfig(csra_clust_dev_tbl[i].csra66x0_ptr); + csra66x0_init(csra_clust_dev_tbl[i].csra66x0_ptr); + } + } else { + csra66x0_reset(csra66x0); + csra66x0_init(csra66x0); + } + + rc = strnlen(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static DEVICE_ATTR(write2reg_addr_value, 0200, NULL, + csra66x0_sysfs_write2reg_addr_value); +static DEVICE_ATTR(read2reg_addr, 0644, csra66x0_sysfs_read2reg_addr_get, + csra66x0_sysfs_read2reg_addr_set); +static DEVICE_ATTR(read2reg_value, 0444, csra66x0_sysfs_read2reg_value, NULL); +static DEVICE_ATTR(reset, 0200, NULL, csra66x0_sysfs_reset); + +static struct attribute *csra66x0_fs_attrs[] = { + &dev_attr_write2reg_addr_value.attr, + &dev_attr_read2reg_addr.attr, + &dev_attr_read2reg_value.attr, + &dev_attr_reset.attr, + NULL, +}; + +static struct attribute_group csra66x0_fs_attrs_group = { + .attrs = csra66x0_fs_attrs, +}; + +static int csra66x0_sysfs_create(struct i2c_client *client, + struct csra66x0_priv *csra66x0) +{ + int rc; + + rc = sysfs_create_group(&client->dev.kobj, &csra66x0_fs_attrs_group); + return rc; +} + +static void csra66x0_sysfs_remove(struct i2c_client *client, + struct csra66x0_priv *csra66x0) +{ + sysfs_remove_group(&client->dev.kobj, &csra66x0_fs_attrs_group); +} + +#if IS_ENABLED(CONFIG_I2C) +static int csra66x0_i2c_probe(struct i2c_client *client_i2c, + const struct i2c_device_id *id) +{ + struct csra66x0_priv *csra66x0; + int ret, irq_trigger; +#if IS_ENABLED(CONFIG_DEBUG_FS) + char debugfs_dir_name[32]; +#endif + + csra66x0 = devm_kzalloc(&client_i2c->dev, sizeof(struct csra66x0_priv), + GFP_KERNEL); + if (csra66x0 == NULL) + return -ENOMEM; + + csra66x0->regmap = devm_regmap_init_i2c(client_i2c, + &csra66x0_regmap_config); + if (IS_ERR(csra66x0->regmap)) { + ret = PTR_ERR(csra66x0->regmap); + dev_err(&client_i2c->dev, + "%s %d: Failed to allocate register map for I2C device: %d\n", + __func__, __LINE__, ret); + return ret; + } + + i2c_set_clientdata(client_i2c, csra66x0); + + /* get data from device tree */ + if (client_i2c->dev.of_node) { + /* cluster of multiple devices */ + ret = of_property_read_u32( + client_i2c->dev.of_node, "qcom,csra-cluster", + &csra66x0->in_cluster); + if (ret) { + dev_info(&client_i2c->dev, + "%s: qcom,csra-cluster property not defined in DT\n", __func__); + csra66x0->in_cluster = 0; + } + /* master or slave device */ + ret = of_property_read_u32( + client_i2c->dev.of_node, "qcom,csra-cluster-master", + &csra66x0->is_master); + if (ret) { + dev_info(&client_i2c->dev, + "%s: qcom,csra-cluster-master property not defined in DT, slave assumed\n", + __func__); + csra66x0->is_master = 0; + } + + /* gpio setup for vreg */ + csra66x0->vreg_gpio = of_get_named_gpio(client_i2c->dev.of_node, + "qcom,csra-vreg-en-gpio", 0); + if (!gpio_is_valid(csra66x0->vreg_gpio)) { + dev_err(&client_i2c->dev, "%s: %s property is not found %d\n", + __func__, "qcom,csra-vreg-en-gpio", + csra66x0->vreg_gpio); + return -ENODEV; + } + dev_dbg(&client_i2c->dev, "%s: vreg_en gpio %d\n", __func__, + csra66x0->vreg_gpio); + ret = gpio_request(csra66x0->vreg_gpio, dev_name(&client_i2c->dev)); + if (ret) { + if (ret == -EBUSY) { + /* GPIO was already requested */ + dev_dbg(&client_i2c->dev, + "%s: gpio %d is already set\n", + __func__, csra66x0->vreg_gpio); + } else { + dev_err(&client_i2c->dev, "%s: Failed to request gpio %d, err: %d\n", + __func__, csra66x0->vreg_gpio, ret); + } + } else { + gpio_direction_output(csra66x0->vreg_gpio, 1); + gpio_set_value(csra66x0->vreg_gpio, 0); + } + + /* register interrupt handle */ + if (client_i2c->irq) { + csra66x0->irq = client_i2c->irq; + /* interrupt polarity */ + ret = of_property_read_u32( + client_i2c->dev.of_node, "irq-active-low", + &csra66x0->irq_active_low); + if (ret) { + dev_info(&client_i2c->dev, + "%s: irq-active-low property not defined in DT\n", __func__); + csra66x0->irq_active_low = 0; + } + if (csra66x0->irq_active_low) + irq_trigger = IRQF_TRIGGER_LOW; + else + irq_trigger = IRQF_TRIGGER_HIGH; + + ret = devm_request_threaded_irq(&client_i2c->dev, + csra66x0->irq, NULL, csra66x0_irq, + irq_trigger | IRQF_ONESHOT, + "csra66x0_irq", csra66x0); + if (ret) { + dev_err(&client_i2c->dev, + "%s: Failed to request IRQ %d: %d\n", + __func__, csra66x0->irq, ret); + csra66x0->irq = 0; + } + } + } + +#if IS_ENABLED(CONFIG_DEBUG_FS) + /* debugfs interface */ + snprintf(debugfs_dir_name, sizeof(debugfs_dir_name), "%s-%s", + client_i2c->name, dev_name(&client_i2c->dev)); + csra66x0->debugfs_dir = debugfs_create_dir(debugfs_dir_name, NULL); + if (!csra66x0->debugfs_dir) { + dev_dbg(&client_i2c->dev, + "%s: Failed to create /sys/kernel/debug/%s for debugfs\n", + __func__, debugfs_dir_name); + ret = -ENOMEM; + goto err_debugfs; + } + csra66x0->debugfs_file_wo = debugfs_create_file( + "write_reg_val", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, + (void *) csra66x0, + &debugfs_codec_ops); + if (!csra66x0->debugfs_file_wo) { + dev_dbg(&client_i2c->dev, + "%s: Failed to create /sys/kernel/debug/%s/write_reg_val\n", + __func__, debugfs_dir_name); + ret = -ENOMEM; + goto err_debugfs; + } + csra66x0->debugfs_file_ro = debugfs_create_file( + "show_reg_dump", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, + (void *) csra66x0, + &debugfs_codec_ops); + if (!csra66x0->debugfs_file_ro) { + dev_dbg(&client_i2c->dev, + "%s: Failed to create /sys/kernel/debug/%s/show_reg_dump\n", + __func__, debugfs_dir_name); + ret = -ENOMEM; + goto err_debugfs; + } +#endif /* CONFIG_DEBUG_FS */ + + /* register component */ + ret = snd_soc_register_component(&client_i2c->dev, + &soc_codec_drv_csra66x0, NULL, 0); + if (ret != 0) { + dev_err(&client_i2c->dev, "%s %d: Failed to register component: %d\n", + __func__, __LINE__, ret); + if (gpio_is_valid(csra66x0->vreg_gpio)) { + gpio_set_value(csra66x0->vreg_gpio, 0); + gpio_free(csra66x0->vreg_gpio); + } + return ret; + } + + ret = csra66x0_sysfs_create(client_i2c, csra66x0); + if (ret) { + dev_err(&client_i2c->dev, "%s: sysfs creation failed ret=%d\n", + __func__, ret); + goto err_sysfs; + } + + return 0; + +err_sysfs: + snd_soc_unregister_component(&client_i2c->dev); + return ret; + +#if IS_ENABLED(CONFIG_DEBUG_FS) +err_debugfs: + debugfs_remove_recursive(csra66x0->debugfs_dir); + return ret; +#endif +} + +static int csra66x0_i2c_remove(struct i2c_client *client_i2c) +{ + struct csra66x0_priv *csra66x0 = i2c_get_clientdata(client_i2c); + + if (csra66x0) { + if (gpio_is_valid(csra66x0->vreg_gpio)) { + gpio_set_value(csra66x0->vreg_gpio, 0); + gpio_free(csra66x0->vreg_gpio); + } +#if IS_ENABLED(CONFIG_DEBUG_FS) + debugfs_remove_recursive(csra66x0->debugfs_dir); +#endif + } + + csra66x0_sysfs_remove(client_i2c, csra66x0); + snd_soc_unregister_component(&i2c_client->dev); + + return 0; +} + +static const struct i2c_device_id csra66x0_i2c_id[] = { + { "csra66x0", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, csra66x0_i2c_id); + +static struct i2c_driver csra66x0_i2c_driver = { + .probe = csra66x0_i2c_probe, + .remove = csra66x0_i2c_remove, + .id_table = csra66x0_i2c_id, + .driver = { + .name = "csra66x0", + .owner = THIS_MODULE, + .of_match_table = csra66x0_of_match + }, +}; +#endif + +static int __init csra66x0_codec_init(void) +{ + int ret = 0; +#if IS_ENABLED(CONFIG_I2C) + ret = i2c_add_driver(&csra66x0_i2c_driver); + if (ret != 0) + pr_err("%s: Failed to register CSRA66X0 I2C driver, ret = %d\n", + __func__, ret); +#endif + return ret; +} +module_init(csra66x0_codec_init); + +static void __exit csra66x0_codec_exit(void) +{ +#if IS_ENABLED(CONFIG_I2C) + i2c_del_driver(&csra66x0_i2c_driver); +#endif +} +module_exit(csra66x0_codec_exit); + +MODULE_DESCRIPTION("CSRA66X0 Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/csra66x0.h b/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/csra66x0.h new file mode 100644 index 0000000000..2bde3cc06b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/csra66x0/csra66x0.h @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CSRA66X0_H +#define _CSRA66X0_H + +/* CSRA66X0 register addresses */ +#define CSRA66X0_BASE 0x7000 + +#define CSRA66X0_AUDIO_IF_RX_CONFIG1 (CSRA66X0_BASE+0x0000) +#define CSRA66X0_AUDIO_IF_RX_CONFIG2 (CSRA66X0_BASE+0x0001) +#define CSRA66X0_AUDIO_IF_RX_CONFIG3 (CSRA66X0_BASE+0x0002) +#define CSRA66X0_AUDIO_IF_TX_EN (CSRA66X0_BASE+0x0003) +#define CSRA66X0_AUDIO_IF_TX_CONFIG1 (CSRA66X0_BASE+0x0004) +#define CSRA66X0_AUDIO_IF_TX_CONFIG2 (CSRA66X0_BASE+0x0005) +#define CSRA66X0_I2C_DEVICE_ADDRESS (CSRA66X0_BASE+0x0006) +#define CSRA66X0_CHIP_ID_FA (CSRA66X0_BASE+0x0007) +#define CSRA66X0_ROM_VER_FA (CSRA66X0_BASE+0x0008) +#define CSRA66X0_CHIP_REV_0_FA (CSRA66X0_BASE+0x0009) +#define CSRA66X0_CHIP_REV_1_FA (CSRA66X0_BASE+0x000A) +#define CSRA66X0_CH1_MIX_SEL (CSRA66X0_BASE+0x000B) +#define CSRA66X0_CH2_MIX_SEL (CSRA66X0_BASE+0x000C) +#define CSRA66X0_CH1_SAMPLE1_SCALE_0 (CSRA66X0_BASE+0x000D) +#define CSRA66X0_CH1_SAMPLE1_SCALE_1 (CSRA66X0_BASE+0x000E) +#define CSRA66X0_CH1_SAMPLE3_SCALE_0 (CSRA66X0_BASE+0x000F) +#define CSRA66X0_CH1_SAMPLE3_SCALE_1 (CSRA66X0_BASE+0x0010) +#define CSRA66X0_CH1_SAMPLE5_SCALE_0 (CSRA66X0_BASE+0x0011) +#define CSRA66X0_CH1_SAMPLE5_SCALE_1 (CSRA66X0_BASE+0x0012) +#define CSRA66X0_CH1_SAMPLE7_SCALE_0 (CSRA66X0_BASE+0x0013) +#define CSRA66X0_CH1_SAMPLE7_SCALE_1 (CSRA66X0_BASE+0x0014) +#define CSRA66X0_CH1_SAMPLE2_SCALE_0 (CSRA66X0_BASE+0x0015) +#define CSRA66X0_CH1_SAMPLE2_SCALE_1 (CSRA66X0_BASE+0x0016) +#define CSRA66X0_CH1_SAMPLE4_SCALE_0 (CSRA66X0_BASE+0x0017) +#define CSRA66X0_CH1_SAMPLE4_SCALE_1 (CSRA66X0_BASE+0x0018) +#define CSRA66X0_CH1_SAMPLE6_SCALE_0 (CSRA66X0_BASE+0x0019) +#define CSRA66X0_CH1_SAMPLE6_SCALE_1 (CSRA66X0_BASE+0x001A) +#define CSRA66X0_CH1_SAMPLE8_SCALE_0 (CSRA66X0_BASE+0x001B) +#define CSRA66X0_CH1_SAMPLE8_SCALE_1 (CSRA66X0_BASE+0x001C) +#define CSRA66X0_CH2_SAMPLE1_SCALE_0 (CSRA66X0_BASE+0x001D) +#define CSRA66X0_CH2_SAMPLE1_SCALE_1 (CSRA66X0_BASE+0x001E) +#define CSRA66X0_CH2_SAMPLE3_SCALE_0 (CSRA66X0_BASE+0x001F) +#define CSRA66X0_CH2_SAMPLE3_SCALE_1 (CSRA66X0_BASE+0x0020) +#define CSRA66X0_CH2_SAMPLE5_SCALE_0 (CSRA66X0_BASE+0x0021) +#define CSRA66X0_CH2_SAMPLE5_SCALE_1 (CSRA66X0_BASE+0x0022) +#define CSRA66X0_CH2_SAMPLE7_SCALE_0 (CSRA66X0_BASE+0x0023) +#define CSRA66X0_CH2_SAMPLE7_SCALE_1 (CSRA66X0_BASE+0x0024) +#define CSRA66X0_CH2_SAMPLE2_SCALE_0 (CSRA66X0_BASE+0x0025) +#define CSRA66X0_CH2_SAMPLE2_SCALE_1 (CSRA66X0_BASE+0x0026) +#define CSRA66X0_CH2_SAMPLE4_SCALE_0 (CSRA66X0_BASE+0x0027) +#define CSRA66X0_CH2_SAMPLE4_SCALE_1 (CSRA66X0_BASE+0x0028) +#define CSRA66X0_CH2_SAMPLE6_SCALE_0 (CSRA66X0_BASE+0x0029) +#define CSRA66X0_CH2_SAMPLE6_SCALE_1 (CSRA66X0_BASE+0x002A) +#define CSRA66X0_CH2_SAMPLE8_SCALE_0 (CSRA66X0_BASE+0x002B) +#define CSRA66X0_CH2_SAMPLE8_SCALE_1 (CSRA66X0_BASE+0x002C) +#define CSRA66X0_VOLUME_CONFIG_FA (CSRA66X0_BASE+0x002D) +#define CSRA66X0_STARTUP_DELAY_FA (CSRA66X0_BASE+0x002E) +#define CSRA66X0_CH1_VOLUME_0_FA (CSRA66X0_BASE+0x002F) +#define CSRA66X0_CH1_VOLUME_1_FA (CSRA66X0_BASE+0x0030) +#define CSRA66X0_CH2_VOLUME_0_FA (CSRA66X0_BASE+0x0031) +#define CSRA66X0_CH2_VOLUME_1_FA (CSRA66X0_BASE+0x0032) +#define CSRA66X0_QUAD_ENC_COUNT_0_FA (CSRA66X0_BASE+0x0033) +#define CSRA66X0_QUAD_ENC_COUNT_1_FA (CSRA66X0_BASE+0x0034) +#define CSRA66X0_SOFT_CLIP_CONFIG (CSRA66X0_BASE+0x0035) +#define CSRA66X0_CH1_HARD_CLIP_THRESH (CSRA66X0_BASE+0x0036) +#define CSRA66X0_CH2_HARD_CLIP_THRESH (CSRA66X0_BASE+0x0037) +#define CSRA66X0_SOFT_CLIP_THRESH (CSRA66X0_BASE+0x0038) +#define CSRA66X0_DS_ENABLE_THRESH_0 (CSRA66X0_BASE+0x0039) +#define CSRA66X0_DS_ENABLE_THRESH_1 (CSRA66X0_BASE+0x003A) +#define CSRA66X0_DS_TARGET_COUNT_0 (CSRA66X0_BASE+0x003B) +#define CSRA66X0_DS_TARGET_COUNT_1 (CSRA66X0_BASE+0x003C) +#define CSRA66X0_DS_TARGET_COUNT_2 (CSRA66X0_BASE+0x003D) +#define CSRA66X0_DS_DISABLE_THRESH_0 (CSRA66X0_BASE+0x003E) +#define CSRA66X0_DS_DISABLE_THRESH_1 (CSRA66X0_BASE+0x003F) +#define CSRA66X0_DCA_CTRL (CSRA66X0_BASE+0x0040) +#define CSRA66X0_CH1_DCA_THRESH (CSRA66X0_BASE+0x0041) +#define CSRA66X0_CH2_DCA_THRESH (CSRA66X0_BASE+0x0042) +#define CSRA66X0_DCA_ATTACK_RATE (CSRA66X0_BASE+0x0043) +#define CSRA66X0_DCA_RELEASE_RATE (CSRA66X0_BASE+0x0044) +#define CSRA66X0_CH1_OUTPUT_INVERT_EN (CSRA66X0_BASE+0x0045) +#define CSRA66X0_CH2_OUTPUT_INVERT_EN (CSRA66X0_BASE+0x0046) +#define CSRA66X0_CH1_176P4K_DELAY (CSRA66X0_BASE+0x0047) +#define CSRA66X0_CH2_176P4K_DELAY (CSRA66X0_BASE+0x0048) +#define CSRA66X0_CH1_192K_DELAY (CSRA66X0_BASE+0x0049) +#define CSRA66X0_CH2_192K_DELAY (CSRA66X0_BASE+0x004A) +#define CSRA66X0_DEEMP_CONFIG_FA (CSRA66X0_BASE+0x004B) +#define CSRA66X0_CH1_TREBLE_GAIN_CTRL_FA (CSRA66X0_BASE+0x004C) +#define CSRA66X0_CH2_TREBLE_GAIN_CTRL_FA (CSRA66X0_BASE+0x004D) +#define CSRA66X0_CH1_TREBLE_FC_CTRL_FA (CSRA66X0_BASE+0x004E) +#define CSRA66X0_CH2_TREBLE_FC_CTRL_FA (CSRA66X0_BASE+0x004F) +#define CSRA66X0_CH1_BASS_GAIN_CTRL_FA (CSRA66X0_BASE+0x0050) +#define CSRA66X0_CH2_BASS_GAIN_CTRL_FA (CSRA66X0_BASE+0x0051) +#define CSRA66X0_CH1_BASS_FC_CTRL_FA (CSRA66X0_BASE+0x0052) +#define CSRA66X0_CH2_BASS_FC_CTRL_FA (CSRA66X0_BASE+0x0053) +#define CSRA66X0_FILTER_SEL_8K (CSRA66X0_BASE+0x0054) +#define CSRA66X0_FILTER_SEL_11P025K (CSRA66X0_BASE+0x0055) +#define CSRA66X0_FILTER_SEL_16K (CSRA66X0_BASE+0x0056) +#define CSRA66X0_FILTER_SEL_22P05K (CSRA66X0_BASE+0x0057) +#define CSRA66X0_FILTER_SEL_32K (CSRA66X0_BASE+0x0058) +#define CSRA66X0_FILTER_SEL_44P1K_48K (CSRA66X0_BASE+0x0059) +#define CSRA66X0_FILTER_SEL_88P2K_96K (CSRA66X0_BASE+0x005A) +#define CSRA66X0_FILTER_SEL_176P4K_192K (CSRA66X0_BASE+0x005B) +/* RESERVED (CSRA66X0_BASE+0x005C) */ +#define CSRA66X0_USER_DSP_CTRL (CSRA66X0_BASE+0x005D) +#define CSRA66X0_TEST_TONE_CTRL (CSRA66X0_BASE+0x005E) +#define CSRA66X0_TEST_TONE_FREQ_0 (CSRA66X0_BASE+0x005F) +#define CSRA66X0_TEST_TONE_FREQ_1 (CSRA66X0_BASE+0x0060) +#define CSRA66X0_TEST_TONE_FREQ_2 (CSRA66X0_BASE+0x0061) +#define CSRA66X0_AUDIO_RATE_CTRL_FA (CSRA66X0_BASE+0x0062) +#define CSRA66X0_MODULATION_INDEX_CTRL (CSRA66X0_BASE+0x0063) +#define CSRA66X0_MODULATION_INDEX_COUNT (CSRA66X0_BASE+0x0064) +#define CSRA66X0_MIN_MODULATION_PULSE_WIDTH (CSRA66X0_BASE+0x0065) +#define CSRA66X0_DEAD_TIME_CTRL (CSRA66X0_BASE+0x0066) +#define CSRA66X0_DEAD_TIME_THRESHOLD_0 (CSRA66X0_BASE+0x0067) +#define CSRA66X0_DEAD_TIME_THRESHOLD_1 (CSRA66X0_BASE+0x0068) +#define CSRA66X0_DEAD_TIME_THRESHOLD_2 (CSRA66X0_BASE+0x0069) +#define CSRA66X0_CH1_LOW_SIDE_DLY (CSRA66X0_BASE+0x006A) +#define CSRA66X0_CH2_LOW_SIDE_DLY (CSRA66X0_BASE+0x006B) +#define CSRA66X0_SPECTRUM_CTRL (CSRA66X0_BASE+0x006C) +/* RESERVED (CSRA66X0_BASE+0x006D) */ +#define CSRA66X0_SPECTRUM_SPREAD_CTRL (CSRA66X0_BASE+0x006E) +/* RESERVED (CSRA66X0_BASE+0x006F) */ +/* ... */ +/* RESERVED (CSRA66X0_BASE+0x007C) */ +#define CSRA66X0_EXT_PA_PROTECT_POLARITY (CSRA66X0_BASE+0x007D) +#define CSRA66X0_TEMP0_BACKOFF_COMP_VALUE (CSRA66X0_BASE+0x007E) +#define CSRA66X0_TEMP0_SHUTDOWN_COMP_VALUE (CSRA66X0_BASE+0x007F) +#define CSRA66X0_TEMP1_BACKOFF_COMP_VALUE (CSRA66X0_BASE+0x0080) +#define CSRA66X0_TEMP1_SHUTDOWN_COMP_VALUE (CSRA66X0_BASE+0x0081) +#define CSRA66X0_TEMP_PROT_BACKOFF (CSRA66X0_BASE+0x0082) +#define CSRA66X0_TEMP_READ0_FA (CSRA66X0_BASE+0x0083) +#define CSRA66X0_TEMP_READ1_FA (CSRA66X0_BASE+0x0084) +#define CSRA66X0_CHIP_STATE_CTRL_FA (CSRA66X0_BASE+0x0085) +/* RESERVED (CSRA66X0_BASE+0x0086) */ +#define CSRA66X0_PWM_OUTPUT_CONFIG (CSRA66X0_BASE+0x0087) +#define CSRA66X0_MISC_CONTROL_STATUS_0 (CSRA66X0_BASE+0x0088) +#define CSRA66X0_MISC_CONTROL_STATUS_1_FA (CSRA66X0_BASE+0x0089) +#define CSRA66X0_PIO0_SELECT (CSRA66X0_BASE+0x008A) +#define CSRA66X0_PIO1_SELECT (CSRA66X0_BASE+0x008B) +#define CSRA66X0_PIO2_SELECT (CSRA66X0_BASE+0x008C) +#define CSRA66X0_PIO3_SELECT (CSRA66X0_BASE+0x008D) +#define CSRA66X0_PIO4_SELECT (CSRA66X0_BASE+0x008E) +#define CSRA66X0_PIO5_SELECT (CSRA66X0_BASE+0x008F) +#define CSRA66X0_PIO6_SELECT (CSRA66X0_BASE+0x0090) +#define CSRA66X0_PIO7_SELECT (CSRA66X0_BASE+0x0091) +#define CSRA66X0_PIO8_SELECT (CSRA66X0_BASE+0x0092) +#define CSRA66X0_PIO_DIRN0 (CSRA66X0_BASE+0x0093) +#define CSRA66X0_PIO_DIRN1 (CSRA66X0_BASE+0x0094) +#define CSRA66X0_PIO_PULL_EN0 (CSRA66X0_BASE+0x0095) +#define CSRA66X0_PIO_PULL_EN1 (CSRA66X0_BASE+0x0096) +#define CSRA66X0_PIO_PULL_DIR0 (CSRA66X0_BASE+0x0097) +#define CSRA66X0_PIO_PULL_DIR1 (CSRA66X0_BASE+0x0098) +#define CSRA66X0_PIO_DRIVE_OUT0_FA (CSRA66X0_BASE+0x0099) +#define CSRA66X0_PIO_DRIVE_OUT1_FA (CSRA66X0_BASE+0x009A) +#define CSRA66X0_PIO_STATUS_IN0_FA (CSRA66X0_BASE+0x009B) +#define CSRA66X0_PIO_STATUS_IN1_FA (CSRA66X0_BASE+0x009C) +/* RESERVED (CSRA66X0_BASE+0x009D) */ +#define CSRA66X0_IRQ_OUTPUT_ENABLE (CSRA66X0_BASE+0x009E) +#define CSRA66X0_IRQ_OUTPUT_POLARITY (CSRA66X0_BASE+0x009F) +#define CSRA66X0_IRQ_OUTPUT_STATUS_FA (CSRA66X0_BASE+0x00A0) +#define CSRA66X0_CLIP_DCA_STATUS_FA (CSRA66X0_BASE+0x00A1) +#define CSRA66X0_CHIP_STATE_STATUS_FA (CSRA66X0_BASE+0x00A2) +#define CSRA66X0_FAULT_STATUS_FA (CSRA66X0_BASE+0x00A3) +#define CSRA66X0_OTP_STATUS_FA (CSRA66X0_BASE+0x00A4) +#define CSRA66X0_AUDIO_IF_STATUS_FA (CSRA66X0_BASE+0x00A5) +/* RESERVED (CSRA66X0_BASE+0x00A6) */ +#define CSRA66X0_DSP_SATURATION_STATUS_FA (CSRA66X0_BASE+0x00A7) +#define CSRA66X0_AUDIO_RATE_STATUS_FA (CSRA66X0_BASE+0x00A8) +/* RESERVED (CSRA66X0_BASE+0x00A9) */ +/* ... */ +/* RESERVED (CSRA66X0_BASE+0x00AB) */ +#define CSRA66X0_DISABLE_PWM_OUTPUT (CSRA66X0_BASE+0x00AC) +/* RESERVED (CSRA66X0_BASE+0x00AD) */ +/* ... */ +/* RESERVED (CSRA66X0_BASE+0x00B0) */ +#define CSRA66X0_OTP_VER_FA (CSRA66X0_BASE+0x00B1) +#define CSRA66X0_RAM_VER_FA (CSRA66X0_BASE+0x00B2) +/* RESERVED (CSRA66X0_BASE+0x00B3) */ +#define CSRA66X0_AUDIO_SATURATION_FLAGS_FA (CSRA66X0_BASE+0x00B4) +#define CSRA66X0_DCOFFSET_CHAN_1_01_FA (CSRA66X0_BASE+0x00B5) +#define CSRA66X0_DCOFFSET_CHAN_1_02_FA (CSRA66X0_BASE+0x00B6) +#define CSRA66X0_DCOFFSET_CHAN_1_03_FA (CSRA66X0_BASE+0x00B7) +#define CSRA66X0_DCOFFSET_CHAN_2_01_FA (CSRA66X0_BASE+0x00B8) +#define CSRA66X0_DCOFFSET_CHAN_2_02_FA (CSRA66X0_BASE+0x00B9) +#define CSRA66X0_DCOFFSET_CHAN_2_03_FA (CSRA66X0_BASE+0x00BA) +#define CSRA66X0_FORCED_PA_SWITCHING_CTRL (CSRA66X0_BASE+0x00BB) +#define CSRA66X0_PA_FORCE_PULSE_WIDTH (CSRA66X0_BASE+0x00BC) +#define CSRA66X0_PA_HIGH_MODULATION_CTRL_CH1 (CSRA66X0_BASE+0x00BD) +/* RESERVED (CSRA66X0_BASE+0x00BE) */ +/* RESERVED (CSRA66X0_BASE+0x00BF) */ +#define CSRA66X0_HIGH_MODULATION_THRESHOLD_LOW (CSRA66X0_BASE+0x00C0) +#define CSRA66X0_HIGH_MODULATION_THRESHOLD_HIGH (CSRA66X0_BASE+0x00C1) +/* RESERVED (CSRA66X0_BASE+0x00C2) */ +/* RESERVED (CSRA66X0_BASE+0x00C3) */ +#define CSRA66X0_PA_FREEZE_CTRL (CSRA66X0_BASE+0x00C4) +#define CSRA66X0_DCA_FREEZE_CTRL (CSRA66X0_BASE+0x00C5) +/* RESERVED (CSRA66X0_BASE+0x00C6) */ +/* ... */ +/* RESERVED (CSRA66X0_BASE+0x00FF) */ +#define CSRA66X0_MAX_REGISTER_ADDR CSRA66X0_DCA_FREEZE_CTRL + +#define CSRA66X0_COEFF_BASE 0xD000 +#define CSRA66X0_MAX_COEFF_ADDR 0xD6DF + +#define EXPECTED_CSRA66X0_CHIP_ID 0x39 + +#define SPK_VOLUME_M20DB 0x119 +#define SPK_VOLUME_M20DB_LSB (SPK_VOLUME_M20DB & 0x0FF) +#define SPK_VOLUME_M20DB_MSB ((SPK_VOLUME_M20DB & 0x100)>>8) +#define SPK_VOLUME_LSB_MSK 0x00FF +#define SPK_VOLUME_MSB_MSK 0x0100 + +#define SET_CONFIG_STATE 0x0 +#define SET_RUN_STATE 0x1 +#define SET_STDBY_STATE 0x2 + +#define CONFIG_STATE_ID 0x3 +#define WAIT_FOR_CONFIG_STATE_TIMEOUT_MS 2000 +#define SYSFS_RESET 1 + +#define FAULT_STATUS_INTERNAL 0x01 +#define FAULT_STATUS_OTP_INTEGRITY 0x02 +#define FAULT_STATUS_PADS2 0x04 +#define FAULT_STATUS_SMPS 0x08 +#define FAULT_STATUS_TEMP 0x10 +#define FAULT_STATUS_PROTECT 0x20 + + +void csra66x0_hw_free_mute(struct snd_soc_component *component); +#endif /* _CSRA66X0_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/ep92/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/ep92/Kbuild new file mode 100644 index 0000000000..410d7fafed --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/ep92/Kbuild @@ -0,0 +1,106 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_QCS405), y) + include $(AUDIO_ROOT)/config/qcs405auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/qcs405autoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ EP92 ############ + +# for EP92 Codec +ifdef CONFIG_SND_SOC_EP92 + EP92_OBJS += ep92.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +#EXTRA_CFLAGS += $(INCS) +ccflags-y += $(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 +ccflags-y += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +#EXTRA_CFLAGS += -Wheader-guard +ccflags-y += -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_EP92) += ep92_dlkm.o +ep92_dlkm-y := $(EP92_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/ep92/ep92.c b/qcom/opensource/audio-kernel/asoc/codecs/ep92/ep92.c new file mode 100644 index 0000000000..1c4625898b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/ep92/ep92.c @@ -0,0 +1,2002 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ep92.h" + +#define DRV_NAME "ep92_codec" + +#define EP92_POLL_INTERVAL_OFF_MSEC 200 +#define EP92_POLL_INTERVAL_ON_MSEC 20 +#define EP92_POLL_RUNOUT_MSEC 5000 +#define EP92_SYSFS_ENTRY_MAX_LEN 64 +#define EP92_HYST_CNT 5 + +#define EP92_RATES (SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define EP92_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static const unsigned int ep92_samp_freq_table[8] = { + 32000, 44100, 48000, 88200, 96000, 176400, 192000, 768000 +}; + +static const unsigned int ep92_dsd_freq_table[4] = { + 64, 128, 256, 0 +}; + +/* EP92 register default values */ +static struct reg_default ep92_reg_defaults[] = { + {EP92_BI_VENDOR_ID_0, 0x17}, + {EP92_BI_VENDOR_ID_1, 0x7A}, + {EP92_BI_DEVICE_ID_0, 0x94}, + {EP92_BI_DEVICE_ID_1, 0xA3}, + {EP92_BI_VERSION_NUM, 0x10}, + {EP92_BI_VERSION_YEAR, 0x09}, + {EP92_BI_VERSION_MONTH, 0x07}, + {EP92_BI_VERSION_DATE, 0x06}, + {EP92_BI_GENERAL_INFO_0, 0x00}, + {EP92_BI_GENERAL_INFO_1, 0x00}, + {EP92_BI_GENERAL_INFO_2, 0x00}, + {EP92_BI_GENERAL_INFO_3, 0x00}, + {EP92_BI_GENERAL_INFO_4, 0x00}, + {EP92_BI_GENERAL_INFO_5, 0x00}, + {EP92_BI_GENERAL_INFO_6, 0x00}, + {EP92_ISP_MODE_ENTER_ISP, 0x00}, + {EP92_GENERAL_CONTROL_0, 0x20}, + {EP92_GENERAL_CONTROL_1, 0x00}, + {EP92_GENERAL_CONTROL_2, 0x00}, + {EP92_GENERAL_CONTROL_3, 0x10}, + {EP92_GENERAL_CONTROL_4, 0x00}, + {EP92_CEC_EVENT_CODE, 0x00}, + {EP92_CEC_EVENT_PARAM_1, 0x00}, + {EP92_CEC_EVENT_PARAM_2, 0x00}, + {EP92_CEC_EVENT_PARAM_3, 0x00}, + {EP92_CEC_EVENT_PARAM_4, 0x00}, + {EP92_AUDIO_INFO_SYSTEM_STATUS_0, 0x00}, + {EP92_AUDIO_INFO_SYSTEM_STATUS_1, 0x00}, + {EP92_AUDIO_INFO_AUDIO_STATUS, 0x00}, + {EP92_AUDIO_INFO_CHANNEL_STATUS_0, 0x00}, + {EP92_AUDIO_INFO_CHANNEL_STATUS_1, 0x00}, + {EP92_AUDIO_INFO_CHANNEL_STATUS_2, 0x00}, + {EP92_AUDIO_INFO_CHANNEL_STATUS_3, 0x00}, + {EP92_AUDIO_INFO_CHANNEL_STATUS_4, 0x00}, + {EP92_AUDIO_INFO_ADO_INFO_FRAME_0, 0x00}, + {EP92_AUDIO_INFO_ADO_INFO_FRAME_1, 0x00}, + {EP92_AUDIO_INFO_ADO_INFO_FRAME_2, 0x00}, + {EP92_AUDIO_INFO_ADO_INFO_FRAME_3, 0x00}, + {EP92_AUDIO_INFO_ADO_INFO_FRAME_4, 0x00}, + {EP92_AUDIO_INFO_ADO_INFO_FRAME_5, 0x00}, + {EP92_OTHER_PACKETS_HDMI_VS_0, 0x00}, + {EP92_OTHER_PACKETS_HDMI_VS_1, 0x00}, + {EP92_OTHER_PACKETS_ACP_PACKET, 0x00}, + {EP92_OTHER_PACKETS_AVI_INFO_FRAME_0, 0x00}, + {EP92_OTHER_PACKETS_AVI_INFO_FRAME_1, 0x00}, + {EP92_OTHER_PACKETS_AVI_INFO_FRAME_2, 0x00}, + {EP92_OTHER_PACKETS_AVI_INFO_FRAME_3, 0x00}, + {EP92_OTHER_PACKETS_AVI_INFO_FRAME_4, 0x00}, + {EP92_OTHER_PACKETS_GC_PACKET_0, 0x00}, + {EP92_OTHER_PACKETS_GC_PACKET_1, 0x00}, + {EP92_OTHER_PACKETS_GC_PACKET_2, 0x00}, +}; + +static bool ep92_volatile_register(struct device *dev, unsigned int reg) +{ + /* do not cache register state in regmap */ + return true; +} + +static bool ep92_writeable_registers(struct device *dev, unsigned int reg) +{ + if (reg >= EP92_ISP_MODE_ENTER_ISP && reg <= EP92_GENERAL_CONTROL_4) + return true; + + return false; +} + +static bool ep92_readable_registers(struct device *dev, unsigned int reg) +{ + if (reg >= EP92_BI_VENDOR_ID_0 && reg <= EP92_MAX_REGISTER_ADDR) + return true; + + return false; +} + +/* codec private data */ +struct ep92_pdata { + struct regmap *regmap; + struct snd_soc_component *component; + struct timer_list timer; + struct work_struct read_status_worker; + int irq; + int poll_trig; + int poll_rem; + int force_inactive; + + int hyst_tx_plug; + int hyst_link_on0; + int hyst_link_on1; + int hyst_link_on2; + int filt_tx_plug; + int filt_link_on0; + int filt_link_on1; + int filt_link_on2; + struct { + u8 tx_info; + u8 video_latency; + } gi; /* General Info block */ + + struct { + u8 ctl; + u8 rx_sel; + u8 ctl2; + u8 cec_volume; + u8 link; + } gc; /* General Control block */ + + struct { + u8 system_status_0; + u8 system_status_1; + u8 audio_status; + u8 cs[5]; + u8 cc; + u8 ca; + } ai; /* Audio Info block */ + + u8 old_mode; +#if IS_ENABLED(CONFIG_DEBUG_FS) + struct dentry *debugfs_dir; + struct dentry *debugfs_file_wo; + struct dentry *debugfs_file_ro; +#endif /* CONFIG_DEBUG_FS */ +}; + +struct ep92_mclk_cfg_info { + uint32_t in_sample_rate; + uint32_t out_mclk_freq; + uint8_t mul_val; +}; + +#define EP92_MCLK_MUL_512 0x3 +#define EP92_MCLK_MUL_384 0x2 +#define EP92_MCLK_MUL_256 0x1 +#define EP92_MCLK_MUL_128 0x0 +#define EP92_MCLK_MUL_MASK 0x3 + +/** + * ep92_set_ext_mclk - Configure the mclk based on sample freq + * + * @codec: handle pointer to ep92 codec + * @mclk_freq: mclk frequency to be set + * + * Returns 0 for sucess or appropriate negative error code + */ +int ep92_set_ext_mclk(struct snd_soc_codec *codec, uint32_t mclk_freq) +{ + unsigned int samp_freq = 0; + struct ep92_pdata *ep92 = NULL; + uint8_t value = 0; + int ret = 0; + + if (!codec) + return -EINVAL; + + ep92 = snd_soc_codec_get_drvdata(codec); + + samp_freq = ep92_samp_freq_table[(ep92->ai.audio_status) & + EP92_AI_RATE_MASK]; + + if (!mclk_freq || (mclk_freq % samp_freq)) { + pr_err("%s incompatbile mclk:%u and sample freq:%u\n", + __func__, mclk_freq, samp_freq); + return -EINVAL; + } + + switch (mclk_freq / samp_freq) { + case 512: + value = EP92_MCLK_MUL_512; + break; + case 384: + value = EP92_MCLK_MUL_384; + break; + case 256: + value = EP92_MCLK_MUL_256; + break; + case 128: + value = EP92_MCLK_MUL_128; + break; + default: + dev_err(codec->dev, "unsupported mclk:%u for sample freq:%u\n", + mclk_freq, samp_freq); + return -EINVAL; + } + + pr_debug("%s mclk:%u, in sample freq:%u, write reg:0x%02x val:0x%02x\n", + __func__, mclk_freq, samp_freq, + EP92_GENERAL_CONTROL_2, EP92_MCLK_MUL_MASK & value); + + ret = snd_soc_update_bits(codec, EP92_GENERAL_CONTROL_2, + EP92_MCLK_MUL_MASK, value); + + return (((ret == 0) || (ret == 1)) ? 0 : ret); +} +EXPORT_SYMBOL(ep92_set_ext_mclk); + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static int debugfs_codec_open_op(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int debugfs_get_parameters(char *buf, u32 *param1, int num_of_par) +{ + char *token; + int base, cnt; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +static ssize_t debugfs_codec_write_op(struct file *filp, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + struct ep92_pdata *ep92 = (struct ep92_pdata *) filp->private_data; + struct snd_soc_component *component = ep92->component; + char lbuf[32]; + int rc; + u32 param[2]; + + if (!component) + return -ENODEV; + + if (!filp || !ppos || !ubuf) + return -EINVAL; + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + lbuf[cnt] = '\0'; + rc = debugfs_get_parameters(lbuf, param, 2); + if ((param[0] < EP92_ISP_MODE_ENTER_ISP) + || (param[0] > EP92_GENERAL_CONTROL_4)) { + dev_err(component->dev, "%s: reg address 0x%02X out of range\n", + __func__, param[0]); + return -EINVAL; + } + if ((param[1] < 0) || (param[1] > 255)) { + dev_err(component->dev, "%s: reg data 0x%02X out of range\n", + __func__, param[1]); + return -EINVAL; + } + if (rc == 0) { + rc = cnt; + dev_info(component->dev, "%s: reg[0x%02X]=0x%02X\n", + __func__, param[0], param[1]); + snd_soc_component_write(component, param[0], param[1]); + } else { + dev_err(component->dev, "%s: write to register addr=0x%02X failed\n", + __func__, param[0]); + } + return rc; +} + +static ssize_t debugfs_ep92_reg_show(struct snd_soc_component *component, + char __user *ubuf, size_t count, loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[20]; + + if (!ubuf || !ppos || !component || *ppos < 0) + return -EINVAL; + + for (i = (int) *ppos / 11; i <= EP92_MAX_REGISTER_ADDR; i++) { + reg_val = snd_soc_component_read32(component, i); + len = snprintf(tmp_buf, 20, "0x%02X: 0x%02X\n", i, + (reg_val & 0xFF)); + if ((total + len) > count) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + dev_err(component->dev, "%s: fail to copy reg dump\n", + __func__); + total = -EFAULT; + goto copy_err; + } + *ppos += len; + total += len; + } + +copy_err: + return total; +} + +static ssize_t debugfs_codec_read_op(struct file *filp, + char __user *ubuf, size_t cnt, loff_t *ppos) +{ + struct ep92_pdata *ep92 = (struct ep92_pdata *) filp->private_data; + struct snd_soc_component *component = ep92->component; + ssize_t ret_cnt; + + if (!component) + return -ENODEV; + + if (!filp || !ppos || !ubuf || *ppos < 0) + return -EINVAL; + ret_cnt = debugfs_ep92_reg_show(component, ubuf, cnt, ppos); + return ret_cnt; +} + +static const struct file_operations debugfs_codec_ops = { + .open = debugfs_codec_open_op, + .write = debugfs_codec_write_op, + .read = debugfs_codec_read_op, +}; +#endif /* CONFIG_DEBUG_FS */ + +static int ep92_send_uevent(struct ep92_pdata *ep92, char *event) +{ + char *env[] = { event, NULL }; + + if (!event || !ep92) + return -EINVAL; + + if (!ep92->component) + return -ENODEV; + return kobject_uevent_env(&ep92->component->dev->kobj, + KOBJ_CHANGE, env); +} + +static int ep92_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return 0; +} + +static void ep92_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ +} + +static int ep92_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + return 0; +} + +static struct snd_soc_dai_ops ep92_dai_ops = { + .startup = ep92_startup, + .shutdown = ep92_shutdown, + .hw_params = ep92_hw_params, +}; + +static struct snd_soc_dai_driver ep92_dai[] = { + { + .name = "ep92-hdmi", + .id = 1, + .capture = { + .stream_name = "HDMI Capture", + .rate_max = 192000, + .rate_min = 32000, + .channels_min = 1, + .channels_max = 8, + .rates = EP92_RATES, + .formats = EP92_FORMATS, + }, + .ops = &ep92_dai_ops, /* callbacks */ + }, + { + .name = "ep92-arc", + .id = 2, + .capture = { + .stream_name = "ARC Capture", + .rate_max = 192000, + .rate_min = 32000, + .channels_min = 1, + .channels_max = 2, + .rates = EP92_RATES, + .formats = EP92_FORMATS, + }, + .ops = &ep92_dai_ops, /* callbacks */ + }, +}; + +static void ep92_read_general_control(struct snd_soc_component *component, + struct ep92_pdata *ep92) +{ + u8 old, change; + int val; + + old = ep92->gi.tx_info; + ep92->gi.tx_info = snd_soc_component_read32(component, + EP92_BI_GENERAL_INFO_0); + if (ep92->gi.tx_info == 0xff) { + dev_dbg(component->dev, "ep92 EP92_BI_GENERAL_INFO_0 read 0xff\n"); + ep92->gi.tx_info = old; + } + /* implement hysteresis to prevent events on glitches */ + if (ep92->gi.tx_info & EP92_GI_TX_HOT_PLUG_MASK) { + if (ep92->hyst_tx_plug < EP92_HYST_CNT) { + ep92->hyst_tx_plug++; + if ((ep92->hyst_tx_plug == EP92_HYST_CNT) && + (ep92->filt_tx_plug == 0)) { + ep92->filt_tx_plug = 1; + dev_dbg(component->dev, "ep92 out_plug changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_OUT_PLUG=CONNECTED"); + } + } + } else { + if (ep92->hyst_tx_plug > 0) { + ep92->hyst_tx_plug--; + if ((ep92->hyst_tx_plug == 0) && + (ep92->filt_tx_plug == 1)) { + ep92->filt_tx_plug = 0; + dev_dbg(component->dev, "ep92 out_plug changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_OUT_PLUG=DISCONNECTED"); + } + } + } + + old = ep92->gi.video_latency; + ep92->gi.video_latency = snd_soc_component_read32(component, + EP92_BI_GENERAL_INFO_4); + if (ep92->gi.video_latency == 0xff) { + dev_dbg(component->dev, "ep92 EP92_BI_GENERAL_INFO_4 read 0xff\n"); + ep92->gi.video_latency = old; + } + change = ep92->gi.video_latency ^ old; + if (change & EP92_GI_VIDEO_LATENCY_MASK) { + val = ep92->gi.video_latency; + if (val > 0) + val = (val - 1) * 2; + dev_dbg(component->dev, "ep92 video latency changed to %d\n", val); + ep92_send_uevent(ep92, "EP92EVT_VIDEO_LATENCY=CHANGED"); + } + + old = ep92->gc.ctl; + ep92->gc.ctl = snd_soc_component_read32(component, + EP92_GENERAL_CONTROL_0); + if (ep92->gc.ctl == 0xff) { + dev_dbg(component->dev, "ep92 EP92_GENERAL_CONTROL_0 read 0xff\n"); + ep92->gc.ctl = old; + } + change = ep92->gc.ctl ^ old; + if (change & EP92_GC_POWER_MASK) { + val = (ep92->gc.ctl >> EP92_GC_POWER_SHIFT) & + EP92_2CHOICE_MASK; + dev_dbg(component->dev, "ep92 power changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_POWER=ON"); + else + ep92_send_uevent(ep92, "EP92EVT_POWER=OFF"); + } + if (change & EP92_GC_AUDIO_PATH_MASK) { + val = (ep92->gc.ctl >> EP92_GC_AUDIO_PATH_SHIFT) & + EP92_2CHOICE_MASK; + dev_dbg(component->dev, "ep92 audio_path changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_AUDIO_PATH=TV"); + else + ep92_send_uevent(ep92, "EP92EVT_AUDIO_PATH=SPEAKER"); + } + if (change & EP92_GC_CEC_MUTE_MASK) { + val = (ep92->gc.ctl >> EP92_GC_CEC_MUTE_SHIFT) & + EP92_2CHOICE_MASK; + dev_dbg(component->dev, "ep92 cec_mute changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_CEC_MUTE=NORMAL"); + else + ep92_send_uevent(ep92, "EP92EVT_CEC_MUTE=MUTED"); + } + if (change & EP92_GC_ARC_EN_MASK) { + val = ep92->gc.ctl & EP92_2CHOICE_MASK; + dev_dbg(component->dev, "ep92 arc_en changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_ARC_EN=ON"); + else + ep92_send_uevent(ep92, "EP92EVT_ARC_EN=OFF"); + } + + old = ep92->gc.rx_sel; + ep92->gc.rx_sel = snd_soc_component_read32(component, + EP92_GENERAL_CONTROL_1); + if (ep92->gc.rx_sel == 0xff) { + dev_dbg(component->dev, "ep92 EP92_GENERAL_CONTROL_1 read 0xff\n"); + ep92->gc.rx_sel = old; + } + change = ep92->gc.rx_sel ^ old; + if (change & EP92_GC_RX_SEL_MASK) { + val = ep92->gc.rx_sel & EP92_GC_RX_SEL_MASK; + dev_dbg(component->dev, "ep92 rx_sel changed to %d\n", val); + ep92_send_uevent(ep92, "EP92EVT_SRC_SEL=CHANGED"); + } + + old = ep92->gc.cec_volume; + ep92->gc.cec_volume = snd_soc_component_read32(component, + EP92_GENERAL_CONTROL_3); + if (ep92->gc.cec_volume == 0xff) { + dev_dbg(component->dev, "ep92 EP92_GENERAL_CONTROL_3 read 0xff\n"); + ep92->gc.cec_volume = old; + } + change = ep92->gc.cec_volume ^ old; + if (change & EP92_GC_CEC_VOLUME_MASK) { + val = ep92->gc.cec_volume & EP92_GC_CEC_VOLUME_MASK; + dev_dbg(component->dev, "ep92 cec_volume changed to %d\n", val); + ep92_send_uevent(ep92, "EP92EVT_CEC_VOLUME=CHANGED"); + } + + old = ep92->gc.link; + ep92->gc.link = snd_soc_component_read32(component, + EP92_GENERAL_CONTROL_4); + if (ep92->gc.link == 0xff) { + dev_dbg(component->dev, "ep92 EP92_GENERAL_CONTROL_4 read 0xff\n"); + ep92->gc.link = old; + } + + /* implement hysteresis to prevent events on glitches */ + if (ep92->gc.link & EP92_GC_LINK_ON0_MASK) { + if (ep92->hyst_link_on0 < EP92_HYST_CNT) { + ep92->hyst_link_on0++; + if ((ep92->hyst_link_on0 == EP92_HYST_CNT) && + (ep92->filt_link_on0 == 0)) { + ep92->filt_link_on0 = 1; + dev_dbg(component->dev, "ep92 link_on0 changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON0=CONNECTED"); + } + } + } else { + if (ep92->hyst_link_on0 > 0) { + ep92->hyst_link_on0--; + if ((ep92->hyst_link_on0 == 0) && + (ep92->filt_link_on0 == 1)) { + ep92->filt_link_on0 = 0; + dev_dbg(component->dev, "ep92 link_on0 changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON0=DISCONNECTED"); + } + } + } + + /* implement hysteresis to prevent events on glitches */ + if (ep92->gc.link & EP92_GC_LINK_ON1_MASK) { + if (ep92->hyst_link_on1 < EP92_HYST_CNT) { + ep92->hyst_link_on1++; + if ((ep92->hyst_link_on1 == EP92_HYST_CNT) && + (ep92->filt_link_on1 == 0)) { + ep92->filt_link_on1 = 1; + dev_dbg(component->dev, "ep92 link_on1 changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON1=CONNECTED"); + } + } + } else { + if (ep92->hyst_link_on1 > 0) { + ep92->hyst_link_on1--; + if ((ep92->hyst_link_on1 == 0) && + (ep92->filt_link_on1 == 1)) { + ep92->filt_link_on1 = 0; + dev_dbg(component->dev, "ep92 link_on1 changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON1=DISCONNECTED"); + } + } + } + + /* implement hysteresis to prevent events on glitches */ + if (ep92->gc.link & EP92_GC_LINK_ON2_MASK) { + if (ep92->hyst_link_on2 < EP92_HYST_CNT) { + ep92->hyst_link_on2++; + if ((ep92->hyst_link_on2 == EP92_HYST_CNT) && + (ep92->filt_link_on2 == 0)) { + ep92->filt_link_on2 = 1; + dev_dbg(component->dev, "ep92 link_on2 changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON2=CONNECTED"); + } + } + } else { + if (ep92->hyst_link_on2 > 0) { + ep92->hyst_link_on2--; + if ((ep92->hyst_link_on2 == 0) && + (ep92->filt_link_on2 == 1)) { + ep92->filt_link_on2 = 0; + dev_dbg(component->dev, "ep92 link_on2 changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON2=DISCONNECTED"); + } + } + } +} + +static void ep92_read_audio_info(struct snd_soc_component *component, + struct ep92_pdata *ep92) +{ + u8 old, change; + u8 new_mode; + bool send_uevent = false; + + old = ep92->ai.system_status_0; + ep92->ai.system_status_0 = snd_soc_component_read32(component, + EP92_AUDIO_INFO_SYSTEM_STATUS_0); + if (ep92->ai.system_status_0 == 0xff) { + dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_SYSTEM_STATUS_0 read 0xff\n"); + ep92->ai.system_status_0 = old; + } + change = ep92->ai.system_status_0 ^ old; + if (change & EP92_AI_MCLK_ON_MASK) { + dev_dbg(component->dev, "ep92 status changed to %d\n", + (ep92->ai.system_status_0 >> EP92_AI_MCLK_ON_SHIFT) & + EP92_2CHOICE_MASK); + send_uevent = true; + } + if (change & EP92_AI_AVMUTE_MASK) { + dev_dbg(component->dev, "ep92 avmute changed to %d\n", + (ep92->ai.system_status_0 >> EP92_AI_AVMUTE_SHIFT) & + EP92_2CHOICE_MASK); + send_uevent = true; + } + if (change & EP92_AI_LAYOUT_MASK) { + dev_dbg(component->dev, "ep92 layout changed to %d\n", + (ep92->ai.system_status_0) & EP92_2CHOICE_MASK); + send_uevent = true; + } + + old = ep92->ai.system_status_1; + ep92->ai.system_status_1 = snd_soc_read(codec, + EP92_AUDIO_INFO_SYSTEM_STATUS_1); + if (ep92->ai.system_status_1 == 0xff) { + dev_dbg(codec->dev, + "ep92 EP92_AUDIO_INFO_SYSTEM_STATUS_1 read 0xff\n"); + ep92->ai.system_status_1 = old; + } + change = ep92->ai.system_status_1 ^ old; + if (change & EP92_AI_DSD_RATE_MASK) { + dev_dbg(codec->dev, "ep92 dsd rate changed to %d\n", + ep92_dsd_freq_table[(ep92->ai.system_status_1 & + EP92_AI_DSD_RATE_MASK) + >> EP92_AI_DSD_RATE_SHIFT]); + send_uevent = true; + } + + old = ep92->ai.audio_status; + ep92->ai.audio_status = snd_soc_component_read32(component, + EP92_AUDIO_INFO_AUDIO_STATUS); + if (ep92->ai.audio_status == 0xff) { + dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_AUDIO_STATUS read 0xff\n"); + ep92->ai.audio_status = old; + } + change = ep92->ai.audio_status ^ old; + if (change & EP92_AI_RATE_MASK) { + dev_dbg(component->dev, "ep92 rate changed to %d\n", + ep92_samp_freq_table[(ep92->ai.audio_status) & + EP92_AI_RATE_MASK]); + send_uevent = true; + } + + old = ep92->ai.cs[0]; + ep92->ai.cs[0] = snd_soc_component_read32(component, + EP92_AUDIO_INFO_CHANNEL_STATUS_0); + if (ep92->ai.cs[0] == 0xff) { + dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_CHANNEL_STATUS_0 read 0xff\n"); + ep92->ai.cs[0] = old; + } + change = ep92->ai.cs[0] ^ old; + if (change & EP92_AI_PREEMPH_MASK) { + dev_dbg(component->dev, "ep92 preemph changed to %d\n", + (ep92->ai.cs[0] & EP92_AI_PREEMPH_MASK) >> + EP92_AI_PREEMPH_SHIFT); + send_uevent = true; + } + + new_mode = ep92->old_mode; + if (ep92->ai.audio_status & EP92_AI_DSD_ADO_MASK) + new_mode = 2; /* One bit audio */ + else if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) { + if (ep92->ai.cs[0] & EP92_AI_NPCM_MASK) + new_mode = 1; /* Compr */ + else + new_mode = 0; /* LPCM */ + } else if (ep92->ai.audio_status & EP92_AI_HBR_ADO_MASK) + new_mode = 1; /* Compr */ + + if (ep92->old_mode != new_mode) { + dev_dbg(component->dev, "ep92 mode changed to %d\n", new_mode); + send_uevent = true; + } + ep92->old_mode = new_mode; + + old = ep92->ai.cc; + ep92->ai.cc = snd_soc_component_read32(component, + EP92_AUDIO_INFO_ADO_INFO_FRAME_1); + if (ep92->ai.cc == 0xff) { + dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_ADO_INFO_FRAME_1 read 0xff\n"); + ep92->ai.cc = old; + } + change = ep92->ai.cc ^ old; + if (change & EP92_AI_CH_COUNT_MASK) { + dev_dbg(component->dev, "ep92 ch_count changed to %d (%d)\n", + ep92->ai.cc & EP92_AI_CH_COUNT_MASK, + (ep92->ai.cc & EP92_AI_CH_COUNT_MASK) == 0 ? 0 : + (ep92->ai.cc & EP92_AI_CH_COUNT_MASK) + 1); + send_uevent = true; + } + + old = ep92->ai.ca; + ep92->ai.ca = snd_soc_component_read32(component, + EP92_AUDIO_INFO_ADO_INFO_FRAME_4); + if (ep92->ai.ca == 0xff) { + dev_dbg(component->dev, "ep92 EP92_AUDIO_INFO_ADO_INFO_FRAME_4 read 0xff\n"); + ep92->ai.ca = old; + } + change = ep92->ai.ca ^ old; + if (change & EP92_AI_CH_ALLOC_MASK) { + dev_dbg(component->dev, "ep92 ch_alloc changed to 0x%02x\n", + (ep92->ai.ca) & EP92_AI_CH_ALLOC_MASK); + send_uevent = true; + } + + if (send_uevent) + ep92_send_uevent(ep92, "EP92EVT_AUDIO=MEDIA_CONFIG_CHANGE"); +} + +static void ep92_init(struct snd_soc_component *component, + struct ep92_pdata *ep92) +{ + int reg0 = 0; + int reg1 = 0; + int reg2 = 0; + int reg3 = 0; + + if (!ep92 || !component) + return; + + reg0 = snd_soc_component_read32(component, EP92_BI_VERSION_YEAR); + reg1 = snd_soc_component_read32(component, EP92_BI_VERSION_MONTH); + reg2 = snd_soc_component_read32(component, EP92_BI_VERSION_DATE); + reg3 = snd_soc_component_read32(component, EP92_BI_VERSION_NUM); + + dev_info(compoent->dev, "ep92 version info %02d/%02d/%02d %d\n", + reg0, reg1, reg2, reg3); + + /* update the format information in mixer controls */ + ep92_read_general_control(component, ep92); + ep92_read_audio_info(component, ep92); +} + +static int ep92_probe(struct snd_soc_component *component) +{ + struct ep92_pdata *ep92 = snd_soc_component_get_drvdata(component); + + ep92->component = component; + ep92_init(component, ep92); + + /* start polling when codec is registered */ + mod_timer(&ep92->timer, jiffies + + msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC)); + + return 0; +} + +static void ep92_remove(struct snd_soc_component *component) +{ + return; +} + +static const struct snd_soc_component_driver soc_codec_drv_ep92 = { + .name = DRV_NAME, + .probe = ep92_probe, + .remove = ep92_remove, +}; + +static struct regmap_config ep92_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = ep92_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ep92_reg_defaults), + .max_register = EP92_MAX_REGISTER_ADDR, + .volatile_reg = ep92_volatile_register, + .writeable_reg = ep92_writeable_registers, + .readable_reg = ep92_readable_registers, +}; + +void ep92_read_status(struct work_struct *work) +{ + struct ep92_pdata *ep92 = container_of(work, struct ep92_pdata, + read_status_worker); + struct snd_soc_component *component = ep92->component; + u8 val; + + /* No polling before component is initialized */ + if (component == NULL) + return; + + if (ep92->force_inactive) + return; + + /* check ADO_CHF that is set when audio format has changed */ + val = snd_soc_component_read32(component, EP92_BI_GENERAL_INFO_1); + if (val == 0xff) { + /* workaround for Nak'ed first read */ + val = snd_soc_component_read32(component, + EP92_BI_GENERAL_INFO_1); + if (val == 0xff) + return; /* assume device not present */ + } + + if (val & EP92_GI_ADO_CHF_MASK) + dev_dbg(component->dev, "ep92 audio mode change trigger.\n"); + + if (val & EP92_GI_CEC_ECF_MASK) + dev_dbg(component->dev, "ep92 CEC change trigger.\n"); + + /* check for general control changes */ + ep92_read_general_control(component, ep92); + + /* update the format information in mixer controls */ + ep92_read_audio_info(component, ep92); +} + +static irqreturn_t ep92_irq(int irq, void *data) +{ + struct ep92_pdata *ep92 = data; + struct snd_soc_component *component = ep92->component; + + /* Treat interrupt before component is initialized as spurious */ + if (component == NULL) + return IRQ_NONE; + + dev_dbg(component->dev, "ep92_interrupt\n"); + + ep92->poll_trig = 1; + mod_timer(&ep92->timer, jiffies + + msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC)); + + schedule_work(&ep92->read_status_worker); + + return IRQ_HANDLED; +}; + +void ep92_poll_status(struct timer_list *t) +{ + struct ep92_pdata *ep92 = from_timer(ep92, t, timer); + struct snd_soc_component *component = ep92->component; + + if (ep92->force_inactive) + return; + + /* if no IRQ is configured, always keep on polling */ + if (ep92->irq == 0) + ep92->poll_rem = EP92_POLL_RUNOUT_MSEC; + + /* on interrupt, start polling for some time */ + if (ep92->poll_trig) { + if (ep92->poll_rem == 0) + dev_info(component->dev, "status checking activated\n"); + + ep92->poll_trig = 0; + ep92->poll_rem = EP92_POLL_RUNOUT_MSEC; + } + + /* + * If power_on == 0, poll only until poll_rem reaches zero and stop. + * This allows to system to go to low power sleep mode. + * Otherwise (power_on == 1) always re-arm timer to keep on polling. + */ + if ((ep92->gc.ctl & EP92_GC_POWER_MASK) == 0) { + if (ep92->poll_rem) { + mod_timer(&ep92->timer, jiffies + + msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC)); + if (ep92->poll_rem > EP92_POLL_INTERVAL_OFF_MSEC) { + ep92->poll_rem -= EP92_POLL_INTERVAL_OFF_MSEC; + } else { + dev_info(component->dev, "status checking stopped\n"); + ep92->poll_rem = 0; + } + } + } else { + ep92->poll_rem = EP92_POLL_RUNOUT_MSEC; + mod_timer(&ep92->timer, jiffies + + msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC)); + } + + schedule_work(&ep92->read_status_worker); +} + +static const struct of_device_id ep92_of_match[] = { + { .compatible = "explore,ep92a6", }, + { } +}; +MODULE_DEVICE_TABLE(of, ep92_of_match); + +static ssize_t ep92_sysfs_rda_chipid(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int reg0 = 0; + int reg1 = 0; + int reg2 = 0; + int reg3 = 0; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + reg0 = snd_soc_component_read32(ep92->component, EP92_BI_VENDOR_ID_0); + reg1 = snd_soc_component_read32(ep92->component, EP92_BI_VENDOR_ID_1); + reg2 = snd_soc_component_read32(ep92->component, EP92_BI_DEVICE_ID_0); + reg3 = snd_soc_component_read32(ep92->component, EP92_BI_DEVICE_ID_1); + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%02x%02x/%02x%02x\n", + reg0, reg1, reg2, reg3); + dev_dbg(dev, "%s: '%s'\n", __func__, buf); + + return ret; +} + +static ssize_t ep92_sysfs_rda_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int reg0 = 0; + int reg1 = 0; + int reg2 = 0; + int reg3 = 0; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + reg0 = snd_soc_component_read32(ep92->component, + EP92_BI_VERSION_YEAR); + reg1 = snd_soc_component_read32(ep92->component, + EP92_BI_VERSION_MONTH); + reg2 = snd_soc_component_read32(ep92->component, + EP92_BI_VERSION_DATE); + reg3 = snd_soc_component_read32(ep92->component, + EP92_BI_VERSION_NUM); + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%02d/%02d/%02d %d\n", + reg0, reg1, reg2, reg3); + dev_dbg(dev, "%s: '%s'\n", __func__, buf); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->ai.system_status_0 & EP92_AI_MCLK_ON_MASK) >> + EP92_AI_MCLK_ON_SHIFT; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_format(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->old_mode; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_dsd_rate(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->codec) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92_dsd_freq_table[(ep92->ai.system_status_1 & + EP92_AI_DSD_RATE_MASK) >> EP92_AI_DSD_RATE_SHIFT]; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_rate(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92_samp_freq_table[(ep92->ai.audio_status) & + EP92_AI_RATE_MASK]; + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_layout(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->ai.system_status_0 & EP92_AI_LAYOUT_MASK) >> + EP92_AI_LAYOUT_SHIFT; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_ch_count(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->ai.cc & EP92_AI_CH_COUNT_MASK; + /* mapping is ch_count = reg_val + 1, with exception: 0 = unknown */ + if (val > 0) + val += 1; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_ch_alloc(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->ai.ca & EP92_AI_CH_ALLOC_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_preemph(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->ai.cs[0] & EP92_AI_PREEMPH_MASK) >> + EP92_AI_PREEMPH_SHIFT; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_avmute(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->ai.system_status_0 >> EP92_AI_AVMUTE_SHIFT) & + EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_link_on0(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->filt_link_on0; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_link_on1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->filt_link_on1; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_link_on2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->filt_link_on2; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_out_plug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->filt_tx_plug; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_video_latency(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->gi.video_latency & EP92_GI_VIDEO_LATENCY_MASK; + if (val > 0) + val = (val - 1) * 2; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_arc_disable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->gc.ctl2 >> EP92_GC_ARC_DIS_SHIFT) & + EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_arc_disable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_component_read32(ep92->component, + EP92_GENERAL_CONTROL_2); + reg &= ~EP92_GC_ARC_DIS_MASK; + reg |= ((val << EP92_GC_ARC_DIS_SHIFT) & EP92_GC_ARC_DIS_MASK); + snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_2, reg); + ep92->gc.ctl2 &= ~EP92_GC_ARC_DIS_MASK; + ep92->gc.ctl2 |= (val << EP92_GC_ARC_DIS_SHIFT) & EP92_GC_ARC_DIS_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_power(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->gc.ctl >> EP92_GC_POWER_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_power(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_component_read32(ep92->component, EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_POWER_MASK; + reg |= (val << EP92_GC_POWER_SHIFT) & EP92_GC_POWER_MASK; + snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_POWER_MASK; + ep92->gc.ctl |= (val << EP92_GC_POWER_SHIFT) & EP92_GC_POWER_MASK; + + if (val == 1) { + ep92->poll_trig = 1; + mod_timer(&ep92->timer, jiffies + + msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC)); + } + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_audio_path(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->gc.ctl >> EP92_GC_AUDIO_PATH_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_audio_path(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_component_read32(ep92->component, + EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_AUDIO_PATH_MASK; + reg |= (val << EP92_GC_AUDIO_PATH_SHIFT) & EP92_GC_AUDIO_PATH_MASK; + snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_AUDIO_PATH_MASK; + ep92->gc.ctl |= (val << EP92_GC_AUDIO_PATH_SHIFT) & + EP92_GC_AUDIO_PATH_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_src_sel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->gc.rx_sel & EP92_GC_RX_SEL_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_src_sel(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 7)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_component_read32(ep92->component, + EP92_GENERAL_CONTROL_1); + reg &= ~EP92_GC_RX_SEL_MASK; + reg |= (val << EP92_GC_RX_SEL_SHIFT) & EP92_GC_RX_SEL_MASK; + snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_1, reg); + ep92->gc.rx_sel &= ~EP92_GC_RX_SEL_MASK; + ep92->gc.rx_sel |= (val << EP92_GC_RX_SEL_SHIFT) & EP92_GC_RX_SEL_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_arc_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->gc.ctl >> EP92_GC_ARC_EN_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_arc_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_component_read32(ep92->component, EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_ARC_EN_MASK; + reg |= (val << EP92_GC_ARC_EN_SHIFT) & EP92_GC_ARC_EN_MASK; + snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_ARC_EN_MASK; + ep92->gc.ctl |= (val << EP92_GC_ARC_EN_SHIFT) & + EP92_GC_ARC_EN_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_cec_mute(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->gc.ctl >> EP92_GC_CEC_MUTE_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_cec_mute(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_component_read32(ep92->component, EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_CEC_MUTE_MASK; + reg |= (val << EP92_GC_CEC_MUTE_SHIFT) & EP92_GC_CEC_MUTE_MASK; + snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_CEC_MUTE_MASK; + ep92->gc.ctl |= (val << EP92_GC_CEC_MUTE_SHIFT) & + EP92_GC_CEC_MUTE_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_cec_volume(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = (ep92->gc.cec_volume >> EP92_GC_CEC_VOLUME_SHIFT) & + EP92_GC_CEC_VOLUME_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_cec_volume(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > EP92_GC_CEC_VOLUME_MAX)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = val & EP92_GC_CEC_VOLUME_MASK; + snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_3, reg); + ep92->gc.cec_volume = val & EP92_GC_CEC_VOLUME_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_runout(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->poll_rem; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_force_inactive(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92->force_inactive; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_force_inactive(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->component) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + if (val == 0) { + ep92->force_inactive = 0; + ep92->poll_trig = 1; + mod_timer(&ep92->timer, jiffies + + msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC)); + } else { + ep92->force_inactive = 1; + ep92->poll_rem = 0; + } + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static DEVICE_ATTR(chipid, 0444, ep92_sysfs_rda_chipid, NULL); +static DEVICE_ATTR(version, 0444, ep92_sysfs_rda_version, NULL); +static DEVICE_ATTR(audio_state, 0444, ep92_sysfs_rda_audio_state, NULL); +static DEVICE_ATTR(audio_format, 0444, ep92_sysfs_rda_audio_format, NULL); +static DEVICE_ATTR(audio_rate, 0444, ep92_sysfs_rda_audio_rate, NULL); +static DEVICE_ATTR(audio_layout, 0444, ep92_sysfs_rda_audio_layout, NULL); +static DEVICE_ATTR(audio_ch_count, 0444, ep92_sysfs_rda_audio_ch_count, NULL); +static DEVICE_ATTR(audio_ch_alloc, 0444, ep92_sysfs_rda_audio_ch_alloc, NULL); +static DEVICE_ATTR(audio_preemph, 0444, ep92_sysfs_rda_audio_preemph, NULL); +static DEVICE_ATTR(audio_avmute, 0444, ep92_sysfs_rda_avmute, NULL); +static DEVICE_ATTR(link_on0, 0444, ep92_sysfs_rda_link_on0, NULL); +static DEVICE_ATTR(link_on1, 0444, ep92_sysfs_rda_link_on1, NULL); +static DEVICE_ATTR(link_on2, 0444, ep92_sysfs_rda_link_on2, NULL); +static DEVICE_ATTR(out_plug, 0444, ep92_sysfs_rda_out_plug, NULL); +static DEVICE_ATTR(video_latency, 0444, ep92_sysfs_rda_video_latency, NULL); +static DEVICE_ATTR(arc_disable, 0644, ep92_sysfs_rda_arc_disable, + ep92_sysfs_wta_arc_disable); +static DEVICE_ATTR(power_on, 0644, ep92_sysfs_rda_power, ep92_sysfs_wta_power); +static DEVICE_ATTR(audio_path, 0644, ep92_sysfs_rda_audio_path, + ep92_sysfs_wta_audio_path); +static DEVICE_ATTR(src_sel, 0644, ep92_sysfs_rda_src_sel, + ep92_sysfs_wta_src_sel); +static DEVICE_ATTR(arc_enable, 0644, ep92_sysfs_rda_arc_enable, + ep92_sysfs_wta_arc_enable); +static DEVICE_ATTR(cec_mute, 0644, ep92_sysfs_rda_cec_mute, + ep92_sysfs_wta_cec_mute); +static DEVICE_ATTR(cec_volume, 0644, ep92_sysfs_rda_cec_volume, + ep92_sysfs_wta_cec_volume); +static DEVICE_ATTR(runout, 0444, ep92_sysfs_rda_runout, NULL); +static DEVICE_ATTR(force_inactive, 0644, ep92_sysfs_rda_force_inactive, + ep92_sysfs_wta_force_inactive); +static DEVICE_ATTR(dsd_rate, 0444, ep92_sysfs_rda_dsd_rate, NULL); + +static struct attribute *ep92_fs_attrs[] = { + &dev_attr_chipid.attr, + &dev_attr_version.attr, + &dev_attr_audio_state.attr, + &dev_attr_audio_format.attr, + &dev_attr_audio_rate.attr, + &dev_attr_audio_layout.attr, + &dev_attr_audio_ch_count.attr, + &dev_attr_audio_ch_alloc.attr, + &dev_attr_audio_preemph.attr, + &dev_attr_audio_avmute.attr, + &dev_attr_link_on0.attr, + &dev_attr_link_on1.attr, + &dev_attr_link_on2.attr, + &dev_attr_out_plug.attr, + &dev_attr_video_latency.attr, + &dev_attr_arc_disable.attr, + &dev_attr_power_on.attr, + &dev_attr_audio_path.attr, + &dev_attr_src_sel.attr, + &dev_attr_arc_enable.attr, + &dev_attr_cec_mute.attr, + &dev_attr_cec_volume.attr, + &dev_attr_runout.attr, + &dev_attr_force_inactive.attr, + &dev_attr_dsd_rate.attr, + NULL, +}; + +static struct attribute_group ep92_fs_attrs_group = { + .attrs = ep92_fs_attrs, +}; + +static int ep92_sysfs_create(struct i2c_client *client, + struct ep92_pdata *ep92) +{ + int rc; + + rc = sysfs_create_group(&client->dev.kobj, &ep92_fs_attrs_group); + + return rc; +} + +static void ep92_sysfs_remove(struct i2c_client *client, + struct ep92_pdata *ep92) +{ + sysfs_remove_group(&client->dev.kobj, &ep92_fs_attrs_group); +} + +static int ep92_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ep92_pdata *ep92; + int ret; +#if IS_ENABLED(CONFIG_DEBUG_FS) + char debugfs_dir_name[32]; +#endif + + ep92 = devm_kzalloc(&client->dev, sizeof(struct ep92_pdata), + GFP_KERNEL); + if (ep92 == NULL) + return -ENOMEM; + + ep92->regmap = devm_regmap_init_i2c(client, &ep92_regmap_config); + if (IS_ERR(ep92->regmap)) { + ret = PTR_ERR(ep92->regmap); + dev_err(&client->dev, + "%s: Failed to allocate regmap for I2C device: %d\n", + __func__, ret); + return ret; + } + + i2c_set_clientdata(client, ep92); + + /* register interrupt handler */ + INIT_WORK(&ep92->read_status_worker, ep92_read_status); + ep92->irq = client->irq; + if (ep92->irq) { + ret = devm_request_threaded_irq(&client->dev, ep92->irq, + NULL, ep92_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "ep92_irq", ep92); + if (ret) { + dev_err(&client->dev, + "%s: Failed to request IRQ %d: %d\n", + __func__, ep92->irq, ret); + ep92->irq = 0; + } + } + /* prepare timer */ + timer_setup(&ep92->timer, ep92_poll_status, 0); + ep92->poll_rem = EP92_POLL_RUNOUT_MSEC; + +#if IS_ENABLED(CONFIG_DEBUG_FS) + /* debugfs interface */ + snprintf(debugfs_dir_name, sizeof(debugfs_dir_name), "%s-%s", + client->name, dev_name(&client->dev)); + ep92->debugfs_dir = debugfs_create_dir(debugfs_dir_name, NULL); + if (!ep92->debugfs_dir) { + dev_dbg(&client->dev, + "%s: Failed to create /sys/kernel/debug/%s for debugfs\n", + __func__, debugfs_dir_name); + return -ENOMEM; + } + ep92->debugfs_file_wo = debugfs_create_file( + "write_reg_val", S_IFREG | 0444, ep92->debugfs_dir, + (void *) ep92, + &debugfs_codec_ops); + if (!ep92->debugfs_file_wo) { + dev_dbg(&client->dev, + "%s: Failed to create /sys/kernel/debug/%s/write_reg_val\n", + __func__, debugfs_dir_name); + return -ENOMEM; + } + ep92->debugfs_file_ro = debugfs_create_file( + "show_reg_dump", S_IFREG | 0444, ep92->debugfs_dir, + (void *) ep92, + &debugfs_codec_ops); + if (!ep92->debugfs_file_ro) { + dev_dbg(&client->dev, + "%s: Failed to create /sys/kernel/debug/%s/show_reg_dump\n", + __func__, debugfs_dir_name); + return -ENOMEM; + } +#endif /* CONFIG_DEBUG_FS */ + + /* register component */ + ret = snd_soc_register_component(&client->dev, &soc_codec_drv_ep92, + ep92_dai, ARRAY_SIZE(ep92_dai)); + if (ret) { + dev_err(&client->dev, "%s %d: Failed to register CODEC: %d\n", + __func__, __LINE__, ret); + goto err_reg; + } + + ret = ep92_sysfs_create(client, ep92); + if (ret) { + dev_err(&client->dev, "%s: sysfs creation failed ret=%d\n", + __func__, ret); + goto err_sysfs; + } + + return 0; + +err_sysfs: + snd_soc_unregister_component(&client->dev); +err_reg: + del_timer(&ep92->timer); + + return ret; +} + +static int ep92_i2c_remove(struct i2c_client *client) +{ + struct ep92_pdata *ep92; + + ep92 = i2c_get_clientdata(client); + if (ep92) { + del_timer(&ep92->timer); + +#if IS_ENABLED(CONFIG_DEBUG_FS) + debugfs_remove_recursive(ep92->debugfs_dir); +#endif + } + snd_soc_unregister_component(&client->dev); + + ep92_sysfs_remove(client, ep92); + + return 0; +} + +static const struct i2c_device_id ep92_i2c_id[] = { + { "ep92-dev", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, ep92_i2c_id); + +static struct i2c_driver ep92_i2c_driver = { + .probe = ep92_i2c_probe, + .remove = ep92_i2c_remove, + .id_table = ep92_i2c_id, + .driver = { + .name = "ep92", + .owner = THIS_MODULE, + .of_match_table = ep92_of_match + }, +}; + +static int __init ep92_codec_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&ep92_i2c_driver); + if (ret) + pr_err("Failed to register EP92 I2C driver: %d\n", ret); + + return ret; +} +module_init(ep92_codec_init); + +static void __exit ep92_codec_exit(void) +{ + i2c_del_driver(&ep92_i2c_driver); +} +module_exit(ep92_codec_exit); + +MODULE_DESCRIPTION("EP92 HDMI repeater/switch driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/ep92/ep92.h b/qcom/opensource/audio-kernel/asoc/codecs/ep92/ep92.h new file mode 100644 index 0000000000..04443d05a5 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/ep92/ep92.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __EP92_H__ +#define __EP92_H__ + +/* EP92 register addresses */ +/* BI = Basic Info */ +#define EP92_BI_VENDOR_ID_0 0x00 +#define EP92_BI_VENDOR_ID_1 0x01 +#define EP92_BI_DEVICE_ID_0 0x02 +#define EP92_BI_DEVICE_ID_1 0x03 +#define EP92_BI_VERSION_NUM 0x04 +#define EP92_BI_VERSION_YEAR 0x05 +#define EP92_BI_VERSION_MONTH 0x06 +#define EP92_BI_VERSION_DATE 0x07 +#define EP92_BI_GENERAL_INFO_0 0x08 +#define EP92_BI_GENERAL_INFO_1 0x09 +#define EP92_BI_GENERAL_INFO_2 0x0A +#define EP92_BI_GENERAL_INFO_3 0x0B +#define EP92_BI_GENERAL_INFO_4 0x0C +#define EP92_BI_GENERAL_INFO_5 0x0D +#define EP92_BI_GENERAL_INFO_6 0x0E + +#define EP92_ISP_MODE_ENTER_ISP 0x0F + +#define EP92_GENERAL_CONTROL_0 0x10 +#define EP92_GENERAL_CONTROL_1 0x11 +#define EP92_GENERAL_CONTROL_2 0x12 +#define EP92_GENERAL_CONTROL_3 0x13 +#define EP92_GENERAL_CONTROL_4 0x14 + +#define EP92_CEC_EVENT_CODE 0x15 +#define EP92_CEC_EVENT_PARAM_1 0x16 +#define EP92_CEC_EVENT_PARAM_2 0x17 +#define EP92_CEC_EVENT_PARAM_3 0x18 +#define EP92_CEC_EVENT_PARAM_4 0x19 +/* RESERVED 0x1A */ +/* ... ... */ +/* RESERVED 0x1F */ +#define EP92_AUDIO_INFO_SYSTEM_STATUS_0 0x20 +#define EP92_AUDIO_INFO_SYSTEM_STATUS_1 0x21 +#define EP92_AUDIO_INFO_AUDIO_STATUS 0x22 +#define EP92_AUDIO_INFO_CHANNEL_STATUS_0 0x23 +#define EP92_AUDIO_INFO_CHANNEL_STATUS_1 0x24 +#define EP92_AUDIO_INFO_CHANNEL_STATUS_2 0x25 +#define EP92_AUDIO_INFO_CHANNEL_STATUS_3 0x26 +#define EP92_AUDIO_INFO_CHANNEL_STATUS_4 0x27 +#define EP92_AUDIO_INFO_ADO_INFO_FRAME_0 0x28 +#define EP92_AUDIO_INFO_ADO_INFO_FRAME_1 0x29 +#define EP92_AUDIO_INFO_ADO_INFO_FRAME_2 0x2A +#define EP92_AUDIO_INFO_ADO_INFO_FRAME_3 0x2B +#define EP92_AUDIO_INFO_ADO_INFO_FRAME_4 0x2C +#define EP92_AUDIO_INFO_ADO_INFO_FRAME_5 0x2D + +#define EP92_OTHER_PACKETS_HDMI_VS_0 0x2E +#define EP92_OTHER_PACKETS_HDMI_VS_1 0x2F +#define EP92_OTHER_PACKETS_ACP_PACKET 0x30 +#define EP92_OTHER_PACKETS_AVI_INFO_FRAME_0 0x31 +#define EP92_OTHER_PACKETS_AVI_INFO_FRAME_1 0x32 +#define EP92_OTHER_PACKETS_AVI_INFO_FRAME_2 0x33 +#define EP92_OTHER_PACKETS_AVI_INFO_FRAME_3 0x34 +#define EP92_OTHER_PACKETS_AVI_INFO_FRAME_4 0x35 +#define EP92_OTHER_PACKETS_GC_PACKET_0 0x36 +#define EP92_OTHER_PACKETS_GC_PACKET_1 0x37 +#define EP92_OTHER_PACKETS_GC_PACKET_2 0x38 + +#define EP92_MAX_REGISTER_ADDR EP92_OTHER_PACKETS_GC_PACKET_2 + +/* shift/masks for register bits + * GI = General Info + * GC = General Control + * AI = Audio Info + */ +#define EP92_GI_ADO_CHF_MASK 0x01 +#define EP92_GI_CEC_ECF_MASK 0x02 +#define EP92_GI_TX_HOT_PLUG_SHIFT 7 +#define EP92_GI_TX_HOT_PLUG_MASK 0x80 +#define EP92_GI_VIDEO_LATENCY_SHIFT 0 +#define EP92_GI_VIDEO_LATENCY_MASK 0xff + +#define EP92_GC_POWER_SHIFT 7 +#define EP92_GC_POWER_MASK 0x80 +#define EP92_GC_AUDIO_PATH_SHIFT 5 +#define EP92_GC_AUDIO_PATH_MASK 0x20 +#define EP92_GC_CEC_MUTE_SHIFT 1 +#define EP92_GC_CEC_MUTE_MASK 0x02 +#define EP92_GC_ARC_EN_SHIFT 0 +#define EP92_GC_ARC_EN_MASK 0x01 +#define EP92_GC_ARC_DIS_SHIFT 6 +#define EP92_GC_ARC_DIS_MASK 0x40 +#define EP92_GC_RX_SEL_SHIFT 0 +#define EP92_GC_RX_SEL_MASK 0x07 +#define EP92_GC_CEC_VOLUME_SHIFT 0 +#define EP92_GC_CEC_VOLUME_MASK 0xff +#define EP92_GC_LINK_ON0_SHIFT 0 +#define EP92_GC_LINK_ON0_MASK 0x01 +#define EP92_GC_LINK_ON1_SHIFT 1 +#define EP92_GC_LINK_ON1_MASK 0x02 +#define EP92_GC_LINK_ON2_SHIFT 2 +#define EP92_GC_LINK_ON2_MASK 0x04 + +#define EP92_AI_MCLK_ON_SHIFT 6 +#define EP92_AI_MCLK_ON_MASK 0x40 +#define EP92_AI_AVMUTE_SHIFT 5 +#define EP92_AI_AVMUTE_MASK 0x20 +#define EP92_AI_LAYOUT_SHIFT 0 +#define EP92_AI_LAYOUT_MASK 0x01 +#define EP92_AI_HBR_ADO_SHIFT 5 +#define EP92_AI_HBR_ADO_MASK 0x20 +#define EP92_AI_STD_ADO_SHIFT 3 +#define EP92_AI_STD_ADO_MASK 0x08 +#define EP92_AI_RATE_MASK 0x07 +#define EP92_AI_NPCM_MASK 0x02 +#define EP92_AI_PREEMPH_SHIFT 3 +#define EP92_AI_PREEMPH_MASK 0x38 +#define EP92_AI_CH_COUNT_MASK 0x07 +#define EP92_AI_CH_ALLOC_MASK 0xff +#define EP92_AI_DSD_ADO_SHIFT 4 +#define EP92_AI_DSD_ADO_MASK 0x10 +#define EP92_AI_DSD_RATE_SHIFT 4 +#define EP92_AI_DSD_RATE_MASK 0x30 + +#define EP92_2CHOICE_MASK 1 +#define EP92_GC_CEC_VOLUME_MIN 0 +#define EP92_GC_CEC_VOLUME_MAX 100 +#define EP92_AI_RATE_MIN 0 +#define EP92_AI_RATE_MAX 768000 +#define EP92_AI_CH_COUNT_MIN 0 +#define EP92_AI_CH_COUNT_MAX 8 +#define EP92_AI_CH_ALLOC_MIN 0 +#define EP92_AI_CH_ALLOC_MAX 0xff + +#define EP92_STATUS_NO_SIGNAL 0 +#define EP92_STATUS_AUDIO_ACTIVE 1 + +/* kcontrol storage indices */ +enum { + EP92_KCTL_POWER = 0, + EP92_KCTL_AUDIO_PATH, + EP92_KCTL_CEC_MUTE, + EP92_KCTL_ARC_EN, + EP92_KCTL_RX_SEL, + EP92_KCTL_CEC_VOLUME, + EP92_KCTL_STATE, + EP92_KCTL_AVMUTE, + EP92_KCTL_LAYOUT, + EP92_KCTL_MODE, + EP92_KCTL_RATE, + EP92_KCTL_CH_COUNT, + EP92_KCTL_CH_ALLOC, + EP92_KCTL_MAX +}; + +int ep92_set_ext_mclk(struct snd_soc_codec *codec, uint32_t mclk_freq); + +#endif /* __EP92_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-bt-swr.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-bt-swr.c new file mode 100644 index 0000000000..c19fa181ed --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-bt-swr.c @@ -0,0 +1,672 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "lpass-bt-swr" + +/* pm runtime auto suspend timer in msecs */ +#define LPASS_BT_SWR_AUTO_SUSPEND_DELAY 100 /* delay in msec */ + +#define LPASS_BT_SWR_STRING_LEN 80 + +#define LPASS_BT_SWR_CHILD_DEVICES_MAX 1 + +/* Hold instance to soundwire platform device */ +struct lpass_bt_swr_ctrl_data { + struct platform_device *lpass_bt_swr_pdev; +}; + +struct lpass_bt_swr_ctrl_platform_data { + void *handle; /* holds parent private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +struct lpass_bt_swr_priv { + struct device *dev; + struct mutex vote_lock; + struct mutex swr_clk_lock; + struct mutex ssr_lock; + bool dev_up; + bool initial_boot; + + struct clk *lpass_core_hw_vote; + struct clk *lpass_audio_hw_vote; + int core_hw_vote_count; + int core_audio_vote_count; + int swr_clk_users; + struct clk *clk_handle; + struct clk *clk_handle_2x; + + struct lpass_bt_swr_ctrl_data *swr_ctrl_data; + struct lpass_bt_swr_ctrl_platform_data swr_plat_data; + struct work_struct lpass_bt_swr_add_child_devices_work; + struct platform_device *pdev_child_devices + [LPASS_BT_SWR_CHILD_DEVICES_MAX]; + int child_count; + + struct device_node *bt_swr_gpio_p; + + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + + struct blocking_notifier_head notifier; + struct device *clk_dev; +}; + +static struct lpass_bt_swr_priv *lpass_bt_priv; + +static void lpass_bt_swr_add_child_devices(struct work_struct *work) +{ + struct lpass_bt_swr_priv *priv; + struct platform_device *pdev; + struct device_node *node; + struct lpass_bt_swr_ctrl_data *swr_ctrl_data = NULL, *temp; + int ret; + u16 count = 0, ctrl_num = 0; + struct lpass_bt_swr_ctrl_platform_data *platdata; + char plat_dev_name[LPASS_BT_SWR_STRING_LEN]; + + priv = container_of(work, struct lpass_bt_swr_priv, + lpass_bt_swr_add_child_devices_work); + if (!priv) { + pr_err("%s: Memory for priv does not exist\n", + __func__); + return; + } + if (!priv->dev || !priv->dev->of_node) { + dev_err(priv->dev, + "%s: DT node for priv does not exist\n", __func__); + return; + } + + platdata = &priv->swr_plat_data; + priv->child_count = 0; + + for_each_available_child_of_node(priv->dev->of_node, node) { + if (strnstr(node->name, "bt_swr_mstr", + strlen("bt_swr_mstr")) != NULL) + strscpy(plat_dev_name, "bt_swr_mstr", + (LPASS_BT_SWR_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + return; + } + pdev->dev.parent = priv->dev; + pdev->dev.of_node = node; + + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct lpass_bt_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(&pdev->dev, "out of memory\n"); + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].lpass_bt_swr_pdev = pdev; + ctrl_num++; + + dev_dbg(&pdev->dev, "%s: Adding soundwire ctrl device(s)\n", + __func__); + priv->swr_ctrl_data = swr_ctrl_data; + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (priv->child_count < LPASS_BT_SWR_CHILD_DEVICES_MAX) + priv->pdev_child_devices[ + priv->child_count++] = pdev; + else + return; + } + + return; +fail_pdev_add: + for (count = 0; count < priv->child_count; count++) + platform_device_put(priv->pdev_child_devices[count]); +} + + +bool lpass_bt_swr_check_core_votes(struct lpass_bt_swr_priv *priv) +{ + bool ret = true; + + mutex_lock(&priv->vote_lock); + if (!priv->dev_up || + (priv->lpass_core_hw_vote && !priv->core_hw_vote_count) || + (priv->lpass_audio_hw_vote && !priv->core_audio_vote_count)) + ret = false; + mutex_unlock(&priv->vote_lock); + + return ret; +} + +static int lpass_bt_swr_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct lpass_bt_swr_priv *priv = (struct lpass_bt_swr_priv *) handle; + + if (priv == NULL) { + pr_err_ratelimited("%s: priv data is NULL\n", __func__); + return -EINVAL; + } + + if (!priv->dev_up && enable) { + pr_err("%s: adsp is not up\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(priv->dev); + if (lpass_bt_swr_check_core_votes(priv)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(priv->dev); + pm_runtime_mark_last_busy(priv->dev); + } + return rc; +} + +static int lpass_bt_swr_mclk_enable( + struct lpass_bt_swr_priv *priv, + bool mclk_enable) +{ + int ret = 0; + + dev_dbg(priv->dev, "%s: mclk_enable = %u\n", + __func__, mclk_enable); + + ret = lpass_bt_swr_core_vote(priv, true); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: request core vote failed\n", + __func__); + goto exit; + } + + if (mclk_enable) { + ret = clk_prepare_enable(priv->clk_handle); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: bt_swr_clk enable failed\n", __func__); + goto error; + } + + if (priv->clk_handle_2x) { + ret = clk_prepare_enable(priv->clk_handle_2x); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: bt_swr_2x_clk enable failed\n", __func__); + clk_disable_unprepare(priv->clk_handle); + } + } + } else { + clk_disable_unprepare(priv->clk_handle); + if (priv->clk_handle_2x) + clk_disable_unprepare(priv->clk_handle_2x); + } + +error: + lpass_bt_swr_core_vote(priv, false); +exit: + return ret; +} + +static int lpass_bt_swrm_clock(void *handle, bool enable) +{ + struct lpass_bt_swr_priv *priv = (struct lpass_bt_swr_priv *) handle; + int ret = 0; + + mutex_lock(&priv->swr_clk_lock); + + dev_dbg(priv->dev, "%s: swrm clock %s\n", + __func__, (enable ? "enable" : "disable")); + if (enable) { + pm_runtime_get_sync(priv->dev); + if (priv->swr_clk_users == 0) { + ret = msm_cdc_pinctrl_select_active_state( + priv->bt_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: bt swr pinctrl enable failed\n", + __func__); + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + goto exit; + } + ret = lpass_bt_swr_mclk_enable(priv, true); + if (ret < 0) { + msm_cdc_pinctrl_select_sleep_state( + priv->bt_swr_gpio_p); + dev_err_ratelimited(priv->dev, + "%s: lpass bt swr request clock enable failed\n", + __func__); + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + goto exit; + } + } + priv->swr_clk_users++; + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + } else { + if (priv->swr_clk_users <= 0) { + dev_err_ratelimited(priv->dev, "%s: clock already disabled\n", + __func__); + priv->swr_clk_users = 0; + goto exit; + } + priv->swr_clk_users--; + if (priv->swr_clk_users == 0) { + lpass_bt_swr_mclk_enable(priv, false); + ret = msm_cdc_pinctrl_select_sleep_state( + priv->bt_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: bt swr pinctrl disable failed\n", + __func__); + goto exit; + } + } + } + dev_dbg(priv->dev, "%s: swrm clock users %d\n", + __func__, priv->swr_clk_users); +exit: + mutex_unlock(&priv->swr_clk_lock); + return ret; +} + +static void lpass_bt_swr_ssr_disable(struct device *dev, void *data) +{ + struct lpass_bt_swr_priv *priv = data; + + if (!priv->dev_up) { + dev_err_ratelimited(priv->dev, + "%s: already disabled\n", __func__); + return; + } + + mutex_lock(&priv->ssr_lock); + priv->dev_up = false; + mutex_unlock(&priv->ssr_lock); + + swrm_wcd_notify(priv->swr_ctrl_data->lpass_bt_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + +} + +static int lpass_bt_swr_ssr_enable(struct device *dev, void *data) +{ + struct lpass_bt_swr_priv *priv = data; + int ret; + + if (priv->initial_boot) { + priv->initial_boot = false; + return 0; + } + + mutex_lock(&priv->ssr_lock); + priv->dev_up = true; + mutex_unlock(&priv->ssr_lock); + + mutex_lock(&priv->swr_clk_lock); + + dev_dbg(priv->dev, "%s: swrm clock users %d\n", + __func__, priv->swr_clk_users); + + lpass_bt_swr_mclk_enable(priv, false); + ret = msm_cdc_pinctrl_select_sleep_state( + priv->bt_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: bt swr pinctrl disable failed\n", + __func__); + } + + if (priv->swr_clk_users > 0) { + lpass_bt_swr_mclk_enable(priv, true); + ret = msm_cdc_pinctrl_select_active_state( + priv->bt_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: bt swr pinctrl enable failed\n", + __func__); + } + } + mutex_unlock(&priv->swr_clk_lock); + + swrm_wcd_notify(priv->swr_ctrl_data->lpass_bt_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + + return 0; +} + +static const struct snd_event_ops lpass_bt_swr_ssr_ops = { + .enable = lpass_bt_swr_ssr_enable, + .disable = lpass_bt_swr_ssr_disable, +}; + +static int lpass_bt_swr_probe(struct platform_device *pdev) +{ + struct lpass_bt_swr_priv *priv; + int ret; + struct clk *lpass_core_hw_vote = NULL; + struct clk *lpass_audio_hw_vote = NULL; + struct clk *bt_swr_clk = NULL; + struct clk *bt_swr_2x_clk = NULL; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_bt_swr_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier); + priv->dev = &pdev->dev; + priv->dev_up = true; + priv->core_hw_vote_count = 0; + priv->core_audio_vote_count = 0; + + dev_set_drvdata(&pdev->dev, priv); + mutex_init(&priv->vote_lock); + mutex_init(&priv->swr_clk_lock); + mutex_init(&priv->ssr_lock); + + priv->bt_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,bt-swr-gpios", 0); + if (!priv->bt_swr_gpio_p) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if (msm_cdc_pinctrl_get_state(priv->bt_swr_gpio_p) < 0) { + dev_info(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + + /* Register LPASS core hw vote */ + lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote"); + if (IS_ERR(lpass_core_hw_vote)) { + ret = PTR_ERR(lpass_core_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_core_hw_vote", ret); + lpass_core_hw_vote = NULL; + ret = 0; + } + priv->lpass_core_hw_vote = lpass_core_hw_vote; + + /* Register LPASS audio hw vote */ + lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); + if (IS_ERR(lpass_audio_hw_vote)) { + ret = PTR_ERR(lpass_audio_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_audio_hw_vote", ret); + lpass_audio_hw_vote = NULL; + ret = 0; + } + priv->lpass_audio_hw_vote = lpass_audio_hw_vote; + + /* Register bt swr clk vote */ + bt_swr_clk = devm_clk_get(&pdev->dev, "bt_swr_mclk_clk"); + if (IS_ERR(bt_swr_clk)) { + ret = PTR_ERR(bt_swr_clk); + dev_err(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "bt_swr_clk", ret); + return -EINVAL; + } + priv->clk_handle = bt_swr_clk; + + /* Register bt swr 2x clk vote */ + bt_swr_2x_clk = devm_clk_get(&pdev->dev, "bt_swr_mclk_clk_2x"); + if (IS_ERR(bt_swr_2x_clk)) { + ret = PTR_ERR(bt_swr_2x_clk); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "bt_swr_2x_clk", ret); + bt_swr_2x_clk = NULL; + ret = 0; + } + priv->clk_handle_2x = bt_swr_2x_clk; + + /* Add soundwire child devices. */ + INIT_WORK(&priv->lpass_bt_swr_add_child_devices_work, + lpass_bt_swr_add_child_devices); + + priv->swr_plat_data.handle = (void *)priv; + priv->swr_plat_data.read = NULL; + priv->swr_plat_data.write = NULL; + priv->swr_plat_data.bulk_write = NULL; + priv->swr_plat_data.clk = lpass_bt_swrm_clock; + priv->swr_plat_data.core_vote = lpass_bt_swr_core_vote; + priv->swr_plat_data.handle_irq = NULL; + + lpass_bt_priv = priv; + + pm_runtime_set_autosuspend_delay(&pdev->dev, LPASS_BT_SWR_AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + + /* call scheduler to add child devices. */ + schedule_work(&priv->lpass_bt_swr_add_child_devices_work); + + priv->initial_boot = true; + ret = snd_event_client_register(priv->dev, &lpass_bt_swr_ssr_ops, priv); + if (!ret) { + snd_event_notify(priv->dev, SND_EVENT_UP); + dev_err(&pdev->dev, "%s: Registered SSR ops\n", __func__); + } else { + dev_err(&pdev->dev, + "%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + } + + return 0; +} + +static int lpass_bt_swr_remove(struct platform_device *pdev) +{ + struct lpass_bt_swr_priv *priv = dev_get_drvdata(&pdev->dev); + + if (!priv) + return -EINVAL; + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + of_platform_depopulate(&pdev->dev); + mutex_destroy(&priv->vote_lock); + mutex_destroy(&priv->swr_clk_lock); + mutex_destroy(&priv->ssr_lock); + + return 0; +} + +#ifdef CONFIG_PM +int lpass_bt_swr_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpass_bt_swr_priv *priv = platform_get_drvdata(pdev); + int ret = 0; + + dev_dbg(dev, "%s, enter\n", __func__); + mutex_lock(&priv->vote_lock); + if (priv->lpass_core_hw_vote == NULL) { + dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__); + goto audio_vote; + } + + if (priv->core_hw_vote_count == 0) { + ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_core_hw_vote, dev); + if (ret < 0) { + dev_err_ratelimited(dev, "%s:lpass core hw enable failed\n", + __func__); + goto audio_vote; + } + } + priv->core_hw_vote_count++; + +audio_vote: + if (priv->lpass_audio_hw_vote == NULL) { + dev_dbg(dev, "%s: Invalid lpass audio hw node\n", __func__); + goto done; + } + + if (priv->core_audio_vote_count == 0) { + ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_audio_hw_vote, dev); + if (ret < 0) { + dev_err_ratelimited(dev, "%s:lpass audio hw enable failed\n", + __func__); + goto done; + } + } + priv->core_audio_vote_count++; + +done: + mutex_unlock(&priv->vote_lock); + dev_dbg(dev, "%s, leave, hw_vote %d, audio_vote %d\n", __func__, + priv->core_hw_vote_count, priv->core_audio_vote_count); + pm_runtime_set_autosuspend_delay(priv->dev, LPASS_BT_SWR_AUTO_SUSPEND_DELAY); + + return 0; +} + +int lpass_bt_swr_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpass_bt_swr_priv *priv = platform_get_drvdata(pdev); + + dev_dbg(dev, "%s, enter\n", __func__); + mutex_lock(&priv->vote_lock); + if (priv->lpass_core_hw_vote != NULL) { + if (--priv->core_hw_vote_count == 0) + digital_cdc_rsc_mgr_hw_vote_disable( + priv->lpass_core_hw_vote, dev); + if (priv->core_hw_vote_count < 0) + priv->core_hw_vote_count = 0; + } else { + dev_dbg(dev, "%s: Invalid lpass core hw node\n", + __func__); + } + + if (priv->lpass_audio_hw_vote != NULL) { + if (--priv->core_audio_vote_count == 0) + digital_cdc_rsc_mgr_hw_vote_disable( + priv->lpass_audio_hw_vote, dev); + if (priv->core_audio_vote_count < 0) + priv->core_audio_vote_count = 0; + } else { + dev_dbg(dev, "%s: Invalid lpass audio hw node\n", + __func__); + } + + mutex_unlock(&priv->vote_lock); + dev_dbg(dev, "%s, leave, hw_vote %d, audio_vote %d\n", __func__, + priv->core_hw_vote_count, priv->core_audio_vote_count); + + return 0; +} +#endif /* CONFIG_PM */ + +static const struct of_device_id lpass_bt_swr_dt_match[] = { + {.compatible = "qcom,lpass-bt-swr"}, + {} +}; +MODULE_DEVICE_TABLE(of, lpass_bt_swr_dt_match); + +static const struct dev_pm_ops lpass_bt_swr_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + lpass_bt_swr_runtime_suspend, + lpass_bt_swr_runtime_resume, + NULL + ) +}; + +static struct platform_driver lpass_bt_swr_drv = { + .driver = { + .name = "lpass-bt-swr", + .pm = &lpass_bt_swr_pm_ops, + .of_match_table = lpass_bt_swr_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_bt_swr_probe, + .remove = lpass_bt_swr_remove, +}; + +static int lpass_bt_swr_drv_init(void) +{ + return platform_driver_register(&lpass_bt_swr_drv); +} + +static void lpass_bt_swr_drv_exit(void) +{ + platform_driver_unregister(&lpass_bt_swr_drv); +} + +static int __init lpass_bt_swr_init(void) +{ + lpass_bt_swr_drv_init(); + return 0; +} +module_init(lpass_bt_swr_init); + +static void __exit lpass_bt_swr_exit(void) +{ + lpass_bt_swr_drv_exit(); +} +module_exit(lpass_bt_swr_exit); + +MODULE_SOFTDEP("pre: bt_fm_swr"); +MODULE_DESCRIPTION("LPASS BT SWR driver"); +MODULE_LICENSE("GPL"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Kbuild new file mode 100644 index 0000000000..8989119a03 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Kbuild @@ -0,0 +1,183 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_TRINKET), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_KALAMA), y) + include $(AUDIO_ROOT)/config/kalamaauto.conf + INCS += -include $(AUDIO_ROOT)/config/kalamaautoconf.h + endif + ifeq ($(CONFIG_ARCH_PINEAPPLE), y) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.h + endif + ifeq ($(CONFIG_ARCH_PITTI), y) + include $(AUDIO_ROOT)/config/pittiauto.conf + INCS += -include $(AUDIO_ROOT)/config/pittiautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_BENGAL), y) + include $(AUDIO_ROOT)/config/bengalauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h + endif + ifeq ($(CONFIG_ARCH_QCS405), y) + include $(AUDIO_ROOT)/config/qcs405auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/qcs405autoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ LPASS_CDC ############ + +# for LPASS_CDC Codec +ifdef CONFIG_SND_SOC_LPASS_CDC + LPASS_CDC_OBJS += lpass-cdc.o + LPASS_CDC_OBJS += lpass-cdc-comp.o + LPASS_CDC_OBJS += lpass-cdc-utils.o + LPASS_CDC_OBJS += lpass-cdc-regmap.o + LPASS_CDC_OBJS += lpass-cdc-tables.o + LPASS_CDC_OBJS += lpass-cdc-clk-rsc.o +endif + +ifdef CONFIG_LPASS_CDC_WSA2_MACRO + WSA2_OBJS += lpass-cdc-wsa2-macro.o +endif + +ifdef CONFIG_LPASS_CDC_WSA_MACRO + WSA_OBJS += lpass-cdc-wsa-macro.o +endif + +ifdef CONFIG_LPASS_CDC_VA_MACRO + VA_OBJS += lpass-cdc-va-macro.o +endif + +ifdef CONFIG_LPASS_CDC_TX_MACRO + TX_OBJS += lpass-cdc-tx-macro.o +endif + +ifdef CONFIG_LPASS_CDC_RX_MACRO + RX_OBJS += lpass-cdc-rx-macro.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_LPASS_CDC) += lpass_cdc_dlkm.o +lpass_cdc_dlkm-y := $(LPASS_CDC_OBJS) + +obj-$(CONFIG_LPASS_CDC_WSA2_MACRO) += lpass_cdc_wsa2_macro_dlkm.o +lpass_cdc_wsa2_macro_dlkm-y := $(WSA2_OBJS) + +obj-$(CONFIG_LPASS_CDC_WSA_MACRO) += lpass_cdc_wsa_macro_dlkm.o +lpass_cdc_wsa_macro_dlkm-y := $(WSA_OBJS) + +obj-$(CONFIG_LPASS_CDC_VA_MACRO) += lpass_cdc_va_macro_dlkm.o +lpass_cdc_va_macro_dlkm-y := $(VA_OBJS) + +obj-$(CONFIG_LPASS_CDC_TX_MACRO) += lpass_cdc_tx_macro_dlkm.o +lpass_cdc_tx_macro_dlkm-y := $(TX_OBJS) + +obj-$(CONFIG_LPASS_CDC_RX_MACRO) += lpass_cdc_rx_macro_dlkm.o +lpass_cdc_rx_macro_dlkm-y := $(RX_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Makefile b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/internal.h b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/internal.h new file mode 100644 index 0000000000..91c6e7136f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/internal.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _LPASS_CDC_INTERNAL_H +#define _LPASS_CDC_INTERNAL_H + +#include "lpass-cdc-registers.h" + +#define LPASS_CDC_CHILD_DEVICES_MAX 6 + +/* from lpass_cdc to WCD events */ +enum { + LPASS_CDC_WCD_EVT_TX_CH_HOLD_CLEAR = 1, + LPASS_CDC_WCD_EVT_PA_OFF_PRE_SSR, + LPASS_CDC_WCD_EVT_SSR_DOWN, + LPASS_CDC_WCD_EVT_SSR_UP, + LPASS_CDC_WCD_EVT_PA_ON_POST_FSCLK, + LPASS_CDC_WCD_EVT_PA_ON_POST_FSCLK_ADIE_LB, + LPASS_CDC_WCD_EVT_CLK_NOTIFY, +}; + +enum { + REG_NO_ACCESS, + RD_REG, + WR_REG, + RD_WR_REG +}; + +/* from WCD to lpass_cdc events */ +enum { + WCD_LPASS_CDC_EVT_RX_MUTE = 1, /* for RX mute/unmute */ + WCD_LPASS_CDC_EVT_IMPED_TRUE, /* for imped true */ + WCD_LPASS_CDC_EVT_IMPED_FALSE, /* for imped false */ + WCD_LPASS_CDC_EVT_RX_COMPANDER_SOFT_RST, + WCD_LPASS_CDC_EVT_BCS_CLK_OFF, + WCD_LPASS_CDC_EVT_RX_PA_GAIN_UPDATE, + WCD_LPASS_CDC_EVT_HPHL_HD2_ENABLE, /* to enable hd2 config for hphl */ + WCD_LPASS_CDC_EVT_HPHR_HD2_ENABLE, /* to enable hd2 config for hphr */ +}; + +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); +}; + +struct lpass_cdc_priv { + struct device *dev; + struct snd_soc_component *component; + struct regmap *regmap; + struct mutex macro_lock; + struct mutex io_lock; + struct mutex clk_lock; + struct mutex vote_lock; + bool va_without_decimation; + bool macros_supported[MAX_MACRO]; + bool dev_up; + bool pre_dev_up; + bool initial_boot; + struct macro_ops macro_params[MAX_MACRO]; + struct snd_soc_dai_driver *lpass_cdc_dais; + u16 num_dais; + u16 num_macros_registered; + u16 num_macros; + u16 current_mclk_mux_macro[MAX_MACRO]; + struct work_struct lpass_cdc_add_child_devices_work; + u32 version; + struct clk *lpass_core_hw_vote; + struct clk *lpass_audio_hw_vote; + int core_hw_vote_count; + int core_audio_vote_count; + int core_clk_vote_count; + + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + + int (*read_dev)(struct lpass_cdc_priv *priv, + u16 macro_id, u16 reg, u8 *val); + int (*write_dev)(struct lpass_cdc_priv *priv, + u16 macro_id, u16 reg, u8 val); + struct platform_device *pdev_child_devices + [LPASS_CDC_CHILD_DEVICES_MAX]; + u16 child_count; + struct wcd_ctrl_platform_data plat_data; + struct device *wcd_dev; + struct blocking_notifier_head notifier; + struct device *clk_dev; + rsc_clk_cb_t rsc_clk_cb; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + s32 dmic_6_7_clk_cnt; + u8 dmic_0_1_clk_div; + u8 dmic_2_3_clk_div; + u8 dmic_4_5_clk_div; + u8 dmic_6_7_clk_div; +}; + +struct regmap *lpass_cdc_regmap_init(struct device *dev, + const struct regmap_config *config); +int lpass_cdc_get_macro_id(bool va_no_dec_flag, u16 reg); + +extern const struct regmap_config lpass_cdc_regmap_config; +extern u8 *lpass_cdc_reg_access[MAX_MACRO]; +extern const u16 macro_id_base_offset[MAX_MACRO]; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-clk-rsc.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-clk-rsc.c new file mode 100644 index 0000000000..4b2f8cb880 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-clk-rsc.c @@ -0,0 +1,785 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpass-cdc.h" +#include "lpass-cdc-clk-rsc.h" + +#define DRV_NAME "lpass-cdc-clk-rsc" +#define LPASS_CDC_CLK_NAME_LENGTH 30 +#define NPL_CLK_OFFSET (TX_NPL_CLK - TX_CORE_CLK) + +static char clk_src_name[MAX_CLK][LPASS_CDC_CLK_NAME_LENGTH] = { + "tx_core_clk", + "rx_core_clk", + "wsa_core_clk", + "va_core_clk", + "wsa2_core_clk", + "rx_tx_core_clk", + "wsa_tx_core_clk", + "wsa2_tx_core_clk", + "tx_npl_clk", + "rx_npl_clk", + "wsa_npl_clk", + "va_npl_clk", +}; + +struct lpass_cdc_clk_rsc { + struct device *dev; + struct mutex rsc_clk_lock; + struct mutex fs_gen_lock; + struct clk *clk[MAX_CLK]; + int clk_cnt[MAX_CLK]; + int reg_seq_en_cnt; + int va_tx_clk_cnt; + bool dev_up; + bool dev_up_gfmux; + u32 num_fs_reg; + u32 *fs_gen_seq; + int default_clk_id[MAX_CLK]; + struct regmap *regmap; + char __iomem *rx_clk_muxsel; + char __iomem *wsa_clk_muxsel; + char __iomem *va_clk_muxsel; +}; + +static int lpass_cdc_clk_rsc_cb(struct device *dev, u16 event) +{ + struct lpass_cdc_clk_rsc *priv; + + if (!dev) { + pr_err("%s: Invalid device pointer\n", + __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(dev); + if (!priv) { + pr_err("%s: Invalid clk rsc priviate data\n", + __func__); + return -EINVAL; + } + + mutex_lock(&priv->rsc_clk_lock); + if (event == LPASS_CDC_MACRO_EVT_SSR_UP) { + priv->dev_up = true; + } else if (event == LPASS_CDC_MACRO_EVT_SSR_DOWN) { + priv->dev_up = false; + priv->dev_up_gfmux = false; + } else if (event == LPASS_CDC_MACRO_EVT_SSR_GFMUX_UP) { + priv->dev_up_gfmux = true; + } + mutex_unlock(&priv->rsc_clk_lock); + + return 0; +} + +static char __iomem *lpass_cdc_clk_rsc_get_clk_muxsel(struct lpass_cdc_clk_rsc *priv, + int clk_id) +{ + switch (clk_id) { + case RX_CORE_CLK: + return priv->rx_clk_muxsel; + case WSA_CORE_CLK: + case WSA2_CORE_CLK: + return priv->wsa_clk_muxsel; + case VA_CORE_CLK: + return priv->va_clk_muxsel; + case TX_CORE_CLK: + case RX_TX_CORE_CLK: + case WSA_TX_CORE_CLK: + case WSA2_TX_CORE_CLK: + default: + dev_err_ratelimited(priv->dev, "%s: Invalid case\n", __func__); + break; + } + + return NULL; +} + +int lpass_cdc_rsc_clk_reset(struct device *dev, int clk_id) +{ + struct device *clk_dev = NULL; + struct lpass_cdc_clk_rsc *priv = NULL; + int count = 0; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return -EINVAL; + } + +#ifdef CONFIG_BOLERO_VER_2P1 + if (clk_id < 0 || clk_id >= MAX_CLK - NPL_CLK_OFFSET) { +#else + if (clk_id < 0 || clk_id >= MAX_CLK) { +#endif + pr_err("%s: Invalid clk_id: %d\n", + __func__, clk_id); + return -EINVAL; + } + + clk_dev = lpass_cdc_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk priviate data\n", __func__); + return -EINVAL; + } + mutex_lock(&priv->rsc_clk_lock); + while (__clk_is_enabled(priv->clk[clk_id])) { +#ifdef CONFIG_BOLERO_VER_2P1 + clk_disable_unprepare(priv->clk[clk_id + NPL_CLK_OFFSET]); +#endif + clk_disable_unprepare(priv->clk[clk_id]); + count++; + } + dev_dbg(priv->dev, + "%s: clock reset after ssr, count %d\n", __func__, count); + + while (count--) { + clk_prepare_enable(priv->clk[clk_id]); +#ifdef CONFIG_BOLERO_VER_2P1 + clk_prepare_enable(priv->clk[clk_id + NPL_CLK_OFFSET]); +#endif + } + mutex_unlock(&priv->rsc_clk_lock); + return 0; +} +EXPORT_SYMBOL(lpass_cdc_rsc_clk_reset); + +void lpass_cdc_clk_rsc_enable_all_clocks(struct device *dev, bool enable) +{ + struct device *clk_dev = NULL; + struct lpass_cdc_clk_rsc *priv = NULL; + int i = 0; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + + clk_dev = lpass_cdc_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return; + } + + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk private data\n", __func__); + return; + } + mutex_lock(&priv->rsc_clk_lock); +#ifdef CONFIG_BOLERO_VER_2P1 + for (i = 0; i < MAX_CLK - NPL_CLK_OFFSET; i++) { +#else + for (i = 0; i < MAX_CLK; i++) { +#endif + if (enable) { + if (priv->clk[i]) + clk_prepare_enable(priv->clk[i]); +#ifdef CONFIG_BOLERO_VER_2P1 + if (priv->clk[i + NPL_CLK_OFFSET]) + clk_prepare_enable( + priv->clk[i + NPL_CLK_OFFSET]); +#endif + } else { +#ifdef CONFIG_BOLERO_VER_2P1 + if (priv->clk[i + NPL_CLK_OFFSET] && + __clk_is_enabled(priv->clk[i + NPL_CLK_OFFSET])) + clk_disable_unprepare( + priv->clk[i + NPL_CLK_OFFSET]); +#endif + if (priv->clk[i] && __clk_is_enabled(priv->clk[i])) + clk_disable_unprepare(priv->clk[i]); + } + } + mutex_unlock(&priv->rsc_clk_lock); + return; +} +EXPORT_SYMBOL(lpass_cdc_clk_rsc_enable_all_clocks); + +static int lpass_cdc_clk_rsc_mux0_clk_request(struct lpass_cdc_clk_rsc *priv, + int clk_id, + bool enable) +{ + int ret = 0; + + if (enable) { + /* Enable Requested Core clk */ + if (priv->clk_cnt[clk_id] == 0) { + ret = clk_prepare_enable(priv->clk[clk_id]); + if (ret < 0) { + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, clk_id); + goto done; + } +#ifdef CONFIG_BOLERO_VER_2P1 + if (priv->clk[clk_id + NPL_CLK_OFFSET]) { + ret = clk_prepare_enable( + priv->clk[clk_id + NPL_CLK_OFFSET]); + if (ret < 0) { + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, clk_id + NPL_CLK_OFFSET); + goto err; + } + } +#endif + } + priv->clk_cnt[clk_id]++; + } else { + if (priv->clk_cnt[clk_id] <= 0) { + dev_err_ratelimited(priv->dev, "%s: clk_id: %d is already disabled\n", + __func__, clk_id); + priv->clk_cnt[clk_id] = 0; + goto done; + } + priv->clk_cnt[clk_id]--; + if (priv->clk_cnt[clk_id] == 0) { +#ifdef CONFIG_BOLERO_VER_2P1 + if (priv->clk[clk_id + NPL_CLK_OFFSET]) + clk_disable_unprepare( + priv->clk[clk_id + NPL_CLK_OFFSET]); +#endif + clk_disable_unprepare(priv->clk[clk_id]); + } + } +return ret; +#ifdef CONFIG_BOLERO_VER_2P1 +err: + clk_disable_unprepare(priv->clk[clk_id]); +#endif +done: + return ret; +} + +static int lpass_cdc_clk_rsc_mux1_clk_request(struct lpass_cdc_clk_rsc *priv, + int clk_id, + bool enable) +{ + char __iomem *clk_muxsel = NULL; + int ret = 0; + int default_clk_id = priv->default_clk_id[clk_id]; + u32 muxsel = 0; + + clk_muxsel = lpass_cdc_clk_rsc_get_clk_muxsel(priv, clk_id); + if (!clk_muxsel) { + ret = -EINVAL; + goto done; + } + + if (enable) { + if (priv->clk_cnt[clk_id] == 0) { + if (clk_id != VA_CORE_CLK) { + ret = lpass_cdc_clk_rsc_mux0_clk_request(priv, + default_clk_id, + true); + if (ret < 0) + goto done; + } + + ret = clk_prepare_enable(priv->clk[clk_id]); + if (ret < 0) { + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, clk_id); + goto err_clk; + } +#ifdef CONFIG_BOLERO_VER_2P1 + if (priv->clk[clk_id + NPL_CLK_OFFSET]) { + ret = clk_prepare_enable( + priv->clk[clk_id + NPL_CLK_OFFSET]); + if (ret < 0) { + dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n", + __func__, clk_id + NPL_CLK_OFFSET); + goto err_npl_clk; + } + } +#endif + /* + * Temp SW workaround to address a glitch issue of + * VA GFMux instance responsible for switching from + * TX MCLK to VA MCLK. This configuration would be taken + * care in DSP itself + */ + if (clk_id != VA_CORE_CLK) { + if (priv->dev_up_gfmux) { + iowrite32(0x1, clk_muxsel); + muxsel = ioread32(clk_muxsel); + } + lpass_cdc_clk_rsc_mux0_clk_request(priv, default_clk_id, + false); + } + } + priv->clk_cnt[clk_id]++; + } else { + if (priv->clk_cnt[clk_id] <= 0) { + dev_err_ratelimited(priv->dev, "%s: clk_id: %d is already disabled\n", + __func__, clk_id); + priv->clk_cnt[clk_id] = 0; + goto done; + } + priv->clk_cnt[clk_id]--; + if (priv->clk_cnt[clk_id] == 0) { + /* + * Temp SW workaround to address a glitch issue + * of VA GFMux instance responsible for + * switching from TX MCLK to VA MCLK. + * This configuration would be taken + * care in DSP itself. + */ + if (clk_id != VA_CORE_CLK) { + ret = lpass_cdc_clk_rsc_mux0_clk_request(priv, + default_clk_id, true); + if (!ret && priv->dev_up_gfmux) { + iowrite32(0x0, clk_muxsel); + muxsel = ioread32(clk_muxsel); + } + } +#ifdef CONFIG_BOLERO_VER_2P1 + if (priv->clk[clk_id + NPL_CLK_OFFSET]) + clk_disable_unprepare(priv->clk[clk_id + NPL_CLK_OFFSET]); +#endif + clk_disable_unprepare(priv->clk[clk_id]); + if (clk_id != VA_CORE_CLK && !ret) + lpass_cdc_clk_rsc_mux0_clk_request(priv, + default_clk_id, false); + } + } + return ret; +#ifdef CONFIG_BOLERO_VER_2P1 +err_npl_clk: + clk_disable_unprepare(priv->clk[clk_id]); +#endif +err_clk: + if (clk_id != VA_CORE_CLK) + lpass_cdc_clk_rsc_mux0_clk_request(priv, default_clk_id, false); +done: + return ret; +} + +static int lpass_cdc_clk_rsc_check_and_update_va_clk(struct lpass_cdc_clk_rsc *priv, + bool mux_switch, + int clk_id, + bool enable) +{ + int ret = 0; + + if (enable) { + if (clk_id == VA_CORE_CLK && mux_switch) { + /* + * Handle the following usecase scenarios during enable + * 1. VA only, Active clk is VA_CORE_CLK + * 2. record -> record + VA, Active clk is TX_CORE_CLK + */ + if (priv->clk_cnt[TX_CORE_CLK] == 0) { + ret = lpass_cdc_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, enable); + if (ret < 0) + goto err; + } else { + ret = lpass_cdc_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, enable); + if (ret < 0) + goto err; + priv->va_tx_clk_cnt++; + } + } else if ((priv->clk_cnt[TX_CORE_CLK] > 0) && + (priv->clk_cnt[VA_CORE_CLK] > 0)) { + /* + * Handle following concurrency scenario during enable + * 1. VA-> Record+VA, Increment TX CLK and Disable VA + * 2. VA-> Playback+VA, Increment TX CLK and Disable VA + */ + while (priv->clk_cnt[VA_CORE_CLK] > 0) { + ret = lpass_cdc_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, true); + if (ret < 0) + goto err; + + lpass_cdc_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, false); + priv->va_tx_clk_cnt++; + } + } + } else { + if (clk_id == VA_CORE_CLK && mux_switch) { + /* + * Handle the following usecase scenarios during disable + * 1. VA only, disable VA_CORE_CLK + * 2. Record + VA -> Record, decrement TX CLK count + */ + if (priv->clk_cnt[VA_CORE_CLK]) { + lpass_cdc_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, enable); + } else if (priv->va_tx_clk_cnt) { + lpass_cdc_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, enable); + priv->va_tx_clk_cnt--; + } + } else if (priv->va_tx_clk_cnt == priv->clk_cnt[TX_CORE_CLK]) { + /* + * Handle the following usecase scenarios during disable + * Record+VA-> VA: enable VA CLK, decrement TX CLK count + */ + while (priv->va_tx_clk_cnt) { + ret = lpass_cdc_clk_rsc_mux1_clk_request(priv, + VA_CORE_CLK, true); + if (ret < 0) + goto err; + + lpass_cdc_clk_rsc_mux0_clk_request(priv, + TX_CORE_CLK, false); + priv->va_tx_clk_cnt--; + } + } + } + +err: + return ret; +} + +/** + * lpass_cdc_clk_rsc_fs_gen_request - request to enable/disable fs generation + * sequence + * + * @dev: Macro device pointer + * @enable: enable or disable flag + */ +void lpass_cdc_clk_rsc_fs_gen_request(struct device *dev, bool enable) +{ + int i; + struct regmap *regmap; + struct device *clk_dev = NULL; + struct lpass_cdc_clk_rsc *priv = NULL; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + clk_dev = lpass_cdc_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return; + } + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk priviate data\n", __func__); + return; + } + regmap = dev_get_regmap(priv->dev->parent, NULL); + if (!regmap) { + pr_err("%s: regmap is null\n", __func__); + return; + } + mutex_lock(&priv->fs_gen_lock); + if (enable) { + if (priv->reg_seq_en_cnt++ == 0) { + for (i = 0; i < (priv->num_fs_reg * 3); i += 3) { + dev_dbg(priv->dev, "%s: Register: %d, mask: %d, value: %d\n", + __func__, priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1], + priv->fs_gen_seq[i + 2]); + regmap_update_bits(regmap, + priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1], + priv->fs_gen_seq[i + 2]); + } + } + } else { + if (priv->reg_seq_en_cnt <= 0) { + dev_err_ratelimited(priv->dev, "%s: req_seq_cnt: %d is already disabled\n", + __func__, priv->reg_seq_en_cnt); + priv->reg_seq_en_cnt = 0; + mutex_unlock(&priv->fs_gen_lock); + return; + } + if (--priv->reg_seq_en_cnt == 0) { + for (i = ((priv->num_fs_reg - 1) * 3); i >= 0; i -= 3) { + dev_dbg(priv->dev, "%s: Register: %d, mask: %d\n", + __func__, priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1]); + regmap_update_bits(regmap, priv->fs_gen_seq[i], + priv->fs_gen_seq[i + 1], 0x0); + } + } + } + mutex_unlock(&priv->fs_gen_lock); +} +EXPORT_SYMBOL(lpass_cdc_clk_rsc_fs_gen_request); + +/** + * lpass_cdc_clk_rsc_request_clock - request for clock to + * enable/disable + * + * @dev: Macro device pointer. + * @default_clk_id: mux0 Core clock ID input. + * @clk_id_req: Core clock ID requested to enable/disable + * @enable: enable or disable clock flag + * + * Returns 0 on success or -EINVAL on error. + */ +int lpass_cdc_clk_rsc_request_clock(struct device *dev, + int default_clk_id, + int clk_id_req, + bool enable) +{ + int ret = 0; + struct device *clk_dev = NULL; + struct lpass_cdc_clk_rsc *priv = NULL; + bool mux_switch = false; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return -EINVAL; + } + if ((clk_id_req < 0 || clk_id_req >= MAX_CLK) && + (default_clk_id < 0 || default_clk_id >= MAX_CLK)) { + pr_err("%s: Invalid clk_id_req: %d or default_clk_id: %d\n", + __func__, clk_id_req, default_clk_id); + return -EINVAL; + } + clk_dev = lpass_cdc_get_rsc_clk_device_ptr(dev->parent); + if (!clk_dev) { + pr_err("%s: Invalid rsc clk device\n", __func__); + return -EINVAL; + } + priv = dev_get_drvdata(clk_dev); + if (!priv) { + pr_err("%s: Invalid rsc clk priviate data\n", __func__); + return -EINVAL; + } + + mutex_lock(&priv->rsc_clk_lock); + if (!priv->dev_up && enable) { + dev_err_ratelimited(priv->dev, "%s: SSR is in progress..\n", + __func__); + ret = -EINVAL; + goto err; + } + priv->default_clk_id[clk_id_req] = default_clk_id; + if (default_clk_id != clk_id_req) + mux_switch = true; + + if (mux_switch) { + if (clk_id_req != VA_CORE_CLK) { + ret = lpass_cdc_clk_rsc_mux1_clk_request(priv, clk_id_req, + enable); + if (ret < 0) + goto err; + } + } else { + ret = lpass_cdc_clk_rsc_mux0_clk_request(priv, clk_id_req, enable); + if (ret < 0) + goto err; + } + + ret = lpass_cdc_clk_rsc_check_and_update_va_clk(priv, mux_switch, + clk_id_req, + enable); + if (ret < 0) + goto err; + + dev_dbg(priv->dev, "%s: clk_cnt: %d for requested clk: %d, enable: %d\n", + __func__, priv->clk_cnt[clk_id_req], clk_id_req, + enable); + + mutex_unlock(&priv->rsc_clk_lock); + + return 0; + +err: + mutex_unlock(&priv->rsc_clk_lock); + return ret; +} +EXPORT_SYMBOL(lpass_cdc_clk_rsc_request_clock); + + +static int lpass_cdc_clk_rsc_probe(struct platform_device *pdev) +{ + int ret = 0, fs_gen_size, i, j; + const char **clk_name_array; + int clk_cnt; + struct clk *clk; + struct lpass_cdc_clk_rsc *priv = NULL; + u32 muxsel = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_clk_rsc), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Get clk fs gen sequence from device tree */ + if (!of_find_property(pdev->dev.of_node, "qcom,fs-gen-sequence", + &fs_gen_size)) { + dev_err(&pdev->dev, "%s: unable to find qcom,fs-gen-sequence property\n", + __func__); + ret = -EINVAL; + goto err; + } + priv->num_fs_reg = fs_gen_size/(3 * sizeof(u32)); + priv->fs_gen_seq = devm_kzalloc(&pdev->dev, fs_gen_size, GFP_KERNEL); + if (!priv->fs_gen_seq) { + ret = -ENOMEM; + goto err; + } + dev_dbg(&pdev->dev, "%s: num_fs_reg %d\n", __func__, priv->num_fs_reg); + /* Parse fs-gen-sequence */ + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,fs-gen-sequence", + priv->fs_gen_seq, + priv->num_fs_reg * 3); + if (ret < 0) { + dev_err(&pdev->dev, "%s: unable to parse fs-gen-sequence, ret = %d\n", + __func__, ret); + goto err; + } + + /* Get clk details from device tree */ + clk_cnt = of_property_count_strings(pdev->dev.of_node, "clock-names"); + if (clk_cnt <= 0 || clk_cnt > MAX_CLK) { + dev_err(&pdev->dev, "%s: Invalid number of clocks %d", + __func__, clk_cnt); + ret = -EINVAL; + goto err; + } + clk_name_array = devm_kzalloc(&pdev->dev, clk_cnt * sizeof(char *), + GFP_KERNEL); + if (!clk_name_array) { + ret = -ENOMEM; + goto err; + } + + ret = of_property_read_string_array(pdev->dev.of_node, "clock-names", + clk_name_array, clk_cnt); + + for (i = 0; i < MAX_CLK; i++) { + priv->clk[i] = NULL; + for (j = 0; j < clk_cnt; j++) { + if (!strcmp(clk_src_name[i], clk_name_array[j])) { + clk = devm_clk_get(&pdev->dev, clk_src_name[i]); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(&pdev->dev, "%s: clk get failed for %s with ret %d\n", + __func__, clk_src_name[i], ret); + goto err; + } + priv->clk[i] = clk; + dev_dbg(&pdev->dev, "%s: clk get success for clk name %s\n", + __func__, clk_src_name[i]); + break; + } + } + } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,rx_mclk_mode_muxsel", &muxsel); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find qcom,rx_mclk_mode_muxsel entry in dt\n", + __func__); + } else { + priv->rx_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!priv->rx_clk_muxsel) { + dev_err(&pdev->dev, "%s: ioremap failed for rx muxsel\n", + __func__); + return -ENOMEM; + } + } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,wsa_mclk_mode_muxsel", &muxsel); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find qcom,wsa_mclk_mode_muxsel entry in dt\n", + __func__); + } else { + priv->wsa_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!priv->wsa_clk_muxsel) { + dev_err(&pdev->dev, "%s: ioremap failed for wsa muxsel\n", + __func__); + return -ENOMEM; + } + } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,va_mclk_mode_muxsel", &muxsel); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find qcom,va_mclk_mode_muxsel entry in dt\n", + __func__); + } else { + priv->va_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!priv->va_clk_muxsel) { + dev_err(&pdev->dev, "%s: ioremap failed for va muxsel\n", + __func__); + return -ENOMEM; + } + } + + ret = lpass_cdc_register_res_clk(&pdev->dev, lpass_cdc_clk_rsc_cb); + if (ret < 0) { + dev_err(&pdev->dev, "%s: Failed to register cb %d", + __func__, ret); + goto err; + } + priv->dev = &pdev->dev; + priv->dev_up = true; + priv->dev_up_gfmux = true; + mutex_init(&priv->rsc_clk_lock); + mutex_init(&priv->fs_gen_lock); + dev_set_drvdata(&pdev->dev, priv); + +err: + return ret; +} + +static int lpass_cdc_clk_rsc_remove(struct platform_device *pdev) +{ + struct lpass_cdc_clk_rsc *priv = dev_get_drvdata(&pdev->dev); + + lpass_cdc_unregister_res_clk(&pdev->dev); + of_platform_depopulate(&pdev->dev); + if (!priv) + return -EINVAL; + mutex_destroy(&priv->rsc_clk_lock); + mutex_destroy(&priv->fs_gen_lock); + + return 0; +} + +static const struct of_device_id lpass_cdc_clk_rsc_dt_match[] = { + {.compatible = "qcom,lpass-cdc-clk-rsc-mngr"}, + {} +}; +MODULE_DEVICE_TABLE(of, lpass_cdc_clk_rsc_dt_match); + +static struct platform_driver lpass_cdc_clk_rsc_mgr = { + .driver = { + .name = "lpass-cdc-clk-rsc-mngr", + .owner = THIS_MODULE, + .of_match_table = lpass_cdc_clk_rsc_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_cdc_clk_rsc_probe, + .remove = lpass_cdc_clk_rsc_remove, +}; + +int lpass_cdc_clk_rsc_mgr_init(void) +{ + return platform_driver_register(&lpass_cdc_clk_rsc_mgr); +} + +void lpass_cdc_clk_rsc_mgr_exit(void) +{ + platform_driver_unregister(&lpass_cdc_clk_rsc_mgr); +} +MODULE_DESCRIPTION("LPASS codec clock resource manager driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-clk-rsc.h b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-clk-rsc.h new file mode 100644 index 0000000000..e7457eef7d --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-clk-rsc.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + */ + +#ifndef LPASS_CDC_CLK_RSC_H +#define LPASS_CDC_CLK_RSC_H + +#include +#include + +#if IS_ENABLED(CONFIG_SND_SOC_LPASS_CDC) +int lpass_cdc_clk_rsc_mgr_init(void); +void lpass_cdc_clk_rsc_mgr_exit(void); +void lpass_cdc_clk_rsc_fs_gen_request(struct device *dev, + bool enable); +int lpass_cdc_clk_rsc_request_clock(struct device *dev, + int default_clk_id, + int clk_id_req, + bool enable); +int lpass_cdc_rsc_clk_reset(struct device *dev, int clk_id); +void lpass_cdc_clk_rsc_enable_all_clocks(struct device *dev, bool enable); +#else +static inline void lpass_cdc_clk_rsc_fs_gen_request(struct device *dev, + bool enable) +{ +} +static inline int lpass_cdc_clk_rsc_mgr_init(void) +{ + return 0; +} +static inline void lpass_cdc_clk_rsc_mgr_exit(void) +{ +} +static inline int lpass_cdc_clk_rsc_request_clock(struct device *dev, + int default_clk_id, + int clk_id_req, + bool enable) +{ + return 0; +} +static inline int lpass_cdc_rsc_clk_reset(struct device *dev, int clk_id) +{ + return 0; +} +static inline void lpass_cdc_clk_rsc_enable_all_clocks(struct device *dev, + bool enable) +{ + return; +} +#endif /* CONFIG_SND_SOC_LPASS_CDC */ +#endif /* LPASS_CDC_CLK_RSC_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-comp.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-comp.c new file mode 100644 index 0000000000..49255735fe --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-comp.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + */ +#include "lpass-cdc-comp.h" + +int lpass_cdc_load_compander_coeff(struct snd_soc_component *component, + u16 lsb_reg, u16 msb_reg, + struct comp_coeff_val *comp_coeff_table, + u16 arr_size) +{ + int i = 0; + + /* Load Compander Coeff */ + for (i = 0; i < arr_size; i++) { + snd_soc_component_write(component, lsb_reg, + comp_coeff_table[i].lsb); + snd_soc_component_write(component, msb_reg, + comp_coeff_table[i].msb); + } + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_load_compander_coeff); + +int lpass_cdc_update_compander_setting(struct snd_soc_component *component, + u16 start_addr, + struct lpass_cdc_comp_setting *comp_setting) +{ + int zone2_rms, zone3_rms, zone4_rms, zone5_rms, zone6_rms; + int path_gain; + int max_attn; + int zone1_rms = 6; + int upper_gain_int = comp_setting->upper_gain_int; + int lower_gain_int = comp_setting->lower_gain_int; + int ana_addr_map = comp_setting->ana_addr_map; + int upper_gain_dig_int = upper_gain_int - lower_gain_int; + + /* skip comp_ctl8, comp_ctl9 default settings is fine */ + + /* apply zone settings */ + snd_soc_component_write(component, + start_addr + 8, + zone1_rms); + + if (upper_gain_dig_int >= 24) + zone2_rms = 18; + else if (upper_gain_dig_int >= 18) + zone2_rms = 12; + else + zone2_rms = upper_gain_dig_int; + snd_soc_component_write(component, + start_addr + 0xC, + zone2_rms); + + if (upper_gain_dig_int >= 66) + zone3_rms = 33; + else if (upper_gain_dig_int >= 36) + zone3_rms = 30; + else if (upper_gain_dig_int >= 30) + zone3_rms = 24; + else + zone3_rms = upper_gain_dig_int; + snd_soc_component_write(component, + start_addr + 0x10, + zone3_rms); + + if (upper_gain_dig_int >= 66) + zone4_rms = 48; + else if (upper_gain_dig_int >= 48) + zone4_rms = 42; + else if (upper_gain_dig_int >= 42) + zone4_rms = 36; + else + zone4_rms = upper_gain_dig_int; + snd_soc_component_write(component, + start_addr + 0x14, + zone4_rms); + + if (upper_gain_dig_int >= 69) + zone5_rms = 63; + else if (upper_gain_dig_int >= 66) + zone5_rms = 60; + else if (upper_gain_dig_int >= 60) + zone5_rms = 54; + else if (upper_gain_dig_int >= 54) + zone5_rms = 48; + else + zone5_rms = upper_gain_dig_int; + snd_soc_component_write(component, + start_addr + 0x18, + zone5_rms); + + zone6_rms = upper_gain_dig_int; + snd_soc_component_write(component, + start_addr + 0x1C, + zone6_rms); + + if (lower_gain_int < 0) + max_attn = 256 + lower_gain_int; + else + max_attn = lower_gain_int; + snd_soc_component_write(component, + start_addr + 0x20, + max_attn); + + path_gain = zone6_rms - abs(lower_gain_int); + snd_soc_component_write(component, + start_addr + 0x24, + path_gain); + + snd_soc_component_write(component, + start_addr + 0x28, + ana_addr_map); + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_update_compander_setting); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-comp.h b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-comp.h new file mode 100644 index 0000000000..238d630f2f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-comp.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +#ifndef LPASS_CDC_COMP_H +#define LPASS_CDC_COMP_H + +#include + +struct comp_coeff_val { + u8 lsb; + u8 msb; +}; + +struct lpass_cdc_comp_setting { + int upper_gain_int; + int lower_gain_int; + int ana_addr_map; +}; + +int lpass_cdc_load_compander_coeff(struct snd_soc_component *component, + u16 lsb_reg, u16 msb_reg, + struct comp_coeff_val *comp_coeff_table, + u16 arr_size); +int lpass_cdc_update_compander_setting(struct snd_soc_component *component, + u16 start_addr, + struct lpass_cdc_comp_setting *comp_setting); +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-registers.h new file mode 100644 index 0000000000..9aefc8fcc9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-registers.h @@ -0,0 +1,1426 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _LPASS_CDC_REGISTERS_H +#define _LPASS_CDC_REGISTERS_H + +#define TX_START_OFFSET 0x0000 + +#define LPASS_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL (TX_START_OFFSET + 0x0000) +#define LPASS_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL (TX_START_OFFSET + 0x0004) +#define LPASS_CDC_TX_CLK_RST_CTRL_SWR_CONTROL (TX_START_OFFSET + 0x0008) +#define LPASS_CDC_TX_TOP_CSR_TOP_CFG0 (TX_START_OFFSET + 0x0080) +#define LPASS_CDC_TX_TOP_CSR_ANC_CFG (TX_START_OFFSET + 0x0084) +#define LPASS_CDC_TX_TOP_CSR_SWR_CTRL (TX_START_OFFSET + 0x0088) +#define LPASS_CDC_TX_TOP_CSR_FREQ_MCLK (TX_START_OFFSET + 0x0090) +#define LPASS_CDC_TX_TOP_CSR_DEBUG_BUS (TX_START_OFFSET + 0x0094) +#define LPASS_CDC_TX_TOP_CSR_DEBUG_EN (TX_START_OFFSET + 0x0098) +#define LPASS_CDC_TX_TOP_CSR_TX_I2S_CTL (TX_START_OFFSET + 0x00A4) +#define LPASS_CDC_TX_TOP_CSR_I2S_CLK (TX_START_OFFSET + 0x00A8) +#define LPASS_CDC_TX_TOP_CSR_I2S_RESET (TX_START_OFFSET + 0x00AC) +#define LPASS_CDC_TX_TOP_CSR_SWR_MIC2_CTL (TX_START_OFFSET + 0x00C0) +#define LPASS_CDC_TX_TOP_CSR_SWR_MIC3_CTL (TX_START_OFFSET + 0x00C4) +#define LPASS_CDC_TX_TOP_CSR_SWR_MIC4_CTL (TX_START_OFFSET + 0x00C8) +#define LPASS_CDC_TX_TOP_CSR_SWR_MIC5_CTL (TX_START_OFFSET + 0x00CC) +#define LPASS_CDC_TX_TOP_CSR_SWR_MIC0_CTL (TX_START_OFFSET + 0x00D0) +#define LPASS_CDC_TX_TOP_CSR_SWR_MIC1_CTL (TX_START_OFFSET + 0x00D4) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0 (TX_START_OFFSET + 0x0100) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG1 (TX_START_OFFSET + 0x0104) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG0 (TX_START_OFFSET + 0x0108) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG1 (TX_START_OFFSET + 0x010C) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG0 (TX_START_OFFSET + 0x0110) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG1 (TX_START_OFFSET + 0x0114) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG0 (TX_START_OFFSET + 0x0118) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG1 (TX_START_OFFSET + 0x011C) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG0 (TX_START_OFFSET + 0x0120) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG1 (TX_START_OFFSET + 0x0124) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG0 (TX_START_OFFSET + 0x0128) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG1 (TX_START_OFFSET + 0x012C) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG0 (TX_START_OFFSET + 0x0130) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG1 (TX_START_OFFSET + 0x0134) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG0 (TX_START_OFFSET + 0x0138) +#define LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG1 (TX_START_OFFSET + 0x013C) +#define LPASS_CDC_TX_ANC0_CLK_RESET_CTL (TX_START_OFFSET + 0x0200) +#define LPASS_CDC_TX_ANC0_MODE_1_CTL (TX_START_OFFSET + 0x0204) +#define LPASS_CDC_TX_ANC0_MODE_2_CTL (TX_START_OFFSET + 0x0208) +#define LPASS_CDC_TX_ANC0_FF_SHIFT (TX_START_OFFSET + 0x020C) +#define LPASS_CDC_TX_ANC0_FB_SHIFT (TX_START_OFFSET + 0x0210) +#define LPASS_CDC_TX_ANC0_LPF_FF_A_CTL (TX_START_OFFSET + 0x0214) +#define LPASS_CDC_TX_ANC0_LPF_FF_B_CTL (TX_START_OFFSET + 0x0218) +#define LPASS_CDC_TX_ANC0_LPF_FB_CTL (TX_START_OFFSET + 0x021C) +#define LPASS_CDC_TX_ANC0_SMLPF_CTL (TX_START_OFFSET + 0x0220) +#define LPASS_CDC_TX_ANC0_DCFLT_SHIFT_CTL (TX_START_OFFSET + 0x0224) +#define LPASS_CDC_TX_ANC0_IIR_ADAPT_CTL (TX_START_OFFSET + 0x0228) +#define LPASS_CDC_TX_ANC0_IIR_COEFF_1_CTL (TX_START_OFFSET + 0x022C) +#define LPASS_CDC_TX_ANC0_IIR_COEFF_2_CTL (TX_START_OFFSET + 0x0230) +#define LPASS_CDC_TX_ANC0_FF_A_GAIN_CTL (TX_START_OFFSET + 0x0234) +#define LPASS_CDC_TX_ANC0_FF_B_GAIN_CTL (TX_START_OFFSET + 0x0238) +#define LPASS_CDC_TX_ANC0_FB_GAIN_CTL (TX_START_OFFSET + 0x023C) +#define LPASS_CDC_TX0_TX_PATH_CTL (TX_START_OFFSET + 0x0400) +#define LPASS_CDC_TX0_TX_PATH_CFG0 (TX_START_OFFSET + 0x0404) +#define LPASS_CDC_TX0_TX_PATH_CFG1 (TX_START_OFFSET + 0x0408) +#define LPASS_CDC_TX0_TX_VOL_CTL (TX_START_OFFSET + 0x040C) +#define LPASS_CDC_TX0_TX_PATH_SEC0 (TX_START_OFFSET + 0x0410) +#define LPASS_CDC_TX0_TX_PATH_SEC1 (TX_START_OFFSET + 0x0414) +#define LPASS_CDC_TX0_TX_PATH_SEC2 (TX_START_OFFSET + 0x0418) +#define LPASS_CDC_TX0_TX_PATH_SEC3 (TX_START_OFFSET + 0x041C) +#define LPASS_CDC_TX0_TX_PATH_SEC4 (TX_START_OFFSET + 0x0420) +#define LPASS_CDC_TX0_TX_PATH_SEC5 (TX_START_OFFSET + 0x0424) +#define LPASS_CDC_TX0_TX_PATH_SEC6 (TX_START_OFFSET + 0x0428) +#define LPASS_CDC_TX0_TX_PATH_SEC7 (TX_START_OFFSET + 0x042C) +#define LPASS_CDC_TX1_TX_PATH_CTL (TX_START_OFFSET + 0x0480) +#define LPASS_CDC_TX1_TX_PATH_CFG0 (TX_START_OFFSET + 0x0484) +#define LPASS_CDC_TX1_TX_PATH_CFG1 (TX_START_OFFSET + 0x0488) +#define LPASS_CDC_TX1_TX_VOL_CTL (TX_START_OFFSET + 0x048C) +#define LPASS_CDC_TX1_TX_PATH_SEC0 (TX_START_OFFSET + 0x0490) +#define LPASS_CDC_TX1_TX_PATH_SEC1 (TX_START_OFFSET + 0x0494) +#define LPASS_CDC_TX1_TX_PATH_SEC2 (TX_START_OFFSET + 0x0498) +#define LPASS_CDC_TX1_TX_PATH_SEC3 (TX_START_OFFSET + 0x049C) +#define LPASS_CDC_TX1_TX_PATH_SEC4 (TX_START_OFFSET + 0x04A0) +#define LPASS_CDC_TX1_TX_PATH_SEC5 (TX_START_OFFSET + 0x04A4) +#define LPASS_CDC_TX1_TX_PATH_SEC6 (TX_START_OFFSET + 0x04A8) +#define LPASS_CDC_TX2_TX_PATH_CTL (TX_START_OFFSET + 0x0500) +#define LPASS_CDC_TX2_TX_PATH_CFG0 (TX_START_OFFSET + 0x0504) +#define LPASS_CDC_TX2_TX_PATH_CFG1 (TX_START_OFFSET + 0x0508) +#define LPASS_CDC_TX2_TX_VOL_CTL (TX_START_OFFSET + 0x050C) +#define LPASS_CDC_TX2_TX_PATH_SEC0 (TX_START_OFFSET + 0x0510) +#define LPASS_CDC_TX2_TX_PATH_SEC1 (TX_START_OFFSET + 0x0514) +#define LPASS_CDC_TX2_TX_PATH_SEC2 (TX_START_OFFSET + 0x0518) +#define LPASS_CDC_TX2_TX_PATH_SEC3 (TX_START_OFFSET + 0x051C) +#define LPASS_CDC_TX2_TX_PATH_SEC4 (TX_START_OFFSET + 0x0520) +#define LPASS_CDC_TX2_TX_PATH_SEC5 (TX_START_OFFSET + 0x0524) +#define LPASS_CDC_TX2_TX_PATH_SEC6 (TX_START_OFFSET + 0x0528) +#define LPASS_CDC_TX3_TX_PATH_CTL (TX_START_OFFSET + 0x0580) +#define LPASS_CDC_TX3_TX_PATH_CFG0 (TX_START_OFFSET + 0x0584) +#define LPASS_CDC_TX3_TX_PATH_CFG1 (TX_START_OFFSET + 0x0588) +#define LPASS_CDC_TX3_TX_VOL_CTL (TX_START_OFFSET + 0x058C) +#define LPASS_CDC_TX3_TX_PATH_SEC0 (TX_START_OFFSET + 0x0590) +#define LPASS_CDC_TX3_TX_PATH_SEC1 (TX_START_OFFSET + 0x0594) +#define LPASS_CDC_TX3_TX_PATH_SEC2 (TX_START_OFFSET + 0x0598) +#define LPASS_CDC_TX3_TX_PATH_SEC3 (TX_START_OFFSET + 0x059C) +#define LPASS_CDC_TX3_TX_PATH_SEC4 (TX_START_OFFSET + 0x05A0) +#define LPASS_CDC_TX3_TX_PATH_SEC5 (TX_START_OFFSET + 0x05A4) +#define LPASS_CDC_TX3_TX_PATH_SEC6 (TX_START_OFFSET + 0x05A8) +#define LPASS_CDC_TX4_TX_PATH_CTL (TX_START_OFFSET + 0x0600) +#define LPASS_CDC_TX4_TX_PATH_CFG0 (TX_START_OFFSET + 0x0604) +#define LPASS_CDC_TX4_TX_PATH_CFG1 (TX_START_OFFSET + 0x0608) +#define LPASS_CDC_TX4_TX_VOL_CTL (TX_START_OFFSET + 0x060C) +#define LPASS_CDC_TX4_TX_PATH_SEC0 (TX_START_OFFSET + 0x0610) +#define LPASS_CDC_TX4_TX_PATH_SEC1 (TX_START_OFFSET + 0x0614) +#define LPASS_CDC_TX4_TX_PATH_SEC2 (TX_START_OFFSET + 0x0618) +#define LPASS_CDC_TX4_TX_PATH_SEC3 (TX_START_OFFSET + 0x061C) +#define LPASS_CDC_TX4_TX_PATH_SEC4 (TX_START_OFFSET + 0x0620) +#define LPASS_CDC_TX4_TX_PATH_SEC5 (TX_START_OFFSET + 0x0624) +#define LPASS_CDC_TX4_TX_PATH_SEC6 (TX_START_OFFSET + 0x0628) +#define LPASS_CDC_TX5_TX_PATH_CTL (TX_START_OFFSET + 0x0680) +#define LPASS_CDC_TX5_TX_PATH_CFG0 (TX_START_OFFSET + 0x0684) +#define LPASS_CDC_TX5_TX_PATH_CFG1 (TX_START_OFFSET + 0x0688) +#define LPASS_CDC_TX5_TX_VOL_CTL (TX_START_OFFSET + 0x068C) +#define LPASS_CDC_TX5_TX_PATH_SEC0 (TX_START_OFFSET + 0x0690) +#define LPASS_CDC_TX5_TX_PATH_SEC1 (TX_START_OFFSET + 0x0694) +#define LPASS_CDC_TX5_TX_PATH_SEC2 (TX_START_OFFSET + 0x0698) +#define LPASS_CDC_TX5_TX_PATH_SEC3 (TX_START_OFFSET + 0x069C) +#define LPASS_CDC_TX5_TX_PATH_SEC4 (TX_START_OFFSET + 0x06A0) +#define LPASS_CDC_TX5_TX_PATH_SEC5 (TX_START_OFFSET + 0x06A4) +#define LPASS_CDC_TX5_TX_PATH_SEC6 (TX_START_OFFSET + 0x06A8) +#define LPASS_CDC_TX6_TX_PATH_CTL (TX_START_OFFSET + 0x0700) +#define LPASS_CDC_TX6_TX_PATH_CFG0 (TX_START_OFFSET + 0x0704) +#define LPASS_CDC_TX6_TX_PATH_CFG1 (TX_START_OFFSET + 0x0708) +#define LPASS_CDC_TX6_TX_VOL_CTL (TX_START_OFFSET + 0x070C) +#define LPASS_CDC_TX6_TX_PATH_SEC0 (TX_START_OFFSET + 0x0710) +#define LPASS_CDC_TX6_TX_PATH_SEC1 (TX_START_OFFSET + 0x0714) +#define LPASS_CDC_TX6_TX_PATH_SEC2 (TX_START_OFFSET + 0x0718) +#define LPASS_CDC_TX6_TX_PATH_SEC3 (TX_START_OFFSET + 0x071C) +#define LPASS_CDC_TX6_TX_PATH_SEC4 (TX_START_OFFSET + 0x0720) +#define LPASS_CDC_TX6_TX_PATH_SEC5 (TX_START_OFFSET + 0x0724) +#define LPASS_CDC_TX6_TX_PATH_SEC6 (TX_START_OFFSET + 0x0728) +#define LPASS_CDC_TX7_TX_PATH_CTL (TX_START_OFFSET + 0x0780) +#define LPASS_CDC_TX7_TX_PATH_CFG0 (TX_START_OFFSET + 0x0784) +#define LPASS_CDC_TX7_TX_PATH_CFG1 (TX_START_OFFSET + 0x0788) +#define LPASS_CDC_TX7_TX_VOL_CTL (TX_START_OFFSET + 0x078C) +#define LPASS_CDC_TX7_TX_PATH_SEC0 (TX_START_OFFSET + 0x0790) +#define LPASS_CDC_TX7_TX_PATH_SEC1 (TX_START_OFFSET + 0x0794) +#define LPASS_CDC_TX7_TX_PATH_SEC2 (TX_START_OFFSET + 0x0798) +#define LPASS_CDC_TX7_TX_PATH_SEC3 (TX_START_OFFSET + 0x079C) +#define LPASS_CDC_TX7_TX_PATH_SEC4 (TX_START_OFFSET + 0x07A0) +#define LPASS_CDC_TX7_TX_PATH_SEC5 (TX_START_OFFSET + 0x07A4) +#define LPASS_CDC_TX7_TX_PATH_SEC6 (TX_START_OFFSET + 0x07A8) +#define TX_MAX_OFFSET (TX_START_OFFSET + 0x07A8) + +#define LPASS_CDC_TX_MACRO_MAX 0x1EB /* 7A8/4 = 1EA + 1 */ + +#define RX_START_OFFSET 0x1000 +#define LPASS_CDC_RX_TOP_TOP_CFG0 (RX_START_OFFSET + 0x0000) +#define LPASS_CDC_RX_TOP_TOP_CFG1 (RX_START_OFFSET + 0x0004) +#define LPASS_CDC_RX_TOP_SWR_CTRL (RX_START_OFFSET + 0x0008) +#define LPASS_CDC_RX_TOP_DEBUG (RX_START_OFFSET + 0x000C) +#define LPASS_CDC_RX_TOP_DEBUG_BUS (RX_START_OFFSET + 0x0010) +#define LPASS_CDC_RX_TOP_DEBUG_EN0 (RX_START_OFFSET + 0x0014) +#define LPASS_CDC_RX_TOP_DEBUG_EN1 (RX_START_OFFSET + 0x0018) +#define LPASS_CDC_RX_TOP_DEBUG_EN2 (RX_START_OFFSET + 0x001C) +#define LPASS_CDC_RX_TOP_HPHL_COMP_WR_LSB (RX_START_OFFSET + 0x0020) +#define LPASS_CDC_RX_TOP_HPHL_COMP_WR_MSB (RX_START_OFFSET + 0x0024) +#define LPASS_CDC_RX_TOP_HPHL_COMP_LUT (RX_START_OFFSET + 0x0028) +#define LPASS_CDC_RX_TOP_HPHL_COMP_RD_LSB (RX_START_OFFSET + 0x002C) +#define LPASS_CDC_RX_TOP_HPHL_COMP_RD_MSB (RX_START_OFFSET + 0x0030) +#define LPASS_CDC_RX_TOP_HPHR_COMP_WR_LSB (RX_START_OFFSET + 0x0034) +#define LPASS_CDC_RX_TOP_HPHR_COMP_WR_MSB (RX_START_OFFSET + 0x0038) +#define LPASS_CDC_RX_TOP_HPHR_COMP_LUT (RX_START_OFFSET + 0x003C) +#define LPASS_CDC_RX_TOP_HPHR_COMP_RD_LSB (RX_START_OFFSET + 0x0040) +#define LPASS_CDC_RX_TOP_HPHR_COMP_RD_MSB (RX_START_OFFSET + 0x0044) +#define LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG0 (RX_START_OFFSET + 0x0070) +#define LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG1 (RX_START_OFFSET + 0x0074) +#define LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG2 (RX_START_OFFSET + 0x0078) +#define LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG3 (RX_START_OFFSET + 0x007C) +#define LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG0 (RX_START_OFFSET + 0x0080) +#define LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG1 (RX_START_OFFSET + 0x0084) +#define LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG2 (RX_START_OFFSET + 0x0088) +#define LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG3 (RX_START_OFFSET + 0x008C) +#define LPASS_CDC_RX_TOP_RX_I2S_CTL (RX_START_OFFSET + 0x0090) +#define LPASS_CDC_RX_TOP_TX_I2S2_CTL (RX_START_OFFSET + 0x0094) +#define LPASS_CDC_RX_TOP_I2S_CLK (RX_START_OFFSET + 0x0098) +#define LPASS_CDC_RX_TOP_I2S_RESET (RX_START_OFFSET + 0x009C) +#define LPASS_CDC_RX_TOP_I2S_MUX (RX_START_OFFSET + 0x00A0) +#define LPASS_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL (RX_START_OFFSET + 0x0100) +#define LPASS_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL \ + (RX_START_OFFSET + 0x0104) +#define LPASS_CDC_RX_CLK_RST_CTRL_SWR_CONTROL (RX_START_OFFSET + 0x0108) +#define LPASS_CDC_RX_CLK_RST_CTRL_DSD_CONTROL (RX_START_OFFSET + 0x010C) +#define LPASS_CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL \ + (RX_START_OFFSET + 0x0110) +#define LPASS_CDC_RX_SOFTCLIP_CRC (RX_START_OFFSET + 0x0140) +#define LPASS_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL (RX_START_OFFSET + 0x0144) +#define LPASS_CDC_RX_INP_MUX_RX_INT0_CFG0 (RX_START_OFFSET + 0x0180) +#define LPASS_CDC_RX_INP_MUX_RX_INT0_CFG1 (RX_START_OFFSET + 0x0184) +#define LPASS_CDC_RX_INP_MUX_RX_INT1_CFG0 (RX_START_OFFSET + 0x0188) +#define LPASS_CDC_RX_INP_MUX_RX_INT1_CFG1 (RX_START_OFFSET + 0x018C) +#define LPASS_CDC_RX_INP_MUX_RX_INT2_CFG0 (RX_START_OFFSET + 0x0190) +#define LPASS_CDC_RX_INP_MUX_RX_INT2_CFG1 (RX_START_OFFSET + 0x0194) +#define LPASS_CDC_RX_INP_MUX_RX_MIX_CFG4 (RX_START_OFFSET + 0x0198) +#define LPASS_CDC_RX_INP_MUX_RX_MIX_CFG5 (RX_START_OFFSET + 0x019C) +#define LPASS_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0 (RX_START_OFFSET + 0x01A0) +#define LPASS_CDC_RX_CLSH_CRC (RX_START_OFFSET + 0x0200) +#define LPASS_CDC_RX_CLSH_DLY_CTRL (RX_START_OFFSET + 0x0204) +#define LPASS_CDC_RX_CLSH_DECAY_CTRL (RX_START_OFFSET + 0x0208) +#define LPASS_CDC_RX_CLSH_HPH_V_PA (RX_START_OFFSET + 0x020C) +#define LPASS_CDC_RX_CLSH_EAR_V_PA (RX_START_OFFSET + 0x0210) +#define LPASS_CDC_RX_CLSH_HPH_V_HD (RX_START_OFFSET + 0x0214) +#define LPASS_CDC_RX_CLSH_EAR_V_HD (RX_START_OFFSET + 0x0218) +#define LPASS_CDC_RX_CLSH_K1_MSB (RX_START_OFFSET + 0x021C) +#define LPASS_CDC_RX_CLSH_K1_LSB (RX_START_OFFSET + 0x0220) +#define LPASS_CDC_RX_CLSH_K2_MSB (RX_START_OFFSET + 0x0224) +#define LPASS_CDC_RX_CLSH_K2_LSB (RX_START_OFFSET + 0x0228) +#define LPASS_CDC_RX_CLSH_IDLE_CTRL (RX_START_OFFSET + 0x022C) +#define LPASS_CDC_RX_CLSH_IDLE_HPH (RX_START_OFFSET + 0x0230) +#define LPASS_CDC_RX_CLSH_IDLE_EAR (RX_START_OFFSET + 0x0234) +#define LPASS_CDC_RX_CLSH_TEST0 (RX_START_OFFSET + 0x0238) +#define LPASS_CDC_RX_CLSH_TEST1 (RX_START_OFFSET + 0x023C) +#define LPASS_CDC_RX_CLSH_OVR_VREF (RX_START_OFFSET + 0x0240) +#define LPASS_CDC_RX_CLSH_CLSG_CTL (RX_START_OFFSET + 0x0244) +#define LPASS_CDC_RX_CLSH_CLSG_CFG1 (RX_START_OFFSET + 0x0248) +#define LPASS_CDC_RX_CLSH_CLSG_CFG2 (RX_START_OFFSET + 0x024C) +#define LPASS_CDC_RX_BCL_VBAT_PATH_CTL (RX_START_OFFSET + 0x0280) +#define LPASS_CDC_RX_BCL_VBAT_CFG (RX_START_OFFSET + 0x0284) +#define LPASS_CDC_RX_BCL_VBAT_ADC_CAL1 (RX_START_OFFSET + 0x0288) +#define LPASS_CDC_RX_BCL_VBAT_ADC_CAL2 (RX_START_OFFSET + 0x028C) +#define LPASS_CDC_RX_BCL_VBAT_ADC_CAL3 (RX_START_OFFSET + 0x0290) +#define LPASS_CDC_RX_BCL_VBAT_PK_EST1 (RX_START_OFFSET + 0x0294) +#define LPASS_CDC_RX_BCL_VBAT_PK_EST2 (RX_START_OFFSET + 0x0298) +#define LPASS_CDC_RX_BCL_VBAT_PK_EST3 (RX_START_OFFSET + 0x029C) +#define LPASS_CDC_RX_BCL_VBAT_RF_PROC1 (RX_START_OFFSET + 0x02A0) +#define LPASS_CDC_RX_BCL_VBAT_RF_PROC2 (RX_START_OFFSET + 0x02A4) +#define LPASS_CDC_RX_BCL_VBAT_TAC1 (RX_START_OFFSET + 0x02A8) +#define LPASS_CDC_RX_BCL_VBAT_TAC2 (RX_START_OFFSET + 0x02AC) +#define LPASS_CDC_RX_BCL_VBAT_TAC3 (RX_START_OFFSET + 0x02B0) +#define LPASS_CDC_RX_BCL_VBAT_TAC4 (RX_START_OFFSET + 0x02B4) +#define LPASS_CDC_RX_BCL_VBAT_GAIN_UPD1 (RX_START_OFFSET + 0x02B8) +#define LPASS_CDC_RX_BCL_VBAT_GAIN_UPD2 (RX_START_OFFSET + 0x02BC) +#define LPASS_CDC_RX_BCL_VBAT_GAIN_UPD3 (RX_START_OFFSET + 0x02C0) +#define LPASS_CDC_RX_BCL_VBAT_GAIN_UPD4 (RX_START_OFFSET + 0x02C4) +#define LPASS_CDC_RX_BCL_VBAT_GAIN_UPD5 (RX_START_OFFSET + 0x02C8) +#define LPASS_CDC_RX_BCL_VBAT_DEBUG1 (RX_START_OFFSET + 0x02CC) +#define LPASS_CDC_RX_BCL_VBAT_GAIN_UPD_MON (RX_START_OFFSET + 0x02D0) +#define LPASS_CDC_RX_BCL_VBAT_GAIN_MON_VAL (RX_START_OFFSET + 0x02D4) +#define LPASS_CDC_RX_BCL_VBAT_BAN (RX_START_OFFSET + 0x02D8) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1 (RX_START_OFFSET + 0x02DC) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2 (RX_START_OFFSET + 0x02E0) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3 (RX_START_OFFSET + 0x02E4) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4 (RX_START_OFFSET + 0x02E8) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5 (RX_START_OFFSET + 0x02EC) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6 (RX_START_OFFSET + 0x02F0) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7 (RX_START_OFFSET + 0x02F4) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8 (RX_START_OFFSET + 0x02F8) +#define LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9 (RX_START_OFFSET + 0x02FC) +#define LPASS_CDC_RX_BCL_VBAT_ATTN1 (RX_START_OFFSET + 0x0300) +#define LPASS_CDC_RX_BCL_VBAT_ATTN2 (RX_START_OFFSET + 0x0304) +#define LPASS_CDC_RX_BCL_VBAT_ATTN3 (RX_START_OFFSET + 0x0308) +#define LPASS_CDC_RX_INTR_CTRL_CFG (RX_START_OFFSET + 0x0340) +#define LPASS_CDC_RX_INTR_CTRL_CLR_COMMIT (RX_START_OFFSET + 0x0344) +#define LPASS_CDC_RX_INTR_CTRL_PIN1_MASK0 (RX_START_OFFSET + 0x0360) +#define LPASS_CDC_RX_INTR_CTRL_PIN1_STATUS0 (RX_START_OFFSET + 0x0368) +#define LPASS_CDC_RX_INTR_CTRL_PIN1_CLEAR0 (RX_START_OFFSET + 0x0370) +#define LPASS_CDC_RX_INTR_CTRL_PIN2_MASK0 (RX_START_OFFSET + 0x0380) +#define LPASS_CDC_RX_INTR_CTRL_PIN2_STATUS0 (RX_START_OFFSET + 0x0388) +#define LPASS_CDC_RX_INTR_CTRL_PIN2_CLEAR0 (RX_START_OFFSET + 0x0390) +#define LPASS_CDC_RX_INTR_CTRL_LEVEL0 (RX_START_OFFSET + 0x03C0) +#define LPASS_CDC_RX_INTR_CTRL_BYPASS0 (RX_START_OFFSET + 0x03C8) +#define LPASS_CDC_RX_INTR_CTRL_SET0 (RX_START_OFFSET + 0x03D0) +#define LPASS_CDC_RX_RX0_RX_PATH_CTL (RX_START_OFFSET + 0x0400) +#define LPASS_CDC_RX_RX0_RX_PATH_CFG0 (RX_START_OFFSET + 0x0404) +#define LPASS_CDC_RX_RX0_RX_PATH_CFG1 (RX_START_OFFSET + 0x0408) +#define LPASS_CDC_RX_RX0_RX_PATH_CFG2 (RX_START_OFFSET + 0x040C) +#define LPASS_CDC_RX_RX0_RX_PATH_CFG3 (RX_START_OFFSET + 0x0410) +#define LPASS_CDC_RX_RX0_RX_VOL_CTL (RX_START_OFFSET + 0x0414) +#define LPASS_CDC_RX_RX0_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x0418) +#define LPASS_CDC_RX_RX0_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x041C) +#define LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x0420) +#define LPASS_CDC_RX_RX0_RX_PATH_SEC1 (RX_START_OFFSET + 0x0424) +#define LPASS_CDC_RX_RX0_RX_PATH_SEC2 (RX_START_OFFSET + 0x0428) +#define LPASS_CDC_RX_RX0_RX_PATH_SEC3 (RX_START_OFFSET + 0x042C) +#define LPASS_CDC_RX_RX0_RX_PATH_SEC4 (RX_START_OFFSET + 0x0430) +#define LPASS_CDC_RX_RX0_RX_PATH_SEC7 (RX_START_OFFSET + 0x0434) +#define LPASS_CDC_RX_RX0_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x0438) +#define LPASS_CDC_RX_RX0_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x043C) +#define LPASS_CDC_RX_RX0_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x0440) +#define LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA1 (RX_START_OFFSET + 0x0444) +#define LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA2 (RX_START_OFFSET + 0x0448) +#define LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA3 (RX_START_OFFSET + 0x044C) +#define LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA4 (RX_START_OFFSET + 0x0450) +#define LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA5 (RX_START_OFFSET + 0x0454) +#define LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA6 (RX_START_OFFSET + 0x0458) +#define LPASS_CDC_RX_IDLE_DETECT_PATH_CTL (RX_START_OFFSET + 0x0780) +#define LPASS_CDC_RX_IDLE_DETECT_CFG0 (RX_START_OFFSET + 0x0784) +#define LPASS_CDC_RX_IDLE_DETECT_CFG1 (RX_START_OFFSET + 0x0788) +#define LPASS_CDC_RX_IDLE_DETECT_CFG2 (RX_START_OFFSET + 0x078C) +#define LPASS_CDC_RX_IDLE_DETECT_CFG3 (RX_START_OFFSET + 0x0790) +#define LPASS_CDC_RX_COMPANDER0_CTL0 (RX_START_OFFSET + 0x0800) +#define LPASS_CDC_RX_COMPANDER0_CTL1 (RX_START_OFFSET + 0x0804) +#define LPASS_CDC_RX_COMPANDER0_CTL2 (RX_START_OFFSET + 0x0808) +#define LPASS_CDC_RX_COMPANDER0_CTL3 (RX_START_OFFSET + 0x080C) +#define LPASS_CDC_RX_COMPANDER0_CTL4 (RX_START_OFFSET + 0x0810) +#define LPASS_CDC_RX_COMPANDER0_CTL5 (RX_START_OFFSET + 0x0814) +#define LPASS_CDC_RX_COMPANDER0_CTL6 (RX_START_OFFSET + 0x0818) +#define LPASS_CDC_RX_COMPANDER0_CTL7 (RX_START_OFFSET + 0x081C) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL \ + (RX_START_OFFSET + 0x0A00) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL \ + (RX_START_OFFSET + 0x0A04) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL \ + (RX_START_OFFSET + 0x0A08) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL \ + (RX_START_OFFSET + 0x0A0C) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL \ + (RX_START_OFFSET + 0x0A10) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL \ + (RX_START_OFFSET + 0x0A14) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL \ + (RX_START_OFFSET + 0x0A18) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL \ + (RX_START_OFFSET + 0x0A1C) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL \ + (RX_START_OFFSET + 0x0A20) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_CTL (RX_START_OFFSET + 0x0A24) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL \ + (RX_START_OFFSET + 0x0A28) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL \ + (RX_START_OFFSET + 0x0A2C) +#define LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL \ + (RX_START_OFFSET + 0x0A30) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL \ + (RX_START_OFFSET + 0x0A80) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL \ + (RX_START_OFFSET + 0x0A84) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL \ + (RX_START_OFFSET + 0x0A88) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL \ + (RX_START_OFFSET + 0x0A8C) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL \ + (RX_START_OFFSET + 0x0A90) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL \ + (RX_START_OFFSET + 0x0A94) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL \ + (RX_START_OFFSET + 0x0A98) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL \ + (RX_START_OFFSET + 0x0A9C) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL \ + (RX_START_OFFSET + 0x0AA0) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_CTL (RX_START_OFFSET + 0x0AA4) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL \ + (RX_START_OFFSET + 0x0AA8) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL \ + (RX_START_OFFSET + 0x0AAC) +#define LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL \ + (RX_START_OFFSET + 0x0AB0) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0 (RX_START_OFFSET + 0x0B00) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1 (RX_START_OFFSET + 0x0B04) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2 (RX_START_OFFSET + 0x0B08) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3 (RX_START_OFFSET + 0x0B0C) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0 (RX_START_OFFSET + 0x0B10) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1 (RX_START_OFFSET + 0x0B14) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2 (RX_START_OFFSET + 0x0B18) +#define LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3 (RX_START_OFFSET + 0x0B1C) +#define LPASS_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL \ + (RX_START_OFFSET + 0x0B40) +#define LPASS_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1 \ + (RX_START_OFFSET + 0x0B44) +#define LPASS_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL \ + (RX_START_OFFSET + 0x0B50) +#define LPASS_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1 \ + (RX_START_OFFSET + 0x0B54) +#define LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL \ + (RX_START_OFFSET + 0x0C00) +#define LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0 (RX_START_OFFSET + 0x0C04) +#define LPASS_CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL \ + (RX_START_OFFSET + 0x0C40) +#define LPASS_CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0 (RX_START_OFFSET + 0x0C44) +#define LPASS_CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL \ + (RX_START_OFFSET + 0x0C80) +#define LPASS_CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0 (RX_START_OFFSET + 0x0C84) +#define LPASS_CDC_RX_EC_ASRC0_CLK_RST_CTL (RX_START_OFFSET + 0x0D00) +#define LPASS_CDC_RX_EC_ASRC0_CTL0 (RX_START_OFFSET + 0x0D04) +#define LPASS_CDC_RX_EC_ASRC0_CTL1 (RX_START_OFFSET + 0x0D08) +#define LPASS_CDC_RX_EC_ASRC0_FIFO_CTL (RX_START_OFFSET + 0x0D0C) +#define LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB \ + (RX_START_OFFSET + 0x0D10) +#define LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB \ + (RX_START_OFFSET + 0x0D14) +#define LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB \ + (RX_START_OFFSET + 0x0D18) +#define LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB \ + (RX_START_OFFSET + 0x0D1C) +#define LPASS_CDC_RX_EC_ASRC0_STATUS_FIFO (RX_START_OFFSET + 0x0D20) +#define LPASS_CDC_RX_EC_ASRC1_CLK_RST_CTL (RX_START_OFFSET + 0x0D40) +#define LPASS_CDC_RX_EC_ASRC1_CTL0 (RX_START_OFFSET + 0x0D44) +#define LPASS_CDC_RX_EC_ASRC1_CTL1 (RX_START_OFFSET + 0x0D48) +#define LPASS_CDC_RX_EC_ASRC1_FIFO_CTL (RX_START_OFFSET + 0x0D4C) +#define LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB \ + (RX_START_OFFSET + 0x0D50) +#define LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB \ + (RX_START_OFFSET + 0x0D54) +#define LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB \ + (RX_START_OFFSET + 0x0D58) +#define LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB \ + (RX_START_OFFSET + 0x0D5C) +#define LPASS_CDC_RX_EC_ASRC1_STATUS_FIFO (RX_START_OFFSET + 0x0D60) +#define LPASS_CDC_RX_EC_ASRC2_CLK_RST_CTL (RX_START_OFFSET + 0x0D80) +#define LPASS_CDC_RX_EC_ASRC2_CTL0 (RX_START_OFFSET + 0x0D84) +#define LPASS_CDC_RX_EC_ASRC2_CTL1 (RX_START_OFFSET + 0x0D88) +#define LPASS_CDC_RX_EC_ASRC2_FIFO_CTL (RX_START_OFFSET + 0x0D8C) +#define LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB \ + (RX_START_OFFSET + 0x0D90) +#define LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB \ + (RX_START_OFFSET + 0x0D94) +#define LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB \ + (RX_START_OFFSET + 0x0D98) +#define LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB \ + (RX_START_OFFSET + 0x0D9C) +#define LPASS_CDC_RX_EC_ASRC2_STATUS_FIFO (RX_START_OFFSET + 0x0DA0) +#define LPASS_CDC_RX_DSD0_PATH_CTL (RX_START_OFFSET + 0x0F00) +#define LPASS_CDC_RX_DSD0_CFG0 (RX_START_OFFSET + 0x0F04) +#define LPASS_CDC_RX_DSD0_CFG1 (RX_START_OFFSET + 0x0F08) +#define LPASS_CDC_RX_DSD0_CFG2 (RX_START_OFFSET + 0x0F0C) +#define LPASS_CDC_RX_DSD1_PATH_CTL (RX_START_OFFSET + 0x0F80) +#define LPASS_CDC_RX_DSD1_CFG0 (RX_START_OFFSET + 0x0F84) +#define LPASS_CDC_RX_DSD1_CFG1 (RX_START_OFFSET + 0x0F88) +#define LPASS_CDC_RX_DSD1_CFG2 (RX_START_OFFSET + 0x0F8C) + +#ifdef CONFIG_BOLERO_VER_2P6 +#define LPASS_CDC_RX_RX0_RX_FIR_CTL (RX_START_OFFSET + 0x045C) +#define LPASS_CDC_RX_RX0_RX_FIR_CFG (RX_START_OFFSET + 0x0460) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_ADDR (RX_START_OFFSET + 0x0464) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA0 (RX_START_OFFSET + 0x0468) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA1 (RX_START_OFFSET + 0x046C) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA2 (RX_START_OFFSET + 0x0470) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA3 (RX_START_OFFSET + 0x0474) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA4 (RX_START_OFFSET + 0x0478) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA5 (RX_START_OFFSET + 0x047C) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA6 (RX_START_OFFSET + 0x0480) +#define LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA7 (RX_START_OFFSET + 0x0484) +#define LPASS_CDC_RX_RX1_RX_PATH_CTL (RX_START_OFFSET + 0x04C0) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG0 (RX_START_OFFSET + 0x04C4) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG1 (RX_START_OFFSET + 0x04C8) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG2 (RX_START_OFFSET + 0x04CC) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG3 (RX_START_OFFSET + 0x04D0) +#define LPASS_CDC_RX_RX1_RX_VOL_CTL (RX_START_OFFSET + 0x04D4) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x04D8) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x04DC) +#define LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x04E0) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC1 (RX_START_OFFSET + 0x04E4) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC2 (RX_START_OFFSET + 0x04E8) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC3 (RX_START_OFFSET + 0x04EC) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC4 (RX_START_OFFSET + 0x04F0) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC7 (RX_START_OFFSET + 0x04F4) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x04F8) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x04FC) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x0500) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA1 (RX_START_OFFSET + 0x0504) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA2 (RX_START_OFFSET + 0x0508) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA3 (RX_START_OFFSET + 0x050C) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA4 (RX_START_OFFSET + 0x0510) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA5 (RX_START_OFFSET + 0x0514) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA6 (RX_START_OFFSET + 0x0518) +#define LPASS_CDC_RX_RX1_RX_FIR_CTL (RX_START_OFFSET + 0x051C) +#define LPASS_CDC_RX_RX1_RX_FIR_CFG (RX_START_OFFSET + 0x0520) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_ADDR (RX_START_OFFSET + 0x0524) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA0 (RX_START_OFFSET + 0x0528) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA1 (RX_START_OFFSET + 0x052C) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA2 (RX_START_OFFSET + 0x0530) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA3 (RX_START_OFFSET + 0x0534) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA4 (RX_START_OFFSET + 0x0538) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA5 (RX_START_OFFSET + 0x053C) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA6 (RX_START_OFFSET + 0x0540) +#define LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA7 (RX_START_OFFSET + 0x0544) +#define LPASS_CDC_RX_RX2_RX_PATH_CTL (RX_START_OFFSET + 0x0580) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG0 (RX_START_OFFSET + 0x0584) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG1 (RX_START_OFFSET + 0x0588) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG2 (RX_START_OFFSET + 0x058C) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG3 (RX_START_OFFSET + 0x0590) +#define LPASS_CDC_RX_RX2_RX_VOL_CTL (RX_START_OFFSET + 0x0594) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x0598) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x059C) +#define LPASS_CDC_RX_RX2_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x05A0) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC0 (RX_START_OFFSET + 0x05A4) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC1 (RX_START_OFFSET + 0x05A8) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC2 (RX_START_OFFSET + 0x05AC) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC3 (RX_START_OFFSET + 0x05B0) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC4 (RX_START_OFFSET + 0x05B4) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC5 (RX_START_OFFSET + 0x05B8) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC6 (RX_START_OFFSET + 0x05BC) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC7 (RX_START_OFFSET + 0x05C0) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x05C4) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x05C8) +#define LPASS_CDC_RX_RX2_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x05CC) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL1 (RX_START_OFFSET + 0x0600) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL2 (RX_START_OFFSET + 0x0604) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL3 (RX_START_OFFSET + 0x0608) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG1 (RX_START_OFFSET + 0x060C) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG2 (RX_START_OFFSET + 0x0610) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG3 (RX_START_OFFSET + 0x0614) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG4 (RX_START_OFFSET + 0x0618) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG5 (RX_START_OFFSET + 0x061C) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG6 (RX_START_OFFSET + 0x0620) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG7 (RX_START_OFFSET + 0x0624) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG8 (RX_START_OFFSET + 0x0628) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST1 (RX_START_OFFSET + 0x062C) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST2 (RX_START_OFFSET + 0x0630) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST3 (RX_START_OFFSET + 0x0634) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST4 (RX_START_OFFSET + 0x0638) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST1 (RX_START_OFFSET + 0x063C) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST2 (RX_START_OFFSET + 0x0640) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST3 (RX_START_OFFSET + 0x0644) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST4 (RX_START_OFFSET + 0x0648) +#define LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST5 (RX_START_OFFSET + 0x064C) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_PATH_CTL (RX_START_OFFSET + 0x0680) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_CFG (RX_START_OFFSET + 0x0684) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL1 (RX_START_OFFSET + 0x0688) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL2 (RX_START_OFFSET + 0x068C) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL3 (RX_START_OFFSET + 0x0690) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST1 (RX_START_OFFSET + 0x0694) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST2 (RX_START_OFFSET + 0x0698) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST3 (RX_START_OFFSET + 0x069C) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_RF_PROC1 (RX_START_OFFSET + 0x06A0) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_RF_PROC2 (RX_START_OFFSET + 0x06A4) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC1 (RX_START_OFFSET + 0x06A8) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC2 (RX_START_OFFSET + 0x06AC) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC3 (RX_START_OFFSET + 0x06B0) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC4 (RX_START_OFFSET + 0x06B4) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD1 (RX_START_OFFSET + 0x06B8) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD2 (RX_START_OFFSET + 0x06BC) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD3 (RX_START_OFFSET + 0x06C0) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD4 (RX_START_OFFSET + 0x06C4) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD5 (RX_START_OFFSET + 0x06C8) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_DEBUG1 (RX_START_OFFSET + 0x06CC) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD_MON \ + (RX_START_OFFSET + 0x06D0) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_MON_VAL \ + (RX_START_OFFSET + 0x06D4) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BAN (RX_START_OFFSET + 0x06D8) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD1 \ + (RX_START_OFFSET + 0x06DC) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD2 \ + (RX_START_OFFSET + 0x06E0) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD3 \ + (RX_START_OFFSET + 0x06E4) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD4 \ + (RX_START_OFFSET + 0x06E8) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD5 \ + (RX_START_OFFSET + 0x06EC) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD6 \ + (RX_START_OFFSET + 0x06F0) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD7 \ + (RX_START_OFFSET + 0x06F4) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD8 \ + (RX_START_OFFSET + 0x06F8) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD9 \ + (RX_START_OFFSET + 0x06FC) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN1 (RX_START_OFFSET + 0x0700) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN2 (RX_START_OFFSET + 0x0704) +#define LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN3 (RX_START_OFFSET + 0x0708) + +#define LPASS_CDC_RX_COMPANDER0_CTL8 (RX_START_OFFSET + 0x0820) +#define LPASS_CDC_RX_COMPANDER0_CTL9 (RX_START_OFFSET + 0x0824) +#define LPASS_CDC_RX_COMPANDER0_CTL10 (RX_START_OFFSET + 0x0828) +#define LPASS_CDC_RX_COMPANDER0_CTL11 (RX_START_OFFSET + 0x082C) +#define LPASS_CDC_RX_COMPANDER0_CTL12 (RX_START_OFFSET + 0x0830) +#define LPASS_CDC_RX_COMPANDER0_CTL13 (RX_START_OFFSET + 0x0834) +#define LPASS_CDC_RX_COMPANDER0_CTL14 (RX_START_OFFSET + 0x0838) +#define LPASS_CDC_RX_COMPANDER0_CTL15 (RX_START_OFFSET + 0x083C) +#define LPASS_CDC_RX_COMPANDER0_CTL16 (RX_START_OFFSET + 0x0840) +#define LPASS_CDC_RX_COMPANDER0_CTL17 (RX_START_OFFSET + 0x0844) +#define LPASS_CDC_RX_COMPANDER0_CTL18 (RX_START_OFFSET + 0x0848) +#define LPASS_CDC_RX_COMPANDER0_CTL19 (RX_START_OFFSET + 0x084C) +#define LPASS_CDC_RX_COMPANDER1_CTL0 (RX_START_OFFSET + 0x0860) +#define LPASS_CDC_RX_COMPANDER1_CTL1 (RX_START_OFFSET + 0x0864) +#define LPASS_CDC_RX_COMPANDER1_CTL2 (RX_START_OFFSET + 0x0868) +#define LPASS_CDC_RX_COMPANDER1_CTL3 (RX_START_OFFSET + 0x086C) +#define LPASS_CDC_RX_COMPANDER1_CTL4 (RX_START_OFFSET + 0x0870) +#define LPASS_CDC_RX_COMPANDER1_CTL5 (RX_START_OFFSET + 0x0874) +#define LPASS_CDC_RX_COMPANDER1_CTL6 (RX_START_OFFSET + 0x0878) +#define LPASS_CDC_RX_COMPANDER1_CTL7 (RX_START_OFFSET + 0x087C) +#define LPASS_CDC_RX_COMPANDER1_CTL8 (RX_START_OFFSET + 0x0880) +#define LPASS_CDC_RX_COMPANDER1_CTL9 (RX_START_OFFSET + 0x0884) +#define LPASS_CDC_RX_COMPANDER1_CTL10 (RX_START_OFFSET + 0x0888) +#define LPASS_CDC_RX_COMPANDER1_CTL11 (RX_START_OFFSET + 0x088C) +#define LPASS_CDC_RX_COMPANDER1_CTL12 (RX_START_OFFSET + 0x0890) +#define LPASS_CDC_RX_COMPANDER1_CTL13 (RX_START_OFFSET + 0x0894) +#define LPASS_CDC_RX_COMPANDER1_CTL14 (RX_START_OFFSET + 0x0898) +#define LPASS_CDC_RX_COMPANDER1_CTL15 (RX_START_OFFSET + 0x089C) +#define LPASS_CDC_RX_COMPANDER1_CTL16 (RX_START_OFFSET + 0x08A0) +#define LPASS_CDC_RX_COMPANDER1_CTL17 (RX_START_OFFSET + 0x08A4) +#define LPASS_CDC_RX_COMPANDER1_CTL18 (RX_START_OFFSET + 0x08A8) +#define LPASS_CDC_RX_COMPANDER1_CTL19 (RX_START_OFFSET + 0x08AC) +#else +#define LPASS_CDC_RX_BCL_VBAT_DECODE_CTL1 (RX_START_OFFSET + 0x030C) +#define LPASS_CDC_RX_BCL_VBAT_DECODE_CTL2 (RX_START_OFFSET + 0x0310) +#define LPASS_CDC_RX_BCL_VBAT_DECODE_CFG1 (RX_START_OFFSET + 0x0314) +#define LPASS_CDC_RX_BCL_VBAT_DECODE_CFG2 (RX_START_OFFSET + 0x0318) +#define LPASS_CDC_RX_BCL_VBAT_DECODE_CFG3 (RX_START_OFFSET + 0x031C) +#define LPASS_CDC_RX_BCL_VBAT_DECODE_CFG4 (RX_START_OFFSET + 0x0320) +#define LPASS_CDC_RX_BCL_VBAT_DECODE_ST (RX_START_OFFSET + 0x0324) +#define LPASS_CDC_RX_RX1_RX_PATH_CTL (RX_START_OFFSET + 0x0480) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG0 (RX_START_OFFSET + 0x0484) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG1 (RX_START_OFFSET + 0x0488) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG2 (RX_START_OFFSET + 0x048C) +#define LPASS_CDC_RX_RX1_RX_PATH_CFG3 (RX_START_OFFSET + 0x0490) +#define LPASS_CDC_RX_RX1_RX_VOL_CTL (RX_START_OFFSET + 0x0494) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x0498) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x049C) +#define LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x04A0) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC1 (RX_START_OFFSET + 0x04A4) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC2 (RX_START_OFFSET + 0x04A8) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC3 (RX_START_OFFSET + 0x04AC) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC4 (RX_START_OFFSET + 0x04B0) +#define LPASS_CDC_RX_RX1_RX_PATH_SEC7 (RX_START_OFFSET + 0x04B4) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x04B8) +#define LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x04BC) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x04C0) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA1 (RX_START_OFFSET + 0x04C4) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA2 (RX_START_OFFSET + 0x04C8) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA3 (RX_START_OFFSET + 0x04CC) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA4 (RX_START_OFFSET + 0x04D0) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA5 (RX_START_OFFSET + 0x04D4) +#define LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA6 (RX_START_OFFSET + 0x04D8) +#define LPASS_CDC_RX_RX2_RX_PATH_CTL (RX_START_OFFSET + 0x0500) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG0 (RX_START_OFFSET + 0x0504) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG1 (RX_START_OFFSET + 0x0508) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG2 (RX_START_OFFSET + 0x050C) +#define LPASS_CDC_RX_RX2_RX_PATH_CFG3 (RX_START_OFFSET + 0x0510) +#define LPASS_CDC_RX_RX2_RX_VOL_CTL (RX_START_OFFSET + 0x0514) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_CTL (RX_START_OFFSET + 0x0518) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_CFG (RX_START_OFFSET + 0x051C) +#define LPASS_CDC_RX_RX2_RX_VOL_MIX_CTL (RX_START_OFFSET + 0x0520) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC0 (RX_START_OFFSET + 0x0524) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC1 (RX_START_OFFSET + 0x0528) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC2 (RX_START_OFFSET + 0x052C) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC3 (RX_START_OFFSET + 0x0530) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC4 (RX_START_OFFSET + 0x0534) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC5 (RX_START_OFFSET + 0x0538) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC6 (RX_START_OFFSET + 0x053C) +#define LPASS_CDC_RX_RX2_RX_PATH_SEC7 (RX_START_OFFSET + 0x0540) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC0 (RX_START_OFFSET + 0x0544) +#define LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC1 (RX_START_OFFSET + 0x0548) +#define LPASS_CDC_RX_RX2_RX_PATH_DSM_CTL (RX_START_OFFSET + 0x054C) +#define LPASS_CDC_RX_COMPANDER1_CTL0 (RX_START_OFFSET + 0x0840) +#define LPASS_CDC_RX_COMPANDER1_CTL1 (RX_START_OFFSET + 0x0844) +#define LPASS_CDC_RX_COMPANDER1_CTL2 (RX_START_OFFSET + 0x0848) +#define LPASS_CDC_RX_COMPANDER1_CTL3 (RX_START_OFFSET + 0x084C) +#define LPASS_CDC_RX_COMPANDER1_CTL4 (RX_START_OFFSET + 0x0850) +#define LPASS_CDC_RX_COMPANDER1_CTL5 (RX_START_OFFSET + 0x0854) +#define LPASS_CDC_RX_COMPANDER1_CTL6 (RX_START_OFFSET + 0x0858) +#define LPASS_CDC_RX_COMPANDER1_CTL7 (RX_START_OFFSET + 0x085C) +#endif +#define RX_MAX_OFFSET (RX_START_OFFSET + 0x0F8C) + +#define LPASS_CDC_RX_MACRO_MAX 0x3E4 /* F8C/4 = 3E3 + 1 */ + +/* WSA - macro#2 */ +#define WSA_START_OFFSET 0x2000 +#define LPASS_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL \ + (WSA_START_OFFSET + 0x0000) +#define LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL \ + (WSA_START_OFFSET + 0x0004) +#define LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL (WSA_START_OFFSET + 0x0008) +#define LPASS_CDC_WSA_TOP_TOP_CFG0 (WSA_START_OFFSET + 0x0080) +#define LPASS_CDC_WSA_TOP_TOP_CFG1 (WSA_START_OFFSET + 0x0084) +#define LPASS_CDC_WSA_TOP_FREQ_MCLK (WSA_START_OFFSET + 0x0088) +#define LPASS_CDC_WSA_TOP_DEBUG_BUS_SEL (WSA_START_OFFSET + 0x008C) +#define LPASS_CDC_WSA_TOP_DEBUG_EN0 (WSA_START_OFFSET + 0x0090) +#define LPASS_CDC_WSA_TOP_DEBUG_EN1 (WSA_START_OFFSET + 0x0094) +#define LPASS_CDC_WSA_TOP_DEBUG_DSM_LB (WSA_START_OFFSET + 0x0098) +#define LPASS_CDC_WSA_TOP_RX_I2S_CTL (WSA_START_OFFSET + 0x009C) +#define LPASS_CDC_WSA_TOP_TX_I2S_CTL (WSA_START_OFFSET + 0x00A0) +#define LPASS_CDC_WSA_TOP_I2S_CLK (WSA_START_OFFSET + 0x00A4) +#define LPASS_CDC_WSA_TOP_I2S_RESET (WSA_START_OFFSET + 0x00A8) +#define LPASS_CDC_WSA_TOP_FS_UNGATE (WSA_START_OFFSET + 0x00AC) +#define LPASS_CDC_WSA_TOP_GRP_SEL (WSA_START_OFFSET + 0x00B0) +#define LPASS_CDC_WSA_TOP_SPKR_COMP7_WR_LSB (WSA_START_OFFSET + 0x00B4) +#define LPASS_CDC_WSA_TOP_SPKR_COMP7_WR_MSB (WSA_START_OFFSET + 0x00B8) +#define LPASS_CDC_WSA_TOP_SPKR_COMP7_LUT (WSA_START_OFFSET + 0x00BC) +#define LPASS_CDC_WSA_TOP_SPKR_COMP7_RD_LSB (WSA_START_OFFSET + 0x00C0) +#define LPASS_CDC_WSA_TOP_SPKR_COMP7_RD_MSB (WSA_START_OFFSET + 0x00C4) +#define LPASS_CDC_WSA_TOP_SPKR_COMP8_WR_LSB (WSA_START_OFFSET + 0x00C8) +#define LPASS_CDC_WSA_TOP_SPKR_COMP8_WR_MSB (WSA_START_OFFSET + 0x00CC) +#define LPASS_CDC_WSA_TOP_SPKR_COMP8_LUT (WSA_START_OFFSET + 0x00D0) +#define LPASS_CDC_WSA_TOP_SPKR_COMP8_RD_LSB (WSA_START_OFFSET + 0x00D4) +#define LPASS_CDC_WSA_TOP_SPKR_COMP8_RD_MSB (WSA_START_OFFSET + 0x00D8) +#define LPASS_CDC_WSA_TOP_FS_UNGATE2 (WSA_START_OFFSET + 0x00DC) +#define LPASS_CDC_WSA_TOP_SEQ_CTL0 (WSA_START_OFFSET + 0x00E0) +#define LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (WSA_START_OFFSET + 0x0100) +#define LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (WSA_START_OFFSET + 0x0104) +#define LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (WSA_START_OFFSET + 0x0108) +#define LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (WSA_START_OFFSET + 0x010C) +#define LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (WSA_START_OFFSET + 0x0110) +#define LPASS_CDC_WSA_RX_INP_MUX_RX_EC_CFG0 (WSA_START_OFFSET + 0x0114) +#define LPASS_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0 (WSA_START_OFFSET + 0x0118) +/* VBAT registers */ +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL (WSA_START_OFFSET + 0x0180) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG (WSA_START_OFFSET + 0x0184) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1 (WSA_START_OFFSET + 0x0188) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2 (WSA_START_OFFSET + 0x018C) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3 (WSA_START_OFFSET + 0x0190) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST1 (WSA_START_OFFSET + 0x0194) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST2 (WSA_START_OFFSET + 0x0198) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST3 (WSA_START_OFFSET + 0x019C) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1 (WSA_START_OFFSET + 0x01A0) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2 (WSA_START_OFFSET + 0x01A4) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC1 (WSA_START_OFFSET + 0x01A8) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC2 (WSA_START_OFFSET + 0x01AC) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC3 (WSA_START_OFFSET + 0x01B0) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC4 (WSA_START_OFFSET + 0x01B4) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1 (WSA_START_OFFSET + 0x01B8) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2 (WSA_START_OFFSET + 0x01BC) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3 (WSA_START_OFFSET + 0x01C0) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4 (WSA_START_OFFSET + 0x01C4) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5 (WSA_START_OFFSET + 0x01C8) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_DEBUG1 (WSA_START_OFFSET + 0x01CC) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON \ + (WSA_START_OFFSET + 0x01D0) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL \ + (WSA_START_OFFSET + 0x01D4) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BAN (WSA_START_OFFSET + 0x01D8) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1 \ + (WSA_START_OFFSET + 0x01DC) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2 \ + (WSA_START_OFFSET + 0x01E0) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3 \ + (WSA_START_OFFSET + 0x01E4) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4 \ + (WSA_START_OFFSET + 0x01E8) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5 \ + (WSA_START_OFFSET + 0x01EC) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6 \ + (WSA_START_OFFSET + 0x01F0) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7 \ + (WSA_START_OFFSET + 0x01F4) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8 \ + (WSA_START_OFFSET + 0x01F8) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9 \ + (WSA_START_OFFSET + 0x01FC) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1 (WSA_START_OFFSET + 0x0200) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2 (WSA_START_OFFSET + 0x0204) +#define LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3 (WSA_START_OFFSET + 0x0208) +#define LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0244) +#define LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0248) +#define LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0264) +#define LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0268) +#define LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x0284) +#define LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x0288) +#define LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL (WSA_START_OFFSET + 0x02A4) +#define LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0 (WSA_START_OFFSET + 0x02A8) +#define LPASS_CDC_WSA_INTR_CTRL_CFG (WSA_START_OFFSET + 0x0340) +#define LPASS_CDC_WSA_INTR_CTRL_CLR_COMMIT (WSA_START_OFFSET + 0x0344) +#define LPASS_CDC_WSA_INTR_CTRL_PIN1_MASK0 (WSA_START_OFFSET + 0x0360) +#define LPASS_CDC_WSA_INTR_CTRL_PIN1_STATUS0 (WSA_START_OFFSET + 0x0368) +#define LPASS_CDC_WSA_INTR_CTRL_PIN1_CLEAR0 (WSA_START_OFFSET + 0x0370) +#define LPASS_CDC_WSA_INTR_CTRL_PIN2_MASK0 (WSA_START_OFFSET + 0x0380) +#define LPASS_CDC_WSA_INTR_CTRL_PIN2_STATUS0 (WSA_START_OFFSET + 0x0388) +#define LPASS_CDC_WSA_INTR_CTRL_PIN2_CLEAR0 (WSA_START_OFFSET + 0x0390) +#define LPASS_CDC_WSA_INTR_CTRL_LEVEL0 (WSA_START_OFFSET + 0x03C0) +#define LPASS_CDC_WSA_INTR_CTRL_BYPASS0 (WSA_START_OFFSET + 0x03C8) +#define LPASS_CDC_WSA_INTR_CTRL_SET0 (WSA_START_OFFSET + 0x03D0) +#define LPASS_CDC_WSA_RX0_RX_PATH_CTL (WSA_START_OFFSET + 0x0400) +#define LPASS_CDC_WSA_RX0_RX_PATH_CFG0 (WSA_START_OFFSET + 0x0404) +#define LPASS_CDC_WSA_RX0_RX_PATH_CFG1 (WSA_START_OFFSET + 0x0408) +#define LPASS_CDC_WSA_RX0_RX_PATH_CFG2 (WSA_START_OFFSET + 0x040C) +#define LPASS_CDC_WSA_RX0_RX_PATH_CFG3 (WSA_START_OFFSET + 0x0410) +#define LPASS_CDC_WSA_RX0_RX_VOL_CTL (WSA_START_OFFSET + 0x0414) +#define LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL (WSA_START_OFFSET + 0x0418) +#define LPASS_CDC_WSA_RX0_RX_PATH_MIX_CFG (WSA_START_OFFSET + 0x041C) +#define LPASS_CDC_WSA_RX0_RX_VOL_MIX_CTL (WSA_START_OFFSET + 0x0420) +#define LPASS_CDC_WSA_RX0_RX_PATH_SEC0 (WSA_START_OFFSET + 0x0424) +#define LPASS_CDC_WSA_RX0_RX_PATH_SEC1 (WSA_START_OFFSET + 0x0428) +#define LPASS_CDC_WSA_RX0_RX_PATH_SEC2 (WSA_START_OFFSET + 0x042C) +#define LPASS_CDC_WSA_RX0_RX_PATH_SEC3 (WSA_START_OFFSET + 0x0430) +#define LPASS_CDC_WSA_RX0_RX_PATH_SEC5 (WSA_START_OFFSET + 0x0438) +#define LPASS_CDC_WSA_RX0_RX_PATH_SEC6 (WSA_START_OFFSET + 0x043C) +#define LPASS_CDC_WSA_RX0_RX_PATH_SEC7 (WSA_START_OFFSET + 0x0440) +#define LPASS_CDC_WSA_RX0_RX_PATH_MIX_SEC0 (WSA_START_OFFSET + 0x0444) +#define LPASS_CDC_WSA_RX0_RX_PATH_MIX_SEC1 (WSA_START_OFFSET + 0x0448) +#define LPASS_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL (WSA_START_OFFSET + 0x044C) +#define LPASS_CDC_WSA_RX1_RX_PATH_CTL (WSA_START_OFFSET + 0x0480) +#define LPASS_CDC_WSA_RX1_RX_PATH_CFG0 (WSA_START_OFFSET + 0x0484) +#define LPASS_CDC_WSA_RX1_RX_PATH_CFG1 (WSA_START_OFFSET + 0x0488) +#define LPASS_CDC_WSA_RX1_RX_PATH_CFG2 (WSA_START_OFFSET + 0x048C) +#define LPASS_CDC_WSA_RX1_RX_PATH_CFG3 (WSA_START_OFFSET + 0x0490) +#define LPASS_CDC_WSA_RX1_RX_VOL_CTL (WSA_START_OFFSET + 0x0494) +#define LPASS_CDC_WSA_RX1_RX_PATH_MIX_CTL (WSA_START_OFFSET + 0x0498) +#define LPASS_CDC_WSA_RX1_RX_PATH_MIX_CFG (WSA_START_OFFSET + 0x049C) +#define LPASS_CDC_WSA_RX1_RX_VOL_MIX_CTL (WSA_START_OFFSET + 0x04A0) +#define LPASS_CDC_WSA_RX1_RX_PATH_SEC0 (WSA_START_OFFSET + 0x04A4) +#define LPASS_CDC_WSA_RX1_RX_PATH_SEC1 (WSA_START_OFFSET + 0x04A8) +#define LPASS_CDC_WSA_RX1_RX_PATH_SEC2 (WSA_START_OFFSET + 0x04AC) +#define LPASS_CDC_WSA_RX1_RX_PATH_SEC3 (WSA_START_OFFSET + 0x04B0) +#define LPASS_CDC_WSA_RX1_RX_PATH_SEC5 (WSA_START_OFFSET + 0x04B8) +#define LPASS_CDC_WSA_RX1_RX_PATH_SEC6 (WSA_START_OFFSET + 0x04BC) +#define LPASS_CDC_WSA_RX1_RX_PATH_SEC7 (WSA_START_OFFSET + 0x04C0) +#define LPASS_CDC_WSA_RX1_RX_PATH_MIX_SEC0 (WSA_START_OFFSET + 0x04C4) +#define LPASS_CDC_WSA_RX1_RX_PATH_MIX_SEC1 (WSA_START_OFFSET + 0x04C8) +#define LPASS_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL (WSA_START_OFFSET + 0x04CC) +#define LPASS_CDC_WSA_BOOST0_BOOST_PATH_CTL (WSA_START_OFFSET + 0x0500) +#define LPASS_CDC_WSA_BOOST0_BOOST_CTL (WSA_START_OFFSET + 0x0504) +#define LPASS_CDC_WSA_BOOST0_BOOST_CFG1 (WSA_START_OFFSET + 0x0508) +#define LPASS_CDC_WSA_BOOST0_BOOST_CFG2 (WSA_START_OFFSET + 0x050C) +#define LPASS_CDC_WSA_BOOST1_BOOST_PATH_CTL (WSA_START_OFFSET + 0x0540) +#define LPASS_CDC_WSA_BOOST1_BOOST_CTL (WSA_START_OFFSET + 0x0544) +#define LPASS_CDC_WSA_BOOST1_BOOST_CFG1 (WSA_START_OFFSET + 0x0548) +#define LPASS_CDC_WSA_BOOST1_BOOST_CFG2 (WSA_START_OFFSET + 0x054C) +#define LPASS_CDC_WSA_COMPANDER0_CTL0 (WSA_START_OFFSET + 0x0580) +#define LPASS_CDC_WSA_COMPANDER0_CTL1 (WSA_START_OFFSET + 0x0584) +#define LPASS_CDC_WSA_COMPANDER0_CTL2 (WSA_START_OFFSET + 0x0588) +#define LPASS_CDC_WSA_COMPANDER0_CTL3 (WSA_START_OFFSET + 0x058C) +#define LPASS_CDC_WSA_COMPANDER0_CTL4 (WSA_START_OFFSET + 0x0590) +#define LPASS_CDC_WSA_COMPANDER0_CTL5 (WSA_START_OFFSET + 0x0594) +#define LPASS_CDC_WSA_COMPANDER0_CTL6 (WSA_START_OFFSET + 0x0598) +#define LPASS_CDC_WSA_COMPANDER0_CTL7 (WSA_START_OFFSET + 0x059C) +#define LPASS_CDC_WSA_COMPANDER0_CTL8 (WSA_START_OFFSET + 0x05A0) +#define LPASS_CDC_WSA_COMPANDER0_CTL9 (WSA_START_OFFSET + 0x05A4) +#define LPASS_CDC_WSA_COMPANDER0_CTL10 (WSA_START_OFFSET + 0x05A8) +#define LPASS_CDC_WSA_COMPANDER0_CTL11 (WSA_START_OFFSET + 0x05AC) +#define LPASS_CDC_WSA_COMPANDER0_CTL12 (WSA_START_OFFSET + 0x05B0) +#define LPASS_CDC_WSA_COMPANDER0_CTL13 (WSA_START_OFFSET + 0x05B4) +#define LPASS_CDC_WSA_COMPANDER0_CTL14 (WSA_START_OFFSET + 0x05B8) +#define LPASS_CDC_WSA_COMPANDER0_CTL15 (WSA_START_OFFSET + 0x05BC) +#define LPASS_CDC_WSA_COMPANDER0_CTL16 (WSA_START_OFFSET + 0x05C0) +#define LPASS_CDC_WSA_COMPANDER0_CTL17 (WSA_START_OFFSET + 0x05C4) +#define LPASS_CDC_WSA_COMPANDER0_CTL18 (WSA_START_OFFSET + 0x05C8) +#define LPASS_CDC_WSA_COMPANDER0_CTL19 (WSA_START_OFFSET + 0x05CC) +#define LPASS_CDC_WSA_COMPANDER1_CTL0 (WSA_START_OFFSET + 0x05E0) +#define LPASS_CDC_WSA_COMPANDER1_CTL1 (WSA_START_OFFSET + 0x05E4) +#define LPASS_CDC_WSA_COMPANDER1_CTL2 (WSA_START_OFFSET + 0x05E8) +#define LPASS_CDC_WSA_COMPANDER1_CTL3 (WSA_START_OFFSET + 0x05EC) +#define LPASS_CDC_WSA_COMPANDER1_CTL4 (WSA_START_OFFSET + 0x05F0) +#define LPASS_CDC_WSA_COMPANDER1_CTL5 (WSA_START_OFFSET + 0x05F4) +#define LPASS_CDC_WSA_COMPANDER1_CTL6 (WSA_START_OFFSET + 0x05F8) +#define LPASS_CDC_WSA_COMPANDER1_CTL7 (WSA_START_OFFSET + 0x05FC) +#define LPASS_CDC_WSA_COMPANDER1_CTL8 (WSA_START_OFFSET + 0x0600) +#define LPASS_CDC_WSA_COMPANDER1_CTL9 (WSA_START_OFFSET + 0x0604) +#define LPASS_CDC_WSA_COMPANDER1_CTL10 (WSA_START_OFFSET + 0x0608) +#define LPASS_CDC_WSA_COMPANDER1_CTL11 (WSA_START_OFFSET + 0x060C) +#define LPASS_CDC_WSA_COMPANDER1_CTL12 (WSA_START_OFFSET + 0x0610) +#define LPASS_CDC_WSA_COMPANDER1_CTL13 (WSA_START_OFFSET + 0x0614) +#define LPASS_CDC_WSA_COMPANDER1_CTL14 (WSA_START_OFFSET + 0x0618) +#define LPASS_CDC_WSA_COMPANDER1_CTL15 (WSA_START_OFFSET + 0x061C) +#define LPASS_CDC_WSA_COMPANDER1_CTL16 (WSA_START_OFFSET + 0x0620) +#define LPASS_CDC_WSA_COMPANDER1_CTL17 (WSA_START_OFFSET + 0x0624) +#define LPASS_CDC_WSA_COMPANDER1_CTL18 (WSA_START_OFFSET + 0x0628) +#define LPASS_CDC_WSA_COMPANDER1_CTL19 (WSA_START_OFFSET + 0x062C) +#define LPASS_CDC_WSA_SOFTCLIP0_CRC (WSA_START_OFFSET + 0x0640) +#define LPASS_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (WSA_START_OFFSET + 0x0644) +#define LPASS_CDC_WSA_SOFTCLIP1_CRC (WSA_START_OFFSET + 0x0660) +#define LPASS_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (WSA_START_OFFSET + 0x0664) +#define LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL \ + (WSA_START_OFFSET + 0x0680) +#define LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 (WSA_START_OFFSET + 0x0684) +#define LPASS_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL \ + (WSA_START_OFFSET + 0x06C0) +#define LPASS_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0 (WSA_START_OFFSET + 0x06C4) +#define LPASS_CDC_WSA_IDLE_DETECT_PATH_CTL (WSA_START_OFFSET + 0x0780) +#define LPASS_CDC_WSA_IDLE_DETECT_CFG0 (WSA_START_OFFSET + 0x0784) +#define LPASS_CDC_WSA_IDLE_DETECT_CFG1 (WSA_START_OFFSET + 0x0788) +#define LPASS_CDC_WSA_IDLE_DETECT_CFG2 (WSA_START_OFFSET + 0x078C) +#define LPASS_CDC_WSA_IDLE_DETECT_CFG3 (WSA_START_OFFSET + 0x0790) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL1 (WSA_START_OFFSET + 0x0900) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL2 (WSA_START_OFFSET + 0x0904) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL3 (WSA_START_OFFSET + 0x0908) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG1 (WSA_START_OFFSET + 0x090C) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG2 (WSA_START_OFFSET + 0x0910) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG3 (WSA_START_OFFSET + 0x0914) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG4 (WSA_START_OFFSET + 0x0918) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG5 (WSA_START_OFFSET + 0x091C) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG6 (WSA_START_OFFSET + 0x0920) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG7 (WSA_START_OFFSET + 0x0924) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG8 (WSA_START_OFFSET + 0x0928) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST1 \ + (WSA_START_OFFSET + 0x092C) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST2 \ + (WSA_START_OFFSET + 0x0930) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST3 \ + (WSA_START_OFFSET + 0x0934) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST4 \ + (WSA_START_OFFSET + 0x0938) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST1 (WSA_START_OFFSET + 0x093C) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST2 (WSA_START_OFFSET + 0x0940) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST3 (WSA_START_OFFSET + 0x0944) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST4 (WSA_START_OFFSET + 0x0948) +#define LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST5 (WSA_START_OFFSET + 0x094C) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_PATH_CTL (WSA_START_OFFSET + 0x0980) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_CFG (WSA_START_OFFSET + 0x0984) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL1 (WSA_START_OFFSET + 0x0988) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL2 (WSA_START_OFFSET + 0x098C) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL3 (WSA_START_OFFSET + 0x0990) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST1 (WSA_START_OFFSET + 0x0994) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST2 (WSA_START_OFFSET + 0x0998) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST3 (WSA_START_OFFSET + 0x099C) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_RF_PROC1 (WSA_START_OFFSET + 0x09A0) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_RF_PROC2 (WSA_START_OFFSET + 0x09A4) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC1 (WSA_START_OFFSET + 0x09A8) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC2 (WSA_START_OFFSET + 0x09AC) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC3 (WSA_START_OFFSET + 0x09B0) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC4 (WSA_START_OFFSET + 0x09B4) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD1 (WSA_START_OFFSET + 0x09B8) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD2 (WSA_START_OFFSET + 0x09BC) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD3 (WSA_START_OFFSET + 0x09C0) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD4 (WSA_START_OFFSET + 0x09C4) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD5 (WSA_START_OFFSET + 0x09C8) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_DEBUG1 (WSA_START_OFFSET + 0x09CC) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD_MON \ + (WSA_START_OFFSET + 0x09D0) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_MON_VAL \ + (WSA_START_OFFSET + 0x09D4) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BAN (WSA_START_OFFSET + 0x09D8) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD1 \ + (WSA_START_OFFSET + 0x09DC) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD2 \ + (WSA_START_OFFSET + 0x09E0) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD3 \ + (WSA_START_OFFSET + 0x09E4) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD4 \ + (WSA_START_OFFSET + 0x09E8) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD5 \ + (WSA_START_OFFSET + 0x09EC) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD6 \ + (WSA_START_OFFSET + 0x09F0) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD7 \ + (WSA_START_OFFSET + 0x09F4) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD8 \ + (WSA_START_OFFSET + 0x09F8) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD9 \ + (WSA_START_OFFSET + 0x09FC) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN1 (WSA_START_OFFSET + 0x0A00) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN2 (WSA_START_OFFSET + 0x0A04) +#define LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN3 (WSA_START_OFFSET + 0x0A08) +/* lpass 2.6 new registers */ +#define LPASS_CDC_WSA_PBR_PATH_CTL (WSA_START_OFFSET + 0xB00) +#define LPASS_CDC_WSA_LA_CFG (WSA_START_OFFSET + 0xB04) +#define LPASS_CDC_WSA_PBR_CFG1 (WSA_START_OFFSET + 0xB08) +#define LPASS_CDC_WSA_PBR_CFG2 (WSA_START_OFFSET + 0xB0C) +#define LPASS_CDC_WSA_PBR_CFG3 (WSA_START_OFFSET + 0xB10) +#define LPASS_CDC_WSA_PBR_CFG4 (WSA_START_OFFSET + 0xB14) +#define LPASS_CDC_WSA_PBR_CFG5 (WSA_START_OFFSET + 0xB18) +#define LPASS_CDC_WSA_PBR_CFG6 (WSA_START_OFFSET + 0xB1C) +#define LPASS_CDC_WSA_PBR_CFG7 (WSA_START_OFFSET + 0xB20) +#define LPASS_CDC_WSA_PBR_CFG8 (WSA_START_OFFSET + 0xB24) +#define LPASS_CDC_WSA_PBR_CFG9 (WSA_START_OFFSET + 0xB28) +#define LPASS_CDC_WSA_PBR_CFG10 (WSA_START_OFFSET + 0xB2C) +#define LPASS_CDC_WSA_PBR_CFG11 (WSA_START_OFFSET + 0xB30) +#define LPASS_CDC_WSA_PBR_CFG12 (WSA_START_OFFSET + 0xB34) +#define LPASS_CDC_WSA_PBR_CFG13 (WSA_START_OFFSET + 0xB38) +#define LPASS_CDC_WSA_PBR_CFG14 (WSA_START_OFFSET + 0xB3C) +#define LPASS_CDC_WSA_PBR_CFG15 (WSA_START_OFFSET + 0xB40) +#define LPASS_CDC_WSA_PBR_CFG16 (WSA_START_OFFSET + 0xB44) +#define LPASS_CDC_WSA_PBR_CFG17 (WSA_START_OFFSET + 0xB48) +#define LPASS_CDC_WSA_ILIM_CFG0 (WSA_START_OFFSET + 0xB4C) +#define LPASS_CDC_WSA_ILIM_CFG1 (WSA_START_OFFSET + 0xB50) +#define LPASS_CDC_WSA_ILIM_CFG2 (WSA_START_OFFSET + 0xB54) +#define LPASS_CDC_WSA_ILIM_CFG3 (WSA_START_OFFSET + 0xB58) +#define LPASS_CDC_WSA_ILIM_CFG4 (WSA_START_OFFSET + 0xB5C) +#define LPASS_CDC_WSA_ILIM_CFG5 (WSA_START_OFFSET + 0xB60) +#define LPASS_CDC_WSA_ILIM_CFG6 (WSA_START_OFFSET + 0xB64) +#define LPASS_CDC_WSA_ILIM_CFG7 (WSA_START_OFFSET + 0xB68) +#define LPASS_CDC_WSA_ILIM_CFG8 (WSA_START_OFFSET + 0xB6C) +#define LPASS_CDC_WSA_LA_CFG_1 (WSA_START_OFFSET + 0xB70) +#define LPASS_CDC_WSA_PBR_CFG1_1 (WSA_START_OFFSET + 0xB74) +#define LPASS_CDC_WSA_PBR_CFG2_1 (WSA_START_OFFSET + 0xB78) +#define LPASS_CDC_WSA_PBR_CFG3_1 (WSA_START_OFFSET + 0xB7C) +#define LPASS_CDC_WSA_PBR_CFG4_1 (WSA_START_OFFSET + 0xB80) +#define LPASS_CDC_WSA_PBR_CFG5_1 (WSA_START_OFFSET + 0xB84) +#define LPASS_CDC_WSA_PBR_CFG6_1 (WSA_START_OFFSET + 0xB88) +#define LPASS_CDC_WSA_PBR_CFG7_1 (WSA_START_OFFSET + 0xB8C) +#define LPASS_CDC_WSA_PBR_CFG8_1 (WSA_START_OFFSET + 0xB90) +#define LPASS_CDC_WSA_PBR_CFG9_1 (WSA_START_OFFSET + 0xB94) +#define LPASS_CDC_WSA_PBR_CFG10_1 (WSA_START_OFFSET + 0xB98) +#define LPASS_CDC_WSA_PBR_CFG11_1 (WSA_START_OFFSET + 0xB9C) +#define LPASS_CDC_WSA_PBR_CFG12_1 (WSA_START_OFFSET + 0xBA0) +#define LPASS_CDC_WSA_PBR_CFG13_1 (WSA_START_OFFSET + 0xBA4) +#define LPASS_CDC_WSA_PBR_CFG14_1 (WSA_START_OFFSET + 0xBA8) +#define LPASS_CDC_WSA_PBR_CFG15_1 (WSA_START_OFFSET + 0xBAC) +#define LPASS_CDC_WSA_PBR_CFG16_1 (WSA_START_OFFSET + 0xBB0) +#define LPASS_CDC_WSA_ILIM_CFG0_1 (WSA_START_OFFSET + 0xBB4) +#define LPASS_CDC_WSA_ILIM_CFG1_1 (WSA_START_OFFSET + 0xBB8) +#define LPASS_CDC_WSA_ILIM_CFG2_1 (WSA_START_OFFSET + 0xBBC) +#define LPASS_CDC_WSA_ILIM_CFG5_1 (WSA_START_OFFSET + 0xBC0) +#define LPASS_CDC_WSA_ILIM_CFG9 (WSA_START_OFFSET + 0xBC4) +#define LPASS_CDC_WSA_ILIM_CFG6_1 (WSA_START_OFFSET + 0xBC8) +#define LPASS_CDC_WSA_PBR_CFG18 (WSA_START_OFFSET + 0xBCC) +#define LPASS_CDC_WSA_PBR_CFG18_1 (WSA_START_OFFSET + 0xBD0) +#define LPASS_CDC_WSA_PBR_CFG19 (WSA_START_OFFSET + 0xBD4) +#define LPASS_CDC_WSA_PBR_CFG20 (WSA_START_OFFSET + 0xBD8) +#define LPASS_CDC_WSA_PBR_CFG21 (WSA_START_OFFSET + 0xBDC) +#define LPASS_CDC_WSA_PBR_CFG22 (WSA_START_OFFSET + 0xBE0) +#define LPASS_CDC_WSA_PBR_CFG23 (WSA_START_OFFSET + 0xBE4) +#define WSA_MAX_OFFSET (WSA_START_OFFSET + 0xBE4) + +#define LPASS_CDC_WSA_MACRO_MAX 0x2FA /* 0xBE4/4 = 0x2F9 + 1 registers */ + +/* VA macro registers */ +#define VA_START_OFFSET 0x3000 +#define LPASS_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL (VA_START_OFFSET + 0x0000) +#define LPASS_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL \ + (VA_START_OFFSET + 0x0004) +#define LPASS_CDC_VA_CLK_RST_CTRL_SWR_CONTROL (VA_START_OFFSET + 0x0008) +#define LPASS_CDC_VA_TOP_CSR_TOP_CFG0 (VA_START_OFFSET + 0x0080) +#define LPASS_CDC_VA_TOP_CSR_DMIC0_CTL (VA_START_OFFSET + 0x0084) +#define LPASS_CDC_VA_TOP_CSR_DMIC1_CTL (VA_START_OFFSET + 0x0088) +#define LPASS_CDC_VA_TOP_CSR_DMIC2_CTL (VA_START_OFFSET + 0x008C) +#define LPASS_CDC_VA_TOP_CSR_DMIC3_CTL (VA_START_OFFSET + 0x0090) +#define LPASS_CDC_VA_TOP_CSR_DMIC_CFG (VA_START_OFFSET + 0x0094) +#define LPASS_CDC_VA_TOP_CSR_VAD_MUX (VA_START_OFFSET + 0x0098) +#define LPASS_CDC_VA_TOP_CSR_DEBUG_BUS (VA_START_OFFSET + 0x009C) +#define LPASS_CDC_VA_TOP_CSR_DEBUG_EN (VA_START_OFFSET + 0x00A0) +#define LPASS_CDC_VA_TOP_CSR_TX_I2S_CTL (VA_START_OFFSET + 0x00A4) +#define LPASS_CDC_VA_TOP_CSR_I2S_CLK (VA_START_OFFSET + 0x00A8) +#define LPASS_CDC_VA_TOP_CSR_I2S_RESET (VA_START_OFFSET + 0x00AC) +#define LPASS_CDC_VA_TOP_CSR_DEBUG_CLK (VA_START_OFFSET + 0x00B0) +#define LPASS_CDC_VA_TOP_CSR_CORE_ID_0 (VA_START_OFFSET + 0x00C0) +#define LPASS_CDC_VA_TOP_CSR_CORE_ID_1 (VA_START_OFFSET + 0x00C4) +#define LPASS_CDC_VA_TOP_CSR_CORE_ID_2 (VA_START_OFFSET + 0x00C8) +#define LPASS_CDC_VA_TOP_CSR_CORE_ID_3 (VA_START_OFFSET + 0x00CC) +#define LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL0 (VA_START_OFFSET + 0x00D0) +#define LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL1 (VA_START_OFFSET + 0x00D4) +#define LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL2 (VA_START_OFFSET + 0x00D8) +#define LPASS_CDC_VA_TOP_CSR_SWR_CTRL (VA_START_OFFSET + 0x00DC) +#define LPASS_CDC_VA_TOP_CSR_SEQ_CTL0 (VA_START_OFFSET + 0x00E0) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0 (VA_START_OFFSET + 0x0100) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG1 (VA_START_OFFSET + 0x0104) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG0 (VA_START_OFFSET + 0x0108) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG1 (VA_START_OFFSET + 0x010C) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG0 (VA_START_OFFSET + 0x0110) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG1 (VA_START_OFFSET + 0x0114) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG0 (VA_START_OFFSET + 0x0118) +#define LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG1 (VA_START_OFFSET + 0x011C) +#define LPASS_CDC_VA_TX0_TX_PATH_CTL (VA_START_OFFSET + 0x0400) +#define LPASS_CDC_VA_TX0_TX_PATH_CFG0 (VA_START_OFFSET + 0x0404) +#define LPASS_CDC_VA_TX0_TX_PATH_CFG1 (VA_START_OFFSET + 0x0408) +#define LPASS_CDC_VA_TX0_TX_VOL_CTL (VA_START_OFFSET + 0x040C) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC0 (VA_START_OFFSET + 0x0410) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC1 (VA_START_OFFSET + 0x0414) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC2 (VA_START_OFFSET + 0x0418) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC3 (VA_START_OFFSET + 0x041C) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC4 (VA_START_OFFSET + 0x0420) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC5 (VA_START_OFFSET + 0x0424) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC6 (VA_START_OFFSET + 0x0428) +#define LPASS_CDC_VA_TX0_TX_PATH_SEC7 (VA_START_OFFSET + 0x042C) +#define LPASS_CDC_VA_TX1_TX_PATH_CTL (VA_START_OFFSET + 0x0480) +#define LPASS_CDC_VA_TX1_TX_PATH_CFG0 (VA_START_OFFSET + 0x0484) +#define LPASS_CDC_VA_TX1_TX_PATH_CFG1 (VA_START_OFFSET + 0x0488) +#define LPASS_CDC_VA_TX1_TX_VOL_CTL (VA_START_OFFSET + 0x048C) +#define LPASS_CDC_VA_TX1_TX_PATH_SEC0 (VA_START_OFFSET + 0x0490) +#define LPASS_CDC_VA_TX1_TX_PATH_SEC1 (VA_START_OFFSET + 0x0494) +#define LPASS_CDC_VA_TX1_TX_PATH_SEC2 (VA_START_OFFSET + 0x0498) +#define LPASS_CDC_VA_TX1_TX_PATH_SEC3 (VA_START_OFFSET + 0x049C) +#define LPASS_CDC_VA_TX1_TX_PATH_SEC4 (VA_START_OFFSET + 0x04A0) +#define LPASS_CDC_VA_TX1_TX_PATH_SEC5 (VA_START_OFFSET + 0x04A4) +#define LPASS_CDC_VA_TX1_TX_PATH_SEC6 (VA_START_OFFSET + 0x04A8) +#define LPASS_CDC_VA_TX2_TX_PATH_CTL (VA_START_OFFSET + 0x0500) +#define LPASS_CDC_VA_TX2_TX_PATH_CFG0 (VA_START_OFFSET + 0x0504) +#define LPASS_CDC_VA_TX2_TX_PATH_CFG1 (VA_START_OFFSET + 0x0508) +#define LPASS_CDC_VA_TX2_TX_VOL_CTL (VA_START_OFFSET + 0x050C) +#define LPASS_CDC_VA_TX2_TX_PATH_SEC0 (VA_START_OFFSET + 0x0510) +#define LPASS_CDC_VA_TX2_TX_PATH_SEC1 (VA_START_OFFSET + 0x0514) +#define LPASS_CDC_VA_TX2_TX_PATH_SEC2 (VA_START_OFFSET + 0x0518) +#define LPASS_CDC_VA_TX2_TX_PATH_SEC3 (VA_START_OFFSET + 0x051C) +#define LPASS_CDC_VA_TX2_TX_PATH_SEC4 (VA_START_OFFSET + 0x0520) +#define LPASS_CDC_VA_TX2_TX_PATH_SEC5 (VA_START_OFFSET + 0x0524) +#define LPASS_CDC_VA_TX2_TX_PATH_SEC6 (VA_START_OFFSET + 0x0528) +#define LPASS_CDC_VA_TX3_TX_PATH_CTL (VA_START_OFFSET + 0x0580) +#define LPASS_CDC_VA_TX3_TX_PATH_CFG0 (VA_START_OFFSET + 0x0584) +#define LPASS_CDC_VA_TX3_TX_PATH_CFG1 (VA_START_OFFSET + 0x0588) +#define LPASS_CDC_VA_TX3_TX_VOL_CTL (VA_START_OFFSET + 0x058C) +#define LPASS_CDC_VA_TX3_TX_PATH_SEC0 (VA_START_OFFSET + 0x0590) +#define LPASS_CDC_VA_TX3_TX_PATH_SEC1 (VA_START_OFFSET + 0x0594) +#define LPASS_CDC_VA_TX3_TX_PATH_SEC2 (VA_START_OFFSET + 0x0598) +#define LPASS_CDC_VA_TX3_TX_PATH_SEC3 (VA_START_OFFSET + 0x059C) +#define LPASS_CDC_VA_TX3_TX_PATH_SEC4 (VA_START_OFFSET + 0x05A0) +#define LPASS_CDC_VA_TX3_TX_PATH_SEC5 (VA_START_OFFSET + 0x05A4) +#define LPASS_CDC_VA_TX3_TX_PATH_SEC6 (VA_START_OFFSET + 0x05A8) +#define VA_MAX_OFFSET (VA_START_OFFSET + 0x05A8) + +#define LPASS_CDC_VA_MACRO_MAX 0x16B /* 5A8/4 = 16A + 1 = 16B */ + +/* WSA2 - macro#5 */ +#define WSA2_START_OFFSET 0x4000 +#define LPASS_CDC_WSA2_CLK_RST_CTRL_MCLK_CONTROL \ + (WSA2_START_OFFSET + 0x0000) +#define LPASS_CDC_WSA2_CLK_RST_CTRL_FS_CNT_CONTROL \ + (WSA2_START_OFFSET + 0x0004) +#define LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL (WSA2_START_OFFSET + 0x0008) +#define LPASS_CDC_WSA2_TOP_TOP_CFG0 (WSA2_START_OFFSET + 0x0080) +#define LPASS_CDC_WSA2_TOP_TOP_CFG1 (WSA2_START_OFFSET + 0x0084) +#define LPASS_CDC_WSA2_TOP_FREQ_MCLK (WSA2_START_OFFSET + 0x0088) +#define LPASS_CDC_WSA2_TOP_DEBUG_BUS_SEL (WSA2_START_OFFSET + 0x008C) +#define LPASS_CDC_WSA2_TOP_DEBUG_EN0 (WSA2_START_OFFSET + 0x0090) +#define LPASS_CDC_WSA2_TOP_DEBUG_EN1 (WSA2_START_OFFSET + 0x0094) +#define LPASS_CDC_WSA2_TOP_DEBUG_DSM_LB (WSA2_START_OFFSET + 0x0098) +#define LPASS_CDC_WSA2_TOP_RX_I2S_CTL (WSA2_START_OFFSET + 0x009C) +#define LPASS_CDC_WSA2_TOP_TX_I2S_CTL (WSA2_START_OFFSET + 0x00A0) +#define LPASS_CDC_WSA2_TOP_I2S_CLK (WSA2_START_OFFSET + 0x00A4) +#define LPASS_CDC_WSA2_TOP_I2S_RESET (WSA2_START_OFFSET + 0x00A8) +#define LPASS_CDC_WSA2_TOP_FS_UNGATE (WSA2_START_OFFSET + 0x00AC) +#define LPASS_CDC_WSA2_TOP_GRP_SEL (WSA2_START_OFFSET + 0x00B0) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP7_WR_LSB (WSA2_START_OFFSET + 0x00B4) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP7_WR_MSB (WSA2_START_OFFSET + 0x00B8) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP7_LUT (WSA2_START_OFFSET + 0x00BC) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP7_RD_LSB (WSA2_START_OFFSET + 0x00C0) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP7_RD_MSB (WSA2_START_OFFSET + 0x00C4) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP8_WR_LSB (WSA2_START_OFFSET + 0x00C8) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP8_WR_MSB (WSA2_START_OFFSET + 0x00CC) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP8_LUT (WSA2_START_OFFSET + 0x00D0) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP8_RD_LSB (WSA2_START_OFFSET + 0x00D4) +#define LPASS_CDC_WSA2_TOP_SPKR_COMP8_RD_MSB (WSA2_START_OFFSET + 0x00D8) +#define LPASS_CDC_WSA2_TOP_FS_UNGATE2 (WSA2_START_OFFSET + 0x00DC) +#define LPASS_CDC_WSA2_TOP_SEQ_CTL0 (WSA2_START_OFFSET + 0x00E0) +#define LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0 (WSA2_START_OFFSET + 0x0100) +#define LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1 (WSA2_START_OFFSET + 0x0104) +#define LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG0 (WSA2_START_OFFSET + 0x0108) +#define LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG1 (WSA2_START_OFFSET + 0x010C) +#define LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0 (WSA2_START_OFFSET + 0x0110) +#define LPASS_CDC_WSA2_RX_INP_MUX_RX_EC_CFG0 (WSA2_START_OFFSET + 0x0114) +#define LPASS_CDC_WSA2_RX_INP_MUX_SOFTCLIP_CFG0 (WSA2_START_OFFSET + 0x0118) +/* VBAT registers */ +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_PATH_CTL (WSA2_START_OFFSET + 0x0180) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG (WSA2_START_OFFSET + 0x0184) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL1 (WSA2_START_OFFSET + 0x0188) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL2 (WSA2_START_OFFSET + 0x018C) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL3 (WSA2_START_OFFSET + 0x0190) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST1 (WSA2_START_OFFSET + 0x0194) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST2 (WSA2_START_OFFSET + 0x0198) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST3 (WSA2_START_OFFSET + 0x019C) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_RF_PROC1 (WSA2_START_OFFSET + 0x01A0) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_RF_PROC2 (WSA2_START_OFFSET + 0x01A4) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC1 (WSA2_START_OFFSET + 0x01A8) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC2 (WSA2_START_OFFSET + 0x01AC) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC3 (WSA2_START_OFFSET + 0x01B0) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC4 (WSA2_START_OFFSET + 0x01B4) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD1 (WSA2_START_OFFSET + 0x01B8) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD2 (WSA2_START_OFFSET + 0x01BC) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD3 (WSA2_START_OFFSET + 0x01C0) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD4 (WSA2_START_OFFSET + 0x01C4) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD5 (WSA2_START_OFFSET + 0x01C8) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_DEBUG1 (WSA2_START_OFFSET + 0x01CC) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD_MON \ + (WSA2_START_OFFSET + 0x01D0) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_MON_VAL \ + (WSA2_START_OFFSET + 0x01D4) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BAN (WSA2_START_OFFSET + 0x01D8) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD1 \ + (WSA2_START_OFFSET + 0x01DC) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD2 \ + (WSA2_START_OFFSET + 0x01E0) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD3 \ + (WSA2_START_OFFSET + 0x01E4) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD4 \ + (WSA2_START_OFFSET + 0x01E8) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD5 \ + (WSA2_START_OFFSET + 0x01EC) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD6 \ + (WSA2_START_OFFSET + 0x01F0) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD7 \ + (WSA2_START_OFFSET + 0x01F4) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD8 \ + (WSA2_START_OFFSET + 0x01F8) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD9 \ + (WSA2_START_OFFSET + 0x01FC) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN1 (WSA2_START_OFFSET + 0x0200) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN2 (WSA2_START_OFFSET + 0x0204) +#define LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN3 (WSA2_START_OFFSET + 0x0208) +#define LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL (WSA2_START_OFFSET + 0x0244) +#define LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CFG0 (WSA2_START_OFFSET + 0x0248) +#define LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL (WSA2_START_OFFSET + 0x0264) +#define LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CFG0 (WSA2_START_OFFSET + 0x0268) +#define LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL (WSA2_START_OFFSET + 0x0284) +#define LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CFG0 (WSA2_START_OFFSET + 0x0288) +#define LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL (WSA2_START_OFFSET + 0x02A4) +#define LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CFG0 (WSA2_START_OFFSET + 0x02A8) +#define LPASS_CDC_WSA2_INTR_CTRL_CFG (WSA2_START_OFFSET + 0x0340) +#define LPASS_CDC_WSA2_INTR_CTRL_CLR_COMMIT (WSA2_START_OFFSET + 0x0344) +#define LPASS_CDC_WSA2_INTR_CTRL_PIN1_MASK0 (WSA2_START_OFFSET + 0x0360) +#define LPASS_CDC_WSA2_INTR_CTRL_PIN1_STATUS0 (WSA2_START_OFFSET + 0x0368) +#define LPASS_CDC_WSA2_INTR_CTRL_PIN1_CLEAR0 (WSA2_START_OFFSET + 0x0370) +#define LPASS_CDC_WSA2_INTR_CTRL_PIN2_MASK0 (WSA2_START_OFFSET + 0x0380) +#define LPASS_CDC_WSA2_INTR_CTRL_PIN2_STATUS0 (WSA2_START_OFFSET + 0x0388) +#define LPASS_CDC_WSA2_INTR_CTRL_PIN2_CLEAR0 (WSA2_START_OFFSET + 0x0390) +#define LPASS_CDC_WSA2_INTR_CTRL_LEVEL0 (WSA2_START_OFFSET + 0x03C0) +#define LPASS_CDC_WSA2_INTR_CTRL_BYPASS0 (WSA2_START_OFFSET + 0x03C8) +#define LPASS_CDC_WSA2_INTR_CTRL_SET0 (WSA2_START_OFFSET + 0x03D0) +#define LPASS_CDC_WSA2_RX0_RX_PATH_CTL (WSA2_START_OFFSET + 0x0400) +#define LPASS_CDC_WSA2_RX0_RX_PATH_CFG0 (WSA2_START_OFFSET + 0x0404) +#define LPASS_CDC_WSA2_RX0_RX_PATH_CFG1 (WSA2_START_OFFSET + 0x0408) +#define LPASS_CDC_WSA2_RX0_RX_PATH_CFG2 (WSA2_START_OFFSET + 0x040C) +#define LPASS_CDC_WSA2_RX0_RX_PATH_CFG3 (WSA2_START_OFFSET + 0x0410) +#define LPASS_CDC_WSA2_RX0_RX_VOL_CTL (WSA2_START_OFFSET + 0x0414) +#define LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL (WSA2_START_OFFSET + 0x0418) +#define LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CFG (WSA2_START_OFFSET + 0x041C) +#define LPASS_CDC_WSA2_RX0_RX_VOL_MIX_CTL (WSA2_START_OFFSET + 0x0420) +#define LPASS_CDC_WSA2_RX0_RX_PATH_SEC0 (WSA2_START_OFFSET + 0x0424) +#define LPASS_CDC_WSA2_RX0_RX_PATH_SEC1 (WSA2_START_OFFSET + 0x0428) +#define LPASS_CDC_WSA2_RX0_RX_PATH_SEC2 (WSA2_START_OFFSET + 0x042C) +#define LPASS_CDC_WSA2_RX0_RX_PATH_SEC3 (WSA2_START_OFFSET + 0x0430) +#define LPASS_CDC_WSA2_RX0_RX_PATH_SEC5 (WSA2_START_OFFSET + 0x0438) +#define LPASS_CDC_WSA2_RX0_RX_PATH_SEC6 (WSA2_START_OFFSET + 0x043C) +#define LPASS_CDC_WSA2_RX0_RX_PATH_SEC7 (WSA2_START_OFFSET + 0x0440) +#define LPASS_CDC_WSA2_RX0_RX_PATH_MIX_SEC0 (WSA2_START_OFFSET + 0x0444) +#define LPASS_CDC_WSA2_RX0_RX_PATH_MIX_SEC1 (WSA2_START_OFFSET + 0x0448) +#define LPASS_CDC_WSA2_RX0_RX_PATH_DSMDEM_CTL (WSA2_START_OFFSET + 0x044C) +#define LPASS_CDC_WSA2_RX1_RX_PATH_CTL (WSA2_START_OFFSET + 0x0480) +#define LPASS_CDC_WSA2_RX1_RX_PATH_CFG0 (WSA2_START_OFFSET + 0x0484) +#define LPASS_CDC_WSA2_RX1_RX_PATH_CFG1 (WSA2_START_OFFSET + 0x0488) +#define LPASS_CDC_WSA2_RX1_RX_PATH_CFG2 (WSA2_START_OFFSET + 0x048C) +#define LPASS_CDC_WSA2_RX1_RX_PATH_CFG3 (WSA2_START_OFFSET + 0x0490) +#define LPASS_CDC_WSA2_RX1_RX_VOL_CTL (WSA2_START_OFFSET + 0x0494) +#define LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CTL (WSA2_START_OFFSET + 0x0498) +#define LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CFG (WSA2_START_OFFSET + 0x049C) +#define LPASS_CDC_WSA2_RX1_RX_VOL_MIX_CTL (WSA2_START_OFFSET + 0x04A0) +#define LPASS_CDC_WSA2_RX1_RX_PATH_SEC0 (WSA2_START_OFFSET + 0x04A4) +#define LPASS_CDC_WSA2_RX1_RX_PATH_SEC1 (WSA2_START_OFFSET + 0x04A8) +#define LPASS_CDC_WSA2_RX1_RX_PATH_SEC2 (WSA2_START_OFFSET + 0x04AC) +#define LPASS_CDC_WSA2_RX1_RX_PATH_SEC3 (WSA2_START_OFFSET + 0x04B0) +#define LPASS_CDC_WSA2_RX1_RX_PATH_SEC5 (WSA2_START_OFFSET + 0x04B8) +#define LPASS_CDC_WSA2_RX1_RX_PATH_SEC6 (WSA2_START_OFFSET + 0x04BC) +#define LPASS_CDC_WSA2_RX1_RX_PATH_SEC7 (WSA2_START_OFFSET + 0x04C0) +#define LPASS_CDC_WSA2_RX1_RX_PATH_MIX_SEC0 (WSA2_START_OFFSET + 0x04C4) +#define LPASS_CDC_WSA2_RX1_RX_PATH_MIX_SEC1 (WSA2_START_OFFSET + 0x04C8) +#define LPASS_CDC_WSA2_RX1_RX_PATH_DSMDEM_CTL (WSA2_START_OFFSET + 0x04CC) +#define LPASS_CDC_WSA2_BOOST0_BOOST_PATH_CTL (WSA2_START_OFFSET + 0x0500) +#define LPASS_CDC_WSA2_BOOST0_BOOST_CTL (WSA2_START_OFFSET + 0x0504) +#define LPASS_CDC_WSA2_BOOST0_BOOST_CFG1 (WSA2_START_OFFSET + 0x0508) +#define LPASS_CDC_WSA2_BOOST0_BOOST_CFG2 (WSA2_START_OFFSET + 0x050C) +#define LPASS_CDC_WSA2_BOOST1_BOOST_PATH_CTL (WSA2_START_OFFSET + 0x0540) +#define LPASS_CDC_WSA2_BOOST1_BOOST_CTL (WSA2_START_OFFSET + 0x0544) +#define LPASS_CDC_WSA2_BOOST1_BOOST_CFG1 (WSA2_START_OFFSET + 0x0548) +#define LPASS_CDC_WSA2_BOOST1_BOOST_CFG2 (WSA2_START_OFFSET + 0x054C) +#define LPASS_CDC_WSA2_COMPANDER0_CTL0 (WSA2_START_OFFSET + 0x0580) +#define LPASS_CDC_WSA2_COMPANDER0_CTL1 (WSA2_START_OFFSET + 0x0584) +#define LPASS_CDC_WSA2_COMPANDER0_CTL2 (WSA2_START_OFFSET + 0x0588) +#define LPASS_CDC_WSA2_COMPANDER0_CTL3 (WSA2_START_OFFSET + 0x058C) +#define LPASS_CDC_WSA2_COMPANDER0_CTL4 (WSA2_START_OFFSET + 0x0590) +#define LPASS_CDC_WSA2_COMPANDER0_CTL5 (WSA2_START_OFFSET + 0x0594) +#define LPASS_CDC_WSA2_COMPANDER0_CTL6 (WSA2_START_OFFSET + 0x0598) +#define LPASS_CDC_WSA2_COMPANDER0_CTL7 (WSA2_START_OFFSET + 0x059C) +#define LPASS_CDC_WSA2_COMPANDER0_CTL8 (WSA2_START_OFFSET + 0x05A0) +#define LPASS_CDC_WSA2_COMPANDER0_CTL9 (WSA2_START_OFFSET + 0x05A4) +#define LPASS_CDC_WSA2_COMPANDER0_CTL10 (WSA2_START_OFFSET + 0x05A8) +#define LPASS_CDC_WSA2_COMPANDER0_CTL11 (WSA2_START_OFFSET + 0x05AC) +#define LPASS_CDC_WSA2_COMPANDER0_CTL12 (WSA2_START_OFFSET + 0x05B0) +#define LPASS_CDC_WSA2_COMPANDER0_CTL13 (WSA2_START_OFFSET + 0x05B4) +#define LPASS_CDC_WSA2_COMPANDER0_CTL14 (WSA2_START_OFFSET + 0x05B8) +#define LPASS_CDC_WSA2_COMPANDER0_CTL15 (WSA2_START_OFFSET + 0x05BC) +#define LPASS_CDC_WSA2_COMPANDER0_CTL16 (WSA2_START_OFFSET + 0x05C0) +#define LPASS_CDC_WSA2_COMPANDER0_CTL17 (WSA2_START_OFFSET + 0x05C4) +#define LPASS_CDC_WSA2_COMPANDER0_CTL18 (WSA2_START_OFFSET + 0x05C8) +#define LPASS_CDC_WSA2_COMPANDER0_CTL19 (WSA2_START_OFFSET + 0x05CC) +#define LPASS_CDC_WSA2_COMPANDER1_CTL0 (WSA2_START_OFFSET + 0x05E0) +#define LPASS_CDC_WSA2_COMPANDER1_CTL1 (WSA2_START_OFFSET + 0x05E4) +#define LPASS_CDC_WSA2_COMPANDER1_CTL2 (WSA2_START_OFFSET + 0x05E8) +#define LPASS_CDC_WSA2_COMPANDER1_CTL3 (WSA2_START_OFFSET + 0x05EC) +#define LPASS_CDC_WSA2_COMPANDER1_CTL4 (WSA2_START_OFFSET + 0x05F0) +#define LPASS_CDC_WSA2_COMPANDER1_CTL5 (WSA2_START_OFFSET + 0x05F4) +#define LPASS_CDC_WSA2_COMPANDER1_CTL6 (WSA2_START_OFFSET + 0x05F8) +#define LPASS_CDC_WSA2_COMPANDER1_CTL7 (WSA2_START_OFFSET + 0x05FC) +#define LPASS_CDC_WSA2_COMPANDER1_CTL8 (WSA2_START_OFFSET + 0x0600) +#define LPASS_CDC_WSA2_COMPANDER1_CTL9 (WSA2_START_OFFSET + 0x0604) +#define LPASS_CDC_WSA2_COMPANDER1_CTL10 (WSA2_START_OFFSET + 0x0608) +#define LPASS_CDC_WSA2_COMPANDER1_CTL11 (WSA2_START_OFFSET + 0x060C) +#define LPASS_CDC_WSA2_COMPANDER1_CTL12 (WSA2_START_OFFSET + 0x0610) +#define LPASS_CDC_WSA2_COMPANDER1_CTL13 (WSA2_START_OFFSET + 0x0614) +#define LPASS_CDC_WSA2_COMPANDER1_CTL14 (WSA2_START_OFFSET + 0x0618) +#define LPASS_CDC_WSA2_COMPANDER1_CTL15 (WSA2_START_OFFSET + 0x061C) +#define LPASS_CDC_WSA2_COMPANDER1_CTL16 (WSA2_START_OFFSET + 0x0620) +#define LPASS_CDC_WSA2_COMPANDER1_CTL17 (WSA2_START_OFFSET + 0x0624) +#define LPASS_CDC_WSA2_COMPANDER1_CTL18 (WSA2_START_OFFSET + 0x0628) +#define LPASS_CDC_WSA2_COMPANDER1_CTL19 (WSA2_START_OFFSET + 0x062C) +#define LPASS_CDC_WSA2_SOFTCLIP0_CRC (WSA2_START_OFFSET + 0x0640) +#define LPASS_CDC_WSA2_SOFTCLIP0_SOFTCLIP_CTRL (WSA2_START_OFFSET + 0x0644) +#define LPASS_CDC_WSA2_SOFTCLIP1_CRC (WSA2_START_OFFSET + 0x0660) +#define LPASS_CDC_WSA2_SOFTCLIP1_SOFTCLIP_CTRL (WSA2_START_OFFSET + 0x0664) +#define LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_PATH_CTL \ + (WSA2_START_OFFSET + 0x0680) +#define LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_CFG0 (WSA2_START_OFFSET + 0x0684) +#define LPASS_CDC_WSA2_EC_HQ1_EC_REF_HQ_PATH_CTL \ + (WSA2_START_OFFSET + 0x06C0) +#define LPASS_CDC_WSA2_EC_HQ1_EC_REF_HQ_CFG0 (WSA2_START_OFFSET + 0x06C4) +#define LPASS_CDC_WSA2_IDLE_DETECT_PATH_CTL (WSA2_START_OFFSET + 0x0780) +#define LPASS_CDC_WSA2_IDLE_DETECT_CFG0 (WSA2_START_OFFSET + 0x0784) +#define LPASS_CDC_WSA2_IDLE_DETECT_CFG1 (WSA2_START_OFFSET + 0x0788) +#define LPASS_CDC_WSA2_IDLE_DETECT_CFG2 (WSA2_START_OFFSET + 0x078C) +#define LPASS_CDC_WSA2_IDLE_DETECT_CFG3 (WSA2_START_OFFSET + 0x0790) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1 (WSA2_START_OFFSET + 0x0900) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2 (WSA2_START_OFFSET + 0x0904) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3 (WSA2_START_OFFSET + 0x0908) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG1 (WSA2_START_OFFSET + 0x090C) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG2 (WSA2_START_OFFSET + 0x0910) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG3 (WSA2_START_OFFSET + 0x0914) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG4 (WSA2_START_OFFSET + 0x0918) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG5 (WSA2_START_OFFSET + 0x091C) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG6 (WSA2_START_OFFSET + 0x0920) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG7 (WSA2_START_OFFSET + 0x0924) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG8 (WSA2_START_OFFSET + 0x0928) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST1 \ + (WSA2_START_OFFSET + 0x092C) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST2 \ + (WSA2_START_OFFSET + 0x0930) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST3 \ + (WSA2_START_OFFSET + 0x0934) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST4 \ + (WSA2_START_OFFSET + 0x0938) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST1 (WSA2_START_OFFSET + 0x093C) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST2 (WSA2_START_OFFSET + 0x0940) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST3 (WSA2_START_OFFSET + 0x0944) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST4 (WSA2_START_OFFSET + 0x0948) +#define LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST5 (WSA2_START_OFFSET + 0x094C) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PATH_CTL (WSA2_START_OFFSET + 0x0980) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_CFG (WSA2_START_OFFSET + 0x0984) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL1 (WSA2_START_OFFSET + 0x0988) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL2 (WSA2_START_OFFSET + 0x098C) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL3 (WSA2_START_OFFSET + 0x0990) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST1 (WSA2_START_OFFSET + 0x0994) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST2 (WSA2_START_OFFSET + 0x0998) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST3 (WSA2_START_OFFSET + 0x099C) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_RF_PROC1 (WSA2_START_OFFSET + 0x09A0) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_RF_PROC2 (WSA2_START_OFFSET + 0x09A4) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC1 (WSA2_START_OFFSET + 0x09A8) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC2 (WSA2_START_OFFSET + 0x09AC) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC3 (WSA2_START_OFFSET + 0x09B0) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC4 (WSA2_START_OFFSET + 0x09B4) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD1 (WSA2_START_OFFSET + 0x09B8) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD2 (WSA2_START_OFFSET + 0x09BC) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD3 (WSA2_START_OFFSET + 0x09C0) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD4 (WSA2_START_OFFSET + 0x09C4) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD5 (WSA2_START_OFFSET + 0x09C8) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_DEBUG1 (WSA2_START_OFFSET + 0x09CC) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD_MON \ + (WSA2_START_OFFSET + 0x09D0) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_MON_VAL \ + (WSA2_START_OFFSET + 0x09D4) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BAN (WSA2_START_OFFSET + 0x09D8) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD1 \ + (WSA2_START_OFFSET + 0x09DC) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD2 \ + (WSA2_START_OFFSET + 0x09E0) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD3 \ + (WSA2_START_OFFSET + 0x09E4) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD4 \ + (WSA2_START_OFFSET + 0x09E8) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD5 \ + (WSA2_START_OFFSET + 0x09EC) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD6 \ + (WSA2_START_OFFSET + 0x09F0) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD7 \ + (WSA2_START_OFFSET + 0x09F4) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD8 \ + (WSA2_START_OFFSET + 0x09F8) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD9 \ + (WSA2_START_OFFSET + 0x09FC) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN1 (WSA2_START_OFFSET + 0x0A00) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN2 (WSA2_START_OFFSET + 0x0A04) +#define LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN3 (WSA2_START_OFFSET + 0x0A08) +/* lpass 2.6 new registers */ +#define LPASS_CDC_WSA2_PBR_PATH_CTL (WSA2_START_OFFSET + 0xB00) +#define LPASS_CDC_WSA2_LA_CFG (WSA2_START_OFFSET + 0xB04) +#define LPASS_CDC_WSA2_PBR_CFG1 (WSA2_START_OFFSET + 0xB08) +#define LPASS_CDC_WSA2_PBR_CFG2 (WSA2_START_OFFSET + 0xB0C) +#define LPASS_CDC_WSA2_PBR_CFG3 (WSA2_START_OFFSET + 0xB10) +#define LPASS_CDC_WSA2_PBR_CFG4 (WSA2_START_OFFSET + 0xB14) +#define LPASS_CDC_WSA2_PBR_CFG5 (WSA2_START_OFFSET + 0xB18) +#define LPASS_CDC_WSA2_PBR_CFG6 (WSA2_START_OFFSET + 0xB1C) +#define LPASS_CDC_WSA2_PBR_CFG7 (WSA2_START_OFFSET + 0xB20) +#define LPASS_CDC_WSA2_PBR_CFG8 (WSA2_START_OFFSET + 0xB24) +#define LPASS_CDC_WSA2_PBR_CFG9 (WSA2_START_OFFSET + 0xB28) +#define LPASS_CDC_WSA2_PBR_CFG10 (WSA2_START_OFFSET + 0xB2C) +#define LPASS_CDC_WSA2_PBR_CFG11 (WSA2_START_OFFSET + 0xB30) +#define LPASS_CDC_WSA2_PBR_CFG12 (WSA2_START_OFFSET + 0xB34) +#define LPASS_CDC_WSA2_PBR_CFG13 (WSA2_START_OFFSET + 0xB38) +#define LPASS_CDC_WSA2_PBR_CFG14 (WSA2_START_OFFSET + 0xB3C) +#define LPASS_CDC_WSA2_PBR_CFG15 (WSA2_START_OFFSET + 0xB40) +#define LPASS_CDC_WSA2_PBR_CFG16 (WSA2_START_OFFSET + 0xB44) +#define LPASS_CDC_WSA2_PBR_CFG17 (WSA2_START_OFFSET + 0xB48) +#define LPASS_CDC_WSA2_ILIM_CFG0 (WSA2_START_OFFSET + 0xB4C) +#define LPASS_CDC_WSA2_ILIM_CFG1 (WSA2_START_OFFSET + 0xB50) +#define LPASS_CDC_WSA2_ILIM_CFG2 (WSA2_START_OFFSET + 0xB54) +#define LPASS_CDC_WSA2_ILIM_CFG3 (WSA2_START_OFFSET + 0xB58) +#define LPASS_CDC_WSA2_ILIM_CFG4 (WSA2_START_OFFSET + 0xB5C) +#define LPASS_CDC_WSA2_ILIM_CFG5 (WSA2_START_OFFSET + 0xB60) +#define LPASS_CDC_WSA2_ILIM_CFG6 (WSA2_START_OFFSET + 0xB64) +#define LPASS_CDC_WSA2_ILIM_CFG7 (WSA2_START_OFFSET + 0xB68) +#define LPASS_CDC_WSA2_ILIM_CFG8 (WSA2_START_OFFSET + 0xB6C) +#define LPASS_CDC_WSA2_LA_CFG_1 (WSA2_START_OFFSET + 0xB70) +#define LPASS_CDC_WSA2_PBR_CFG1_1 (WSA2_START_OFFSET + 0xB74) +#define LPASS_CDC_WSA2_PBR_CFG2_1 (WSA2_START_OFFSET + 0xB78) +#define LPASS_CDC_WSA2_PBR_CFG3_1 (WSA2_START_OFFSET + 0xB7C) +#define LPASS_CDC_WSA2_PBR_CFG4_1 (WSA2_START_OFFSET + 0xB80) +#define LPASS_CDC_WSA2_PBR_CFG5_1 (WSA2_START_OFFSET + 0xB84) +#define LPASS_CDC_WSA2_PBR_CFG6_1 (WSA2_START_OFFSET + 0xB88) +#define LPASS_CDC_WSA2_PBR_CFG7_1 (WSA2_START_OFFSET + 0xB8C) +#define LPASS_CDC_WSA2_PBR_CFG8_1 (WSA2_START_OFFSET + 0xB90) +#define LPASS_CDC_WSA2_PBR_CFG9_1 (WSA2_START_OFFSET + 0xB94) +#define LPASS_CDC_WSA2_PBR_CFG10_1 (WSA2_START_OFFSET + 0xB98) +#define LPASS_CDC_WSA2_PBR_CFG11_1 (WSA2_START_OFFSET + 0xB9C) +#define LPASS_CDC_WSA2_PBR_CFG12_1 (WSA2_START_OFFSET + 0xBA0) +#define LPASS_CDC_WSA2_PBR_CFG13_1 (WSA2_START_OFFSET + 0xBA4) +#define LPASS_CDC_WSA2_PBR_CFG14_1 (WSA2_START_OFFSET + 0xBA8) +#define LPASS_CDC_WSA2_PBR_CFG15_1 (WSA2_START_OFFSET + 0xBAC) +#define LPASS_CDC_WSA2_PBR_CFG16_1 (WSA2_START_OFFSET + 0xBB0) +#define LPASS_CDC_WSA2_ILIM_CFG0_1 (WSA2_START_OFFSET + 0xBB4) +#define LPASS_CDC_WSA2_ILIM_CFG1_1 (WSA2_START_OFFSET + 0xBB8) +#define LPASS_CDC_WSA2_ILIM_CFG2_1 (WSA2_START_OFFSET + 0xBBC) +#define LPASS_CDC_WSA2_ILIM_CFG5_1 (WSA2_START_OFFSET + 0xBC0) +#define LPASS_CDC_WSA2_ILIM_CFG9 (WSA2_START_OFFSET + 0xBC4) +#define LPASS_CDC_WSA2_ILIM_CFG6_1 (WSA2_START_OFFSET + 0xBC8) +#define LPASS_CDC_WSA2_PBR_CFG18 (WSA2_START_OFFSET + 0xBCC) +#define LPASS_CDC_WSA2_PBR_CFG18_1 (WSA2_START_OFFSET + 0xBD0) +#define LPASS_CDC_WSA2_PBR_CFG19 (WSA2_START_OFFSET + 0xBD4) +#define LPASS_CDC_WSA2_PBR_CFG20 (WSA2_START_OFFSET + 0xBD8) +#define LPASS_CDC_WSA2_PBR_CFG21 (WSA2_START_OFFSET + 0xBDC) +#define LPASS_CDC_WSA2_PBR_CFG22 (WSA2_START_OFFSET + 0xBE0) +#define LPASS_CDC_WSA2_PBR_CFG23 (WSA2_START_OFFSET + 0xBE4) + +#define WSA2_MAX_OFFSET (WSA2_START_OFFSET + 0xBE4) + +#define LPASS_CDC_WSA2_MACRO_MAX 0x2FA /* 0xBE4/4 = 0x2F9 + 1 registers */ + +#define LPASS_CDC_MAX_REGISTER WSA2_MAX_OFFSET + +#define LPASS_CDC_REG(reg) (((reg) & 0x0FFF)/4) + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-regmap.c new file mode 100644 index 0000000000..ae012c7af6 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-regmap.c @@ -0,0 +1,1401 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "lpass-cdc.h" +#include "internal.h" + +static const struct reg_default lpass_cdc_defaults[] = { + /* TX Macro */ + { LPASS_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, 0x00 }, + { LPASS_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00 }, + { LPASS_CDC_TX_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { LPASS_CDC_TX_TOP_CSR_TOP_CFG0, 0x00}, + { LPASS_CDC_TX_TOP_CSR_ANC_CFG, 0x00}, + { LPASS_CDC_TX_TOP_CSR_FREQ_MCLK, 0x00}, + { LPASS_CDC_TX_TOP_CSR_DEBUG_BUS, 0x00}, + { LPASS_CDC_TX_TOP_CSR_DEBUG_EN, 0x00}, + { LPASS_CDC_TX_TOP_CSR_TX_I2S_CTL, 0x0C}, + { LPASS_CDC_TX_TOP_CSR_I2S_CLK, 0x00}, + { LPASS_CDC_TX_TOP_CSR_I2S_RESET, 0x00}, + + { LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG1, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG1, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG1, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0x00}, + { LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG1, 0x00}, + { LPASS_CDC_TX_ANC0_CLK_RESET_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_MODE_1_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_MODE_2_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_FF_SHIFT, 0x00}, + { LPASS_CDC_TX_ANC0_FB_SHIFT, 0x00}, + { LPASS_CDC_TX_ANC0_LPF_FF_A_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_LPF_FF_B_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_LPF_FB_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_SMLPF_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_DCFLT_SHIFT_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_IIR_ADAPT_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_IIR_COEFF_1_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_IIR_COEFF_2_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_FF_A_GAIN_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_FF_B_GAIN_CTL, 0x00}, + { LPASS_CDC_TX_ANC0_FB_GAIN_CTL, 0x00}, + { LPASS_CDC_TX0_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX0_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX0_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX0_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX0_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX0_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX0_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX0_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX0_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX0_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX0_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_TX0_TX_PATH_SEC7, 0x25}, + { LPASS_CDC_TX1_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX1_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX1_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX1_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX1_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX1_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX1_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX1_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX1_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX1_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX1_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_TX2_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX2_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX2_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX2_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX2_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX2_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX2_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX2_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX2_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX2_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX2_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_TX3_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX3_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX3_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX3_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX3_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX3_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX3_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX3_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX3_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX3_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX3_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_TX4_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX4_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX4_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX4_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX4_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX4_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX4_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX4_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX4_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX4_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX4_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_TX5_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX5_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX5_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX5_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX5_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX5_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX5_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX5_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX5_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX5_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX5_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_TX6_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX6_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX6_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX6_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX6_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX6_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX6_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX6_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX6_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX6_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX6_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_TX7_TX_PATH_CTL, 0x04}, + { LPASS_CDC_TX7_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_TX7_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_TX7_TX_VOL_CTL, 0x00}, + { LPASS_CDC_TX7_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_TX7_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_TX7_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_TX7_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_TX7_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_TX7_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_TX7_TX_PATH_SEC6, 0x00}, +#ifdef CONFIG_BOLERO_VER_2P6 + { LPASS_CDC_TX_TOP_CSR_SWR_CTRL, 0x60}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC2_CTL, 0x0E}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC3_CTL, 0x0E}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC4_CTL, 0x0E}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC5_CTL, 0x0E}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC0_CTL, 0x0E}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC1_CTL, 0x0E}, +#else + { LPASS_CDC_TX_TOP_CSR_SWR_CTRL, 0x00}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC2_CTL, 0x00}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC3_CTL, 0x00}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC4_CTL, 0x00}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC5_CTL, 0x00}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC0_CTL, 0x00}, + { LPASS_CDC_TX_TOP_CSR_SWR_MIC1_CTL, 0x00}, +#endif + + /* RX Macro */ + { LPASS_CDC_RX_TOP_TOP_CFG0, 0x00}, + { LPASS_CDC_RX_TOP_TOP_CFG1, 0x00}, + { LPASS_CDC_RX_TOP_SWR_CTRL, 0x00}, + { LPASS_CDC_RX_TOP_DEBUG, 0x00}, + { LPASS_CDC_RX_TOP_DEBUG_BUS, 0x00}, + { LPASS_CDC_RX_TOP_DEBUG_EN0, 0x00}, + { LPASS_CDC_RX_TOP_DEBUG_EN1, 0x00}, + { LPASS_CDC_RX_TOP_DEBUG_EN2, 0x00}, + { LPASS_CDC_RX_TOP_HPHL_COMP_WR_LSB, 0x00}, + { LPASS_CDC_RX_TOP_HPHL_COMP_WR_MSB, 0x00}, + { LPASS_CDC_RX_TOP_HPHL_COMP_LUT, 0x00}, + { LPASS_CDC_RX_TOP_HPHL_COMP_RD_LSB, 0x00}, + { LPASS_CDC_RX_TOP_HPHL_COMP_RD_MSB, 0x00}, + { LPASS_CDC_RX_TOP_HPHR_COMP_WR_LSB, 0x00}, + { LPASS_CDC_RX_TOP_HPHR_COMP_WR_MSB, 0x00}, + { LPASS_CDC_RX_TOP_HPHR_COMP_LUT, 0x00}, + { LPASS_CDC_RX_TOP_HPHR_COMP_RD_LSB, 0x00}, + { LPASS_CDC_RX_TOP_HPHR_COMP_RD_MSB, 0x00}, + { LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG0, 0x11}, + { LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG1, 0x20}, + { LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG2, 0x00}, + { LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG0, 0x11}, + { LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG1, 0x20}, + { LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG2, 0x00}, + { LPASS_CDC_RX_TOP_RX_I2S_CTL, 0x0C}, + { LPASS_CDC_RX_TOP_TX_I2S2_CTL, 0x0C}, + { LPASS_CDC_RX_TOP_I2S_CLK, 0x0C}, + { LPASS_CDC_RX_TOP_I2S_RESET, 0x00}, + { LPASS_CDC_RX_TOP_I2S_MUX, 0x00}, + { LPASS_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { LPASS_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { LPASS_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { LPASS_CDC_RX_CLK_RST_CTRL_DSD_CONTROL, 0x00}, + { LPASS_CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL, 0x08}, + { LPASS_CDC_RX_SOFTCLIP_CRC, 0x00}, + { LPASS_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x38}, + { LPASS_CDC_RX_INP_MUX_RX_INT0_CFG0, 0x00}, + { LPASS_CDC_RX_INP_MUX_RX_INT0_CFG1, 0x00}, + { LPASS_CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00}, + { LPASS_CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00}, + { LPASS_CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00}, + { LPASS_CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00}, + { LPASS_CDC_RX_INP_MUX_RX_MIX_CFG4, 0x00}, + { LPASS_CDC_RX_INP_MUX_RX_MIX_CFG5, 0x00}, + { LPASS_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00}, + { LPASS_CDC_RX_CLSH_CRC, 0x00}, + { LPASS_CDC_RX_CLSH_DLY_CTRL, 0x03}, + { LPASS_CDC_RX_CLSH_DECAY_CTRL, 0x02}, + { LPASS_CDC_RX_CLSH_HPH_V_PA, 0x1C}, + { LPASS_CDC_RX_CLSH_EAR_V_PA, 0x39}, + { LPASS_CDC_RX_CLSH_HPH_V_HD, 0x0C}, + { LPASS_CDC_RX_CLSH_EAR_V_HD, 0x0C}, + { LPASS_CDC_RX_CLSH_K1_MSB, 0x01}, + { LPASS_CDC_RX_CLSH_K1_LSB, 0x00}, + { LPASS_CDC_RX_CLSH_K2_MSB, 0x00}, + { LPASS_CDC_RX_CLSH_K2_LSB, 0x80}, + { LPASS_CDC_RX_CLSH_IDLE_CTRL, 0x00}, + { LPASS_CDC_RX_CLSH_IDLE_HPH, 0x00}, + { LPASS_CDC_RX_CLSH_IDLE_EAR, 0x00}, + { LPASS_CDC_RX_CLSH_TEST0, 0x07}, + { LPASS_CDC_RX_CLSH_TEST1, 0x00}, + { LPASS_CDC_RX_CLSH_OVR_VREF, 0x00}, + { LPASS_CDC_RX_CLSH_CLSG_CTL, 0x02}, + { LPASS_CDC_RX_CLSH_CLSG_CFG1, 0x9A}, + { LPASS_CDC_RX_CLSH_CLSG_CFG2, 0x10}, + { LPASS_CDC_RX_BCL_VBAT_PATH_CTL, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_CFG, 0x10}, + { LPASS_CDC_RX_BCL_VBAT_ADC_CAL1, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_ADC_CAL2, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_ADC_CAL3, 0x04}, + { LPASS_CDC_RX_BCL_VBAT_PK_EST1, 0xE0}, + { LPASS_CDC_RX_BCL_VBAT_PK_EST2, 0x01}, + { LPASS_CDC_RX_BCL_VBAT_PK_EST3, 0x40}, + { LPASS_CDC_RX_BCL_VBAT_RF_PROC1, 0x2A}, + { LPASS_CDC_RX_BCL_VBAT_RF_PROC2, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_TAC1, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_TAC2, 0x18}, + { LPASS_CDC_RX_BCL_VBAT_TAC3, 0x18}, + { LPASS_CDC_RX_BCL_VBAT_TAC4, 0x03}, + { LPASS_CDC_RX_BCL_VBAT_GAIN_UPD1, 0x01}, + { LPASS_CDC_RX_BCL_VBAT_GAIN_UPD2, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_GAIN_UPD3, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_GAIN_UPD4, 0x64}, + { LPASS_CDC_RX_BCL_VBAT_GAIN_UPD5, 0x01}, + { LPASS_CDC_RX_BCL_VBAT_DEBUG1, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_GAIN_UPD_MON, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_GAIN_MON_VAL, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_BAN, 0x0C}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, 0x77}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, 0x01}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, 0x4B}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, 0x01}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_ATTN1, 0x04}, + { LPASS_CDC_RX_BCL_VBAT_ATTN2, 0x08}, + { LPASS_CDC_RX_BCL_VBAT_ATTN3, 0x0C}, + { LPASS_CDC_RX_INTR_CTRL_CFG, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_CLR_COMMIT, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_PIN1_MASK0, 0xFF}, + { LPASS_CDC_RX_INTR_CTRL_PIN1_STATUS0, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_PIN1_CLEAR0, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_PIN2_MASK0, 0xFF}, + { LPASS_CDC_RX_INTR_CTRL_PIN2_STATUS0, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_PIN2_CLEAR0, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_LEVEL0, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_BYPASS0, 0x00}, + { LPASS_CDC_RX_INTR_CTRL_SET0, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_CTL, 0x04}, + { LPASS_CDC_RX_RX0_RX_PATH_CFG0, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_CFG1, 0x64}, + { LPASS_CDC_RX_RX0_RX_PATH_CFG2, 0x8F}, + { LPASS_CDC_RX_RX0_RX_VOL_CTL, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_MIX_CTL, 0x04}, + { LPASS_CDC_RX_RX0_RX_PATH_MIX_CFG, 0x7E}, + { LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x08}, + { LPASS_CDC_RX_RX0_RX_PATH_SEC2, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_SEC3, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_SEC4, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_SEC7, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_MIX_SEC0, 0x08}, + { LPASS_CDC_RX_RX0_RX_PATH_MIX_SEC1, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_DSM_CTL, 0x08}, + { LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA1, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA2, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA3, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA4, 0x55}, + { LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA5, 0x55}, + { LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA6, 0x55}, + { LPASS_CDC_RX_RX1_RX_PATH_CTL, 0x04}, + { LPASS_CDC_RX_RX1_RX_PATH_CFG0, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_CFG1, 0x64}, + { LPASS_CDC_RX_RX1_RX_PATH_CFG2, 0x8F}, + { LPASS_CDC_RX_RX1_RX_VOL_CTL, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04}, + { LPASS_CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E}, + { LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x08}, + { LPASS_CDC_RX_RX1_RX_PATH_SEC2, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_SEC3, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_SEC4, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_SEC7, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08}, + { LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08}, + { LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55}, + { LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55}, + { LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55}, + { LPASS_CDC_RX_RX2_RX_PATH_CTL, 0x04}, + { LPASS_CDC_RX_RX2_RX_PATH_CFG0, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_CFG1, 0x64}, + { LPASS_CDC_RX_RX2_RX_PATH_CFG2, 0x8F}, + { LPASS_CDC_RX_RX2_RX_VOL_CTL, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04}, + { LPASS_CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E}, + { LPASS_CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC0, 0x04}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC1, 0x08}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC2, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC3, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC4, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC5, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC6, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_SEC7, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08}, + { LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00}, + { LPASS_CDC_RX_IDLE_DETECT_PATH_CTL, 0x00}, + { LPASS_CDC_RX_IDLE_DETECT_CFG0, 0x07}, + { LPASS_CDC_RX_IDLE_DETECT_CFG1, 0x3C}, + { LPASS_CDC_RX_IDLE_DETECT_CFG2, 0x00}, + { LPASS_CDC_RX_IDLE_DETECT_CFG3, 0x00}, + { LPASS_CDC_RX_COMPANDER0_CTL0, 0x60}, + { LPASS_CDC_RX_COMPANDER0_CTL1, 0xDB}, + { LPASS_CDC_RX_COMPANDER0_CTL2, 0xFF}, + { LPASS_CDC_RX_COMPANDER0_CTL3, 0x35}, + { LPASS_CDC_RX_COMPANDER0_CTL4, 0xFF}, + { LPASS_CDC_RX_COMPANDER0_CTL5, 0x00}, + { LPASS_CDC_RX_COMPANDER0_CTL6, 0x01}, + { LPASS_CDC_RX_COMPANDER0_CTL7, 0x28}, + { LPASS_CDC_RX_COMPANDER1_CTL0, 0x60}, + { LPASS_CDC_RX_COMPANDER1_CTL1, 0xDB}, + { LPASS_CDC_RX_COMPANDER1_CTL2, 0xFF}, + { LPASS_CDC_RX_COMPANDER1_CTL3, 0x35}, + { LPASS_CDC_RX_COMPANDER1_CTL4, 0xFF}, + { LPASS_CDC_RX_COMPANDER1_CTL5, 0x00}, + { LPASS_CDC_RX_COMPANDER1_CTL6, 0x01}, + { LPASS_CDC_RX_COMPANDER1_CTL7, 0x28}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_CTL, 0x40}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_CTL, 0x40}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL, 0x00}, + { LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00}, + { LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00}, + { LPASS_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04}, + { LPASS_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00}, + { LPASS_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL, 0x04}, + { LPASS_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1, 0x00}, + { LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, + { LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0, 0x01}, + { LPASS_CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, + { LPASS_CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0, 0x01}, + { LPASS_CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL, 0x00}, + { LPASS_CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0, 0x01}, + { LPASS_CDC_RX_EC_ASRC0_CLK_RST_CTL, 0x00}, + { LPASS_CDC_RX_EC_ASRC0_CTL0, 0x00}, + { LPASS_CDC_RX_EC_ASRC0_CTL1, 0x00}, + { LPASS_CDC_RX_EC_ASRC0_FIFO_CTL, 0xA8}, + { LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC0_STATUS_FIFO, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_CLK_RST_CTL, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_CTL0, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_CTL1, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_FIFO_CTL, 0xA8}, + { LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC1_STATUS_FIFO, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_CLK_RST_CTL, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_CTL0, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_CTL1, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_FIFO_CTL, 0xA8}, + { LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB, 0x00}, + { LPASS_CDC_RX_EC_ASRC2_STATUS_FIFO, 0x00}, + { LPASS_CDC_RX_DSD0_PATH_CTL, 0x00}, + { LPASS_CDC_RX_DSD0_CFG0, 0x00}, + { LPASS_CDC_RX_DSD0_CFG1, 0x62}, + { LPASS_CDC_RX_DSD0_CFG2, 0x96}, + { LPASS_CDC_RX_DSD1_PATH_CTL, 0x00}, + { LPASS_CDC_RX_DSD1_CFG0, 0x00}, + { LPASS_CDC_RX_DSD1_CFG1, 0x62}, + { LPASS_CDC_RX_DSD1_CFG2, 0x96}, +#ifdef CONFIG_BOLERO_VER_2P6 + { LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG3, 0x08}, + { LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG3, 0x08}, + { LPASS_CDC_RX_RX0_RX_PATH_CFG3, 0x03}, + { LPASS_CDC_RX_RX0_RX_FIR_CTL, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_CFG, 0x64}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_ADDR, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA0, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA1, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA2, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA3, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA4, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA5, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA6, 0x00}, + { LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA7, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_CFG3, 0x03}, + { LPASS_CDC_RX_RX1_RX_FIR_CTL, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_CFG, 0x64}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_ADDR, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA0, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA1, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA2, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA3, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA4, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA5, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA6, 0x00}, + { LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA7, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_CFG3, 0x03}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL1, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL2, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL3, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG1, 0x85}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG2, 0xDC}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG3, 0x85}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG4, 0xDC}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG5, 0x85}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG6, 0xDC}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG7, 0x32}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG8, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST1, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST2, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST3, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST4, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST1, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST2, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST3, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST4, 0x00}, + { LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST5, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_PATH_CTL, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_CFG, 0x10}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL1, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL2, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL3, 0x04}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST1, 0xE0}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST2, 0x01}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST3, 0x40}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_RF_PROC1, 0x2A}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_RF_PROC1, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC1, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC2, 0x18}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC3, 0x18}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC4, 0x03}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD1, 0x01}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD2, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD3, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD4, 0x64}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD5, 0x01}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_DEBUG1, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD_MON, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_MON_VAL, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BAN, 0x0C}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD1, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD2, 0x77}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD3, 0x01}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD4, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD5, 0x4B}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD6, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD7, 0x01}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD8, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD9, 0x00}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN1, 0x04}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN2, 0x08}, + { LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN3, 0x0C}, + { LPASS_CDC_RX_COMPANDER0_CTL8, 0x00}, + { LPASS_CDC_RX_COMPANDER0_CTL9, 0x00}, + { LPASS_CDC_RX_COMPANDER0_CTL10, 0x06}, + { LPASS_CDC_RX_COMPANDER0_CTL11, 0x12}, + { LPASS_CDC_RX_COMPANDER0_CTL12, 0x1E}, + { LPASS_CDC_RX_COMPANDER0_CTL13, 0x2A}, + { LPASS_CDC_RX_COMPANDER0_CTL14, 0x36}, + { LPASS_CDC_RX_COMPANDER0_CTL15, 0x3C}, + { LPASS_CDC_RX_COMPANDER0_CTL16, 0xC4}, + { LPASS_CDC_RX_COMPANDER0_CTL17, 0x00}, + { LPASS_CDC_RX_COMPANDER0_CTL18, 0x0C}, + { LPASS_CDC_RX_COMPANDER0_CTL19, 0x16}, + { LPASS_CDC_RX_COMPANDER1_CTL8, 0x00}, + { LPASS_CDC_RX_COMPANDER1_CTL9, 0x00}, + { LPASS_CDC_RX_COMPANDER1_CTL10, 0x06}, + { LPASS_CDC_RX_COMPANDER1_CTL11, 0x12}, + { LPASS_CDC_RX_COMPANDER1_CTL12, 0x1E}, + { LPASS_CDC_RX_COMPANDER1_CTL13, 0x2A}, + { LPASS_CDC_RX_COMPANDER1_CTL14, 0x36}, + { LPASS_CDC_RX_COMPANDER1_CTL15, 0x3C}, + { LPASS_CDC_RX_COMPANDER1_CTL16, 0xC4}, + { LPASS_CDC_RX_COMPANDER1_CTL17, 0x00}, + { LPASS_CDC_RX_COMPANDER1_CTL18, 0x0C}, + { LPASS_CDC_RX_COMPANDER1_CTL19, 0x16}, +#else + { LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG3, 0x00}, + { LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG3, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_DECODE_CTL1, 0xE0}, + { LPASS_CDC_RX_BCL_VBAT_DECODE_CTL2, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_DECODE_CFG1, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_DECODE_CFG2, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_DECODE_CFG3, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_DECODE_CFG4, 0x00}, + { LPASS_CDC_RX_BCL_VBAT_DECODE_ST, 0x00}, + { LPASS_CDC_RX_RX0_RX_PATH_CFG3, 0x00}, + { LPASS_CDC_RX_RX1_RX_PATH_CFG3, 0x00}, + { LPASS_CDC_RX_RX2_RX_PATH_CFG3, 0x00}, +#endif + + /* WSA Macro */ + { LPASS_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { LPASS_CDC_WSA_TOP_TOP_CFG0, 0x00}, + { LPASS_CDC_WSA_TOP_TOP_CFG1, 0x00}, + { LPASS_CDC_WSA_TOP_FREQ_MCLK, 0x00}, + { LPASS_CDC_WSA_TOP_DEBUG_BUS_SEL, 0x00}, + { LPASS_CDC_WSA_TOP_DEBUG_EN0, 0x00}, + { LPASS_CDC_WSA_TOP_DEBUG_EN1, 0x00}, + { LPASS_CDC_WSA_TOP_DEBUG_DSM_LB, 0x88}, + { LPASS_CDC_WSA_TOP_RX_I2S_CTL, 0x0C}, + { LPASS_CDC_WSA_TOP_TX_I2S_CTL, 0x0C}, + { LPASS_CDC_WSA_TOP_I2S_CLK, 0x02}, + { LPASS_CDC_WSA_TOP_I2S_RESET, 0x00}, + { LPASS_CDC_WSA_TOP_FS_UNGATE, 0xFF}, + { LPASS_CDC_WSA_TOP_GRP_SEL, 0x08}, + { LPASS_CDC_WSA_TOP_SPKR_COMP7_WR_LSB, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP7_WR_MSB, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP7_LUT, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP7_RD_LSB, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP7_RD_MSB, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP8_WR_LSB, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP8_WR_MSB, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP8_LUT, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP8_RD_LSB, 0x00}, + { LPASS_CDC_WSA_TOP_SPKR_COMP8_RD_MSB, 0x00}, + { LPASS_CDC_WSA_TOP_FS_UNGATE2, 0x1F}, + { LPASS_CDC_WSA_TOP_SEQ_CTL0, 0x00}, + { LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, 0x00}, + { LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, 0x00}, + { LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, 0x00}, + { LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, 0x00}, + { LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00}, + { LPASS_CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00}, + { LPASS_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x10}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3, 0x04}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST1, 0xE0}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST2, 0x01}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST3, 0x40}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1, 0x2A}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC1, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC2, 0x18}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC3, 0x18}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC4, 0x03}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1, 0x01}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4, 0x64}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5, 0x01}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_DEBUG1, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BAN, 0x0C}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2, 0x77}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3, 0x01}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5, 0x4B}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7, 0x01}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9, 0x00}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1, 0x04}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2, 0x08}, + { LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3, 0x0C}, + { LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA_INTR_CTRL_CFG, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF}, + { LPASS_CDC_WSA_INTR_CTRL_PIN1_STATUS0, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_PIN1_CLEAR0, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_PIN2_MASK0, 0xFF}, + { LPASS_CDC_WSA_INTR_CTRL_PIN2_STATUS0, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_PIN2_CLEAR0, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_LEVEL0, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_BYPASS0, 0x00}, + { LPASS_CDC_WSA_INTR_CTRL_SET0, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_CTL, 0x04}, + { LPASS_CDC_WSA_RX0_RX_PATH_CFG0, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_CFG1, 0x64}, + { LPASS_CDC_WSA_RX0_RX_PATH_CFG2, 0x8F}, + { LPASS_CDC_WSA_RX0_RX_PATH_CFG3, 0x00}, + { LPASS_CDC_WSA_RX0_RX_VOL_CTL, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL, 0x04}, + { LPASS_CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x7E}, + { LPASS_CDC_WSA_RX0_RX_VOL_MIX_CTL, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_SEC0, 0x04}, + { LPASS_CDC_WSA_RX0_RX_PATH_SEC1, 0x08}, + { LPASS_CDC_WSA_RX0_RX_PATH_SEC2, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_SEC3, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_SEC5, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_SEC6, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_SEC7, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_MIX_SEC0, 0x08}, + { LPASS_CDC_WSA_RX0_RX_PATH_MIX_SEC1, 0x00}, + { LPASS_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_CFG0, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_CFG1, 0x64}, + { LPASS_CDC_WSA_RX1_RX_PATH_CFG2, 0x8F}, + { LPASS_CDC_WSA_RX1_RX_PATH_CFG3, 0x00}, + { LPASS_CDC_WSA_RX1_RX_VOL_CTL, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_MIX_CTL, 0x04}, + { LPASS_CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x7E}, + { LPASS_CDC_WSA_RX1_RX_VOL_MIX_CTL, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_SEC0, 0x04}, + { LPASS_CDC_WSA_RX1_RX_PATH_SEC1, 0x08}, + { LPASS_CDC_WSA_RX1_RX_PATH_SEC2, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_SEC3, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_SEC5, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_SEC6, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_SEC7, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_MIX_SEC0, 0x08}, + { LPASS_CDC_WSA_RX1_RX_PATH_MIX_SEC1, 0x00}, + { LPASS_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL, 0x00}, + { LPASS_CDC_WSA_BOOST0_BOOST_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_BOOST0_BOOST_CTL, 0xD0}, + { LPASS_CDC_WSA_BOOST0_BOOST_CFG1, 0x89}, + { LPASS_CDC_WSA_BOOST0_BOOST_CFG2, 0x04}, + { LPASS_CDC_WSA_BOOST1_BOOST_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_BOOST1_BOOST_CTL, 0xD0}, + { LPASS_CDC_WSA_BOOST1_BOOST_CFG1, 0x89}, + { LPASS_CDC_WSA_BOOST1_BOOST_CFG2, 0x04}, + { LPASS_CDC_WSA_COMPANDER0_CTL0, 0x60}, + { LPASS_CDC_WSA_COMPANDER0_CTL1, 0xDB}, + { LPASS_CDC_WSA_COMPANDER0_CTL2, 0xFF}, + { LPASS_CDC_WSA_COMPANDER0_CTL3, 0x35}, + { LPASS_CDC_WSA_COMPANDER0_CTL4, 0xFF}, + { LPASS_CDC_WSA_COMPANDER0_CTL5, 0x00}, + { LPASS_CDC_WSA_COMPANDER0_CTL6, 0x01}, + { LPASS_CDC_WSA_COMPANDER0_CTL7, 0x28}, + { LPASS_CDC_WSA_COMPANDER0_CTL8, 0x00}, + { LPASS_CDC_WSA_COMPANDER0_CTL9, 0x00}, + { LPASS_CDC_WSA_COMPANDER0_CTL10, 0x06}, + { LPASS_CDC_WSA_COMPANDER0_CTL11, 0x12}, + { LPASS_CDC_WSA_COMPANDER0_CTL12, 0x1E}, + { LPASS_CDC_WSA_COMPANDER0_CTL13, 0x24}, + { LPASS_CDC_WSA_COMPANDER0_CTL14, 0x24}, + { LPASS_CDC_WSA_COMPANDER0_CTL15, 0x24}, + { LPASS_CDC_WSA_COMPANDER0_CTL16, 0x00}, + { LPASS_CDC_WSA_COMPANDER0_CTL17, 0x24}, + { LPASS_CDC_WSA_COMPANDER0_CTL18, 0x2A}, + { LPASS_CDC_WSA_COMPANDER0_CTL19, 0x16}, + { LPASS_CDC_WSA_COMPANDER1_CTL0, 0x60}, + { LPASS_CDC_WSA_COMPANDER1_CTL1, 0xDB}, + { LPASS_CDC_WSA_COMPANDER1_CTL2, 0xFF}, + { LPASS_CDC_WSA_COMPANDER1_CTL3, 0x35}, + { LPASS_CDC_WSA_COMPANDER1_CTL4, 0xFF}, + { LPASS_CDC_WSA_COMPANDER1_CTL5, 0x00}, + { LPASS_CDC_WSA_COMPANDER1_CTL6, 0x01}, + { LPASS_CDC_WSA_COMPANDER1_CTL7, 0x28}, + { LPASS_CDC_WSA_COMPANDER1_CTL8, 0x00}, + { LPASS_CDC_WSA_COMPANDER1_CTL9, 0x00}, + { LPASS_CDC_WSA_COMPANDER1_CTL10, 0x06}, + { LPASS_CDC_WSA_COMPANDER1_CTL11, 0x12}, + { LPASS_CDC_WSA_COMPANDER1_CTL12, 0x1E}, + { LPASS_CDC_WSA_COMPANDER1_CTL13, 0x24}, + { LPASS_CDC_WSA_COMPANDER1_CTL14, 0x24}, + { LPASS_CDC_WSA_COMPANDER1_CTL15, 0x24}, + { LPASS_CDC_WSA_COMPANDER1_CTL16, 0x00}, + { LPASS_CDC_WSA_COMPANDER1_CTL17, 0x24}, + { LPASS_CDC_WSA_COMPANDER1_CTL18, 0x2A}, + { LPASS_CDC_WSA_COMPANDER1_CTL19, 0x16}, + { LPASS_CDC_WSA_SOFTCLIP0_CRC, 0x00}, + { LPASS_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38}, + { LPASS_CDC_WSA_SOFTCLIP1_CRC, 0x00}, + { LPASS_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, + { LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01}, + { LPASS_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0, 0x01}, + { LPASS_CDC_WSA_IDLE_DETECT_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_IDLE_DETECT_CFG0, 0x07}, + { LPASS_CDC_WSA_IDLE_DETECT_CFG1, 0x3C}, + { LPASS_CDC_WSA_IDLE_DETECT_CFG2, 0x00}, + { LPASS_CDC_WSA_IDLE_DETECT_CFG3, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL1, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL2, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL3, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG1, 0x85}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG2, 0xDC}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG3, 0x85}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG4, 0xDC}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG5, 0x85}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG6, 0xDC}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG7, 0x32}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG8, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST1, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST2, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST3, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST4, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST1, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST2, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST3, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST4, 0x00}, + { LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST5, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_CFG, 0x10}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL1, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL2, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL3, 0x04}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST1, 0xE0}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST2, 0x01}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST3, 0x40}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_RF_PROC1, 0x2A}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_RF_PROC1, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC1, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC2, 0x18}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC3, 0x18}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC4, 0x03}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD1, 0x01}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD2, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD3, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD4, 0x64}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD5, 0x01}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_DEBUG1, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD_MON, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_MON_VAL, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BAN, 0x0C}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD1, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD2, 0x77}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD3, 0x01}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD4, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD5, 0x4B}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD6, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD7, 0x01}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD8, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD9, 0x00}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN1, 0x04}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN2, 0x08}, + { LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN3, 0x0C}, + /* lpass 2.6 new registers */ + { LPASS_CDC_WSA_PBR_PATH_CTL, 0x00}, + { LPASS_CDC_WSA_LA_CFG, 0x00}, + { LPASS_CDC_WSA_PBR_CFG1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG2, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG3, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG4, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG5, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG6, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG7, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG8, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG9, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG10, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG11, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG12, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG13, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG14, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG15, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG16, 0x00}, + { LPASS_CDC_WSA_PBR_CFG17, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG0, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG1, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG2, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG3, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG4, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG5, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG6, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG7, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG8, 0x00}, + { LPASS_CDC_WSA_LA_CFG_1, 0x00}, + { LPASS_CDC_WSA_PBR_CFG1_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG2_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG3_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG4_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG5_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG6_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG7_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG8_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG9_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG10_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG11_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG12_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG13_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG14_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG15_1, 0xFF}, + { LPASS_CDC_WSA_PBR_CFG16_1, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG0_1, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG1_1, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG2_1, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG5_1, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG9, 0x00}, + { LPASS_CDC_WSA_ILIM_CFG6_1, 0x00}, + { LPASS_CDC_WSA_PBR_CFG18, 0x00}, + { LPASS_CDC_WSA_PBR_CFG18_1, 0x00}, + { LPASS_CDC_WSA_PBR_CFG19, 0x00}, + { LPASS_CDC_WSA_PBR_CFG20, 0x00}, + { LPASS_CDC_WSA_PBR_CFG21, 0x00}, + { LPASS_CDC_WSA_PBR_CFG22, 0x00}, + { LPASS_CDC_WSA_PBR_CFG23, 0x00}, + + /* VA macro */ + { LPASS_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { LPASS_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { LPASS_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { LPASS_CDC_VA_TOP_CSR_TOP_CFG0, 0x00}, + { LPASS_CDC_VA_TOP_CSR_DMIC0_CTL, 0x00}, + { LPASS_CDC_VA_TOP_CSR_DMIC1_CTL, 0x00}, + { LPASS_CDC_VA_TOP_CSR_DMIC2_CTL, 0x00}, + { LPASS_CDC_VA_TOP_CSR_DMIC3_CTL, 0x00}, + { LPASS_CDC_VA_TOP_CSR_DMIC_CFG, 0x80}, + { LPASS_CDC_VA_TOP_CSR_VAD_MUX, 0x00}, + { LPASS_CDC_VA_TOP_CSR_DEBUG_BUS, 0x00}, + { LPASS_CDC_VA_TOP_CSR_DEBUG_EN, 0x00}, + { LPASS_CDC_VA_TOP_CSR_TX_I2S_CTL, 0x0C}, + { LPASS_CDC_VA_TOP_CSR_I2S_CLK, 0x00}, + { LPASS_CDC_VA_TOP_CSR_I2S_RESET, 0x00}, + { LPASS_CDC_VA_TOP_CSR_CORE_ID_0, 0x00}, + { LPASS_CDC_VA_TOP_CSR_CORE_ID_1, 0x00}, + { LPASS_CDC_VA_TOP_CSR_CORE_ID_2, 0x00}, + { LPASS_CDC_VA_TOP_CSR_CORE_ID_3, 0x00}, + { LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE}, + { LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE}, + { LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE}, + { LPASS_CDC_VA_TOP_CSR_SWR_CTRL, 0x06}, + { LPASS_CDC_VA_TOP_CSR_SEQ_CTL0, 0x00}, + + /* VA core */ + { LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0, 0x00}, + { LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG1, 0x00}, + { LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG0, 0x00}, + { LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG1, 0x00}, + { LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG0, 0x00}, + { LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG1, 0x00}, + { LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG0, 0x00}, + { LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG1, 0x00}, + { LPASS_CDC_VA_TX0_TX_PATH_CTL, 0x04}, + { LPASS_CDC_VA_TX0_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_VA_TX0_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_VA_TX0_TX_VOL_CTL, 0x00}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_VA_TX0_TX_PATH_SEC7, 0x25}, + { LPASS_CDC_VA_TX1_TX_PATH_CTL, 0x04}, + { LPASS_CDC_VA_TX1_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_VA_TX1_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_VA_TX1_TX_VOL_CTL, 0x00}, + { LPASS_CDC_VA_TX1_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_VA_TX1_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_VA_TX1_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_VA_TX1_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_VA_TX1_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_VA_TX1_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_VA_TX1_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_VA_TX2_TX_PATH_CTL, 0x04}, + { LPASS_CDC_VA_TX2_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_VA_TX2_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_VA_TX2_TX_VOL_CTL, 0x00}, + { LPASS_CDC_VA_TX2_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_VA_TX2_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_VA_TX2_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_VA_TX2_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_VA_TX2_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_VA_TX2_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_VA_TX2_TX_PATH_SEC6, 0x00}, + { LPASS_CDC_VA_TX3_TX_PATH_CTL, 0x04}, + { LPASS_CDC_VA_TX3_TX_PATH_CFG0, 0x10}, + { LPASS_CDC_VA_TX3_TX_PATH_CFG1, 0x0B}, + { LPASS_CDC_VA_TX3_TX_VOL_CTL, 0x00}, + { LPASS_CDC_VA_TX3_TX_PATH_SEC0, 0x00}, + { LPASS_CDC_VA_TX3_TX_PATH_SEC1, 0x00}, + { LPASS_CDC_VA_TX3_TX_PATH_SEC2, 0x01}, + { LPASS_CDC_VA_TX3_TX_PATH_SEC3, 0x3C}, + { LPASS_CDC_VA_TX3_TX_PATH_SEC4, 0x20}, + { LPASS_CDC_VA_TX3_TX_PATH_SEC5, 0x00}, + { LPASS_CDC_VA_TX3_TX_PATH_SEC6, 0x00}, + + /* WSA2 Macro */ + { LPASS_CDC_WSA2_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { LPASS_CDC_WSA2_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { LPASS_CDC_WSA2_TOP_TOP_CFG0, 0x00}, + { LPASS_CDC_WSA2_TOP_TOP_CFG1, 0x00}, + { LPASS_CDC_WSA2_TOP_FREQ_MCLK, 0x00}, + { LPASS_CDC_WSA2_TOP_DEBUG_BUS_SEL, 0x00}, + { LPASS_CDC_WSA2_TOP_DEBUG_EN0, 0x00}, + { LPASS_CDC_WSA2_TOP_DEBUG_EN1, 0x00}, + { LPASS_CDC_WSA2_TOP_DEBUG_DSM_LB, 0x88}, + { LPASS_CDC_WSA2_TOP_RX_I2S_CTL, 0x0C}, + { LPASS_CDC_WSA2_TOP_TX_I2S_CTL, 0x0C}, + { LPASS_CDC_WSA2_TOP_I2S_CLK, 0x02}, + { LPASS_CDC_WSA2_TOP_I2S_RESET, 0x00}, + { LPASS_CDC_WSA2_TOP_FS_UNGATE, 0xFF}, + { LPASS_CDC_WSA2_TOP_GRP_SEL, 0x08}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP7_WR_LSB, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP7_WR_MSB, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP7_LUT, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP7_RD_LSB, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP7_RD_MSB, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP8_WR_LSB, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP8_WR_MSB, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP8_LUT, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP8_RD_LSB, 0x00}, + { LPASS_CDC_WSA2_TOP_SPKR_COMP8_RD_MSB, 0x00}, + { LPASS_CDC_WSA2_TOP_FS_UNGATE2, 0x03}, + { LPASS_CDC_WSA2_TOP_SEQ_CTL0, 0x00}, + { LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0, 0x00}, + { LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1, 0x00}, + { LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG0, 0x00}, + { LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG1, 0x00}, + { LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0, 0x00}, + { LPASS_CDC_WSA2_RX_INP_MUX_RX_EC_CFG0, 0x00}, + { LPASS_CDC_WSA2_RX_INP_MUX_SOFTCLIP_CFG0, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG, 0x10}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL1, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL2, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL3, 0x04}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST1, 0xE0}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST2, 0x01}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST3, 0x40}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_RF_PROC1, 0x2A}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_RF_PROC2, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC1, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC2, 0x18}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC3, 0x18}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC4, 0x03}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD1, 0x01}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD2, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD3, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD4, 0x64}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD5, 0x01}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_DEBUG1, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD_MON, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_MON_VAL, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BAN, 0x0C}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD1, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD2, 0x77}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD3, 0x01}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD4, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD5, 0x4B}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD6, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD7, 0x01}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD8, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD9, 0x00}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN1, 0x04}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN2, 0x08}, + { LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN3, 0x0C}, + { LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, 0x04}, + { LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CFG0, 0x02}, + { LPASS_CDC_WSA2_INTR_CTRL_CFG, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_CLR_COMMIT, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_PIN1_MASK0, 0xFF}, + { LPASS_CDC_WSA2_INTR_CTRL_PIN1_STATUS0, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_PIN1_CLEAR0, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_PIN2_MASK0, 0xFF}, + { LPASS_CDC_WSA2_INTR_CTRL_PIN2_STATUS0, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_PIN2_CLEAR0, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_LEVEL0, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_BYPASS0, 0x00}, + { LPASS_CDC_WSA2_INTR_CTRL_SET0, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_CTL, 0x04}, + { LPASS_CDC_WSA2_RX0_RX_PATH_CFG0, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, 0x64}, + { LPASS_CDC_WSA2_RX0_RX_PATH_CFG2, 0x8F}, + { LPASS_CDC_WSA2_RX0_RX_PATH_CFG3, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_VOL_CTL, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL, 0x04}, + { LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CFG, 0x7E}, + { LPASS_CDC_WSA2_RX0_RX_VOL_MIX_CTL, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_SEC0, 0x04}, + { LPASS_CDC_WSA2_RX0_RX_PATH_SEC1, 0x08}, + { LPASS_CDC_WSA2_RX0_RX_PATH_SEC2, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_SEC3, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_SEC5, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_SEC6, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_SEC7, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_MIX_SEC0, 0x08}, + { LPASS_CDC_WSA2_RX0_RX_PATH_MIX_SEC1, 0x00}, + { LPASS_CDC_WSA2_RX0_RX_PATH_DSMDEM_CTL, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_CFG0, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_CFG1, 0x64}, + { LPASS_CDC_WSA2_RX1_RX_PATH_CFG2, 0x8F}, + { LPASS_CDC_WSA2_RX1_RX_PATH_CFG3, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_VOL_CTL, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CTL, 0x04}, + { LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CFG, 0x7E}, + { LPASS_CDC_WSA2_RX1_RX_VOL_MIX_CTL, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_SEC0, 0x04}, + { LPASS_CDC_WSA2_RX1_RX_PATH_SEC1, 0x08}, + { LPASS_CDC_WSA2_RX1_RX_PATH_SEC2, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_SEC3, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_SEC5, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_SEC6, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_SEC7, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_MIX_SEC0, 0x08}, + { LPASS_CDC_WSA2_RX1_RX_PATH_MIX_SEC1, 0x00}, + { LPASS_CDC_WSA2_RX1_RX_PATH_DSMDEM_CTL, 0x00}, + { LPASS_CDC_WSA2_BOOST0_BOOST_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_BOOST0_BOOST_CTL, 0xD0}, + { LPASS_CDC_WSA2_BOOST0_BOOST_CFG1, 0x89}, + { LPASS_CDC_WSA2_BOOST0_BOOST_CFG2, 0x04}, + { LPASS_CDC_WSA2_BOOST1_BOOST_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_BOOST1_BOOST_CTL, 0xD0}, + { LPASS_CDC_WSA2_BOOST1_BOOST_CFG1, 0x89}, + { LPASS_CDC_WSA2_BOOST1_BOOST_CFG2, 0x04}, + { LPASS_CDC_WSA2_COMPANDER0_CTL0, 0x60}, + { LPASS_CDC_WSA2_COMPANDER0_CTL1, 0xDB}, + { LPASS_CDC_WSA2_COMPANDER0_CTL2, 0xFF}, + { LPASS_CDC_WSA2_COMPANDER0_CTL3, 0x35}, + { LPASS_CDC_WSA2_COMPANDER0_CTL4, 0xFF}, + { LPASS_CDC_WSA2_COMPANDER0_CTL5, 0x00}, + { LPASS_CDC_WSA2_COMPANDER0_CTL6, 0x01}, + { LPASS_CDC_WSA2_COMPANDER0_CTL7, 0x28}, + { LPASS_CDC_WSA2_COMPANDER0_CTL8, 0x00}, + { LPASS_CDC_WSA2_COMPANDER0_CTL9, 0x00}, + { LPASS_CDC_WSA2_COMPANDER0_CTL10, 0x06}, + { LPASS_CDC_WSA2_COMPANDER0_CTL11, 0x12}, + { LPASS_CDC_WSA2_COMPANDER0_CTL12, 0x1E}, + { LPASS_CDC_WSA2_COMPANDER0_CTL13, 0x24}, + { LPASS_CDC_WSA2_COMPANDER0_CTL14, 0x24}, + { LPASS_CDC_WSA2_COMPANDER0_CTL15, 0x24}, + { LPASS_CDC_WSA2_COMPANDER0_CTL16, 0x00}, + { LPASS_CDC_WSA2_COMPANDER0_CTL17, 0x24}, + { LPASS_CDC_WSA2_COMPANDER0_CTL18, 0x2A}, + { LPASS_CDC_WSA2_COMPANDER0_CTL19, 0x16}, + { LPASS_CDC_WSA2_COMPANDER1_CTL0, 0x60}, + { LPASS_CDC_WSA2_COMPANDER1_CTL1, 0xDB}, + { LPASS_CDC_WSA2_COMPANDER1_CTL2, 0xFF}, + { LPASS_CDC_WSA2_COMPANDER1_CTL3, 0x35}, + { LPASS_CDC_WSA2_COMPANDER1_CTL4, 0xFF}, + { LPASS_CDC_WSA2_COMPANDER1_CTL5, 0x00}, + { LPASS_CDC_WSA2_COMPANDER1_CTL6, 0x01}, + { LPASS_CDC_WSA2_COMPANDER1_CTL7, 0x28}, + { LPASS_CDC_WSA2_COMPANDER1_CTL8, 0x00}, + { LPASS_CDC_WSA2_COMPANDER1_CTL9, 0x00}, + { LPASS_CDC_WSA2_COMPANDER1_CTL10, 0x06}, + { LPASS_CDC_WSA2_COMPANDER1_CTL11, 0x12}, + { LPASS_CDC_WSA2_COMPANDER1_CTL12, 0x1E}, + { LPASS_CDC_WSA2_COMPANDER1_CTL13, 0x24}, + { LPASS_CDC_WSA2_COMPANDER1_CTL14, 0x24}, + { LPASS_CDC_WSA2_COMPANDER1_CTL15, 0x24}, + { LPASS_CDC_WSA2_COMPANDER1_CTL16, 0x00}, + { LPASS_CDC_WSA2_COMPANDER1_CTL17, 0x24}, + { LPASS_CDC_WSA2_COMPANDER1_CTL18, 0x2A}, + { LPASS_CDC_WSA2_COMPANDER1_CTL19, 0x16}, + { LPASS_CDC_WSA2_SOFTCLIP0_CRC, 0x00}, + { LPASS_CDC_WSA2_SOFTCLIP0_SOFTCLIP_CTRL, 0x38}, + { LPASS_CDC_WSA2_SOFTCLIP1_CRC, 0x00}, + { LPASS_CDC_WSA2_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, + { LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_CFG0, 0x01}, + { LPASS_CDC_WSA2_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_EC_HQ1_EC_REF_HQ_CFG0, 0x01}, + { LPASS_CDC_WSA2_IDLE_DETECT_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_IDLE_DETECT_CFG0, 0x07}, + { LPASS_CDC_WSA2_IDLE_DETECT_CFG1, 0x3C}, + { LPASS_CDC_WSA2_IDLE_DETECT_CFG2, 0x00}, + { LPASS_CDC_WSA2_IDLE_DETECT_CFG3, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG1, 0x85}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG2, 0xDC}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG3, 0x85}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG4, 0xDC}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG5, 0x85}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG6, 0xDC}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG7, 0x32}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG8, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST1, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST2, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST3, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST4, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST1, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST2, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST3, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST4, 0x00}, + { LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST5, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_CFG, 0x10}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL1, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL2, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL3, 0x04}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST1, 0xE0}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST2, 0x01}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST3, 0x40}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_RF_PROC1, 0x2A}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_RF_PROC1, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC1, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC2, 0x18}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC3, 0x18}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC4, 0x03}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD1, 0x01}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD2, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD3, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD4, 0x64}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD5, 0x01}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_DEBUG1, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD_MON, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_MON_VAL, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BAN, 0x0C}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD1, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD2, 0x77}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD3, 0x01}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD4, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD5, 0x4B}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD6, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD7, 0x01}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD8, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD9, 0x00}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN1, 0x04}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN2, 0x08}, + { LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN3, 0x0C}, + /* lpass 2.6 new registers */ + { LPASS_CDC_WSA2_PBR_PATH_CTL, 0x00}, + { LPASS_CDC_WSA2_LA_CFG, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG2, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG3, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG4, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG5, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG6, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG7, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG8, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG9, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG10, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG11, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG12, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG13, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG14, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG15, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG16, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG17, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG0, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG1, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG2, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG3, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG4, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG5, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG6, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG7, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG8, 0x00}, + { LPASS_CDC_WSA2_LA_CFG_1, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG1_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG2_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG3_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG4_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG5_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG6_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG7_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG8_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG9_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG10_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG11_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG12_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG13_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG14_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG15_1, 0xFF}, + { LPASS_CDC_WSA2_PBR_CFG16_1, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG0_1, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG1_1, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG2_1, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG5_1, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG9, 0x00}, + { LPASS_CDC_WSA2_ILIM_CFG6_1, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG18, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG18_1, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG19, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG20, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG21, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG22, 0x00}, + { LPASS_CDC_WSA2_PBR_CFG23, 0x00}, +}; + +static bool lpass_cdc_is_readable_register(struct device *dev, + unsigned int reg) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(dev); + u16 reg_offset; + int macro_id; + u8 *reg_tbl = NULL; + + if (!priv) + return false; + + macro_id = lpass_cdc_get_macro_id(priv->va_without_decimation, + reg); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return false; + + reg_tbl = lpass_cdc_reg_access[macro_id]; + reg_offset = (reg - macro_id_base_offset[macro_id])/4; + + if (reg_tbl) + return (reg_tbl[reg_offset] & RD_REG); + + return false; +} + +static bool lpass_cdc_is_writeable_register(struct device *dev, + unsigned int reg) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(dev); + u16 reg_offset; + int macro_id; + const u8 *reg_tbl = NULL; + + if (!priv) + return false; + + macro_id = lpass_cdc_get_macro_id(priv->va_without_decimation, + reg); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return false; + + reg_tbl = lpass_cdc_reg_access[macro_id]; + reg_offset = (reg - macro_id_base_offset[macro_id])/4; + + if (reg_tbl) + return (reg_tbl[reg_offset] & WR_REG); + + return false; +} + +static bool lpass_cdc_is_volatile_register(struct device *dev, + unsigned int reg) +{ + /* Update volatile list for rx/tx macros */ + switch (reg) { + case LPASS_CDC_VA_TOP_CSR_CORE_ID_0: + case LPASS_CDC_VA_TOP_CSR_CORE_ID_1: + case LPASS_CDC_VA_TOP_CSR_CORE_ID_2: + case LPASS_CDC_VA_TOP_CSR_CORE_ID_3: + case LPASS_CDC_VA_TOP_CSR_DMIC0_CTL: + case LPASS_CDC_VA_TOP_CSR_DMIC1_CTL: + case LPASS_CDC_VA_TOP_CSR_DMIC2_CTL: + case LPASS_CDC_VA_TOP_CSR_DMIC3_CTL: + case LPASS_CDC_TX_TOP_CSR_SWR_MIC2_CTL: + case LPASS_CDC_TX_TOP_CSR_SWR_MIC3_CTL: + case LPASS_CDC_TX_TOP_CSR_SWR_MIC4_CTL: + case LPASS_CDC_TX_TOP_CSR_SWR_MIC5_CTL: + case LPASS_CDC_TX_TOP_CSR_SWR_MIC0_CTL: + case LPASS_CDC_TX_TOP_CSR_SWR_MIC1_CTL: + case LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL: + case LPASS_CDC_WSA_INTR_CTRL_PIN1_STATUS0: + case LPASS_CDC_WSA_INTR_CTRL_PIN2_STATUS0: + case LPASS_CDC_WSA_COMPANDER0_CTL6: + case LPASS_CDC_WSA_COMPANDER1_CTL6: + case LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_MON_VAL: + case LPASS_CDC_WSA2_INTR_CTRL_PIN1_STATUS0: + case LPASS_CDC_WSA2_INTR_CTRL_PIN2_STATUS0: + case LPASS_CDC_WSA2_COMPANDER0_CTL6: + case LPASS_CDC_WSA2_COMPANDER1_CTL6: + case LPASS_CDC_RX_TOP_HPHL_COMP_RD_LSB: + case LPASS_CDC_RX_TOP_HPHL_COMP_WR_LSB: + case LPASS_CDC_RX_TOP_HPHL_COMP_RD_MSB: + case LPASS_CDC_RX_TOP_HPHL_COMP_WR_MSB: + case LPASS_CDC_RX_TOP_HPHR_COMP_RD_LSB: + case LPASS_CDC_RX_TOP_HPHR_COMP_WR_LSB: + case LPASS_CDC_RX_TOP_HPHR_COMP_RD_MSB: + case LPASS_CDC_RX_TOP_HPHR_COMP_WR_MSB: + case LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG2: + case LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG2: + case LPASS_CDC_RX_BCL_VBAT_GAIN_MON_VAL: + case LPASS_CDC_RX_INTR_CTRL_PIN1_STATUS0: + case LPASS_CDC_RX_INTR_CTRL_PIN2_STATUS0: + case LPASS_CDC_RX_COMPANDER0_CTL6: + case LPASS_CDC_RX_COMPANDER1_CTL6: + case LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB: + case LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB: + case LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB: + case LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB: + case LPASS_CDC_RX_EC_ASRC0_STATUS_FIFO: + case LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB: + case LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB: + case LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB: + case LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB: + case LPASS_CDC_RX_EC_ASRC1_STATUS_FIFO: + case LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB: + case LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB: + case LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB: + case LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB: + case LPASS_CDC_RX_EC_ASRC2_STATUS_FIFO: + case LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL: + case LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL: + case LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL: + case LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL: +#ifdef CONFIG_BOLERO_VER_2P6 + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_ADDR: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA0: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA1: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA2: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA3: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA4: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA5: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA6: + case LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA7: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_ADDR: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA0: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA1: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA2: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA3: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA4: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA5: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA6: + case LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA7: + case LPASS_CDC_RX_RX0_RX_FIR_CTL: + case LPASS_CDC_RX_RX1_RX_FIR_CTL: + case LPASS_CDC_RX_RX0_RX_PATH_CTL: + case LPASS_CDC_RX_RX1_RX_PATH_CTL: +#endif + return true; + } + return false; +} + +const struct regmap_config lpass_cdc_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .reg_stride = 4, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = lpass_cdc_defaults, + .num_reg_defaults = ARRAY_SIZE(lpass_cdc_defaults), + .max_register = LPASS_CDC_MAX_REGISTER, + .writeable_reg = lpass_cdc_is_writeable_register, + .volatile_reg = lpass_cdc_is_volatile_register, + .readable_reg = lpass_cdc_is_readable_register, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c new file mode 100644 index 0000000000..d324d10bb9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c @@ -0,0 +1,5026 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "lpass-cdc.h" +#include "lpass-cdc-comp.h" +#include "lpass-cdc-registers.h" +#include "lpass-cdc-clk-rsc.h" + +#define AUTO_SUSPEND_DELAY 50 /* delay in msec */ +#define LPASS_CDC_RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define LPASS_CDC_RX_MACRO_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define LPASS_CDC_RX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define LPASS_CDC_RX_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_48000) +#define LPASS_CDC_RX_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define SAMPLING_RATE_44P1KHZ 44100 +#define SAMPLING_RATE_88P2KHZ 88200 +#define SAMPLING_RATE_176P4KHZ 176400 +#define SAMPLING_RATE_352P8KHZ 352800 + +#define LPASS_CDC_RX_MACRO_MAX_OFFSET 0x1000 + +#define LPASS_CDC_RX_MACRO_MAX_DMA_CH_PER_PORT 2 +#define RX_SWR_STRING_LEN 80 +#define LPASS_CDC_RX_MACRO_CHILD_DEVICES_MAX 3 + +#define LPASS_CDC_RX_MACRO_INTERP_MUX_NUM_INPUTS 3 +#define LPASS_CDC_RX_MACRO_SIDETONE_IIR_COEFF_MAX 5 +#ifdef CONFIG_BOLERO_VER_2P6 +#define LPASS_CDC_RX_MACRO_FIR_COEFF_MAX 100 +#define LPASS_CDC_RX_MACRO_FIR_COEFF_ARRAY_MAX \ + (LPASS_CDC_RX_MACRO_FIR_COEFF_MAX + 1) +/* first value represent number of coefficients in each 100 integer group */ +#define LPASS_CDC_RX_MACRO_FIR_FILTER_BYTES \ + (sizeof(u32) * LPASS_CDC_RX_MACRO_FIR_COEFF_ARRAY_MAX) +#endif + +#define STRING(name) #name +#define LPASS_CDC_RX_MACRO_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define LPASS_CDC_RX_MACRO_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +#define LPASS_CDC_RX_MACRO_RX_PATH_OFFSET \ + (LPASS_CDC_RX_RX1_RX_PATH_CTL - LPASS_CDC_RX_RX0_RX_PATH_CTL) +#define LPASS_CDC_RX_MACRO_COMP_OFFSET \ + (LPASS_CDC_RX_COMPANDER1_CTL0 - LPASS_CDC_RX_COMPANDER0_CTL0) + +#define MAX_IMPED_PARAMS 6 + +#define LPASS_CDC_RX_MACRO_EC_MIX_TX0_MASK 0xf0 +#define LPASS_CDC_RX_MACRO_EC_MIX_TX1_MASK 0x0f +#define LPASS_CDC_RX_MACRO_EC_MIX_TX2_MASK 0x0f + +#define LPASS_CDC_RX_MACRO_GAIN_MAX_VAL 0x28 +#define LPASS_CDC_RX_MACRO_GAIN_VAL_UNITY 0x0 +/* Define macros to increase PA Gain by half */ +#define LPASS_CDC_RX_MACRO_MOD_GAIN (LPASS_CDC_RX_MACRO_GAIN_VAL_UNITY + 6) + +#define COMP_MAX_COEFF 25 + +struct wcd_imped_val { + u32 imped_val; + u8 index; +}; + +static const struct wcd_imped_val imped_index[] = { + {4, 0}, + {5, 1}, + {6, 2}, + {7, 3}, + {8, 4}, + {9, 5}, + {10, 6}, + {11, 7}, + {12, 8}, + {13, 9}, +}; + +enum { + HPH_ULP, + HPH_LOHIFI, + HPH_MODE_MAX, +}; + +static struct comp_coeff_val + comp_coeff_table [HPH_MODE_MAX][COMP_MAX_COEFF] = { + { + {0x40, 0x00}, + {0x4C, 0x00}, + {0x5A, 0x00}, + {0x6B, 0x00}, + {0x7F, 0x00}, + {0x97, 0x00}, + {0xB3, 0x00}, + {0xD5, 0x00}, + {0xFD, 0x00}, + {0x2D, 0x01}, + {0x66, 0x01}, + {0xA7, 0x01}, + {0xF8, 0x01}, + {0x57, 0x02}, + {0xC7, 0x02}, + {0x4B, 0x03}, + {0xE9, 0x03}, + {0xA3, 0x04}, + {0x7D, 0x05}, + {0x90, 0x06}, + {0xD1, 0x07}, + {0x49, 0x09}, + {0x00, 0x0B}, + {0x01, 0x0D}, + {0x59, 0x0F}, + }, + { + {0x40, 0x00}, + {0x4C, 0x00}, + {0x5A, 0x00}, + {0x6B, 0x00}, + {0x80, 0x00}, + {0x98, 0x00}, + {0xB4, 0x00}, + {0xD5, 0x00}, + {0xFE, 0x00}, + {0x2E, 0x01}, + {0x66, 0x01}, + {0xA9, 0x01}, + {0xF8, 0x01}, + {0x56, 0x02}, + {0xC4, 0x02}, + {0x4F, 0x03}, + {0xF0, 0x03}, + {0xAE, 0x04}, + {0x8B, 0x05}, + {0x8E, 0x06}, + {0xBC, 0x07}, + {0x56, 0x09}, + {0x0F, 0x0B}, + {0x13, 0x0D}, + {0x6F, 0x0F}, + }, +}; + +enum { + RX_MODE_ULP, + RX_MODE_LOHIFI, + RX_MODE_EAR, + RX_MODE_MAX +}; + +#ifdef CONFIG_BOLERO_VER_2P6 +static struct lpass_cdc_comp_setting comp_setting_table[RX_MODE_MAX] = +{ + {12, -60, 12}, + {0, -60, 12}, + {12, -36, 12}, +}; +#endif + +struct lpass_cdc_rx_macro_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static const struct lpass_cdc_rx_macro_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = { + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf2}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf2}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf4}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf4}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf7}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x01}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf7}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xf9}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xf9}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfa}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfa}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfb}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfb}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfc}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfc}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x00}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX0_RX_PATH_SEC1, 0x01, 0x01}, + {LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC1, 0x01, 0x01}, + }, +}; + +enum { + INTERP_HPHL, + INTERP_HPHR, + INTERP_AUX, + INTERP_MAX +}; + +enum { + LPASS_CDC_RX_MACRO_RX0, + LPASS_CDC_RX_MACRO_RX1, + LPASS_CDC_RX_MACRO_RX2, + LPASS_CDC_RX_MACRO_RX3, + LPASS_CDC_RX_MACRO_RX4, + LPASS_CDC_RX_MACRO_RX5, + LPASS_CDC_RX_MACRO_PORTS_MAX +}; + +enum { + LPASS_CDC_RX_MACRO_COMP1, /* HPH_L */ + LPASS_CDC_RX_MACRO_COMP2, /* HPH_R */ + LPASS_CDC_RX_MACRO_COMP_MAX +}; + +enum { + LPASS_CDC_RX_MACRO_EC0_MUX = 0, + LPASS_CDC_RX_MACRO_EC1_MUX, + LPASS_CDC_RX_MACRO_EC2_MUX, + LPASS_CDC_RX_MACRO_EC_MUX_MAX, +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, + INTn_1_INP_SEL_IIR0, + INTn_1_INP_SEL_IIR1, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_RX4, + INTn_1_INP_SEL_RX5, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, +}; + +enum { + INTERP_MAIN_PATH, + INTERP_MIX_PATH, +}; + +/* Codec supports 2 IIR filters */ +enum { + IIR0 = 0, + IIR1, + IIR_MAX, +}; + +/* Each IIR has 5 Filter Stages */ +enum { + BAND1 = 0, + BAND2, + BAND3, + BAND4, + BAND5, + BAND_MAX, +}; + +#define LPASS_CDC_RX_MACRO_IIR_FILTER_SIZE (sizeof(u32) * BAND_MAX) + +struct lpass_cdc_rx_macro_iir_filter_ctl { + unsigned int iir_idx; + unsigned int band_idx; + struct soc_bytes_ext bytes_ext; +}; + +#define LPASS_CDC_RX_MACRO_IIR_FILTER_CTL(xname, iidx, bidx) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = lpass_cdc_rx_macro_iir_filter_info, \ + .get = lpass_cdc_rx_macro_iir_band_audio_mixer_get, \ + .put = lpass_cdc_rx_macro_iir_band_audio_mixer_put, \ + .private_value = (unsigned long)&(struct lpass_cdc_rx_macro_iir_filter_ctl) { \ + .iir_idx = iidx, \ + .band_idx = bidx, \ + .bytes_ext = {.max = LPASS_CDC_RX_MACRO_IIR_FILTER_SIZE, }, \ + } \ +} + +#ifdef CONFIG_BOLERO_VER_2P6 +/* Codec supports 2 FIR filters Path */ +enum { + RX0_PATH = 0, + RX1_PATH, + FIR_PATH_MAX, +}; + +/* Each RX Path has 2 group of coefficients */ +enum { + GRP0 = 0, + GRP1, + GRP_MAX, +}; + +struct lpass_cdc_rx_macro_fir_filter_ctl { + unsigned int path_idx; + unsigned int grp_idx; + struct soc_bytes_ext bytes_ext; +}; + +#define LPASS_CDC_RX_MACRO_FIR_FILTER_CTL(xname, pidx, gidx) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = lpass_cdc_rx_macro_fir_filter_info, \ + .get = lpass_cdc_rx_macro_fir_audio_mixer_get, \ + .put = lpass_cdc_rx_macro_fir_audio_mixer_put, \ + .private_value = (unsigned long)&(struct lpass_cdc_rx_macro_fir_filter_ctl) { \ + .path_idx = pidx, \ + .grp_idx = gidx, \ + .bytes_ext = {.max = LPASS_CDC_RX_MACRO_FIR_FILTER_BYTES, }, \ + } \ +} +#endif + +struct lpass_cdc_rx_macro_idle_detect_config { + u8 hph_idle_thr; + u8 hph_idle_detect_en; +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +static struct interp_sample_rate sr_val_tbl[] = { + {8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5}, + {192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA}, + {176400, 0xB}, {352800, 0xC}, +}; + +struct lpass_cdc_rx_macro_bcl_pmic_params { + u8 id; + u8 sid; + u8 ppid; +}; + +static int lpass_cdc_rx_macro_core_vote(void *handle, bool enable); +static int lpass_cdc_rx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +static int lpass_cdc_rx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); +static int lpass_cdc_rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int lpass_cdc_rx_macro_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int lpass_cdc_rx_macro_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int lpass_cdc_rx_macro_enable_interp_clk(struct snd_soc_component *component, + int event, int interp_idx); + +/* Hold instance to soundwire platform device */ +struct rx_swr_ctrl_data { + struct platform_device *rx_swr_pdev; +}; + +struct rx_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +enum { + RX_MACRO_AIF_INVALID = 0, + RX_MACRO_AIF1_PB, + RX_MACRO_AIF2_PB, + RX_MACRO_AIF3_PB, + RX_MACRO_AIF4_PB, + RX_MACRO_AIF_ECHO, + RX_MACRO_AIF5_PB, + RX_MACRO_AIF6_PB, + LPASS_CDC_RX_MACRO_MAX_DAIS, +}; + +enum { + RX_MACRO_AIF1_CAP = 0, + RX_MACRO_AIF2_CAP, + RX_MACRO_AIF3_CAP, + LPASS_CDC_RX_MACRO_MAX_AIF_CAP_DAIS +}; +/* + * @dev: rx macro device pointer + * @comp_enabled: compander enable mixer value set + * @prim_int_users: Users of interpolator + * @rx_mclk_users: RX MCLK users count + * @vi_feed_value: VI sense mask + * @swr_clk_lock: to lock swr master clock operations + * @swr_ctrl_data: SoundWire data structure + * @swr_plat_data: Soundwire platform data + * @lpass_cdc_rx_macro_add_child_devices_work: work for adding child devices + * @rx_swr_gpio_p: used by pinctrl API + * @component: codec handle + */ +struct lpass_cdc_rx_macro_priv { + struct device *dev; + int comp_enabled[LPASS_CDC_RX_MACRO_COMP_MAX]; + u8 is_pcm_enabled; + /* Main path clock users count */ + int main_clk_users[INTERP_MAX]; + int rx_port_value[LPASS_CDC_RX_MACRO_PORTS_MAX]; + u16 prim_int_users[INTERP_MAX]; + int rx_mclk_users; + int swr_clk_users; + bool dapm_mclk_enable; + bool reset_swr; + int clsh_users; + int rx_mclk_cnt; +#ifdef CONFIG_BOLERO_VER_2P6 + u8 fir_total_coeff_num[FIR_PATH_MAX]; + bool is_fir_coeff_written[FIR_PATH_MAX][GRP_MAX]; + u32 fir_coeff_array[FIR_PATH_MAX][GRP_MAX] + [LPASS_CDC_RX_MACRO_FIR_COEFF_MAX]; + u32 num_fir_coeff[FIR_PATH_MAX][GRP_MAX]; +#endif + bool is_native_on; + bool is_ear_mode_on; + bool is_fir_filter_on; + bool is_fir_capable; + bool dev_up; + bool pre_dev_up; + bool hph_pwr_mode; + bool hph_hd2_mode; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct rx_swr_ctrl_data *swr_ctrl_data; + struct rx_swr_ctrl_platform_data swr_plat_data; + struct work_struct lpass_cdc_rx_macro_add_child_devices_work; + struct device_node *rx_swr_gpio_p; + struct snd_soc_component *component; + unsigned long active_ch_mask[LPASS_CDC_RX_MACRO_MAX_DAIS]; + unsigned long active_ch_cnt[LPASS_CDC_RX_MACRO_MAX_DAIS]; + u16 bit_width[LPASS_CDC_RX_MACRO_MAX_DAIS]; + char __iomem *rx_io_base; + char __iomem *rx_mclk_mode_muxsel; + struct lpass_cdc_rx_macro_idle_detect_config idle_det_cfg; + u8 sidetone_coeff_array[IIR_MAX][BAND_MAX] + [LPASS_CDC_RX_MACRO_SIDETONE_IIR_COEFF_MAX * 4]; + /* NOT designed to always reflect the actual hardware value */ + struct platform_device *pdev_child_devices + [LPASS_CDC_RX_MACRO_CHILD_DEVICES_MAX]; + int child_count; + int is_softclip_on; + int is_aux_hpf_on; + int softclip_clk_users; + struct lpass_cdc_rx_macro_bcl_pmic_params bcl_pmic_params; + u16 clk_id; + u16 default_clk_id; + struct clk *hifi_fir_clk; + int8_t rx0_gain_val; + int8_t rx1_gain_val; + int pcm_select_users; +}; + +static struct snd_soc_dai_driver lpass_cdc_rx_macro_dai[]; +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5" +}; + +static const char * const rx_sidetone_mix_text[] = { + "ZERO", "SRC0", "SRC1", "SRC_SUM" +}; + +static const char * const iir_inp_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", + "RX0", "RX1", "RX2", "RX3", "RX4", "RX5" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_1_interp_mux_text[] = { + "ZERO", "RX INT0_1 MIX1", +}; + +static const char * const rx_int1_1_interp_mux_text[] = { + "ZERO", "RX INT1_1 MIX1", +}; + +static const char * const rx_int2_1_interp_mux_text[] = { + "ZERO", "RX INT2_1 MIX1", +}; + +static const char * const rx_int0_2_interp_mux_text[] = { + "ZERO", "RX INT0_2 MUX", +}; + +static const char * const rx_int1_2_interp_mux_text[] = { + "ZERO", "RX INT1_2 MUX", +}; + +static const char * const rx_int2_2_interp_mux_text[] = { + "ZERO", "RX INT2_2 MUX", +}; + +static const char *const lpass_cdc_rx_macro_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB" +}; + +static const char *const lpass_cdc_rx_macro_ear_mode_text[] = {"OFF", "ON"}; +static const struct soc_enum lpass_cdc_rx_macro_ear_mode_enum = + SOC_ENUM_SINGLE_EXT(2, lpass_cdc_rx_macro_ear_mode_text); + +static const char *const lpass_cdc_rx_macro_hph_hd2_mode_text[] = {"OFF", "ON"}; +static const struct soc_enum lpass_cdc_rx_macro_hph_hd2_mode_enum = + SOC_ENUM_SINGLE_EXT(2, lpass_cdc_rx_macro_hph_hd2_mode_text); + +static const char *const lpass_cdc_rx_macro_hph_pwr_mode_text[] = {"ULP", "LOHIFI"}; +static const struct soc_enum lpass_cdc_rx_macro_hph_pwr_mode_enum = + SOC_ENUM_SINGLE_EXT(2, lpass_cdc_rx_macro_hph_pwr_mode_text); + +static const char * const lpass_cdc_rx_macro_vbat_bcl_gsm_mode_text[] = {"OFF", "ON"}; +static const struct soc_enum lpass_cdc_rx_macro_vbat_bcl_gsm_mode_enum = + SOC_ENUM_SINGLE_EXT(2, lpass_cdc_rx_macro_vbat_bcl_gsm_mode_text); + +#ifdef CONFIG_BOLERO_VER_2P6 +static const char *const lpass_cdc_rx_macro_fir_filter_text[] = {"OFF", "ON"}; +static const struct soc_enum lpass_cdc_rx_macro_fir_filter_enum = + SOC_ENUM_SINGLE_EXT(2, lpass_cdc_rx_macro_fir_filter_text); +#endif + +static const struct snd_kcontrol_new rx_int2_1_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("RX AUX VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const char * const hph_idle_detect_text[] = {"OFF", "ON"}; + +static SOC_ENUM_SINGLE_EXT_DECL(hph_idle_detect_enum, hph_idle_detect_text); + +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int0_2, LPASS_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, + rx_int_mix_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int1_2, LPASS_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, + rx_int_mix_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int2_2, LPASS_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, + rx_int_mix_mux_text); + + +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int0_1_mix_inp0, LPASS_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int0_1_mix_inp1, LPASS_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int0_1_mix_inp2, LPASS_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int1_1_mix_inp0, LPASS_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int1_1_mix_inp1, LPASS_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int1_1_mix_inp2, LPASS_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int2_1_mix_inp0, LPASS_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int2_1_mix_inp1, LPASS_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, + rx_prim_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int2_1_mix_inp2, LPASS_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, + rx_prim_mix_text); + +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int0_mix2_inp, LPASS_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, + rx_sidetone_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int1_mix2_inp, LPASS_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, + rx_sidetone_mix_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int2_mix2_inp, LPASS_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6, + rx_sidetone_mix_text); + +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir0_inp0, LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0, 0, + iir_inp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir0_inp1, LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1, 0, + iir_inp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir0_inp2, LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2, 0, + iir_inp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir0_inp3, LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3, 0, + iir_inp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir1_inp0, LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0, 0, + iir_inp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir1_inp1, LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1, 0, + iir_inp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir1_inp2, LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2, 0, + iir_inp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(iir1_inp3, LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3, 0, + iir_inp_mux_text); + +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int0_1_interp, SND_SOC_NOPM, 0, + rx_int0_1_interp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int1_1_interp, SND_SOC_NOPM, 0, + rx_int1_1_interp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int2_1_interp, SND_SOC_NOPM, 0, + rx_int2_1_interp_mux_text); + +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int0_2_interp, SND_SOC_NOPM, 0, + rx_int0_2_interp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int1_2_interp, SND_SOC_NOPM, 0, + rx_int1_2_interp_mux_text); +LPASS_CDC_RX_MACRO_DAPM_ENUM(rx_int2_2_interp, SND_SOC_NOPM, 0, + rx_int2_2_interp_mux_text); + +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(rx_int0_dem_inp, LPASS_CDC_RX_RX0_RX_PATH_CFG1, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_rx_macro_int_dem_inp_mux_put); +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(rx_int1_dem_inp, LPASS_CDC_RX_RX1_RX_PATH_CFG1, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_rx_macro_int_dem_inp_mux_put); + +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(lpass_cdc_rx_macro_rx0, SND_SOC_NOPM, 0, lpass_cdc_rx_macro_mux_text, + lpass_cdc_rx_macro_mux_get, lpass_cdc_rx_macro_mux_put); +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(lpass_cdc_rx_macro_rx1, SND_SOC_NOPM, 0, lpass_cdc_rx_macro_mux_text, + lpass_cdc_rx_macro_mux_get, lpass_cdc_rx_macro_mux_put); +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(lpass_cdc_rx_macro_rx2, SND_SOC_NOPM, 0, lpass_cdc_rx_macro_mux_text, + lpass_cdc_rx_macro_mux_get, lpass_cdc_rx_macro_mux_put); +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(lpass_cdc_rx_macro_rx3, SND_SOC_NOPM, 0, lpass_cdc_rx_macro_mux_text, + lpass_cdc_rx_macro_mux_get, lpass_cdc_rx_macro_mux_put); +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(lpass_cdc_rx_macro_rx4, SND_SOC_NOPM, 0, lpass_cdc_rx_macro_mux_text, + lpass_cdc_rx_macro_mux_get, lpass_cdc_rx_macro_mux_put); +LPASS_CDC_RX_MACRO_DAPM_ENUM_EXT(lpass_cdc_rx_macro_rx5, SND_SOC_NOPM, 0, lpass_cdc_rx_macro_mux_text, + lpass_cdc_rx_macro_mux_get, lpass_cdc_rx_macro_mux_put); + +static const char * const rx_echo_mux_text[] = { + "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2" +}; + +static const struct soc_enum rx_mix_tx2_mux_enum = + SOC_ENUM_SINGLE(LPASS_CDC_RX_INP_MUX_RX_MIX_CFG5, 0, 4, + rx_echo_mux_text); + +static const struct snd_kcontrol_new rx_mix_tx2_mux = + SOC_DAPM_ENUM("RX MIX TX2_MUX Mux", rx_mix_tx2_mux_enum); + +static const struct soc_enum rx_mix_tx1_mux_enum = + SOC_ENUM_SINGLE(LPASS_CDC_RX_INP_MUX_RX_MIX_CFG4, 0, 4, + rx_echo_mux_text); + +static const struct snd_kcontrol_new rx_mix_tx1_mux = + SOC_DAPM_ENUM("RX MIX TX1_MUX Mux", rx_mix_tx1_mux_enum); + +static const struct soc_enum rx_mix_tx0_mux_enum = + SOC_ENUM_SINGLE(LPASS_CDC_RX_INP_MUX_RX_MIX_CFG4, 4, 4, + rx_echo_mux_text); + +static const struct snd_kcontrol_new rx_mix_tx0_mux = + SOC_DAPM_ENUM("RX MIX TX0_MUX Mux", rx_mix_tx0_mux_enum); + +static struct snd_soc_dai_ops lpass_cdc_rx_macro_dai_ops = { + .hw_params = lpass_cdc_rx_macro_hw_params, + .get_channel_map = lpass_cdc_rx_macro_get_channel_map, +}; + +static struct snd_soc_dai_driver lpass_cdc_rx_macro_dai[] = { + { + .name = "rx_macro_rx1", + .id = RX_MACRO_AIF1_PB, + .playback = { + .stream_name = "RX_MACRO_AIF1 Playback", + .rates = LPASS_CDC_RX_MACRO_RATES | LPASS_CDC_RX_MACRO_FRAC_RATES, + .formats = LPASS_CDC_RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx2", + .id = RX_MACRO_AIF2_PB, + .playback = { + .stream_name = "RX_MACRO_AIF2 Playback", + .rates = LPASS_CDC_RX_MACRO_RATES | LPASS_CDC_RX_MACRO_FRAC_RATES, + .formats = LPASS_CDC_RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx3", + .id = RX_MACRO_AIF3_PB, + .playback = { + .stream_name = "RX_MACRO_AIF3 Playback", + .rates = LPASS_CDC_RX_MACRO_RATES | LPASS_CDC_RX_MACRO_FRAC_RATES, + .formats = LPASS_CDC_RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx4", + .id = RX_MACRO_AIF4_PB, + .playback = { + .stream_name = "RX_MACRO_AIF4 Playback", + .rates = LPASS_CDC_RX_MACRO_RATES | LPASS_CDC_RX_MACRO_FRAC_RATES, + .formats = LPASS_CDC_RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_rx_macro_dai_ops, + }, + { + .name = "rx_macro_echo", + .id = RX_MACRO_AIF_ECHO, + .capture = { + .stream_name = "RX_AIF_ECHO Capture", + .rates = LPASS_CDC_RX_MACRO_ECHO_RATES, + .formats = LPASS_CDC_RX_MACRO_ECHO_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 3, + }, + .ops = &lpass_cdc_rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx5", + .id = RX_MACRO_AIF5_PB, + .playback = { + .stream_name = "RX_MACRO_AIF5 Playback", + .rates = LPASS_CDC_RX_MACRO_RATES | LPASS_CDC_RX_MACRO_FRAC_RATES, + .formats = LPASS_CDC_RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &lpass_cdc_rx_macro_dai_ops, + }, + { + .name = "rx_macro_rx6", + .id = RX_MACRO_AIF6_PB, + .playback = { + .stream_name = "RX_MACRO_AIF6 Playback", + .rates = LPASS_CDC_RX_MACRO_RATES | LPASS_CDC_RX_MACRO_FRAC_RATES, + .formats = LPASS_CDC_RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &lpass_cdc_rx_macro_dai_ops, + }, +}; + +static int get_impedance_index(int imped) +{ + int i = 0; + + if (imped < imped_index[i].imped_val) { + pr_debug("%s, detected impedance is less than %d Ohm\n", + __func__, imped_index[i].imped_val); + i = 0; + goto ret; + } + if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) { + pr_debug("%s, detected impedance is greater than %d Ohm\n", + __func__, + imped_index[ARRAY_SIZE(imped_index) - 1].imped_val); + i = ARRAY_SIZE(imped_index) - 1; + goto ret; + } + for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) { + if (imped >= imped_index[i].imped_val && + imped < imped_index[i + 1].imped_val) + break; + } +ret: + pr_debug("%s: selected impedance index = %d\n", + __func__, imped_index[i].index); + return imped_index[i].index; +} + +/* + * lpass_cdc_rx_macro_wcd_clsh_imped_config - + * This function updates HPHL and HPHR gain settings + * according to the impedance value. + * + * @component: codec pointer handle + * @imped: impedance value of HPHL/R + * @reset: bool variable to reset registers when teardown + */ +static void lpass_cdc_rx_macro_wcd_clsh_imped_config(struct snd_soc_component *component, + int imped, bool reset) +{ + int i; + int index = 0; + int table_size; + + static const struct lpass_cdc_rx_macro_reg_mask_val + (*imped_table_ptr)[MAX_IMPED_PARAMS]; + + table_size = ARRAY_SIZE(imped_table); + imped_table_ptr = imped_table; + /* reset = 1, which means request is to reset the register values */ + if (reset) { + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, 0); + return; + } + index = get_impedance_index(imped); + if (index >= (ARRAY_SIZE(imped_index) - 1)) { + pr_debug("%s, impedance not in range = %d\n", __func__, imped); + return; + } + if (index >= table_size) { + pr_debug("%s, impedance index not in range = %d\n", __func__, + index); + return; + } + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, + imped_table_ptr[index][i].val); +} + +static bool lpass_cdc_rx_macro_get_data(struct snd_soc_component *component, + struct device **rx_dev, + struct lpass_cdc_rx_macro_priv **rx_priv, + const char *func_name) +{ + *rx_dev = lpass_cdc_get_device_ptr(component->dev, RX_MACRO); + + if (!(*rx_dev)) { + dev_err_ratelimited(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + + *rx_priv = dev_get_drvdata((*rx_dev)); + if (!(*rx_priv)) { + dev_err_ratelimited(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + + if (!(*rx_priv)->component) { + dev_err_ratelimited(component->dev, + "%s: rx_priv component is not initialized!\n", func_name); + return false; + } + + return true; +} + +static int lpass_cdc_rx_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (rx_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +static int lpass_cdc_rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val = 0; + unsigned short look_ahead_dly_reg = + LPASS_CDC_RX_RX0_RX_PATH_CFG0; + + val = ucontrol->value.enumerated.item[0]; + if (val >= e->items) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + if (e->reg == LPASS_CDC_RX_RX0_RX_PATH_CFG1) + look_ahead_dly_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG0; + else if (e->reg == LPASS_CDC_RX_RX1_RX_PATH_CFG1) + look_ahead_dly_reg = LPASS_CDC_RX_RX1_RX_PATH_CFG0; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, look_ahead_dly_reg, + 0x08, (val ? 0x08 : 0x00)); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int lpass_cdc_rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp = 0; + u32 j = 0, port = 0; + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u16 int_fs_reg = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 inp0_sel = 0, inp1_sel = 0, inp2_sel = 0; + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + for_each_set_bit(port, &rx_priv->active_ch_mask[dai->id], + LPASS_CDC_RX_MACRO_PORTS_MAX) { + int_1_mix1_inp = port; + if ((int_1_mix1_inp < LPASS_CDC_RX_MACRO_RX0) || + (int_1_mix1_inp > LPASS_CDC_RX_MACRO_PORTS_MAX)) { + pr_err_ratelimited("%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg0 = LPASS_CDC_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the rx port + * is connected + */ + for (j = 0; j < INTERP_MAX; j++) { + int_mux_cfg1 = int_mux_cfg0 + 4; + + int_mux_cfg0_val = snd_soc_component_read( + component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read( + component, int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & 0x0F; + inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F; + inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F; + if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { + int_fs_reg = LPASS_CDC_RX_RX0_RX_PATH_CTL + + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET * j; + pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + pr_debug("%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + /* sample_rate is in Hz */ + snd_soc_component_update_bits(component, + int_fs_reg, + 0x0F, rate_reg_val); + } + int_mux_cfg0 += 8; + } + } + + return 0; +} + +static int lpass_cdc_rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp = 0; + u32 j = 0, port = 0; + u16 int_mux_cfg1 = 0, int_fs_reg = 0; + u8 int_mux_cfg1_val = 0; + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + for_each_set_bit(port, &rx_priv->active_ch_mask[dai->id], + LPASS_CDC_RX_MACRO_PORTS_MAX) { + int_2_inp = port; + if ((int_2_inp < LPASS_CDC_RX_MACRO_RX0) || + (int_2_inp > LPASS_CDC_RX_MACRO_PORTS_MAX)) { + pr_err_ratelimited("%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg1 = LPASS_CDC_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < INTERP_MAX; j++) { + int_mux_cfg1_val = snd_soc_component_read( + component, int_mux_cfg1) & + 0x0F; + if (int_mux_cfg1_val == int_2_inp + + INTn_2_INP_SEL_RX0) { + int_fs_reg = LPASS_CDC_RX_RX0_RX_PATH_MIX_CTL + + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET * j; + pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + pr_debug("%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits( + component, int_fs_reg, + 0x0F, rate_reg_val); + } + int_mux_cfg1 += 8; + } + } + return 0; +} + +static bool lpass_cdc_rx_macro_is_fractional_sample_rate(u32 sample_rate) +{ + switch (sample_rate) { + case SAMPLING_RATE_44P1KHZ: + case SAMPLING_RATE_88P2KHZ: + case SAMPLING_RATE_176P4KHZ: + case SAMPLING_RATE_352P8KHZ: + return true; + default: + return false; + } + return false; +} + +static int lpass_cdc_rx_macro_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_component *component = dai->component; + int rate_val = 0; + int i = 0, ret = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + + for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) { + if (sample_rate == sr_val_tbl[i].sample_rate) { + rate_val = sr_val_tbl[i].rate_val; + if (lpass_cdc_rx_macro_is_fractional_sample_rate(sample_rate)) + rx_priv->is_native_on = true; + else + rx_priv->is_native_on = false; + break; + } + } + if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) { + dev_err(component->dev, "%s: Unsupported sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + } + + ret = lpass_cdc_rx_macro_set_prim_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + ret = lpass_cdc_rx_macro_set_mix_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + + return ret; +} + +static int lpass_cdc_rx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = lpass_cdc_rx_macro_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + pr_err_ratelimited("%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + rx_priv->bit_width[dai->id] = params_width(params); + break; + case SNDRV_PCM_STREAM_CAPTURE: + default: + break; + } + return 0; +} + +static int lpass_cdc_rx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + unsigned int temp = 0, ch_mask = 0; + u16 val = 0, mask = 0, cnt = 0, i = 0; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case RX_MACRO_AIF1_PB: + case RX_MACRO_AIF2_PB: + case RX_MACRO_AIF3_PB: + case RX_MACRO_AIF4_PB: + for_each_set_bit(temp, &rx_priv->active_ch_mask[dai->id], + LPASS_CDC_RX_MACRO_PORTS_MAX) { + ch_mask |= (1 << temp); + if (++i == LPASS_CDC_RX_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + /* + * CDC_DMA_RX_0 port drives RX0/RX1 -- ch_mask 0x1/0x2/0x3 + * CDC_DMA_RX_1 port drives RX2/RX3 -- ch_mask 0x1/0x2/0x3 + * CDC_DMA_RX_2 port drives RX4 -- ch_mask 0x1 + * CDC_DMA_RX_3 port drives RX5 -- ch_mask 0x1 + * AIFn can pair to any CDC_DMA_RX_n port. + * In general, below convention is used:: + * CDC_DMA_RX_0(AIF1)/CDC_DMA_RX_1(AIF2)/ + * CDC_DMA_RX_2(AIF3)/CDC_DMA_RX_3(AIF4) + * Above is reflected in machine driver BE dailink + */ + if (ch_mask & 0x0C) + ch_mask = ch_mask >> 2; + if ((ch_mask & 0x10) || (ch_mask & 0x20)) + ch_mask = 0x1; + *rx_slot = ch_mask; + *rx_num = rx_priv->active_ch_cnt[dai->id]; + dev_dbg(rx_priv->dev, + "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d active_mask: 0x%x\n", + __func__, dai->id, *rx_slot, *rx_num, rx_priv->active_ch_mask[dai->id]); + break; + case RX_MACRO_AIF5_PB: + *rx_slot = 0x1; + *rx_num = 0x01; + dev_dbg(rx_priv->dev, + "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d\n", + __func__, dai->id, *rx_slot, *rx_num); + break; + case RX_MACRO_AIF6_PB: + *rx_slot = 0x1; + *rx_num = 0x01; + dev_dbg(rx_priv->dev, + "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d\n", + __func__, dai->id, *rx_slot, *rx_num); + break; + case RX_MACRO_AIF_ECHO: + val = snd_soc_component_read(component, + LPASS_CDC_RX_INP_MUX_RX_MIX_CFG4); + if (val & LPASS_CDC_RX_MACRO_EC_MIX_TX0_MASK) { + mask |= 0x1; + cnt++; + } + if (val & LPASS_CDC_RX_MACRO_EC_MIX_TX1_MASK) { + mask |= 0x2; + cnt++; + } + val = snd_soc_component_read(component, + LPASS_CDC_RX_INP_MUX_RX_MIX_CFG5); + if (val & LPASS_CDC_RX_MACRO_EC_MIX_TX2_MASK) { + mask |= 0x4; + cnt++; + } + *tx_slot = mask; + *tx_num = cnt; + break; + default: + dev_err_ratelimited(rx_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static int lpass_cdc_rx_macro_mclk_enable( + struct lpass_cdc_rx_macro_priv *rx_priv, + bool mclk_enable, bool dapm) +{ + struct regmap *regmap = dev_get_regmap(rx_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(rx_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(rx_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n", + __func__, mclk_enable, dapm, rx_priv->rx_mclk_users); + + mutex_lock(&rx_priv->mclk_lock); + if (mclk_enable) { + if (rx_priv->rx_mclk_users == 0) { + if (rx_priv->is_native_on) + rx_priv->clk_id = RX_CORE_CLK; + ret = lpass_cdc_rx_macro_core_vote(rx_priv, true); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, + "%s: rx request core vote failed\n", + __func__); + goto exit; + } + ret = lpass_cdc_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + rx_priv->clk_id, + true); + lpass_cdc_rx_macro_core_vote(rx_priv, false); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, + "%s: rx request clock enable failed\n", + __func__); + goto exit; + } + lpass_cdc_clk_rsc_fs_gen_request(rx_priv->dev, + true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + RX_START_OFFSET, + RX_MAX_OFFSET); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + rx_priv->rx_mclk_users++; + } else { + if (rx_priv->rx_mclk_users <= 0) { + dev_err_ratelimited(rx_priv->dev, "%s: clock already disabled\n", + __func__); + rx_priv->rx_mclk_users = 0; + goto exit; + } + rx_priv->rx_mclk_users--; + if (rx_priv->rx_mclk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + lpass_cdc_clk_rsc_fs_gen_request(rx_priv->dev, + false); + ret = lpass_cdc_rx_macro_core_vote(rx_priv, true); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, + "%s: rx request core vote failed\n", + __func__); + } + lpass_cdc_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + rx_priv->clk_id, + false); + if (!ret) + lpass_cdc_rx_macro_core_vote(rx_priv, false); + rx_priv->clk_id = rx_priv->default_clk_id; + } + } +exit: + mutex_unlock(&rx_priv->mclk_lock); + return ret; +} + +static int lpass_cdc_rx_macro_mclk_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); + int ret = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + int mclk_freq = MCLK_FREQ; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(rx_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (rx_priv->is_native_on) + mclk_freq = MCLK_FREQ_NATIVE; + if (rx_priv->swr_ctrl_data) + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_CLK_FREQ, &mclk_freq); + ret = lpass_cdc_rx_macro_mclk_enable(rx_priv, 1, true); + if (ret) + rx_priv->dapm_mclk_enable = false; + else + rx_priv->dapm_mclk_enable = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (rx_priv->dapm_mclk_enable) + ret = lpass_cdc_rx_macro_mclk_enable(rx_priv, 0, true); + break; + default: + dev_err_ratelimited(rx_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int lpass_cdc_rx_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + u16 reg = 0, reg_mix = 0, rx_idx = 0, mute = 0x0, val = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + int ret = 0; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (event) { + case LPASS_CDC_MACRO_EVT_RX_MUTE: + rx_idx = data >> 0x10; + mute = data & 0xffff; + val = mute ? 0x10 : 0x00; + reg = LPASS_CDC_RX_RX0_RX_PATH_CTL + (rx_idx * + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + reg_mix = LPASS_CDC_RX_RX0_RX_PATH_MIX_CTL + (rx_idx * + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + snd_soc_component_update_bits(component, reg, + 0x10, val); + snd_soc_component_update_bits(component, reg_mix, + 0x10, val); + break; + case LPASS_CDC_MACRO_EVT_RX_COMPANDER_SOFT_RST: + rx_idx = data >> 0x10; + if (rx_idx == INTERP_AUX) + goto done; + reg = LPASS_CDC_RX_COMPANDER0_CTL0 + + (rx_idx * LPASS_CDC_RX_MACRO_COMP_OFFSET); + snd_soc_component_write(component, reg, + snd_soc_component_read(component, reg)); + break; + case LPASS_CDC_MACRO_EVT_IMPED_TRUE: + lpass_cdc_rx_macro_wcd_clsh_imped_config(component, data, true); + break; + case LPASS_CDC_MACRO_EVT_IMPED_FALSE: + lpass_cdc_rx_macro_wcd_clsh_imped_config(component, data, false); + break; + case LPASS_CDC_MACRO_EVT_SSR_DOWN: + rx_priv->pre_dev_up = false; + rx_priv->dev_up = false; + if (rx_priv->swr_ctrl_data) { + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(rx_dev) || + !pm_runtime_suspended(rx_dev))) { + ret = lpass_cdc_runtime_suspend(rx_dev); + if (!ret) { + pm_runtime_disable(rx_dev); + pm_runtime_set_suspended(rx_dev); + pm_runtime_enable(rx_dev); + } + } + break; + case LPASS_CDC_MACRO_EVT_PRE_SSR_UP: + rx_priv->pre_dev_up = true; + ret = lpass_cdc_rx_macro_core_vote(rx_priv, true); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, + "%s: rx request core vote failed\n", + __func__); + break; + } + /* enable&disable RX_CORE_CLK to reset GFMUX reg */ + ret = lpass_cdc_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + RX_CORE_CLK, true); + if (ret < 0) + dev_err_ratelimited(rx_priv->dev, + "%s, failed to enable clk, ret:%d\n", + __func__, ret); + else + lpass_cdc_clk_rsc_request_clock(rx_priv->dev, + rx_priv->default_clk_id, + RX_CORE_CLK, false); + lpass_cdc_rx_macro_core_vote(rx_priv, false); + break; + case LPASS_CDC_MACRO_EVT_SSR_UP: + rx_priv->dev_up = true; + /* reset swr after ssr/pdr */ + rx_priv->reset_swr = true; + + if (rx_priv->swr_ctrl_data) + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case LPASS_CDC_MACRO_EVT_CLK_RESET: + lpass_cdc_rsc_clk_reset(rx_dev, RX_CORE_CLK); + lpass_cdc_rsc_clk_reset(rx_dev, RX_TX_CORE_CLK); + break; + case LPASS_CDC_MACRO_EVT_RX_PA_GAIN_UPDATE: + rx_priv->rx0_gain_val = snd_soc_component_read(component, + LPASS_CDC_RX_RX0_RX_VOL_CTL); + rx_priv->rx1_gain_val = snd_soc_component_read(component, + LPASS_CDC_RX_RX1_RX_VOL_CTL); + if (data) { + /* Reduce gain by half only if its greater than -6DB */ + if ((rx_priv->rx0_gain_val >= LPASS_CDC_RX_MACRO_GAIN_VAL_UNITY) + && (rx_priv->rx0_gain_val <= LPASS_CDC_RX_MACRO_GAIN_MAX_VAL)) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xFF, + (rx_priv->rx0_gain_val - + LPASS_CDC_RX_MACRO_MOD_GAIN)); + if ((rx_priv->rx1_gain_val >= LPASS_CDC_RX_MACRO_GAIN_VAL_UNITY) + && (rx_priv->rx1_gain_val <= LPASS_CDC_RX_MACRO_GAIN_MAX_VAL)) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xFF, + (rx_priv->rx1_gain_val - + LPASS_CDC_RX_MACRO_MOD_GAIN)); + } + else { + /* Reset gain value to default */ + if ((rx_priv->rx0_gain_val >= + (LPASS_CDC_RX_MACRO_GAIN_VAL_UNITY - LPASS_CDC_RX_MACRO_MOD_GAIN)) && + (rx_priv->rx0_gain_val <= (LPASS_CDC_RX_MACRO_GAIN_MAX_VAL - + LPASS_CDC_RX_MACRO_MOD_GAIN))) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX0_RX_VOL_CTL, 0xFF, + (rx_priv->rx0_gain_val + + LPASS_CDC_RX_MACRO_MOD_GAIN)); + if ((rx_priv->rx1_gain_val >= + (LPASS_CDC_RX_MACRO_GAIN_VAL_UNITY - LPASS_CDC_RX_MACRO_MOD_GAIN)) && + (rx_priv->rx1_gain_val <= (LPASS_CDC_RX_MACRO_GAIN_MAX_VAL - + LPASS_CDC_RX_MACRO_MOD_GAIN))) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX1_RX_VOL_CTL, 0xFF, + (rx_priv->rx1_gain_val + + LPASS_CDC_RX_MACRO_MOD_GAIN)); + } + break; + case LPASS_CDC_MACRO_EVT_HPHL_HD2_ENABLE: + /* Enable hd2 config for hphl*/ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX0_RX_PATH_CFG0, 0x04, data); + break; + case LPASS_CDC_MACRO_EVT_HPHR_HD2_ENABLE: + /* Enable hd2 config for hphr*/ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX1_RX_PATH_CFG0, 0x04, data); + break; + } +done: + return ret; +} + +static int lpass_cdc_rx_macro_find_playback_dai_id_for_port(int port_id, + struct lpass_cdc_rx_macro_priv *rx_priv) +{ + int i = 0; + + for (i = RX_MACRO_AIF1_PB; i < LPASS_CDC_RX_MACRO_MAX_DAIS; i++) { + if (test_bit(port_id, &rx_priv->active_ch_mask[i])) + return i; + } + + return -EINVAL; +} + +static int lpass_cdc_rx_macro_set_idle_detect_thr(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int interp, int path_type) +{ + int port_id[4] = { 0, 0, 0, 0 }; + int *port_ptr = NULL; + int num_ports = 0; + int bit_width = 0, i = 0; + int mux_reg = 0, mux_reg_val = 0; + int dai_id = 0, idle_thr = 0; + + if ((interp != INTERP_HPHL) && (interp != INTERP_HPHR)) + return 0; + + if (!rx_priv->idle_det_cfg.hph_idle_detect_en) + return 0; + + port_ptr = &port_id[0]; + num_ports = 0; + + /* + * Read interpolator MUX input registers and find + * which cdc_dma port is connected and store the port + * numbers in port_id array. + */ + if (path_type == INTERP_MIX_PATH) { + mux_reg = LPASS_CDC_RX_INP_MUX_RX_INT0_CFG1 + + 2 * interp; + mux_reg_val = snd_soc_component_read(component, mux_reg) & + 0x0f; + + if ((mux_reg_val >= INTn_2_INP_SEL_RX0) && + (mux_reg_val <= INTn_2_INP_SEL_RX5)) { + *port_ptr++ = mux_reg_val - 1; + num_ports++; + } + } + + if (path_type == INTERP_MAIN_PATH) { + mux_reg = LPASS_CDC_RX_INP_MUX_RX_INT1_CFG0 + + 2 * (interp - 1); + mux_reg_val = snd_soc_component_read(component, mux_reg) & + 0x0f; + i = LPASS_CDC_RX_MACRO_INTERP_MUX_NUM_INPUTS; + + while (i) { + if ((mux_reg_val >= INTn_1_INP_SEL_RX0) && + (mux_reg_val <= INTn_1_INP_SEL_RX5)) { + *port_ptr++ = mux_reg_val - + INTn_1_INP_SEL_RX0; + num_ports++; + } + mux_reg_val = + (snd_soc_component_read(component, mux_reg) & + 0xf0) >> 4; + mux_reg += 1; + i--; + } + } + + dev_dbg(component->dev, "%s: num_ports: %d, ports[%d %d %d %d]\n", + __func__, num_ports, port_id[0], port_id[1], + port_id[2], port_id[3]); + + i = 0; + while (num_ports) { + dai_id = lpass_cdc_rx_macro_find_playback_dai_id_for_port(port_id[i++], + rx_priv); + + if ((dai_id >= 0) && (dai_id < LPASS_CDC_RX_MACRO_MAX_DAIS)) { + dev_dbg(component->dev, "%s: dai_id: %d bit_width: %d\n", + __func__, dai_id, + rx_priv->bit_width[dai_id]); + + if (rx_priv->bit_width[dai_id] > bit_width) + bit_width = rx_priv->bit_width[dai_id]; + } + num_ports--; + } + + switch (bit_width) { + case 16: + idle_thr = 0xff; /* F16 */ + break; + case 24: + case 32: + idle_thr = 0x03; /* F22 */ + break; + default: + idle_thr = 0x00; + break; + } + + dev_dbg(component->dev, "%s: (new) idle_thr: %d, (cur) idle_thr: %d\n", + __func__, idle_thr, rx_priv->idle_det_cfg.hph_idle_thr); + + if ((rx_priv->idle_det_cfg.hph_idle_thr == 0) || + (idle_thr < rx_priv->idle_det_cfg.hph_idle_thr)) { + snd_soc_component_write(component, + LPASS_CDC_RX_IDLE_DETECT_CFG3, idle_thr); + rx_priv->idle_det_cfg.hph_idle_thr = idle_thr; + } + + return 0; +} + +static int lpass_cdc_rx_macro_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg = 0, mix_reg = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + if (w->shift >= INTERP_MAX) { + dev_err_ratelimited(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + } + + gain_reg = LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL + + (w->shift * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + mix_reg = LPASS_CDC_RX_RX0_RX_PATH_MIX_CTL + + (w->shift * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + lpass_cdc_rx_macro_set_idle_detect_thr(component, rx_priv, w->shift, + INTERP_MIX_PATH); + lpass_cdc_rx_macro_enable_interp_clk(component, event, w->shift); + /* Clk Enable */ + snd_soc_component_update_bits(component, mix_reg, 0x20, 0x20); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write(component, gain_reg, + snd_soc_component_read(component, gain_reg)); + break; + case SND_SOC_DAPM_POST_PMD: + /* Clk Disable */ + snd_soc_component_update_bits(component, mix_reg, 0x20, 0x00); + lpass_cdc_rx_macro_enable_interp_clk(component, event, w->shift); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x40); + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x00); + break; + } + + return 0; +} + +static bool lpass_cdc_rx_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0; + + int_mux_cfg0 = LPASS_CDC_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || + int_n_inp0 == INTn_1_INP_SEL_DEC1 || + int_n_inp0 == INTn_1_INP_SEL_IIR0 || + int_n_inp0 == INTn_1_INP_SEL_IIR1) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || + int_n_inp1 == INTn_1_INP_SEL_DEC1 || + int_n_inp1 == INTn_1_INP_SEL_IIR0 || + int_n_inp1 == INTn_1_INP_SEL_IIR1) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || + int_n_inp2 == INTn_1_INP_SEL_DEC1 || + int_n_inp2 == INTn_1_INP_SEL_IIR0 || + int_n_inp2 == INTn_1_INP_SEL_IIR1) + return true; + + return false; +} + +static int lpass_cdc_rx_macro_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg = 0; + u16 reg = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (w->shift >= INTERP_MAX) { + dev_err_ratelimited(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + } + + reg = LPASS_CDC_RX_RX0_RX_PATH_CTL + (w->shift * + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + gain_reg = LPASS_CDC_RX_RX0_RX_VOL_CTL + (w->shift * + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + lpass_cdc_rx_macro_set_idle_detect_thr(component, rx_priv, w->shift, + INTERP_MAIN_PATH); + lpass_cdc_rx_macro_enable_interp_clk(component, event, w->shift); + if (lpass_cdc_rx_macro_adie_lb(component, w->shift)) + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write(component, gain_reg, + snd_soc_component_read(component, gain_reg)); + break; + case SND_SOC_DAPM_POST_PMD: + lpass_cdc_rx_macro_enable_interp_clk(component, event, w->shift); + break; + } + + return 0; +} + +static void lpass_cdc_rx_macro_droop_setting(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int interp_n, int event) +{ + u8 pcm_rate = 0, val = 0; + u16 rx0_path_ctl_reg = 0, rx_path_cfg3_reg = 0; + + if (rx_priv->is_pcm_enabled) + return; + + rx_path_cfg3_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG3 + + (interp_n * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + rx0_path_ctl_reg = LPASS_CDC_RX_RX0_RX_PATH_CTL + + (interp_n * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + pcm_rate = (snd_soc_component_read(component, rx0_path_ctl_reg) + & 0x0F); + if (pcm_rate < 0x06) + val = 0x03; + else if (pcm_rate < 0x08) + val = 0x01; + else if (pcm_rate < 0x0B) + val = 0x02; + else + val = 0x00; + + if (SND_SOC_DAPM_EVENT_ON(event)) + snd_soc_component_update_bits(component, rx_path_cfg3_reg, + 0x03, val); + if (SND_SOC_DAPM_EVENT_OFF(event)) + snd_soc_component_update_bits(component, rx_path_cfg3_reg, + 0x03, 0x03); +} + +static int lpass_cdc_rx_macro_config_compander(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int interp_n, int event) +{ + int comp = 0; + u16 comp_ctl0_reg = 0, rx_path_cfg0_reg = 0; + u16 comp_coeff_lsb_reg = 0, comp_coeff_msb_reg = 0; + u16 mode = rx_priv->hph_pwr_mode; +#ifdef CONFIG_BOLERO_VER_2P6 + u16 comp_ctl8_reg = 0; +#endif + + /* AUX does not have compander */ + if (interp_n == INTERP_AUX) + return 0; + + comp = interp_n; + if (!rx_priv->comp_enabled[comp]) + return 0; + if (rx_priv->is_pcm_enabled) + return 0; + + if (rx_priv->is_ear_mode_on && interp_n == INTERP_HPHL) + mode = RX_MODE_EAR; + + if (interp_n == INTERP_HPHL) { + comp_coeff_lsb_reg = LPASS_CDC_RX_TOP_HPHL_COMP_WR_LSB; + comp_coeff_msb_reg = LPASS_CDC_RX_TOP_HPHL_COMP_WR_MSB; + } else if (interp_n == INTERP_HPHR) { + comp_coeff_lsb_reg = LPASS_CDC_RX_TOP_HPHR_COMP_WR_LSB; + comp_coeff_msb_reg = LPASS_CDC_RX_TOP_HPHR_COMP_WR_MSB; + } else { + /* compander coefficients are loaded only for hph path */ + return 0; + } + comp_ctl0_reg = LPASS_CDC_RX_COMPANDER0_CTL0 + + (comp * LPASS_CDC_RX_MACRO_COMP_OFFSET); +#ifdef CONFIG_BOLERO_VER_2P6 + comp_ctl8_reg = LPASS_CDC_RX_COMPANDER0_CTL8 + + (comp * LPASS_CDC_RX_MACRO_COMP_OFFSET); +#endif + rx_path_cfg0_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG0 + + (comp * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + if (SND_SOC_DAPM_EVENT_ON(event)) { + lpass_cdc_load_compander_coeff(component, + comp_coeff_lsb_reg, comp_coeff_msb_reg, + comp_coeff_table[rx_priv->hph_pwr_mode], + COMP_MAX_COEFF); +#ifdef CONFIG_BOLERO_VER_2P6 + lpass_cdc_update_compander_setting(component, + comp_ctl8_reg, + &comp_setting_table[mode]); +#endif + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x04); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x00); + } + + return 0; +} + +static void lpass_cdc_rx_macro_enable_softclip_clk(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + bool enable) +{ + if (enable) { + if (rx_priv->softclip_clk_users == 0) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_SOFTCLIP_CRC, + 0x01, 0x01); + rx_priv->softclip_clk_users++; + } else { + rx_priv->softclip_clk_users--; + if (rx_priv->softclip_clk_users == 0) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_SOFTCLIP_CRC, + 0x01, 0x00); + } +} + +static int lpass_cdc_rx_macro_config_softclip(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int event) +{ + dev_dbg(component->dev, "%s: event %d, enabled %d\n", + __func__, event, rx_priv->is_softclip_on); + + if (!rx_priv->is_softclip_on) + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Softclip clock */ + lpass_cdc_rx_macro_enable_softclip_clk(component, rx_priv, true); + /* Enable Softclip control */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x01, 0x01); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + LPASS_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL, 0x01, 0x00); + lpass_cdc_rx_macro_enable_softclip_clk(component, rx_priv, false); + } + + return 0; +} + +static int lpass_cdc_rx_macro_config_aux_hpf(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int event) +{ + dev_dbg(component->dev, "%s: event %d, enabled %d\n", + __func__, event, rx_priv->is_aux_hpf_on); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Update Aux HPF control */ + if (!rx_priv->is_aux_hpf_on) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x00); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + /* Reset to default (HPF=ON) */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x04); + } + + return 0; +} + + +static inline void +lpass_cdc_rx_macro_enable_clsh_block(struct lpass_cdc_rx_macro_priv *rx_priv, bool enable) +{ + if ((enable && ++rx_priv->clsh_users == 1) || + (!enable && --rx_priv->clsh_users == 0)) + snd_soc_component_update_bits(rx_priv->component, + LPASS_CDC_RX_CLSH_CRC, 0x01, + (u8) enable); + if (rx_priv->clsh_users < 0) + rx_priv->clsh_users = 0; + dev_dbg(rx_priv->dev, "%s: clsh_users %d, enable %d", __func__, + rx_priv->clsh_users, enable); +} + +static int lpass_cdc_rx_macro_config_classh(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int interp_n, int event) +{ + if (interp_n == INTERP_AUX) + return 0; /* AUX does not have Class-H */ + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + lpass_cdc_rx_macro_enable_clsh_block(rx_priv, false); + return 0; + } + + if (!SND_SOC_DAPM_EVENT_ON(event)) + return 0; + + lpass_cdc_rx_macro_enable_clsh_block(rx_priv, true); + if (interp_n == INTERP_HPHL || + interp_n == INTERP_HPHR) { + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_K1_LSB, + 0xFF, 0xC0); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_K1_MSB, + 0x0F, 0x00); + } + switch (interp_n) { + case INTERP_HPHL: + if (rx_priv->is_ear_mode_on) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x39); + else + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x1C); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_DECAY_CTRL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX0_RX_PATH_CFG0, + 0x40, 0x40); + break; + case INTERP_HPHR: + if (rx_priv->is_ear_mode_on) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x39); + else + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x1C); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CLSH_DECAY_CTRL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX1_RX_PATH_CFG0, + 0x40, 0x40); + break; + case INTERP_AUX: + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG0, + 0x08, 0x08); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG0, + 0x10, 0x10); + break; + } + + return 0; +} + +static void lpass_cdc_rx_macro_hd2_control(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + u16 interp_idx, int event) +{ + u16 hd2_scale_reg = 0; + u16 hd2_enable_reg = 0; + + if (rx_priv->is_pcm_enabled) + return; + + switch (interp_idx) { + case INTERP_HPHL: + hd2_scale_reg = LPASS_CDC_RX_RX0_RX_PATH_SEC3; + hd2_enable_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG0; + break; + case INTERP_HPHR: + hd2_scale_reg = LPASS_CDC_RX_RX1_RX_PATH_SEC3; + hd2_enable_reg = LPASS_CDC_RX_RX1_RX_PATH_CFG0; + break; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x14); + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x00); + } +} + +static int lpass_cdc_rx_macro_hph_idle_detect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + struct device *rx_dev = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + rx_priv->idle_det_cfg.hph_idle_detect_en; + + return 0; +} + +static int lpass_cdc_rx_macro_hph_idle_detect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + struct device *rx_dev = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->idle_det_cfg.hph_idle_detect_en = + ucontrol->value.integer.value[0]; + + return 0; +} + +#ifdef CONFIG_BOLERO_VER_2P6 +static int lpass_cdc_rx_macro_get_pcm_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->is_pcm_enabled; + return 0; +} + +static int lpass_cdc_rx_macro_put_pcm_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_pcm_enabled = ucontrol->value.integer.value[0]; + return 0; +} +#endif + +static int lpass_cdc_rx_macro_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->comp_enabled[comp]; + return 0; +} + +static int lpass_cdc_rx_macro_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, rx_priv->comp_enabled[comp], value); + rx_priv->comp_enabled[comp] = value; + + return 0; +} + +static int lpass_cdc_rx_macro_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + rx_priv->rx_port_value[widget->shift]; + return 0; +} + +static int lpass_cdc_rx_macro_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 rx_port_value = ucontrol->value.integer.value[0]; + u32 aif_rst = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + aif_rst = rx_priv->rx_port_value[widget->shift]; + if (!rx_port_value) { + if (aif_rst == 0) { + dev_err_ratelimited(rx_dev, "%s:AIF reset already\n", __func__); + return 0; + } + if (aif_rst > RX_MACRO_AIF4_PB) { + dev_err_ratelimited(rx_dev, "%s: Invalid AIF reset\n", __func__); + return 0; + } + } + rx_priv->rx_port_value[widget->shift] = rx_port_value; + + dev_dbg(rx_dev, "%s: mux input: %d, mux output: %d, aif_rst: %d\n", + __func__, rx_port_value, widget->shift, aif_rst); + + switch (rx_port_value) { + case 0: + if (rx_priv->active_ch_cnt[aif_rst]) { + clear_bit(widget->shift, + &rx_priv->active_ch_mask[aif_rst]); + rx_priv->active_ch_cnt[aif_rst]--; + } + break; + case 1: + case 2: + case 3: + case 4: + set_bit(widget->shift, + &rx_priv->active_ch_mask[rx_port_value]); + rx_priv->active_ch_cnt[rx_port_value]++; + break; + default: + dev_err_ratelimited(component->dev, + "%s:Invalid AIF_ID for LPASS_CDC_RX_MACRO MUX %d\n", + __func__, rx_port_value); + goto err; + } + + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + return 0; +err: + return -EINVAL; +} + +static int lpass_cdc_rx_macro_get_ear_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->is_ear_mode_on; + return 0; +} + +static int lpass_cdc_rx_macro_put_ear_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_ear_mode_on = + (!ucontrol->value.integer.value[0] ? false : true); + return 0; +} + +static int lpass_cdc_rx_macro_get_hph_hd2_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->hph_hd2_mode; + return 0; +} + +static int lpass_cdc_rx_macro_put_hph_hd2_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->hph_hd2_mode = ucontrol->value.integer.value[0]; + return 0; +} + +static int lpass_cdc_rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->hph_pwr_mode; + return 0; +} + +static int lpass_cdc_rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->hph_pwr_mode = ucontrol->value.integer.value[0]; + return 0; +} + +static int lpass_cdc_rx_macro_vbat_bcl_gsm_mode_func_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ucontrol->value.integer.value[0] = + ((snd_soc_component_read( + component, LPASS_CDC_RX_BCL_VBAT_CFG) & 0x04) ? + 1 : 0); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_rx_macro_vbat_bcl_gsm_mode_func_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + /* Set Vbat register configuration for GSM mode bit based on value */ + if (ucontrol->value.integer.value[0]) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_CFG, + 0x04, 0x04); + else + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_CFG, + 0x04, 0x00); + + return 0; +} + +static int lpass_cdc_rx_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->is_softclip_on; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_rx_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_softclip_on = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: soft clip enable = %d\n", __func__, + rx_priv->is_softclip_on); + + return 0; +} + +static int lpass_cdc_rx_macro_aux_hpf_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = rx_priv->is_aux_hpf_on; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_rx_macro_aux_hpf_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_aux_hpf_on = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: aux hpf enable = %d\n", __func__, + rx_priv->is_aux_hpf_on); + + return 0; +} + + +static int lpass_cdc_rx_macro_enable_vbat(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 device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable clock for VBAT block */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_PATH_CTL, 0x10, 0x10); + /* Enable VBAT block */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_CFG, 0x01, 0x01); + /* Update interpolator with 384K path */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG1, 0x80, 0x80); + /* Update DSM FS rate */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_SEC7, 0x02, 0x02); + /* Use attenuation mode */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_CFG, 0x02, 0x00); + /* BCL block needs softclip clock to be enabled */ + lpass_cdc_rx_macro_enable_softclip_clk(component, rx_priv, true); + /* Enable VBAT at channel level */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG1, 0x02, 0x02); + /* Set the ATTK1 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + /* Set the ATTK2 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + /* Set the ATTK3 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); +#ifdef CONFIG_BOLERO_VER_2P6 + /* Enable CB decode block clock */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x01); + /* Enable BCL path */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x01); + /* Request for BCL data */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x01); +#endif + break; + + case SND_SOC_DAPM_POST_PMD: +#ifdef CONFIG_BOLERO_VER_2P6 + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x00); +#endif + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG1, + 0x80, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_SEC7, + 0x02, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_CFG, + 0x02, 0x02); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX2_RX_PATH_CFG1, + 0x02, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + lpass_cdc_rx_macro_enable_softclip_clk(component, rx_priv, false); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_CFG, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_PATH_CTL, 0x10, 0x00); + break; + default: + dev_err_ratelimited(rx_dev, "%s: Invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static void lpass_cdc_rx_macro_idle_detect_control(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int interp, int event) +{ + int reg = 0, mask = 0, val = 0; + + if (!rx_priv->idle_det_cfg.hph_idle_detect_en) + return; + + if (!rx_priv->is_pcm_enabled) + return; + + if (interp == INTERP_HPHL) { + reg = LPASS_CDC_RX_IDLE_DETECT_PATH_CTL; + mask = 0x01; + val = 0x01; + } + if (interp == INTERP_HPHR) { + reg = LPASS_CDC_RX_IDLE_DETECT_PATH_CTL; + mask = 0x02; + val = 0x02; + } + + if (reg && SND_SOC_DAPM_EVENT_ON(event)) + snd_soc_component_update_bits(component, reg, mask, val); + + if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, reg, mask, 0x00); + rx_priv->idle_det_cfg.hph_idle_thr = 0; + snd_soc_component_write(component, + LPASS_CDC_RX_IDLE_DETECT_CFG3, 0x0); + } +} + +static void lpass_cdc_rx_macro_hphdelay_lutbypass(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + u16 interp_idx, int event) +{ + u16 hph_lut_bypass_reg = 0; + u16 hph_comp_ctrl7 = 0; + + if (rx_priv->is_pcm_enabled) + return; + + switch (interp_idx) { + case INTERP_HPHL: + hph_lut_bypass_reg = LPASS_CDC_RX_TOP_HPHL_COMP_LUT; + hph_comp_ctrl7 = LPASS_CDC_RX_COMPANDER0_CTL7; + break; + case INTERP_HPHR: + hph_lut_bypass_reg = LPASS_CDC_RX_TOP_HPHR_COMP_LUT; + hph_comp_ctrl7 = LPASS_CDC_RX_COMPANDER1_CTL7; + break; + default: + break; + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) { + if (interp_idx == INTERP_HPHL) { + if (rx_priv->is_ear_mode_on) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX0_RX_PATH_CFG1, + 0x02, 0x02); + else + snd_soc_component_update_bits(component, + hph_lut_bypass_reg, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, + hph_lut_bypass_reg, + 0x80, 0x80); + } + if (rx_priv->hph_pwr_mode) + snd_soc_component_update_bits(component, + hph_comp_ctrl7, + 0x20, 0x00); + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + LPASS_CDC_RX_RX0_RX_PATH_CFG1, + 0x02, 0x00); + snd_soc_component_update_bits(component, hph_lut_bypass_reg, + 0x80, 0x00); + snd_soc_component_update_bits(component, hph_comp_ctrl7, + 0x20, 0x20); + } +} + +static int lpass_cdc_rx_macro_enable_interp_clk(struct snd_soc_component *component, + int event, int interp_idx) +{ + u16 main_reg = 0, dsm_reg = 0, rx_cfg2_reg = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + main_reg = LPASS_CDC_RX_RX0_RX_PATH_CTL + + (interp_idx * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + dsm_reg = LPASS_CDC_RX_RX0_RX_PATH_DSM_CTL + + (interp_idx * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + if (interp_idx == INTERP_AUX) + dsm_reg = LPASS_CDC_RX_RX2_RX_PATH_DSM_CTL; + rx_cfg2_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG2 + + (interp_idx * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (rx_priv->main_clk_users[interp_idx] == 0) { + /* Main path PGA mute enable */ + snd_soc_component_update_bits(component, main_reg, + 0x10, 0x10); + snd_soc_component_update_bits(component, dsm_reg, + 0x01, 0x01); + /* Clk Enable */ + snd_soc_component_update_bits(component, main_reg, + 0x20, 0x20); + snd_soc_component_update_bits(component, rx_cfg2_reg, + 0x03, 0x03); + lpass_cdc_rx_macro_idle_detect_control(component, rx_priv, + interp_idx, event); + if (rx_priv->hph_hd2_mode) + lpass_cdc_rx_macro_hd2_control( + component, rx_priv, interp_idx, event); + lpass_cdc_rx_macro_hphdelay_lutbypass(component, rx_priv, + interp_idx, event); + lpass_cdc_rx_macro_droop_setting(component, + rx_priv, interp_idx, event); + lpass_cdc_rx_macro_config_compander(component, rx_priv, + interp_idx, event); + if (interp_idx == INTERP_AUX) { + lpass_cdc_rx_macro_config_softclip(component, rx_priv, + event); + lpass_cdc_rx_macro_config_aux_hpf(component, rx_priv, + event); + } + lpass_cdc_rx_macro_config_classh(component, rx_priv, + interp_idx, event); + /*select PCM path and swr clk is 9.6MHz*/ + if (rx_priv->is_pcm_enabled && !rx_priv->is_native_on && + interp_idx != INTERP_AUX) { + if (rx_priv->pcm_select_users == 0) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_TOP_SWR_CTRL, 0x02, 0x02); + ++rx_priv->pcm_select_users; + } + lpass_cdc_notify_wcd_rx_clk(rx_dev, rx_priv->is_native_on); + } + rx_priv->main_clk_users[interp_idx]++; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + rx_priv->main_clk_users[interp_idx]--; + if (rx_priv->main_clk_users[interp_idx] <= 0) { + rx_priv->main_clk_users[interp_idx] = 0; + /* Main path PGA mute enable */ + snd_soc_component_update_bits(component, main_reg, + 0x10, 0x10); + /*Unselect PCM path*/ + if (rx_priv->is_pcm_enabled && !rx_priv->is_native_on && + interp_idx != INTERP_AUX) { + if (rx_priv->pcm_select_users == 1) + snd_soc_component_update_bits(component, + LPASS_CDC_RX_TOP_SWR_CTRL, 0x02, 0x00); + --rx_priv->pcm_select_users; + if (rx_priv->pcm_select_users < 0) + rx_priv->pcm_select_users = 0; + } + + /* Clk Disable */ + snd_soc_component_update_bits(component, dsm_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, main_reg, + 0x20, 0x00); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x00); + /* Reset rate to 48K*/ + snd_soc_component_update_bits(component, main_reg, + 0x0F, 0x04); + snd_soc_component_update_bits(component, rx_cfg2_reg, + 0x03, 0x00); + lpass_cdc_rx_macro_config_classh(component, rx_priv, + interp_idx, event); + lpass_cdc_rx_macro_config_compander(component, rx_priv, + interp_idx, event); + if (interp_idx == INTERP_AUX) { + lpass_cdc_rx_macro_config_softclip(component, rx_priv, + event); + lpass_cdc_rx_macro_config_aux_hpf(component, rx_priv, + event); + } + lpass_cdc_rx_macro_hphdelay_lutbypass(component, rx_priv, + interp_idx, event); + if (rx_priv->hph_hd2_mode) + lpass_cdc_rx_macro_hd2_control(component, + rx_priv, interp_idx, event); + lpass_cdc_rx_macro_idle_detect_control(component, rx_priv, + interp_idx, event); + } + } + + dev_dbg(component->dev, "%s event %d main_clk_users %d\n", + __func__, event, rx_priv->main_clk_users[interp_idx]); + + return rx_priv->main_clk_users[interp_idx]; +} + +static int lpass_cdc_rx_macro_enable_rx_path_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 sidetone_reg = 0, fs_reg = 0; + + dev_dbg(component->dev, "%s %d %d\n", __func__, event, w->shift); + sidetone_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG1 + + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET * (w->shift); + fs_reg = LPASS_CDC_RX_RX0_RX_PATH_CTL + + LPASS_CDC_RX_MACRO_RX_PATH_OFFSET * (w->shift); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + lpass_cdc_rx_macro_enable_interp_clk(component, event, w->shift); + snd_soc_component_update_bits(component, sidetone_reg, + 0x10, 0x10); + snd_soc_component_update_bits(component, fs_reg, + 0x20, 0x20); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, sidetone_reg, + 0x10, 0x00); + lpass_cdc_rx_macro_enable_interp_clk(component, event, w->shift); + break; + default: + break; + }; + return 0; +} + +static void lpass_cdc_rx_macro_restore_iir_coeff(struct lpass_cdc_rx_macro_priv *rx_priv, int iir_idx, + int band_idx) +{ + u16 reg_add = 0, coeff_idx = 0, idx = 0; + struct regmap *regmap = dev_get_regmap(rx_priv->dev->parent, NULL); + + if (regmap == NULL) { + dev_err_ratelimited(rx_priv->dev, "%s: regmap is NULL\n", __func__); + return; + } + + regmap_write(regmap, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + reg_add = LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx; + + /* 5 coefficients per band and 4 writes per coefficient */ + for (coeff_idx = 0; coeff_idx < LPASS_CDC_RX_MACRO_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + /* Four 8 bit values(one 32 bit) per coefficient */ + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + regmap_write(regmap, reg_add, + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++]); + } +} + +static int lpass_cdc_rx_macro_iir_enable_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + /* IIR filter band registers are at integer multiples of 0x80 */ + u16 iir_reg = LPASS_CDC_RX_SIDETONE_IIR0_IIR_CTL + 0x80 * iir_idx; + + ucontrol->value.integer.value[0] = ( + snd_soc_component_read(component, iir_reg) & + (1 << band_idx)) != 0; + + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0]); + return 0; +} + +static int lpass_cdc_rx_macro_iir_enable_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + bool iir_band_en_status = 0; + int value = ucontrol->value.integer.value[0]; + u16 iir_reg = LPASS_CDC_RX_SIDETONE_IIR0_IIR_CTL + 0x80 * iir_idx; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + lpass_cdc_rx_macro_restore_iir_coeff(rx_priv, iir_idx, band_idx); + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_component_update_bits(component, iir_reg, (1 << band_idx), + (value << band_idx)); + + iir_band_en_status = ((snd_soc_component_read(component, iir_reg) & + (1 << band_idx)) != 0); + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, iir_band_en_status); + return 0; +} + +static uint32_t get_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + int coeff_idx) +{ + uint32_t value = 0; + + /* Address does not automatically update if reading */ + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_component_read(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx)); + + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_component_read(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 0x80 * iir_idx)) << 8); + + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_component_read(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 0x80 * iir_idx)) << 16); + + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_component_read(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 0x80 * iir_idx)) & 0x3F) << 24); + + return value; +} + +static int lpass_cdc_rx_macro_iir_filter_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *ucontrol) +{ + struct lpass_cdc_rx_macro_iir_filter_ctl *ctl = + (struct lpass_cdc_rx_macro_iir_filter_ctl *)kcontrol->private_value; + struct soc_bytes_ext *params = &ctl->bytes_ext; + + ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; + ucontrol->count = params->max; + + return 0; +} + +static int lpass_cdc_rx_macro_iir_band_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_rx_macro_iir_filter_ctl *ctl = + (struct lpass_cdc_rx_macro_iir_filter_ctl *)kcontrol->private_value; + struct soc_bytes_ext *params = &ctl->bytes_ext; + int iir_idx = ctl->iir_idx; + int band_idx = ctl->band_idx; + u32 coeff[BAND_MAX]; + int coeff_idx = 0; + + for (coeff_idx = 0; coeff_idx < LPASS_CDC_RX_MACRO_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + coeff[coeff_idx] = + get_iir_band_coeff(component, iir_idx, band_idx, coeff_idx); + } + + memcpy(ucontrol->value.bytes.data, &coeff[0], params->max); + + dev_dbg(component->dev, "%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, coeff[0], + __func__, iir_idx, band_idx, coeff[1], + __func__, iir_idx, band_idx, coeff[2], + __func__, iir_idx, band_idx, coeff[3], + __func__, iir_idx, band_idx, coeff[4]); + return 0; +} + +static void set_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + uint32_t value) +{ + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value & 0xFF)); + + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value >> 8) & 0xFF); + + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx), + (value >> 24) & 0x3F); +} + +static int lpass_cdc_rx_macro_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_rx_macro_iir_filter_ctl *ctl = + (struct lpass_cdc_rx_macro_iir_filter_ctl *)kcontrol->private_value; + struct soc_bytes_ext *params = &ctl->bytes_ext; + int iir_idx = ctl->iir_idx; + int band_idx = ctl->band_idx; + u32 coeff[BAND_MAX]; + int coeff_idx, idx = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + memcpy(&coeff[0], ucontrol->value.bytes.data, params->max); + + /* + * Mask top bit it is reserved + * Updates addr automatically for each B2 write + */ + snd_soc_component_write(component, + (LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + /* Store the coefficients in sidetone coeff array */ + for (coeff_idx = 0; coeff_idx < LPASS_CDC_RX_MACRO_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + uint32_t value = coeff[coeff_idx]; + + set_iir_band_coeff(component, iir_idx, band_idx, value); + + /* Four 8 bit values(one 32 bit) per coefficient */ + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value & 0xFF); + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 8) & 0xFF; + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 16) & 0xFF; + rx_priv->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 24) & 0xFF; + } + + pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 0), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 1), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 2), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 3), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 4)); + return 0; +} + +static int lpass_cdc_rx_macro_set_iir_gain(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: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: /* fall through */ + case SND_SOC_DAPM_PRE_PMD: + if (strnstr(w->name, "IIR0", sizeof("IIR0"))) { + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL)); + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL)); + } else { + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL)); + snd_soc_component_write(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, + snd_soc_component_read(component, + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL)); + } + break; + } + return 0; +} + +#ifdef CONFIG_BOLERO_VER_2P6 +static int lpass_cdc_rx_macro_fir_filter_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + ucontrol->value.bytes.data[0] = (unsigned char)rx_priv->is_fir_filter_on; + return 0; +} + +static int lpass_cdc_rx_macro_fir_filter_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + int ret = 0; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + if (!rx_priv->hifi_fir_clk) { + dev_dbg(rx_priv->dev, "%s: Undefined HIFI FIR Clock.\n", + __func__); + return 0; + } + + if (!rx_priv->is_fir_capable) { + dev_dbg(rx_priv->dev, "%s: HIFI FIR is not supported.\n", + __func__); + return 0; + } + + rx_priv->is_fir_filter_on = + (!ucontrol->value.bytes.data[0] ? false : true); + + dev_dbg(rx_priv->dev, "%s:is_fir_filter_on=%d\n", + __func__, rx_priv->is_fir_filter_on); + + if (rx_priv->is_fir_filter_on) { + ret = clk_prepare_enable(rx_priv->hifi_fir_clk); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, "%s:hifi_fir_clk enable failed\n", + __func__); + return ret; + } + + snd_soc_component_write(component, LPASS_CDC_RX_RX0_RX_FIR_CFG, + rx_priv->fir_total_coeff_num[RX0_PATH]); + dev_dbg(component->dev, "%s: HIFI FIR Path:%d total coefficients" + " number written: %d.\n", + __func__, RX0_PATH, + rx_priv->fir_total_coeff_num[RX0_PATH]); + snd_soc_component_write(component, LPASS_CDC_RX_RX1_RX_FIR_CFG, + rx_priv->fir_total_coeff_num[RX1_PATH]); + dev_dbg(component->dev, "%s: HIFI FIR Path:%d total coefficients" + " number written: %d.\n", + __func__, RX1_PATH, + rx_priv->fir_total_coeff_num[RX1_PATH]); + + /* Enable HIFI_FEAT_EN bit */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_TOP_TOP_CFG1, 0x01, 0x01); + /* Enable FIR_CLK_EN */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX0_RX_PATH_CTL, 0x80, 0x80); + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX1_RX_PATH_CTL, 0x80, 0x80); + /* Start the FIR filter */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX0_RX_FIR_CTL, 0x0D, 0x05); + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX1_RX_FIR_CTL, 0x0D, 0x05); + } else { + /* Stop the FIR filter */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX0_RX_FIR_CTL, 0x0D, 0x00); + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX1_RX_FIR_CTL, 0x0D, 0x00); + /* Disable FIR_CLK_EN */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX0_RX_PATH_CTL, 0x80, 0x00); + snd_soc_component_update_bits(component, LPASS_CDC_RX_RX1_RX_PATH_CTL, 0x80, 0x00); + /* Disable HIFI_FEAT_EN bit */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_TOP_TOP_CFG1, 0x01, 0x00); + + clk_disable_unprepare(rx_priv->hifi_fir_clk); + } + + return 0; +} + +static int lpass_cdc_rx_macro_fir_filter_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *ucontrol) +{ + struct lpass_cdc_rx_macro_fir_filter_ctl *ctl = + (struct lpass_cdc_rx_macro_fir_filter_ctl *)kcontrol->private_value; + struct soc_bytes_ext *params = &ctl->bytes_ext; + + ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; + ucontrol->count = params->max; + return 0; +} + +static int lpass_cdc_rx_macro_fir_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_rx_macro_fir_filter_ctl *ctl = + (struct lpass_cdc_rx_macro_fir_filter_ctl *)kcontrol->private_value; + unsigned int path_idx = ctl->path_idx; + unsigned int grp_idx = ctl->grp_idx; + u32 num_coeff_grp = 0; + u32 readArray[LPASS_CDC_RX_MACRO_FIR_COEFF_ARRAY_MAX]; + + unsigned int coeff_idx = 0, array_idx = 0; + unsigned int copy_size; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + if (path_idx >= FIR_PATH_MAX) { + dev_err_ratelimited(rx_priv->dev, "%s: path_idx:%d is invalid\n", + __func__, path_idx); + return -EINVAL; + } + + if (grp_idx >= GRP_MAX) { + dev_err_ratelimited(rx_priv->dev, "%s: grp_idx:%d is invalid\n", + __func__, grp_idx); + return -EINVAL; + } + + num_coeff_grp = rx_priv->num_fir_coeff[path_idx][grp_idx]; + readArray[array_idx++] = num_coeff_grp; + + for (coeff_idx = 0; coeff_idx < num_coeff_grp; coeff_idx++) { + readArray[array_idx++] = + rx_priv->fir_coeff_array[path_idx][grp_idx][coeff_idx]; + } + copy_size = array_idx; + + memcpy(ucontrol->value.bytes.data, &readArray[0], sizeof(readArray[0]) * copy_size); + + return 0; +} + +static int set_fir_filter_coeff(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + unsigned int path_idx) +{ + int grp_idx = 0, coeff_idx = 0; + unsigned int ret = 0; + unsigned int max_coeff_num, num_coeff_grp; + unsigned int path_ctl_addr = 0, wdata0_addr = 0, coeff_addr = 0; + unsigned int fir_ctl_addr = 0; + bool all_coeff_written = true; + + switch (path_idx) { + case RX0_PATH: + path_ctl_addr = LPASS_CDC_RX_RX0_RX_PATH_CTL; + wdata0_addr = LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA0; + coeff_addr = LPASS_CDC_RX_RX0_RX_FIR_COEFF_ADDR; + fir_ctl_addr = LPASS_CDC_RX_RX0_RX_FIR_CTL; + break; + case RX1_PATH: + path_ctl_addr = LPASS_CDC_RX_RX1_RX_PATH_CTL; + wdata0_addr = LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA0; + coeff_addr = LPASS_CDC_RX_RX1_RX_FIR_COEFF_ADDR; + fir_ctl_addr = LPASS_CDC_RX_RX1_RX_FIR_CTL; + break; + default: + dev_err_ratelimited(rx_priv->dev, + "%s: inavlid FIR ID: %d\n", __func__, path_idx); + ret = -EINVAL; + goto exit; + } + + max_coeff_num = LPASS_CDC_RX_MACRO_FIR_COEFF_MAX; + + for (grp_idx = 0; grp_idx < GRP_MAX; grp_idx++) + all_coeff_written = all_coeff_written && + rx_priv->is_fir_coeff_written[path_idx][grp_idx]; + + if (all_coeff_written) + goto exit; + + ret = lpass_cdc_rx_macro_mclk_enable(rx_priv, 1, false); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, "%s:rx_macro_mclk enable failed\n", + __func__); + goto exit; + } + + ret = clk_prepare_enable(rx_priv->hifi_fir_clk); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, "%s:hifi_fir_clk enable failed\n", + __func__); + goto disable_mclk_block; + } + + /* Enable HIFI_FEAT_EN bit */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_TOP_TOP_CFG1, 0x01, 0x01); + /* Enable FIR_CLK_EN, datapath reset */ + snd_soc_component_update_bits(component, path_ctl_addr, 0xC0, 0xC0); + /* Enable FIR_CLK_EN, Release Reset */ + snd_soc_component_update_bits(component, path_ctl_addr, 0xC0, 0x80); + + /* wait for data ram initialization after enabling clock */ + usleep_range(10, 11); + + for (grp_idx = 0; grp_idx < GRP_MAX; grp_idx++) { + unsigned int coeff_idx_start = 0, array_idx = 0; + + /* Skip if this group is written and no futher update */ + if (rx_priv->is_fir_coeff_written[path_idx][grp_idx]) + continue; + + num_coeff_grp = rx_priv->num_fir_coeff[path_idx][grp_idx]; + if (num_coeff_grp > max_coeff_num) { + dev_err_ratelimited(rx_priv->dev, + "%s: inavlid number of RX_FIR coefficients:%d" + " in path:%d, group:%d\n", + __func__, num_coeff_grp, path_idx, grp_idx); + ret = -EINVAL; + goto disable_FIR; + } + coeff_idx_start = grp_idx * max_coeff_num; + + for (coeff_idx = coeff_idx_start; + coeff_idx < coeff_idx_start + num_coeff_grp / 2 * 2; + coeff_idx += 2) { + + unsigned int addr_offset = coeff_idx / 2; + + /* First coefficient in pair */ + u32 value = rx_priv->fir_coeff_array[path_idx][grp_idx][array_idx++]; + dev_dbg(rx_priv->dev, "%s: val of coeff_idx:%d, COEFF:0x%x\n", + __func__, coeff_idx, value); + snd_soc_component_write(component, wdata0_addr, + value & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0x4, + (value >> 8) & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0x8, + (value >> 16) & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0xC, + (value >> 24) & 0xFF); + + /* Second coefficient in pair */ + value = rx_priv->fir_coeff_array[path_idx][grp_idx][array_idx++]; + dev_dbg(rx_priv->dev, "%s: val of coeff_idx:%d, COEFF:0x%x\n", + __func__, coeff_idx, value); + snd_soc_component_write(component, wdata0_addr + 0x10, + value & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0x14, + (value >> 8) & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0x18, + (value >> 16) & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0x1C, + (value >> 24) & 0xFF); + + snd_soc_component_write(component, coeff_addr, addr_offset); + snd_soc_component_update_bits(component, fir_ctl_addr, 0x02, 0x02); + usleep_range(13, 15); + snd_soc_component_update_bits(component, fir_ctl_addr, 0x02, 0x00); + } + + /* odd number of coefficients in this group, handle last one */ + if (num_coeff_grp % 2 != 0) { + int addr_offset = coeff_idx / 2; + + /* First coefficient in pair */ + u32 value = rx_priv->fir_coeff_array[path_idx][grp_idx][array_idx++]; + dev_dbg(rx_priv->dev, "%s: val of coeff_idx:%d, COEFF:0x%x\n", + __func__, coeff_idx, value); + snd_soc_component_write(component, wdata0_addr, + value & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0x4, + (value >> 8) & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0x8, + (value >> 16) & 0xFF); + snd_soc_component_write(component, wdata0_addr + 0xC, + (value >> 24) & 0xFF); + + /* Second coefficient in pair */ + dev_dbg(rx_priv->dev, "%s: val of coeff_idx:%d, COEFF:0x%x\n", + __func__, coeff_idx, 0x0); + snd_soc_component_write(component, wdata0_addr + 0x10, 0x0); + snd_soc_component_write(component, wdata0_addr + 0x14, 0x0); + snd_soc_component_write(component, wdata0_addr + 0x18, 0x0); + snd_soc_component_write(component, wdata0_addr + 0x1C, 0x0); + + snd_soc_component_write(component, coeff_addr, addr_offset); + snd_soc_component_update_bits(component, fir_ctl_addr, 0x02, 0x02); + usleep_range(13, 15); + snd_soc_component_update_bits(component, fir_ctl_addr, 0x02, 0x00); + } + + rx_priv->is_fir_coeff_written[path_idx][grp_idx] = true; + dev_dbg(component->dev, "%s: HIFI FIR Path:%d Group:%d coefficients" + " updated.\n", + __func__, path_idx, grp_idx); + } + +disable_FIR: + /* disable FIR_CLK_EN */ + snd_soc_component_update_bits(component, path_ctl_addr, 0x80, 0x00); + + /* Disable HIFI_FEAT_EN bit */ + snd_soc_component_update_bits(component, LPASS_CDC_RX_TOP_TOP_CFG1, 0x01, 0x00); + + clk_disable_unprepare(rx_priv->hifi_fir_clk); + +disable_mclk_block: + lpass_cdc_rx_macro_mclk_enable(rx_priv, 0, false); + +exit: + return ret; +} + +static int lpass_cdc_rx_macro_fir_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_rx_macro_fir_filter_ctl *ctl = + (struct lpass_cdc_rx_macro_fir_filter_ctl *)kcontrol->private_value; + unsigned int path_idx = ctl->path_idx; + unsigned int grp_idx = ctl->grp_idx; + u32 ele_size = 0, num_coeff_grp = 0; + u32 coeff[LPASS_CDC_RX_MACRO_FIR_COEFF_ARRAY_MAX]; + + int ret = 0; + unsigned int stored_total_num = 0; + unsigned int grp_iidx = 0, coeff_idx = 0, array_idx = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + if (path_idx >= FIR_PATH_MAX) { + dev_err_ratelimited(rx_priv->dev, "%s: path_idx:%d is invalid\n", + __func__, path_idx); + return -EINVAL; + } + + if (grp_idx >= GRP_MAX) { + dev_err_ratelimited(rx_priv->dev, "%s: grp_idx:%d is invalid\n", + __func__, grp_idx); + return -EINVAL; + } + + if (!rx_priv->hifi_fir_clk) { + dev_dbg(rx_priv->dev, "%s: Undefined HIFI FIR Clock.\n", + __func__); + return 0; + } + + if (!rx_priv->is_fir_capable) { + dev_dbg(rx_priv->dev, "%s: HIFI FIR is not supported.\n", + __func__); + return 0; + } + + ele_size = sizeof(coeff[0]); + memcpy(&coeff[0], ucontrol->value.bytes.data, ele_size); + num_coeff_grp = coeff[0]; + + dev_dbg(rx_priv->dev, "%s: bytes.data: path:%d, grp:%d, num_coeff_grp:%d\n", + __func__, path_idx, grp_idx, num_coeff_grp); + + if (num_coeff_grp > LPASS_CDC_RX_MACRO_FIR_COEFF_MAX) { + dev_err_ratelimited(rx_priv->dev, + "%s: inavlid number of RX_FIR coefficients:%d in path:%d, group:%d\n", + __func__, num_coeff_grp, path_idx, grp_idx); + rx_priv->num_fir_coeff[path_idx][grp_idx] = 0; + return -EINVAL; + } else { + rx_priv->num_fir_coeff[path_idx][grp_idx] = num_coeff_grp; + } + + memcpy(&coeff[1], &(ucontrol->value.bytes.data[ele_size]), ele_size * num_coeff_grp); + + /* Store the coefficients in FIR coeff array */ + array_idx = 1; + for (coeff_idx = 0; coeff_idx < num_coeff_grp; coeff_idx++) + rx_priv->fir_coeff_array[path_idx][grp_idx][coeff_idx] = coeff[array_idx++]; + + /* Clear the written flag so this group is ready to be written */ + rx_priv->is_fir_coeff_written[path_idx][grp_idx] = false; + + stored_total_num = 0; + for (grp_iidx = 0; grp_iidx < GRP_MAX; grp_iidx++) { + stored_total_num += rx_priv->num_fir_coeff[path_idx][grp_iidx]; + } + + /* Only write coeffs if total num matches, otherwise delay the write */ + if (rx_priv->fir_total_coeff_num[path_idx] == stored_total_num) + ret = set_fir_filter_coeff(component, rx_priv, path_idx); + + return ret; +} + +static int lpass_cdc_rx_macro_fir_coeff_num_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + unsigned int path_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + if (path_idx >= FIR_PATH_MAX) { + dev_err_ratelimited(rx_priv->dev, "%s: path_idx:%d is invalid\n", + __func__, path_idx); + return -EINVAL; + } + + ucontrol->value.bytes.data[0] = rx_priv->fir_total_coeff_num[path_idx]; + + return 0; +} + +static int lpass_cdc_rx_macro_fir_coeff_num_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + unsigned int path_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + u8 fir_total_coeff_num = ucontrol->value.bytes.data[0]; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + unsigned int ret = 0; + unsigned int grp_idx, stored_total_num; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + if (fir_total_coeff_num > LPASS_CDC_RX_MACRO_FIR_COEFF_MAX * GRP_MAX) { + dev_err_ratelimited(rx_priv->dev, + "%s: inavlid total number of RX_FIR coefficients:%d" + " in path:%d\n", + __func__, fir_total_coeff_num, path_idx); + rx_priv->fir_total_coeff_num[path_idx] = 0; + return -EINVAL; + } else { + rx_priv->fir_total_coeff_num[path_idx] = fir_total_coeff_num; + } + + dev_dbg(component->dev, "%s: HIFI FIR Path:%d total coefficients" + " number updated in private data: %d.\n", + __func__, path_idx, fir_total_coeff_num); + + stored_total_num = 0; + for (grp_idx = 0; grp_idx < GRP_MAX; grp_idx++) + stored_total_num += rx_priv->num_fir_coeff[path_idx][grp_idx]; + + if (fir_total_coeff_num == stored_total_num) + ret = set_fir_filter_coeff(component, rx_priv, path_idx); + + return ret; +} +#endif + +static const struct snd_kcontrol_new lpass_cdc_rx_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", + LPASS_CDC_RX_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", + LPASS_CDC_RX_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", + LPASS_CDC_RX_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", + LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", + LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", + LPASS_CDC_RX_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + + SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, LPASS_CDC_RX_MACRO_COMP1, 1, 0, + lpass_cdc_rx_macro_get_compander, lpass_cdc_rx_macro_set_compander), + SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, LPASS_CDC_RX_MACRO_COMP2, 1, 0, + lpass_cdc_rx_macro_get_compander, lpass_cdc_rx_macro_set_compander), + +#ifdef CONFIG_BOLERO_VER_2P6 + SOC_SINGLE_EXT("RX_HPH PCM", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_rx_macro_get_pcm_path, lpass_cdc_rx_macro_put_pcm_path), + + SOC_SINGLE_EXT("RX0 FIR Coeff Num", SND_SOC_NOPM, RX0_PATH, + (LPASS_CDC_RX_MACRO_FIR_COEFF_MAX * GRP_MAX), 0, + lpass_cdc_rx_macro_fir_coeff_num_get, lpass_cdc_rx_macro_fir_coeff_num_put), + + SOC_SINGLE_EXT("RX1 FIR Coeff Num", SND_SOC_NOPM, RX1_PATH, + (LPASS_CDC_RX_MACRO_FIR_COEFF_MAX * GRP_MAX), 0, + lpass_cdc_rx_macro_fir_coeff_num_get, lpass_cdc_rx_macro_fir_coeff_num_put), + SOC_ENUM_EXT("RX_FIR Filter", lpass_cdc_rx_macro_fir_filter_enum, + lpass_cdc_rx_macro_fir_filter_enable_get, lpass_cdc_rx_macro_fir_filter_enable_put), +#endif + + SOC_ENUM_EXT("HPH Idle Detect", hph_idle_detect_enum, + lpass_cdc_rx_macro_hph_idle_detect_get, lpass_cdc_rx_macro_hph_idle_detect_put), + + SOC_ENUM_EXT("RX_EAR Mode", lpass_cdc_rx_macro_ear_mode_enum, + lpass_cdc_rx_macro_get_ear_mode, lpass_cdc_rx_macro_put_ear_mode), + + + SOC_ENUM_EXT("RX_HPH HD2 Mode", lpass_cdc_rx_macro_hph_hd2_mode_enum, + lpass_cdc_rx_macro_get_hph_hd2_mode, lpass_cdc_rx_macro_put_hph_hd2_mode), + + SOC_ENUM_EXT("RX_HPH_PWR_MODE", lpass_cdc_rx_macro_hph_pwr_mode_enum, + lpass_cdc_rx_macro_get_hph_pwr_mode, lpass_cdc_rx_macro_put_hph_pwr_mode), + + SOC_ENUM_EXT("RX_GSM mode Enable", lpass_cdc_rx_macro_vbat_bcl_gsm_mode_enum, + lpass_cdc_rx_macro_vbat_bcl_gsm_mode_func_get, + lpass_cdc_rx_macro_vbat_bcl_gsm_mode_func_put), + SOC_SINGLE_EXT("RX_Softclip Enable", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_rx_macro_soft_clip_enable_get, + lpass_cdc_rx_macro_soft_clip_enable_put), + SOC_SINGLE_EXT("AUX_HPF Enable", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_rx_macro_aux_hpf_mode_get, + lpass_cdc_rx_macro_aux_hpf_mode_put), + + SOC_SINGLE_S8_TLV("IIR0 INP0 Volume", + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP1 Volume", + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP2 Volume", + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP3 Volume", + LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP0 Volume", + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", + LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40, + digital_gain), + + SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band2", IIR0, BAND2, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band3", IIR0, BAND3, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band4", IIR0, BAND4, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band5", IIR0, BAND5, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0, + lpass_cdc_rx_macro_iir_enable_audio_mixer_get, + lpass_cdc_rx_macro_iir_enable_audio_mixer_put), + + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR0 Band1", IIR0, BAND1), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR0 Band2", IIR0, BAND2), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR0 Band3", IIR0, BAND3), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR0 Band4", IIR0, BAND4), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR0 Band5", IIR0, BAND5), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR1 Band1", IIR1, BAND1), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR1 Band2", IIR1, BAND2), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR1 Band3", IIR1, BAND3), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR1 Band4", IIR1, BAND4), + LPASS_CDC_RX_MACRO_IIR_FILTER_CTL("IIR1 Band5", IIR1, BAND5), + +#ifdef CONFIG_BOLERO_VER_2P6 + LPASS_CDC_RX_MACRO_FIR_FILTER_CTL("RX0 FIR Coeff Group0", RX0_PATH, GRP0), + LPASS_CDC_RX_MACRO_FIR_FILTER_CTL("RX0 FIR Coeff Group1", RX0_PATH, GRP1), + LPASS_CDC_RX_MACRO_FIR_FILTER_CTL("RX1 FIR Coeff Group0", RX1_PATH, GRP0), + LPASS_CDC_RX_MACRO_FIR_FILTER_CTL("RX1 FIR Coeff Group1", RX1_PATH, GRP1), +#endif +}; + +static int lpass_cdc_rx_macro_enable_echo(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 device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + u16 val = 0, ec_hq_reg = 0; + int ec_tx = 0; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + dev_dbg(rx_dev, "%s %d %s\n", __func__, event, w->name); + + val = snd_soc_component_read(component, + LPASS_CDC_RX_INP_MUX_RX_MIX_CFG4); + if (!(strcmp(w->name, "RX MIX TX0 MUX"))) + ec_tx = ((val & 0xf0) >> 0x4) - 1; + else if (!(strcmp(w->name, "RX MIX TX1 MUX"))) + ec_tx = (val & 0x0f) - 1; + + val = snd_soc_component_read(component, + LPASS_CDC_RX_INP_MUX_RX_MIX_CFG5); + if (!(strcmp(w->name, "RX MIX TX2 MUX"))) + ec_tx = (val & 0x0f) - 1; + + if (ec_tx < 0 || (ec_tx >= LPASS_CDC_RX_MACRO_EC_MUX_MAX)) { + dev_err_ratelimited(rx_dev, "%s: EC mix control not set correctly\n", + __func__); + return -EINVAL; + } + ec_hq_reg = LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL + + 0x40 * ec_tx; + snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01); + ec_hq_reg = LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0 + + 0x40 * ec_tx; + /* default set to 48k */ + snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08); + + return 0; +} + +static const struct snd_soc_dapm_widget lpass_cdc_rx_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX AIF1 PB", "RX_MACRO_AIF1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF2 PB", "RX_MACRO_AIF2 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF3 PB", "RX_MACRO_AIF3 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF4 PB", "RX_MACRO_AIF4 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("RX AIF_ECHO", "RX_AIF_ECHO Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF5 PB", "RX_MACRO_AIF5 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("RX AIF6 PB", "RX_MACRO_AIF6 Playback", 0, + SND_SOC_NOPM, 0, 0), + + LPASS_CDC_RX_MACRO_DAPM_MUX("RX_MACRO RX0 MUX", LPASS_CDC_RX_MACRO_RX0, lpass_cdc_rx_macro_rx0), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX_MACRO RX1 MUX", LPASS_CDC_RX_MACRO_RX1, lpass_cdc_rx_macro_rx1), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX_MACRO RX2 MUX", LPASS_CDC_RX_MACRO_RX2, lpass_cdc_rx_macro_rx2), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX_MACRO RX3 MUX", LPASS_CDC_RX_MACRO_RX3, lpass_cdc_rx_macro_rx3), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX_MACRO RX4 MUX", LPASS_CDC_RX_MACRO_RX4, lpass_cdc_rx_macro_rx4), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX_MACRO RX5 MUX", LPASS_CDC_RX_MACRO_RX5, lpass_cdc_rx_macro_rx5), + + SND_SOC_DAPM_MIXER("RX_RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX_RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR0 INP0 MUX", 0, iir0_inp0), + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR0 INP1 MUX", 0, iir0_inp1), + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR0 INP2 MUX", 0, iir0_inp2), + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR0 INP3 MUX", 0, iir0_inp3), + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR1 INP0 MUX", 0, iir1_inp0), + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR1 INP1 MUX", 0, iir1_inp1), + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR1 INP2 MUX", 0, iir1_inp2), + LPASS_CDC_RX_MACRO_DAPM_MUX("IIR1 INP3 MUX", 0, iir1_inp3), + + SND_SOC_DAPM_MUX_E("RX MIX TX0 MUX", SND_SOC_NOPM, + LPASS_CDC_RX_MACRO_EC0_MUX, 0, + &rx_mix_tx0_mux, lpass_cdc_rx_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX MIX TX1 MUX", SND_SOC_NOPM, + LPASS_CDC_RX_MACRO_EC1_MUX, 0, + &rx_mix_tx1_mux, lpass_cdc_rx_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX MIX TX2 MUX", SND_SOC_NOPM, + LPASS_CDC_RX_MACRO_EC2_MUX, 0, + &rx_mix_tx2_mux, lpass_cdc_rx_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("IIR0", LPASS_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL, + 4, 0, NULL, 0, lpass_cdc_rx_macro_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER_E("IIR1", LPASS_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL, + 4, 0, NULL, 0, lpass_cdc_rx_macro_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER("SRC0", LPASS_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SRC1", LPASS_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT0 DEM MUX", 0, rx_int0_dem_inp), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT1 DEM MUX", 0, rx_int1_dem_inp), + + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int0_2_mux, lpass_cdc_rx_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int1_2_mux, lpass_cdc_rx_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", SND_SOC_NOPM, INTERP_AUX, 0, + &rx_int2_2_mux, lpass_cdc_rx_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT0_1 MIX1 INP0", 0, rx_int0_1_mix_inp0), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT0_1 MIX1 INP1", 0, rx_int0_1_mix_inp1), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT0_1 MIX1 INP2", 0, rx_int0_1_mix_inp2), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT1_1 MIX1 INP0", 0, rx_int1_1_mix_inp0), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT1_1 MIX1 INP1", 0, rx_int1_1_mix_inp1), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT1_1 MIX1 INP2", 0, rx_int1_1_mix_inp2), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT2_1 MIX1 INP0", 0, rx_int2_1_mix_inp0), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT2_1 MIX1 INP1", 0, rx_int2_1_mix_inp1), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT2_1 MIX1 INP2", 0, rx_int2_1_mix_inp2), + + SND_SOC_DAPM_MUX_E("RX INT0_1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int0_1_interp_mux, lpass_cdc_rx_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1_1 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int1_1_interp_mux, lpass_cdc_rx_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2_1 INTERP", SND_SOC_NOPM, INTERP_AUX, 0, + &rx_int2_1_interp_mux, lpass_cdc_rx_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT0_2 INTERP", 0, rx_int0_2_interp), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT1_2 INTERP", 0, rx_int1_2_interp), + LPASS_CDC_RX_MACRO_DAPM_MUX("RX INT2_2 INTERP", 0, rx_int2_2_interp), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", SND_SOC_NOPM, INTERP_HPHL, + 0, &rx_int0_mix2_inp_mux, lpass_cdc_rx_macro_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", SND_SOC_NOPM, INTERP_HPHR, + 0, &rx_int1_mix2_inp_mux, lpass_cdc_rx_macro_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", SND_SOC_NOPM, INTERP_AUX, + 0, &rx_int2_mix2_inp_mux, lpass_cdc_rx_macro_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("RX INT2_1 VBAT", SND_SOC_NOPM, + 0, 0, rx_int2_1_vbat_mix_switch, + ARRAY_SIZE(rx_int2_1_vbat_mix_switch), + lpass_cdc_rx_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("HPHL_OUT"), + SND_SOC_DAPM_OUTPUT("HPHR_OUT"), + SND_SOC_DAPM_OUTPUT("AUX_OUT"), + SND_SOC_DAPM_OUTPUT("PCM_OUT"), + + SND_SOC_DAPM_INPUT("RX_TX DEC0_INP"), + SND_SOC_DAPM_INPUT("RX_TX DEC1_INP"), + SND_SOC_DAPM_INPUT("RX_TX DEC2_INP"), + SND_SOC_DAPM_INPUT("RX_TX DEC3_INP"), + + SND_SOC_DAPM_SUPPLY_S("RX_MCLK", 0, SND_SOC_NOPM, 0, 0, + lpass_cdc_rx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route rx_audio_map[] = { + {"RX AIF1 PB", NULL, "RX_MCLK"}, + {"RX AIF2 PB", NULL, "RX_MCLK"}, + {"RX AIF3 PB", NULL, "RX_MCLK"}, + {"RX AIF4 PB", NULL, "RX_MCLK"}, + + {"RX AIF6 PB", NULL, "RX_MCLK"}, + {"PCM_OUT", NULL, "RX AIF6 PB"}, + + {"RX_MACRO RX0 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX1 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX2 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX3 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX4 MUX", "AIF1_PB", "RX AIF1 PB"}, + {"RX_MACRO RX5 MUX", "AIF1_PB", "RX AIF1 PB"}, + + {"RX_MACRO RX0 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX1 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX2 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX3 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX4 MUX", "AIF2_PB", "RX AIF2 PB"}, + {"RX_MACRO RX5 MUX", "AIF2_PB", "RX AIF2 PB"}, + + {"RX_MACRO RX0 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX1 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX2 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX3 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX4 MUX", "AIF3_PB", "RX AIF3 PB"}, + {"RX_MACRO RX5 MUX", "AIF3_PB", "RX AIF3 PB"}, + + {"RX_MACRO RX0 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX1 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX2 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX3 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX4 MUX", "AIF4_PB", "RX AIF4 PB"}, + {"RX_MACRO RX5 MUX", "AIF4_PB", "RX AIF4 PB"}, + + {"RX_RX0", NULL, "RX_MACRO RX0 MUX"}, + {"RX_RX1", NULL, "RX_MACRO RX1 MUX"}, + {"RX_RX2", NULL, "RX_MACRO RX2 MUX"}, + {"RX_RX3", NULL, "RX_MACRO RX3 MUX"}, + {"RX_RX4", NULL, "RX_MACRO RX4 MUX"}, + {"RX_RX5", NULL, "RX_MACRO RX5 MUX"}, + + {"RX INT0_1 MIX1 INP0", "RX0", "RX_RX0"}, + {"RX INT0_1 MIX1 INP0", "RX1", "RX_RX1"}, + {"RX INT0_1 MIX1 INP0", "RX2", "RX_RX2"}, + {"RX INT0_1 MIX1 INP0", "RX3", "RX_RX3"}, + {"RX INT0_1 MIX1 INP0", "RX4", "RX_RX4"}, + {"RX INT0_1 MIX1 INP0", "RX5", "RX_RX5"}, + {"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT0_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT0_1 MIX1 INP1", "RX0", "RX_RX0"}, + {"RX INT0_1 MIX1 INP1", "RX1", "RX_RX1"}, + {"RX INT0_1 MIX1 INP1", "RX2", "RX_RX2"}, + {"RX INT0_1 MIX1 INP1", "RX3", "RX_RX3"}, + {"RX INT0_1 MIX1 INP1", "RX4", "RX_RX4"}, + {"RX INT0_1 MIX1 INP1", "RX5", "RX_RX5"}, + {"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT0_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT0_1 MIX1 INP2", "RX0", "RX_RX0"}, + {"RX INT0_1 MIX1 INP2", "RX1", "RX_RX1"}, + {"RX INT0_1 MIX1 INP2", "RX2", "RX_RX2"}, + {"RX INT0_1 MIX1 INP2", "RX3", "RX_RX3"}, + {"RX INT0_1 MIX1 INP2", "RX4", "RX_RX4"}, + {"RX INT0_1 MIX1 INP2", "RX5", "RX_RX5"}, + {"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT0_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"}, + + {"RX INT1_1 MIX1 INP0", "RX0", "RX_RX0"}, + {"RX INT1_1 MIX1 INP0", "RX1", "RX_RX1"}, + {"RX INT1_1 MIX1 INP0", "RX2", "RX_RX2"}, + {"RX INT1_1 MIX1 INP0", "RX3", "RX_RX3"}, + {"RX INT1_1 MIX1 INP0", "RX4", "RX_RX4"}, + {"RX INT1_1 MIX1 INP0", "RX5", "RX_RX5"}, + {"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT1_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT1_1 MIX1 INP1", "RX0", "RX_RX0"}, + {"RX INT1_1 MIX1 INP1", "RX1", "RX_RX1"}, + {"RX INT1_1 MIX1 INP1", "RX2", "RX_RX2"}, + {"RX INT1_1 MIX1 INP1", "RX3", "RX_RX3"}, + {"RX INT1_1 MIX1 INP1", "RX4", "RX_RX4"}, + {"RX INT1_1 MIX1 INP1", "RX5", "RX_RX5"}, + {"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT1_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT1_1 MIX1 INP2", "RX0", "RX_RX0"}, + {"RX INT1_1 MIX1 INP2", "RX1", "RX_RX1"}, + {"RX INT1_1 MIX1 INP2", "RX2", "RX_RX2"}, + {"RX INT1_1 MIX1 INP2", "RX3", "RX_RX3"}, + {"RX INT1_1 MIX1 INP2", "RX4", "RX_RX4"}, + {"RX INT1_1 MIX1 INP2", "RX5", "RX_RX5"}, + {"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT1_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"}, + + {"RX INT2_1 MIX1 INP0", "RX0", "RX_RX0"}, + {"RX INT2_1 MIX1 INP0", "RX1", "RX_RX1"}, + {"RX INT2_1 MIX1 INP0", "RX2", "RX_RX2"}, + {"RX INT2_1 MIX1 INP0", "RX3", "RX_RX3"}, + {"RX INT2_1 MIX1 INP0", "RX4", "RX_RX4"}, + {"RX INT2_1 MIX1 INP0", "RX5", "RX_RX5"}, + {"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT2_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT2_1 MIX1 INP1", "RX0", "RX_RX0"}, + {"RX INT2_1 MIX1 INP1", "RX1", "RX_RX1"}, + {"RX INT2_1 MIX1 INP1", "RX2", "RX_RX2"}, + {"RX INT2_1 MIX1 INP1", "RX3", "RX_RX3"}, + {"RX INT2_1 MIX1 INP1", "RX4", "RX_RX4"}, + {"RX INT2_1 MIX1 INP1", "RX5", "RX_RX5"}, + {"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT2_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"}, + {"RX INT2_1 MIX1 INP2", "RX0", "RX_RX0"}, + {"RX INT2_1 MIX1 INP2", "RX1", "RX_RX1"}, + {"RX INT2_1 MIX1 INP2", "RX2", "RX_RX2"}, + {"RX INT2_1 MIX1 INP2", "RX3", "RX_RX3"}, + {"RX INT2_1 MIX1 INP2", "RX4", "RX_RX4"}, + {"RX INT2_1 MIX1 INP2", "RX5", "RX_RX5"}, + {"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"}, + {"RX INT2_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"}, + + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"}, + + {"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX AIF_ECHO", NULL, "RX MIX TX0 MUX"}, + {"RX AIF_ECHO", NULL, "RX MIX TX1 MUX"}, + {"RX AIF_ECHO", NULL, "RX MIX TX2 MUX"}, + {"RX AIF_ECHO", NULL, "RX_MCLK"}, + + /* Mixing path INT0 */ + {"RX INT0_2 MUX", "RX0", "RX_RX0"}, + {"RX INT0_2 MUX", "RX1", "RX_RX1"}, + {"RX INT0_2 MUX", "RX2", "RX_RX2"}, + {"RX INT0_2 MUX", "RX3", "RX_RX3"}, + {"RX INT0_2 MUX", "RX4", "RX_RX4"}, + {"RX INT0_2 MUX", "RX5", "RX_RX5"}, + {"RX INT0_2 INTERP", NULL, "RX INT0_2 MUX"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_2 INTERP"}, + + /* Mixing path INT1 */ + {"RX INT1_2 MUX", "RX0", "RX_RX0"}, + {"RX INT1_2 MUX", "RX1", "RX_RX1"}, + {"RX INT1_2 MUX", "RX2", "RX_RX2"}, + {"RX INT1_2 MUX", "RX3", "RX_RX3"}, + {"RX INT1_2 MUX", "RX4", "RX_RX4"}, + {"RX INT1_2 MUX", "RX5", "RX_RX5"}, + {"RX INT1_2 INTERP", NULL, "RX INT1_2 MUX"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_2 INTERP"}, + + /* Mixing path INT2 */ + {"RX INT2_2 MUX", "RX0", "RX_RX0"}, + {"RX INT2_2 MUX", "RX1", "RX_RX1"}, + {"RX INT2_2 MUX", "RX2", "RX_RX2"}, + {"RX INT2_2 MUX", "RX3", "RX_RX3"}, + {"RX INT2_2 MUX", "RX4", "RX_RX4"}, + {"RX INT2_2 MUX", "RX5", "RX_RX5"}, + {"RX INT2_2 INTERP", NULL, "RX INT2_2 MUX"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_2 INTERP"}, + + {"RX INT0_1 INTERP", NULL, "RX INT0_1 MIX1"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_1 INTERP"}, + {"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"}, + {"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"}, + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 MIX2"}, + {"HPHL_OUT", NULL, "RX INT0 DEM MUX"}, + {"HPHL_OUT", NULL, "RX_MCLK"}, + + {"RX INT1_1 INTERP", NULL, "RX INT1_1 MIX1"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_1 INTERP"}, + {"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"}, + {"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"}, + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 MIX2"}, + {"HPHR_OUT", NULL, "RX INT1 DEM MUX"}, + {"HPHR_OUT", NULL, "RX_MCLK"}, + + {"RX INT2_1 INTERP", NULL, "RX INT2_1 MIX1"}, + + {"RX INT2_1 VBAT", "RX AUX VBAT Enable", "RX INT2_1 INTERP"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_1 VBAT"}, + + {"RX INT2 SEC MIX", NULL, "RX INT2_1 INTERP"}, + {"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"}, + {"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"}, + {"AUX_OUT", NULL, "RX INT2 MIX2"}, + {"AUX_OUT", NULL, "RX_MCLK"}, + + {"IIR0", NULL, "RX_MCLK"}, + {"IIR0", NULL, "IIR0 INP0 MUX"}, + {"IIR0 INP0 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP0 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP0 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP0 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP0 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP0 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP0 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP0 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP0 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP0 MUX", "RX5", "RX_RX5"}, + {"IIR0", NULL, "IIR0 INP1 MUX"}, + {"IIR0 INP1 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP1 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP1 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP1 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP1 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP1 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP1 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP1 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP1 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP1 MUX", "RX5", "RX_RX5"}, + {"IIR0", NULL, "IIR0 INP2 MUX"}, + {"IIR0 INP2 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP2 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP2 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP2 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP2 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP2 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP2 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP2 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP2 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP2 MUX", "RX5", "RX_RX5"}, + {"IIR0", NULL, "IIR0 INP3 MUX"}, + {"IIR0 INP3 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR0 INP3 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR0 INP3 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR0 INP3 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR0 INP3 MUX", "RX0", "RX_RX0"}, + {"IIR0 INP3 MUX", "RX1", "RX_RX1"}, + {"IIR0 INP3 MUX", "RX2", "RX_RX2"}, + {"IIR0 INP3 MUX", "RX3", "RX_RX3"}, + {"IIR0 INP3 MUX", "RX4", "RX_RX4"}, + {"IIR0 INP3 MUX", "RX5", "RX_RX5"}, + + {"IIR1", NULL, "RX_MCLK"}, + {"IIR1", NULL, "IIR1 INP0 MUX"}, + {"IIR1 INP0 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP0 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP0 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP0 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP0 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP0 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP0 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP0 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP0 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP0 MUX", "RX5", "RX_RX5"}, + {"IIR1", NULL, "IIR1 INP1 MUX"}, + {"IIR1 INP1 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP1 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP1 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP1 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP1 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP1 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP1 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP1 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP1 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP1 MUX", "RX5", "RX_RX5"}, + {"IIR1", NULL, "IIR1 INP2 MUX"}, + {"IIR1 INP2 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP2 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP2 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP2 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP2 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP2 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP2 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP2 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP2 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP2 MUX", "RX5", "RX_RX5"}, + {"IIR1", NULL, "IIR1 INP3 MUX"}, + {"IIR1 INP3 MUX", "DEC0", "RX_TX DEC0_INP"}, + {"IIR1 INP3 MUX", "DEC1", "RX_TX DEC1_INP"}, + {"IIR1 INP3 MUX", "DEC2", "RX_TX DEC2_INP"}, + {"IIR1 INP3 MUX", "DEC3", "RX_TX DEC3_INP"}, + {"IIR1 INP3 MUX", "RX0", "RX_RX0"}, + {"IIR1 INP3 MUX", "RX1", "RX_RX1"}, + {"IIR1 INP3 MUX", "RX2", "RX_RX2"}, + {"IIR1 INP3 MUX", "RX3", "RX_RX3"}, + {"IIR1 INP3 MUX", "RX4", "RX_RX4"}, + {"IIR1 INP3 MUX", "RX5", "RX_RX5"}, + + {"SRC0", NULL, "IIR0"}, + {"SRC1", NULL, "IIR1"}, + {"RX INT0 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT0 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT1 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT1 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT2 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT2 MIX2 INP", "SRC1", "SRC1"}, +}; + +static int lpass_cdc_rx_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct lpass_cdc_rx_macro_priv *rx_priv = (struct lpass_cdc_rx_macro_priv *) handle; + + if (rx_priv == NULL) { + pr_err_ratelimited("%s: rx priv data is NULL\n", __func__); + return -EINVAL; + } + + if (!rx_priv->pre_dev_up && enable) { + pr_debug("%s: adsp is not up\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(rx_priv->dev); + if (lpass_cdc_check_core_votes(rx_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(rx_priv->dev); + pm_runtime_mark_last_busy(rx_priv->dev); + } + return rc; +} + +static int rx_swrm_clock(void *handle, bool enable) +{ + struct lpass_cdc_rx_macro_priv *rx_priv = (struct lpass_cdc_rx_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(rx_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(rx_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&rx_priv->swr_clk_lock); + + dev_dbg(rx_priv->dev, "%s: swrm clock %s\n", + __func__, (enable ? "enable" : "disable")); + if (enable) { + pm_runtime_get_sync(rx_priv->dev); + if (rx_priv->swr_clk_users == 0) { + ret = msm_cdc_pinctrl_select_active_state( + rx_priv->rx_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, + "%s: rx swr pinctrl enable failed\n", + __func__); + pm_runtime_mark_last_busy(rx_priv->dev); + pm_runtime_put_autosuspend(rx_priv->dev); + goto exit; + } + ret = lpass_cdc_rx_macro_mclk_enable(rx_priv, 1, true); + if (ret < 0) { + msm_cdc_pinctrl_select_sleep_state( + rx_priv->rx_swr_gpio_p); + dev_err_ratelimited(rx_priv->dev, + "%s: rx request clock enable failed\n", + __func__); + pm_runtime_mark_last_busy(rx_priv->dev); + pm_runtime_put_autosuspend(rx_priv->dev); + goto exit; + } + if (rx_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (rx_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + rx_priv->reset_swr = false; + } + pm_runtime_mark_last_busy(rx_priv->dev); + pm_runtime_put_autosuspend(rx_priv->dev); + rx_priv->swr_clk_users++; + } else { + if (rx_priv->swr_clk_users <= 0) { + dev_err_ratelimited(rx_priv->dev, + "%s: rx swrm clock users already reset\n", + __func__); + rx_priv->swr_clk_users = 0; + goto exit; + } + rx_priv->swr_clk_users--; + if (rx_priv->swr_clk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + lpass_cdc_rx_macro_mclk_enable(rx_priv, 0, true); + ret = msm_cdc_pinctrl_select_sleep_state( + rx_priv->rx_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(rx_priv->dev, + "%s: rx swr pinctrl disable failed\n", + __func__); + goto exit; + } + } + } + dev_dbg(rx_priv->dev, "%s: swrm clock users %d\n", + __func__, rx_priv->swr_clk_users); +exit: + mutex_unlock(&rx_priv->swr_clk_lock); + return ret; +} + +#ifdef CONFIG_BOLERO_VER_2P6 +/** + * lpass_cdc_rx_set_fir_capability - Set RX HIFI FIR Filter capability + * + * @component: Codec component ptr. + * @capable: if the target have RX HIFI FIR available. + * + * Set RX HIFI FIR capability, stored the capability into RX macro private data. + */ +int lpass_cdc_rx_set_fir_capability(struct snd_soc_component *component, bool capable) +{ + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->is_fir_capable = capable; + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_rx_set_fir_capability); +#endif + +static const struct lpass_cdc_rx_macro_reg_mask_val + lpass_cdc_rx_macro_reg_init[] = { + {LPASS_CDC_RX_RX0_RX_PATH_SEC7, 0x07, 0x02}, + {LPASS_CDC_RX_RX1_RX_PATH_SEC7, 0x07, 0x02}, + {LPASS_CDC_RX_RX2_RX_PATH_SEC7, 0x07, 0x02}, + {LPASS_CDC_RX_RX0_RX_PATH_CFG3, 0x03, 0x02}, + {LPASS_CDC_RX_RX1_RX_PATH_CFG3, 0x03, 0x02}, + {LPASS_CDC_RX_RX2_RX_PATH_CFG3, 0x03, 0x02}, +}; + +#ifdef CONFIG_BOLERO_VER_2P1 +static void lpass_cdc_rx_macro_init_bcl_pmic_reg(struct snd_soc_component *component) +{ + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!component) { + pr_err("%s: NULL component pointer!\n", __func__); + return; + } + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return; + + switch (rx_priv->bcl_pmic_params.id) { + case 0: + /* Enable ID0 to listen to respective PMIC group interrupts */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_DECODE_CTL1, 0x02, 0x02); + /* Update MC_SID0 */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_DECODE_CFG1, 0x0F, + rx_priv->bcl_pmic_params.sid); + /* Update MC_PPID0 */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_DECODE_CFG2, 0xFF, + rx_priv->bcl_pmic_params.ppid); + break; + case 1: + /* Enable ID1 to listen to respective PMIC group interrupts */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_DECODE_CTL1, 0x01, 0x01); + /* Update MC_SID1 */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_DECODE_CFG3, 0x0F, + rx_priv->bcl_pmic_params.sid); + /* Update MC_PPID1 */ + snd_soc_component_update_bits(component, + LPASS_CDC_RX_BCL_VBAT_DECODE_CFG1, 0xFF, + rx_priv->bcl_pmic_params.ppid); + break; + default: + dev_err(rx_dev, "%s: PMIC ID is invalid %d\n", + __func__, rx_priv->bcl_pmic_params.id); + break; + } +} +#endif + +static int lpass_cdc_rx_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = 0; + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + int i; + + rx_dev = lpass_cdc_get_device_ptr(component->dev, RX_MACRO); + if (!rx_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + rx_priv = dev_get_drvdata(rx_dev); + if (!rx_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + + ret = snd_soc_dapm_new_controls(dapm, lpass_cdc_rx_macro_dapm_widgets, + ARRAY_SIZE(lpass_cdc_rx_macro_dapm_widgets)); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add controls\n", __func__); + return ret; + } + ret = snd_soc_dapm_add_routes(dapm, rx_audio_map, + ARRAY_SIZE(rx_audio_map)); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add routes\n", __func__); + return ret; + } + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add widgets\n", __func__); + return ret; + } + ret = snd_soc_add_component_controls(component, lpass_cdc_rx_macro_snd_controls, + ARRAY_SIZE(lpass_cdc_rx_macro_snd_controls)); + if (ret < 0) { + dev_err(rx_dev, "%s: failed to add snd_ctls\n", __func__); + return ret; + } + rx_priv->dev_up = true; + rx_priv->rx0_gain_val = 0; + rx_priv->rx1_gain_val = 0; + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF2 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF3 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF4 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF5 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF6 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "AUX_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "PCM_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC1_INP"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC2_INP"); + snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC3_INP"); + snd_soc_dapm_sync(dapm); + + for (i = 0; i < ARRAY_SIZE(lpass_cdc_rx_macro_reg_init); i++) + snd_soc_component_update_bits(component, + lpass_cdc_rx_macro_reg_init[i].reg, + lpass_cdc_rx_macro_reg_init[i].mask, + lpass_cdc_rx_macro_reg_init[i].val); + + rx_priv->component = component; +#ifdef CONFIG_BOLERO_VER_2P1 + lpass_cdc_rx_macro_init_bcl_pmic_reg(component); +#endif + + return 0; +} + +static int lpass_cdc_rx_macro_deinit(struct snd_soc_component *component) +{ + struct device *rx_dev = NULL; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + + if (!lpass_cdc_rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + rx_priv->component = NULL; + + return 0; +} + +static void lpass_cdc_rx_macro_add_child_devices(struct work_struct *work) +{ + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + struct platform_device *pdev = NULL; + struct device_node *node = NULL; + struct rx_swr_ctrl_data *swr_ctrl_data = NULL, *temp = NULL; + int ret = 0; + u16 count = 0, ctrl_num = 0; + struct rx_swr_ctrl_platform_data *platdata = NULL; + char plat_dev_name[RX_SWR_STRING_LEN] = ""; + bool rx_swr_master_node = false; + + rx_priv = container_of(work, struct lpass_cdc_rx_macro_priv, + lpass_cdc_rx_macro_add_child_devices_work); + if (!rx_priv) { + pr_err("%s: Memory for rx_priv does not exist\n", + __func__); + return; + } + + if (!rx_priv->dev) { + pr_err("%s: RX device does not exist\n", __func__); + return; + } + + if(!rx_priv->dev->of_node) { + dev_err(rx_priv->dev, + "%s: DT node for RX dev does not exist\n", __func__); + return; + } + + platdata = &rx_priv->swr_plat_data; + rx_priv->child_count = 0; + + for_each_available_child_of_node(rx_priv->dev->of_node, node) { + rx_swr_master_node = false; + if (strnstr(node->name, "rx_swr_master", + strlen("rx_swr_master")) != NULL) + rx_swr_master_node = true; + + if(rx_swr_master_node) + strlcpy(plat_dev_name, "rx_swr_ctrl", + (RX_SWR_STRING_LEN - 1)); + else + strlcpy(plat_dev_name, node->name, + (RX_SWR_STRING_LEN - 1)); + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(rx_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = rx_priv->dev; + pdev->dev.of_node = node; + + if (rx_swr_master_node) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct rx_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].rx_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + rx_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (rx_priv->child_count < LPASS_CDC_RX_MACRO_CHILD_DEVICES_MAX) + rx_priv->pdev_child_devices[ + rx_priv->child_count++] = pdev; + else + goto err; + } + return; +fail_pdev_add: + for (count = 0; count < rx_priv->child_count; count++) + platform_device_put(rx_priv->pdev_child_devices[count]); +err: + return; +} + +static void lpass_cdc_rx_macro_init_ops(struct macro_ops *ops, char __iomem *rx_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->init = lpass_cdc_rx_macro_init; + ops->exit = lpass_cdc_rx_macro_deinit; + ops->io_base = rx_io_base; + ops->dai_ptr = lpass_cdc_rx_macro_dai; + ops->num_dais = ARRAY_SIZE(lpass_cdc_rx_macro_dai); + ops->event_handler = lpass_cdc_rx_macro_event_handler; + ops->set_port_map = lpass_cdc_rx_macro_set_port_map; +} + +static int lpass_cdc_rx_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops = {0}; + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + u32 rx_base_addr = 0, muxsel = 0; + char __iomem *rx_io_base = NULL, *muxsel_io = NULL; + int ret = 0; +#ifdef CONFIG_BOLERO_VER_2P1 + u8 bcl_pmic_params[3]; +#endif + u32 default_clk_id = 0; +#ifdef CONFIG_BOLERO_VER_2P6 + struct clk *hifi_fir_clk = NULL; +#endif + u32 is_used_rx_swr_gpio = 1; + const char *is_used_rx_swr_gpio_dt = "qcom,is-used-swr-gpio"; + + if (!lpass_cdc_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + + rx_priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_rx_macro_priv), + GFP_KERNEL); + if (!rx_priv) + return -ENOMEM; + + rx_priv->pre_dev_up = true; + rx_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &rx_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, "qcom,rx_mclk_mode_muxsel", + &muxsel); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id", + &default_clk_id); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,default-clk-id"); + default_clk_id = RX_CORE_CLK; + } + if (of_find_property(pdev->dev.of_node, is_used_rx_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_rx_swr_gpio_dt, + &is_used_rx_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_rx_swr_gpio_dt); + is_used_rx_swr_gpio = 1; + } + } + rx_priv->rx_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,rx-swr-gpios", 0); + if (!rx_priv->rx_swr_gpio_p && is_used_rx_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if (msm_cdc_pinctrl_get_state(rx_priv->rx_swr_gpio_p) < 0 && + is_used_rx_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + msm_cdc_pinctrl_set_wakeup_capable( + rx_priv->rx_swr_gpio_p, false); + + rx_io_base = devm_ioremap(&pdev->dev, rx_base_addr, + LPASS_CDC_RX_MACRO_MAX_OFFSET); + if (!rx_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -ENOMEM; + } + rx_priv->rx_io_base = rx_io_base; + muxsel_io = devm_ioremap(&pdev->dev, muxsel, 0x4); + if (!muxsel_io) { + dev_err(&pdev->dev, "%s: ioremap failed for muxsel\n", + __func__); + return -ENOMEM; + } + rx_priv->rx_mclk_mode_muxsel = muxsel_io; + rx_priv->reset_swr = true; + INIT_WORK(&rx_priv->lpass_cdc_rx_macro_add_child_devices_work, + lpass_cdc_rx_macro_add_child_devices); + rx_priv->swr_plat_data.handle = (void *) rx_priv; + rx_priv->swr_plat_data.read = NULL; + rx_priv->swr_plat_data.write = NULL; + rx_priv->swr_plat_data.bulk_write = NULL; + rx_priv->swr_plat_data.clk = rx_swrm_clock; + rx_priv->swr_plat_data.core_vote = lpass_cdc_rx_macro_core_vote; + rx_priv->swr_plat_data.handle_irq = NULL; + +#ifdef CONFIG_BOLERO_VER_2P1 + ret = of_property_read_u8_array(pdev->dev.of_node, + "qcom,rx-bcl-pmic-params", bcl_pmic_params, + sizeof(bcl_pmic_params)); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,rx-bcl-pmic-params"); + } else { + rx_priv->bcl_pmic_params.id = bcl_pmic_params[0]; + rx_priv->bcl_pmic_params.sid = bcl_pmic_params[1]; + rx_priv->bcl_pmic_params.ppid = bcl_pmic_params[2]; + } +#endif + + rx_priv->clk_id = default_clk_id; + rx_priv->default_clk_id = default_clk_id; + ops.clk_id_req = rx_priv->clk_id; + ops.default_clk_id = default_clk_id; + +#ifdef CONFIG_BOLERO_VER_2P6 + hifi_fir_clk = devm_clk_get(&pdev->dev, "rx_mclk2_2x_clk"); + if (IS_ERR(hifi_fir_clk)) { + ret = PTR_ERR(hifi_fir_clk); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "rx_mclk2_2x_clk", ret); + hifi_fir_clk = NULL; + } + rx_priv->hifi_fir_clk = hifi_fir_clk; +#endif + + rx_priv->is_aux_hpf_on = 1; + + dev_set_drvdata(&pdev->dev, rx_priv); + mutex_init(&rx_priv->mclk_lock); + mutex_init(&rx_priv->swr_clk_lock); + lpass_cdc_rx_macro_init_ops(&ops, rx_io_base); + + ret = lpass_cdc_register_macro(&pdev->dev, RX_MACRO, &ops); + if (ret) { + dev_err(&pdev->dev, + "%s: register macro failed\n", __func__); + goto err_reg_macro; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + schedule_work(&rx_priv->lpass_cdc_rx_macro_add_child_devices_work); + return 0; + +err_reg_macro: + mutex_destroy(&rx_priv->mclk_lock); + mutex_destroy(&rx_priv->swr_clk_lock); + return ret; +} + +static int lpass_cdc_rx_macro_remove(struct platform_device *pdev) +{ + struct lpass_cdc_rx_macro_priv *rx_priv = NULL; + u16 count = 0; + + rx_priv = dev_get_drvdata(&pdev->dev); + + if (!rx_priv) + return -EINVAL; + + for (count = 0; count < rx_priv->child_count && + count < LPASS_CDC_RX_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister(rx_priv->pdev_child_devices[count]); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + lpass_cdc_unregister_macro(&pdev->dev, RX_MACRO); + mutex_destroy(&rx_priv->mclk_lock); + mutex_destroy(&rx_priv->swr_clk_lock); + kfree(rx_priv->swr_ctrl_data); + return 0; +} + +static const struct of_device_id lpass_cdc_rx_macro_dt_match[] = { + {.compatible = "qcom,lpass-cdc-rx-macro"}, + {} +}; + +static const struct dev_pm_ops lpass_cdc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + lpass_cdc_runtime_suspend, + lpass_cdc_runtime_resume, + NULL + ) +}; + +static struct platform_driver lpass_cdc_rx_macro_driver = { + .driver = { + .name = "lpass_cdc_rx_macro", + .owner = THIS_MODULE, + .pm = &lpass_cdc_dev_pm_ops, + .of_match_table = lpass_cdc_rx_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_cdc_rx_macro_probe, + .remove = lpass_cdc_rx_macro_remove, +}; + +module_platform_driver(lpass_cdc_rx_macro_driver); + +MODULE_DESCRIPTION("RX macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-tables.c new file mode 100644 index 0000000000..4a20c6632a --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-tables.c @@ -0,0 +1,1245 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "lpass-cdc.h" +#include "internal.h" + +u8 lpass_cdc_tx_reg_access[LPASS_CDC_TX_MACRO_MAX] = { + [LPASS_CDC_REG(LPASS_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_ANC_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_SWR_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_FREQ_MCLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_I2S_CLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_I2S_RESET)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_SWR_MIC2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_SWR_MIC3_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_SWR_MIC4_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_SWR_MIC5_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_SWR_MIC0_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_TOP_CSR_SWR_MIC1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_CLK_RESET_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_MODE_1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_MODE_2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_FF_SHIFT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_FB_SHIFT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_LPF_FF_A_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_LPF_FF_B_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_LPF_FB_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_SMLPF_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_DCFLT_SHIFT_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_IIR_ADAPT_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_IIR_COEFF_1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_IIR_COEFF_2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_FF_A_GAIN_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_FF_B_GAIN_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX_ANC0_FB_GAIN_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX0_TX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX1_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX2_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX3_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX4_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX5_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX6_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_TX7_TX_PATH_SEC6)] = RD_WR_REG, +}; + +u8 lpass_cdc_rx_reg_access[LPASS_CDC_RX_MACRO_MAX] = { + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_TOP_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_TOP_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_SWR_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DEBUG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DEBUG_BUS)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DEBUG_EN0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DEBUG_EN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DEBUG_EN2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHL_COMP_WR_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHL_COMP_WR_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHL_COMP_LUT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHL_COMP_RD_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHL_COMP_RD_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHR_COMP_WR_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHR_COMP_WR_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHR_COMP_LUT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHR_COMP_RD_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_HPHR_COMP_RD_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG2)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD0_DEBUG_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG2)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_DSD1_DEBUG_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_RX_I2S_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_TX_I2S2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_I2S_CLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_I2S_RESET)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_TOP_I2S_MUX)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLK_RST_CTRL_DSD_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLK_RST_CTRL_ASRC_SHARE_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SOFTCLIP_CRC)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SOFTCLIP_SOFTCLIP_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_INT0_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_INT0_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_INT1_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_INT1_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_INT2_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_INT2_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_MIX_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_RX_MIX_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_CRC)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_DLY_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_DECAY_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_HPH_V_PA)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_EAR_V_PA)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_HPH_V_HD)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_EAR_V_HD)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_K1_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_K1_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_K2_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_K2_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_IDLE_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_IDLE_HPH)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_IDLE_EAR)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_TEST0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_TEST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_OVR_VREF)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_CLSG_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_CLSG_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CLSH_CLSG_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_ADC_CAL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_ADC_CAL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_ADC_CAL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_PK_EST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_PK_EST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_PK_EST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_RF_PROC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_RF_PROC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_TAC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_TAC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_TAC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_TAC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DEBUG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_GAIN_UPD_MON)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_GAIN_MON_VAL)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BAN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_ATTN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_ATTN2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_ATTN3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_CLR_COMMIT)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_PIN1_MASK0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_PIN1_STATUS0)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_PIN1_CLEAR0)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_PIN2_MASK0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_PIN2_STATUS0)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_PIN2_CLEAR0)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_LEVEL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_BYPASS0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_INTR_CTRL_SET0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_MIX_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_VOL_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_DSM_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_PATH_DSM_DATA6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_MIX_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_VOL_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_DSM_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_PATH_DSM_DATA6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_MIX_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_VOL_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX2_RX_PATH_DSM_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IDLE_DETECT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IDLE_DETECT_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IDLE_DETECT_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IDLE_DETECT_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IDLE_DETECT_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = + RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] = + RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_IIR1_IIR_COEF_B2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR0_MIX_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_IIR_INP_MUX_IIR1_MIX_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_REF_HQ0_EC_REF_HQ_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_REF_HQ1_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_REF_HQ1_EC_REF_HQ_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_REF_HQ2_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_REF_HQ2_EC_REF_HQ_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_CLK_RST_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_FIFO_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC0_STATUS_FIFO)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_CLK_RST_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_FIFO_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC1_STATUS_FIFO)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_CLK_RST_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_FIFO_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_STATUS_FMIN_CNTR_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_STATUS_FMAX_CNTR_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_EC_ASRC2_STATUS_FIFO)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD0_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD0_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD0_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD0_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD1_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD1_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD1_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_DSD1_CFG2)] = RD_WR_REG, +#ifdef CONFIG_BOLERO_VER_2P6 + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_ADDR)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX0_RX_FIR_COEFF_WDATA7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_ADDR)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_RX1_RX_FIR_COEFF_WDATA7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CTL3)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_CFG8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_TEST4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST2)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST3)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST4)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_CB_DECODE_CB_DECODE_ST5)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_ADC_CAL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_PK_EST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_RF_PROC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_RF_PROC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_TAC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_DEBUG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_UPD_MON)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_GAIN_MON_VAL)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BAN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_VBAT_TEMP_VBAT_BCL_ATTN3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL17)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL18)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER0_CTL19)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL17)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL18)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_COMPANDER1_CTL19)] = RD_WR_REG, +#else + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DECODE_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DECODE_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DECODE_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DECODE_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DECODE_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DECODE_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_RX_BCL_VBAT_DECODE_ST)] = RD_REG, +#endif +}; + +u8 lpass_cdc_va_reg_access[LPASS_CDC_VA_MACRO_MAX] = { + [LPASS_CDC_REG(LPASS_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_DMIC2_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_DMIC3_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_DMIC_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_VAD_MUX)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_DEBUG_BUS)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_DEBUG_EN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_I2S_CLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_I2S_RESET)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_CORE_ID_0)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_CORE_ID_1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_CORE_ID_2)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_SWR_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TOP_CSR_SEQ_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX0_TX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX1_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX2_TX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_SEC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_VA_TX3_TX_PATH_SEC6)] = RD_WR_REG, +}; + +u8 lpass_cdc_wsa_reg_access[LPASS_CDC_WSA_MACRO_MAX] = { + [LPASS_CDC_REG(LPASS_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_TOP_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_TOP_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_FREQ_MCLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_DEBUG_BUS_SEL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_DEBUG_EN0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_DEBUG_EN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_DEBUG_DSM_LB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_RX_I2S_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_TX_I2S_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_I2S_CLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_I2S_RESET)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_FS_UNGATE)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_GRP_SEL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP7_WR_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP7_WR_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP7_LUT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP7_RD_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP7_RD_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP8_WR_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP8_WR_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP8_LUT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP8_RD_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SPKR_COMP8_RD_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_FS_UNGATE2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TOP_SEQ_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX_INP_MUX_RX_EC_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_ADC_CAL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_PK_EST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_RF_PROC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_RF_PROC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_TAC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_DEBUG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_UPD_MON)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BAN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_ATTN3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_CLR_COMMIT)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_PIN1_MASK0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_PIN1_STATUS0)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_PIN1_CLEAR0)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_PIN2_MASK0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_PIN2_STATUS0)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_PIN2_CLEAR0)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_LEVEL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_BYPASS0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_INTR_CTRL_SET0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_MIX_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_VOL_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX0_RX_PATH_DSMDEM_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_MIX_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_VOL_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_RX1_RX_PATH_DSMDEM_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST0_BOOST_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST0_BOOST_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST0_BOOST_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST0_BOOST_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST1_BOOST_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST1_BOOST_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST1_BOOST_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_BOOST1_BOOST_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL17)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL18)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER0_CTL19)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL17)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL18)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_COMPANDER1_CTL19)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_SOFTCLIP0_CRC)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_SOFTCLIP1_CRC)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_IDLE_DETECT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_IDLE_DETECT_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_IDLE_DETECT_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_IDLE_DETECT_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_IDLE_DETECT_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL3)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CFG8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_TEST4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST2)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST3)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST4)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_CB_DECODE_CB_DECODE_ST5)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_ADC_CAL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_PK_EST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_RF_PROC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_RF_PROC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_TAC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_DEBUG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_UPD_MON)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_GAIN_MON_VAL)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BAN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_VBAT_TEMP_VBAT_BCL_ATTN3)] = RD_WR_REG, + /* lpass 2.6 new registers */ + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_LA_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG17)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG7)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG8)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_LA_CFG_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG1_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG2_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG3_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG4_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG5_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG6_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG7_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG8_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG9_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG10_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG11_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG12_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG13_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG14_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG15_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG16_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG0_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG1_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG2_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG5_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_ILIM_CFG6_1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG18)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG18_1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG19)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG20)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG21)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG22)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA_PBR_CFG23)] = RD_WR_REG, +}; + +u8 lpass_cdc_wsa2_reg_access[LPASS_CDC_WSA2_MACRO_MAX] = { + [LPASS_CDC_REG(LPASS_CDC_WSA2_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_TOP_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_TOP_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_FREQ_MCLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_DEBUG_BUS_SEL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_DEBUG_EN0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_DEBUG_EN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_DEBUG_DSM_LB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_RX_I2S_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_TX_I2S_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_I2S_CLK)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_I2S_RESET)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_FS_UNGATE)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_GRP_SEL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP7_WR_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP7_WR_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP7_LUT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP7_RD_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP7_RD_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP8_WR_LSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP8_WR_MSB)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP8_LUT)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP8_RD_LSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SPKR_COMP8_RD_MSB)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_FS_UNGATE2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TOP_SEQ_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX_INP_MUX_RX_EC_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX_INP_MUX_SOFTCLIP_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_ADC_CAL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_PK_EST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_RF_PROC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_RF_PROC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_TAC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_DEBUG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_UPD_MON)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_GAIN_MON_VAL)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BAN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_ATTN3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_CLR_COMMIT)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_PIN1_MASK0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_PIN1_STATUS0)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_PIN1_CLEAR0)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_PIN2_MASK0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_PIN2_STATUS0)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_PIN2_CLEAR0)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_LEVEL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_BYPASS0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_INTR_CTRL_SET0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_VOL_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX0_RX_PATH_DSMDEM_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_VOL_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_VOL_MIX_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_SEC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_SEC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_SEC5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_SEC6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_SEC7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_MIX_SEC0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_MIX_SEC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_RX1_RX_PATH_DSMDEM_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST0_BOOST_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST0_BOOST_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST0_BOOST_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST0_BOOST_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST1_BOOST_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST1_BOOST_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST1_BOOST_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_BOOST1_BOOST_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL17)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL18)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER0_CTL19)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL17)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL18)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_COMPANDER1_CTL19)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_SOFTCLIP0_CRC)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_SOFTCLIP0_SOFTCLIP_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_SOFTCLIP1_CRC)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_SOFTCLIP1_SOFTCLIP_CTRL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_EC_HQ1_EC_REF_HQ_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_EC_HQ1_EC_REF_HQ_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_IDLE_DETECT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_IDLE_DETECT_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_IDLE_DETECT_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_IDLE_DETECT_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_IDLE_DETECT_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CFG8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_TEST4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST2)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST3)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST4)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_ST5)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_ADC_CAL3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_PK_EST3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_RF_PROC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_RF_PROC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_TAC4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_DEBUG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_UPD_MON)] = WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_GAIN_MON_VAL)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BAN)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_GAIN_UPD9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_VBAT_TEMP_VBAT_BCL_ATTN3)] = RD_WR_REG, + /* lpass 2.6 new registers */ + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_PATH_CTL)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_LA_CFG)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG6)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG7)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG8)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG10)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG11)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG12)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG13)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG14)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG15)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG16)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG17)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG0)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG2)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG3)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG4)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG5)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG6)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG7)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG8)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_LA_CFG_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG1_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG2_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG3_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG4_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG5_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG6_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG7_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG8_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG9_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG10_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG11_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG12_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG13_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG14_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG15_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG16_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG0_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG1_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG2_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG5_1)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG9)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_ILIM_CFG6_1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG18)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG18_1)] = RD_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG19)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG20)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG21)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG22)] = RD_WR_REG, + [LPASS_CDC_REG(LPASS_CDC_WSA2_PBR_CFG23)] = RD_WR_REG, + +}; + +u8 *lpass_cdc_reg_access[MAX_MACRO] = { + [TX_MACRO] = lpass_cdc_tx_reg_access, + [RX_MACRO] = lpass_cdc_rx_reg_access, + [WSA_MACRO] = lpass_cdc_wsa_reg_access, + [VA_MACRO] = lpass_cdc_va_reg_access, + [WSA2_MACRO] = lpass_cdc_wsa2_reg_access, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-tx-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-tx-macro.c new file mode 100644 index 0000000000..b2c3ad2486 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-tx-macro.c @@ -0,0 +1,2175 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpass-cdc.h" +#include "lpass-cdc-registers.h" +#include "lpass-cdc-clk-rsc.h" + +#define AUTO_SUSPEND_DELAY 50 /* delay in msec */ +#define LPASS_CDC_TX_MACRO_MAX_OFFSET 0x1000 + +#define NUM_DECIMATORS 8 + +#define LPASS_CDC_TX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define LPASS_CDC_TX_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define LPASS_CDC_TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED 0 +#define LPASS_CDC_TX_MACRO_MCLK_FREQ 9600000 +#define LPASS_CDC_TX_MACRO_TX_PATH_OFFSET \ + (LPASS_CDC_TX1_TX_PATH_CTL - LPASS_CDC_TX0_TX_PATH_CTL) +#define LPASS_CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK 0xF +#define LPASS_CDC_TX_MACRO_ADC_MUX_CFG_OFFSET 0x8 +#define LPASS_CDC_TX_MACRO_ADC_MODE_CFG0_SHIFT 1 + +#define LPASS_CDC_TX_MACRO_DMIC_UNMUTE_DELAY_MS 40 +#define LPASS_CDC_TX_MACRO_AMIC_UNMUTE_DELAY_MS 100 +#define LPASS_CDC_TX_MACRO_DMIC_HPF_DELAY_MS 300 +#define LPASS_CDC_TX_MACRO_AMIC_HPF_DELAY_MS 300 + +static int tx_unmute_delay = LPASS_CDC_TX_MACRO_DMIC_UNMUTE_DELAY_MS; +module_param(tx_unmute_delay, int, 0664); +MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path"); + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +static int lpass_cdc_tx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +static int lpass_cdc_tx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); + +#define LPASS_CDC_TX_MACRO_SWR_STRING_LEN 80 +#define LPASS_CDC_TX_MACRO_CHILD_DEVICES_MAX 3 + +enum { + LPASS_CDC_TX_MACRO_AIF_INVALID = 0, + LPASS_CDC_TX_MACRO_AIF1_CAP, + LPASS_CDC_TX_MACRO_AIF2_CAP, + LPASS_CDC_TX_MACRO_AIF3_CAP, + LPASS_CDC_TX_MACRO_MAX_DAIS +}; + +enum { + LPASS_CDC_TX_MACRO_DEC0, + LPASS_CDC_TX_MACRO_DEC1, + LPASS_CDC_TX_MACRO_DEC2, + LPASS_CDC_TX_MACRO_DEC3, + LPASS_CDC_TX_MACRO_DEC4, + LPASS_CDC_TX_MACRO_DEC5, + LPASS_CDC_TX_MACRO_DEC6, + LPASS_CDC_TX_MACRO_DEC7, + LPASS_CDC_TX_MACRO_DEC_MAX, +}; + +enum { + LPASS_CDC_TX_MACRO_CLK_DIV_2, + LPASS_CDC_TX_MACRO_CLK_DIV_3, + LPASS_CDC_TX_MACRO_CLK_DIV_4, + LPASS_CDC_TX_MACRO_CLK_DIV_6, + LPASS_CDC_TX_MACRO_CLK_DIV_8, + LPASS_CDC_TX_MACRO_CLK_DIV_16, +}; + +enum { + MSM_DMIC, + SWR_MIC, + ANC_FB_TUNE1 +}; + +enum { + TX_MCLK, + VA_MCLK, +}; + +struct lpass_cdc_tx_macro_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +struct tx_mute_work { + struct lpass_cdc_tx_macro_priv *tx_priv; + u32 decimator; + struct delayed_work dwork; +}; + +struct hpf_work { + struct lpass_cdc_tx_macro_priv *tx_priv; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +struct lpass_cdc_tx_macro_priv { + struct device *dev; + bool dec_active[NUM_DECIMATORS]; + int tx_mclk_users; + bool dapm_mclk_enable; + struct mutex mclk_lock; + struct mutex wlock; + struct snd_soc_component *component; + struct hpf_work tx_hpf_work[NUM_DECIMATORS]; + struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS]; + u16 dmic_clk_div; + u32 version; + unsigned long active_ch_mask[LPASS_CDC_TX_MACRO_MAX_DAIS]; + unsigned long active_ch_cnt[LPASS_CDC_TX_MACRO_MAX_DAIS]; + char __iomem *tx_io_base; + struct platform_device *pdev_child_devices + [LPASS_CDC_TX_MACRO_CHILD_DEVICES_MAX]; + int child_count; + bool bcs_enable; + int dec_mode[NUM_DECIMATORS]; + int bcs_ch; + bool bcs_clk_en; + bool hs_slow_insert_complete; + int pcm_rate[NUM_DECIMATORS]; + bool swr_dmic_enable; + int wlock_holders; +}; + +static int lpass_cdc_tx_macro_wake_enable(struct lpass_cdc_tx_macro_priv *tx_priv, + bool wake_enable) +{ + int ret = 0; + + mutex_lock(&tx_priv->wlock); + if (wake_enable) { + if (tx_priv->wlock_holders++ == 0) { + dev_dbg(tx_priv->dev, "%s: pm wake\n", __func__); + pm_stay_awake(tx_priv->dev); + } + } else { + if (--tx_priv->wlock_holders == 0) { + dev_dbg(tx_priv->dev, "%s: pm release\n", __func__); + pm_relax(tx_priv->dev); + } + if (tx_priv->wlock_holders < 0) + tx_priv->wlock_holders = 0; + } + mutex_unlock(&tx_priv->wlock); + return ret; +} + +static bool lpass_cdc_tx_macro_get_data(struct snd_soc_component *component, + struct device **tx_dev, + struct lpass_cdc_tx_macro_priv **tx_priv, + const char *func_name) +{ + *tx_dev = lpass_cdc_get_device_ptr(component->dev, TX_MACRO); + if (!(*tx_dev)) { + dev_err_ratelimited(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + + *tx_priv = dev_get_drvdata((*tx_dev)); + if (!(*tx_priv)) { + dev_err_ratelimited(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + + if (!(*tx_priv)->component) { + dev_err_ratelimited(component->dev, + "%s: tx_priv->component not initialized!\n", func_name); + return false; + } + + return true; +} + +static int lpass_cdc_tx_macro_mclk_enable( + struct lpass_cdc_tx_macro_priv *tx_priv, + bool mclk_enable) +{ + struct regmap *regmap = dev_get_regmap(tx_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(tx_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(tx_priv->dev, "%s: mclk_enable = %u,clk_users= %d\n", + __func__, mclk_enable, tx_priv->tx_mclk_users); + + mutex_lock(&tx_priv->mclk_lock); + if (mclk_enable) { + ret = lpass_cdc_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + if (ret < 0) { + dev_err_ratelimited(tx_priv->dev, + "%s: request clock enable failed\n", + __func__); + goto exit; + } + lpass_cdc_clk_rsc_fs_gen_request(tx_priv->dev, + true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + TX_START_OFFSET, + TX_MAX_OFFSET); + if (tx_priv->tx_mclk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + regmap_update_bits(regmap, + LPASS_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + tx_priv->tx_mclk_users++; + } else { + if (tx_priv->tx_mclk_users <= 0) { + dev_err_ratelimited(tx_priv->dev, "%s: clock already disabled\n", + __func__); + tx_priv->tx_mclk_users = 0; + goto exit; + } + tx_priv->tx_mclk_users--; + if (tx_priv->tx_mclk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + } + + lpass_cdc_clk_rsc_fs_gen_request(tx_priv->dev, + false); + lpass_cdc_clk_rsc_request_clock(tx_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + } +exit: + mutex_unlock(&tx_priv->mclk_lock); + return ret; +} + +static int __lpass_cdc_tx_macro_mclk_enable(struct snd_soc_component *component, + bool enable) +{ + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + return lpass_cdc_tx_macro_mclk_enable(tx_priv, enable); +} + +static int lpass_cdc_tx_macro_mclk_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); + int ret = 0; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + dev_dbg(tx_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = lpass_cdc_tx_macro_mclk_enable(tx_priv, 1); + if (ret) + tx_priv->dapm_mclk_enable = false; + else + tx_priv->dapm_mclk_enable = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (tx_priv->dapm_mclk_enable) + ret = lpass_cdc_tx_macro_mclk_enable(tx_priv, 0); + break; + default: + dev_err_ratelimited(tx_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int lpass_cdc_tx_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + int ret = 0; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + switch (event) { + case LPASS_CDC_MACRO_EVT_SSR_DOWN: + if ((!pm_runtime_enabled(tx_dev) || + !pm_runtime_suspended(tx_dev))) { + ret = lpass_cdc_runtime_suspend(tx_dev); + if (!ret) { + pm_runtime_disable(tx_dev); + pm_runtime_set_suspended(tx_dev); + pm_runtime_enable(tx_dev); + } + } + break; + case LPASS_CDC_MACRO_EVT_SSR_UP: + break; + case LPASS_CDC_MACRO_EVT_CLK_RESET: + lpass_cdc_rsc_clk_reset(tx_dev, TX_CORE_CLK); + break; + case LPASS_CDC_MACRO_EVT_BCS_CLK_OFF: + if (tx_priv->bcs_clk_en) + snd_soc_component_update_bits(component, + LPASS_CDC_TX0_TX_PATH_SEC7, 0x40, data << 6); + if (data) + tx_priv->hs_slow_insert_complete = true; + else + tx_priv->hs_slow_insert_complete = false; + break; + default: + pr_debug("%s Invalid Event\n", __func__); + break; + } + return 0; +} + +static bool is_amic_enabled(struct snd_soc_component *component, int decimator) +{ + u16 adc_mux_reg = 0; + bool ret = false; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return ret; + + adc_mux_reg = LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + LPASS_CDC_TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + + if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) { + if (!tx_priv->swr_dmic_enable) + return true; + } + + return ret; +} + +static void lpass_cdc_tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work = NULL; + struct hpf_work *hpf_work = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct snd_soc_component *component = NULL; + u16 dec_cfg_reg = 0, hpf_gate_reg = 0; + u8 hpf_cut_off_freq = 0; + u16 adc_reg = 0, adc_n = 0; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + tx_priv = hpf_work->tx_priv; + component = tx_priv->component; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = LPASS_CDC_TX0_TX_PATH_CFG0 + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + hpf_gate_reg = LPASS_CDC_TX0_TX_PATH_SEC2 + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + + dev_dbg(component->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + if (is_amic_enabled(component, hpf_work->decimator)) { + adc_reg = LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + LPASS_CDC_TX_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator; + adc_n = snd_soc_component_read(component, adc_reg) & + LPASS_CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK; + /* analog mic clear TX hold */ + lpass_cdc_clear_amic_tx_hold(component->dev, adc_n); + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x02); + /* Add delay between toggle hpf gate based on sample rate */ + switch (tx_priv->pcm_rate[hpf_work->decimator]) { + case 0: + usleep_range(125, 130); + break; + case 1: + usleep_range(62, 65); + break; + case 3: + usleep_range(31, 32); + break; + case 4: + usleep_range(20, 21); + break; + case 5: + usleep_range(10, 11); + break; + case 6: + usleep_range(5, 6); + break; + default: + usleep_range(125, 130); + } + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x01); + } else { + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x02); + /* Minimum 1 clk cycle delay is required as per HW spec */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x00); + } + lpass_cdc_tx_macro_wake_enable(tx_priv, 0); +} + +static void lpass_cdc_tx_macro_mute_update_callback(struct work_struct *work) +{ + struct tx_mute_work *tx_mute_dwork = NULL; + struct snd_soc_component *component = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct delayed_work *delayed_work = NULL; + u16 tx_vol_ctl_reg = 0; + u8 decimator = 0; + + delayed_work = to_delayed_work(work); + tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork); + tx_priv = tx_mute_dwork->tx_priv; + component = tx_priv->component; + decimator = tx_mute_dwork->decimator; + + tx_vol_ctl_reg = + LPASS_CDC_TX0_TX_PATH_CTL + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * decimator; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, 0x10, 0x00); + dev_dbg(tx_priv->dev, "%s: decimator %u unmute\n", + __func__, decimator); + lpass_cdc_tx_macro_wake_enable(tx_priv, 0); +} + +static int lpass_cdc_tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val = 0; + u16 mic_sel_reg = 0; + u16 dmic_clk_reg = 0; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0: + mic_sel_reg = LPASS_CDC_TX0_TX_PATH_CFG0; + break; + case LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG0: + mic_sel_reg = LPASS_CDC_TX1_TX_PATH_CFG0; + break; + case LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG0: + mic_sel_reg = LPASS_CDC_TX2_TX_PATH_CFG0; + break; + case LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG0: + mic_sel_reg = LPASS_CDC_TX3_TX_PATH_CFG0; + break; + case LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG0: + mic_sel_reg = LPASS_CDC_TX4_TX_PATH_CFG0; + break; + case LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG0: + mic_sel_reg = LPASS_CDC_TX5_TX_PATH_CFG0; + break; + case LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG0: + mic_sel_reg = LPASS_CDC_TX6_TX_PATH_CFG0; + break; + case LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG0: + mic_sel_reg = LPASS_CDC_TX7_TX_PATH_CFG0; + break; + default: + dev_err_ratelimited(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + if (strnstr(widget->name, "SMIC", strlen(widget->name))) { + if (val != 0) { + if (!tx_priv->swr_dmic_enable) { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x0 << 7); + } else { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x1 << 7); + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + dmic_clk_reg = + LPASS_CDC_TX_TOP_CSR_SWR_MIC0_CTL + + ((val - 5)/2) * 4; + snd_soc_component_update_bits(component, + dmic_clk_reg, + 0x0E, tx_priv->dmic_clk_div << 0x1); + } + } + } else { + /* DMIC selected */ + if (val != 0) + snd_soc_component_update_bits(component, mic_sel_reg, + 1 << 7, 1 << 7); + } + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int lpass_cdc_tx_macro_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (test_bit(dec_id, &tx_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + return 0; +} + +static int lpass_cdc_tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (enable) { + if (test_bit(dec_id, &tx_priv->active_ch_mask[dai_id])) { + dev_err(component->dev, "%s: channel is already enabled, dec_id = %d, dai_id = %d\n", + __func__, dec_id, dai_id); + } else { + set_bit(dec_id, &tx_priv->active_ch_mask[dai_id]); + tx_priv->active_ch_cnt[dai_id]++; + } + } else { + if (!test_bit(dec_id, &tx_priv->active_ch_mask[dai_id])) { + dev_err(component->dev, "%s: channel is already disabled, dec_id = %d, dai_id = %d\n", + __func__, dec_id, dai_id); + } else { + tx_priv->active_ch_cnt[dai_id]--; + clear_bit(dec_id, &tx_priv->active_ch_mask[dai_id]); + } + } + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static inline int lpass_cdc_tx_macro_path_get(const char *wname, + unsigned int *path_num) +{ + int ret = 0; + char *widget_name = NULL; + char *w_name = NULL; + char *path_num_char = NULL; + char *path_name = NULL; + + widget_name = kstrndup(wname, 10, GFP_KERNEL); + if (!widget_name) + return -EINVAL; + + w_name = widget_name; + + path_name = strsep(&widget_name, " "); + if (!path_name) { + pr_err_ratelimited("%s: Invalid widget name = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto err; + } + path_num_char = strpbrk(path_name, "01234567"); + if (!path_num_char) { + pr_err_ratelimited("%s: tx path index not found\n", + __func__); + ret = -EINVAL; + goto err; + } + ret = kstrtouint(path_num_char, 10, path_num); + if (ret < 0) + pr_err_ratelimited("%s: Invalid tx path = %s\n", + __func__, w_name); + +err: + kfree(w_name); + return ret; +} + +static int lpass_cdc_tx_macro_dec_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int ret = 0; + int path = 0; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ret = lpass_cdc_tx_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = tx_priv->dec_mode[path]; + + return 0; +} + +static int lpass_cdc_tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = ucontrol->value.integer.value[0]; + int ret = 0; + int path = 0; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ret = lpass_cdc_tx_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + tx_priv->dec_mode[path] = value; + + return 0; +} + +static int lpass_cdc_tx_macro_bcs_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ucontrol->value.enumerated.item[0] = tx_priv->bcs_ch; + + return 0; +} + +static int lpass_cdc_tx_macro_bcs_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = ucontrol->value.enumerated.item[0]; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->bcs_ch = value; + + return 0; +} + +static int lpass_cdc_tx_macro_swr_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = tx_priv->swr_dmic_enable; + + return 0; +} + +static int lpass_cdc_tx_macro_swr_dmic_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = ucontrol->value.integer.value[0]; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->swr_dmic_enable = value; + + return 0; +} + +static int lpass_cdc_tx_macro_get_bcs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = tx_priv->bcs_enable; + + return 0; +} + +static int lpass_cdc_tx_macro_set_bcs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = ucontrol->value.integer.value[0]; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->bcs_enable = value; + + return 0; +} + +static const char * const bcs_ch_sel_mux_text[] = { + "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3", + "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7", + "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11", +}; + +static const struct soc_enum bcs_ch_sel_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(bcs_ch_sel_mux_text), + bcs_ch_sel_mux_text); + +static int lpass_cdc_tx_macro_get_bcs_ch_sel(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value = 0; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + value = (snd_soc_component_read(component, + LPASS_CDC_VA_TOP_CSR_SWR_CTRL)) & 0x0F; + + ucontrol->value.integer.value[0] = value; + return 0; +} + +static int lpass_cdc_tx_macro_put_bcs_ch_sel(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + struct device *tx_dev = NULL; + int value; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > ARRAY_SIZE(bcs_ch_sel_mux_text)) + return -EINVAL; + + value = ucontrol->value.integer.value[0]; + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, value); + + return 0; +} + +static int lpass_cdc_tx_macro_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event, u16 adc_mux0_cfg) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + unsigned int dmic = 0; + + dmic = (snd_soc_component_read(component, adc_mux0_cfg) >> 4) - 1; + + dev_dbg(component->dev, "%s: event %d DMIC%d\n", + __func__, event, dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + lpass_cdc_dmic_clk_enable(component, dmic, DMIC_TX, true); + break; + case SND_SOC_DAPM_POST_PMD: + lpass_cdc_dmic_clk_enable(component, dmic, DMIC_TX, false); + break; + } + + return 0; +} + +static int lpass_cdc_tx_macro_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + unsigned int decimator = 0; + u16 tx_vol_ctl_reg = 0; + u16 dec_cfg_reg = 0; + u16 hpf_gate_reg = 0; + u16 tx_gain_ctl_reg = 0; + u16 tx_fs_reg = 0; + u8 hpf_cut_off_freq = 0; + u16 adc_mux_reg = 0; + u16 adc_mux0_reg = 0; + int hpf_delay = LPASS_CDC_TX_MACRO_DMIC_HPF_DELAY_MS; + int unmute_delay = LPASS_CDC_TX_MACRO_DMIC_UNMUTE_DELAY_MS; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + decimator = w->shift; + + dev_dbg(component->dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = LPASS_CDC_TX0_TX_PATH_CTL + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * decimator; + hpf_gate_reg = LPASS_CDC_TX0_TX_PATH_SEC2 + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * decimator; + dec_cfg_reg = LPASS_CDC_TX0_TX_PATH_CFG0 + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * decimator; + tx_gain_ctl_reg = LPASS_CDC_TX0_TX_VOL_CTL + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * decimator; + adc_mux_reg = LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + LPASS_CDC_TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + adc_mux0_reg = LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + LPASS_CDC_TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + tx_fs_reg = LPASS_CDC_TX0_TX_PATH_CTL + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * decimator; + + tx_priv->pcm_rate[decimator] = (snd_soc_component_read(component, + tx_fs_reg) & 0x0F); + + if(!is_amic_enabled(component, decimator)) + lpass_cdc_tx_macro_enable_dmic(w, kcontrol, event, adc_mux0_reg); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + dec_cfg_reg, 0x06, tx_priv->dec_mode[decimator] << + LPASS_CDC_TX_MACRO_ADC_MODE_CFG0_SHIFT); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x20, 0x20); + if (!is_amic_enabled(component, decimator)) { + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x01, 0x00); + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + } + hpf_cut_off_freq = ( + snd_soc_component_read(component, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + + if (is_amic_enabled(component, decimator)) { + hpf_delay = LPASS_CDC_TX_MACRO_AMIC_HPF_DELAY_MS; + unmute_delay = LPASS_CDC_TX_MACRO_AMIC_UNMUTE_DELAY_MS; + } + if (tx_unmute_delay < unmute_delay) + tx_unmute_delay = unmute_delay; + lpass_cdc_tx_macro_wake_enable(tx_priv, 1); + /* schedule work queue to Remove Mute */ + queue_delayed_work(system_freezable_wq, + &tx_priv->tx_mute_dwork[decimator].dwork, + msecs_to_jiffies(tx_unmute_delay)); + if (tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) { + lpass_cdc_tx_macro_wake_enable(tx_priv, 1); + queue_delayed_work(system_freezable_wq, + &tx_priv->tx_hpf_work[decimator].dwork, + msecs_to_jiffies(hpf_delay)); + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x02); + if (!is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x00); + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x01); + /* + * 6ms delay is required as per HW spec + */ + usleep_range(6000, 6010); + } + /* apply gain after decimator is enabled */ + snd_soc_component_write(component, tx_gain_ctl_reg, + snd_soc_component_read(component, + tx_gain_ctl_reg)); + if (tx_priv->bcs_enable) { + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, + tx_priv->bcs_ch); + + snd_soc_component_update_bits(component, dec_cfg_reg, + 0x01, 0x01); + tx_priv->bcs_clk_en = true; + if (tx_priv->hs_slow_insert_complete) + snd_soc_component_update_bits(component, + LPASS_CDC_TX0_TX_PATH_SEC7, 0x40, + 0x40); + } + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x10, 0x10); + if (cancel_delayed_work_sync( + &tx_priv->tx_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits( + component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + if (is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x02); + else + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x03); + + /* + * Minimum 1 clk cycle delay is required + * as per HW spec + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x01); + } + } + lpass_cdc_tx_macro_wake_enable(tx_priv, 0); + cancel_delayed_work_sync( + &tx_priv->tx_mute_dwork[decimator].dwork); + lpass_cdc_tx_macro_wake_enable(tx_priv, 0); + + if (snd_soc_component_read(component, adc_mux_reg) + & SWR_MIC) + snd_soc_component_update_bits(component, + LPASS_CDC_TX_TOP_CSR_SWR_CTRL, + 0x01, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x20, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x00); + snd_soc_component_update_bits(component, + dec_cfg_reg, 0x06, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x00); + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, 0x04); + if (tx_priv->bcs_enable) { + snd_soc_component_update_bits(component, dec_cfg_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_TX0_TX_PATH_SEC7, 0x40, 0x00); + tx_priv->bcs_clk_en = false; + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, + 0x00); + } + break; + } + return 0; +} + +static int lpass_cdc_tx_macro_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return 0; +} + +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, LPASS_CDC_TX0_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, LPASS_CDC_TX1_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec2_enum, LPASS_CDC_TX2_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec3_enum, LPASS_CDC_TX3_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec4_enum, LPASS_CDC_TX4_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec5_enum, LPASS_CDC_TX5_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec6_enum, LPASS_CDC_TX6_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec7_enum, LPASS_CDC_TX7_TX_PATH_CFG0, 5, + cf_text); + +static int lpass_cdc_tx_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int tx_fs_rate = -EINVAL; + struct snd_soc_component *component = dai->component; + u32 decimator = 0; + u32 sample_rate = 0; + u16 tx_fs_reg = 0; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + sample_rate = params_rate(params); + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + } + for_each_set_bit(decimator, &tx_priv->active_ch_mask[dai->id], + LPASS_CDC_TX_MACRO_DEC_MAX) { + if (decimator >= 0) { + tx_fs_reg = LPASS_CDC_TX0_TX_PATH_CTL + + LPASS_CDC_TX_MACRO_TX_PATH_OFFSET * decimator; + dev_dbg(component->dev, "%s: set DEC%u rate to %u\n", + __func__, decimator, sample_rate); + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, tx_fs_rate); + } else { + dev_err_ratelimited(component->dev, + "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int lpass_cdc_tx_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case LPASS_CDC_TX_MACRO_AIF1_CAP: + case LPASS_CDC_TX_MACRO_AIF2_CAP: + case LPASS_CDC_TX_MACRO_AIF3_CAP: + *tx_slot = tx_priv->active_ch_mask[dai->id]; + *tx_num = tx_priv->active_ch_cnt[dai->id]; + break; + default: + dev_err_ratelimited(tx_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static struct snd_soc_dai_ops lpass_cdc_tx_macro_dai_ops = { + .hw_params = lpass_cdc_tx_macro_hw_params, + .get_channel_map = lpass_cdc_tx_macro_get_channel_map, +}; + +static struct snd_soc_dai_driver lpass_cdc_tx_macro_dai[] = { + { + .name = "tx_macro_tx1", + .id = LPASS_CDC_TX_MACRO_AIF1_CAP, + .capture = { + .stream_name = "TX_AIF1 Capture", + .rates = LPASS_CDC_TX_MACRO_RATES, + .formats = LPASS_CDC_TX_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &lpass_cdc_tx_macro_dai_ops, + }, + { + .name = "tx_macro_tx2", + .id = LPASS_CDC_TX_MACRO_AIF2_CAP, + .capture = { + .stream_name = "TX_AIF2 Capture", + .rates = LPASS_CDC_TX_MACRO_RATES, + .formats = LPASS_CDC_TX_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &lpass_cdc_tx_macro_dai_ops, + }, + { + .name = "tx_macro_tx3", + .id = LPASS_CDC_TX_MACRO_AIF3_CAP, + .capture = { + .stream_name = "TX_AIF3 Capture", + .rates = LPASS_CDC_TX_MACRO_RATES, + .formats = LPASS_CDC_TX_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &lpass_cdc_tx_macro_dai_ops, + }, +}; + +#define STRING(name) #name +#define LPASS_CDC_TX_MACRO_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define LPASS_CDC_TX_MACRO_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +static const char * const adc_mux_text[] = { + "MSM_DMIC", "SWR_MIC", "ANC_FB_TUNE1" +}; + +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec0, LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG1, + 0, adc_mux_text); +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec1, LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG1, + 0, adc_mux_text); +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec2, LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG1, + 0, adc_mux_text); +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec3, LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG1, + 0, adc_mux_text); +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec4, LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG1, + 0, adc_mux_text); +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec5, LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG1, + 0, adc_mux_text); +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec6, LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG1, + 0, adc_mux_text); +LPASS_CDC_TX_MACRO_DAPM_ENUM(tx_dec7, LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG1, + 0, adc_mux_text); + + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", + "DMIC4", "DMIC5", "DMIC6", "DMIC7" +}; + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic0, LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic1, LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic2, LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic3, LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic4, LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic5, LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic6, LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_dmic7, LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +static const char * const smic_mux_text[] = { + "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3", + "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7", + "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11" +}; + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic0, LPASS_CDC_TX_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic1, LPASS_CDC_TX_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic2, LPASS_CDC_TX_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic3, LPASS_CDC_TX_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic4, LPASS_CDC_TX_INP_MUX_ADC_MUX4_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic5, LPASS_CDC_TX_INP_MUX_ADC_MUX5_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic6, LPASS_CDC_TX_INP_MUX_ADC_MUX6_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +LPASS_CDC_TX_MACRO_DAPM_ENUM_EXT(tx_smic7, LPASS_CDC_TX_INP_MUX_ADC_MUX7_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_tx_macro_put_dec_enum); + +static const char * const dec_mode_mux_text[] = { + "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF", +}; + +static const struct soc_enum dec_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text); + +static const char * const bcs_ch_enum_text[] = { + "CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8", "CH9", + "CH10", "CH11", +}; + +static const struct soc_enum bcs_ch_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(bcs_ch_enum_text), + bcs_ch_enum_text); + +static const struct snd_kcontrol_new tx_aif1_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC0, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC1, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC2, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC3, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC4, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC5, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC6, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC7, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new tx_aif2_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC0, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC1, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC2, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC3, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC4, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC5, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC6, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC7, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new tx_aif3_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC0, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC1, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC2, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC3, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC4, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC5, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC6, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, LPASS_CDC_TX_MACRO_DEC7, 1, 0, + lpass_cdc_tx_macro_tx_mixer_get, lpass_cdc_tx_macro_tx_mixer_put), +}; + +static const struct snd_soc_dapm_widget lpass_cdc_tx_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0, + SND_SOC_NOPM, LPASS_CDC_TX_MACRO_AIF1_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("TX_AIF2 CAP", "TX_AIF2 Capture", 0, + SND_SOC_NOPM, LPASS_CDC_TX_MACRO_AIF2_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("TX_AIF3 CAP", "TX_AIF3 Capture", 0, + SND_SOC_NOPM, LPASS_CDC_TX_MACRO_AIF3_CAP, 0), + + SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_AIF1_CAP, 0, + tx_aif1_cap_mixer, ARRAY_SIZE(tx_aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_AIF2_CAP, 0, + tx_aif2_cap_mixer, ARRAY_SIZE(tx_aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_AIF3_CAP, 0, + tx_aif3_cap_mixer, ARRAY_SIZE(tx_aif3_cap_mixer)), + + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX0", 0, tx_dmic0), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX1", 0, tx_dmic1), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX2", 0, tx_dmic2), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX3", 0, tx_dmic3), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX4", 0, tx_dmic4), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX5", 0, tx_dmic5), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX6", 0, tx_dmic6), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX DMIC MUX7", 0, tx_dmic7), + + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX4", 0, tx_smic4), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX5", 0, tx_smic5), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX6", 0, tx_smic6), + LPASS_CDC_TX_MACRO_DAPM_MUX("TX SMIC MUX7", 0, tx_smic7), + + SND_SOC_DAPM_SUPPLY("TX MIC BIAS1", SND_SOC_NOPM, 0, 0, + lpass_cdc_tx_macro_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC("TX DMIC0", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("TX DMIC1", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("TX DMIC2", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("TX DMIC3", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("TX DMIC4", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("TX DMIC5", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("TX DMIC6", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("TX DMIC7", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_INPUT("TX SWR_INPUT"), + + SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC0, 0, + &tx_dec0_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC1 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC1, 0, + &tx_dec1_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC2 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC2, 0, + &tx_dec2_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC3 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC3, 0, + &tx_dec3_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC4 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC4, 0, + &tx_dec4_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC5 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC5, 0, + &tx_dec5_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC6 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC6, 0, + &tx_dec6_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("TX DEC7 MUX", SND_SOC_NOPM, + LPASS_CDC_TX_MACRO_DEC7, 0, + &tx_dec7_mux, lpass_cdc_tx_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0, + lpass_cdc_tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route tx_audio_map[] = { + {"TX_AIF1 CAP", NULL, "TX_MCLK"}, + {"TX_AIF2 CAP", NULL, "TX_MCLK"}, + {"TX_AIF3 CAP", NULL, "TX_MCLK"}, + + {"TX_AIF1 CAP", NULL, "TX_AIF1_CAP Mixer"}, + {"TX_AIF2 CAP", NULL, "TX_AIF2_CAP Mixer"}, + {"TX_AIF3 CAP", NULL, "TX_AIF3_CAP Mixer"}, + + {"TX_AIF1_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF1_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX_AIF2_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF2_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX_AIF3_CAP Mixer", "DEC0", "TX DEC0 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC1", "TX DEC1 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC2", "TX DEC2 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC3", "TX DEC3 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC4", "TX DEC4 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC5", "TX DEC5 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC6", "TX DEC6 MUX"}, + {"TX_AIF3_CAP Mixer", "DEC7", "TX DEC7 MUX"}, + + {"TX DEC0 MUX", NULL, "TX_MCLK"}, + {"TX DEC1 MUX", NULL, "TX_MCLK"}, + {"TX DEC2 MUX", NULL, "TX_MCLK"}, + {"TX DEC3 MUX", NULL, "TX_MCLK"}, + {"TX DEC4 MUX", NULL, "TX_MCLK"}, + {"TX DEC5 MUX", NULL, "TX_MCLK"}, + {"TX DEC6 MUX", NULL, "TX_MCLK"}, + {"TX DEC7 MUX", NULL, "TX_MCLK"}, + + {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"}, + {"TX DMIC MUX0", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX0", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX0", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX0", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX0", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX0", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX0", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX0", "DMIC7", "TX DMIC7"}, + + {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"}, + {"TX SMIC MUX0", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX0", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"}, + {"TX DMIC MUX1", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX1", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX1", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX1", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX1", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX1", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX1", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX1", "DMIC7", "TX DMIC7"}, + + {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"}, + {"TX SMIC MUX1", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX1", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"}, + {"TX DMIC MUX2", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX2", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX2", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX2", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX2", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX2", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX2", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX2", "DMIC7", "TX DMIC7"}, + + {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"}, + {"TX SMIC MUX2", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX2", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"}, + {"TX DMIC MUX3", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX3", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX3", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX3", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX3", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX3", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX3", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX3", "DMIC7", "TX DMIC7"}, + + {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"}, + {"TX SMIC MUX3", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX3", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"}, + {"TX DMIC MUX4", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX4", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX4", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX4", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX4", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX4", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX4", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX4", "DMIC7", "TX DMIC7"}, + + {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"}, + {"TX SMIC MUX4", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX4", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"}, + {"TX DMIC MUX5", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX5", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX5", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX5", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX5", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX5", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX5", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX5", "DMIC7", "TX DMIC7"}, + + {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"}, + {"TX SMIC MUX5", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX5", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"}, + {"TX DMIC MUX6", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX6", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX6", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX6", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX6", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX6", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX6", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX6", "DMIC7", "TX DMIC7"}, + + {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"}, + {"TX SMIC MUX6", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX6", "SWR_MIC11", "TX SWR_INPUT"}, + + {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"}, + {"TX DMIC MUX7", "DMIC0", "TX DMIC0"}, + {"TX DMIC MUX7", "DMIC1", "TX DMIC1"}, + {"TX DMIC MUX7", "DMIC2", "TX DMIC2"}, + {"TX DMIC MUX7", "DMIC3", "TX DMIC3"}, + {"TX DMIC MUX7", "DMIC4", "TX DMIC4"}, + {"TX DMIC MUX7", "DMIC5", "TX DMIC5"}, + {"TX DMIC MUX7", "DMIC6", "TX DMIC6"}, + {"TX DMIC MUX7", "DMIC7", "TX DMIC7"}, + + {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"}, + {"TX SMIC MUX7", "SWR_MIC0", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC1", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC2", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC3", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC4", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC5", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC6", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC7", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC8", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC9", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC10", "TX SWR_INPUT"}, + {"TX SMIC MUX7", "SWR_MIC11", "TX SWR_INPUT"}, +}; + +static const struct snd_kcontrol_new lpass_cdc_tx_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("TX_DEC0 Volume", + LPASS_CDC_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC1 Volume", + LPASS_CDC_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC2 Volume", + LPASS_CDC_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC3 Volume", + LPASS_CDC_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC4 Volume", + LPASS_CDC_TX4_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC5 Volume", + LPASS_CDC_TX5_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC6 Volume", + LPASS_CDC_TX6_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC7 Volume", + LPASS_CDC_TX7_TX_VOL_CTL, + -84, 40, digital_gain), + + SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + + SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum, + lpass_cdc_tx_macro_dec_mode_get, lpass_cdc_tx_macro_dec_mode_put), + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + + SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_tx_macro_get_bcs, lpass_cdc_tx_macro_set_bcs), + + SOC_SINGLE_EXT("TX_SWR_DMIC Enable", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_tx_macro_swr_dmic_get, lpass_cdc_tx_macro_swr_dmic_put), + + SOC_ENUM_EXT("BCS Channel", bcs_ch_enum, + lpass_cdc_tx_macro_bcs_ch_get, lpass_cdc_tx_macro_bcs_ch_put), + + SOC_ENUM_EXT("BCS CH_SEL", bcs_ch_sel_mux_enum, + lpass_cdc_tx_macro_get_bcs_ch_sel, lpass_cdc_tx_macro_put_bcs_ch_sel), +}; + +static int lpass_cdc_tx_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + return (int)tx_priv->dmic_clk_div; +} + +static int lpass_cdc_tx_macro_validate_dmic_sample_rate(u32 dmic_sample_rate, + struct lpass_cdc_tx_macro_priv *tx_priv) +{ + u32 div_factor = LPASS_CDC_TX_MACRO_CLK_DIV_2; + u32 mclk_rate = LPASS_CDC_TX_MACRO_MCLK_FREQ; + + if (dmic_sample_rate == LPASS_CDC_TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED || + mclk_rate % dmic_sample_rate != 0) + goto undefined_rate; + + div_factor = mclk_rate / dmic_sample_rate; + + switch (div_factor) { + case 2: + tx_priv->dmic_clk_div = LPASS_CDC_TX_MACRO_CLK_DIV_2; + break; + case 3: + tx_priv->dmic_clk_div = LPASS_CDC_TX_MACRO_CLK_DIV_3; + break; + case 4: + tx_priv->dmic_clk_div = LPASS_CDC_TX_MACRO_CLK_DIV_4; + break; + case 6: + tx_priv->dmic_clk_div = LPASS_CDC_TX_MACRO_CLK_DIV_6; + break; + case 8: + tx_priv->dmic_clk_div = LPASS_CDC_TX_MACRO_CLK_DIV_8; + break; + case 16: + tx_priv->dmic_clk_div = LPASS_CDC_TX_MACRO_CLK_DIV_16; + break; + default: + /* Any other DIV factor is invalid */ + goto undefined_rate; + } + + /* Valid dmic DIV factors */ + dev_dbg(tx_priv->dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n", + __func__, div_factor, mclk_rate); + + return dmic_sample_rate; + +undefined_rate: + dev_dbg(tx_priv->dev, "%s: Invalid rate %d, for mclk %d\n", + __func__, dmic_sample_rate, mclk_rate); + dmic_sample_rate = LPASS_CDC_TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED; + + return dmic_sample_rate; +} + +static const struct lpass_cdc_tx_macro_reg_mask_val + lpass_cdc_tx_macro_reg_init[] = { + {LPASS_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x0A}, +}; + +static int lpass_cdc_tx_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = 0, i = 0; + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + tx_dev = lpass_cdc_get_device_ptr(component->dev, TX_MACRO); + if (!tx_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + tx_priv = dev_get_drvdata(tx_dev); + if (!tx_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + tx_priv->version = lpass_cdc_get_version(tx_dev); + ret = snd_soc_dapm_new_controls(dapm, lpass_cdc_tx_macro_dapm_widgets, + ARRAY_SIZE(lpass_cdc_tx_macro_dapm_widgets)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, tx_audio_map, + ARRAY_SIZE(tx_audio_map)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add widgets\n", __func__); + return ret; + } + + ret = snd_soc_add_component_controls(component, + lpass_cdc_tx_macro_snd_controls, + ARRAY_SIZE(lpass_cdc_tx_macro_snd_controls)); + if (ret < 0) { + dev_err(tx_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + + snd_soc_dapm_ignore_suspend(dapm, "TX_AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "TX_AIF2 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "TX_AIF3 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "TX SWR_INPUT"); + snd_soc_dapm_sync(dapm); + + for (i = 0; i < NUM_DECIMATORS; i++) { + tx_priv->tx_hpf_work[i].tx_priv = tx_priv; + tx_priv->tx_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&tx_priv->tx_hpf_work[i].dwork, + lpass_cdc_tx_macro_tx_hpf_corner_freq_callback); + } + + for (i = 0; i < NUM_DECIMATORS; i++) { + tx_priv->tx_mute_dwork[i].tx_priv = tx_priv; + tx_priv->tx_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&tx_priv->tx_mute_dwork[i].dwork, + lpass_cdc_tx_macro_mute_update_callback); + } + tx_priv->component = component; + + for (i = 0; i < ARRAY_SIZE(lpass_cdc_tx_macro_reg_init); i++) + snd_soc_component_update_bits(component, + lpass_cdc_tx_macro_reg_init[i].reg, + lpass_cdc_tx_macro_reg_init[i].mask, + lpass_cdc_tx_macro_reg_init[i].val); + + return 0; +} + +static int lpass_cdc_tx_macro_deinit(struct snd_soc_component *component) +{ + struct device *tx_dev = NULL; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + if (!lpass_cdc_tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + tx_priv->component = NULL; + return 0; +} + +static void lpass_cdc_tx_macro_init_ops(struct macro_ops *ops, + char __iomem *tx_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->init = lpass_cdc_tx_macro_init; + ops->exit = lpass_cdc_tx_macro_deinit; + ops->io_base = tx_io_base; + ops->dai_ptr = lpass_cdc_tx_macro_dai; + ops->num_dais = ARRAY_SIZE(lpass_cdc_tx_macro_dai); + ops->event_handler = lpass_cdc_tx_macro_event_handler; + ops->clk_div_get = lpass_cdc_tx_macro_clk_div_get; + ops->clk_enable = __lpass_cdc_tx_macro_mclk_enable; +} + +static int lpass_cdc_tx_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops = {0}; + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + u32 tx_base_addr = 0, sample_rate = 0; + char __iomem *tx_io_base = NULL; + int ret = 0; + const char *dmic_sample_rate = "qcom,tx-dmic-sample-rate"; + + if (!lpass_cdc_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + + tx_priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_tx_macro_priv), + GFP_KERNEL); + if (!tx_priv) + return -ENOMEM; + platform_set_drvdata(pdev, tx_priv); + + tx_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &tx_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + dev_set_drvdata(&pdev->dev, tx_priv); + + tx_io_base = devm_ioremap(&pdev->dev, + tx_base_addr, LPASS_CDC_TX_MACRO_MAX_OFFSET); + if (!tx_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -ENOMEM; + } + tx_priv->tx_io_base = tx_io_base; + tx_priv->swr_dmic_enable = false; + tx_priv->wlock_holders = 0; + ret = of_property_read_u32(pdev->dev.of_node, dmic_sample_rate, + &sample_rate); + if (ret) { + dev_err(&pdev->dev, + "%s: could not find sample_rate entry in dt\n", + __func__); + tx_priv->dmic_clk_div = LPASS_CDC_TX_MACRO_CLK_DIV_2; + } else { + if (lpass_cdc_tx_macro_validate_dmic_sample_rate( + sample_rate, tx_priv) == LPASS_CDC_TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED) + return -EINVAL; + } + + mutex_init(&tx_priv->mclk_lock); + mutex_init(&tx_priv->wlock); + lpass_cdc_tx_macro_init_ops(&ops, tx_io_base); + ops.clk_id_req = TX_CORE_CLK; + ops.default_clk_id = TX_CORE_CLK; + ret = lpass_cdc_register_macro(&pdev->dev, TX_MACRO, &ops); + if (ret) { + dev_err(&pdev->dev, + "%s: register macro failed\n", __func__); + goto err_reg_macro; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + + return 0; +err_reg_macro: + mutex_destroy(&tx_priv->mclk_lock); + mutex_destroy(&tx_priv->wlock); + return ret; +} + +static int lpass_cdc_tx_macro_remove(struct platform_device *pdev) +{ + struct lpass_cdc_tx_macro_priv *tx_priv = NULL; + + tx_priv = platform_get_drvdata(pdev); + + if (!tx_priv) + return -EINVAL; + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + mutex_destroy(&tx_priv->mclk_lock); + mutex_destroy(&tx_priv->wlock); + lpass_cdc_unregister_macro(&pdev->dev, TX_MACRO); + return 0; +} + + +static const struct of_device_id lpass_cdc_tx_macro_dt_match[] = { + {.compatible = "qcom,lpass-cdc-tx-macro"}, + {} +}; + +static const struct dev_pm_ops lpass_cdc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + lpass_cdc_runtime_suspend, + lpass_cdc_runtime_resume, + NULL + ) +}; + +static struct platform_driver lpass_cdc_tx_macro_driver = { + .driver = { + .name = "lpass_cdc_tx_macro", + .owner = THIS_MODULE, + .pm = &lpass_cdc_dev_pm_ops, + .of_match_table = lpass_cdc_tx_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_cdc_tx_macro_probe, + .remove = lpass_cdc_tx_macro_remove, +}; + +module_platform_driver(lpass_cdc_tx_macro_driver); + +MODULE_DESCRIPTION("TX macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-utils.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-utils.c new file mode 100644 index 0000000000..a8a3fe64f2 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-utils.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include "lpass-cdc.h" +#include "internal.h" + +#define REG_BYTES 2 +#define VAL_BYTES 1 + +const u16 macro_id_base_offset[MAX_MACRO] = { + TX_START_OFFSET, + RX_START_OFFSET, + WSA_START_OFFSET, + VA_START_OFFSET, + WSA2_START_OFFSET, +}; + +int lpass_cdc_get_macro_id(bool va_no_dec_flag, u16 reg) +{ + if (reg >= TX_START_OFFSET + && reg <= TX_MAX_OFFSET) + return TX_MACRO; + if (reg >= RX_START_OFFSET + && reg <= RX_MAX_OFFSET) + return RX_MACRO; + if (reg >= WSA_START_OFFSET + && reg <= WSA_MAX_OFFSET) + return WSA_MACRO; + if (reg >= WSA2_START_OFFSET + && reg <= WSA2_MAX_OFFSET) + return WSA2_MACRO; + if (reg >= VA_START_OFFSET && + reg <= VA_MAX_OFFSET) + return VA_MACRO; + + return -EINVAL; +} + +static int regmap_bus_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct lpass_cdc_priv *priv = dev_get_drvdata(dev); + u16 *reg_p; + u16 __reg; + int macro_id, i; + u8 temp = 0; + int ret = -EINVAL; + + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is NULL\n", __func__); + return ret; + } + if (!reg || !val) { + dev_err_ratelimited(dev, "%s: reg or val is NULL\n", __func__); + return ret; + } + if (reg_size != REG_BYTES) { + dev_err_ratelimited(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return ret; + } + + reg_p = (u16 *)reg; + macro_id = lpass_cdc_get_macro_id(priv->va_without_decimation, + reg_p[0]); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return 0; + + mutex_lock(&priv->io_lock); + for (i = 0; i < val_size; i++) { + __reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id]; + ret = priv->read_dev(priv, macro_id, __reg, &temp); + if (ret < 0) { + dev_err_ratelimited(dev, + "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n", + __func__, ret, reg_p[0] + i * 4, val_size); + break; + } + ((u8 *)val)[i] = temp; + dev_dbg(dev, "%s: Read 0x%02x from reg 0x%x\n", + __func__, temp, reg_p[0] + i * 4); + } + mutex_unlock(&priv->io_lock); + + return ret; +} + +static int regmap_bus_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) +{ + struct device *dev = context; + struct lpass_cdc_priv *priv = dev_get_drvdata(dev); + u16 *reg_p; + u16 __reg; + int macro_id, i; + int ret = -EINVAL; + + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is NULL\n", __func__); + return ret; + } + if (!reg || !val) { + dev_err_ratelimited(dev, "%s: reg or val is NULL\n", __func__); + return ret; + } + if (reg_size != REG_BYTES) { + dev_err_ratelimited(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return ret; + } + + reg_p = (u16 *)reg; + macro_id = lpass_cdc_get_macro_id(priv->va_without_decimation, + reg_p[0]); + if (macro_id < 0 || !priv->macros_supported[macro_id]) + return 0; + + mutex_lock(&priv->io_lock); + for (i = 0; i < val_size; i++) { + __reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id]; + ret = priv->write_dev(priv, macro_id, __reg, ((u8 *)val)[i]); + if (ret < 0) { + dev_err_ratelimited(dev, + "%s: Codec write failed (%d), reg:0x%x, size:%zd\n", + __func__, ret, reg_p[0] + i * 4, val_size); + break; + } + dev_dbg(dev, "Write %02x to reg 0x%x\n", ((u8 *)val)[i], + reg_p[0] + i * 4); + } + mutex_unlock(&priv->io_lock); + return ret; +} + +static int regmap_bus_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct lpass_cdc_priv *priv = dev_get_drvdata(dev); + + if (!priv) + return -EINVAL; + + if (count < REG_BYTES) { + dev_err_ratelimited(dev, "%s: count %zd bytes < %d, not supported\n", + __func__, count, REG_BYTES); + return -EINVAL; + } + + return regmap_bus_gather_write(context, data, REG_BYTES, + data + REG_BYTES, + count - REG_BYTES); +} + +static struct regmap_bus regmap_bus_config = { + .write = regmap_bus_write, + .gather_write = regmap_bus_gather_write, + .read = regmap_bus_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +struct regmap *lpass_cdc_regmap_init(struct device *dev, + const struct regmap_config *config) +{ + return devm_regmap_init(dev, ®map_bus_config, dev, config); +} diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-va-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-va-macro.c new file mode 100644 index 0000000000..3098b34318 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-va-macro.c @@ -0,0 +1,2677 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpass-cdc.h" +#include "lpass-cdc-registers.h" +#include "lpass-cdc-clk-rsc.h" + +/* pm runtime auto suspend timer in msecs */ +#define VA_AUTO_SUSPEND_DELAY 100 /* delay in msec */ +#define LPASS_CDC_VA_MACRO_MAX_OFFSET 0x1000 + +#define LPASS_CDC_VA_MACRO_NUM_DECIMATORS 4 + +#define LPASS_CDC_VA_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define LPASS_CDC_VA_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define LPASS_CDC_VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED 0 +#define LPASS_CDC_VA_MACRO_MCLK_FREQ 9600000 +#define LPASS_CDC_VA_MACRO_TX_PATH_OFFSET \ + (LPASS_CDC_VA_TX1_TX_PATH_CTL - LPASS_CDC_VA_TX0_TX_PATH_CTL) +#define LPASS_CDC_VA_MACRO_TX_DMIC_CLK_DIV_MASK 0x0E +#define LPASS_CDC_VA_MACRO_TX_DMIC_CLK_DIV_SHFT 0x01 +#define LPASS_CDC_VA_MACRO_SWR_MIC_MUX_SEL_MASK 0xF +#define LPASS_CDC_VA_MACRO_ADC_MUX_CFG_OFFSET 0x8 +#define LPASS_CDC_VA_MACRO_ADC_MODE_CFG0_SHIFT 1 + +#define LPASS_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS 40 +#define LPASS_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS 100 +#define LPASS_CDC_VA_TX_DMIC_HPF_DELAY_MS 300 +#define LPASS_CDC_VA_TX_AMIC_HPF_DELAY_MS 300 +#define MAX_RETRY_ATTEMPTS 500 +#define LPASS_CDC_VA_MACRO_SWR_STRING_LEN 80 +#define LPASS_CDC_VA_MACRO_CHILD_DEVICES_MAX 3 + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static int va_tx_unmute_delay = LPASS_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS; +module_param(va_tx_unmute_delay, int, 0664); +MODULE_PARM_DESC(va_tx_unmute_delay, "delay to unmute the tx path"); + +static int lpass_cdc_va_macro_core_vote(void *handle, bool enable); +enum { + LPASS_CDC_VA_MACRO_AIF_INVALID = 0, + LPASS_CDC_VA_MACRO_AIF1_CAP, + LPASS_CDC_VA_MACRO_AIF2_CAP, + LPASS_CDC_VA_MACRO_AIF3_CAP, + LPASS_CDC_VA_MACRO_MAX_DAIS, +}; + +enum { + LPASS_CDC_VA_MACRO_DEC0, + LPASS_CDC_VA_MACRO_DEC1, + LPASS_CDC_VA_MACRO_DEC2, + LPASS_CDC_VA_MACRO_DEC3, + LPASS_CDC_VA_MACRO_DEC_MAX, +}; + +enum { + LPASS_CDC_VA_MACRO_CLK_DIV_2, + LPASS_CDC_VA_MACRO_CLK_DIV_3, + LPASS_CDC_VA_MACRO_CLK_DIV_4, + LPASS_CDC_VA_MACRO_CLK_DIV_6, + LPASS_CDC_VA_MACRO_CLK_DIV_8, + LPASS_CDC_VA_MACRO_CLK_DIV_16, +}; + +enum { + MSM_DMIC, + SWR_MIC, +}; + +enum { + TX_MCLK, + VA_MCLK, +}; + +struct va_mute_work { + struct lpass_cdc_va_macro_priv *va_priv; + u32 decimator; + struct delayed_work dwork; +}; + +struct hpf_work { + struct lpass_cdc_va_macro_priv *va_priv; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +/* Hold instance to soundwire platform device */ +struct lpass_cdc_va_macro_swr_ctrl_data { + struct platform_device *va_swr_pdev; +}; + +struct lpass_cdc_va_macro_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +struct lpass_cdc_va_macro_priv { + struct device *dev; + bool dec_active[LPASS_CDC_VA_MACRO_NUM_DECIMATORS]; + bool va_without_decimation; + struct clk *lpass_audio_hw_vote; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct mutex wlock; + struct snd_soc_component *component; + struct hpf_work va_hpf_work[LPASS_CDC_VA_MACRO_NUM_DECIMATORS]; + struct va_mute_work va_mute_dwork[LPASS_CDC_VA_MACRO_NUM_DECIMATORS]; + unsigned long active_ch_mask[LPASS_CDC_VA_MACRO_MAX_DAIS]; + unsigned long active_ch_cnt[LPASS_CDC_VA_MACRO_MAX_DAIS]; + u16 dmic_clk_div; + u16 va_mclk_users; + int swr_clk_users; + bool reset_swr; + struct device_node *va_swr_gpio_p; + struct lpass_cdc_va_macro_swr_ctrl_data *swr_ctrl_data; + struct lpass_cdc_va_macro_swr_ctrl_platform_data swr_plat_data; + struct work_struct lpass_cdc_va_macro_add_child_devices_work; + int child_count; + u16 mclk_mux_sel; + char __iomem *va_io_base; + char __iomem *va_island_mode_muxsel; + struct platform_device *pdev_child_devices + [LPASS_CDC_VA_MACRO_CHILD_DEVICES_MAX]; + struct regulator *micb_supply; + u32 micb_voltage; + u32 micb_current; + u32 version; + u32 is_used_va_swr_gpio; + int micb_users; + u16 default_clk_id; + u16 clk_id; + int tx_swr_clk_cnt; + int va_swr_clk_cnt; + int va_clk_status; + int tx_clk_status; + bool lpi_enable; + bool clk_div_switch; + int dec_mode[LPASS_CDC_VA_MACRO_NUM_DECIMATORS]; + int pcm_rate[LPASS_CDC_VA_MACRO_NUM_DECIMATORS]; + int dapm_tx_clk_status; + u16 current_clk_id; + bool dev_up; + bool pre_dev_up; + bool swr_dmic_enable; + bool use_lpi_mixer_control; + int wlock_holders; +}; + + +static int lpass_cdc_va_macro_wake_enable(struct lpass_cdc_va_macro_priv *va_priv, + bool wake_enable) +{ + int ret = 0; + + mutex_lock(&va_priv->wlock); + if (wake_enable) { + if (va_priv->wlock_holders++ == 0) { + dev_dbg(va_priv->dev, "%s: pm wake\n", __func__); + pm_stay_awake(va_priv->dev); + } + } else { + if (--va_priv->wlock_holders == 0) { + dev_dbg(va_priv->dev, "%s: pm release\n", __func__); + pm_relax(va_priv->dev); + } + if (va_priv->wlock_holders < 0) + va_priv->wlock_holders = 0; + } + mutex_unlock(&va_priv->wlock); + return ret; +} + +static bool lpass_cdc_va_macro_get_data(struct snd_soc_component *component, + struct device **va_dev, + struct lpass_cdc_va_macro_priv **va_priv, + const char *func_name) +{ + *va_dev = lpass_cdc_get_device_ptr(component->dev, VA_MACRO); + if (!(*va_dev)) { + dev_err_ratelimited(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + *va_priv = dev_get_drvdata((*va_dev)); + if (!(*va_priv) || !(*va_priv)->component) { + dev_err_ratelimited(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + return true; +} + +static int lpass_cdc_va_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + if (va_priv->clk_div_switch && + (va_priv->dmic_clk_div == LPASS_CDC_VA_MACRO_CLK_DIV_16)) + return LPASS_CDC_VA_MACRO_CLK_DIV_4; + + + return (int)va_priv->dmic_clk_div; +} + +static int lpass_cdc_va_macro_mclk_enable( + struct lpass_cdc_va_macro_priv *va_priv, + bool mclk_enable, bool dapm) +{ + struct regmap *regmap = dev_get_regmap(va_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(va_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(va_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n", + __func__, mclk_enable, dapm, va_priv->va_mclk_users); + + mutex_lock(&va_priv->mclk_lock); + if (mclk_enable) { + ret = lpass_cdc_va_macro_core_vote(va_priv, true); + if (ret < 0) { + dev_err_ratelimited(va_priv->dev, + "%s: va request core vote failed\n", + __func__); + goto exit; + } + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, + true); + lpass_cdc_va_macro_core_vote(va_priv, false); + if (ret < 0) { + dev_err_ratelimited(va_priv->dev, + "%s: va request clock en failed\n", + __func__); + goto exit; + } + lpass_cdc_clk_rsc_fs_gen_request(va_priv->dev, + true); + if (va_priv->va_mclk_users == 0) { + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + VA_START_OFFSET, + VA_MAX_OFFSET); + } + va_priv->va_mclk_users++; + } else { + if (va_priv->va_mclk_users <= 0) { + dev_err_ratelimited(va_priv->dev, "%s: clock already disabled\n", + __func__); + va_priv->va_mclk_users = 0; + goto exit; + } + va_priv->va_mclk_users--; + lpass_cdc_clk_rsc_fs_gen_request(va_priv->dev, + false); + ret = lpass_cdc_va_macro_core_vote(va_priv, true); + if (ret < 0) { + dev_err_ratelimited(va_priv->dev, + "%s: va request core vote failed\n", + __func__); + } + lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, + false); + if (!ret) + lpass_cdc_va_macro_core_vote(va_priv, false); + } +exit: + mutex_unlock(&va_priv->mclk_lock); + return ret; +} + +static int lpass_cdc_va_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + int retry_cnt = MAX_RETRY_ATTEMPTS; + int ret = 0; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + switch (event) { + case LPASS_CDC_MACRO_EVT_WAIT_VA_CLK_RESET: + while ((va_priv->va_mclk_users != 0) && (retry_cnt != 0)) { + dev_dbg_ratelimited(va_dev, "%s:retry_cnt: %d\n", + __func__, retry_cnt); + /* + * Userspace takes 10 seconds to close + * the session when pcm_start fails due to concurrency + * with PDR/SSR. Loop and check every 20ms till 10 + * seconds for va_mclk user count to get reset to 0 + * which ensures userspace teardown is done and SSR + * powerup seq can proceed. + */ + msleep(20); + retry_cnt--; + } + if (retry_cnt == 0) + dev_err_ratelimited(va_dev, + "%s: va_mclk_users non-zero, SSR fail!!\n", + __func__); + break; + case LPASS_CDC_MACRO_EVT_PRE_SSR_UP: + va_priv->pre_dev_up = true; + /* enable&disable VA_CORE_CLK to reset GFMUX reg */ + ret = lpass_cdc_va_macro_core_vote(va_priv, true); + if (ret < 0) { + dev_err_ratelimited(va_priv->dev, + "%s: va request core vote failed\n", + __func__); + break; + } + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, true); + if (ret < 0) + dev_err_ratelimited(va_priv->dev, + "%s, failed to enable clk, ret:%d\n", + __func__, ret); + else + lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, false); + lpass_cdc_va_macro_core_vote(va_priv, false); + break; + case LPASS_CDC_MACRO_EVT_SSR_UP: + /* reset swr after ssr/pdr */ + va_priv->reset_swr = true; + va_priv->dev_up = true; + if (va_priv->swr_ctrl_data) + swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case LPASS_CDC_MACRO_EVT_CLK_RESET: + lpass_cdc_rsc_clk_reset(va_dev, VA_CORE_CLK); + break; + case LPASS_CDC_MACRO_EVT_SSR_DOWN: + va_priv->pre_dev_up = false; + va_priv->dev_up = false; + if (va_priv->swr_ctrl_data) { + swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(va_dev) || + !pm_runtime_suspended(va_dev))) { + ret = lpass_cdc_runtime_suspend(va_dev); + if (!ret) { + pm_runtime_disable(va_dev); + pm_runtime_set_suspended(va_dev); + pm_runtime_enable(va_dev); + } + } + break; + default: + break; + } + return 0; +} + +static int lpass_cdc_va_macro_swr_clk_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 device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + va_priv->va_swr_clk_cnt++; + break; + case SND_SOC_DAPM_POST_PMD: + va_priv->va_swr_clk_cnt--; + break; + default: + break; + } + return 0; +} + +static int lpass_cdc_va_macro_swr_pwr_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); + int ret = 0; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + bool vote_err = false; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d\n",__func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dev_dbg(component->dev, + "%s: va_swr_clk_cnt %d, tx_swr_clk_cnt %d, tx_clk_status %d\n", + __func__, va_priv->va_swr_clk_cnt, + va_priv->tx_swr_clk_cnt, va_priv->tx_clk_status); + if (va_priv->current_clk_id == VA_CORE_CLK) { + return 0; + } else if ( va_priv->va_swr_clk_cnt != 0 && + va_priv->tx_clk_status) { + ret = lpass_cdc_va_macro_core_vote(va_priv, true); + if (ret < 0) { + dev_err_ratelimited(va_priv->dev, + "%s: va request core vote failed\n", + __func__); + break; + } + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, + true); + lpass_cdc_va_macro_core_vote(va_priv, false); + if (ret) { + dev_dbg(component->dev, + "%s: request clock VA_CLK enable failed\n", + __func__); + break; + } + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + false); + if (ret) { + dev_dbg(component->dev, + "%s: request clock TX_CLK disable failed\n", + __func__); + lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, + false); + break; + } + va_priv->current_clk_id = VA_CORE_CLK; + } + break; + case SND_SOC_DAPM_POST_PMD: + if (va_priv->current_clk_id == VA_CORE_CLK) { + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + true); + if (ret) { + dev_err_ratelimited(component->dev, + "%s: request clock TX_CLK enable failed\n", + __func__); + if (va_priv->dev_up) + break; + } + ret = lpass_cdc_va_macro_core_vote(va_priv, true); + if (ret < 0) { + dev_err_ratelimited(va_priv->dev, + "%s: va request core vote failed\n", + __func__); + if (va_priv->dev_up) + break; + vote_err = true; + } + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + VA_CORE_CLK, + false); + if (!vote_err) + lpass_cdc_va_macro_core_vote(va_priv, false); + if (ret) { + dev_err_ratelimited(component->dev, + "%s: request clock VA_CLK disable failed\n", + __func__); + if (va_priv->dev_up) + lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + false); + break; + } + va_priv->current_clk_id = TX_CORE_CLK; + } + break; + default: + dev_err_ratelimited(va_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int lpass_cdc_va_macro_tx_swr_clk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + if (SND_SOC_DAPM_EVENT_ON(event)) + ++va_priv->tx_swr_clk_cnt; + if (SND_SOC_DAPM_EVENT_OFF(event)) + --va_priv->tx_swr_clk_cnt; + + return 0; +} + +static int lpass_cdc_va_macro_mclk_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); + int ret = 0; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + true); + if (!ret) + va_priv->dapm_tx_clk_status++; + + if (!va_priv->use_lpi_mixer_control) { + ret = lpass_cdc_va_macro_mclk_enable(va_priv, 1, true); + } else { + if (va_priv->lpi_enable) + ret = lpass_cdc_va_macro_mclk_enable(va_priv, 1, true); + else + ret = lpass_cdc_tx_mclk_enable(component, 1); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (!va_priv->use_lpi_mixer_control) { + lpass_cdc_va_macro_mclk_enable(va_priv, 0, true); + } else { + if (va_priv->lpi_enable) + lpass_cdc_va_macro_mclk_enable(va_priv, 0, true); + else + lpass_cdc_tx_mclk_enable(component, 0); + } + + if (va_priv->dapm_tx_clk_status > 0) { + lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + false); + va_priv->dapm_tx_clk_status--; + } + break; + default: + dev_err_ratelimited(va_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int lpass_cdc_va_macro_tx_va_mclk_enable( + struct lpass_cdc_va_macro_priv *va_priv, + struct regmap *regmap, int clk_type, + bool enable) +{ + int ret = 0, clk_tx_ret = 0; + + dev_dbg(va_priv->dev, + "%s: clock type %s, enable: %s tx_mclk_users: %d\n", + __func__, (clk_type ? "VA_MCLK" : "TX_MCLK"), + (enable ? "enable" : "disable"), va_priv->va_mclk_users); + + if (enable) { + if (va_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_select_active_state( + va_priv->va_swr_gpio_p); + msm_cdc_pinctrl_set_wakeup_capable( + va_priv->va_swr_gpio_p, false); + } + clk_tx_ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + if (clk_type == TX_MCLK) { + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + if (ret < 0) { + if (va_priv->swr_clk_users == 0) + msm_cdc_pinctrl_select_sleep_state( + va_priv->va_swr_gpio_p); + dev_err_ratelimited(va_priv->dev, + "%s: swr request clk failed\n", + __func__); + goto done; + } + lpass_cdc_clk_rsc_fs_gen_request(va_priv->dev, + true); + } + if (clk_type == VA_MCLK) { + ret = lpass_cdc_va_macro_mclk_enable(va_priv, 1, true); + if (ret < 0) { + if (va_priv->swr_clk_users == 0) + msm_cdc_pinctrl_select_sleep_state( + va_priv->va_swr_gpio_p); + dev_err_ratelimited(va_priv->dev, + "%s: request clock enable failed\n", + __func__); + goto done; + } + } + if (va_priv->swr_clk_users == 0) { + dev_dbg(va_priv->dev, "%s: reset_swr: %d\n", + __func__, va_priv->reset_swr); + if (va_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (va_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + va_priv->reset_swr = false; + } + if (!clk_tx_ret) + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + va_priv->swr_clk_users++; + } else { + if (va_priv->swr_clk_users <= 0) { + dev_err_ratelimited(va_priv->dev, + "va swrm clock users already 0\n"); + va_priv->swr_clk_users = 0; + return 0; + } + clk_tx_ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + true); + va_priv->swr_clk_users--; + if (va_priv->swr_clk_users == 0) + regmap_update_bits(regmap, + LPASS_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + if (clk_type == VA_MCLK) + lpass_cdc_va_macro_mclk_enable(va_priv, 0, true); + if (clk_type == TX_MCLK) { + lpass_cdc_clk_rsc_fs_gen_request(va_priv->dev, + false); + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + if (ret < 0) { + if (va_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_select_sleep_state( + va_priv->va_swr_gpio_p); + } + dev_err_ratelimited(va_priv->dev, + "%s: swr request clk failed\n", + __func__); + goto done; + } + } + if (!clk_tx_ret) + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + if (va_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_select_sleep_state( + va_priv->va_swr_gpio_p); + msm_cdc_pinctrl_set_wakeup_capable( + va_priv->va_swr_gpio_p, true); + } + } + return 0; + +done: + if (!clk_tx_ret) + lpass_cdc_clk_rsc_request_clock(va_priv->dev, + TX_CORE_CLK, + TX_CORE_CLK, + false); + return ret; +} + +static int lpass_cdc_va_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct lpass_cdc_va_macro_priv *va_priv = + (struct lpass_cdc_va_macro_priv *) handle; + + if (va_priv == NULL) { + pr_err_ratelimited("%s: va priv data is NULL\n", __func__); + return -EINVAL; + } + if (!va_priv->pre_dev_up && enable) { + pr_err("%s: adsp is not up\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(va_priv->dev); + if (lpass_cdc_check_core_votes(va_priv->dev)) { + rc = 0; + } else { + rc = -ENOTSYNC; + } + } else { + pm_runtime_put_autosuspend(va_priv->dev); + pm_runtime_mark_last_busy(va_priv->dev); + } + return rc; +} + +static int lpass_cdc_va_macro_swrm_clock(void *handle, bool enable) +{ + struct lpass_cdc_va_macro_priv *va_priv = + (struct lpass_cdc_va_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(va_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(va_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&va_priv->swr_clk_lock); + dev_dbg(va_priv->dev, + "%s: swrm clock %s tx_swr_clk_cnt: %d va_swr_clk_cnt: %d\n", + __func__, (enable ? "enable" : "disable"), + va_priv->tx_swr_clk_cnt, va_priv->va_swr_clk_cnt); + + if (enable) { + pm_runtime_get_sync(va_priv->dev); + if (va_priv->va_swr_clk_cnt && !va_priv->tx_swr_clk_cnt) { + ret = lpass_cdc_va_macro_tx_va_mclk_enable(va_priv, + regmap, VA_MCLK, enable); + if (ret) { + pm_runtime_mark_last_busy(va_priv->dev); + pm_runtime_put_autosuspend(va_priv->dev); + goto done; + } + va_priv->va_clk_status++; + } else { + ret = lpass_cdc_va_macro_tx_va_mclk_enable(va_priv, + regmap, TX_MCLK, enable); + if (ret) { + pm_runtime_mark_last_busy(va_priv->dev); + pm_runtime_put_autosuspend(va_priv->dev); + goto done; + } + va_priv->tx_clk_status++; + } + pm_runtime_mark_last_busy(va_priv->dev); + pm_runtime_put_autosuspend(va_priv->dev); + } else { + if (va_priv->va_clk_status && !va_priv->tx_clk_status) { + ret = lpass_cdc_va_macro_tx_va_mclk_enable(va_priv, + regmap, + VA_MCLK, enable); + if (ret) + goto done; + --va_priv->va_clk_status; + } else if (!va_priv->va_clk_status && va_priv->tx_clk_status) { + ret = lpass_cdc_va_macro_tx_va_mclk_enable(va_priv, + regmap, + TX_MCLK, enable); + if (ret) + goto done; + --va_priv->tx_clk_status; + } else if (va_priv->va_clk_status && va_priv->tx_clk_status) { + if (!va_priv->va_swr_clk_cnt && + va_priv->tx_swr_clk_cnt) { + ret = lpass_cdc_va_macro_tx_va_mclk_enable( + va_priv, regmap, + VA_MCLK, enable); + if (ret) + goto done; + --va_priv->va_clk_status; + } else { + ret = lpass_cdc_va_macro_tx_va_mclk_enable( + va_priv, regmap, + TX_MCLK, enable); + if (ret) + goto done; + --va_priv->tx_clk_status; + } + + } else { + dev_dbg(va_priv->dev, + "%s: Both clocks are disabled\n", __func__); + } + } + dev_dbg(va_priv->dev, + "%s: swrm clock usr %d tx_clk_sts_cnt: %d va_clk_sts_cnt: %d\n", + __func__, va_priv->swr_clk_users, va_priv->tx_clk_status, + va_priv->va_clk_status); +done: + mutex_unlock(&va_priv->swr_clk_lock); + return ret; +} + +static bool is_amic_enabled(struct snd_soc_component *component, int decimator) +{ + u16 adc_mux_reg = 0; + bool ret = false; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return ret; + + adc_mux_reg = LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG1 + + LPASS_CDC_VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; + if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) { + if (!va_priv->swr_dmic_enable) + return true; + } + + return ret; +} + +static void lpass_cdc_va_macro_tx_hpf_corner_freq_callback( + struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct lpass_cdc_va_macro_priv *va_priv; + struct snd_soc_component *component; + u16 dec_cfg_reg, hpf_gate_reg; + u8 hpf_cut_off_freq; + u16 adc_reg = 0, adc_n = 0; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + va_priv = hpf_work->va_priv; + component = va_priv->component; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = LPASS_CDC_VA_TX0_TX_PATH_CFG0 + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + hpf_gate_reg = LPASS_CDC_VA_TX0_TX_PATH_SEC2 + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * hpf_work->decimator; + + dev_dbg(va_priv->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + if (is_amic_enabled(component, hpf_work->decimator)) { + adc_reg = LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0 + + LPASS_CDC_VA_MACRO_ADC_MUX_CFG_OFFSET * + hpf_work->decimator; + adc_n = snd_soc_component_read(component, adc_reg) & + LPASS_CDC_VA_MACRO_SWR_MIC_MUX_SEL_MASK; + /* analog mic clear TX hold */ + lpass_cdc_clear_amic_tx_hold(component->dev, adc_n); + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x02); + /* Add delay between toggle hpf gate based on sample rate */ + switch (va_priv->pcm_rate[hpf_work->decimator]) { + case 0: + usleep_range(125, 130); + break; + case 1: + usleep_range(62, 65); + break; + case 3: + usleep_range(31, 32); + break; + case 4: + usleep_range(20, 21); + break; + case 5: + usleep_range(10, 11); + break; + case 6: + usleep_range(5, 6); + break; + default: + usleep_range(125, 130); + } + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x03, 0x01); + } else { + snd_soc_component_update_bits(component, + dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x02); + /* Minimum 1 clk cycle delay is required as per HW spec */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x00); + } + lpass_cdc_va_macro_wake_enable(va_priv, 0); +} + +static void lpass_cdc_va_macro_mute_update_callback(struct work_struct *work) +{ + struct va_mute_work *va_mute_dwork; + struct snd_soc_component *component = NULL; + struct lpass_cdc_va_macro_priv *va_priv; + struct delayed_work *delayed_work; + u16 tx_vol_ctl_reg, decimator; + + delayed_work = to_delayed_work(work); + va_mute_dwork = container_of(delayed_work, struct va_mute_work, dwork); + va_priv = va_mute_dwork->va_priv; + component = va_priv->component; + decimator = va_mute_dwork->decimator; + + tx_vol_ctl_reg = + LPASS_CDC_VA_TX0_TX_PATH_CTL + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * decimator; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, 0x10, 0x00); + dev_dbg(va_priv->dev, "%s: decimator %u unmute\n", + __func__, decimator); + lpass_cdc_va_macro_wake_enable(va_priv, 0); +} + +static int lpass_cdc_va_macro_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + u16 mic_sel_reg, dmic_clk_reg; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0: + mic_sel_reg = LPASS_CDC_VA_TX0_TX_PATH_CFG0; + break; + case LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG0: + mic_sel_reg = LPASS_CDC_VA_TX1_TX_PATH_CFG0; + break; + case LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG0: + mic_sel_reg = LPASS_CDC_VA_TX2_TX_PATH_CFG0; + break; + case LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG0: + mic_sel_reg = LPASS_CDC_VA_TX3_TX_PATH_CFG0; + break; + default: + dev_err_ratelimited(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + if (strnstr(widget->name, "SMIC", strlen(widget->name))) { + if (val != 0) { + if (!va_priv->swr_dmic_enable) { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x0 << 7); + } else { + snd_soc_component_update_bits(component, + mic_sel_reg, + 1 << 7, 0x1 << 7); + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + dmic_clk_reg = + LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL0 + + ((val - 5)/2) * 4; + snd_soc_component_update_bits(component, + dmic_clk_reg, + 0x0E, va_priv->dmic_clk_div << 0x1); + } + } + } else { + /* DMIC selected */ + if (val != 0) + snd_soc_component_update_bits(component, mic_sel_reg, + 1 << 7, 1 << 7); + } + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int lpass_cdc_va_macro_lpi_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = va_priv->lpi_enable; + + return 0; +} + +static int lpass_cdc_va_macro_lpi_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + va_priv->lpi_enable = ucontrol->value.integer.value[0]; + + return 0; +} + +static int lpass_cdc_va_macro_swr_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = va_priv->swr_dmic_enable; + + return 0; +} + +static int lpass_cdc_va_macro_swr_dmic_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + va_priv->swr_dmic_enable = ucontrol->value.integer.value[0]; + + return 0; +} + + +static int lpass_cdc_va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + if (test_bit(dec_id, &va_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + return 0; +} + +static int lpass_cdc_va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 dec_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + if (enable) { + if (test_bit(dec_id, &va_priv->active_ch_mask[dai_id])) { + dev_err_ratelimited(component->dev, "%s: channel is already enabled, dec_id = %d, dai_id = %d\n", + __func__, dec_id, dai_id); + } else { + set_bit(dec_id, &va_priv->active_ch_mask[dai_id]); + va_priv->active_ch_cnt[dai_id]++; + } + } else { + if (!test_bit(dec_id, &va_priv->active_ch_mask[dai_id])) { + dev_err_ratelimited(component->dev, "%s: channel is already disabled, dec_id = %d, dai_id = %d\n", + __func__, dec_id, dai_id); + } else { + va_priv->active_ch_cnt[dai_id]--; + clear_bit(dec_id, &va_priv->active_ch_mask[dai_id]); + } + } + + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static int lpass_cdc_va_macro_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event, u16 adc_mux0_cfg) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + unsigned int dmic = 0; + + dmic = (snd_soc_component_read(component, adc_mux0_cfg) >> 4) - 1; + + dev_dbg(component->dev, "%s: event %d DMIC%d\n", + __func__, event, dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + lpass_cdc_dmic_clk_enable(component, (u32)dmic, (u32)DMIC_VA, true); + break; + case SND_SOC_DAPM_POST_PMD: + lpass_cdc_dmic_clk_enable(component, (u32)dmic, (u32)DMIC_VA, false); + break; + } + + return 0; +} + +static int lpass_cdc_va_macro_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + unsigned int decimator; + u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + u8 hpf_cut_off_freq; + u16 adc_mux_reg = 0; + u16 adc_mux0_reg = 0; + u16 tx_fs_reg = 0; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + int hpf_delay = LPASS_CDC_VA_TX_DMIC_HPF_DELAY_MS; + int unmute_delay = LPASS_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + decimator = w->shift; + + dev_dbg(va_dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = LPASS_CDC_VA_TX0_TX_PATH_CTL + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * decimator; + hpf_gate_reg = LPASS_CDC_VA_TX0_TX_PATH_SEC2 + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * decimator; + dec_cfg_reg = LPASS_CDC_VA_TX0_TX_PATH_CFG0 + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * decimator; + tx_gain_ctl_reg = LPASS_CDC_VA_TX0_TX_VOL_CTL + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * decimator; + adc_mux_reg = LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG1 + + LPASS_CDC_VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; + adc_mux0_reg = LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0 + + LPASS_CDC_VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; + tx_fs_reg = LPASS_CDC_VA_TX0_TX_PATH_CTL + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * decimator; + va_priv->pcm_rate[decimator] = (snd_soc_component_read(component, + tx_fs_reg) & 0x0F); + + if(!is_amic_enabled(component, decimator)) + lpass_cdc_va_macro_enable_dmic(w, kcontrol, event, adc_mux0_reg); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + dec_cfg_reg, 0x06, va_priv->dec_mode[decimator] << + LPASS_CDC_VA_MACRO_ADC_MODE_CFG0_SHIFT); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + /* Enable TX CLK */ + snd_soc_component_update_bits(component, + tx_vol_ctl_reg, 0x20, 0x20); + if (!is_amic_enabled(component, decimator)) { + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x01, 0x00); + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + } + hpf_cut_off_freq = (snd_soc_component_read( + component, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + va_priv->va_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + } + if (is_amic_enabled(component, decimator)) { + hpf_delay = LPASS_CDC_VA_TX_AMIC_HPF_DELAY_MS; + unmute_delay = LPASS_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS; + if (va_tx_unmute_delay < unmute_delay) + va_tx_unmute_delay = unmute_delay; + } + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x02); + if (!is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x00); + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + hpf_gate_reg, 0x03, 0x01); + /* + * 6ms delay is required as per HW spec + */ + usleep_range(6000, 6010); + /* schedule work queue to Remove Mute */ + lpass_cdc_va_macro_wake_enable(va_priv, 1); + queue_delayed_work(system_freezable_wq, + &va_priv->va_mute_dwork[decimator].dwork, + msecs_to_jiffies(va_tx_unmute_delay)); + if (va_priv->va_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) { + lpass_cdc_va_macro_wake_enable(va_priv, 1); + queue_delayed_work(system_freezable_wq, + &va_priv->va_hpf_work[decimator].dwork, + msecs_to_jiffies(hpf_delay)); + } + /* apply gain after decimator is enabled */ + snd_soc_component_write(component, tx_gain_ctl_reg, + snd_soc_component_read(component, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + va_priv->va_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + if (cancel_delayed_work_sync( + &va_priv->va_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(component, + dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + if (is_amic_enabled(component, decimator)) + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x02); + else + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x03); + /* + * Minimum 1 clk cycle delay is required + * as per HW spec + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x03, 0x01); + } + } + lpass_cdc_va_macro_wake_enable(va_priv, 0); + cancel_delayed_work_sync( + &va_priv->va_mute_dwork[decimator].dwork); + lpass_cdc_va_macro_wake_enable(va_priv, 0); + break; + case SND_SOC_DAPM_POST_PMD: + /* Disable TX CLK */ + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x20, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x40, 0x00); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x00); + break; + } + return 0; +} + +static int lpass_cdc_va_macro_enable_tx(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 device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + int ret = 0; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (va_priv->dapm_tx_clk_status > 0) { + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + false); + va_priv->dapm_tx_clk_status--; + } + break; + case SND_SOC_DAPM_PRE_PMD: + ret = lpass_cdc_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + TX_CORE_CLK, + true); + if (!ret) + va_priv->dapm_tx_clk_status++; + break; + default: + dev_err_ratelimited(va_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + break; + } + + return ret; +} + +static int lpass_cdc_va_macro_enable_micbias(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 device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + int ret = 0; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + if (!va_priv->micb_supply) { + dev_err_ratelimited(va_dev, + "%s:regulator not provided in dtsi\n", __func__); + return -EINVAL; + } + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (va_priv->micb_users++ > 0) + return 0; + ret = regulator_set_voltage(va_priv->micb_supply, + va_priv->micb_voltage, + va_priv->micb_voltage); + if (ret) { + dev_err_ratelimited(va_dev, "%s: Setting voltage failed, err = %d\n", + __func__, ret); + return ret; + } + ret = regulator_set_load(va_priv->micb_supply, + va_priv->micb_current); + if (ret) { + dev_err_ratelimited(va_dev, "%s: Setting current failed, err = %d\n", + __func__, ret); + return ret; + } + ret = regulator_enable(va_priv->micb_supply); + if (ret) { + dev_err_ratelimited(va_dev, "%s: regulator enable failed, err = %d\n", + __func__, ret); + return ret; + } + break; + case SND_SOC_DAPM_POST_PMD: + if (--va_priv->micb_users > 0) + return 0; + if (va_priv->micb_users < 0) { + va_priv->micb_users = 0; + dev_dbg(va_dev, "%s: regulator already disabled\n", + __func__); + return 0; + } + ret = regulator_disable(va_priv->micb_supply); + if (ret) { + dev_err_ratelimited(va_dev, "%s: regulator disable failed, err = %d\n", + __func__, ret); + return ret; + } + regulator_set_voltage(va_priv->micb_supply, 0, + va_priv->micb_voltage); + regulator_set_load(va_priv->micb_supply, 0); + break; + } + return 0; +} + +static inline int lpass_cdc_va_macro_path_get(const char *wname, + unsigned int *path_num) +{ + int ret = 0; + char *widget_name = NULL; + char *w_name = NULL; + char *path_num_char = NULL; + char *path_name = NULL; + + widget_name = kstrndup(wname, 10, GFP_KERNEL); + if (!widget_name) + return -EINVAL; + + w_name = widget_name; + + path_name = strsep(&widget_name, " "); + if (!path_name) { + pr_err_ratelimited("%s: Invalid widget name = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto err; + } + path_num_char = strpbrk(path_name, "01234567"); + if (!path_num_char) { + pr_err_ratelimited("%s: va path index not found\n", + __func__); + ret = -EINVAL; + goto err; + } + ret = kstrtouint(path_num_char, 10, path_num); + if (ret < 0) + pr_err_ratelimited("%s: Invalid tx path = %s\n", + __func__, w_name); + +err: + kfree(w_name); + return ret; +} + +static int lpass_cdc_va_macro_dec_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_va_macro_priv *priv = NULL; + struct device *va_dev = NULL; + int ret = 0; + int path = 0; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, &priv, __func__)) + return -EINVAL; + + ret = lpass_cdc_va_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = priv->dec_mode[path]; + + return 0; +} + +static int lpass_cdc_va_macro_dec_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_va_macro_priv *priv = NULL; + struct device *va_dev = NULL; + int value = ucontrol->value.integer.value[0]; + int ret = 0; + int path = 0; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, &priv, __func__)) + return -EINVAL; + + ret = lpass_cdc_va_macro_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + priv->dec_mode[path] = value; + + return 0; +} + +static int lpass_cdc_va_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int tx_fs_rate = -EINVAL; + struct snd_soc_component *component = dai->component; + u32 decimator, sample_rate; + u16 tx_fs_reg = 0; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + sample_rate = params_rate(params); + if (sample_rate > 16000) + va_priv->clk_div_switch = true; + else + va_priv->clk_div_switch = false; + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err_ratelimited(va_dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + } + for_each_set_bit(decimator, &va_priv->active_ch_mask[dai->id], + LPASS_CDC_VA_MACRO_DEC_MAX) { + if (decimator >= 0) { + tx_fs_reg = LPASS_CDC_VA_TX0_TX_PATH_CTL + + LPASS_CDC_VA_MACRO_TX_PATH_OFFSET * decimator; + dev_dbg(va_dev, "%s: set DEC%u rate to %u\n", + __func__, decimator, sample_rate); + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, tx_fs_rate); + } else { + dev_err_ratelimited(va_dev, + "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int lpass_cdc_va_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case LPASS_CDC_VA_MACRO_AIF1_CAP: + case LPASS_CDC_VA_MACRO_AIF2_CAP: + case LPASS_CDC_VA_MACRO_AIF3_CAP: + *tx_slot = va_priv->active_ch_mask[dai->id]; + *tx_num = va_priv->active_ch_cnt[dai->id]; + break; + default: + dev_err_ratelimited(va_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static struct snd_soc_dai_ops lpass_cdc_va_macro_dai_ops = { + .hw_params = lpass_cdc_va_macro_hw_params, + .get_channel_map = lpass_cdc_va_macro_get_channel_map, +}; + +static struct snd_soc_dai_driver lpass_cdc_va_macro_dai[] = { + { + .name = "va_macro_tx1", + .id = LPASS_CDC_VA_MACRO_AIF1_CAP, + .capture = { + .stream_name = "VA_AIF1 Capture", + .rates = LPASS_CDC_VA_MACRO_RATES, + .formats = LPASS_CDC_VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &lpass_cdc_va_macro_dai_ops, + }, + { + .name = "va_macro_tx2", + .id = LPASS_CDC_VA_MACRO_AIF2_CAP, + .capture = { + .stream_name = "VA_AIF2 Capture", + .rates = LPASS_CDC_VA_MACRO_RATES, + .formats = LPASS_CDC_VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &lpass_cdc_va_macro_dai_ops, + }, + { + .name = "va_macro_tx3", + .id = LPASS_CDC_VA_MACRO_AIF3_CAP, + .capture = { + .stream_name = "VA_AIF3 Capture", + .rates = LPASS_CDC_VA_MACRO_RATES, + .formats = LPASS_CDC_VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &lpass_cdc_va_macro_dai_ops, + }, +}; + +#define STRING(name) #name +#define LPASS_CDC_VA_MACRO_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define LPASS_CDC_VA_MACRO_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +static const char * const adc_mux_text[] = { + "MSM_DMIC", "SWR_MIC" +}; + +LPASS_CDC_VA_MACRO_DAPM_ENUM(va_dec0, LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG1, + 0, adc_mux_text); +LPASS_CDC_VA_MACRO_DAPM_ENUM(va_dec1, LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG1, + 0, adc_mux_text); +LPASS_CDC_VA_MACRO_DAPM_ENUM(va_dec2, LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG1, + 0, adc_mux_text); +LPASS_CDC_VA_MACRO_DAPM_ENUM(va_dec3, LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG1, + 0, adc_mux_text); + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", + "DMIC4", "DMIC5", "DMIC6", "DMIC7" +}; + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_dmic0, LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_dmic1, LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_dmic2, LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_dmic3, LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG0, + 4, dmic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +static const char * const smic_mux_text[] = { + "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3", + "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7", + "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11" +}; + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_smic0, LPASS_CDC_VA_INP_MUX_ADC_MUX0_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_smic1, LPASS_CDC_VA_INP_MUX_ADC_MUX1_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_smic2, LPASS_CDC_VA_INP_MUX_ADC_MUX2_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +LPASS_CDC_VA_MACRO_DAPM_ENUM_EXT(va_smic3, LPASS_CDC_VA_INP_MUX_ADC_MUX3_CFG0, + 0, smic_mux_text, snd_soc_dapm_get_enum_double, + lpass_cdc_va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_aif1_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC0, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC1, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC2, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC3, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif2_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC0, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC1, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC2, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC3, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif3_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC0, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC1, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC2, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC3, 1, 0, + lpass_cdc_va_macro_tx_mixer_get, lpass_cdc_va_macro_tx_mixer_put), +}; + +static const struct snd_soc_dapm_widget lpass_cdc_va_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT_E("VA_AIF1 CAP", "VA_AIF1 Capture", 0, + SND_SOC_NOPM, LPASS_CDC_VA_MACRO_AIF1_CAP, 0, + lpass_cdc_va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT_E("VA_AIF2 CAP", "VA_AIF2 Capture", 0, + SND_SOC_NOPM, LPASS_CDC_VA_MACRO_AIF2_CAP, 0, + lpass_cdc_va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT_E("VA_AIF3 CAP", "VA_AIF3 Capture", 0, + SND_SOC_NOPM, LPASS_CDC_VA_MACRO_AIF3_CAP, 0, + lpass_cdc_va_macro_enable_tx, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM, + LPASS_CDC_VA_MACRO_AIF1_CAP, 0, + va_aif1_cap_mixer, ARRAY_SIZE(va_aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM, + LPASS_CDC_VA_MACRO_AIF2_CAP, 0, + va_aif2_cap_mixer, ARRAY_SIZE(va_aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM, + LPASS_CDC_VA_MACRO_AIF3_CAP, 0, + va_aif3_cap_mixer, ARRAY_SIZE(va_aif3_cap_mixer)), + + LPASS_CDC_VA_MACRO_DAPM_MUX("VA DMIC MUX0", 0, va_dmic0), + LPASS_CDC_VA_MACRO_DAPM_MUX("VA DMIC MUX1", 0, va_dmic1), + LPASS_CDC_VA_MACRO_DAPM_MUX("VA DMIC MUX2", 0, va_dmic2), + LPASS_CDC_VA_MACRO_DAPM_MUX("VA DMIC MUX3", 0, va_dmic3), + + LPASS_CDC_VA_MACRO_DAPM_MUX("VA SMIC MUX0", 0, va_smic0), + LPASS_CDC_VA_MACRO_DAPM_MUX("VA SMIC MUX1", 0, va_smic1), + LPASS_CDC_VA_MACRO_DAPM_MUX("VA SMIC MUX2", 0, va_smic2), + LPASS_CDC_VA_MACRO_DAPM_MUX("VA SMIC MUX3", 0, va_smic3), + + SND_SOC_DAPM_INPUT("VA SWR_INPUT"), + + SND_SOC_DAPM_SUPPLY("VA MIC BIAS", SND_SOC_NOPM, 0, 0, + lpass_cdc_va_macro_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC("VA DMIC0", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("VA DMIC1", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("VA DMIC2", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("VA DMIC3", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("VA DMIC4", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("VA DMIC5", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("VA DMIC6", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("VA DMIC7", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC0, 0, + &va_dec0_mux, lpass_cdc_va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC1 MUX", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC1, 0, + &va_dec1_mux, lpass_cdc_va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC2 MUX", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC2, 0, + &va_dec2_mux, lpass_cdc_va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC3 MUX", SND_SOC_NOPM, LPASS_CDC_VA_MACRO_DEC3, 0, + &va_dec3_mux, lpass_cdc_va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0, + lpass_cdc_va_macro_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", 0, SND_SOC_NOPM, 0, 0, + lpass_cdc_va_macro_swr_pwr_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_TX_SWR_CLK", -1, SND_SOC_NOPM, 0, 0, + lpass_cdc_va_macro_tx_swr_clk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", -1, SND_SOC_NOPM, 0, 0, + lpass_cdc_va_macro_swr_clk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route va_audio_map[] = { + {"VA_AIF1 CAP", NULL, "VA_MCLK"}, + {"VA_AIF2 CAP", NULL, "VA_MCLK"}, + {"VA_AIF3 CAP", NULL, "VA_MCLK"}, + + {"VA_AIF1 CAP", NULL, "VA_AIF1_CAP Mixer"}, + {"VA_AIF2 CAP", NULL, "VA_AIF2_CAP Mixer"}, + {"VA_AIF3 CAP", NULL, "VA_AIF3_CAP Mixer"}, + + {"VA_AIF1_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA_AIF2_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA_AIF3_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA DEC0 MUX", "MSM_DMIC", "VA DMIC MUX0"}, + {"VA DMIC MUX0", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX0", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX0", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX0", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX0", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX0", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX0", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX0", "DMIC7", "VA DMIC7"}, + + {"VA DEC0 MUX", "SWR_MIC", "VA SMIC MUX0"}, + {"VA SMIC MUX0", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX0", "SWR_MIC11", "VA SWR_INPUT"}, + + {"VA DEC1 MUX", "MSM_DMIC", "VA DMIC MUX1"}, + {"VA DMIC MUX1", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX1", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX1", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX1", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX1", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX1", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX1", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX1", "DMIC7", "VA DMIC7"}, + + {"VA DEC1 MUX", "SWR_MIC", "VA SMIC MUX1"}, + {"VA SMIC MUX1", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX1", "SWR_MIC11", "VA SWR_INPUT"}, + + {"VA DEC2 MUX", "MSM_DMIC", "VA DMIC MUX2"}, + {"VA DMIC MUX2", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX2", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX2", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX2", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX2", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX2", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX2", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX2", "DMIC7", "VA DMIC7"}, + + {"VA DEC2 MUX", "SWR_MIC", "VA SMIC MUX2"}, + {"VA SMIC MUX2", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX2", "SWR_MIC11", "VA SWR_INPUT"}, + + {"VA DEC3 MUX", "MSM_DMIC", "VA DMIC MUX3"}, + {"VA DMIC MUX3", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX3", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX3", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX3", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX3", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX3", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX3", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX3", "DMIC7", "VA DMIC7"}, + + {"VA DEC3 MUX", "SWR_MIC", "VA SMIC MUX3"}, + {"VA SMIC MUX3", "SWR_MIC0", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC1", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC2", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC3", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC4", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC5", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC6", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC7", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC8", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC9", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC10", "VA SWR_INPUT"}, + {"VA SMIC MUX3", "SWR_MIC11", "VA SWR_INPUT"}, + + {"VA SWR_INPUT", NULL, "VA_SWR_PWR"}, + + {"VA SWR_INPUT", NULL, "VA_SWR_CLK"}, +}; + +static const char * const dec_mode_mux_text[] = { + "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF", +}; + +static const struct soc_enum dec_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text); + +static const struct snd_kcontrol_new lpass_cdc_va_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("VA_DEC0 Volume", + LPASS_CDC_VA_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC1 Volume", + LPASS_CDC_VA_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC2 Volume", + LPASS_CDC_VA_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC3 Volume", + LPASS_CDC_VA_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0, + lpass_cdc_va_macro_lpi_get, lpass_cdc_va_macro_lpi_put), + + SOC_SINGLE_EXT("VA_SWR_DMIC Enable", 0, 0, 1, 0, + lpass_cdc_va_macro_swr_dmic_get, lpass_cdc_va_macro_swr_dmic_put), + + SOC_ENUM_EXT("VA_DEC0 MODE", dec_mode_mux_enum, + lpass_cdc_va_macro_dec_mode_get, lpass_cdc_va_macro_dec_mode_put), + + SOC_ENUM_EXT("VA_DEC1 MODE", dec_mode_mux_enum, + lpass_cdc_va_macro_dec_mode_get, lpass_cdc_va_macro_dec_mode_put), + + SOC_ENUM_EXT("VA_DEC2 MODE", dec_mode_mux_enum, + lpass_cdc_va_macro_dec_mode_get, lpass_cdc_va_macro_dec_mode_put), + + SOC_ENUM_EXT("VA_DEC3 MODE", dec_mode_mux_enum, + lpass_cdc_va_macro_dec_mode_get, lpass_cdc_va_macro_dec_mode_put), +}; + +static int lpass_cdc_va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate, + struct lpass_cdc_va_macro_priv *va_priv) +{ + u32 div_factor; + u32 mclk_rate = LPASS_CDC_VA_MACRO_MCLK_FREQ; + + if (dmic_sample_rate == LPASS_CDC_VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED || + mclk_rate % dmic_sample_rate != 0) + goto undefined_rate; + + div_factor = mclk_rate / dmic_sample_rate; + + switch (div_factor) { + case 2: + va_priv->dmic_clk_div = LPASS_CDC_VA_MACRO_CLK_DIV_2; + break; + case 3: + va_priv->dmic_clk_div = LPASS_CDC_VA_MACRO_CLK_DIV_3; + break; + case 4: + va_priv->dmic_clk_div = LPASS_CDC_VA_MACRO_CLK_DIV_4; + break; + case 6: + va_priv->dmic_clk_div = LPASS_CDC_VA_MACRO_CLK_DIV_6; + break; + case 8: + va_priv->dmic_clk_div = LPASS_CDC_VA_MACRO_CLK_DIV_8; + break; + case 16: + va_priv->dmic_clk_div = LPASS_CDC_VA_MACRO_CLK_DIV_16; + break; + default: + /* Any other DIV factor is invalid */ + goto undefined_rate; + } + + /* Valid dmic DIV factors */ + dev_dbg(va_priv->dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n", + __func__, div_factor, mclk_rate); + + return dmic_sample_rate; + +undefined_rate: + dev_dbg(va_priv->dev, "%s: Invalid rate %d, for mclk %d\n", + __func__, dmic_sample_rate, mclk_rate); + dmic_sample_rate = LPASS_CDC_VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED; + + return dmic_sample_rate; +} + +static int lpass_cdc_va_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret, i; + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + va_dev = lpass_cdc_get_device_ptr(component->dev, VA_MACRO); + if (!va_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + va_priv = dev_get_drvdata(va_dev); + if (!va_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + + va_priv->lpi_enable = false; + va_priv->swr_dmic_enable = false; + //va_priv->register_event_listener = false; + + va_priv->version = lpass_cdc_get_version(va_dev); + + ret = snd_soc_dapm_new_controls(dapm, + lpass_cdc_va_macro_dapm_widgets, + ARRAY_SIZE(lpass_cdc_va_macro_dapm_widgets)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add controls\n", + __func__); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, va_audio_map, + ARRAY_SIZE(va_audio_map)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add widgets\n", __func__); + return ret; + } + + ret = snd_soc_add_component_controls(component, + lpass_cdc_va_macro_snd_controls, + ARRAY_SIZE(lpass_cdc_va_macro_snd_controls)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add snd_ctls\n", + __func__); + return ret; + } + + snd_soc_dapm_ignore_suspend(dapm, "VA_AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "VA_AIF2 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "VA_AIF3 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "VA SWR_INPUT"); + snd_soc_dapm_sync(dapm); + + va_priv->dev_up = true; + + for (i = 0; i < LPASS_CDC_VA_MACRO_NUM_DECIMATORS; i++) { + va_priv->va_hpf_work[i].va_priv = va_priv; + va_priv->va_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&va_priv->va_hpf_work[i].dwork, + lpass_cdc_va_macro_tx_hpf_corner_freq_callback); + } + + for (i = 0; i < LPASS_CDC_VA_MACRO_NUM_DECIMATORS; i++) { + va_priv->va_mute_dwork[i].va_priv = va_priv; + va_priv->va_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&va_priv->va_mute_dwork[i].dwork, + lpass_cdc_va_macro_mute_update_callback); + } + va_priv->component = component; + + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE, 0xCC); + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE, 0xCC); + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE, 0xCC); + + return 0; +} + +static int lpass_cdc_va_macro_deinit(struct snd_soc_component *component) +{ + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + va_priv->component = NULL; + return 0; +} + +static void lpass_cdc_va_macro_add_child_devices(struct work_struct *work) +{ + struct lpass_cdc_va_macro_priv *va_priv = NULL; + struct platform_device *pdev = NULL; + struct device_node *node = NULL; + struct lpass_cdc_va_macro_swr_ctrl_data *swr_ctrl_data = NULL; + struct lpass_cdc_va_macro_swr_ctrl_data *temp = NULL; + int ret = 0; + u16 count = 0, ctrl_num = 0; + struct lpass_cdc_va_macro_swr_ctrl_platform_data *platdata = NULL; + char plat_dev_name[LPASS_CDC_VA_MACRO_SWR_STRING_LEN] = ""; + bool va_swr_master_node = false; + + va_priv = container_of(work, struct lpass_cdc_va_macro_priv, + lpass_cdc_va_macro_add_child_devices_work); + if (!va_priv) { + pr_err("%s: Memory for va_priv does not exist\n", + __func__); + return; + } + + if (!va_priv->dev) { + pr_err("%s: VA dev does not exist\n", __func__); + return; + } + + if (!va_priv->dev->of_node) { + dev_err(va_priv->dev, + "%s: DT node for va_priv does not exist\n", __func__); + return; + } + + platdata = &va_priv->swr_plat_data; + va_priv->child_count = 0; + + for_each_available_child_of_node(va_priv->dev->of_node, node) { + va_swr_master_node = false; + if (strnstr(node->name, "va_swr_master", + strlen("va_swr_master")) != NULL) + va_swr_master_node = true; + + if (va_swr_master_node) + strlcpy(plat_dev_name, "va_swr_ctrl", + (LPASS_CDC_VA_MACRO_SWR_STRING_LEN - 1)); + else + strlcpy(plat_dev_name, node->name, + (LPASS_CDC_VA_MACRO_SWR_STRING_LEN - 1)); + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(va_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = va_priv->dev; + pdev->dev.of_node = node; + + if (va_swr_master_node) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct lpass_cdc_va_macro_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].va_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + va_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (va_priv->child_count < LPASS_CDC_VA_MACRO_CHILD_DEVICES_MAX) + va_priv->pdev_child_devices[ + va_priv->child_count++] = pdev; + else + goto err; + } + return; +fail_pdev_add: + for (count = 0; count < va_priv->child_count; count++) + platform_device_put(va_priv->pdev_child_devices[count]); +err: + return; +} + +static int lpass_cdc_va_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (va_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +static int lpass_cdc_va_macro_reg_wake_irq(struct snd_soc_component *component, + u32 data) +{ + struct device *va_dev = NULL; + struct lpass_cdc_va_macro_priv *va_priv = NULL; + u32 ipc_wakeup = data; + int ret = 0; + + if (!lpass_cdc_va_macro_get_data(component, &va_dev, + &va_priv, __func__)) + return -EINVAL; + + if (va_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_REGISTER_WAKE_IRQ, &ipc_wakeup); + + return ret; +} + +static void lpass_cdc_va_macro_init_ops(struct macro_ops *ops, + char __iomem *va_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->dai_ptr = lpass_cdc_va_macro_dai; + ops->num_dais = ARRAY_SIZE(lpass_cdc_va_macro_dai); + ops->init = lpass_cdc_va_macro_init; + ops->exit = lpass_cdc_va_macro_deinit; + ops->io_base = va_io_base; + ops->event_handler = lpass_cdc_va_macro_event_handler; + ops->set_port_map = lpass_cdc_va_macro_set_port_map; + ops->reg_wake_irq = lpass_cdc_va_macro_reg_wake_irq; + ops->clk_div_get = lpass_cdc_va_macro_clk_div_get; +} + +static int lpass_cdc_va_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops; + struct lpass_cdc_va_macro_priv *va_priv; + u32 va_base_addr, sample_rate = 0; + char __iomem *va_io_base; + const char *micb_supply_str = "va-vdd-micb-supply"; + const char *micb_supply_str1 = "va-vdd-micb"; + const char *micb_voltage_str = "qcom,va-vdd-micb-voltage"; + const char *micb_current_str = "qcom,va-vdd-micb-current"; + int ret = 0; + const char *dmic_sample_rate = "qcom,va-dmic-sample-rate"; + u32 default_clk_id = 0, use_clk_id = 0; + struct clk *lpass_audio_hw_vote = NULL; + u32 is_used_va_swr_gpio = 0; + const char *is_used_va_swr_gpio_dt = "qcom,is-used-swr-gpio"; + + va_priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_va_macro_priv), + GFP_KERNEL); + if (!va_priv) + return -ENOMEM; + + va_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &va_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, dmic_sample_rate, + &sample_rate); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %d entry in dt\n", + __func__, sample_rate); + va_priv->dmic_clk_div = LPASS_CDC_VA_MACRO_CLK_DIV_2; + } else { + if (lpass_cdc_va_macro_validate_dmic_sample_rate( + sample_rate, va_priv) == + LPASS_CDC_VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED) + return -EINVAL; + } + + if (of_find_property(pdev->dev.of_node, is_used_va_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_va_swr_gpio_dt, + &is_used_va_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_va_swr_gpio_dt); + is_used_va_swr_gpio = 0; + } + } + + va_priv->va_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,va-swr-gpios", 0); + if (!va_priv->va_swr_gpio_p && is_used_va_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if ((msm_cdc_pinctrl_get_state(va_priv->va_swr_gpio_p) < 0) && + is_used_va_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + + va_io_base = devm_ioremap(&pdev->dev, va_base_addr, + LPASS_CDC_VA_MACRO_MAX_OFFSET); + if (!va_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -EINVAL; + } + va_priv->va_io_base = va_io_base; + + lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); + if (IS_ERR(lpass_audio_hw_vote)) { + ret = PTR_ERR(lpass_audio_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_audio_hw_vote", ret); + lpass_audio_hw_vote = NULL; + ret = 0; + } + va_priv->lpass_audio_hw_vote = lpass_audio_hw_vote; + + if (of_parse_phandle(pdev->dev.of_node, micb_supply_str, 0)) { + va_priv->micb_supply = devm_regulator_get(&pdev->dev, + micb_supply_str1); + if (IS_ERR(va_priv->micb_supply)) { + ret = PTR_ERR(va_priv->micb_supply); + dev_err(&pdev->dev, + "%s:Failed to get micbias supply for VA Mic %d\n", + __func__, ret); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, + micb_voltage_str, + &va_priv->micb_voltage); + if (ret) { + dev_err(&pdev->dev, + "%s:Looking up %s property in node %s failed\n", + __func__, micb_voltage_str, + pdev->dev.of_node->full_name); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, + micb_current_str, + &va_priv->micb_current); + if (ret) { + dev_err(&pdev->dev, + "%s:Looking up %s property in node %s failed\n", + __func__, micb_current_str, + pdev->dev.of_node->full_name); + return ret; + } + } + use_clk_id = VA_CORE_CLK; /* default to using VA CORE CLK */ + if (of_find_property(pdev->dev.of_node, "qcom,use-clk-id", NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, "qcom,use-clk-id", + &use_clk_id); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,use-clk-id"); + use_clk_id = VA_CORE_CLK; + } + } + va_priv->clk_id = use_clk_id; + ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id", + &default_clk_id); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,default-clk-id"); + default_clk_id = use_clk_id; + } + va_priv->default_clk_id = default_clk_id; + va_priv->current_clk_id = TX_CORE_CLK; + va_priv->wlock_holders = 0; + + va_priv->use_lpi_mixer_control = false; + if (of_find_property(pdev->dev.of_node, "use-lpi-control", NULL)) { + dev_dbg(&pdev->dev, "%s(): Usage of LPI Enable mixer control is enabled\n", + __func__); + va_priv->use_lpi_mixer_control = true; + } + + if (is_used_va_swr_gpio) { + va_priv->reset_swr = true; + INIT_WORK(&va_priv->lpass_cdc_va_macro_add_child_devices_work, + lpass_cdc_va_macro_add_child_devices); + va_priv->swr_plat_data.handle = (void *) va_priv; + va_priv->swr_plat_data.read = NULL; + va_priv->swr_plat_data.write = NULL; + va_priv->swr_plat_data.bulk_write = NULL; + va_priv->swr_plat_data.clk = lpass_cdc_va_macro_swrm_clock; + va_priv->swr_plat_data.core_vote = lpass_cdc_va_macro_core_vote; + va_priv->swr_plat_data.handle_irq = NULL; + mutex_init(&va_priv->swr_clk_lock); + } + va_priv->is_used_va_swr_gpio = is_used_va_swr_gpio; + va_priv->pre_dev_up = true; + + mutex_init(&va_priv->mclk_lock); + mutex_init(&va_priv->wlock); + dev_set_drvdata(&pdev->dev, va_priv); + lpass_cdc_va_macro_init_ops(&ops, va_io_base); + ops.clk_id_req = va_priv->default_clk_id; + ops.default_clk_id = va_priv->default_clk_id; + ret = lpass_cdc_register_macro(&pdev->dev, VA_MACRO, &ops); + if (ret < 0) { + dev_err(&pdev->dev, "%s: register macro failed\n", __func__); + goto reg_macro_fail; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, VA_AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + if (is_used_va_swr_gpio) + schedule_work(&va_priv->lpass_cdc_va_macro_add_child_devices_work); + return ret; + +reg_macro_fail: + mutex_destroy(&va_priv->mclk_lock); + mutex_destroy(&va_priv->wlock); + if (is_used_va_swr_gpio) + mutex_destroy(&va_priv->swr_clk_lock); + return ret; +} + +static int lpass_cdc_va_macro_remove(struct platform_device *pdev) +{ + struct lpass_cdc_va_macro_priv *va_priv; + int count = 0; + + va_priv = dev_get_drvdata(&pdev->dev); + + if (!va_priv) + return -EINVAL; + if (va_priv->is_used_va_swr_gpio) { + if (va_priv->swr_ctrl_data) + kfree(va_priv->swr_ctrl_data); + for (count = 0; count < va_priv->child_count && + count < LPASS_CDC_VA_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister( + va_priv->pdev_child_devices[count]); + } + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + lpass_cdc_unregister_macro(&pdev->dev, VA_MACRO); + mutex_destroy(&va_priv->mclk_lock); + mutex_destroy(&va_priv->wlock); + if (va_priv->is_used_va_swr_gpio) + mutex_destroy(&va_priv->swr_clk_lock); + return 0; +} + + +static const struct of_device_id lpass_cdc_va_macro_dt_match[] = { + {.compatible = "qcom,lpass-cdc-va-macro"}, + {} +}; + +static const struct dev_pm_ops lpass_cdc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + lpass_cdc_runtime_suspend, + lpass_cdc_runtime_resume, + NULL + ) +}; + +static struct platform_driver lpass_cdc_va_macro_driver = { + .driver = { + .name = "lpass_cdc_va_macro", + .owner = THIS_MODULE, + .pm = &lpass_cdc_dev_pm_ops, + .of_match_table = lpass_cdc_va_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_cdc_va_macro_probe, + .remove = lpass_cdc_va_macro_remove, +}; + +module_platform_driver(lpass_cdc_va_macro_driver); + +MODULE_DESCRIPTION("LPASS codec VA macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c new file mode 100644 index 0000000000..b3b7a68b2d --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c @@ -0,0 +1,4206 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "lpass-cdc.h" +#include "lpass-cdc-comp.h" +#include "lpass-cdc-registers.h" +#include "lpass-cdc-wsa-macro.h" +#include "lpass-cdc-clk-rsc.h" + +#define AUTO_SUSPEND_DELAY 50 /* delay in msec */ +#define LPASS_CDC_WSA_MACRO_MAX_OFFSET 0x1000 + +#define LPASS_CDC_WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define LPASS_CDC_WSA_MACRO_RX_MIX_RATES (SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define LPASS_CDC_WSA_MACRO_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define LPASS_CDC_WSA_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_48000) +#define LPASS_CDC_WSA_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define LPASS_CDC_WSA_MACRO_CPS_RATES (48000) +#define LPASS_CDC_WSA_MACRO_CPS_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) + +#define NUM_INTERPOLATORS 2 + +#define LPASS_CDC_WSA_MACRO_MUX_INP_SHFT 0x3 +#define LPASS_CDC_WSA_MACRO_MUX_INP_MASK1 0x07 +#define LPASS_CDC_WSA_MACRO_MUX_INP_MASK2 0x38 +#define LPASS_CDC_WSA_MACRO_MUX_CFG_OFFSET 0x8 +#define LPASS_CDC_WSA_MACRO_MUX_CFG1_OFFSET 0x4 +#define LPASS_CDC_WSA_MACRO_RX_COMP_OFFSET \ + (LPASS_CDC_WSA_COMPANDER1_CTL0 - LPASS_CDC_WSA_COMPANDER0_CTL0) +#define LPASS_CDC_WSA_MACRO_RX_SOFTCLIP_OFFSET \ + (LPASS_CDC_WSA_SOFTCLIP1_CRC - LPASS_CDC_WSA_SOFTCLIP0_CRC) +#define LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET \ + (LPASS_CDC_WSA_RX1_RX_PATH_CTL - LPASS_CDC_WSA_RX0_RX_PATH_CTL) +#define LPASS_CDC_WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10 +#define LPASS_CDC_WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C +#define LPASS_CDC_WSA_MACRO_FS_RATE_MASK 0x0F +#define LPASS_CDC_WSA_MACRO_EC_MIX_TX0_MASK 0x03 +#define LPASS_CDC_WSA_MACRO_EC_MIX_TX1_MASK 0x18 + +#define LPASS_CDC_WSA_MACRO_MAX_DMA_CH_PER_PORT 0x2 +#define LPASS_CDC_WSA_MACRO_THERMAL_MAX_STATE 11 + +enum { + LPASS_CDC_WSA_MACRO_RX0 = 0, + LPASS_CDC_WSA_MACRO_RX1, + LPASS_CDC_WSA_MACRO_RX_MIX, + LPASS_CDC_WSA_MACRO_RX_MIX0 = LPASS_CDC_WSA_MACRO_RX_MIX, + LPASS_CDC_WSA_MACRO_RX_MIX1, + LPASS_CDC_WSA_MACRO_RX4, + LPASS_CDC_WSA_MACRO_RX5, + LPASS_CDC_WSA_MACRO_RX6, + LPASS_CDC_WSA_MACRO_RX7, + LPASS_CDC_WSA_MACRO_RX8, + LPASS_CDC_WSA_MACRO_RX_MAX, +}; + +enum { + LPASS_CDC_WSA_MACRO_TX0 = 0, + LPASS_CDC_WSA_MACRO_TX1, + LPASS_CDC_WSA_MACRO_TX_MAX, +}; + +enum { + LPASS_CDC_WSA_MACRO_EC0_MUX = 0, + LPASS_CDC_WSA_MACRO_EC1_MUX, + LPASS_CDC_WSA_MACRO_EC_MUX_MAX, +}; + +enum { + LPASS_CDC_WSA_MACRO_COMP1, /* SPK_L */ + LPASS_CDC_WSA_MACRO_COMP2, /* SPK_R */ + LPASS_CDC_WSA_MACRO_COMP_MAX +}; + +enum { + LPASS_CDC_WSA_MACRO_SOFTCLIP0, /* RX0 */ + LPASS_CDC_WSA_MACRO_SOFTCLIP1, /* RX1 */ + LPASS_CDC_WSA_MACRO_SOFTCLIP_MAX +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_RX4, + INTn_1_INP_SEL_RX5, + INTn_1_INP_SEL_RX6, + INTn_1_INP_SEL_RX7, + INTn_1_INP_SEL_RX8, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_RX8, +}; + +enum { + IDLE_DETECT, + NG1, + NG2, + NG3, +}; + +static struct lpass_cdc_comp_setting comp_setting_table[G_MAX_DB] = { + {42, 0, 42}, + {39, 0, 42}, + {36, 0, 42}, + {33, 0, 42}, + {30, 0, 42}, + {27, 0, 42}, + {24, 0, 42}, + {21, 0, 42}, + {18, 0, 42}, +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +/* + * Structure used to update codec + * register defaults after reset + */ +struct lpass_cdc_wsa_macro_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static struct interp_sample_rate int_prim_sample_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +static struct interp_sample_rate int_mix_sample_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +#define LPASS_CDC_WSA_MACRO_SWR_STRING_LEN 80 + +static int lpass_cdc_wsa_macro_core_vote(void *handle, bool enable); +static int lpass_cdc_wsa_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +static int lpass_cdc_wsa_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); +static int lpass_cdc_wsa_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream); + +#define LPASS_CDC_WSA_MACRO_VTH_TO_REG(vth) ((vth) == 0 ? 255 : (vth)) +/* Hold instance to soundwire platform device */ +struct lpass_cdc_wsa_macro_swr_ctrl_data { + struct platform_device *wsa_swr_pdev; +}; +static int lpass_cdc_wsa_macro_enable_vi_decimator(struct snd_soc_component *component); + +#define LPASS_CDC_WSA_MACRO_SET_VOLUME_TLV(xname, xreg, xmin, xmax, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = lpass_cdc_wsa_macro_set_digital_volume, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg, .rreg = xreg, \ + .min = xmin, .max = xmax, \ + .sign_bit = 7,} } + +struct lpass_cdc_wsa_macro_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +enum { + LPASS_CDC_WSA_MACRO_AIF_INVALID = 0, + LPASS_CDC_WSA_MACRO_AIF1_PB, + LPASS_CDC_WSA_MACRO_AIF_MIX1_PB, + LPASS_CDC_WSA_MACRO_AIF_VI, + LPASS_CDC_WSA_MACRO_AIF_ECHO, + LPASS_CDC_WSA_MACRO_AIF_CPS, + LPASS_CDC_WSA_MACRO_MAX_DAIS, +}; + + +#define LPASS_CDC_WSA_MACRO_CHILD_DEVICES_MAX 3 + +/* + * @dev: wsa macro device pointer + * @comp_enabled: compander enable mixer value set + * @ec_hq: echo HQ enable mixer value set + * @prim_int_users: Users of interpolator + * @wsa_mclk_users: WSA MCLK users count + * @swr_clk_users: SWR clk users count + * @vi_feed_value: VI sense mask + * @mclk_lock: to lock mclk operations + * @swr_clk_lock: to lock swr master clock operations + * @swr_ctrl_data: SoundWire data structure + * @swr_plat_data: Soundwire platform data + * @lpass_cdc_wsa_macro_add_child_devices_work: work for adding child devices + * @wsa_swr_gpio_p: used by pinctrl API + * @component: codec handle + * @rx_0_count: RX0 interpolation users + * @rx_1_count: RX1 interpolation users + * @active_ch_mask: channel mask for all AIF DAIs + * @active_ch_cnt: channel count of all AIF DAIs + * @rx_port_value: mixer ctl value of WSA RX MUXes + * @wsa_io_base: Base address of WSA macro addr space + * @wsa_sys_gain System gain value, see wsa driver + * @wsa_bat_cfg Battery Configuration value, see wsa driver + * @wsa_rload Resistor load value for WSA Speaker, see wsa driver + */ +struct lpass_cdc_wsa_macro_priv { + struct device *dev; + int comp_enabled[LPASS_CDC_WSA_MACRO_COMP_MAX]; + int comp_mode[LPASS_CDC_WSA_MACRO_COMP_MAX]; + int ec_hq[LPASS_CDC_WSA_MACRO_RX1 + 1]; + u16 prim_int_users[LPASS_CDC_WSA_MACRO_RX1 + 1]; + u16 wsa_mclk_users; + u16 swr_clk_users; + bool dapm_mclk_enable; + bool reset_swr; + unsigned int vi_feed_value; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct lpass_cdc_wsa_macro_swr_ctrl_data *swr_ctrl_data; + struct lpass_cdc_wsa_macro_swr_ctrl_platform_data swr_plat_data; + struct work_struct lpass_cdc_wsa_macro_add_child_devices_work; + struct device_node *wsa_swr_gpio_p; + struct snd_soc_component *component; + int rx_0_count; + int rx_1_count; + unsigned long active_ch_mask[LPASS_CDC_WSA_MACRO_MAX_DAIS]; + unsigned long active_ch_cnt[LPASS_CDC_WSA_MACRO_MAX_DAIS]; + u16 bit_width[LPASS_CDC_WSA_MACRO_MAX_DAIS]; + int rx_port_value[LPASS_CDC_WSA_MACRO_RX_MAX]; + char __iomem *wsa_io_base; + struct platform_device *pdev_child_devices + [LPASS_CDC_WSA_MACRO_CHILD_DEVICES_MAX]; + int child_count; + int wsa_spkrrecv; + int spkr_gain_offset; + int spkr_mode; + int is_softclip_on[LPASS_CDC_WSA_MACRO_SOFTCLIP_MAX]; + int softclip_clk_users[LPASS_CDC_WSA_MACRO_SOFTCLIP_MAX]; + char __iomem *mclk_mode_muxsel; + u16 default_clk_id; + u32 pcm_rate_vi; + int wsa_digital_mute_status[LPASS_CDC_WSA_MACRO_RX_MAX]; + u8 rx0_origin_gain; + u8 rx1_origin_gain; + struct thermal_cooling_device *tcdev; + uint32_t thermal_cur_state; + uint32_t thermal_max_state; + struct work_struct lpass_cdc_wsa_macro_cooling_work; + bool pbr_enable; + u32 wsa_sys_gain[2 * (LPASS_CDC_WSA_MACRO_RX1 + 1)]; + u32 wsa_bat_cfg[LPASS_CDC_WSA_MACRO_RX1 + 1]; + u32 wsa_rload[LPASS_CDC_WSA_MACRO_RX1 + 1]; + u32 wsa_fs_ctl_reg; + u8 idle_detect_en; + int noise_gate_mode; + bool pre_dev_up; + int pbr_clk_users; + char __iomem *wsa_fs_reg_base; +}; + +static struct snd_soc_dai_driver lpass_cdc_wsa_macro_dai[]; +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +/* for Version 2P6 */ +static const char *const rx_text_v2p6[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", + "RX5", "RX6", "RX7", "RX8", "DEC0", "DEC1" +}; + +static const char *const rx_mix_text_v2p6[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8" +}; + +/* for Version 2P5 */ +static const char *const rx_text_v2p5[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", + "RX5", "DEC0", "DEC1" +}; + +static const char *const rx_mix_text_v2p5[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5" +}; + +static const char *const rx_mix_ec_text[] = { + "ZERO", "RX_MIX_TX0", "RX_MIX_TX1" +}; + +static const char *const rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF_MIX1_PB" +}; + +static const char *const rx_sidetone_mix_text[] = { + "ZERO", "SRC0" +}; + +static const char * const lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_text[] = { + "OFF", "ON" +}; + +static const char * const lpass_cdc_wsa_macro_comp_mode_text[] = { + "G_21_DB", "G_19P5_DB", "G_18_DB", "G_16P5_DB", "G_15_DB", + "G_13P5_DB", "G_12_DB", "G_10P5_DB", "G_9_DB" +}; + +static const struct snd_kcontrol_new wsa_int0_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("WSA RX0 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new wsa_int1_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("WSA RX1 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + + +static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_enum, + lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_text); +static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa_macro_comp_mode_enum, + lpass_cdc_wsa_macro_comp_mode_text); + +/* RX INT0 */ +static const struct soc_enum rx0_sidetone_mix_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text); + +/* for Version 2P5 */ +static const struct soc_enum rx0_prim_inp0_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 0, 9, rx_text_v2p5); + +static const struct soc_enum rx0_prim_inp1_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 3, 9, rx_text_v2p5); + +static const struct soc_enum rx0_prim_inp2_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 3, 9, rx_text_v2p5); + +static const struct soc_enum rx0_mix_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 0, 7, rx_mix_text_v2p5); + +static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2p5); + +static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2p5); + +static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2p5); + +static const struct snd_kcontrol_new rx0_mix_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2p5); + +static const struct soc_enum rx1_prim_inp0_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 0, 9, rx_text_v2p5); + +static const struct soc_enum rx1_prim_inp1_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 3, 9, rx_text_v2p5); + +static const struct soc_enum rx1_prim_inp2_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 3, 9, rx_text_v2p5); + +static const struct soc_enum rx1_mix_chain_enum_v2p5 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 0, 7, rx_mix_text_v2p5); + +static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2p5); + +static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2p5); + +static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2p5); + +static const struct snd_kcontrol_new rx1_mix_mux_v2p5 = + SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2p5); +/* End of Version 2P5 */ + +/* for Version 2P6 */ +static const struct soc_enum rx0_prim_inp0_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 0, 12, rx_text_v2p6); + +static const struct soc_enum rx0_prim_inp1_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 3, 12, rx_text_v2p6); + +static const struct soc_enum rx0_prim_inp2_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 3, 12, rx_text_v2p6); + +static const struct soc_enum rx0_mix_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 0, 10, rx_mix_text_v2p6); + +static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2p6); + +static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2p6); + +static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2p6); + +static const struct snd_kcontrol_new rx0_mix_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2p6); + +static const struct soc_enum rx1_prim_inp0_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 0, 12, rx_text_v2p6); + +static const struct soc_enum rx1_prim_inp1_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 3, 12, rx_text_v2p6); + +static const struct soc_enum rx1_prim_inp2_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 3, 12, rx_text_v2p6); + +static const struct soc_enum rx1_mix_chain_enum_v2p6 = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 0, 10, rx_mix_text_v2p6); + +static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2p6); + +static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2p6); + +static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2p6); + +static const struct snd_kcontrol_new rx1_mix_mux_v2p6 = + SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2p6); +/* End of Version 2P6 */ + +static const struct snd_kcontrol_new rx0_sidetone_mix_mux = + SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum); + +static const struct soc_enum rx_mix_ec0_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 0, 3, rx_mix_ec_text); + +static const struct soc_enum rx_mix_ec1_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 3, 3, rx_mix_ec_text); + +static const struct snd_kcontrol_new rx_mix_ec0_mux = + SOC_DAPM_ENUM("WSA RX_MIX EC0_Mux", rx_mix_ec0_enum); + +static const struct snd_kcontrol_new rx_mix_ec1_mux = + SOC_DAPM_ENUM("WSA RX_MIX EC1_Mux", rx_mix_ec1_enum); + +static struct snd_soc_dai_ops lpass_cdc_wsa_macro_dai_ops = { + .hw_params = lpass_cdc_wsa_macro_hw_params, + .get_channel_map = lpass_cdc_wsa_macro_get_channel_map, + .mute_stream = lpass_cdc_wsa_macro_mute_stream, +}; + +static struct snd_soc_dai_driver lpass_cdc_wsa_macro_dai[] = { + { + .name = "wsa_macro_rx1", + .id = LPASS_CDC_WSA_MACRO_AIF1_PB, + .playback = { + .stream_name = "WSA_AIF1 Playback", + .rates = LPASS_CDC_WSA_MACRO_RX_RATES, + .formats = LPASS_CDC_WSA_MACRO_RX_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_rx_mix", + .id = LPASS_CDC_WSA_MACRO_AIF_MIX1_PB, + .playback = { + .stream_name = "WSA_AIF_MIX1 Playback", + .rates = LPASS_CDC_WSA_MACRO_RX_MIX_RATES, + .formats = LPASS_CDC_WSA_MACRO_RX_FORMATS, + .rate_max = 192000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_vifeedback", + .id = LPASS_CDC_WSA_MACRO_AIF_VI, + .capture = { + .stream_name = "WSA_AIF_VI Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000, + .formats = LPASS_CDC_WSA_MACRO_RX_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &lpass_cdc_wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_echo", + .id = LPASS_CDC_WSA_MACRO_AIF_ECHO, + .capture = { + .stream_name = "WSA_AIF_ECHO Capture", + .rates = LPASS_CDC_WSA_MACRO_ECHO_RATES, + .formats = LPASS_CDC_WSA_MACRO_ECHO_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_cpsfeedback", + .id = LPASS_CDC_WSA_MACRO_AIF_CPS, + .capture = { + .stream_name = "WSA_AIF_CPS Capture", + .rates = LPASS_CDC_WSA_MACRO_CPS_RATES, + .formats = LPASS_CDC_WSA_MACRO_CPS_FORMATS, + .rate_max = 48000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa_macro_dai_ops, + }, +}; + +static bool lpass_cdc_wsa_macro_get_data(struct snd_soc_component *component, + struct device **wsa_dev, + struct lpass_cdc_wsa_macro_priv **wsa_priv, + const char *func_name) +{ + *wsa_dev = lpass_cdc_get_device_ptr(component->dev, + WSA_MACRO); + if (!(*wsa_dev)) { + dev_err_ratelimited(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + *wsa_priv = dev_get_drvdata((*wsa_dev)); + if (!(*wsa_priv) || !(*wsa_priv)->component) { + dev_err_ratelimited(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + return true; +} + +static int lpass_cdc_wsa_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (wsa_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +static int lpass_cdc_wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 int_prim_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp; + u32 j, port; + u16 int_mux_cfg0, int_mux_cfg1; + u16 int_fs_reg; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 inp0_sel, inp1_sel, inp2_sel; + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + for_each_set_bit(port, &wsa_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA_MACRO_RX_MAX) { + int_1_mix1_inp = port; + if ((int_1_mix1_inp < LPASS_CDC_WSA_MACRO_RX0) || + (int_1_mix1_inp > LPASS_CDC_WSA_MACRO_RX_MAX)) { + dev_err_ratelimited(wsa_dev, + "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg0 = LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the cdc_dma rx port + * is connected + */ + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1 = int_mux_cfg0 + LPASS_CDC_WSA_MACRO_MUX_CFG1_OFFSET; + + int_mux_cfg0_val = snd_soc_component_read(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & LPASS_CDC_WSA_MACRO_MUX_INP_MASK1; + inp1_sel = (int_mux_cfg0_val >> + LPASS_CDC_WSA_MACRO_MUX_INP_SHFT) & + LPASS_CDC_WSA_MACRO_MUX_INP_MASK1; + inp2_sel = (int_mux_cfg1_val >> + LPASS_CDC_WSA_MACRO_MUX_INP_SHFT) & + LPASS_CDC_WSA_MACRO_MUX_INP_MASK1; + if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { + int_fs_reg = LPASS_CDC_WSA_RX0_RX_PATH_CTL + + LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET * j; + dev_dbg(wsa_dev, + "%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + dev_dbg(wsa_dev, + "%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + /* sample_rate is in Hz */ + snd_soc_component_update_bits(component, + int_fs_reg, + LPASS_CDC_WSA_MACRO_FS_RATE_MASK, + int_prim_fs_rate_reg_val); + } + int_mux_cfg0 += LPASS_CDC_WSA_MACRO_MUX_CFG_OFFSET; + } + } + + return 0; +} + +static int lpass_cdc_wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 int_mix_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp; + u32 j, port; + u16 int_mux_cfg1, int_fs_reg; + u8 int_mux_cfg1_val; + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + + for_each_set_bit(port, &wsa_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA_MACRO_RX_MAX) { + int_2_inp = port; + if ((int_2_inp < LPASS_CDC_WSA_MACRO_RX0) || + (int_2_inp > LPASS_CDC_WSA_MACRO_RX_MIX1)) { + dev_err_ratelimited(wsa_dev, + "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg1 = LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1) & + LPASS_CDC_WSA_MACRO_MUX_INP_MASK1; + if (int_mux_cfg1_val == int_2_inp + + INTn_2_INP_SEL_RX0) { + int_fs_reg = + LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL + + LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET * j; + + dev_dbg(wsa_dev, + "%s: AIF_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + dev_dbg(wsa_dev, + "%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits(component, + int_fs_reg, + LPASS_CDC_WSA_MACRO_FS_RATE_MASK, + int_mix_fs_rate_reg_val); + } + int_mux_cfg1 += LPASS_CDC_WSA_MACRO_MUX_CFG_OFFSET; + } + } + return 0; +} + +static int lpass_cdc_wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + int rate_val = 0; + int i, ret; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) { + if (sample_rate == + int_mix_sample_rate_val[i].sample_rate) { + rate_val = + int_mix_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) || + (rate_val < 0)) + goto prim_rate; + ret = lpass_cdc_wsa_macro_set_mix_interpolator_rate(dai, + (u8) rate_val, sample_rate); +prim_rate: + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) { + if (sample_rate == + int_prim_sample_rate_val[i].sample_rate) { + rate_val = + int_prim_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) || + (rate_val < 0)) + return -EINVAL; + ret = lpass_cdc_wsa_macro_set_prim_interpolator_rate(dai, + (u8) rate_val, sample_rate); + return ret; +} + +static int lpass_cdc_wsa_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv = dev_get_drvdata(wsa_dev); + if (!wsa_priv) + return -EINVAL; + + dev_dbg(component->dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = lpass_cdc_wsa_macro_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err_ratelimited(component->dev, + "%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16: + wsa_priv->bit_width[dai->id] = 16; + break; + case 24: + wsa_priv->bit_width[dai->id] = 24; + break; + case 32: + wsa_priv->bit_width[dai->id] = 32; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } + break; + case SNDRV_PCM_STREAM_CAPTURE: + if (dai->id == LPASS_CDC_WSA_MACRO_AIF_VI) + wsa_priv->pcm_rate_vi = params_rate(params); + switch (params_width(params)) { + case 16: + wsa_priv->bit_width[dai->id] = 16; + break; + case 24: + wsa_priv->bit_width[dai->id] = 24; + break; + case 32: + wsa_priv->bit_width[dai->id] = 32; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } + break; + default: + break; + } + return 0; +} + +static int lpass_cdc_wsa_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 val = 0, mask = 0, cnt = 0, temp = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv = dev_get_drvdata(wsa_dev); + if (!wsa_priv) + return -EINVAL; + + switch (dai->id) { + case LPASS_CDC_WSA_MACRO_AIF_VI: + for_each_set_bit(temp, &wsa_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA_MACRO_TX_MAX) { + mask |= (1 << temp); + if (++cnt == LPASS_CDC_WSA_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + if (mask & 0x0C) + mask = mask >> 0x2; + + *tx_slot = mask; + *tx_num = cnt; + break; + case LPASS_CDC_WSA_MACRO_AIF_CPS: + *tx_slot = wsa_priv->active_ch_mask[dai->id]; + *tx_num = wsa_priv->active_ch_cnt[dai->id]; + break; + case LPASS_CDC_WSA_MACRO_AIF1_PB: + case LPASS_CDC_WSA_MACRO_AIF_MIX1_PB: + for_each_set_bit(temp, &wsa_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA_MACRO_RX_MAX) { + mask |= (1 << temp); + if (++cnt == LPASS_CDC_WSA_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + if (mask & 0x0C) + mask = mask >> 0x2; + *rx_slot = mask; + *rx_num = cnt; + break; + case LPASS_CDC_WSA_MACRO_AIF_ECHO: + val = snd_soc_component_read(component, + LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0); + if (val & LPASS_CDC_WSA_MACRO_EC_MIX_TX1_MASK) { + mask |= 0x2; + cnt++; + } + if (val & LPASS_CDC_WSA_MACRO_EC_MIX_TX0_MASK) { + mask |= 0x1; + cnt++; + } + *tx_slot = mask; + *tx_num = cnt; + break; + default: + dev_err_ratelimited(wsa_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static void lpass_cdc_wsa_unmute_interpolator(struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + uint16_t j = 0, reg = 0, mix_reg = 0; + + switch (dai->id) { + case LPASS_CDC_WSA_MACRO_AIF1_PB: + case LPASS_CDC_WSA_MACRO_AIF_MIX1_PB: + for (j = 0; j < NUM_INTERPOLATORS; ++j) { + reg = LPASS_CDC_WSA_RX0_RX_PATH_CTL + + (j * LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET); + mix_reg = LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL + + (j * LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET); + + snd_soc_component_update_bits(component, reg, 0x10, 0x00); + snd_soc_component_update_bits(component, mix_reg, 0x10, 0x00); + } + } +} + +static int lpass_cdc_wsa_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + bool adie_lb = false; + uint32_t temp; + + if (mute) + return 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + switch (dai->id) { + case LPASS_CDC_WSA_MACRO_AIF1_PB: + case LPASS_CDC_WSA_MACRO_AIF_MIX1_PB: + lpass_cdc_wsa_pa_on(wsa_dev, adie_lb); + lpass_cdc_wsa_unmute_interpolator(dai); + lpass_cdc_wsa_macro_enable_vi_decimator(component); + break; + default: + break; + } + if ((test_bit(LPASS_CDC_WSA_MACRO_RX4, + &wsa_priv->active_ch_mask[dai->id]) || + test_bit(LPASS_CDC_WSA_MACRO_RX5, + &wsa_priv->active_ch_mask[dai->id])) && + wsa_priv->wsa_fs_reg_base) { + temp = ioread32(wsa_priv->wsa_fs_reg_base); + if (temp != 0) { + temp = 0; + iowrite32(temp, wsa_priv->wsa_fs_reg_base); + } + dev_dbg(wsa_dev, "%s: LPASS_WSA_FS_CTL : %d", __func__, temp); + } + + return 0; +} + +static int lpass_cdc_wsa_macro_mclk_enable( + struct lpass_cdc_wsa_macro_priv *wsa_priv, + bool mclk_enable, bool dapm) +{ + struct regmap *regmap = dev_get_regmap(wsa_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(wsa_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(wsa_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n", + __func__, mclk_enable, dapm, wsa_priv->wsa_mclk_users); + + mutex_lock(&wsa_priv->mclk_lock); + if (mclk_enable) { + if (wsa_priv->wsa_mclk_users == 0) { + ret = lpass_cdc_clk_rsc_request_clock(wsa_priv->dev, + wsa_priv->default_clk_id, + wsa_priv->default_clk_id, + true); + if (ret < 0) { + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa request clock enable failed\n", + __func__); + goto exit; + } + lpass_cdc_clk_rsc_fs_gen_request(wsa_priv->dev, + true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + WSA_START_OFFSET, + WSA_MAX_OFFSET); + /* 9.6MHz MCLK, set value 0x00 if other frequency */ + regmap_update_bits(regmap, + LPASS_CDC_WSA_TOP_FREQ_MCLK, 0x01, 0x01); + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + /* Toggle fs_cntr_clr bit*/ + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x0); + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + wsa_priv->wsa_mclk_users++; + } else { + if (wsa_priv->wsa_mclk_users <= 0) { + dev_err_ratelimited(wsa_priv->dev, "%s: clock already disabled\n", + __func__); + wsa_priv->wsa_mclk_users = 0; + goto exit; + } + wsa_priv->wsa_mclk_users--; + if (wsa_priv->wsa_mclk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + lpass_cdc_clk_rsc_fs_gen_request(wsa_priv->dev, + false); + + lpass_cdc_clk_rsc_request_clock(wsa_priv->dev, + wsa_priv->default_clk_id, + wsa_priv->default_clk_id, + false); + } + } +exit: + mutex_unlock(&wsa_priv->mclk_lock); + return ret; +} + +static int lpass_cdc_wsa_macro_mclk_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); + int ret = 0; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = lpass_cdc_wsa_macro_mclk_enable(wsa_priv, 1, true); + if (ret) + wsa_priv->dapm_mclk_enable = false; + else + wsa_priv->dapm_mclk_enable = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (wsa_priv->dapm_mclk_enable) { + lpass_cdc_wsa_macro_mclk_enable(wsa_priv, 0, true); + wsa_priv->dapm_mclk_enable = false; + } + break; + default: + dev_err_ratelimited(wsa_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int lpass_cdc_wsa_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + int ret = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (event) { + case LPASS_CDC_MACRO_EVT_SSR_DOWN: + wsa_priv->pre_dev_up = false; + if (wsa_priv->swr_ctrl_data) { + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(wsa_dev) || + !pm_runtime_suspended(wsa_dev))) { + ret = lpass_cdc_runtime_suspend(wsa_dev); + if (!ret) { + pm_runtime_disable(wsa_dev); + pm_runtime_set_suspended(wsa_dev); + pm_runtime_enable(wsa_dev); + } + } + break; + case LPASS_CDC_MACRO_EVT_PRE_SSR_UP: + break; + case LPASS_CDC_MACRO_EVT_SSR_UP: + wsa_priv->pre_dev_up = true; + /* reset swr after ssr/pdr */ + wsa_priv->reset_swr = true; + if (wsa_priv->swr_ctrl_data) + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case LPASS_CDC_MACRO_EVT_CLK_RESET: + lpass_cdc_rsc_clk_reset(wsa_dev, WSA_CORE_CLK); + lpass_cdc_rsc_clk_reset(wsa_dev, WSA_TX_CORE_CLK); + break; + } + return 0; +} + +static int lpass_cdc_wsa_macro_enable_vi_decimator(struct snd_soc_component *component) +{ + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u8 val = 0x0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + usleep_range(5000, 5500); + dev_dbg(wsa_dev, "%s: wsa_priv->pcm_rate_vi %d\n", __func__, wsa_priv->pcm_rate_vi); + switch (wsa_priv->pcm_rate_vi) { + case 48000: + val = 0x04; + break; + case 24000: + val = 0x02; + break; + case 8000: + default: + val = 0x00; + break; + } + + if (test_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + dev_dbg(wsa_dev, "%s: spkr1 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + usleep_range(1000, 1500); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + usleep_range(1000, 1500); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + if (test_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + dev_dbg(wsa_dev, "%s: spkr2 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + usleep_range(1000, 1500); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + usleep_range(1000, 1500); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + return 0; +} + +static int lpass_cdc_wsa_macro_disable_vi_feedback(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 device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + if (test_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + /* Disable V&I sensing */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + dev_dbg(wsa_dev, "%s: spkr1 disabled\n", __func__); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + if (test_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + /* Disable V&I sensing */ + dev_dbg(wsa_dev, "%s: spkr2 disabled\n", __func__); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + break; + } + + return 0; +} + +static void lpass_cdc_wsa_macro_hd2_control(struct snd_soc_component *component, + u16 reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (reg == LPASS_CDC_WSA_RX0_RX_PATH_CTL) { + hd2_scale_reg = LPASS_CDC_WSA_RX0_RX_PATH_SEC3; + hd2_enable_reg = LPASS_CDC_WSA_RX0_RX_PATH_CFG0; + } + if (reg == LPASS_CDC_WSA_RX1_RX_PATH_CTL) { + hd2_scale_reg = LPASS_CDC_WSA_RX1_RX_PATH_SEC3; + hd2_enable_reg = LPASS_CDC_WSA_RX1_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x10); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x01); + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x00); + } +} + +static int lpass_cdc_wsa_macro_enable_swr(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ch_cnt; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!(strnstr(w->name, "RX0", sizeof("WSA_RX0"))) && + !wsa_priv->rx_0_count) + wsa_priv->rx_0_count++; + if (!(strnstr(w->name, "RX1", sizeof("WSA_RX1"))) && + !wsa_priv->rx_1_count) + wsa_priv->rx_1_count++; + ch_cnt = wsa_priv->rx_0_count + wsa_priv->rx_1_count; + + if (wsa_priv->swr_ctrl_data) { + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_UP, NULL); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (!(strnstr(w->name, "RX0", sizeof("WSA_RX0"))) && + wsa_priv->rx_0_count) + wsa_priv->rx_0_count--; + if (!(strnstr(w->name, "RX1", sizeof("WSA_RX1"))) && + wsa_priv->rx_1_count) + wsa_priv->rx_1_count--; + ch_cnt = wsa_priv->rx_0_count + wsa_priv->rx_1_count; + + break; + } + dev_dbg(wsa_priv->dev, "%s: current swr ch cnt: %d\n", + __func__, wsa_priv->rx_0_count + wsa_priv->rx_1_count); + + return 0; +} + +static int lpass_cdc_wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int offset_val = 0; + int val = 0; + uint16_t mix_reg = 0; + uint16_t reg = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "WSA_RX0 MIX INP"))) { + gain_reg = LPASS_CDC_WSA_RX0_RX_VOL_MIX_CTL; + reg = LPASS_CDC_WSA_RX0_RX_PATH_CTL + + (LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET * w->shift); + mix_reg = LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL + + LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET * w->shift; + } else if (!(strcmp(w->name, "WSA_RX1 MIX INP"))) { + gain_reg = LPASS_CDC_WSA_RX1_RX_VOL_MIX_CTL; + reg = LPASS_CDC_WSA_RX1_RX_PATH_CTL + + (LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET * w->shift); + mix_reg = LPASS_CDC_WSA_RX1_RX_PATH_MIX_CTL + + LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET * w->shift; + } else { + dev_err_ratelimited(component->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x40); + usleep_range(500, 510); + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x00); + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + snd_soc_component_update_bits(component, + mix_reg, 0x20, 0x20); + lpass_cdc_wsa_macro_enable_swr(w, kcontrol, event); + val = snd_soc_component_read(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + w->reg, 0x20, 0x00); + lpass_cdc_wsa_macro_enable_swr(w, kcontrol, event); + break; + } + + return 0; +} + +static int lpass_cdc_wsa_macro_config_compander(struct snd_soc_component *component, + int comp, int event) +{ + u16 comp_ctl0_reg, comp_ctl8_reg, rx_path_cfg0_reg; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + struct lpass_cdc_comp_setting *comp_settings = NULL; + u16 mode = 0; + u16 index = 0; + int sys_gain, bat_cfg, sys_gain_int, upper_gain, lower_gain; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (comp >= LPASS_CDC_WSA_MACRO_COMP_MAX || comp < 0) { + dev_err(component->dev, "%s: Invalid compander value: %d\n", + __func__, comp); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, wsa_priv->comp_enabled[comp]); + + if (!wsa_priv->comp_enabled[comp]) + return 0; + + mode = wsa_priv->comp_mode[comp]; + if (mode >= G_MAX_DB || mode < 0) + mode = 0; + comp_ctl0_reg = LPASS_CDC_WSA_COMPANDER0_CTL0 + + (comp * LPASS_CDC_WSA_MACRO_RX_COMP_OFFSET); + comp_ctl8_reg = LPASS_CDC_WSA_COMPANDER0_CTL8 + + (comp * LPASS_CDC_WSA_MACRO_RX_COMP_OFFSET); + rx_path_cfg0_reg = LPASS_CDC_WSA_RX0_RX_PATH_CFG0 + + (comp * LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET); + comp_settings = &comp_setting_table[mode]; + + /* If System has battery configuration */ + if (wsa_priv->wsa_bat_cfg[comp]) { + index = (comp * 2) + wsa_priv->wsa_spkrrecv; + if (index >= (2 * (LPASS_CDC_WSA_MACRO_RX1 + 1))) { + dev_err(component->dev, "%s: Invalid index: %d\n", + __func__, index); + return -EINVAL; + } + sys_gain = wsa_priv->wsa_sys_gain[index]; + bat_cfg = wsa_priv->wsa_bat_cfg[comp]; + /* Convert enum to value and + * multiply all values by 10 to avoid float + */ + sys_gain_int = -15 * sys_gain + 210; + switch (bat_cfg) { + case CONFIG_1S: + case EXT_1S: + if (sys_gain > G_13P5_DB) { + upper_gain = sys_gain_int + 60; + lower_gain = 0; + } else { + upper_gain = 210; + lower_gain = 0; + } + break; + case CONFIG_3S: + case EXT_3S: + upper_gain = sys_gain_int; + lower_gain = 75; + break; + case EXT_ABOVE_3S: + upper_gain = sys_gain_int; + lower_gain = 120; + break; + default: + upper_gain = sys_gain_int; + lower_gain = 0; + break; + } + /* Truncate after calculation */ + comp_settings->lower_gain_int = (lower_gain * 2) / 10; + comp_settings->upper_gain_int = (upper_gain * 2) / 10; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + lpass_cdc_update_compander_setting(component, + comp_ctl8_reg, + comp_settings); + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x04); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x00); + } + + return 0; +} + +static void lpass_cdc_wsa_macro_enable_softclip_clk(struct snd_soc_component *component, + struct lpass_cdc_wsa_macro_priv *wsa_priv, + int path, + bool enable) +{ + u16 softclip_clk_reg = LPASS_CDC_WSA_SOFTCLIP0_CRC + + (path * LPASS_CDC_WSA_MACRO_RX_SOFTCLIP_OFFSET); + u8 softclip_mux_mask = (1 << path); + u8 softclip_mux_value = (1 << path); + + dev_dbg(component->dev, "%s: path %d, enable %d\n", + __func__, path, enable); + if (enable) { + if (wsa_priv->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, 0x01, 0x01); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, softclip_mux_value); + } + wsa_priv->softclip_clk_users[path]++; + } else { + wsa_priv->softclip_clk_users[path]--; + if (wsa_priv->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, 0x00); + } + } +} + +static int lpass_cdc_wsa_macro_config_softclip(struct snd_soc_component *component, + int path, int event) +{ + u16 softclip_ctrl_reg = 0; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + int softclip_path = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (path == LPASS_CDC_WSA_MACRO_COMP1) + softclip_path = LPASS_CDC_WSA_MACRO_SOFTCLIP0; + else if (path == LPASS_CDC_WSA_MACRO_COMP2) + softclip_path = LPASS_CDC_WSA_MACRO_SOFTCLIP1; + + dev_dbg(component->dev, "%s: event %d path %d, enabled %d\n", + __func__, event, softclip_path, + wsa_priv->is_softclip_on[softclip_path]); + + if (!wsa_priv->is_softclip_on[softclip_path]) + return 0; + + softclip_ctrl_reg = LPASS_CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL + + (softclip_path * LPASS_CDC_WSA_MACRO_RX_SOFTCLIP_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Softclip clock and mux */ + lpass_cdc_wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, true); + /* Enable Softclip control */ + snd_soc_component_update_bits(component, softclip_ctrl_reg, + 0x01, 0x01); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, softclip_ctrl_reg, + 0x01, 0x00); + lpass_cdc_wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, false); + } + + return 0; +} + +static int lpass_cdc_was_macro_config_pbr(struct snd_soc_component *component, + int path, int event) +{ + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 reg1 = 0, reg2 = 0, reg3 = 0; + int softclip_path = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (path == LPASS_CDC_WSA_MACRO_COMP1) { + reg1 = LPASS_CDC_WSA_COMPANDER0_CTL0; + reg2 = LPASS_CDC_WSA_RX0_RX_PATH_CFG3; + reg3 = LPASS_CDC_WSA_RX0_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA_MACRO_SOFTCLIP0; + } else if (path == LPASS_CDC_WSA_MACRO_COMP2) { + reg1 = LPASS_CDC_WSA_COMPANDER1_CTL0; + reg2 = LPASS_CDC_WSA_RX1_RX_PATH_CFG3; + reg3 = LPASS_CDC_WSA_RX1_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA_MACRO_SOFTCLIP1; + } + if (!wsa_priv->pbr_enable || wsa_priv->wsa_bat_cfg[path] >= EXT_1S || + wsa_priv->wsa_sys_gain[path * 2] > G_12_DB || + wsa_priv->wsa_spkrrecv || !reg1 || !reg2 || !reg3) + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, + reg1, 0x08, 0x08); + snd_soc_component_update_bits(component, + reg2, 0x40, 0x40); + snd_soc_component_update_bits(component, + reg3, 0x80, 0x80); + lpass_cdc_wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, true); + if (wsa_priv->pbr_clk_users == 0) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_PBR_PATH_CTL, + 0x01, 0x01); + ++wsa_priv->pbr_clk_users; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + if (wsa_priv->pbr_clk_users == 1) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_PBR_PATH_CTL, + 0x01, 0x00); + lpass_cdc_wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, false); + snd_soc_component_update_bits(component, + reg1, 0x08, 0x00); + snd_soc_component_update_bits(component, + reg2, 0x40, 0x00); + snd_soc_component_update_bits(component, + reg3, 0x80, 0x00); + --wsa_priv->pbr_clk_users; + if (wsa_priv->pbr_clk_users < 0) + wsa_priv->pbr_clk_users = 0; + } + return 0; +} + +static bool lpass_cdc_wsa_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0; + int int_1_rx = INTn_1_INP_SEL_DEC0; + int int_2_rx = INTn_1_INP_SEL_DEC1; + u32 version; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + int_mux_cfg0 = LPASS_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + + version = lpass_cdc_get_version(wsa_dev); + + /* For Lpass version <= 2.5 the config mux didnot have rx6,rx7,rx8. + * So decrease by 3 will select the correct index. + */ + if (version <= LPASS_CDC_VERSION_2_5) { + int_1_rx = int_1_rx - 3; + int_2_rx = int_2_rx - 3; + } + + if (int_n_inp0 == int_1_rx || + int_n_inp0 == int_2_rx) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == int_1_rx || + int_n_inp1 == int_2_rx) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == int_1_rx || + int_n_inp2 == int_2_rx) + return true; + + return false; +} + +static int lpass_cdc_wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 reg = 0; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + bool adie_lb = false; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + + reg = LPASS_CDC_WSA_RX0_RX_PATH_CTL + + LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET * w->shift; + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, reg, 0x40, 0x40); + usleep_range(500, 510); + snd_soc_component_update_bits(component, reg, 0x40, 0x00); + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + if (lpass_cdc_wsa_macro_adie_lb(component, w->shift)) { + adie_lb = true; + lpass_cdc_wsa_pa_on(wsa_dev, adie_lb); + snd_soc_component_update_bits(component, + reg, 0x10, 0x00); + } + break; + default: + break; + } + return 0; +} + +static int lpass_cdc_wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = 0; + + switch (reg) { + case LPASS_CDC_WSA_RX0_RX_PATH_CTL: + case LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL: + prim_int_reg = LPASS_CDC_WSA_RX0_RX_PATH_CTL; + *ind = 0; + break; + case LPASS_CDC_WSA_RX1_RX_PATH_CTL: + case LPASS_CDC_WSA_RX1_RX_PATH_MIX_CTL: + prim_int_reg = LPASS_CDC_WSA_RX1_RX_PATH_CTL; + *ind = 1; + break; + } + + return prim_int_reg; +} + +static int lpass_cdc_wsa_macro_enable_prim_interpolator( + struct snd_soc_component *component, + u16 reg, int event) +{ + u16 prim_int_reg; + u16 ind = 0; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + prim_int_reg = lpass_cdc_wsa_macro_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wsa_priv->prim_int_users[ind]++; + if (wsa_priv->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(component, + prim_int_reg + LPASS_CDC_WSA_MACRO_RX_PATH_CFG3_OFFSET, + 0x03, 0x03); + snd_soc_component_update_bits(component, prim_int_reg, + 0x10, 0x10); + lpass_cdc_wsa_macro_hd2_control(component, prim_int_reg, event); + snd_soc_component_update_bits(component, + prim_int_reg + LPASS_CDC_WSA_MACRO_RX_PATH_DSMDEM_OFFSET, + 0x1, 0x1); + } + if ((reg != prim_int_reg) && + ((snd_soc_component_read( + component, prim_int_reg)) & 0x10)) + snd_soc_component_update_bits(component, reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + wsa_priv->prim_int_users[ind]--; + if (wsa_priv->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(component, prim_int_reg, + 1 << 0x5, 0 << 0x5); + snd_soc_component_update_bits(component, + prim_int_reg + LPASS_CDC_WSA_MACRO_RX_PATH_DSMDEM_OFFSET, + 0x1, 0x0); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x00); + lpass_cdc_wsa_macro_hd2_control(component, prim_int_reg, event); + } + break; + } + + dev_dbg(component->dev, "%s: primary interpolator: INT%d, users: %d\n", + __func__, ind, wsa_priv->prim_int_users[ind]); + return 0; +} + +static void lpass_cdc_macro_idle_detect_control(struct snd_soc_component *component, + struct lpass_cdc_wsa_macro_priv *wsa_priv, + int interp, int event) +{ + int reg = 0, mask = 0, val = 0, source_reg = 0; + u16 mode = 0; + + dev_dbg(component->dev, "%s: Idle_detect_en value: %d\n", __func__, + wsa_priv->idle_detect_en); + + if (!wsa_priv->idle_detect_en) + return; + + if (interp == LPASS_CDC_WSA_MACRO_COMP1) { + source_reg = LPASS_CDC_WSA_RX0_RX_PATH_CFG3; + reg = LPASS_CDC_WSA_IDLE_DETECT_PATH_CTL; + mask = 0x01; + val = 0x01; + } + if (interp == LPASS_CDC_WSA_MACRO_COMP2) { + source_reg = LPASS_CDC_WSA_RX1_RX_PATH_CFG3; + reg = LPASS_CDC_WSA_IDLE_DETECT_PATH_CTL; + mask = 0x02; + val = 0x02; + } + + mode = wsa_priv->comp_mode[interp]; + + if ((wsa_priv->noise_gate_mode == NG2 && mode >= G_13P5_DB) || + wsa_priv->noise_gate_mode == IDLE_DETECT || !wsa_priv->pbr_enable || + wsa_priv->wsa_spkrrecv) { + snd_soc_component_update_bits(component, source_reg, 0x80, 0x00); + dev_dbg(component->dev, "%s: Idle detect source: Legacy\n", __func__); + } else { + snd_soc_component_update_bits(component, source_reg, 0x80, 0x80); + dev_dbg(component->dev, "%s: Idle detect source: PRE-LA\n", __func__); + } + + if (reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, reg, mask, val); + dev_dbg(component->dev, "%s: Idle detect clks ON\n", __func__); + } + + if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, reg, mask, 0x00); + snd_soc_component_write(component, + LPASS_CDC_WSA_IDLE_DETECT_CFG3, 0x0); + dev_dbg(component->dev, "%s: Idle detect clks OFF\n", __func__); + } +} + +static int lpass_cdc_wsa_macro_enable_interpolator(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 device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u8 gain = 0; + u16 reg = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "WSA_RX INT0 INTERP"))) { + reg = LPASS_CDC_WSA_RX0_RX_PATH_CTL; + } else if (!(strcmp(w->name, "WSA_RX INT1 INTERP"))) { + reg = LPASS_CDC_WSA_RX1_RX_PATH_CTL; + } else { + dev_err_ratelimited(component->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + lpass_cdc_wsa_macro_enable_prim_interpolator(component, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + if (!strcmp(w->name, "WSA_RX INT0 INTERP")) { + gain = (u8)(wsa_priv->rx0_origin_gain - + wsa_priv->thermal_cur_state); + if (snd_soc_component_read(wsa_priv->component, + LPASS_CDC_WSA_RX0_RX_VOL_CTL) != gain) { + snd_soc_component_update_bits(wsa_priv->component, + LPASS_CDC_WSA_RX0_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa_priv->dev, + "%s: RX0 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa_priv->thermal_cur_state, gain); + } + } + + if (!strcmp(w->name, "WSA_RX INT1 INTERP")) { + gain = (u8)(wsa_priv->rx1_origin_gain - + wsa_priv->thermal_cur_state); + if (snd_soc_component_read(wsa_priv->component, + LPASS_CDC_WSA_RX1_RX_VOL_CTL) != gain) { + snd_soc_component_update_bits(wsa_priv->component, + LPASS_CDC_WSA_RX1_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa_priv->dev, + "%s: RX1 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa_priv->thermal_cur_state, gain); + } + } + + lpass_cdc_wsa_macro_config_compander(component, w->shift, event); + lpass_cdc_macro_idle_detect_control(component, wsa_priv, + w->shift, event); + lpass_cdc_wsa_macro_config_softclip(component, w->shift, event); + lpass_cdc_was_macro_config_pbr(component, w->shift, event); + if (wsa_priv->wsa_spkrrecv) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX0_RX_PATH_CFG1, + 0x08, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08); + lpass_cdc_wsa_macro_config_compander(component, w->shift, event); + lpass_cdc_macro_idle_detect_control(component, wsa_priv, + w->shift, event); + lpass_cdc_wsa_macro_config_softclip(component, w->shift, event); + lpass_cdc_was_macro_config_pbr(component, w->shift, event); + lpass_cdc_wsa_macro_enable_prim_interpolator(component, reg, event); + break; + } + + return 0; +} + +static int lpass_cdc_wsa_macro_spk_boost_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); + u16 boost_path_ctl, boost_path_cfg1; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) { + boost_path_ctl = LPASS_CDC_WSA_BOOST0_BOOST_PATH_CTL; + boost_path_cfg1 = LPASS_CDC_WSA_RX0_RX_PATH_CFG1; + } else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) { + boost_path_ctl = LPASS_CDC_WSA_BOOST1_BOOST_PATH_CTL; + boost_path_cfg1 = LPASS_CDC_WSA_RX1_RX_PATH_CFG1; + } else { + dev_err_ratelimited(component->dev, "%s: unknown widget: %s\n", + __func__, w->name); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x01); + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x00); + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x00); + break; + } + + return 0; +} + + +static int lpass_cdc_wsa_macro_enable_vbat(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 device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 vbat_path_cfg = 0; + int softclip_path = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + if (!strcmp(w->name, "WSA_RX INT0 VBAT")) { + vbat_path_cfg = LPASS_CDC_WSA_RX0_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA_MACRO_SOFTCLIP0; + } else if (!strcmp(w->name, "WSA_RX INT1 VBAT")) { + vbat_path_cfg = LPASS_CDC_WSA_RX1_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA_MACRO_SOFTCLIP1; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable clock for VBAT block */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x10); + /* Enable VBAT block */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x01, 0x01); + /* Update interpolator with 384K path */ + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x80, 0x80); + /* Use attenuation mode */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x02, 0x00); + /* + * BCL block needs softclip clock and mux config to be enabled + */ + lpass_cdc_wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, true); + /* Enable VBAT at channel level */ + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x02); + /* Set the ATTK1 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + /* Set the ATTK2 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + /* Set the ATTK3 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + /* Enable CB decode block clock */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x01); + /* Enable BCL path */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x01); + /* Request for BCL data */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x01); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x00); + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x80, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG, + 0x02, 0x02); + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + lpass_cdc_wsa_macro_enable_softclip_clk(component, wsa_priv, + softclip_path, false); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x00); + break; + default: + dev_err_ratelimited(wsa_dev, "%s: Invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static int lpass_cdc_wsa_macro_enable_echo(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 device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 val, ec_tx = 0, ec_hq_reg; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa_dev, "%s %d %s\n", __func__, event, w->name); + + val = snd_soc_component_read(component, + LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0); + if (!(strcmp(w->name, "WSA RX_MIX EC0_MUX"))) + ec_tx = (val & 0x07) - 1; + else + ec_tx = ((val & 0x38) >> 0x3) - 1; + + if (ec_tx < 0 || ec_tx >= (LPASS_CDC_WSA_MACRO_RX1 + 1)) { + dev_err_ratelimited(wsa_dev, "%s: EC mix control not set correctly\n", + __func__); + return -EINVAL; + } + if (wsa_priv->ec_hq[ec_tx]) { + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 0x1 << ec_tx, 0x1 << ec_tx); + ec_hq_reg = LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL + + 0x40 * ec_tx; + snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01); + ec_hq_reg = LPASS_CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 + + 0x40 * ec_tx; + /* default set to 48k */ + snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08); + } + + return 0; +} + +static int lpass_cdc_wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->ec_hq[ec_tx]; + return 0; +} + +static int lpass_cdc_wsa_macro_set_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa_dev, "%s: enable current %d, new %d\n", + __func__, wsa_priv->ec_hq[ec_tx], value); + wsa_priv->ec_hq[ec_tx] = value; + + return 0; +} + +static int lpass_cdc_wsa_macro_get_rx_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + int wsa_rx_shift = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + wsa_priv->wsa_digital_mute_status[wsa_rx_shift]; + return 0; +} + +static int lpass_cdc_wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + int value = ucontrol->value.integer.value[0]; + int wsa_rx_shift = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int ret = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + pm_runtime_get_sync(wsa_priv->dev); + switch (wsa_rx_shift) { + case 0: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX0_RX_PATH_CTL, + 0x10, value << 4); + break; + case 1: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX1_RX_PATH_CTL, + 0x10, value << 4); + break; + case 2: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX0_RX_PATH_MIX_CTL, + 0x10, value << 4); + break; + case 3: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_RX1_RX_PATH_MIX_CTL, + 0x10, value << 4); + break; + default: + pr_err_ratelimited("%s: invalid argument rx_shift = %d\n", __func__, + wsa_rx_shift); + ret = -EINVAL; + } + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + + dev_dbg(component->dev, "%s: WSA Digital Mute RX %d Enable %d\n", + __func__, wsa_rx_shift, value); + wsa_priv->wsa_digital_mute_status[wsa_rx_shift] = value; + + return ret; +} + +static int lpass_cdc_wsa_macro_set_digital_volume(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u8 gain = 0; + int ret = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (!wsa_priv) { + pr_err_ratelimited("%s: priv is null for macro!\n", + __func__); + return -EINVAL; + } + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (mc->reg == LPASS_CDC_WSA_RX0_RX_VOL_CTL) { + wsa_priv->rx0_origin_gain = + (u8)snd_soc_component_read(wsa_priv->component, + mc->reg); + gain = (u8)(wsa_priv->rx0_origin_gain - + wsa_priv->thermal_cur_state); + } else if (mc->reg == LPASS_CDC_WSA_RX1_RX_VOL_CTL) { + wsa_priv->rx1_origin_gain = + (u8)snd_soc_component_read(wsa_priv->component, + mc->reg); + gain = (u8)(wsa_priv->rx1_origin_gain - + wsa_priv->thermal_cur_state); + } else { + dev_err_ratelimited(wsa_priv->dev, + "%s: Incorrect RX Path selected\n", __func__); + return -EINVAL; + } + + /* only adjust gain if thermal state is positive */ + if (wsa_priv->dapm_mclk_enable && + wsa_priv->thermal_cur_state > 0) { + snd_soc_component_update_bits(wsa_priv->component, + mc->reg, 0xFF, gain); + dev_dbg(wsa_priv->dev, + "%s: Current thermal state: %d, adjusted gain: %x\n", + __func__, wsa_priv->thermal_cur_state, gain); + } + + return ret; +} + +static int lpass_cdc_wsa_macro_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->comp_enabled[comp]; + return 0; +} + +static int lpass_cdc_wsa_macro_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, wsa_priv->comp_enabled[comp], value); + wsa_priv->comp_enabled[comp] = value; + + return 0; +} + +static int lpass_cdc_wsa_macro_ear_spkrrecv_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->wsa_spkrrecv; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa_macro_ear_spkrrecv_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->wsa_spkrrecv = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s:spkrrecv status = %d\n", + __func__, wsa_priv->wsa_spkrrecv); + + return 0; +} + +static int lpass_cdc_wsa_macro_idle_detect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + struct device *wsa_dev = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->idle_detect_en; + + return 0; +} + +static int lpass_cdc_wsa_macro_idle_detect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + struct device *wsa_dev = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->idle_detect_en = ucontrol->value.integer.value[0]; + + return 0; +} + +static int lpass_cdc_wsa_macro_comp_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 idx = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (strnstr(kcontrol->id.name, "RX0", sizeof("WSA_RX0"))) + idx = LPASS_CDC_WSA_MACRO_COMP1; + if (strnstr(kcontrol->id.name, "RX1", sizeof("WSA_RX1"))) + idx = LPASS_CDC_WSA_MACRO_COMP2; + ucontrol->value.integer.value[0] = wsa_priv->comp_mode[idx]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa_macro_comp_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 idx = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (strnstr(kcontrol->id.name, "RX0", sizeof("WSA_RX0"))) + idx = LPASS_CDC_WSA_MACRO_COMP1; + if (strnstr(kcontrol->id.name, "RX1", sizeof("WSA_RX1"))) + idx = LPASS_CDC_WSA_MACRO_COMP2; + + if (ucontrol->value.integer.value[0] < G_MAX_DB && ucontrol->value.integer.value[0] >= 0) + wsa_priv->comp_mode[idx] = ucontrol->value.integer.value[0]; + else + return 0; + + dev_dbg(component->dev, "%s: comp_mode = %d\n", __func__, + wsa_priv->comp_mode[idx]); + + return 0; +} + +static int lpass_cdc_wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + wsa_priv->rx_port_value[widget->shift]; + return 0; +} + +static int lpass_cdc_wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 rx_port_value = ucontrol->value.integer.value[0]; + u32 bit_input = 0; + u32 aif_rst; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + aif_rst = wsa_priv->rx_port_value[widget->shift]; + if (!rx_port_value) { + if (aif_rst == 0) { + dev_err_ratelimited(wsa_dev, "%s: AIF reset already\n", __func__); + return 0; + } + if (aif_rst >= LPASS_CDC_WSA_MACRO_MAX_DAIS) { + dev_err_ratelimited(wsa_dev, "%s: Invalid AIF reset\n", __func__); + return 0; + } + } + wsa_priv->rx_port_value[widget->shift] = rx_port_value; + + bit_input = widget->shift; + + dev_dbg(wsa_dev, + "%s: mux input: %d, mux output: %d, bit: %d\n", + __func__, rx_port_value, widget->shift, bit_input); + + switch (rx_port_value) { + case 0: + if (wsa_priv->active_ch_cnt[aif_rst]) { + clear_bit(bit_input, + &wsa_priv->active_ch_mask[aif_rst]); + wsa_priv->active_ch_cnt[aif_rst]--; + } + break; + case 1: + case 2: + set_bit(bit_input, + &wsa_priv->active_ch_mask[rx_port_value]); + wsa_priv->active_ch_cnt[rx_port_value]++; + break; + default: + dev_err_ratelimited(wsa_dev, + "%s: Invalid AIF_ID for WSA RX MUX %d\n", + __func__, rx_port_value); + return -EINVAL; + } + + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + return 0; +} + +static int lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_func_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ucontrol->value.integer.value[0] = + ((snd_soc_component_read( + component, LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG) & 0x04) ? + 1 : 0); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_func_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + /* Set Vbat register configuration for GSM mode bit based on value */ + if (ucontrol->value.integer.value[0]) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG, + 0x04, 0x04); + else + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_VBAT_BCL_VBAT_CFG, + 0x04, 0x00); + + return 0; +} + +static int lpass_cdc_wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + int path = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->is_softclip_on[path]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + int path = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->is_softclip_on[path] = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: soft clip enable for %d: %d\n", __func__, + path, wsa_priv->is_softclip_on[path]); + + return 0; +} + +static int lpass_cdc_wsa_macro_pbr_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa_priv->pbr_enable; + return 0; +} + +static int lpass_cdc_wsa_macro_pbr_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->pbr_enable = ucontrol->value.integer.value[0]; + return 0; + +} + + +static const struct snd_kcontrol_new lpass_cdc_wsa_macro_snd_controls[] = { + SOC_ENUM_EXT("GSM mode Enable", lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_enum, + lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_func_get, + lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_func_put), + SOC_ENUM_EXT("WSA_RX0 comp_mode", lpass_cdc_wsa_macro_comp_mode_enum, + lpass_cdc_wsa_macro_comp_mode_get, + lpass_cdc_wsa_macro_comp_mode_put), + SOC_ENUM_EXT("WSA_RX1 comp_mode", lpass_cdc_wsa_macro_comp_mode_enum, + lpass_cdc_wsa_macro_comp_mode_get, + lpass_cdc_wsa_macro_comp_mode_put), + SOC_SINGLE_EXT("WSA SPKRRECV", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_wsa_macro_ear_spkrrecv_get, + lpass_cdc_wsa_macro_ear_spkrrecv_put), + SOC_SINGLE_EXT("Idle Detect", SND_SOC_NOPM, 0, 1, + 0, lpass_cdc_wsa_macro_idle_detect_get, + lpass_cdc_wsa_macro_idle_detect_put), + SOC_SINGLE_EXT("WSA_Softclip0 Enable", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_SOFTCLIP0, 1, 0, + lpass_cdc_wsa_macro_soft_clip_enable_get, + lpass_cdc_wsa_macro_soft_clip_enable_put), + SOC_SINGLE_EXT("WSA_Softclip1 Enable", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_SOFTCLIP1, 1, 0, + lpass_cdc_wsa_macro_soft_clip_enable_get, + lpass_cdc_wsa_macro_soft_clip_enable_put), + LPASS_CDC_WSA_MACRO_SET_VOLUME_TLV("WSA_RX0 Digital Volume", + LPASS_CDC_WSA_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + LPASS_CDC_WSA_MACRO_SET_VOLUME_TLV("WSA_RX1 Digital Volume", + LPASS_CDC_WSA_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_EXT("WSA_RX0 Digital Mute", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX0, 1, + 0, lpass_cdc_wsa_macro_get_rx_mute_status, + lpass_cdc_wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_RX1 Digital Mute", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX1, 1, + 0, lpass_cdc_wsa_macro_get_rx_mute_status, + lpass_cdc_wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_RX0_MIX Digital Mute", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_RX_MIX0, 1, 0, lpass_cdc_wsa_macro_get_rx_mute_status, + lpass_cdc_wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_RX1_MIX Digital Mute", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_RX_MIX1, 1, 0, lpass_cdc_wsa_macro_get_rx_mute_status, + lpass_cdc_wsa_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA_COMP1 Switch", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_COMP1, 1, 0, + lpass_cdc_wsa_macro_get_compander, lpass_cdc_wsa_macro_set_compander), + SOC_SINGLE_EXT("WSA_COMP2 Switch", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_COMP2, 1, 0, + lpass_cdc_wsa_macro_get_compander, lpass_cdc_wsa_macro_set_compander), + SOC_SINGLE_EXT("WSA_RX0 EC_HQ Switch", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX0, + 1, 0, lpass_cdc_wsa_macro_get_ec_hq, lpass_cdc_wsa_macro_set_ec_hq), + SOC_SINGLE_EXT("WSA_RX1 EC_HQ Switch", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX1, + 1, 0, lpass_cdc_wsa_macro_get_ec_hq, lpass_cdc_wsa_macro_set_ec_hq), + SOC_SINGLE_EXT("WSA PBR Enable", SND_SOC_NOPM, 0, 1, + 0, lpass_cdc_wsa_macro_pbr_enable_get, + lpass_cdc_wsa_macro_pbr_enable_put), +}; + +static const struct soc_enum rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_mux_text), rx_mux_text); + +static const struct snd_kcontrol_new rx_mux[LPASS_CDC_WSA_MACRO_RX_MAX] = { + SOC_DAPM_ENUM_EXT("WSA RX0 Mux", rx_mux_enum, + lpass_cdc_wsa_macro_rx_mux_get, lpass_cdc_wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX1 Mux", rx_mux_enum, + lpass_cdc_wsa_macro_rx_mux_get, lpass_cdc_wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX_MIX0 Mux", rx_mux_enum, + lpass_cdc_wsa_macro_rx_mux_get, lpass_cdc_wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX_MIX1 Mux", rx_mux_enum, + lpass_cdc_wsa_macro_rx_mux_get, lpass_cdc_wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX4 Mux", rx_mux_enum, + lpass_cdc_wsa_macro_rx_mux_get, lpass_cdc_wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX5 Mux", rx_mux_enum, + lpass_cdc_wsa_macro_rx_mux_get, lpass_cdc_wsa_macro_rx_mux_put), +}; + +static int lpass_cdc_wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 spk_tx_id = mixer->shift; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (test_bit(spk_tx_id, &wsa_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int lpass_cdc_wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 spk_tx_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->vi_feed_value = ucontrol->value.integer.value[0]; + + if (enable) { + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX0 && + !test_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + set_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI]); + wsa_priv->active_ch_cnt[LPASS_CDC_WSA_MACRO_AIF_VI]++; + } + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX1 && + !test_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + set_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI]); + wsa_priv->active_ch_cnt[LPASS_CDC_WSA_MACRO_AIF_VI]++; + } + } else { + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX0 && + test_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + clear_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI]); + wsa_priv->active_ch_cnt[LPASS_CDC_WSA_MACRO_AIF_VI]--; + } + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX1 && + test_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI])) { + clear_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[LPASS_CDC_WSA_MACRO_AIF_VI]); + wsa_priv->active_ch_cnt[LPASS_CDC_WSA_MACRO_AIF_VI]--; + } + } + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +static const struct snd_kcontrol_new aif_vi_mixer[] = { + SOC_SINGLE_EXT("WSA_SPKR_VI_1", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_TX0, 1, 0, + lpass_cdc_wsa_macro_vi_feed_mixer_get, + lpass_cdc_wsa_macro_vi_feed_mixer_put), + SOC_SINGLE_EXT("WSA_SPKR_VI_2", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_TX1, 1, 0, + lpass_cdc_wsa_macro_vi_feed_mixer_get, + lpass_cdc_wsa_macro_vi_feed_mixer_put), +}; + +static int lpass_cdc_wsa_macro_cps_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 spk_tx_id = mixer->shift; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (test_bit(spk_tx_id, &wsa_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int lpass_cdc_wsa_macro_cps_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 spk_tx_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (enable) { + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX0 && + !test_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[dai_id])) { + set_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[dai_id]); + wsa_priv->active_ch_cnt[dai_id]++; + } + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX1 && + !test_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[dai_id])) { + set_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[dai_id]); + wsa_priv->active_ch_cnt[dai_id]++; + } + } else { + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX0 && + test_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[dai_id])) { + clear_bit(LPASS_CDC_WSA_MACRO_TX0, + &wsa_priv->active_ch_mask[dai_id]); + wsa_priv->active_ch_cnt[dai_id]--; + } + if (spk_tx_id == LPASS_CDC_WSA_MACRO_TX1 && + test_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[dai_id])) { + clear_bit(LPASS_CDC_WSA_MACRO_TX1, + &wsa_priv->active_ch_mask[dai_id]); + wsa_priv->active_ch_cnt[dai_id]--; + } + } + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +static const struct snd_kcontrol_new aif_cps_mixer[] = { + SOC_SINGLE_EXT("WSA_SPKR_CPS_1", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_TX0, 1, 0, + lpass_cdc_wsa_macro_cps_feed_mixer_get, + lpass_cdc_wsa_macro_cps_feed_mixer_put), + SOC_SINGLE_EXT("WSA_SPKR_CPS_2", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_TX1, 1, 0, + lpass_cdc_wsa_macro_cps_feed_mixer_get, + lpass_cdc_wsa_macro_cps_feed_mixer_put), +}; + +static const struct snd_soc_dapm_widget lpass_cdc_wsa_macro_dapm_widgets_v2p6[] = { + + SND_SOC_DAPM_MUX_E("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp0_mux_v2p6, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp1_mux_v2p6, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp2_mux_v2p6, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, + 0, 0, &rx0_mix_mux_v2p6, lpass_cdc_wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp0_mux_v2p6, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp1_mux_v2p6, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp2_mux_v2p6, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, + 0, 0, &rx1_mix_mux_v2p6, lpass_cdc_wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget lpass_cdc_wsa_macro_dapm_widgets_v2p5[] = { + SND_SOC_DAPM_MUX_E("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp0_mux_v2p5, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp1_mux_v2p5, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp2_mux_v2p5, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, + 0, 0, &rx0_mix_mux_v2p5, lpass_cdc_wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp0_mux_v2p5, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp1_mux_v2p5, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp2_mux_v2p5, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, + 0, 0, &rx1_mix_mux_v2p5, lpass_cdc_wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_widget lpass_cdc_wsa_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("WSA AIF1 PB", "WSA_AIF1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("WSA AIF_MIX1 PB", "WSA_AIF_MIX1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT_E("WSA AIF_VI", "WSA_AIF_VI Capture", 0, + SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_AIF_VI, 0, + lpass_cdc_wsa_macro_disable_vi_feedback, + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT("WSA AIF_ECHO", "WSA_AIF_ECHO Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("WSA AIF_CPS", "WSA_AIF_CPS Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER("WSA_AIF_VI Mixer", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_AIF_VI, + 0, aif_vi_mixer, ARRAY_SIZE(aif_vi_mixer)), + SND_SOC_DAPM_MIXER("WSA_AIF_CPS Mixer", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_AIF_CPS, + 0, aif_cps_mixer, ARRAY_SIZE(aif_cps_mixer)), + SND_SOC_DAPM_MUX_E("WSA RX_MIX EC0_MUX", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_EC0_MUX, 0, + &rx_mix_ec0_mux, lpass_cdc_wsa_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA RX_MIX EC1_MUX", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_EC1_MUX, 0, + &rx_mix_ec1_mux, lpass_cdc_wsa_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("WSA RX0 MUX", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX0, 0, + &rx_mux[LPASS_CDC_WSA_MACRO_RX0]), + SND_SOC_DAPM_MUX("WSA RX1 MUX", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX1, 0, + &rx_mux[LPASS_CDC_WSA_MACRO_RX1]), + SND_SOC_DAPM_MUX("WSA RX_MIX0 MUX", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX_MIX0, 0, + &rx_mux[LPASS_CDC_WSA_MACRO_RX_MIX0]), + SND_SOC_DAPM_MUX("WSA RX_MIX1 MUX", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX_MIX1, 0, + &rx_mux[LPASS_CDC_WSA_MACRO_RX_MIX1]), + SND_SOC_DAPM_MUX("WSA RX4 MUX", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX4, 0, + &rx_mux[LPASS_CDC_WSA_MACRO_RX4]), + SND_SOC_DAPM_MUX("WSA RX5 MUX", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX5, 0, + &rx_mux[LPASS_CDC_WSA_MACRO_RX5]), + + SND_SOC_DAPM_MIXER("WSA RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA_E("WSA_RX INT0 MIX", SND_SOC_NOPM, + 0, 0, NULL, 0, lpass_cdc_wsa_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_E("WSA_RX INT1 MIX", SND_SOC_NOPM, + 1, 0, NULL, 0, lpass_cdc_wsa_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("WSA_RX0 INT0 SIDETONE MIX", + LPASS_CDC_WSA_RX0_RX_PATH_CFG1, 4, 0, + &rx0_sidetone_mix_mux, lpass_cdc_wsa_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_INPUT("WSA SRC0_INP"), + + SND_SOC_DAPM_INPUT("WSA_TX DEC0_INP"), + SND_SOC_DAPM_INPUT("WSA_TX DEC1_INP"), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 INTERP", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_COMP1, 0, NULL, 0, lpass_cdc_wsa_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 INTERP", SND_SOC_NOPM, + LPASS_CDC_WSA_MACRO_COMP2, 0, NULL, 0, lpass_cdc_wsa_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, lpass_cdc_wsa_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, lpass_cdc_wsa_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 VBAT", SND_SOC_NOPM, + 0, 0, wsa_int0_vbat_mix_switch, + ARRAY_SIZE(wsa_int0_vbat_mix_switch), + lpass_cdc_wsa_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 VBAT", SND_SOC_NOPM, + 0, 0, wsa_int1_vbat_mix_switch, + ARRAY_SIZE(wsa_int1_vbat_mix_switch), + lpass_cdc_wsa_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("VIINPUT_WSA"), + + SND_SOC_DAPM_INPUT("CPSINPUT_WSA"), + + SND_SOC_DAPM_OUTPUT("WSA_SPK1 OUT"), + SND_SOC_DAPM_OUTPUT("WSA_SPK2 OUT"), + + SND_SOC_DAPM_SUPPLY_S("WSA_MCLK", 0, SND_SOC_NOPM, 0, 0, + lpass_cdc_wsa_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route wsa_audio_map[] = { + /* VI Feedback */ + {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"}, + {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_2", "VIINPUT_WSA"}, + {"WSA AIF_VI", NULL, "WSA_AIF_VI Mixer"}, + {"WSA AIF_VI", NULL, "WSA_MCLK"}, + + /* CPS Feedback */ + {"WSA_AIF_CPS Mixer", "WSA_SPKR_CPS_1", "CPSINPUT_WSA"}, + {"WSA_AIF_CPS Mixer", "WSA_SPKR_CPS_2", "CPSINPUT_WSA"}, + {"WSA AIF_CPS", NULL, "WSA_AIF_CPS Mixer"}, + {"WSA AIF_CPS", NULL, "WSA_MCLK"}, + + {"WSA RX_MIX EC0_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"}, + {"WSA RX_MIX EC1_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"}, + {"WSA RX_MIX EC0_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"}, + {"WSA RX_MIX EC1_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"}, + {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC0_MUX"}, + {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC1_MUX"}, + {"WSA AIF_ECHO", NULL, "WSA_MCLK"}, + + {"WSA AIF1 PB", NULL, "WSA_MCLK"}, + {"WSA AIF_MIX1 PB", NULL, "WSA_MCLK"}, + + {"WSA RX0 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX1 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX_MIX0 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX_MIX1 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX4 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX5 MUX", "AIF1_PB", "WSA AIF1 PB"}, + + {"WSA RX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX_MIX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX_MIX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX4 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX5 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + + {"WSA RX0", NULL, "WSA RX0 MUX"}, + {"WSA RX1", NULL, "WSA RX1 MUX"}, + {"WSA RX_MIX0", NULL, "WSA RX_MIX0 MUX"}, + {"WSA RX_MIX1", NULL, "WSA RX_MIX1 MUX"}, + {"WSA RX4", NULL, "WSA RX4 MUX"}, + {"WSA RX5", NULL, "WSA RX5 MUX"}, + + {"WSA_RX0 INP0", "RX0", "WSA RX0"}, + {"WSA_RX0 INP0", "RX1", "WSA RX1"}, + {"WSA_RX0 INP0", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP0", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP0", "RX4", "WSA RX4"}, + {"WSA_RX0 INP0", "RX5", "WSA RX5"}, + {"WSA_RX0 INP0", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP0", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP0"}, + + {"WSA_RX0 INP1", "RX0", "WSA RX0"}, + {"WSA_RX0 INP1", "RX1", "WSA RX1"}, + {"WSA_RX0 INP1", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP1", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP1", "RX4", "WSA RX4"}, + {"WSA_RX0 INP1", "RX5", "WSA RX5"}, + {"WSA_RX0 INP1", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP1", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP1"}, + + {"WSA_RX0 INP2", "RX0", "WSA RX0"}, + {"WSA_RX0 INP2", "RX1", "WSA RX1"}, + {"WSA_RX0 INP2", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP2", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP2", "RX4", "WSA RX4"}, + {"WSA_RX0 INP2", "RX5", "WSA RX5"}, + {"WSA_RX0 INP2", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP2", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP2"}, + + {"WSA_RX0 MIX INP", "RX0", "WSA RX0"}, + {"WSA_RX0 MIX INP", "RX1", "WSA RX1"}, + {"WSA_RX0 MIX INP", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 MIX INP", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 MIX INP", "RX4", "WSA RX4"}, + {"WSA_RX0 MIX INP", "RX5", "WSA RX5"}, + {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX0 MIX INP"}, + + {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX INT0 MIX"}, + {"WSA_RX INT0 INTERP", NULL, "WSA_RX INT0 SEC MIX"}, + {"WSA_RX0 INT0 SIDETONE MIX", "SRC0", "WSA SRC0_INP"}, + {"WSA_RX INT0 INTERP", NULL, "WSA_RX0 INT0 SIDETONE MIX"}, + {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 INTERP"}, + + {"WSA_RX INT0 VBAT", "WSA RX0 VBAT Enable", "WSA_RX INT0 INTERP"}, + {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 VBAT"}, + + {"WSA_SPK1 OUT", NULL, "WSA_RX INT0 CHAIN"}, + {"WSA_SPK1 OUT", NULL, "WSA_MCLK"}, + + {"WSA_RX1 INP0", "RX0", "WSA RX0"}, + {"WSA_RX1 INP0", "RX1", "WSA RX1"}, + {"WSA_RX1 INP0", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP0", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP0", "RX4", "WSA RX4"}, + {"WSA_RX1 INP0", "RX5", "WSA RX5"}, + {"WSA_RX1 INP0", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP0", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP0"}, + + {"WSA_RX1 INP1", "RX0", "WSA RX0"}, + {"WSA_RX1 INP1", "RX1", "WSA RX1"}, + {"WSA_RX1 INP1", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP1", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP1", "RX4", "WSA RX4"}, + {"WSA_RX1 INP1", "RX5", "WSA RX5"}, + {"WSA_RX1 INP1", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP1", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP1"}, + + {"WSA_RX1 INP2", "RX0", "WSA RX0"}, + {"WSA_RX1 INP2", "RX1", "WSA RX1"}, + {"WSA_RX1 INP2", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP2", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP2", "RX4", "WSA RX4"}, + {"WSA_RX1 INP2", "RX5", "WSA RX5"}, + {"WSA_RX1 INP2", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP2", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP2"}, + + {"WSA_RX1 MIX INP", "RX0", "WSA RX0"}, + {"WSA_RX1 MIX INP", "RX1", "WSA RX1"}, + {"WSA_RX1 MIX INP", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 MIX INP", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 MIX INP", "RX4", "WSA RX4"}, + {"WSA_RX1 MIX INP", "RX5", "WSA RX5"}, + {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX1 MIX INP"}, + + {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX INT1 MIX"}, + {"WSA_RX INT1 INTERP", NULL, "WSA_RX INT1 SEC MIX"}, + + {"WSA_RX INT1 VBAT", "WSA RX1 VBAT Enable", "WSA_RX INT1 INTERP"}, + {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 VBAT"}, + + {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 INTERP"}, + {"WSA_SPK2 OUT", NULL, "WSA_RX INT1 CHAIN"}, + {"WSA_SPK2 OUT", NULL, "WSA_MCLK"}, +}; + +static void lpass_cdc_wsa_macro_init_pbr(struct snd_soc_component *component) +{ + int sys_gain, bat_cfg, rload; + int vth1, vth2, vth3, vth4, vth5, vth6, vth7, vth8, vth9; + int vth10, vth11, vth12, vth13, vth14, vth15; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return; + + /* RX0 */ + sys_gain = wsa_priv->wsa_sys_gain[0]; + bat_cfg = wsa_priv->wsa_bat_cfg[0]; + rload = wsa_priv->wsa_rload[0]; + /* ILIM */ + switch (rload) { + case WSA_4_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0, 0xE0, 0x40); + break; + case WSA_6_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0, 0xE0, 0x80); + break; + case WSA_8_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0, 0xE0, 0xC0); + break; + case WSA_32_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0, 0xE0, 0xE0); + break; + default: + break; + } + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG1, 0x0F, sys_gain); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG9, 0xC0, (bat_cfg - 1) << 0x6); + /* Thesh */ + vth1 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth1_data[sys_gain][bat_cfg][rload]); + vth2 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth2_data[sys_gain][bat_cfg][rload]); + vth3 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth3_data[sys_gain][bat_cfg][rload]); + vth4 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth4_data[sys_gain][bat_cfg][rload]); + vth5 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth5_data[sys_gain][bat_cfg][rload]); + vth6 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth6_data[sys_gain][bat_cfg][rload]); + vth7 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth7_data[sys_gain][bat_cfg][rload]); + vth8 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth8_data[sys_gain][bat_cfg][rload]); + vth9 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth9_data[sys_gain][bat_cfg][rload]); + vth10 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth10_data[sys_gain][bat_cfg][rload]); + vth11 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth11_data[sys_gain][bat_cfg][rload]); + vth12 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth12_data[sys_gain][bat_cfg][rload]); + vth13 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth13_data[sys_gain][bat_cfg][rload]); + vth14 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth14_data[sys_gain][bat_cfg][rload]); + vth15 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth15_data[sys_gain][bat_cfg][rload]); + + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG1, vth1); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG2, vth2); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG3, vth3); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG4, vth4); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG5, vth5); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG6, vth6); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG7, vth7); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG8, vth8); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG9, vth9); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG10, vth10); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG11, vth11); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG12, vth12); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG13, vth13); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG14, vth14); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG15, vth15); + + /* RX1 */ + sys_gain = wsa_priv->wsa_sys_gain[2]; + bat_cfg = wsa_priv->wsa_bat_cfg[1]; + rload = wsa_priv->wsa_rload[1]; + /* ILIM */ + switch (rload) { + case WSA_4_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0_1, 0xE0, 0x40); + break; + case WSA_6_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0_1, 0xE0, 0x80); + break; + case WSA_8_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0_1, 0xE0, 0xC0); + break; + case WSA_32_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG0_1, 0xE0, 0xE0); + break; + default: + break; + } + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG1_1, 0x0F, sys_gain); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA_ILIM_CFG9, 0x30, (bat_cfg - 1) << 0x4); + /* Thesh */ + vth1 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth1_data[sys_gain][bat_cfg][rload]); + vth2 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth2_data[sys_gain][bat_cfg][rload]); + vth3 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth3_data[sys_gain][bat_cfg][rload]); + vth4 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth4_data[sys_gain][bat_cfg][rload]); + vth5 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth5_data[sys_gain][bat_cfg][rload]); + vth6 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth6_data[sys_gain][bat_cfg][rload]); + vth7 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth7_data[sys_gain][bat_cfg][rload]); + vth8 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth8_data[sys_gain][bat_cfg][rload]); + vth9 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth9_data[sys_gain][bat_cfg][rload]); + vth10 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth10_data[sys_gain][bat_cfg][rload]); + vth11 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth11_data[sys_gain][bat_cfg][rload]); + vth12 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth12_data[sys_gain][bat_cfg][rload]); + vth13 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth13_data[sys_gain][bat_cfg][rload]); + vth14 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth14_data[sys_gain][bat_cfg][rload]); + vth15 = LPASS_CDC_WSA_MACRO_VTH_TO_REG(pbr_vth15_data[sys_gain][bat_cfg][rload]); + + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG1_1, vth1); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG2_1, vth2); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG3_1, vth3); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG4_1, vth4); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG5_1, vth5); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG6_1, vth6); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG7_1, vth7); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG8_1, vth8); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG9_1, vth9); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG10_1, vth10); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG11_1, vth11); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG12_1, vth12); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG13_1, vth13); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG14_1, vth14); + snd_soc_component_write(component, LPASS_CDC_WSA_PBR_CFG15_1, vth15); +} + +static const struct lpass_cdc_wsa_macro_reg_mask_val + lpass_cdc_wsa_macro_reg_init[] = { + {LPASS_CDC_WSA_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {LPASS_CDC_WSA_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {LPASS_CDC_WSA_COMPANDER0_CTL7, 0x3E, 0x2e}, + {LPASS_CDC_WSA_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {LPASS_CDC_WSA_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {LPASS_CDC_WSA_COMPANDER1_CTL7, 0x3E, 0x2e}, + {LPASS_CDC_WSA_BOOST0_BOOST_CTL, 0x70, 0x58}, + {LPASS_CDC_WSA_BOOST1_BOOST_CTL, 0x70, 0x58}, + {LPASS_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08}, + {LPASS_CDC_WSA_RX1_RX_PATH_CFG1, 0x08, 0x08}, + {LPASS_CDC_WSA_TOP_TOP_CFG1, 0x02, 0x02}, + {LPASS_CDC_WSA_TOP_TOP_CFG1, 0x01, 0x01}, + {LPASS_CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA_RX0_RX_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA_RX1_RX_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {LPASS_CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {LPASS_CDC_WSA_LA_CFG, 0x3F, 0xF}, + {LPASS_CDC_WSA_PBR_CFG16, 0xFF, 0x42}, + {LPASS_CDC_WSA_PBR_CFG19, 0xFF, 0xFC}, + {LPASS_CDC_WSA_PBR_CFG20, 0xF0, 0x60}, + {LPASS_CDC_WSA_ILIM_CFG1, 0x70, 0x40}, + {LPASS_CDC_WSA_ILIM_CFG0, 0x03, 0x01}, + {LPASS_CDC_WSA_ILIM_CFG3, 0x1F, 0x15}, + {LPASS_CDC_WSA_LA_CFG_1, 0x3F, 0x0F}, + {LPASS_CDC_WSA_PBR_CFG16_1, 0xFF, 0x42}, + {LPASS_CDC_WSA_PBR_CFG21, 0xFF, 0xFC}, + {LPASS_CDC_WSA_PBR_CFG22, 0xF0, 0x60}, + {LPASS_CDC_WSA_ILIM_CFG1_1, 0x70, 0x40}, + {LPASS_CDC_WSA_ILIM_CFG0_1, 0x03, 0x01}, + {LPASS_CDC_WSA_ILIM_CFG4, 0x1F, 0x15}, + {LPASS_CDC_WSA_ILIM_CFG2_1, 0xFF, 0x2A}, + {LPASS_CDC_WSA_ILIM_CFG2, 0x3F, 0x1B}, + {LPASS_CDC_WSA_ILIM_CFG9, 0x0F, 0x05}, + {LPASS_CDC_WSA_IDLE_DETECT_CFG1, 0xFF, 0x1D}, +}; + +static void lpass_cdc_wsa_macro_init_reg(struct snd_soc_component *component) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lpass_cdc_wsa_macro_reg_init); i++) + snd_soc_component_update_bits(component, + lpass_cdc_wsa_macro_reg_init[i].reg, + lpass_cdc_wsa_macro_reg_init[i].mask, + lpass_cdc_wsa_macro_reg_init[i].val); + lpass_cdc_wsa_macro_init_pbr(component); +} + +static int lpass_cdc_wsa_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct lpass_cdc_wsa_macro_priv *wsa_priv = (struct lpass_cdc_wsa_macro_priv *) handle; + + if (wsa_priv == NULL) { + pr_err_ratelimited("%s: wsa priv data is NULL\n", __func__); + return -EINVAL; + } + if (!wsa_priv->pre_dev_up && enable) { + pr_debug("%s: adsp is not up\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(wsa_priv->dev); + if (lpass_cdc_check_core_votes(wsa_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(wsa_priv->dev); + pm_runtime_mark_last_busy(wsa_priv->dev); + } + + return rc; +} + +static int wsa_swrm_clock(void *handle, bool enable) +{ + struct lpass_cdc_wsa_macro_priv *wsa_priv = (struct lpass_cdc_wsa_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(wsa_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(wsa_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&wsa_priv->swr_clk_lock); + + dev_dbg(wsa_priv->dev, "%s: swrm clock %s\n", + __func__, (enable ? "enable" : "disable")); + if (enable) { + pm_runtime_get_sync(wsa_priv->dev); + if (wsa_priv->swr_clk_users == 0) { + ret = msm_cdc_pinctrl_select_active_state( + wsa_priv->wsa_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa swr pinctrl enable failed\n", + __func__); + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + goto exit; + } + ret = lpass_cdc_wsa_macro_mclk_enable(wsa_priv, 1, true); + if (ret < 0) { + msm_cdc_pinctrl_select_sleep_state( + wsa_priv->wsa_swr_gpio_p); + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa request clock enable failed\n", + __func__); + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + goto exit; + } + if (wsa_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (wsa_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x1C, 0x0C); + wsa_priv->reset_swr = false; + } + wsa_priv->swr_clk_users++; + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); + } else { + if (wsa_priv->swr_clk_users <= 0) { + dev_err_ratelimited(wsa_priv->dev, "%s: clock already disabled\n", + __func__); + wsa_priv->swr_clk_users = 0; + goto exit; + } + wsa_priv->swr_clk_users--; + if (wsa_priv->swr_clk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + lpass_cdc_wsa_macro_mclk_enable(wsa_priv, 0, true); + ret = msm_cdc_pinctrl_select_sleep_state( + wsa_priv->wsa_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(wsa_priv->dev, + "%s: wsa swr pinctrl disable failed\n", + __func__); + goto exit; + } + } + } + dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n", + __func__, wsa_priv->swr_clk_users); +exit: + mutex_unlock(&wsa_priv->swr_clk_lock); + return ret; +} + +/* Thermal Functions */ +static int lpass_cdc_wsa_macro_get_max_state( + struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct lpass_cdc_wsa_macro_priv *wsa_priv = cdev->devdata; + if (!wsa_priv) { + pr_err_ratelimited("%s: cdev->devdata is NULL\n", __func__); + return -EINVAL; + } + *state = wsa_priv->thermal_max_state; + + return 0; +} + +static int lpass_cdc_wsa_macro_get_cur_state( + struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct lpass_cdc_wsa_macro_priv *wsa_priv = cdev->devdata; + + if (!wsa_priv) { + pr_err_ratelimited("%s: cdev->devdata is NULL\n", __func__); + return -EINVAL; + } + *state = wsa_priv->thermal_cur_state; + + pr_debug("%s: thermal current state:%lu\n", __func__, *state); + return 0; +} + +static int lpass_cdc_wsa_macro_set_cur_state( + struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct lpass_cdc_wsa_macro_priv *wsa_priv = cdev->devdata; + + if (!wsa_priv || !wsa_priv->dev) { + pr_err_ratelimited("%s: cdev->devdata is NULL\n", __func__); + return -EINVAL; + } + + if (state <= wsa_priv->thermal_max_state) { + wsa_priv->thermal_cur_state = state; + } else { + dev_err_ratelimited(wsa_priv->dev, + "%s: incorrect requested state:%d\n", + __func__, state); + return -EINVAL; + } + + dev_dbg(wsa_priv->dev, + "%s: set the thermal current state to %d\n", + __func__, wsa_priv->thermal_cur_state); + + schedule_work(&wsa_priv->lpass_cdc_wsa_macro_cooling_work); + + return 0; +} + +static struct thermal_cooling_device_ops wsa_cooling_ops = { + .get_max_state = lpass_cdc_wsa_macro_get_max_state, + .get_cur_state = lpass_cdc_wsa_macro_get_cur_state, + .set_cur_state = lpass_cdc_wsa_macro_set_cur_state, +}; + +static int lpass_cdc_wsa_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret; + u32 version; + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + wsa_dev = lpass_cdc_get_device_ptr(component->dev, WSA_MACRO); + if (!wsa_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + wsa_priv = dev_get_drvdata(wsa_dev); + if (!wsa_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + + ret = snd_soc_dapm_new_controls(dapm, lpass_cdc_wsa_macro_dapm_widgets, + ARRAY_SIZE(lpass_cdc_wsa_macro_dapm_widgets)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add controls\n", __func__); + return ret; + } + + version = lpass_cdc_get_version(wsa_dev); + + if (version <= LPASS_CDC_VERSION_2_5) { + ret = snd_soc_dapm_new_controls(dapm, lpass_cdc_wsa_macro_dapm_widgets_v2p5, + ARRAY_SIZE(lpass_cdc_wsa_macro_dapm_widgets_v2p5)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add lpass v2p5 controls\n", __func__); + return ret; + } + } else { + ret = snd_soc_dapm_new_controls(dapm, lpass_cdc_wsa_macro_dapm_widgets_v2p6, + ARRAY_SIZE(lpass_cdc_wsa_macro_dapm_widgets_v2p6)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add lpass v2p6 controls\n", __func__); + return ret; + } + } + + ret = snd_soc_dapm_add_routes(dapm, wsa_audio_map, + ARRAY_SIZE(wsa_audio_map)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add routes\n", __func__); + return ret; + } + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add widgets\n", __func__); + return ret; + } + + ret = snd_soc_add_component_controls(component, lpass_cdc_wsa_macro_snd_controls, + ARRAY_SIZE(lpass_cdc_wsa_macro_snd_controls)); + if (ret < 0) { + dev_err(wsa_dev, "%s: Failed to add snd_ctls\n", __func__); + return ret; + } + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_MIX1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_VI Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_ECHO Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_AIF_CPS Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK1 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_SPK2 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_WSA"); + snd_soc_dapm_ignore_suspend(dapm, "CPSINPUT_WSA"); + snd_soc_dapm_ignore_suspend(dapm, "WSA SRC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_TX DEC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "WSA_TX DEC1_INP"); + snd_soc_dapm_sync(dapm); + + wsa_priv->component = component; + wsa_priv->spkr_gain_offset = LPASS_CDC_WSA_MACRO_GAIN_OFFSET_0_DB; + lpass_cdc_wsa_macro_init_reg(component); + + return 0; +} + +static int lpass_cdc_wsa_macro_deinit(struct snd_soc_component *component) +{ + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + wsa_priv->component = NULL; + + return 0; +} + +static void lpass_cdc_wsa_macro_add_child_devices(struct work_struct *work) +{ + struct lpass_cdc_wsa_macro_priv *wsa_priv; + struct platform_device *pdev; + struct device_node *node; + struct lpass_cdc_wsa_macro_swr_ctrl_data *swr_ctrl_data = NULL, *temp; + int ret; + u16 count = 0, ctrl_num = 0; + struct lpass_cdc_wsa_macro_swr_ctrl_platform_data *platdata; + char plat_dev_name[LPASS_CDC_WSA_MACRO_SWR_STRING_LEN]; + + wsa_priv = container_of(work, struct lpass_cdc_wsa_macro_priv, + lpass_cdc_wsa_macro_add_child_devices_work); + if (!wsa_priv) { + pr_err("%s: Memory for wsa_priv does not exist\n", + __func__); + return; + } + if (!wsa_priv->dev || !wsa_priv->dev->of_node) { + dev_err(wsa_priv->dev, + "%s: DT node for wsa_priv does not exist\n", __func__); + return; + } + + platdata = &wsa_priv->swr_plat_data; + wsa_priv->child_count = 0; + + for_each_available_child_of_node(wsa_priv->dev->of_node, node) { + if (strnstr(node->name, "wsa_swr_master", + strlen("wsa_swr_master")) != NULL) + strlcpy(plat_dev_name, "wsa_swr_ctrl", + (LPASS_CDC_WSA_MACRO_SWR_STRING_LEN - 1)); + else if (strnstr(node->name, "msm_cdc_pinctrl", + strlen("msm_cdc_pinctrl")) != NULL) + strlcpy(plat_dev_name, node->name, + (LPASS_CDC_WSA_MACRO_SWR_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(wsa_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = wsa_priv->dev; + pdev->dev.of_node = node; + + if (strnstr(node->name, "wsa_swr_master", + strlen("wsa_swr_master")) != NULL) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct lpass_cdc_wsa_macro_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(&pdev->dev, "out of memory\n"); + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].wsa_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + wsa_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (wsa_priv->child_count < LPASS_CDC_WSA_MACRO_CHILD_DEVICES_MAX) + wsa_priv->pdev_child_devices[ + wsa_priv->child_count++] = pdev; + else + goto err; + } + + return; +fail_pdev_add: + for (count = 0; count < wsa_priv->child_count; count++) + platform_device_put(wsa_priv->pdev_child_devices[count]); +err: + return; +} + +static void lpass_cdc_wsa_macro_cooling_adjust_gain(struct work_struct *work) +{ + struct lpass_cdc_wsa_macro_priv *wsa_priv; + u8 gain = 0; + + wsa_priv = container_of(work, struct lpass_cdc_wsa_macro_priv, + lpass_cdc_wsa_macro_cooling_work); + if (!wsa_priv) { + pr_err("%s: priv is null for macro!\n", + __func__); + return; + } + if (!wsa_priv->dev || !wsa_priv->dev->of_node) { + dev_err(wsa_priv->dev, + "%s: DT node for wsa_priv does not exist\n", __func__); + return; + } + + /* Only adjust the volume when WSA clock is enabled */ + if (wsa_priv->dapm_mclk_enable) { + gain = (u8)(wsa_priv->rx0_origin_gain - + wsa_priv->thermal_cur_state); + snd_soc_component_update_bits(wsa_priv->component, + LPASS_CDC_WSA_RX0_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa_priv->dev, + "%s: RX0 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa_priv->thermal_cur_state, gain); + + gain = (u8)(wsa_priv->rx1_origin_gain - + wsa_priv->thermal_cur_state); + snd_soc_component_update_bits(wsa_priv->component, + LPASS_CDC_WSA_RX1_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa_priv->dev, + "%s: RX1 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa_priv->thermal_cur_state, gain); + } + + return; +} + +static int lpass_cdc_wsa_macro_read_array(struct platform_device *pdev, + const char *name, int num_values, + u32 *output) +{ + u32 len, ret, size; + + if (!of_find_property(pdev->dev.of_node, name, &size)) { + dev_info(&pdev->dev, "%s: missing %s\n", __func__, name); + return 0; + } + + len = size / sizeof(u32); + if (len != num_values) { + dev_info(&pdev->dev, "%s: invalid number of %s\n", __func__, name); + return -EINVAL; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, name, output, len); + if (ret) + dev_info(&pdev->dev, "%s: Failed to read %s\n", __func__, name); + + return 0; + +} + +static void lpass_cdc_wsa_macro_init_ops(struct macro_ops *ops, + char __iomem *wsa_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->init = lpass_cdc_wsa_macro_init; + ops->exit = lpass_cdc_wsa_macro_deinit; + ops->io_base = wsa_io_base; + ops->dai_ptr = lpass_cdc_wsa_macro_dai; + ops->num_dais = ARRAY_SIZE(lpass_cdc_wsa_macro_dai); + ops->event_handler = lpass_cdc_wsa_macro_event_handler; + ops->set_port_map = lpass_cdc_wsa_macro_set_port_map; +} + +static int lpass_cdc_wsa_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops; + struct lpass_cdc_wsa_macro_priv *wsa_priv; + u32 wsa_base_addr, default_clk_id, thermal_max_state; + char __iomem *wsa_io_base; + int ret = 0; + u32 is_used_wsa_swr_gpio = 1; + u32 noise_gate_mode; + const char *is_used_wsa_swr_gpio_dt = "qcom,is-used-swr-gpio"; + + if (!lpass_cdc_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + + wsa_priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_wsa_macro_priv), + GFP_KERNEL); + if (!wsa_priv) + return -ENOMEM; + + wsa_priv->pre_dev_up = true; + wsa_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &wsa_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, "wsa_data_fs_ctl_reg", + &wsa_priv->wsa_fs_ctl_reg); + if (ret) { + dev_dbg(&pdev->dev, "%s: error finding %s entry in dt\n", + __func__, "wsa_data_fs_ctl_reg"); + } + + if (!wsa_priv->wsa_fs_reg_base && wsa_priv->wsa_fs_ctl_reg) + wsa_priv->wsa_fs_reg_base = devm_ioremap(&pdev->dev, + wsa_priv->wsa_fs_ctl_reg, LPASS_CDC_WSA_MACRO_MAX_OFFSET); + + if (of_find_property(pdev->dev.of_node, is_used_wsa_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_wsa_swr_gpio_dt, + &is_used_wsa_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_wsa_swr_gpio_dt); + is_used_wsa_swr_gpio = 1; + } + } + wsa_priv->wsa_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,wsa-swr-gpios", 0); + if (!wsa_priv->wsa_swr_gpio_p && is_used_wsa_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if (msm_cdc_pinctrl_get_state(wsa_priv->wsa_swr_gpio_p) < 0 && + is_used_wsa_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + msm_cdc_pinctrl_set_wakeup_capable( + wsa_priv->wsa_swr_gpio_p, false); + + wsa_io_base = devm_ioremap(&pdev->dev, + wsa_base_addr, LPASS_CDC_WSA_MACRO_MAX_OFFSET); + if (!wsa_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -EINVAL; + } + + lpass_cdc_wsa_macro_read_array(pdev, "qcom,wsa-rloads", + LPASS_CDC_WSA_MACRO_RX1 + 1, wsa_priv->wsa_rload); + lpass_cdc_wsa_macro_read_array(pdev, "qcom,wsa-system-gains", + 2 * (LPASS_CDC_WSA_MACRO_RX1 + 1), wsa_priv->wsa_sys_gain); + lpass_cdc_wsa_macro_read_array(pdev, "qcom,wsa-bat-cfgs", + LPASS_CDC_WSA_MACRO_RX1 + 1, wsa_priv->wsa_bat_cfg); + + + wsa_priv->wsa_io_base = wsa_io_base; + wsa_priv->reset_swr = true; + INIT_WORK(&wsa_priv->lpass_cdc_wsa_macro_add_child_devices_work, + lpass_cdc_wsa_macro_add_child_devices); + INIT_WORK(&wsa_priv->lpass_cdc_wsa_macro_cooling_work, + lpass_cdc_wsa_macro_cooling_adjust_gain); + wsa_priv->swr_plat_data.handle = (void *) wsa_priv; + wsa_priv->swr_plat_data.read = NULL; + wsa_priv->swr_plat_data.write = NULL; + wsa_priv->swr_plat_data.bulk_write = NULL; + wsa_priv->swr_plat_data.clk = wsa_swrm_clock; + wsa_priv->swr_plat_data.core_vote = lpass_cdc_wsa_macro_core_vote; + wsa_priv->swr_plat_data.handle_irq = NULL; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id", + &default_clk_id); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,mux0-clk-id"); + default_clk_id = WSA_CORE_CLK; + } + + wsa_priv->default_clk_id = default_clk_id; + + dev_set_drvdata(&pdev->dev, wsa_priv); + mutex_init(&wsa_priv->mclk_lock); + mutex_init(&wsa_priv->swr_clk_lock); + lpass_cdc_wsa_macro_init_ops(&ops, wsa_io_base); + ops.clk_id_req = wsa_priv->default_clk_id; + ops.default_clk_id = wsa_priv->default_clk_id; + + ret = lpass_cdc_register_macro(&pdev->dev, WSA_MACRO, &ops); + if (ret < 0) { + dev_err(&pdev->dev, "%s: register macro failed\n", __func__); + goto reg_macro_fail; + } + + if (of_find_property(wsa_priv->dev->of_node, "#cooling-cells", NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,thermal-max-state", + &thermal_max_state); + if (ret) { + dev_info(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,thermal-max-state"); + wsa_priv->thermal_max_state = + LPASS_CDC_WSA_MACRO_THERMAL_MAX_STATE; + } else { + wsa_priv->thermal_max_state = thermal_max_state; + } + wsa_priv->tcdev = devm_thermal_of_cooling_device_register( + &pdev->dev, + wsa_priv->dev->of_node, + "wsa", wsa_priv, + &wsa_cooling_ops); + if (IS_ERR(wsa_priv->tcdev)) { + dev_err(&pdev->dev, + "%s: failed to register wsa macro as cooling device\n", + __func__); + wsa_priv->tcdev = NULL; + } + } + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,noise-gate-mode", &noise_gate_mode); + if (ret) { + dev_info(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,noise-gate-mode"); + wsa_priv->noise_gate_mode = IDLE_DETECT; + } else { + if (noise_gate_mode >= IDLE_DETECT && noise_gate_mode <= NG3) + wsa_priv->noise_gate_mode = noise_gate_mode; + else + wsa_priv->noise_gate_mode = IDLE_DETECT; + } + + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + schedule_work(&wsa_priv->lpass_cdc_wsa_macro_add_child_devices_work); + return ret; +reg_macro_fail: + mutex_destroy(&wsa_priv->mclk_lock); + mutex_destroy(&wsa_priv->swr_clk_lock); + return ret; +} + +static int lpass_cdc_wsa_macro_remove(struct platform_device *pdev) +{ + struct lpass_cdc_wsa_macro_priv *wsa_priv; + u16 count = 0; + + wsa_priv = dev_get_drvdata(&pdev->dev); + + if (!wsa_priv) + return -EINVAL; + + if (wsa_priv->tcdev) + thermal_cooling_device_unregister(wsa_priv->tcdev); + + for (count = 0; count < wsa_priv->child_count && + count < LPASS_CDC_WSA_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister(wsa_priv->pdev_child_devices[count]); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + lpass_cdc_unregister_macro(&pdev->dev, WSA_MACRO); + mutex_destroy(&wsa_priv->mclk_lock); + mutex_destroy(&wsa_priv->swr_clk_lock); + return 0; +} + +static const struct of_device_id lpass_cdc_wsa_macro_dt_match[] = { + {.compatible = "qcom,lpass-cdc-wsa-macro"}, + {} +}; + +static const struct dev_pm_ops lpass_cdc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + lpass_cdc_runtime_suspend, + lpass_cdc_runtime_resume, + NULL + ) +}; + +static struct platform_driver lpass_cdc_wsa_macro_driver = { + .driver = { + .name = "lpass_cdc_wsa_macro", + .owner = THIS_MODULE, + .pm = &lpass_cdc_dev_pm_ops, + .of_match_table = lpass_cdc_wsa_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_cdc_wsa_macro_probe, + .remove = lpass_cdc_wsa_macro_remove, +}; + +module_platform_driver(lpass_cdc_wsa_macro_driver); + +MODULE_DESCRIPTION("WSA macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.h b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.h new file mode 100644 index 0000000000..9bf247d6ed --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ +#ifndef LPASS_CDC_WSA_MACRO_H +#define LPASS_CDC_WSA_MACRO_H + +/* + * Selects compander and smart boost settings + * for a given speaker mode + */ +enum { + LPASS_CDC_WSA_MACRO_SPKR_MODE_DEFAULT, + LPASS_CDC_WSA_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */ +}; + +/* Rx path gain offsets */ +enum { + LPASS_CDC_WSA_MACRO_GAIN_OFFSET_M1P5_DB, + LPASS_CDC_WSA_MACRO_GAIN_OFFSET_0_DB, +}; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c new file mode 100644 index 0000000000..5db4e6bc3d --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c @@ -0,0 +1,4100 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "lpass-cdc.h" +#include "lpass-cdc-comp.h" +#include "lpass-cdc-registers.h" +#include "lpass-cdc-wsa2-macro.h" +#include "lpass-cdc-clk-rsc.h" + +#define AUTO_SUSPEND_DELAY 50 /* delay in msec */ +#define LPASS_CDC_WSA2_MACRO_MAX_OFFSET 0x1000 + +#define LPASS_CDC_WSA2_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define LPASS_CDC_WSA2_MACRO_RX_MIX_RATES (SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define LPASS_CDC_WSA2_MACRO_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define LPASS_CDC_WSA2_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_48000) +#define LPASS_CDC_WSA2_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define LPASS_CDC_WSA2_MACRO_CPS_RATES (SNDRV_PCM_RATE_48000) +#define LPASS_CDC_WSA2_MACRO_CPS_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) + +#define NUM_INTERPOLATORS 2 + +#define LPASS_CDC_WSA2_MACRO_MUX_INP_SHFT 0x3 +#define LPASS_CDC_WSA2_MACRO_MUX_INP_MASK1 0x07 +#define LPASS_CDC_WSA2_MACRO_MUX_INP_MASK2 0x38 +#define LPASS_CDC_WSA2_MACRO_MUX_CFG_OFFSET 0x8 +#define LPASS_CDC_WSA2_MACRO_MUX_CFG1_OFFSET 0x4 +#define LPASS_CDC_WSA2_MACRO_RX_COMP_OFFSET \ + (LPASS_CDC_WSA2_COMPANDER1_CTL0 - LPASS_CDC_WSA2_COMPANDER0_CTL0) +#define LPASS_CDC_WSA2_MACRO_RX_SOFTCLIP_OFFSET \ + (LPASS_CDC_WSA2_SOFTCLIP1_CRC - LPASS_CDC_WSA2_SOFTCLIP0_CRC) +#define LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET \ + (LPASS_CDC_WSA2_RX1_RX_PATH_CTL - LPASS_CDC_WSA2_RX0_RX_PATH_CTL) +#define LPASS_CDC_WSA2_MACRO_RX_PATH_CFG3_OFFSET 0x10 +#define LPASS_CDC_WSA2_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C +#define LPASS_CDC_WSA2_MACRO_FS_RATE_MASK 0x0F +#define LPASS_CDC_WSA2_MACRO_EC_MIX_TX0_MASK 0x03 +#define LPASS_CDC_WSA2_MACRO_EC_MIX_TX1_MASK 0x18 + +#define LPASS_CDC_WSA2_MACRO_MAX_DMA_CH_PER_PORT 0x2 +#define LPASS_CDC_WSA2_MACRO_THERMAL_MAX_STATE 11 + +enum { + LPASS_CDC_WSA2_MACRO_RX0 = 0, + LPASS_CDC_WSA2_MACRO_RX1, + LPASS_CDC_WSA2_MACRO_RX_MIX, + LPASS_CDC_WSA2_MACRO_RX_MIX0 = LPASS_CDC_WSA2_MACRO_RX_MIX, + LPASS_CDC_WSA2_MACRO_RX_MIX1, + LPASS_CDC_WSA2_MACRO_RX4, + LPASS_CDC_WSA2_MACRO_RX5, + LPASS_CDC_WSA2_MACRO_RX6, + LPASS_CDC_WSA2_MACRO_RX7, + LPASS_CDC_WSA2_MACRO_RX8, + LPASS_CDC_WSA2_MACRO_RX_MAX, +}; + +enum { + LPASS_CDC_WSA2_MACRO_TX0 = 0, + LPASS_CDC_WSA2_MACRO_TX1, + LPASS_CDC_WSA2_MACRO_TX_MAX, +}; + +enum { + LPASS_CDC_WSA2_MACRO_EC0_MUX = 0, + LPASS_CDC_WSA2_MACRO_EC1_MUX, + LPASS_CDC_WSA2_MACRO_EC_MUX_MAX, +}; + +enum { + LPASS_CDC_WSA2_MACRO_COMP1, /* SPK_L */ + LPASS_CDC_WSA2_MACRO_COMP2, /* SPK_R */ + LPASS_CDC_WSA2_MACRO_COMP_MAX +}; + +enum { + LPASS_CDC_WSA2_MACRO_SOFTCLIP0, /* RX0 */ + LPASS_CDC_WSA2_MACRO_SOFTCLIP1, /* RX1 */ + LPASS_CDC_WSA2_MACRO_SOFTCLIP_MAX +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_RX4, + INTn_1_INP_SEL_RX5, + INTn_1_INP_SEL_RX6, + INTn_1_INP_SEL_RX7, + INTn_1_INP_SEL_RX8, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_RX8, +}; + +enum { + IDLE_DETECT, + NG1, + NG2, + NG3, +}; + +static struct lpass_cdc_comp_setting comp_setting_table[G_MAX_DB] = { + {42, 0, 42}, + {39, 0, 42}, + {36, 0, 42}, + {33, 0, 42}, + {30, 0, 42}, + {27, 0, 42}, + {24, 0, 42}, + {21, 0, 42}, + {18, 0, 42}, +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +/* + * Structure used to update codec + * register defaults after reset + */ +struct lpass_cdc_wsa2_macro_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static struct interp_sample_rate int_prim_sample_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +static struct interp_sample_rate int_mix_sample_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +#define LPASS_CDC_WSA2_MACRO_SWR_STRING_LEN 80 + +static int lpass_cdc_wsa2_macro_core_vote(void *handle, bool enable); +static int lpass_cdc_wsa2_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); +static int lpass_cdc_wsa2_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot); +static int lpass_cdc_wsa2_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream); + +#define LPASS_CDC_WSA2_MACRO_VTH_TO_REG(vth) ((vth) == 0 ? 255 : (vth)) +/* Hold instance to soundwire platform device */ +struct lpass_cdc_wsa2_macro_swr_ctrl_data { + struct platform_device *wsa2_swr_pdev; +}; +static int lpass_cdc_wsa2_macro_enable_vi_decimator(struct snd_soc_component *component); + +#define LPASS_CDC_WSA2_MACRO_SET_VOLUME_TLV(xname, xreg, xmin, xmax, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = lpass_cdc_wsa2_macro_set_digital_volume, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg, .rreg = xreg, \ + .min = xmin, .max = xmax, \ + .sign_bit = 7,} } + +struct lpass_cdc_wsa2_macro_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*core_vote)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +enum { + LPASS_CDC_WSA2_MACRO_AIF_INVALID = 0, + LPASS_CDC_WSA2_MACRO_AIF1_PB, + LPASS_CDC_WSA2_MACRO_AIF_MIX1_PB, + LPASS_CDC_WSA2_MACRO_AIF_VI, + LPASS_CDC_WSA2_MACRO_AIF_ECHO, + LPASS_CDC_WSA2_MACRO_AIF_CPS, + LPASS_CDC_WSA2_MACRO_MAX_DAIS, +}; + + +#define LPASS_CDC_WSA2_MACRO_CHILD_DEVICES_MAX 3 + +/* + * @dev: wsa2 macro device pointer + * @comp_enabled: compander enable mixer value set + * @ec_hq: echo HQ enable mixer value set + * @prim_int_users: Users of interpolator + * @wsa2_mclk_users: WSA2 MCLK users count + * @swr_clk_users: SWR clk users count + * @vi_feed_value: VI sense mask + * @mclk_lock: to lock mclk operations + * @swr_clk_lock: to lock swr master clock operations + * @swr_ctrl_data: SoundWire data structure + * @swr_plat_data: Soundwire platform data + * @lpass_cdc_wsa2_macro_add_child_devices_work: work for adding child devices + * @wsa2_swr_gpio_p: used by pinctrl API + * @component: codec handle + * @rx_0_count: RX0 interpolation users + * @rx_1_count: RX1 interpolation users + * @active_ch_mask: channel mask for all AIF DAIs + * @active_ch_cnt: channel count of all AIF DAIs + * @rx_port_value: mixer ctl value of WSA2 RX MUXes + * @wsa2_io_base: Base address of WSA2 macro addr space + * @wsa2_sys_gain System gain value, see wsa2 driver + * @wsa2_bat_cfg Battery Configuration value, see wsa2 driver + * @wsa2_rload Resistor load value for WSA2 Speaker, see wsa2 driver + */ +struct lpass_cdc_wsa2_macro_priv { + struct device *dev; + int comp_enabled[LPASS_CDC_WSA2_MACRO_COMP_MAX]; + int comp_mode[LPASS_CDC_WSA2_MACRO_COMP_MAX]; + int ec_hq[LPASS_CDC_WSA2_MACRO_RX1 + 1]; + u16 prim_int_users[LPASS_CDC_WSA2_MACRO_RX1 + 1]; + u16 wsa2_mclk_users; + u16 swr_clk_users; + bool dapm_mclk_enable; + bool reset_swr; + unsigned int vi_feed_value; + struct mutex mclk_lock; + struct mutex swr_clk_lock; + struct lpass_cdc_wsa2_macro_swr_ctrl_data *swr_ctrl_data; + struct lpass_cdc_wsa2_macro_swr_ctrl_platform_data swr_plat_data; + struct work_struct lpass_cdc_wsa2_macro_add_child_devices_work; + struct device_node *wsa2_swr_gpio_p; + struct snd_soc_component *component; + int rx_0_count; + int rx_1_count; + unsigned long active_ch_mask[LPASS_CDC_WSA2_MACRO_MAX_DAIS]; + unsigned long active_ch_cnt[LPASS_CDC_WSA2_MACRO_MAX_DAIS]; + u16 bit_width[LPASS_CDC_WSA2_MACRO_MAX_DAIS]; + int rx_port_value[LPASS_CDC_WSA2_MACRO_RX_MAX]; + char __iomem *wsa2_io_base; + struct platform_device *pdev_child_devices + [LPASS_CDC_WSA2_MACRO_CHILD_DEVICES_MAX]; + int child_count; + int wsa2_spkrrecv; + int spkr_gain_offset; + int spkr_mode; + int is_softclip_on[LPASS_CDC_WSA2_MACRO_SOFTCLIP_MAX]; + int softclip_clk_users[LPASS_CDC_WSA2_MACRO_SOFTCLIP_MAX]; + char __iomem *mclk_mode_muxsel; + u16 default_clk_id; + u32 pcm_rate_vi; + int wsa2_digital_mute_status[LPASS_CDC_WSA2_MACRO_RX_MAX]; + u8 rx0_origin_gain; + u8 rx1_origin_gain; + struct thermal_cooling_device *tcdev; + uint32_t thermal_cur_state; + uint32_t thermal_max_state; + struct work_struct lpass_cdc_wsa2_macro_cooling_work; + bool pbr_enable; + u32 wsa2_sys_gain[2 * (LPASS_CDC_WSA2_MACRO_RX1 + 1)]; + u32 wsa2_bat_cfg[LPASS_CDC_WSA2_MACRO_RX1 + 1]; + u32 wsa2_rload[LPASS_CDC_WSA2_MACRO_RX1 + 1]; + u32 wsa2_fs_ctl_reg; + u8 idle_detect_en; + int noise_gate_mode; + bool pre_dev_up; + int pbr_clk_users; + char __iomem *wsa2_fs_reg_base; + bool wsa2_2ch_dma_enable; +}; + +static struct snd_soc_dai_driver lpass_cdc_wsa2_macro_dai[]; +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); + +static const char *const rx_text[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", + "RX5", "RX6", "RX7", "RX8", "DEC0", "DEC1" +}; + +static const char *const rx_mix_text[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8" +}; + +static const char *const rx_mix_ec_text[] = { + "ZERO", "RX_MIX_TX0", "RX_MIX_TX1" +}; + +static const char *const rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF_MIX1_PB" +}; + +static const char *const rx_sidetone_mix_text[] = { + "ZERO", "SRC0" +}; + +static const char * const lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_text[] = { + "OFF", "ON" +}; + +static const char * const lpass_cdc_wsa2_macro_comp_mode_text[] = { + "G_21_DB", "G_19P5_DB", "G_18_DB", "G_16P5_DB", "G_15_DB", + "G_13P5_DB", "G_12_DB", "G_10P5_DB", "G_9_DB" +}; + +static const struct snd_kcontrol_new wsa2_int0_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("WSA2 RX0 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new wsa2_int1_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("WSA2 RX1 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + + +static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_enum, + lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_text); +static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa2_macro_comp_mode_enum, + lpass_cdc_wsa2_macro_comp_mode_text); + +/* RX INT0 */ +static const struct soc_enum rx0_prim_inp0_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0, + 0, 12, rx_text); + +static const struct soc_enum rx0_prim_inp1_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0, + 3, 12, rx_text); + +static const struct soc_enum rx0_prim_inp2_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1, + 3, 12, rx_text); + +static const struct soc_enum rx0_mix_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1, + 0, 10, rx_mix_text); + +static const struct soc_enum rx0_sidetone_mix_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text); + +static const struct snd_kcontrol_new rx0_prim_inp0_mux = + SOC_DAPM_ENUM("WSA2_RX0 INP0 Mux", rx0_prim_inp0_chain_enum); + +static const struct snd_kcontrol_new rx0_prim_inp1_mux = + SOC_DAPM_ENUM("WSA2_RX0 INP1 Mux", rx0_prim_inp1_chain_enum); + +static const struct snd_kcontrol_new rx0_prim_inp2_mux = + SOC_DAPM_ENUM("WSA2_RX0 INP2 Mux", rx0_prim_inp2_chain_enum); + +static const struct snd_kcontrol_new rx0_mix_mux = + SOC_DAPM_ENUM("WSA2_RX0 MIX Mux", rx0_mix_chain_enum); + +static const struct snd_kcontrol_new rx0_sidetone_mix_mux = + SOC_DAPM_ENUM("WSA2_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum); + +/* RX INT1 */ +static const struct soc_enum rx1_prim_inp0_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG0, + 0, 12, rx_text); + +static const struct soc_enum rx1_prim_inp1_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG0, + 3, 12, rx_text); + +static const struct soc_enum rx1_prim_inp2_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG1, + 3, 12, rx_text); + +static const struct soc_enum rx1_mix_chain_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG1, + 0, 10, rx_mix_text); + +static const struct snd_kcontrol_new rx1_prim_inp0_mux = + SOC_DAPM_ENUM("WSA2_RX1 INP0 Mux", rx1_prim_inp0_chain_enum); + +static const struct snd_kcontrol_new rx1_prim_inp1_mux = + SOC_DAPM_ENUM("WSA2_RX1 INP1 Mux", rx1_prim_inp1_chain_enum); + +static const struct snd_kcontrol_new rx1_prim_inp2_mux = + SOC_DAPM_ENUM("WSA2_RX1 INP2 Mux", rx1_prim_inp2_chain_enum); + +static const struct snd_kcontrol_new rx1_mix_mux = + SOC_DAPM_ENUM("WSA2_RX1 MIX Mux", rx1_mix_chain_enum); + +static const struct soc_enum rx_mix_ec0_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0, + 0, 3, rx_mix_ec_text); + +static const struct soc_enum rx_mix_ec1_enum = + SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0, + 3, 3, rx_mix_ec_text); + +static const struct snd_kcontrol_new rx_mix_ec0_mux = + SOC_DAPM_ENUM("WSA2 RX_MIX EC0_Mux", rx_mix_ec0_enum); + +static const struct snd_kcontrol_new rx_mix_ec1_mux = + SOC_DAPM_ENUM("WSA2 RX_MIX EC1_Mux", rx_mix_ec1_enum); + +static struct snd_soc_dai_ops lpass_cdc_wsa2_macro_dai_ops = { + .hw_params = lpass_cdc_wsa2_macro_hw_params, + .get_channel_map = lpass_cdc_wsa2_macro_get_channel_map, + .mute_stream = lpass_cdc_wsa2_macro_mute_stream, +}; + +static struct snd_soc_dai_driver lpass_cdc_wsa2_macro_dai[] = { + { + .name = "wsa2_macro_rx1", + .id = LPASS_CDC_WSA2_MACRO_AIF1_PB, + .playback = { + .stream_name = "WSA2_AIF1 Playback", + .rates = LPASS_CDC_WSA2_MACRO_RX_RATES, + .formats = LPASS_CDC_WSA2_MACRO_RX_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa2_macro_dai_ops, + }, + { + .name = "wsa2_macro_rx_mix", + .id = LPASS_CDC_WSA2_MACRO_AIF_MIX1_PB, + .playback = { + .stream_name = "WSA2_AIF_MIX1 Playback", + .rates = LPASS_CDC_WSA2_MACRO_RX_MIX_RATES, + .formats = LPASS_CDC_WSA2_MACRO_RX_FORMATS, + .rate_max = 192000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa2_macro_dai_ops, + }, + { + .name = "wsa2_macro_vifeedback", + .id = LPASS_CDC_WSA2_MACRO_AIF_VI, + .capture = { + .stream_name = "WSA2_AIF_VI Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000, + .formats = LPASS_CDC_WSA2_MACRO_RX_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &lpass_cdc_wsa2_macro_dai_ops, + }, + { + .name = "wsa2_macro_echo", + .id = LPASS_CDC_WSA2_MACRO_AIF_ECHO, + .capture = { + .stream_name = "WSA2_AIF_ECHO Capture", + .rates = LPASS_CDC_WSA2_MACRO_ECHO_RATES, + .formats = LPASS_CDC_WSA2_MACRO_ECHO_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa2_macro_dai_ops, + }, + { + .name = "wsa2_macro_cpsfeedback", + .id = LPASS_CDC_WSA2_MACRO_AIF_CPS, + .capture = { + .stream_name = "WSA2_AIF_CPS Capture", + .rates = LPASS_CDC_WSA2_MACRO_CPS_RATES, + .formats = LPASS_CDC_WSA2_MACRO_CPS_FORMATS, + .rate_max = 48000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &lpass_cdc_wsa2_macro_dai_ops, + }, +}; + +static bool lpass_cdc_wsa2_macro_get_data(struct snd_soc_component *component, + struct device **wsa2_dev, + struct lpass_cdc_wsa2_macro_priv **wsa2_priv, + const char *func_name) +{ + *wsa2_dev = lpass_cdc_get_device_ptr(component->dev, + WSA2_MACRO); + if (!(*wsa2_dev)) { + dev_err_ratelimited(component->dev, + "%s: null device for macro!\n", func_name); + return false; + } + *wsa2_priv = dev_get_drvdata((*wsa2_dev)); + if (!(*wsa2_priv) || !(*wsa2_priv)->component) { + dev_err_ratelimited(component->dev, + "%s: priv is null for macro!\n", func_name); + return false; + } + return true; +} + +static int lpass_cdc_wsa2_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + if (wsa2_priv->swr_ctrl_data) + ret = swrm_wcd_notify( + wsa2_priv->swr_ctrl_data[0].wsa2_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + +static int lpass_cdc_wsa2_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 int_prim_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp; + u32 j, port; + u16 int_mux_cfg0, int_mux_cfg1; + u16 int_fs_reg; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 inp0_sel, inp1_sel, inp2_sel; + struct snd_soc_component *component = dai->component; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + for_each_set_bit(port, &wsa2_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA2_MACRO_RX_MAX) { + int_1_mix1_inp = port; + if ((int_1_mix1_inp < LPASS_CDC_WSA2_MACRO_RX0) || + (int_1_mix1_inp >= LPASS_CDC_WSA2_MACRO_RX_MAX)) { + dev_err_ratelimited(wsa2_dev, + "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg0 = LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the cdc_dma rx port + * is connected + */ + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1 = int_mux_cfg0 + LPASS_CDC_WSA2_MACRO_MUX_CFG1_OFFSET; + + int_mux_cfg0_val = snd_soc_component_read(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & LPASS_CDC_WSA2_MACRO_MUX_INP_MASK1; + inp1_sel = (int_mux_cfg0_val >> + LPASS_CDC_WSA2_MACRO_MUX_INP_SHFT) & + LPASS_CDC_WSA2_MACRO_MUX_INP_MASK1; + inp2_sel = (int_mux_cfg1_val >> + LPASS_CDC_WSA2_MACRO_MUX_INP_SHFT) & + LPASS_CDC_WSA2_MACRO_MUX_INP_MASK1; + if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { + int_fs_reg = LPASS_CDC_WSA2_RX0_RX_PATH_CTL + + LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET * j; + dev_dbg(wsa2_dev, + "%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + dev_dbg(wsa2_dev, + "%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + /* sample_rate is in Hz */ + snd_soc_component_update_bits(component, + int_fs_reg, + LPASS_CDC_WSA2_MACRO_FS_RATE_MASK, + int_prim_fs_rate_reg_val); + } + int_mux_cfg0 += LPASS_CDC_WSA2_MACRO_MUX_CFG_OFFSET; + } + } + + return 0; +} + +static int lpass_cdc_wsa2_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 int_mix_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp; + u32 j, port; + u16 int_mux_cfg1, int_fs_reg; + u8 int_mux_cfg1_val; + struct snd_soc_component *component = dai->component; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + + for_each_set_bit(port, &wsa2_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA2_MACRO_RX_MAX) { + int_2_inp = port; + if ((int_2_inp < LPASS_CDC_WSA2_MACRO_RX0) || + (int_2_inp > LPASS_CDC_WSA2_MACRO_RX_MIX1)) { + dev_err_ratelimited(wsa2_dev, + "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg1 = LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1) & + LPASS_CDC_WSA2_MACRO_MUX_INP_MASK1; + if (int_mux_cfg1_val == int_2_inp + + INTn_2_INP_SEL_RX0) { + int_fs_reg = + LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL + + LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET * j; + + dev_dbg(wsa2_dev, + "%s: AIF_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + dev_dbg(wsa2_dev, + "%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits(component, + int_fs_reg, + LPASS_CDC_WSA2_MACRO_FS_RATE_MASK, + int_mix_fs_rate_reg_val); + } + int_mux_cfg1 += LPASS_CDC_WSA2_MACRO_MUX_CFG_OFFSET; + } + } + return 0; +} + +static int lpass_cdc_wsa2_macro_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + int rate_val = 0; + int i, ret; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) { + if (sample_rate == + int_mix_sample_rate_val[i].sample_rate) { + rate_val = + int_mix_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) || + (rate_val < 0)) + goto prim_rate; + ret = lpass_cdc_wsa2_macro_set_mix_interpolator_rate(dai, + (u8) rate_val, sample_rate); +prim_rate: + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) { + if (sample_rate == + int_prim_sample_rate_val[i].sample_rate) { + rate_val = + int_prim_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) || + (rate_val < 0)) + return -EINVAL; + ret = lpass_cdc_wsa2_macro_set_prim_interpolator_rate(dai, + (u8) rate_val, sample_rate); + return ret; +} + +static int lpass_cdc_wsa2_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv = dev_get_drvdata(wsa2_dev); + if (!wsa2_priv) + return -EINVAL; + + dev_dbg(component->dev, + "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = lpass_cdc_wsa2_macro_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err_ratelimited(component->dev, + "%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16: + wsa2_priv->bit_width[dai->id] = 16; + break; + case 24: + wsa2_priv->bit_width[dai->id] = 24; + break; + case 32: + wsa2_priv->bit_width[dai->id] = 32; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } + break; + case SNDRV_PCM_STREAM_CAPTURE: + if (dai->id == LPASS_CDC_WSA2_MACRO_AIF_VI) + wsa2_priv->pcm_rate_vi = params_rate(params); + + switch (params_width(params)) { + case 16: + wsa2_priv->bit_width[dai->id] = 16; + break; + case 24: + wsa2_priv->bit_width[dai->id] = 24; + break; + case 32: + wsa2_priv->bit_width[dai->id] = 32; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } + break; + default: + break; + } + return 0; +} + +static int lpass_cdc_wsa2_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u16 val = 0, mask = 0, cnt = 0, temp = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv = dev_get_drvdata(wsa2_dev); + if (!wsa2_priv) + return -EINVAL; + + switch (dai->id) { + case LPASS_CDC_WSA2_MACRO_AIF_VI: + for_each_set_bit(temp, &wsa2_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA2_MACRO_TX_MAX) { + mask |= (1 << temp); + if (++cnt == LPASS_CDC_WSA2_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + /* consider WSA2 Backend is used when 2ch_dma is enabled + * and doesn't require channel mask shift + */ + if (!wsa2_priv->wsa2_2ch_dma_enable) { + if (mask & 0x03) + mask = mask << 0x2; + } + *tx_slot = mask; + *tx_num = cnt; + break; + case LPASS_CDC_WSA2_MACRO_AIF_CPS: + *tx_slot = wsa2_priv->active_ch_mask[dai->id]; + *tx_num = wsa2_priv->active_ch_cnt[dai->id]; + break; + case LPASS_CDC_WSA2_MACRO_AIF1_PB: + case LPASS_CDC_WSA2_MACRO_AIF_MIX1_PB: + for_each_set_bit(temp, &wsa2_priv->active_ch_mask[dai->id], + LPASS_CDC_WSA2_MACRO_RX_MAX) { + mask |= (1 << temp); + if (++cnt == LPASS_CDC_WSA2_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + if (mask & 0x30) + mask = mask >> 0x4; + else + mask = mask << 0x2; + *rx_slot = mask; + *rx_num = cnt; + break; + case LPASS_CDC_WSA2_MACRO_AIF_ECHO: + val = snd_soc_component_read(component, + LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0); + if (val & LPASS_CDC_WSA2_MACRO_EC_MIX_TX1_MASK) { + mask |= 0x2; + cnt++; + } + if (val & LPASS_CDC_WSA2_MACRO_EC_MIX_TX0_MASK) { + mask |= 0x1; + cnt++; + } + *tx_slot = mask; + *tx_num = cnt; + break; + default: + dev_err(wsa2_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static void lpass_cdc_wsa2_unmute_interpolator(struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + uint16_t j = 0, reg = 0, mix_reg = 0; + + switch (dai->id) { + case LPASS_CDC_WSA2_MACRO_AIF1_PB: + case LPASS_CDC_WSA2_MACRO_AIF_MIX1_PB: + for (j = 0; j < NUM_INTERPOLATORS; ++j) { + reg = LPASS_CDC_WSA2_RX0_RX_PATH_CTL + + (j * LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET); + mix_reg = LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL + + (j * LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET); + + snd_soc_component_update_bits(component, reg, 0x10, 0x00); + snd_soc_component_update_bits(component, mix_reg, 0x10, 0x00); + } + } +} + +static int lpass_cdc_wsa2_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + uint32_t temp; + + bool adie_lb = false; + + if (mute) + return 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + switch (dai->id) { + case LPASS_CDC_WSA2_MACRO_AIF1_PB: + case LPASS_CDC_WSA2_MACRO_AIF_MIX1_PB: + lpass_cdc_wsa_pa_on(wsa2_dev, adie_lb); + lpass_cdc_wsa2_unmute_interpolator(dai); + lpass_cdc_wsa2_macro_enable_vi_decimator(component); + break; + default: + break; + } + + if ((test_bit(LPASS_CDC_WSA2_MACRO_RX4, + &wsa2_priv->active_ch_mask[dai->id]) || + test_bit(LPASS_CDC_WSA2_MACRO_RX5, + &wsa2_priv->active_ch_mask[dai->id])) && + wsa2_priv->wsa2_fs_reg_base) { + temp = ioread32(wsa2_priv->wsa2_fs_reg_base); + if (temp != 1) { + temp = 1; + iowrite32(temp, wsa2_priv->wsa2_fs_reg_base); + } + dev_dbg(wsa2_dev, "%s: LPASS_WSA_FS_CTL : %d", __func__, temp); + } + + return 0; +} + +static int lpass_cdc_wsa2_macro_mclk_enable( + struct lpass_cdc_wsa2_macro_priv *wsa2_priv, + bool mclk_enable, bool dapm) +{ + struct regmap *regmap = dev_get_regmap(wsa2_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(wsa2_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(wsa2_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n", + __func__, mclk_enable, dapm, wsa2_priv->wsa2_mclk_users); + + mutex_lock(&wsa2_priv->mclk_lock); + if (mclk_enable) { + if (wsa2_priv->wsa2_mclk_users == 0) { + ret = lpass_cdc_clk_rsc_request_clock(wsa2_priv->dev, + wsa2_priv->default_clk_id, + wsa2_priv->default_clk_id, + true); + if (ret < 0) { + dev_err_ratelimited(wsa2_priv->dev, + "%s: wsa2 request clock enable failed\n", + __func__); + goto exit; + } + lpass_cdc_clk_rsc_fs_gen_request(wsa2_priv->dev, + true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + WSA2_START_OFFSET, + WSA2_MAX_OFFSET); + /* 9.6MHz MCLK, set value 0x00 if other frequency */ + regmap_update_bits(regmap, + LPASS_CDC_WSA2_TOP_FREQ_MCLK, 0x01, 0x01); + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + /* Toggle fs_cntr_clr bit*/ + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x02, 0x0); + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + } + wsa2_priv->wsa2_mclk_users++; + } else { + if (wsa2_priv->wsa2_mclk_users <= 0) { + dev_err_ratelimited(wsa2_priv->dev, "%s: clock already disabled\n", + __func__); + wsa2_priv->wsa2_mclk_users = 0; + goto exit; + } + wsa2_priv->wsa2_mclk_users--; + if (wsa2_priv->wsa2_mclk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x00); + lpass_cdc_clk_rsc_fs_gen_request(wsa2_priv->dev, + false); + + lpass_cdc_clk_rsc_request_clock(wsa2_priv->dev, + wsa2_priv->default_clk_id, + wsa2_priv->default_clk_id, + false); + } + } +exit: + mutex_unlock(&wsa2_priv->mclk_lock); + return ret; +} + +static int lpass_cdc_wsa2_macro_mclk_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); + int ret = 0; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa2_dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = lpass_cdc_wsa2_macro_mclk_enable(wsa2_priv, 1, true); + if (ret) + wsa2_priv->dapm_mclk_enable = false; + else + wsa2_priv->dapm_mclk_enable = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (wsa2_priv->dapm_mclk_enable) { + lpass_cdc_wsa2_macro_mclk_enable(wsa2_priv, 0, true); + wsa2_priv->dapm_mclk_enable = false; + } + break; + default: + dev_err_ratelimited(wsa2_priv->dev, + "%s: invalid DAPM event %d\n", __func__, event); + ret = -EINVAL; + } + return ret; +} + +static int lpass_cdc_wsa2_macro_event_handler(struct snd_soc_component *component, + u16 event, u32 data) +{ + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + int ret = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + switch (event) { + case LPASS_CDC_MACRO_EVT_SSR_DOWN: + wsa2_priv->pre_dev_up = false; + if (wsa2_priv->swr_ctrl_data) { + swrm_wcd_notify( + wsa2_priv->swr_ctrl_data[0].wsa2_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + } + if ((!pm_runtime_enabled(wsa2_dev) || + !pm_runtime_suspended(wsa2_dev))) { + ret = lpass_cdc_runtime_suspend(wsa2_dev); + if (!ret) { + pm_runtime_disable(wsa2_dev); + pm_runtime_set_suspended(wsa2_dev); + pm_runtime_enable(wsa2_dev); + } + } + break; + case LPASS_CDC_MACRO_EVT_PRE_SSR_UP: + break; + case LPASS_CDC_MACRO_EVT_SSR_UP: + wsa2_priv->pre_dev_up = true; + /* reset swr after ssr/pdr */ + wsa2_priv->reset_swr = true; + if (wsa2_priv->swr_ctrl_data) + swrm_wcd_notify( + wsa2_priv->swr_ctrl_data[0].wsa2_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + case LPASS_CDC_MACRO_EVT_CLK_RESET: + lpass_cdc_rsc_clk_reset(wsa2_dev, WSA2_CORE_CLK); + lpass_cdc_rsc_clk_reset(wsa2_dev, WSA2_TX_CORE_CLK); + break; + } + return 0; +} + +static int lpass_cdc_wsa2_macro_enable_vi_decimator(struct snd_soc_component *component) +{ + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u8 val = 0x0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + usleep_range(5000, 5500); + dev_dbg(wsa2_dev, "%s: wsa2_priv->pcm_rate_vi %d\n", __func__, wsa2_priv->pcm_rate_vi); + switch (wsa2_priv->pcm_rate_vi) { + case 48000: + val = 0x04; + break; + case 24000: + val = 0x02; + break; + case 8000: + default: + val = 0x00; + break; + } + + if (test_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + dev_dbg(wsa2_dev, "%s: spkr1 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + + if (test_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + dev_dbg(wsa2_dev, "%s: spkr2 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, + 0x0F, val); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + return 0; +} + +static int lpass_cdc_wsa2_macro_disable_vi_feedback(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 device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + if (test_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + /* Disable V&I sensing */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + dev_dbg(wsa2_dev, "%s: spkr1 disabled\n", __func__); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + if (test_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + /* Disable V&I sensing */ + dev_dbg(wsa2_dev, "%s: spkr2 disabled\n", __func__); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x20); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CTL, + 0x20, 0x00); + } + break; + } + + return 0; +} + +static void lpass_cdc_wsa2_macro_hd2_control(struct snd_soc_component *component, + u16 reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (reg == LPASS_CDC_WSA2_RX0_RX_PATH_CTL) { + hd2_scale_reg = LPASS_CDC_WSA2_RX0_RX_PATH_SEC3; + hd2_enable_reg = LPASS_CDC_WSA2_RX0_RX_PATH_CFG0; + } + if (reg == LPASS_CDC_WSA2_RX1_RX_PATH_CTL) { + hd2_scale_reg = LPASS_CDC_WSA2_RX1_RX_PATH_SEC3; + hd2_enable_reg = LPASS_CDC_WSA2_RX1_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x10); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x01); + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x00); + } +} + +static int lpass_cdc_wsa2_macro_enable_swr(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ch_cnt; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!(strnstr(w->name, "RX0", sizeof("WSA2_RX0"))) && + !wsa2_priv->rx_0_count) + wsa2_priv->rx_0_count++; + if (!(strnstr(w->name, "RX1", sizeof("WSA2_RX1"))) && + !wsa2_priv->rx_1_count) + wsa2_priv->rx_1_count++; + ch_cnt = wsa2_priv->rx_0_count + wsa2_priv->rx_1_count; + + if (wsa2_priv->swr_ctrl_data) { + swrm_wcd_notify( + wsa2_priv->swr_ctrl_data[0].wsa2_swr_pdev, + SWR_DEVICE_UP, NULL); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (!(strnstr(w->name, "RX0", sizeof("WSA2_RX0"))) && + wsa2_priv->rx_0_count) + wsa2_priv->rx_0_count--; + if (!(strnstr(w->name, "RX1", sizeof("WSA2_RX1"))) && + wsa2_priv->rx_1_count) + wsa2_priv->rx_1_count--; + ch_cnt = wsa2_priv->rx_0_count + wsa2_priv->rx_1_count; + + break; + } + dev_dbg(wsa2_priv->dev, "%s: current swr ch cnt: %d\n", + __func__, wsa2_priv->rx_0_count + wsa2_priv->rx_1_count); + + return 0; +} + +static int lpass_cdc_wsa2_macro_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int offset_val = 0; + int val = 0; + uint16_t mix_reg = 0; + uint16_t reg = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "WSA2_RX0 MIX INP"))) { + gain_reg = LPASS_CDC_WSA2_RX0_RX_VOL_MIX_CTL; + } else if (!(strcmp(w->name, "WSA2_RX1 MIX INP"))) { + gain_reg = LPASS_CDC_WSA2_RX1_RX_VOL_MIX_CTL; + } else { + dev_err_ratelimited(component->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + } + + reg = LPASS_CDC_WSA2_RX0_RX_PATH_CTL + + LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET * w->shift; + mix_reg = LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL + + LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET * w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x40); + usleep_range(500, 510); + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x00); + snd_soc_component_update_bits(component, reg, 0x20, 0x20); + snd_soc_component_update_bits(component, + mix_reg, 0x20, 0x20); + lpass_cdc_wsa2_macro_enable_swr(w, kcontrol, event); + val = snd_soc_component_read(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + w->reg, 0x20, 0x00); + lpass_cdc_wsa2_macro_enable_swr(w, kcontrol, event); + break; + } + + return 0; +} + +static int lpass_cdc_wsa2_macro_config_compander(struct snd_soc_component *component, + int comp, int event) +{ + u16 comp_ctl0_reg, comp_ctl8_reg, rx_path_cfg0_reg; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct lpass_cdc_comp_setting *comp_settings = NULL; + u16 mode = 0; + u16 index = 0; + int sys_gain, bat_cfg, sys_gain_int, upper_gain, lower_gain; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, wsa2_priv->comp_enabled[comp]); + + if (comp >= LPASS_CDC_WSA2_MACRO_COMP_MAX || comp < 0) { + dev_err(component->dev, "%s: Invalid compander value: %d\n", + __func__, comp); + return -EINVAL; + } + + if (!wsa2_priv->comp_enabled[comp]) + return 0; + + mode = wsa2_priv->comp_mode[comp]; + if (mode >= G_MAX_DB || mode < 0) + mode = 0; + comp_ctl0_reg = LPASS_CDC_WSA2_COMPANDER0_CTL0 + + (comp * LPASS_CDC_WSA2_MACRO_RX_COMP_OFFSET); + comp_ctl8_reg = LPASS_CDC_WSA2_COMPANDER0_CTL8 + + (comp * LPASS_CDC_WSA2_MACRO_RX_COMP_OFFSET); + rx_path_cfg0_reg = LPASS_CDC_WSA2_RX0_RX_PATH_CFG0 + + (comp * LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET); + comp_settings = &comp_setting_table[mode]; + + /* If System has battery configuration */ + if (wsa2_priv->wsa2_bat_cfg[comp]) { + index = (comp * 2) + wsa2_priv->wsa2_spkrrecv; + if (index >= (2 * (LPASS_CDC_WSA2_MACRO_RX1 + 1))) { + dev_err(component->dev, "%s: Invalid index: %d\n", + __func__, index); + return -EINVAL; + } + sys_gain = wsa2_priv->wsa2_sys_gain[index]; + bat_cfg = wsa2_priv->wsa2_bat_cfg[comp]; + /* Convert enum to value and + * multiply all values by 10 to avoid float + */ + sys_gain_int = -15 * sys_gain + 210; + switch (bat_cfg) { + case CONFIG_1S: + case EXT_1S: + if (sys_gain > G_13P5_DB) { + upper_gain = sys_gain_int + 60; + lower_gain = 0; + } else { + upper_gain = 210; + lower_gain = 0; + } + break; + case CONFIG_3S: + case EXT_3S: + upper_gain = sys_gain_int; + lower_gain = 75; + break; + case EXT_ABOVE_3S: + upper_gain = sys_gain_int; + lower_gain = 120; + break; + default: + upper_gain = sys_gain_int; + lower_gain = 0; + break; + } + /* Truncate after calculation */ + comp_settings->lower_gain_int = (lower_gain * 2) / 10; + comp_settings->upper_gain_int = (upper_gain * 2) / 10; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + lpass_cdc_update_compander_setting(component, + comp_ctl8_reg, + comp_settings); + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x04); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x00); + } + + return 0; +} + +static void lpass_cdc_wsa2_macro_enable_softclip_clk(struct snd_soc_component *component, + struct lpass_cdc_wsa2_macro_priv *wsa2_priv, + int path, + bool enable) +{ + u16 softclip_clk_reg = LPASS_CDC_WSA2_SOFTCLIP0_CRC + + (path * LPASS_CDC_WSA2_MACRO_RX_SOFTCLIP_OFFSET); + u8 softclip_mux_mask = (1 << path); + u8 softclip_mux_value = (1 << path); + + dev_dbg(component->dev, "%s: path %d, enable %d\n", + __func__, path, enable); + if (enable) { + if (wsa2_priv->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, 0x01, 0x01); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, softclip_mux_value); + } + wsa2_priv->softclip_clk_users[path]++; + } else { + wsa2_priv->softclip_clk_users[path]--; + if (wsa2_priv->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, 0x00); + } + } +} + +static int lpass_cdc_wsa2_macro_config_softclip(struct snd_soc_component *component, + int path, int event) +{ + u16 softclip_ctrl_reg = 0; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + int softclip_path = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (path == LPASS_CDC_WSA2_MACRO_COMP1) + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP0; + else if (path == LPASS_CDC_WSA2_MACRO_COMP2) + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP1; + + dev_dbg(component->dev, "%s: event %d path %d, enabled %d\n", + __func__, event, softclip_path, + wsa2_priv->is_softclip_on[softclip_path]); + + if (!wsa2_priv->is_softclip_on[softclip_path]) + return 0; + + softclip_ctrl_reg = LPASS_CDC_WSA2_SOFTCLIP0_SOFTCLIP_CTRL + + (softclip_path * LPASS_CDC_WSA2_MACRO_RX_SOFTCLIP_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Softclip clock and mux */ + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, true); + /* Enable Softclip control */ + snd_soc_component_update_bits(component, softclip_ctrl_reg, + 0x01, 0x01); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, softclip_ctrl_reg, + 0x01, 0x00); + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, false); + } + + return 0; +} + +static int lpass_cdc_was_macro_config_pbr(struct snd_soc_component *component, + int path, int event) +{ + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u16 reg1 = 0, reg2 = 0, reg3 = 0; + int softclip_path = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (path == LPASS_CDC_WSA2_MACRO_COMP1) { + reg1 = LPASS_CDC_WSA2_COMPANDER0_CTL0; + reg2 = LPASS_CDC_WSA2_RX0_RX_PATH_CFG3; + reg3 = LPASS_CDC_WSA2_RX0_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP0; + } else if (path == LPASS_CDC_WSA2_MACRO_COMP2) { + reg1 = LPASS_CDC_WSA2_COMPANDER1_CTL0; + reg2 = LPASS_CDC_WSA2_RX1_RX_PATH_CFG3; + reg3 = LPASS_CDC_WSA2_RX1_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP1; + } + if (!wsa2_priv->pbr_enable || wsa2_priv->wsa2_bat_cfg[path] >= EXT_1S || + wsa2_priv->wsa2_sys_gain[path * 2] > G_12_DB || + wsa2_priv->wsa2_spkrrecv || !reg1 || !reg2 || !reg3) + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, + reg1, 0x08, 0x08); + snd_soc_component_update_bits(component, + reg2, 0x40, 0x40); + snd_soc_component_update_bits(component, + reg3, 0x80, 0x80); + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, true); + if (wsa2_priv->pbr_clk_users == 0) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_PBR_PATH_CTL, + 0x01, 0x01); + ++wsa2_priv->pbr_clk_users; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + if (wsa2_priv->pbr_clk_users) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_PBR_PATH_CTL, + 0x01, 0x00); + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, false); + snd_soc_component_update_bits(component, + reg1, 0x08, 0x00); + snd_soc_component_update_bits(component, + reg2, 0x40, 0x00); + snd_soc_component_update_bits(component, + reg3, 0x80, 0x00); + --wsa2_priv->pbr_clk_users; + if (wsa2_priv->pbr_clk_users < 0) + wsa2_priv->pbr_clk_users = 0; + } + return 0; +} + +static bool lpass_cdc_wsa2_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0; + + int_mux_cfg0 = LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || + int_n_inp0 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || + int_n_inp1 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || + int_n_inp2 == INTn_1_INP_SEL_DEC1) + return true; + + return false; +} + +static int lpass_cdc_wsa2_macro_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 reg = 0; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + bool adie_lb = false; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + reg = LPASS_CDC_WSA2_RX0_RX_PATH_CTL + + LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET * w->shift; + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, reg, 0x40, 0x40); + usleep_range(500, 510); + snd_soc_component_update_bits(component, reg, 0x40, 0x00); + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + if (lpass_cdc_wsa2_macro_adie_lb(component, w->shift)) { + adie_lb = true; + lpass_cdc_wsa_pa_on(wsa2_dev, adie_lb); + snd_soc_component_update_bits(component, + reg, 0x10, 0x00); + } + break; + default: + break; + } + return 0; +} + +static int lpass_cdc_wsa2_macro_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = 0; + + switch (reg) { + case LPASS_CDC_WSA2_RX0_RX_PATH_CTL: + case LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL: + prim_int_reg = LPASS_CDC_WSA2_RX0_RX_PATH_CTL; + *ind = 0; + break; + case LPASS_CDC_WSA2_RX1_RX_PATH_CTL: + case LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CTL: + prim_int_reg = LPASS_CDC_WSA2_RX1_RX_PATH_CTL; + *ind = 1; + break; + } + + return prim_int_reg; +} + +static int lpass_cdc_wsa2_macro_enable_prim_interpolator( + struct snd_soc_component *component, + u16 reg, int event) +{ + u16 prim_int_reg; + u16 ind = 0; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + prim_int_reg = lpass_cdc_wsa2_macro_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wsa2_priv->prim_int_users[ind]++; + if (wsa2_priv->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(component, + prim_int_reg + LPASS_CDC_WSA2_MACRO_RX_PATH_CFG3_OFFSET, + 0x03, 0x03); + snd_soc_component_update_bits(component, prim_int_reg, + 0x10, 0x10); + lpass_cdc_wsa2_macro_hd2_control(component, prim_int_reg, event); + snd_soc_component_update_bits(component, + prim_int_reg + LPASS_CDC_WSA2_MACRO_RX_PATH_DSMDEM_OFFSET, + 0x1, 0x1); + } + if ((reg != prim_int_reg) && + ((snd_soc_component_read( + component, prim_int_reg)) & 0x10)) + snd_soc_component_update_bits(component, reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + wsa2_priv->prim_int_users[ind]--; + if (wsa2_priv->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(component, prim_int_reg, + 1 << 0x5, 0 << 0x5); + snd_soc_component_update_bits(component, + prim_int_reg + LPASS_CDC_WSA2_MACRO_RX_PATH_DSMDEM_OFFSET, + 0x1, 0x0); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x00); + lpass_cdc_wsa2_macro_hd2_control(component, prim_int_reg, event); + } + break; + } + + dev_dbg(component->dev, "%s: primary interpolator: INT%d, users: %d\n", + __func__, ind, wsa2_priv->prim_int_users[ind]); + return 0; +} + +static void lpass_cdc_macro_idle_detect_control(struct snd_soc_component *component, + struct lpass_cdc_wsa2_macro_priv *wsa2_priv, + int interp, int event) +{ + int reg = 0, mask = 0, val = 0, source_reg = 0; + u16 mode = 0; + + dev_dbg(component->dev, "%s: Idle_detect_en value: %d\n", __func__, + wsa2_priv->idle_detect_en); + + if (!wsa2_priv->idle_detect_en) + return; + + if (interp == LPASS_CDC_WSA2_MACRO_COMP1) { + source_reg = LPASS_CDC_WSA2_RX0_RX_PATH_CFG3; + reg = LPASS_CDC_WSA2_IDLE_DETECT_PATH_CTL; + mask = 0x01; + val = 0x01; + } + if (interp == LPASS_CDC_WSA2_MACRO_COMP2) { + source_reg = LPASS_CDC_WSA2_RX1_RX_PATH_CFG3; + reg = LPASS_CDC_WSA2_IDLE_DETECT_PATH_CTL; + mask = 0x02; + val = 0x02; + } + + mode = wsa2_priv->comp_mode[interp]; + + if ((wsa2_priv->noise_gate_mode == NG2 && mode >= G_13P5_DB) || + wsa2_priv->noise_gate_mode == IDLE_DETECT || !wsa2_priv->pbr_enable || + wsa2_priv->wsa2_spkrrecv) { + snd_soc_component_update_bits(component, source_reg, 0x80, 0x00); + dev_dbg(component->dev, "%s: Idle detect source: Legacy\n", __func__); + } else { + snd_soc_component_update_bits(component, source_reg, 0x80, 0x80); + dev_dbg(component->dev, "%s: Idle detect source: PRE-LA\n", __func__); + } + + if (reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, reg, mask, val); + dev_dbg(component->dev, "%s: Idle detect clks ON\n", __func__); + } + + if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, reg, mask, 0x00); + snd_soc_component_write(component, + LPASS_CDC_WSA2_IDLE_DETECT_CFG3, 0x0); + dev_dbg(component->dev, "%s: Idle detect clks OFF\n", __func__); + } +} + +static int lpass_cdc_wsa2_macro_enable_interpolator(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 device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u8 gain = 0; + u16 reg = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "WSA2_RX INT0 INTERP"))) { + reg = LPASS_CDC_WSA2_RX0_RX_PATH_CTL; + } else if (!(strcmp(w->name, "WSA2_RX INT1 INTERP"))) { + reg = LPASS_CDC_WSA2_RX1_RX_PATH_CTL; + } else { + dev_err_ratelimited(component->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + lpass_cdc_wsa2_macro_enable_prim_interpolator(component, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + if (!strcmp(w->name, "WSA2_RX INT0 INTERP")) { + gain = (u8)(wsa2_priv->rx0_origin_gain - + wsa2_priv->thermal_cur_state); + if (snd_soc_component_read(wsa2_priv->component, + LPASS_CDC_WSA2_RX0_RX_VOL_CTL) != gain) { + snd_soc_component_update_bits(wsa2_priv->component, + LPASS_CDC_WSA2_RX0_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa2_priv->dev, + "%s: RX0 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa2_priv->thermal_cur_state, gain); + } + } + + if (!strcmp(w->name, "WSA2_RX INT1 INTERP")) { + gain = (u8)(wsa2_priv->rx1_origin_gain - + wsa2_priv->thermal_cur_state); + if (snd_soc_component_read(wsa2_priv->component, + LPASS_CDC_WSA2_RX1_RX_VOL_CTL) != gain) { + snd_soc_component_update_bits(wsa2_priv->component, + LPASS_CDC_WSA2_RX1_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa2_priv->dev, + "%s: RX1 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa2_priv->thermal_cur_state, gain); + } + } + + lpass_cdc_wsa2_macro_config_compander(component, w->shift, event); + lpass_cdc_macro_idle_detect_control(component, wsa2_priv, + w->shift, event); + lpass_cdc_wsa2_macro_config_softclip(component, w->shift, event); + lpass_cdc_was_macro_config_pbr(component, w->shift, event); + if (wsa2_priv->wsa2_spkrrecv) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, + 0x08, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, 0x08, 0x08); + lpass_cdc_wsa2_macro_config_compander(component, w->shift, event); + lpass_cdc_macro_idle_detect_control(component, wsa2_priv, + w->shift, event); + lpass_cdc_wsa2_macro_config_softclip(component, w->shift, event); + lpass_cdc_was_macro_config_pbr(component, w->shift, event); + lpass_cdc_wsa2_macro_enable_prim_interpolator(component, reg, event); + break; + } + + return 0; +} + +static int lpass_cdc_wsa2_macro_spk_boost_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); + u16 boost_path_ctl, boost_path_cfg1; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + if (!strcmp(w->name, "WSA2_RX INT0 CHAIN")) { + boost_path_ctl = LPASS_CDC_WSA2_BOOST0_BOOST_PATH_CTL; + boost_path_cfg1 = LPASS_CDC_WSA2_RX0_RX_PATH_CFG1; + } else if (!strcmp(w->name, "WSA2_RX INT1 CHAIN")) { + boost_path_ctl = LPASS_CDC_WSA2_BOOST1_BOOST_PATH_CTL; + boost_path_cfg1 = LPASS_CDC_WSA2_RX1_RX_PATH_CFG1; + } else { + dev_err_ratelimited(component->dev, "%s: unknown widget: %s\n", + __func__, w->name); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x01); + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x00); + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x00); + break; + } + + return 0; +} + + +static int lpass_cdc_wsa2_macro_enable_vbat(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 device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u16 vbat_path_cfg = 0; + int softclip_path = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + if (!strcmp(w->name, "WSA2_RX INT0 VBAT")) { + vbat_path_cfg = LPASS_CDC_WSA2_RX0_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP0; + } else if (!strcmp(w->name, "WSA2_RX INT1 VBAT")) { + vbat_path_cfg = LPASS_CDC_WSA2_RX1_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP1; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable clock for VBAT block */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x10); + /* Enable VBAT block */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG, 0x01, 0x01); + /* Update interpolator with 384K path */ + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x80, 0x80); + /* Use attenuation mode */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG, 0x02, 0x00); + /* + * BCL block needs softclip clock and mux config to be enabled + */ + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, true); + /* Enable VBAT at channel level */ + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x02); + /* Set the ATTK1 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + /* Set the ATTK2 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + /* Set the ATTK3 gain */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0xFF); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x03); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + /* Enable CB decode block clock */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x01); + /* Enable BCL path */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x01); + /* Request for BCL data */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x01); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x00); + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x80, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG, + 0x02, 0x02); + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD1, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD2, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD3, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD4, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD5, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD6, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD7, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD8, + 0xFF, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD9, + 0xFF, 0x00); + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, false); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_PATH_CTL, 0x10, 0x00); + break; + default: + dev_err_ratelimited(wsa2_dev, "%s: Invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static int lpass_cdc_wsa2_macro_enable_echo(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 device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u16 val, ec_tx = 0, ec_hq_reg; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa2_dev, "%s %d %s\n", __func__, event, w->name); + + val = snd_soc_component_read(component, + LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0); + if (!(strcmp(w->name, "WSA2 RX_MIX EC0_MUX"))) + ec_tx = (val & 0x07) - 1; + else + ec_tx = ((val & 0x38) >> 0x3) - 1; + + if (ec_tx < 0 || ec_tx >= (LPASS_CDC_WSA2_MACRO_RX1 + 1)) { + dev_err_ratelimited(wsa2_dev, "%s: EC mix control not set correctly\n", + __func__); + return -EINVAL; + } + if (wsa2_priv->ec_hq[ec_tx]) { + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX_INP_MUX_RX_MIX_CFG0, + 0x1 << ec_tx, 0x1 << ec_tx); + ec_hq_reg = LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_PATH_CTL + + 0x40 * ec_tx; + snd_soc_component_update_bits(component, ec_hq_reg, 0x01, 0x01); + ec_hq_reg = LPASS_CDC_WSA2_EC_HQ0_EC_REF_HQ_CFG0 + + 0x40 * ec_tx; + /* default set to 48k */ + snd_soc_component_update_bits(component, ec_hq_reg, 0x1E, 0x08); + } + + return 0; +} + +static int lpass_cdc_wsa2_macro_get_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->ec_hq[ec_tx]; + return 0; +} + +static int lpass_cdc_wsa2_macro_set_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + dev_dbg(wsa2_dev, "%s: enable current %d, new %d\n", + __func__, wsa2_priv->ec_hq[ec_tx], value); + wsa2_priv->ec_hq[ec_tx] = value; + + return 0; +} + +static int lpass_cdc_wsa2_macro_get_rx_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + int wsa2_rx_shift = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + wsa2_priv->wsa2_digital_mute_status[wsa2_rx_shift]; + return 0; +} + +static int lpass_cdc_wsa2_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + int value = ucontrol->value.integer.value[0]; + int wsa2_rx_shift = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int ret = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + pm_runtime_get_sync(wsa2_priv->dev); + switch (wsa2_rx_shift) { + case 0: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX0_RX_PATH_CTL, + 0x10, value << 4); + break; + case 1: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX1_RX_PATH_CTL, + 0x10, value << 4); + break; + case 2: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CTL, + 0x10, value << 4); + break; + case 3: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CTL, + 0x10, value << 4); + break; + default: + pr_err_ratelimited("%s: invalid argument rx_shift = %d\n", __func__, + wsa2_rx_shift); + ret = -EINVAL; + } + pm_runtime_mark_last_busy(wsa2_priv->dev); + pm_runtime_put_autosuspend(wsa2_priv->dev); + + dev_dbg(component->dev, "%s: WSA2 Digital Mute RX %d Enable %d\n", + __func__, wsa2_rx_shift, value); + wsa2_priv->wsa2_digital_mute_status[wsa2_rx_shift] = value; + + return ret; +} + +static int lpass_cdc_wsa2_macro_set_digital_volume(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u8 gain = 0; + int ret = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (!wsa2_priv) { + pr_err_ratelimited("%s: priv is null for macro!\n", + __func__); + return -EINVAL; + } + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (mc->reg == LPASS_CDC_WSA2_RX0_RX_VOL_CTL) { + wsa2_priv->rx0_origin_gain = + (u8)snd_soc_component_read(wsa2_priv->component, + mc->reg); + gain = (u8)(wsa2_priv->rx0_origin_gain - + wsa2_priv->thermal_cur_state); + } else if (mc->reg == LPASS_CDC_WSA2_RX1_RX_VOL_CTL) { + wsa2_priv->rx1_origin_gain = + (u8)snd_soc_component_read(wsa2_priv->component, + mc->reg); + gain = (u8)(wsa2_priv->rx1_origin_gain - + wsa2_priv->thermal_cur_state); + } else { + dev_err_ratelimited(wsa2_priv->dev, + "%s: Incorrect RX Path selected\n", __func__); + return -EINVAL; + } + + /* only adjust gain if thermal state is positive */ + if (wsa2_priv->dapm_mclk_enable && + wsa2_priv->thermal_cur_state > 0) { + snd_soc_component_update_bits(wsa2_priv->component, + mc->reg, 0xFF, gain); + dev_dbg(wsa2_priv->dev, + "%s: Current thermal state: %d, adjusted gain: %x\n", + __func__, wsa2_priv->thermal_cur_state, gain); + } + + return ret; +} + +static int lpass_cdc_wsa2_macro_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->comp_enabled[comp]; + return 0; +} + +static int lpass_cdc_wsa2_macro_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, wsa2_priv->comp_enabled[comp], value); + wsa2_priv->comp_enabled[comp] = value; + + return 0; +} + +static int lpass_cdc_wsa2_macro_ear_spkrrecv_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->wsa2_spkrrecv; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa2_macro_ear_spkrrecv_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->wsa2_spkrrecv = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s:spkrrecv status = %d\n", + __func__, wsa2_priv->wsa2_spkrrecv); + + return 0; +} + +static int lpass_cdc_wsa2_macro_idle_detect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct device *wsa2_dev = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->idle_detect_en; + + return 0; +} + +static int lpass_cdc_wsa2_macro_idle_detect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct device *wsa2_dev = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->idle_detect_en = ucontrol->value.integer.value[0]; + + return 0; +} + +static int lpass_cdc_wsa2_macro_comp_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u16 idx = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (strnstr(kcontrol->id.name, "RX0", sizeof("WSA2_RX0"))) + idx = LPASS_CDC_WSA2_MACRO_COMP1; + if (strnstr(kcontrol->id.name, "RX1", sizeof("WSA2_RX1"))) + idx = LPASS_CDC_WSA2_MACRO_COMP2; + ucontrol->value.integer.value[0] = wsa2_priv->comp_mode[idx]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa2_macro_comp_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u16 idx = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (strnstr(kcontrol->id.name, "RX0", sizeof("WSA2_RX0"))) + idx = LPASS_CDC_WSA2_MACRO_COMP1; + if (strnstr(kcontrol->id.name, "RX1", sizeof("WSA2_RX1"))) + idx = LPASS_CDC_WSA2_MACRO_COMP2; + + if (ucontrol->value.integer.value[0] < G_MAX_DB && + ucontrol->value.integer.value[0] >= 0) + wsa2_priv->comp_mode[idx] = ucontrol->value.integer.value[0]; + else + return 0; + + dev_dbg(component->dev, "%s: comp_mode = %d\n", __func__, + wsa2_priv->comp_mode[idx]); + + return 0; +} + +static int lpass_cdc_wsa2_macro_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = + wsa2_priv->rx_port_value[widget->shift]; + return 0; +} + +static int lpass_cdc_wsa2_macro_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 rx_port_value = ucontrol->value.integer.value[0]; + u32 bit_input = 0; + u32 aif_rst; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + aif_rst = wsa2_priv->rx_port_value[widget->shift]; + if (!rx_port_value) { + if (aif_rst == 0) { + dev_err_ratelimited(wsa2_dev, "%s: AIF reset already\n", __func__); + return 0; + } + if (aif_rst >= LPASS_CDC_WSA2_MACRO_MAX_DAIS) { + dev_err_ratelimited(wsa2_dev, "%s: Invalid AIF reset\n", __func__); + return 0; + } + } + wsa2_priv->rx_port_value[widget->shift] = rx_port_value; + + bit_input = widget->shift; + + dev_dbg(wsa2_dev, + "%s: mux input: %d, mux output: %d, bit: %d\n", + __func__, rx_port_value, widget->shift, bit_input); + + switch (rx_port_value) { + case 0: + if (wsa2_priv->active_ch_cnt[aif_rst]) { + clear_bit(bit_input, + &wsa2_priv->active_ch_mask[aif_rst]); + wsa2_priv->active_ch_cnt[aif_rst]--; + } + break; + case 1: + case 2: + set_bit(bit_input, + &wsa2_priv->active_ch_mask[rx_port_value]); + wsa2_priv->active_ch_cnt[rx_port_value]++; + break; + default: + dev_err_ratelimited(wsa2_dev, + "%s: Invalid AIF_ID for WSA2 RX MUX %d\n", + __func__, rx_port_value); + return -EINVAL; + } + + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + return 0; +} + +static int lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_func_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ucontrol->value.integer.value[0] = + ((snd_soc_component_read( + component, LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG) & 0x04) ? + 1 : 0); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_func_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + /* Set Vbat register configuration for GSM mode bit based on value */ + if (ucontrol->value.integer.value[0]) + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG, + 0x04, 0x04); + else + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_VBAT_BCL_VBAT_CFG, + 0x04, 0x00); + + return 0; +} + +static int lpass_cdc_wsa2_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + int path = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->is_softclip_on[path]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa2_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + int path = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->is_softclip_on[path] = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: soft clip enable for %d: %d\n", __func__, + path, wsa2_priv->is_softclip_on[path]); + + return 0; +} + +static int lpass_cdc_wsa2_macro_pbr_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->pbr_enable; + return 0; +} + +static int lpass_cdc_wsa2_macro_pbr_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->pbr_enable = ucontrol->value.integer.value[0]; + return 0; + +} + +static int lpass_cdc_wsa2_macro_2ch_dma_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->wsa2_2ch_dma_enable; + return 0; +} + +static int lpass_cdc_wsa2_macro_2ch_dma_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->wsa2_2ch_dma_enable = ucontrol->value.integer.value[0]; + return 0; +} + +static const struct snd_kcontrol_new lpass_cdc_wsa2_macro_snd_controls[] = { + SOC_ENUM_EXT("WSA2_GSM mode Enable", lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_enum, + lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_func_get, + lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_func_put), + SOC_ENUM_EXT("WSA2_RX0 comp_mode", lpass_cdc_wsa2_macro_comp_mode_enum, + lpass_cdc_wsa2_macro_comp_mode_get, + lpass_cdc_wsa2_macro_comp_mode_put), + SOC_ENUM_EXT("WSA2_RX1 comp_mode", lpass_cdc_wsa2_macro_comp_mode_enum, + lpass_cdc_wsa2_macro_comp_mode_get, + lpass_cdc_wsa2_macro_comp_mode_put), + SOC_SINGLE_EXT("WSA2 SPKRRECV", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_wsa2_macro_ear_spkrrecv_get, + lpass_cdc_wsa2_macro_ear_spkrrecv_put), + SOC_SINGLE_EXT("WSA2 Idle Detect", SND_SOC_NOPM, 0, 1, + 0, lpass_cdc_wsa2_macro_idle_detect_get, + lpass_cdc_wsa2_macro_idle_detect_put), + SOC_SINGLE_EXT("WSA2_Softclip0 Enable", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_SOFTCLIP0, 1, 0, + lpass_cdc_wsa2_macro_soft_clip_enable_get, + lpass_cdc_wsa2_macro_soft_clip_enable_put), + SOC_SINGLE_EXT("WSA2_Softclip1 Enable", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_SOFTCLIP1, 1, 0, + lpass_cdc_wsa2_macro_soft_clip_enable_get, + lpass_cdc_wsa2_macro_soft_clip_enable_put), + LPASS_CDC_WSA2_MACRO_SET_VOLUME_TLV("WSA2_RX0 Digital Volume", + LPASS_CDC_WSA2_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + LPASS_CDC_WSA2_MACRO_SET_VOLUME_TLV("WSA2_RX1 Digital Volume", + LPASS_CDC_WSA2_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_EXT("WSA2_RX0 Digital Mute", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX0, 1, + 0, lpass_cdc_wsa2_macro_get_rx_mute_status, + lpass_cdc_wsa2_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA2_RX1 Digital Mute", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX1, 1, + 0, lpass_cdc_wsa2_macro_get_rx_mute_status, + lpass_cdc_wsa2_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA2_RX0_MIX Digital Mute", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_RX_MIX0, 1, 0, lpass_cdc_wsa2_macro_get_rx_mute_status, + lpass_cdc_wsa2_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA2_RX1_MIX Digital Mute", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_RX_MIX1, 1, 0, lpass_cdc_wsa2_macro_get_rx_mute_status, + lpass_cdc_wsa2_macro_set_rx_mute_status), + SOC_SINGLE_EXT("WSA2_COMP1 Switch", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_COMP1, 1, 0, + lpass_cdc_wsa2_macro_get_compander, lpass_cdc_wsa2_macro_set_compander), + SOC_SINGLE_EXT("WSA2_COMP2 Switch", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_COMP2, 1, 0, + lpass_cdc_wsa2_macro_get_compander, lpass_cdc_wsa2_macro_set_compander), + SOC_SINGLE_EXT("WSA2_RX0 EC_HQ Switch", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX0, + 1, 0, lpass_cdc_wsa2_macro_get_ec_hq, lpass_cdc_wsa2_macro_set_ec_hq), + SOC_SINGLE_EXT("WSA2_RX1 EC_HQ Switch", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX1, + 1, 0, lpass_cdc_wsa2_macro_get_ec_hq, lpass_cdc_wsa2_macro_set_ec_hq), + SOC_SINGLE_EXT("WSA2 PBR Enable", SND_SOC_NOPM, 0, 1, + 0, lpass_cdc_wsa2_macro_pbr_enable_get, + lpass_cdc_wsa2_macro_pbr_enable_put), + SOC_SINGLE_EXT("WSA2 2CH_DMA ENABLE", SND_SOC_NOPM, 0, 1, + 0, lpass_cdc_wsa2_macro_2ch_dma_enable_get, + lpass_cdc_wsa2_macro_2ch_dma_enable_put), +}; + +static const struct soc_enum rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_mux_text), rx_mux_text); + +static const struct snd_kcontrol_new rx_mux[LPASS_CDC_WSA2_MACRO_RX_MAX] = { + SOC_DAPM_ENUM_EXT("WSA2 RX0 Mux", rx_mux_enum, + lpass_cdc_wsa2_macro_rx_mux_get, lpass_cdc_wsa2_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA2 RX1 Mux", rx_mux_enum, + lpass_cdc_wsa2_macro_rx_mux_get, lpass_cdc_wsa2_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA2 RX_MIX0 Mux", rx_mux_enum, + lpass_cdc_wsa2_macro_rx_mux_get, lpass_cdc_wsa2_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA2 RX_MIX1 Mux", rx_mux_enum, + lpass_cdc_wsa2_macro_rx_mux_get, lpass_cdc_wsa2_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA2 RX4 Mux", rx_mux_enum, + lpass_cdc_wsa2_macro_rx_mux_get, lpass_cdc_wsa2_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA2 RX5 Mux", rx_mux_enum, + lpass_cdc_wsa2_macro_rx_mux_get, lpass_cdc_wsa2_macro_rx_mux_put), +}; + +static int lpass_cdc_wsa2_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 spk_tx_id = mixer->shift; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (test_bit(spk_tx_id, &wsa2_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int lpass_cdc_wsa2_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 spk_tx_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->vi_feed_value = ucontrol->value.integer.value[0]; + + if (enable) { + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX0 && + !test_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + set_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_VI]++; + } + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX1 && + !test_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + set_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_VI]++; + } + } else { + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX0 && + test_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + clear_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_VI]--; + } + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX1 && + test_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI])) { + clear_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_VI]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_VI]--; + } + } + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +static const struct snd_kcontrol_new aif_vi_mixer[] = { + SOC_SINGLE_EXT("WSA2_SPKR_VI_1", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_TX0, 1, 0, + lpass_cdc_wsa2_macro_vi_feed_mixer_get, + lpass_cdc_wsa2_macro_vi_feed_mixer_put), + SOC_SINGLE_EXT("WSA2_SPKR_VI_2", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_TX1, 1, 0, + lpass_cdc_wsa2_macro_vi_feed_mixer_get, + lpass_cdc_wsa2_macro_vi_feed_mixer_put), +}; + +static int lpass_cdc_wsa2_macro_cps_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 spk_tx_id = mixer->shift; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (test_bit(spk_tx_id, &wsa2_priv->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int lpass_cdc_wsa2_macro_cps_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 spk_tx_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (enable) { + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX0 && + !test_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS])) { + set_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_CPS]++; + } + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX1 && + !test_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS])) { + set_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_CPS]++; + } + } else { + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX0 && + test_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS])) { + clear_bit(LPASS_CDC_WSA2_MACRO_TX0, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_CPS]--; + } + if (spk_tx_id == LPASS_CDC_WSA2_MACRO_TX1 && + test_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS])) { + clear_bit(LPASS_CDC_WSA2_MACRO_TX1, + &wsa2_priv->active_ch_mask[LPASS_CDC_WSA2_MACRO_AIF_CPS]); + wsa2_priv->active_ch_cnt[LPASS_CDC_WSA2_MACRO_AIF_CPS]--; + } + } + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +static const struct snd_kcontrol_new aif_cps_mixer[] = { + SOC_SINGLE_EXT("WSA2_SPKR_CPS_1", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_TX0, 1, 0, + lpass_cdc_wsa2_macro_cps_feed_mixer_get, + lpass_cdc_wsa2_macro_cps_feed_mixer_put), + SOC_SINGLE_EXT("WSA2_SPKR_CPS_2", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_TX1, 1, 0, + lpass_cdc_wsa2_macro_cps_feed_mixer_get, + lpass_cdc_wsa2_macro_cps_feed_mixer_put), +}; + +static const struct snd_soc_dapm_widget lpass_cdc_wsa2_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("WSA2 AIF1 PB", "WSA2_AIF1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("WSA2 AIF_MIX1 PB", "WSA2_AIF_MIX1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT_E("WSA2 AIF_VI", "WSA2_AIF_VI Capture", 0, + SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_AIF_VI, 0, + lpass_cdc_wsa2_macro_disable_vi_feedback, + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT("WSA2 AIF_ECHO", "WSA2_AIF_ECHO Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("WSA2 AIF_CPS", "WSA2_AIF_CPS Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER("WSA2_AIF_VI Mixer", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_AIF_VI, + 0, aif_vi_mixer, ARRAY_SIZE(aif_vi_mixer)), + SND_SOC_DAPM_MIXER("WSA2_AIF_CPS Mixer", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_AIF_CPS, + 0, aif_cps_mixer, ARRAY_SIZE(aif_cps_mixer)), + SND_SOC_DAPM_MUX_E("WSA2 RX_MIX EC0_MUX", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_EC0_MUX, 0, + &rx_mix_ec0_mux, lpass_cdc_wsa2_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2 RX_MIX EC1_MUX", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_EC1_MUX, 0, + &rx_mix_ec1_mux, lpass_cdc_wsa2_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("WSA2 RX0 MUX", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX0, 0, + &rx_mux[LPASS_CDC_WSA2_MACRO_RX0]), + SND_SOC_DAPM_MUX("WSA2 RX1 MUX", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX1, 0, + &rx_mux[LPASS_CDC_WSA2_MACRO_RX1]), + SND_SOC_DAPM_MUX("WSA2 RX_MIX0 MUX", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX_MIX0, 0, + &rx_mux[LPASS_CDC_WSA2_MACRO_RX_MIX0]), + SND_SOC_DAPM_MUX("WSA2 RX_MIX1 MUX", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX_MIX1, 0, + &rx_mux[LPASS_CDC_WSA2_MACRO_RX_MIX1]), + SND_SOC_DAPM_MUX("WSA2 RX4 MUX", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX4, 0, + &rx_mux[LPASS_CDC_WSA2_MACRO_RX4]), + SND_SOC_DAPM_MUX("WSA2 RX5 MUX", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX5, 0, + &rx_mux[LPASS_CDC_WSA2_MACRO_RX5]), + + SND_SOC_DAPM_MIXER("WSA2 RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA2 RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA2 RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA2 RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA2 RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA2 RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("WSA2_RX0 INP0", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp0_mux, lpass_cdc_wsa2_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2_RX0 INP1", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp1_mux, lpass_cdc_wsa2_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2_RX0 INP2", SND_SOC_NOPM, 0, 0, + &rx0_prim_inp2_mux, lpass_cdc_wsa2_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2_RX0 MIX INP", SND_SOC_NOPM, + 0, 0, &rx0_mix_mux, lpass_cdc_wsa2_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2_RX1 INP0", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp0_mux, lpass_cdc_wsa2_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2_RX1 INP1", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp1_mux, lpass_cdc_wsa2_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2_RX1 INP2", SND_SOC_NOPM, 0, 0, + &rx1_prim_inp2_mux, lpass_cdc_wsa2_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA2_RX1 MIX INP", SND_SOC_NOPM, + 0, 0, &rx1_mix_mux, lpass_cdc_wsa2_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("WSA2_RX INT0 MIX", SND_SOC_NOPM, + 0, 0, NULL, 0, lpass_cdc_wsa2_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_E("WSA2_RX INT1 MIX", SND_SOC_NOPM, + 1, 0, NULL, 0, lpass_cdc_wsa2_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER("WSA2_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA2_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("WSA2_RX0 INT0 SIDETONE MIX", + LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, 4, 0, + &rx0_sidetone_mix_mux, lpass_cdc_wsa2_macro_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_INPUT("WSA2 SRC0_INP"), + + SND_SOC_DAPM_INPUT("WSA2_TX DEC0_INP"), + SND_SOC_DAPM_INPUT("WSA2_TX DEC1_INP"), + + SND_SOC_DAPM_MIXER_E("WSA2_RX INT0 INTERP", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_COMP1, 0, NULL, 0, lpass_cdc_wsa2_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA2_RX INT1 INTERP", SND_SOC_NOPM, + LPASS_CDC_WSA2_MACRO_COMP2, 0, NULL, 0, lpass_cdc_wsa2_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA2_RX INT0 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, lpass_cdc_wsa2_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA2_RX INT1 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, lpass_cdc_wsa2_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA2_RX INT0 VBAT", SND_SOC_NOPM, + 0, 0, wsa2_int0_vbat_mix_switch, + ARRAY_SIZE(wsa2_int0_vbat_mix_switch), + lpass_cdc_wsa2_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("WSA2_RX INT1 VBAT", SND_SOC_NOPM, + 0, 0, wsa2_int1_vbat_mix_switch, + ARRAY_SIZE(wsa2_int1_vbat_mix_switch), + lpass_cdc_wsa2_macro_enable_vbat, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("VIINPUT_WSA2"), + + SND_SOC_DAPM_INPUT("CPSINPUT_WSA2"), + + SND_SOC_DAPM_OUTPUT("WSA2_SPK1 OUT"), + SND_SOC_DAPM_OUTPUT("WSA2_SPK2 OUT"), + + SND_SOC_DAPM_SUPPLY_S("WSA2_MCLK", 0, SND_SOC_NOPM, 0, 0, + lpass_cdc_wsa2_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route wsa2_audio_map[] = { + /* VI Feedback */ + {"WSA2_AIF_VI Mixer", "WSA2_SPKR_VI_1", "VIINPUT_WSA2"}, + {"WSA2_AIF_VI Mixer", "WSA2_SPKR_VI_2", "VIINPUT_WSA2"}, + {"WSA2 AIF_VI", NULL, "WSA2_AIF_VI Mixer"}, + {"WSA2 AIF_VI", NULL, "WSA2_MCLK"}, + + /* VI Feedback */ + {"WSA2_AIF_CPS Mixer", "WSA2_SPKR_CPS_1", "CPSINPUT_WSA2"}, + {"WSA2_AIF_CPS Mixer", "WSA2_SPKR_CPS_2", "CPSINPUT_WSA2"}, + {"WSA2 AIF_CPS", NULL, "WSA2_AIF_CPS Mixer"}, + {"WSA2 AIF_CPS", NULL, "WSA2_MCLK"}, + + {"WSA2 RX_MIX EC0_MUX", "RX_MIX_TX0", "WSA2_RX INT0 SEC MIX"}, + {"WSA2 RX_MIX EC1_MUX", "RX_MIX_TX0", "WSA2_RX INT0 SEC MIX"}, + {"WSA2 RX_MIX EC0_MUX", "RX_MIX_TX1", "WSA2_RX INT1 SEC MIX"}, + {"WSA2 RX_MIX EC1_MUX", "RX_MIX_TX1", "WSA2_RX INT1 SEC MIX"}, + {"WSA2 AIF_ECHO", NULL, "WSA2 RX_MIX EC0_MUX"}, + {"WSA2 AIF_ECHO", NULL, "WSA2 RX_MIX EC1_MUX"}, + {"WSA2 AIF_ECHO", NULL, "WSA2_MCLK"}, + + {"WSA2 AIF1 PB", NULL, "WSA2_MCLK"}, + {"WSA2 AIF_MIX1 PB", NULL, "WSA2_MCLK"}, + + {"WSA2 RX0 MUX", "AIF1_PB", "WSA2 AIF1 PB"}, + {"WSA2 RX1 MUX", "AIF1_PB", "WSA2 AIF1 PB"}, + {"WSA2 RX_MIX0 MUX", "AIF1_PB", "WSA2 AIF1 PB"}, + {"WSA2 RX_MIX1 MUX", "AIF1_PB", "WSA2 AIF1 PB"}, + {"WSA2 RX4 MUX", "AIF1_PB", "WSA2 AIF1 PB"}, + {"WSA2 RX5 MUX", "AIF1_PB", "WSA2 AIF1 PB"}, + + {"WSA2 RX0 MUX", "AIF_MIX1_PB", "WSA2 AIF_MIX1 PB"}, + {"WSA2 RX1 MUX", "AIF_MIX1_PB", "WSA2 AIF_MIX1 PB"}, + {"WSA2 RX_MIX0 MUX", "AIF_MIX1_PB", "WSA2 AIF_MIX1 PB"}, + {"WSA2 RX_MIX1 MUX", "AIF_MIX1_PB", "WSA2 AIF_MIX1 PB"}, + {"WSA2 RX4 MUX", "AIF_MIX1_PB", "WSA2 AIF_MIX1 PB"}, + {"WSA2 RX5 MUX", "AIF_MIX1_PB", "WSA2 AIF_MIX1 PB"}, + + {"WSA2 RX0", NULL, "WSA2 RX0 MUX"}, + {"WSA2 RX1", NULL, "WSA2 RX1 MUX"}, + {"WSA2 RX_MIX0", NULL, "WSA2 RX_MIX0 MUX"}, + {"WSA2 RX_MIX1", NULL, "WSA2 RX_MIX1 MUX"}, + {"WSA2 RX4", NULL, "WSA2 RX4 MUX"}, + {"WSA2 RX5", NULL, "WSA2 RX5 MUX"}, + + {"WSA2_RX0 INP0", "RX0", "WSA2 RX0"}, + {"WSA2_RX0 INP0", "RX1", "WSA2 RX1"}, + {"WSA2_RX0 INP0", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX0 INP0", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX0 INP0", "RX4", "WSA2 RX4"}, + {"WSA2_RX0 INP0", "RX5", "WSA2 RX5"}, + {"WSA2_RX0 INP0", "DEC0", "WSA2_TX DEC0_INP"}, + {"WSA2_RX0 INP0", "DEC1", "WSA2_TX DEC1_INP"}, + {"WSA2_RX INT0 MIX", NULL, "WSA2_RX0 INP0"}, + + {"WSA2_RX0 INP1", "RX0", "WSA2 RX0"}, + {"WSA2_RX0 INP1", "RX1", "WSA2 RX1"}, + {"WSA2_RX0 INP1", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX0 INP1", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX0 INP1", "RX4", "WSA2 RX4"}, + {"WSA2_RX0 INP1", "RX5", "WSA2 RX5"}, + {"WSA2_RX0 INP1", "DEC0", "WSA2_TX DEC0_INP"}, + {"WSA2_RX0 INP1", "DEC1", "WSA2_TX DEC1_INP"}, + {"WSA2_RX INT0 MIX", NULL, "WSA2_RX0 INP1"}, + + {"WSA2_RX0 INP2", "RX0", "WSA2 RX0"}, + {"WSA2_RX0 INP2", "RX1", "WSA2 RX1"}, + {"WSA2_RX0 INP2", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX0 INP2", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX0 INP2", "RX4", "WSA2 RX4"}, + {"WSA2_RX0 INP2", "RX5", "WSA2 RX5"}, + {"WSA2_RX0 INP2", "DEC0", "WSA2_TX DEC0_INP"}, + {"WSA2_RX0 INP2", "DEC1", "WSA2_TX DEC1_INP"}, + {"WSA2_RX INT0 MIX", NULL, "WSA2_RX0 INP2"}, + + {"WSA2_RX0 MIX INP", "RX0", "WSA2 RX0"}, + {"WSA2_RX0 MIX INP", "RX1", "WSA2 RX1"}, + {"WSA2_RX0 MIX INP", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX0 MIX INP", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX0 MIX INP", "RX4", "WSA2 RX4"}, + {"WSA2_RX0 MIX INP", "RX5", "WSA2 RX5"}, + {"WSA2_RX INT0 SEC MIX", NULL, "WSA2_RX0 MIX INP"}, + + {"WSA2_RX INT0 SEC MIX", NULL, "WSA2_RX INT0 MIX"}, + {"WSA2_RX INT0 INTERP", NULL, "WSA2_RX INT0 SEC MIX"}, + {"WSA2_RX0 INT0 SIDETONE MIX", "SRC0", "WSA2 SRC0_INP"}, + {"WSA2_RX INT0 INTERP", NULL, "WSA2_RX0 INT0 SIDETONE MIX"}, + {"WSA2_RX INT0 CHAIN", NULL, "WSA2_RX INT0 INTERP"}, + + {"WSA2_RX INT0 VBAT", "WSA2 RX0 VBAT Enable", "WSA2_RX INT0 INTERP"}, + {"WSA2_RX INT0 CHAIN", NULL, "WSA2_RX INT0 VBAT"}, + + {"WSA2_SPK1 OUT", NULL, "WSA2_RX INT0 CHAIN"}, + {"WSA2_SPK1 OUT", NULL, "WSA2_MCLK"}, + + {"WSA2_RX1 INP0", "RX0", "WSA2 RX0"}, + {"WSA2_RX1 INP0", "RX1", "WSA2 RX1"}, + {"WSA2_RX1 INP0", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX1 INP0", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX1 INP0", "RX4", "WSA2 RX4"}, + {"WSA2_RX1 INP0", "RX5", "WSA2 RX5"}, + {"WSA2_RX1 INP0", "DEC0", "WSA2_TX DEC0_INP"}, + {"WSA2_RX1 INP0", "DEC1", "WSA2_TX DEC1_INP"}, + {"WSA2_RX INT1 MIX", NULL, "WSA2_RX1 INP0"}, + + {"WSA2_RX1 INP1", "RX0", "WSA2 RX0"}, + {"WSA2_RX1 INP1", "RX1", "WSA2 RX1"}, + {"WSA2_RX1 INP1", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX1 INP1", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX1 INP1", "RX4", "WSA2 RX4"}, + {"WSA2_RX1 INP1", "RX5", "WSA2 RX5"}, + {"WSA2_RX1 INP1", "DEC0", "WSA2_TX DEC0_INP"}, + {"WSA2_RX1 INP1", "DEC1", "WSA2_TX DEC1_INP"}, + {"WSA2_RX INT1 MIX", NULL, "WSA2_RX1 INP1"}, + + {"WSA2_RX1 INP2", "RX0", "WSA2 RX0"}, + {"WSA2_RX1 INP2", "RX1", "WSA2 RX1"}, + {"WSA2_RX1 INP2", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX1 INP2", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX1 INP2", "RX4", "WSA2 RX4"}, + {"WSA2_RX1 INP2", "RX5", "WSA2 RX5"}, + {"WSA2_RX1 INP2", "DEC0", "WSA2_TX DEC0_INP"}, + {"WSA2_RX1 INP2", "DEC1", "WSA2_TX DEC1_INP"}, + {"WSA2_RX INT1 MIX", NULL, "WSA2_RX1 INP2"}, + + {"WSA2_RX1 MIX INP", "RX0", "WSA2 RX0"}, + {"WSA2_RX1 MIX INP", "RX1", "WSA2 RX1"}, + {"WSA2_RX1 MIX INP", "RX_MIX0", "WSA2 RX_MIX0"}, + {"WSA2_RX1 MIX INP", "RX_MIX1", "WSA2 RX_MIX1"}, + {"WSA2_RX1 MIX INP", "RX4", "WSA2 RX4"}, + {"WSA2_RX1 MIX INP", "RX5", "WSA2 RX5"}, + {"WSA2_RX INT1 SEC MIX", NULL, "WSA2_RX1 MIX INP"}, + + {"WSA2_RX INT1 SEC MIX", NULL, "WSA2_RX INT1 MIX"}, + {"WSA2_RX INT1 INTERP", NULL, "WSA2_RX INT1 SEC MIX"}, + + {"WSA2_RX INT1 VBAT", "WSA2 RX1 VBAT Enable", "WSA2_RX INT1 INTERP"}, + {"WSA2_RX INT1 CHAIN", NULL, "WSA2_RX INT1 VBAT"}, + + {"WSA2_RX INT1 CHAIN", NULL, "WSA2_RX INT1 INTERP"}, + {"WSA2_SPK2 OUT", NULL, "WSA2_RX INT1 CHAIN"}, + {"WSA2_SPK2 OUT", NULL, "WSA2_MCLK"}, +}; + +static void lpass_cdc_wsa2_macro_init_pbr(struct snd_soc_component *component) +{ + int sys_gain, bat_cfg, rload; + int vth1, vth2, vth3, vth4, vth5, vth6, vth7, vth8, vth9; + int vth10, vth11, vth12, vth13, vth14, vth15; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return; + + /* RX0 */ + sys_gain = wsa2_priv->wsa2_sys_gain[0]; + bat_cfg = wsa2_priv->wsa2_bat_cfg[0]; + rload = wsa2_priv->wsa2_rload[0]; + /* ILIM */ + switch (rload) { + case WSA_4_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0x40); + break; + case WSA_6_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0x80); + break; + case WSA_8_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0xC0); + break; + case WSA_32_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0xE0); + break; + default: + break; + } + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG1, 0x0F, sys_gain); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG9, 0xC0, (bat_cfg - 1) << 0x6); + /* Thesh */ + vth1 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth1_data[sys_gain][bat_cfg][rload]); + vth2 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth2_data[sys_gain][bat_cfg][rload]); + vth3 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth3_data[sys_gain][bat_cfg][rload]); + vth4 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth4_data[sys_gain][bat_cfg][rload]); + vth5 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth5_data[sys_gain][bat_cfg][rload]); + vth6 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth6_data[sys_gain][bat_cfg][rload]); + vth7 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth7_data[sys_gain][bat_cfg][rload]); + vth8 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth8_data[sys_gain][bat_cfg][rload]); + vth9 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth9_data[sys_gain][bat_cfg][rload]); + vth10 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth10_data[sys_gain][bat_cfg][rload]); + vth11 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth11_data[sys_gain][bat_cfg][rload]); + vth12 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth12_data[sys_gain][bat_cfg][rload]); + vth13 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth13_data[sys_gain][bat_cfg][rload]); + vth14 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth14_data[sys_gain][bat_cfg][rload]); + vth15 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth15_data[sys_gain][bat_cfg][rload]); + + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG1, vth1); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG2, vth2); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG3, vth3); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG4, vth4); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG5, vth5); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG6, vth6); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG7, vth7); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG8, vth8); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG9, vth9); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG10, vth10); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG11, vth11); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG12, vth12); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG13, vth13); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG14, vth14); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG15, vth15); + + /* RX1 */ + sys_gain = wsa2_priv->wsa2_sys_gain[2]; + bat_cfg = wsa2_priv->wsa2_bat_cfg[1]; + rload = wsa2_priv->wsa2_rload[1]; + /* ILIM */ + switch (rload) { + case WSA_4_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0x40); + break; + case WSA_6_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0x80); + break; + case WSA_8_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0xC0); + break; + case WSA_32_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0xE0); + break; + default: + break; + } + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG1_1, 0x0F, sys_gain); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG9, 0x30, (bat_cfg - 1) << 0x4); + /* Thesh */ + vth1 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth1_data[sys_gain][bat_cfg][rload]); + vth2 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth2_data[sys_gain][bat_cfg][rload]); + vth3 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth3_data[sys_gain][bat_cfg][rload]); + vth4 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth4_data[sys_gain][bat_cfg][rload]); + vth5 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth5_data[sys_gain][bat_cfg][rload]); + vth6 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth6_data[sys_gain][bat_cfg][rload]); + vth7 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth7_data[sys_gain][bat_cfg][rload]); + vth8 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth8_data[sys_gain][bat_cfg][rload]); + vth9 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth9_data[sys_gain][bat_cfg][rload]); + vth10 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth10_data[sys_gain][bat_cfg][rload]); + vth11 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth11_data[sys_gain][bat_cfg][rload]); + vth12 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth12_data[sys_gain][bat_cfg][rload]); + vth13 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth13_data[sys_gain][bat_cfg][rload]); + vth14 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth14_data[sys_gain][bat_cfg][rload]); + vth15 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth15_data[sys_gain][bat_cfg][rload]); + + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG1_1, vth1); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG2_1, vth2); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG3_1, vth3); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG4_1, vth4); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG5_1, vth5); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG6_1, vth6); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG7_1, vth7); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG8_1, vth8); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG9_1, vth9); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG10_1, vth10); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG11_1, vth11); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG12_1, vth12); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG13_1, vth13); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG14_1, vth14); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG15_1, vth15); +} + +static const struct lpass_cdc_wsa2_macro_reg_mask_val + lpass_cdc_wsa2_macro_reg_init[] = { + {LPASS_CDC_WSA2_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {LPASS_CDC_WSA2_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {LPASS_CDC_WSA2_COMPANDER0_CTL7, 0x3E, 0x2e}, + {LPASS_CDC_WSA2_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {LPASS_CDC_WSA2_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {LPASS_CDC_WSA2_COMPANDER1_CTL7, 0x3E, 0x2e}, + {LPASS_CDC_WSA2_BOOST0_BOOST_CTL, 0x70, 0x58}, + {LPASS_CDC_WSA2_BOOST1_BOOST_CTL, 0x70, 0x58}, + {LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, 0x08, 0x08}, + {LPASS_CDC_WSA2_RX1_RX_PATH_CFG1, 0x08, 0x08}, + {LPASS_CDC_WSA2_TOP_TOP_CFG1, 0x02, 0x02}, + {LPASS_CDC_WSA2_TOP_TOP_CFG1, 0x01, 0x01}, + {LPASS_CDC_WSA2_TX0_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA2_RX0_RX_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA2_RX1_RX_PATH_CFG0, 0x01, 0x01}, + {LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {LPASS_CDC_WSA2_LA_CFG, 0x3F, 0xF}, + {LPASS_CDC_WSA2_PBR_CFG16, 0xFF, 0x42}, + {LPASS_CDC_WSA2_PBR_CFG19, 0xFF, 0xFC}, + {LPASS_CDC_WSA2_PBR_CFG20, 0xF0, 0x60}, + {LPASS_CDC_WSA2_ILIM_CFG1, 0x70, 0x40}, + {LPASS_CDC_WSA2_ILIM_CFG0, 0x03, 0x01}, + {LPASS_CDC_WSA2_ILIM_CFG3, 0x1F, 0x15}, + {LPASS_CDC_WSA2_LA_CFG_1, 0x3F, 0x0F}, + {LPASS_CDC_WSA2_PBR_CFG16_1, 0xFF, 0x42}, + {LPASS_CDC_WSA2_PBR_CFG21, 0xFF, 0xFC}, + {LPASS_CDC_WSA2_PBR_CFG22, 0xF0, 0x60}, + {LPASS_CDC_WSA2_ILIM_CFG1_1, 0x70, 0x40}, + {LPASS_CDC_WSA2_ILIM_CFG0_1, 0x03, 0x01}, + {LPASS_CDC_WSA2_ILIM_CFG4, 0x1F, 0x15}, + {LPASS_CDC_WSA2_ILIM_CFG2_1, 0xFF, 0x2A}, + {LPASS_CDC_WSA2_ILIM_CFG2, 0x3F, 0x1B}, + {LPASS_CDC_WSA2_ILIM_CFG9, 0x0F, 0x05}, + {LPASS_CDC_WSA2_IDLE_DETECT_CFG1, 0xFF, 0x1D}, +}; + +static void lpass_cdc_wsa2_macro_init_reg(struct snd_soc_component *component) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lpass_cdc_wsa2_macro_reg_init); i++) + snd_soc_component_update_bits(component, + lpass_cdc_wsa2_macro_reg_init[i].reg, + lpass_cdc_wsa2_macro_reg_init[i].mask, + lpass_cdc_wsa2_macro_reg_init[i].val); + lpass_cdc_wsa2_macro_init_pbr(component); +} + +static int lpass_cdc_wsa2_macro_core_vote(void *handle, bool enable) +{ + int rc = 0; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = (struct lpass_cdc_wsa2_macro_priv *) handle; + + if (wsa2_priv == NULL) { + pr_err_ratelimited("%s: wsa2 priv data is NULL\n", __func__); + return -EINVAL; + } + + if (!wsa2_priv->pre_dev_up && enable) { + pr_debug("%s: adsp is not up\n", __func__); + return -EINVAL; + } + + if (enable) { + pm_runtime_get_sync(wsa2_priv->dev); + if (lpass_cdc_check_core_votes(wsa2_priv->dev)) + rc = 0; + else + rc = -ENOTSYNC; + } else { + pm_runtime_put_autosuspend(wsa2_priv->dev); + pm_runtime_mark_last_busy(wsa2_priv->dev); + } + + return rc; +} + +static int wsa2_swrm_clock(void *handle, bool enable) +{ + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = (struct lpass_cdc_wsa2_macro_priv *) handle; + struct regmap *regmap = dev_get_regmap(wsa2_priv->dev->parent, NULL); + int ret = 0; + + if (regmap == NULL) { + dev_err_ratelimited(wsa2_priv->dev, "%s: regmap is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&wsa2_priv->swr_clk_lock); + + dev_dbg(wsa2_priv->dev, "%s: swrm clock %s\n", + __func__, (enable ? "enable" : "disable")); + if (enable) { + pm_runtime_get_sync(wsa2_priv->dev); + if (wsa2_priv->swr_clk_users == 0) { + ret = msm_cdc_pinctrl_select_active_state( + wsa2_priv->wsa2_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(wsa2_priv->dev, + "%s: wsa2 swr pinctrl enable failed\n", + __func__); + pm_runtime_mark_last_busy(wsa2_priv->dev); + pm_runtime_put_autosuspend(wsa2_priv->dev); + goto exit; + } + ret = lpass_cdc_wsa2_macro_mclk_enable(wsa2_priv, 1, true); + if (ret < 0) { + msm_cdc_pinctrl_select_sleep_state( + wsa2_priv->wsa2_swr_gpio_p); + dev_err_ratelimited(wsa2_priv->dev, + "%s: wsa2 request clock enable failed\n", + __func__); + pm_runtime_mark_last_busy(wsa2_priv->dev); + pm_runtime_put_autosuspend(wsa2_priv->dev); + goto exit; + } + if (wsa2_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x02); + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + if (wsa2_priv->reset_swr) + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL, + 0x02, 0x00); + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL, + 0x1C, 0x0C); + wsa2_priv->reset_swr = false; + } + wsa2_priv->swr_clk_users++; + pm_runtime_mark_last_busy(wsa2_priv->dev); + pm_runtime_put_autosuspend(wsa2_priv->dev); + } else { + if (wsa2_priv->swr_clk_users <= 0) { + dev_err_ratelimited(wsa2_priv->dev, "%s: clock already disabled\n", + __func__); + wsa2_priv->swr_clk_users = 0; + goto exit; + } + wsa2_priv->swr_clk_users--; + if (wsa2_priv->swr_clk_users == 0) { + regmap_update_bits(regmap, + LPASS_CDC_WSA2_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + lpass_cdc_wsa2_macro_mclk_enable(wsa2_priv, 0, true); + ret = msm_cdc_pinctrl_select_sleep_state( + wsa2_priv->wsa2_swr_gpio_p); + if (ret < 0) { + dev_err_ratelimited(wsa2_priv->dev, + "%s: wsa2 swr pinctrl disable failed\n", + __func__); + goto exit; + } + } + } + dev_dbg(wsa2_priv->dev, "%s: swrm clock users %d\n", + __func__, wsa2_priv->swr_clk_users); +exit: + mutex_unlock(&wsa2_priv->swr_clk_lock); + return ret; +} + +/* Thermal Functions */ +static int lpass_cdc_wsa2_macro_get_max_state( + struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = cdev->devdata; + if (!wsa2_priv) { + pr_err_ratelimited("%s: cdev->devdata is NULL\n", __func__); + return -EINVAL; + } + *state = wsa2_priv->thermal_max_state; + + return 0; +} + +static int lpass_cdc_wsa2_macro_get_cur_state( + struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = cdev->devdata; + + if (!wsa2_priv) { + pr_err_ratelimited("%s: cdev->devdata is NULL\n", __func__); + return -EINVAL; + } + *state = wsa2_priv->thermal_cur_state; + + pr_debug("%s: thermal current state:%lu\n", __func__, *state); + return 0; +} + +static int lpass_cdc_wsa2_macro_set_cur_state( + struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = cdev->devdata; + + if (!wsa2_priv || !wsa2_priv->dev) { + pr_err_ratelimited("%s: cdev->devdata is NULL\n", __func__); + return -EINVAL; + } + + if (state <= wsa2_priv->thermal_max_state) { + wsa2_priv->thermal_cur_state = state; + } else { + dev_err_ratelimited(wsa2_priv->dev, + "%s: incorrect requested state:%d\n", + __func__, state); + return -EINVAL; + } + + dev_dbg(wsa2_priv->dev, + "%s: set the thermal current state to %d\n", + __func__, wsa2_priv->thermal_cur_state); + + schedule_work(&wsa2_priv->lpass_cdc_wsa2_macro_cooling_work); + + return 0; +} + +static struct thermal_cooling_device_ops wsa2_cooling_ops = { + .get_max_state = lpass_cdc_wsa2_macro_get_max_state, + .get_cur_state = lpass_cdc_wsa2_macro_get_cur_state, + .set_cur_state = lpass_cdc_wsa2_macro_set_cur_state, +}; + +static int lpass_cdc_wsa2_macro_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + wsa2_dev = lpass_cdc_get_device_ptr(component->dev, WSA2_MACRO); + if (!wsa2_dev) { + dev_err(component->dev, + "%s: null device for macro!\n", __func__); + return -EINVAL; + } + wsa2_priv = dev_get_drvdata(wsa2_dev); + if (!wsa2_priv) { + dev_err(component->dev, + "%s: priv is null for macro!\n", __func__); + return -EINVAL; + } + + ret = snd_soc_dapm_new_controls(dapm, lpass_cdc_wsa2_macro_dapm_widgets, + ARRAY_SIZE(lpass_cdc_wsa2_macro_dapm_widgets)); + if (ret < 0) { + dev_err(wsa2_dev, "%s: Failed to add controls\n", __func__); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, wsa2_audio_map, + ARRAY_SIZE(wsa2_audio_map)); + if (ret < 0) { + dev_err(wsa2_dev, "%s: Failed to add routes\n", __func__); + return ret; + } + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) { + dev_err(wsa2_dev, "%s: Failed to add widgets\n", __func__); + return ret; + } + + ret = snd_soc_add_component_controls(component, lpass_cdc_wsa2_macro_snd_controls, + ARRAY_SIZE(lpass_cdc_wsa2_macro_snd_controls)); + if (ret < 0) { + dev_err(wsa2_dev, "%s: Failed to add snd_ctls\n", __func__); + return ret; + } + snd_soc_dapm_ignore_suspend(dapm, "WSA2_AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2_AIF_MIX1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2_AIF_VI Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2_AIF_ECHO Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2_SPK1 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2_SPK2 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_WSA2"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2 SRC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2_TX DEC0_INP"); + snd_soc_dapm_ignore_suspend(dapm, "WSA2_TX DEC1_INP"); + snd_soc_dapm_sync(dapm); + + wsa2_priv->component = component; + wsa2_priv->spkr_gain_offset = LPASS_CDC_WSA2_MACRO_GAIN_OFFSET_0_DB; + lpass_cdc_wsa2_macro_init_reg(component); + + return 0; +} + +static int lpass_cdc_wsa2_macro_deinit(struct snd_soc_component *component) +{ + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->component = NULL; + + return 0; +} + +static void lpass_cdc_wsa2_macro_add_child_devices(struct work_struct *work) +{ + struct lpass_cdc_wsa2_macro_priv *wsa2_priv; + struct platform_device *pdev; + struct device_node *node; + struct lpass_cdc_wsa2_macro_swr_ctrl_data *swr_ctrl_data = NULL, *temp; + int ret; + u16 count = 0, ctrl_num = 0; + struct lpass_cdc_wsa2_macro_swr_ctrl_platform_data *platdata; + char plat_dev_name[LPASS_CDC_WSA2_MACRO_SWR_STRING_LEN]; + + wsa2_priv = container_of(work, struct lpass_cdc_wsa2_macro_priv, + lpass_cdc_wsa2_macro_add_child_devices_work); + if (!wsa2_priv) { + pr_err("%s: Memory for wsa2_priv does not exist\n", + __func__); + return; + } + if (!wsa2_priv->dev || !wsa2_priv->dev->of_node) { + dev_err(wsa2_priv->dev, + "%s: DT node for wsa2_priv does not exist\n", __func__); + return; + } + + platdata = &wsa2_priv->swr_plat_data; + wsa2_priv->child_count = 0; + + for_each_available_child_of_node(wsa2_priv->dev->of_node, node) { + if (strnstr(node->name, "wsa2_swr_master", + strlen("wsa2_swr_master")) != NULL) + strlcpy(plat_dev_name, "wsa2_swr_ctrl", + (LPASS_CDC_WSA2_MACRO_SWR_STRING_LEN - 1)); + else if (strnstr(node->name, "msm_cdc_pinctrl", + strlen("msm_cdc_pinctrl")) != NULL) + strlcpy(plat_dev_name, node->name, + (LPASS_CDC_WSA2_MACRO_SWR_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(wsa2_priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = wsa2_priv->dev; + pdev->dev.of_node = node; + + if (strnstr(node->name, "wsa2_swr_master", + strlen("wsa2_swr_master")) != NULL) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct lpass_cdc_wsa2_macro_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(&pdev->dev, "out of memory\n"); + ret = -ENOMEM; + goto fail_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].wsa2_swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Adding soundwire ctrl device(s)\n", + __func__); + wsa2_priv->swr_ctrl_data = swr_ctrl_data; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (wsa2_priv->child_count < LPASS_CDC_WSA2_MACRO_CHILD_DEVICES_MAX) + wsa2_priv->pdev_child_devices[ + wsa2_priv->child_count++] = pdev; + else + goto err; + } + + return; +fail_pdev_add: + for (count = 0; count < wsa2_priv->child_count; count++) + platform_device_put(wsa2_priv->pdev_child_devices[count]); +err: + return; +} + +static void lpass_cdc_wsa2_macro_cooling_adjust_gain(struct work_struct *work) +{ + struct lpass_cdc_wsa2_macro_priv *wsa2_priv; + u8 gain = 0; + + wsa2_priv = container_of(work, struct lpass_cdc_wsa2_macro_priv, + lpass_cdc_wsa2_macro_cooling_work); + if (!wsa2_priv) { + pr_err("%s: priv is null for macro!\n", + __func__); + return; + } + if (!wsa2_priv->dev || !wsa2_priv->dev->of_node) { + dev_err(wsa2_priv->dev, + "%s: DT node for wsa2_priv does not exist\n", __func__); + return; + } + + /* Only adjust the volume when WSA2 clock is enabled */ + if (wsa2_priv->dapm_mclk_enable) { + gain = (u8)(wsa2_priv->rx0_origin_gain - + wsa2_priv->thermal_cur_state); + snd_soc_component_update_bits(wsa2_priv->component, + LPASS_CDC_WSA2_RX0_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa2_priv->dev, + "%s: RX0 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa2_priv->thermal_cur_state, gain); + + gain = (u8)(wsa2_priv->rx1_origin_gain - + wsa2_priv->thermal_cur_state); + snd_soc_component_update_bits(wsa2_priv->component, + LPASS_CDC_WSA2_RX1_RX_VOL_CTL, 0xFF, gain); + dev_dbg(wsa2_priv->dev, + "%s: RX1 current thermal state: %d, " + "adjusted gain: %#x\n", + __func__, wsa2_priv->thermal_cur_state, gain); + } + + return; +} + +static int lpass_cdc_wsa2_macro_read_array(struct platform_device *pdev, + const char *name, int num_values, + u32 *output) +{ + u32 len, ret, size; + + if (!of_find_property(pdev->dev.of_node, name, &size)) { + dev_info(&pdev->dev, "%s: missing %s\n", __func__, name); + return 0; + } + + len = size / sizeof(u32); + if (len != num_values) { + dev_info(&pdev->dev, "%s: invalid number of %s\n", __func__, name); + return -EINVAL; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, name, output, len); + if (ret) + dev_info(&pdev->dev, "%s: Failed to read %s\n", __func__, name); + + return 0; + +} + +static void lpass_cdc_wsa2_macro_init_ops(struct macro_ops *ops, + char __iomem *wsa2_io_base) +{ + memset(ops, 0, sizeof(struct macro_ops)); + ops->init = lpass_cdc_wsa2_macro_init; + ops->exit = lpass_cdc_wsa2_macro_deinit; + ops->io_base = wsa2_io_base; + ops->dai_ptr = lpass_cdc_wsa2_macro_dai; + ops->num_dais = ARRAY_SIZE(lpass_cdc_wsa2_macro_dai); + ops->event_handler = lpass_cdc_wsa2_macro_event_handler; + ops->set_port_map = lpass_cdc_wsa2_macro_set_port_map; +} + +static int lpass_cdc_wsa2_macro_probe(struct platform_device *pdev) +{ + struct macro_ops ops; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv; + u32 wsa2_base_addr, default_clk_id, thermal_max_state; + char __iomem *wsa2_io_base; + int ret = 0; + u32 is_used_wsa2_swr_gpio = 1; + u32 noise_gate_mode; + const char *is_used_wsa2_swr_gpio_dt = "qcom,is-used-swr-gpio"; + + if (!lpass_cdc_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + + wsa2_priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_wsa2_macro_priv), + GFP_KERNEL); + if (!wsa2_priv) + return -ENOMEM; + + wsa2_priv->pre_dev_up = true; + wsa2_priv->dev = &pdev->dev; + ret = of_property_read_u32(pdev->dev.of_node, "reg", + &wsa2_base_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "reg"); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, "wsa_data_fs_ctl_reg", + &wsa2_priv->wsa2_fs_ctl_reg); + if (ret) { + dev_dbg(&pdev->dev, "%s: error finding %s entry in dt\n", + __func__, "wsa_data_fs_ctl_reg"); + } + + if (!wsa2_priv->wsa2_fs_reg_base && wsa2_priv->wsa2_fs_ctl_reg) + wsa2_priv->wsa2_fs_reg_base = devm_ioremap(&pdev->dev, + wsa2_priv->wsa2_fs_ctl_reg, LPASS_CDC_WSA2_MACRO_MAX_OFFSET); + + if (of_find_property(pdev->dev.of_node, is_used_wsa2_swr_gpio_dt, + NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + is_used_wsa2_swr_gpio_dt, + &is_used_wsa2_swr_gpio); + if (ret) { + dev_err(&pdev->dev, "%s: error reading %s in dt\n", + __func__, is_used_wsa2_swr_gpio_dt); + is_used_wsa2_swr_gpio = 1; + } + } + wsa2_priv->wsa2_swr_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,wsa2-swr-gpios", 0); + if (!wsa2_priv->wsa2_swr_gpio_p && is_used_wsa2_swr_gpio) { + dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n", + __func__); + return -EINVAL; + } + if (msm_cdc_pinctrl_get_state(wsa2_priv->wsa2_swr_gpio_p) < 0 && + is_used_wsa2_swr_gpio) { + dev_err(&pdev->dev, "%s: failed to get swr pin state\n", + __func__); + return -EPROBE_DEFER; + } + msm_cdc_pinctrl_set_wakeup_capable( + wsa2_priv->wsa2_swr_gpio_p, false); + + wsa2_io_base = devm_ioremap(&pdev->dev, + wsa2_base_addr, LPASS_CDC_WSA2_MACRO_MAX_OFFSET); + if (!wsa2_io_base) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + return -EINVAL; + } + + lpass_cdc_wsa2_macro_read_array(pdev, "qcom,wsa-rloads", + LPASS_CDC_WSA2_MACRO_RX1 + 1, wsa2_priv->wsa2_rload); + lpass_cdc_wsa2_macro_read_array(pdev, "qcom,wsa-system-gains", + 2 * (LPASS_CDC_WSA2_MACRO_RX1 + 1), wsa2_priv->wsa2_sys_gain); + lpass_cdc_wsa2_macro_read_array(pdev, "qcom,wsa-bat-cfgs", + LPASS_CDC_WSA2_MACRO_RX1 + 1, wsa2_priv->wsa2_bat_cfg); + + + wsa2_priv->wsa2_io_base = wsa2_io_base; + wsa2_priv->reset_swr = true; + INIT_WORK(&wsa2_priv->lpass_cdc_wsa2_macro_add_child_devices_work, + lpass_cdc_wsa2_macro_add_child_devices); + INIT_WORK(&wsa2_priv->lpass_cdc_wsa2_macro_cooling_work, + lpass_cdc_wsa2_macro_cooling_adjust_gain); + wsa2_priv->swr_plat_data.handle = (void *) wsa2_priv; + wsa2_priv->swr_plat_data.read = NULL; + wsa2_priv->swr_plat_data.write = NULL; + wsa2_priv->swr_plat_data.bulk_write = NULL; + wsa2_priv->swr_plat_data.clk = wsa2_swrm_clock; + wsa2_priv->swr_plat_data.core_vote = lpass_cdc_wsa2_macro_core_vote; + wsa2_priv->swr_plat_data.handle_irq = NULL; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id", + &default_clk_id); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,mux0-clk-id"); + default_clk_id = WSA2_CORE_CLK; + } + + wsa2_priv->default_clk_id = default_clk_id; + + dev_set_drvdata(&pdev->dev, wsa2_priv); + mutex_init(&wsa2_priv->mclk_lock); + mutex_init(&wsa2_priv->swr_clk_lock); + lpass_cdc_wsa2_macro_init_ops(&ops, wsa2_io_base); + ops.clk_id_req = wsa2_priv->default_clk_id; + ops.default_clk_id = wsa2_priv->default_clk_id; + + ret = lpass_cdc_register_macro(&pdev->dev, WSA2_MACRO, &ops); + if (ret < 0) { + dev_err(&pdev->dev, "%s: register macro failed\n", __func__); + goto reg_macro_fail; + } + + if (of_find_property(wsa2_priv->dev->of_node, "#cooling-cells", NULL)) { + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,thermal-max-state", + &thermal_max_state); + if (ret) { + dev_info(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,thermal-max-state"); + wsa2_priv->thermal_max_state = + LPASS_CDC_WSA2_MACRO_THERMAL_MAX_STATE; + } else { + wsa2_priv->thermal_max_state = thermal_max_state; + } + wsa2_priv->tcdev = devm_thermal_of_cooling_device_register( + &pdev->dev, + wsa2_priv->dev->of_node, + "wsa2", wsa2_priv, + &wsa2_cooling_ops); + if (IS_ERR(wsa2_priv->tcdev)) { + dev_err(&pdev->dev, + "%s: failed to register wsa2 macro as cooling device\n", + __func__); + wsa2_priv->tcdev = NULL; + } + } + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,noise-gate-mode", &noise_gate_mode); + if (ret) { + dev_info(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,noise-gate-mode"); + wsa2_priv->noise_gate_mode = IDLE_DETECT; + } else { + if (noise_gate_mode >= IDLE_DETECT && noise_gate_mode <= NG3) + wsa2_priv->noise_gate_mode = noise_gate_mode; + else + wsa2_priv->noise_gate_mode = IDLE_DETECT; + } + + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + schedule_work(&wsa2_priv->lpass_cdc_wsa2_macro_add_child_devices_work); + return ret; +reg_macro_fail: + mutex_destroy(&wsa2_priv->mclk_lock); + mutex_destroy(&wsa2_priv->swr_clk_lock); + return ret; +} + +static int lpass_cdc_wsa2_macro_remove(struct platform_device *pdev) +{ + struct lpass_cdc_wsa2_macro_priv *wsa2_priv; + u16 count = 0; + + wsa2_priv = dev_get_drvdata(&pdev->dev); + + if (!wsa2_priv) + return -EINVAL; + + if (wsa2_priv->tcdev) + thermal_cooling_device_unregister(wsa2_priv->tcdev); + + for (count = 0; count < wsa2_priv->child_count && + count < LPASS_CDC_WSA2_MACRO_CHILD_DEVICES_MAX; count++) + platform_device_unregister(wsa2_priv->pdev_child_devices[count]); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + lpass_cdc_unregister_macro(&pdev->dev, WSA2_MACRO); + mutex_destroy(&wsa2_priv->mclk_lock); + mutex_destroy(&wsa2_priv->swr_clk_lock); + return 0; +} + +static const struct of_device_id lpass_cdc_wsa2_macro_dt_match[] = { + {.compatible = "qcom,lpass-cdc-wsa2-macro"}, + {} +}; + +static const struct dev_pm_ops lpass_cdc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) + SET_RUNTIME_PM_OPS( + lpass_cdc_runtime_suspend, + lpass_cdc_runtime_resume, + NULL + ) +}; + +static struct platform_driver lpass_cdc_wsa2_macro_driver = { + .driver = { + .name = "lpass_cdc_wsa2_macro", + .owner = THIS_MODULE, + .pm = &lpass_cdc_dev_pm_ops, + .of_match_table = lpass_cdc_wsa2_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_cdc_wsa2_macro_probe, + .remove = lpass_cdc_wsa2_macro_remove, +}; + +module_platform_driver(lpass_cdc_wsa2_macro_driver); + +MODULE_DESCRIPTION("WSA2 macro driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.h b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.h new file mode 100644 index 0000000000..f24df4300f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ +#ifndef LPASS_CDC_WSA2_MACRO_H +#define LPASS_CDC_WSA2_MACRO_H + +/* + * Selects compander and smart boost settings + * for a given speaker mode + */ +enum { + LPASS_CDC_WSA2_MACRO_SPKR_MODE_DEFAULT, + LPASS_CDC_WSA2_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */ +}; + +/* Rx path gain offsets */ +enum { + LPASS_CDC_WSA2_MACRO_GAIN_OFFSET_M1P5_DB, + LPASS_CDC_WSA2_MACRO_GAIN_OFFSET_0_DB, +}; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.c b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.c new file mode 100644 index 0000000000..6883749c59 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.c @@ -0,0 +1,1571 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpass-cdc.h" +#include "internal.h" +#include "lpass-cdc-clk-rsc.h" +#include + +#define DRV_NAME "lpass-cdc" + +#define LPASS_CDC_VERSION_ENTRY_SIZE 32 +#define LPASS_CDC_STRING_LEN 80 + +static const struct snd_soc_component_driver lpass_cdc; + +/* pm runtime auto suspend timer in msecs */ +#define LPASS_CDC_AUTO_SUSPEND_DELAY 100 /* delay in msec */ + +/* MCLK_MUX table for all macros */ +static u16 lpass_cdc_mclk_mux_tbl[MAX_MACRO][MCLK_MUX_MAX] = { + {TX_MACRO, VA_MACRO}, + {TX_MACRO, RX_MACRO}, + {TX_MACRO, WSA_MACRO}, + {TX_MACRO, VA_MACRO}, +}; + +static bool lpass_cdc_is_valid_codec_dev(struct device *dev); + +int lpass_cdc_set_port_map(struct snd_soc_component *component, + u32 size, void *data) +{ + struct lpass_cdc_priv *priv = NULL; + struct swr_mstr_port_map *map = NULL; + u16 idx; + + if (!component || (size == 0) || !data) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!lpass_cdc_is_valid_codec_dev(priv->dev)) { + dev_err_ratelimited(priv->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + map = (struct swr_mstr_port_map *)data; + + for (idx = 0; idx < size; idx++) { + if (priv->macro_params[map->id].set_port_map) + priv->macro_params[map->id].set_port_map(component, + map->uc, + SWR_MSTR_PORT_LEN, + map->swr_port_params); + map += 1; + } + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_set_port_map); + +static void lpass_cdc_ahb_write_device(char __iomem *io_base, + u16 reg, u8 value) +{ + u32 temp = (u32)(value) & 0x000000FF; + + iowrite32(temp, io_base + reg); +} + +static void lpass_cdc_ahb_read_device(char __iomem *io_base, + u16 reg, u8 *value) +{ + u32 temp; + + temp = ioread32(io_base + reg); + *value = (u8)temp; +} + +static int __lpass_cdc_reg_read(struct lpass_cdc_priv *priv, + u16 macro_id, u16 reg, u8 *val) +{ + int ret = 0; + + mutex_lock(&priv->clk_lock); + if (!priv->dev_up) { + dev_dbg_ratelimited(priv->dev, + "%s: SSR in progress, exit\n", __func__); + ret = -EINVAL; + goto ssr_err; + } + + if (priv->macro_params[VA_MACRO].dev) { + pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev); + mutex_lock(&priv->vote_lock); + if (((priv->lpass_core_hw_vote && !priv->core_hw_vote_count) || + (priv->lpass_audio_hw_vote && !priv->core_audio_vote_count))) { + goto vote_err; + } + } + lpass_cdc_ahb_read_device( + priv->macro_params[macro_id].io_base, reg, val); + +vote_err: + if (priv->macro_params[VA_MACRO].dev) { + mutex_unlock(&priv->vote_lock); + pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev); + pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev); + } +ssr_err: + mutex_unlock(&priv->clk_lock); + return ret; +} + +static int __lpass_cdc_reg_write(struct lpass_cdc_priv *priv, + u16 macro_id, u16 reg, u8 val) +{ + int ret = 0; + + mutex_lock(&priv->clk_lock); + if (!priv->dev_up) { + dev_dbg_ratelimited(priv->dev, + "%s: SSR in progress, exit\n", __func__); + ret = -EINVAL; + goto ssr_err; + } + if (priv->macro_params[VA_MACRO].dev) { + pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev); + mutex_lock(&priv->vote_lock); + if (((priv->lpass_core_hw_vote && !priv->core_hw_vote_count) || + (priv->lpass_audio_hw_vote && !priv->core_audio_vote_count))) { + goto vote_err; + } + } + lpass_cdc_ahb_write_device( + priv->macro_params[macro_id].io_base, reg, val); + +vote_err: + if (priv->macro_params[VA_MACRO].dev) { + mutex_unlock(&priv->vote_lock); + pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev); + pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev); + } +ssr_err: + mutex_unlock(&priv->clk_lock); + return ret; +} + +static int lpass_cdc_update_wcd_event(void *handle, u16 event, u32 data) +{ + struct lpass_cdc_priv *priv = (struct lpass_cdc_priv *)handle; + + if (!priv) { + pr_err_ratelimited("%s:Invalid lpass_cdc priv handle\n", __func__); + return -EINVAL; + } + + switch (event) { + case WCD_LPASS_CDC_EVT_RX_MUTE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_RX_MUTE, data); + break; + case WCD_LPASS_CDC_EVT_IMPED_TRUE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_IMPED_TRUE, data); + break; + case WCD_LPASS_CDC_EVT_IMPED_FALSE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_IMPED_FALSE, data); + break; + case WCD_LPASS_CDC_EVT_RX_COMPANDER_SOFT_RST: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_RX_COMPANDER_SOFT_RST, data); + break; + case WCD_LPASS_CDC_EVT_BCS_CLK_OFF: + if (priv->macro_params[TX_MACRO].event_handler) + priv->macro_params[TX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_BCS_CLK_OFF, data); + break; + case WCD_LPASS_CDC_EVT_RX_PA_GAIN_UPDATE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_RX_PA_GAIN_UPDATE, + data); + break; + case WCD_LPASS_CDC_EVT_HPHL_HD2_ENABLE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_HPHL_HD2_ENABLE, data); + break; + case WCD_LPASS_CDC_EVT_HPHR_HD2_ENABLE: + if (priv->macro_params[RX_MACRO].event_handler) + priv->macro_params[RX_MACRO].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_HPHR_HD2_ENABLE, data); + break; + default: + dev_err_ratelimited(priv->dev, "%s: Invalid event %d trigger from wcd\n", + __func__, event); + return -EINVAL; + } + return 0; +} + +static int lpass_cdc_register_notifier(void *handle, + struct notifier_block *nblock, + bool enable) +{ + struct lpass_cdc_priv *priv = (struct lpass_cdc_priv *)handle; + + if (!priv || !nblock) { + pr_err_ratelimited("%s: lpass_cdc priv or nblock is null\n", __func__); + return -EINVAL; + } + if (enable) + return blocking_notifier_chain_register(&priv->notifier, + nblock); + + return blocking_notifier_chain_unregister(&priv->notifier, + nblock); +} + +static void lpass_cdc_notifier_call(struct lpass_cdc_priv *priv, + u32 data) +{ + dev_dbg(priv->dev, "%s: notifier call, data:%d\n", __func__, data); + blocking_notifier_call_chain(&priv->notifier, + data, (void *)priv->wcd_dev); +} + +static bool lpass_cdc_is_valid_child_dev(struct device *dev) +{ + if (of_device_is_compatible(dev->parent->of_node, "qcom,lpass-cdc")) + return true; + + return false; +} + +static bool lpass_cdc_is_valid_codec_dev(struct device *dev) +{ + if (of_device_is_compatible(dev->of_node, "qcom,lpass-cdc")) + return true; + + return false; +} + +/** + * lpass_cdc_clear_amic_tx_hold - clears AMIC register on analog codec + * + * @dev: lpass_cdc device ptr. + * + */ +void lpass_cdc_clear_amic_tx_hold(struct device *dev, u16 adc_n) +{ + struct lpass_cdc_priv *priv; + u16 event; + u16 amic = 0; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return; + } + + if (!lpass_cdc_is_valid_codec_dev(dev)) { + pr_err("%s: invalid codec\n", __func__); + return; + } + priv = dev_get_drvdata(dev); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return; + } + event = LPASS_CDC_WCD_EVT_TX_CH_HOLD_CLEAR; + if (adc_n == LPASS_CDC_ADC0) + amic = 0x1; + else if (adc_n == LPASS_CDC_ADC1) + amic = 0x2; + else if (adc_n == LPASS_CDC_ADC2) + amic = 0x2; + else if (adc_n == LPASS_CDC_ADC3) + amic = 0x3; + else + return; + + lpass_cdc_notifier_call(priv, (amic << 0x10 | event)); +} +EXPORT_SYMBOL(lpass_cdc_clear_amic_tx_hold); + +/** + * lpass_cdc_get_device_ptr - Get child or macro device ptr + * + * @dev: lpass_cdc device ptr. + * @macro_id: ID of macro calling this API. + * + * Returns dev ptr on success or NULL on error. + */ +struct device *lpass_cdc_get_device_ptr(struct device *dev, u16 macro_id) +{ + struct lpass_cdc_priv *priv; + + if (!dev) { + pr_err_ratelimited("%s: dev is null\n", __func__); + return NULL; + } + + if (!lpass_cdc_is_valid_codec_dev(dev)) { + pr_err_ratelimited("%s: invalid codec\n", __func__); + return NULL; + } + priv = dev_get_drvdata(dev); + if (!priv || (macro_id >= MAX_MACRO)) { + dev_err_ratelimited(dev, "%s: priv is null or invalid macro\n", __func__); + return NULL; + } + + return priv->macro_params[macro_id].dev; +} +EXPORT_SYMBOL(lpass_cdc_get_device_ptr); + +/** + * lpass_cdc_get_rsc_clk_device_ptr - Get rsc clk device ptr + * + * @dev: lpass_cdc device ptr. + * + * Returns dev ptr on success or NULL on error. + */ +struct device *lpass_cdc_get_rsc_clk_device_ptr(struct device *dev) +{ + struct lpass_cdc_priv *priv; + + if (!dev) { + pr_err_ratelimited("%s: dev is null\n", __func__); + return NULL; + } + + if (!lpass_cdc_is_valid_codec_dev(dev)) { + pr_err_ratelimited("%s: invalid codec\n", __func__); + return NULL; + } + priv = dev_get_drvdata(dev); + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is null\n", __func__); + return NULL; + } + + return priv->clk_dev; +} +EXPORT_SYMBOL(lpass_cdc_get_rsc_clk_device_ptr); + +static int lpass_cdc_copy_dais_from_macro(struct lpass_cdc_priv *priv) +{ + struct snd_soc_dai_driver *dai_ptr; + u16 macro_idx; + + /* memcpy into lpass_cdc_dais all macro dais */ + if (!priv->lpass_cdc_dais) + priv->lpass_cdc_dais = devm_kzalloc(priv->dev, + priv->num_dais * + sizeof( + struct snd_soc_dai_driver), + GFP_KERNEL); + if (!priv->lpass_cdc_dais) + return -ENOMEM; + + dai_ptr = priv->lpass_cdc_dais; + + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (priv->macro_params[macro_idx].dai_ptr) { + memcpy(dai_ptr, + priv->macro_params[macro_idx].dai_ptr, + priv->macro_params[macro_idx].num_dais * + sizeof(struct snd_soc_dai_driver)); + dai_ptr += priv->macro_params[macro_idx].num_dais; + } + } + return 0; +} + +/** + * lpass_cdc_register_res_clk - Registers rsc clk driver to lpass_cdc + * + * @dev: rsc clk device ptr. + * @rsc_clk_cb: event handler callback for notifications like SSR + * + * Returns 0 on success or -EINVAL on error. + */ +int lpass_cdc_register_res_clk(struct device *dev, rsc_clk_cb_t rsc_clk_cb) +{ + struct lpass_cdc_priv *priv; + + if (!dev || !rsc_clk_cb) { + pr_err_ratelimited("%s: dev or rsc_clk_cb is null\n", __func__); + return -EINVAL; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err_ratelimited(dev, "%s: child device :%pK not added yet\n", + __func__, dev); + return -EINVAL; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is null\n", __func__); + return -EINVAL; + } + + priv->clk_dev = dev; + priv->rsc_clk_cb = rsc_clk_cb; + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_register_res_clk); + +/** + * lpass_cdc_unregister_res_clk - Unregisters rsc clk driver from lpass_cdc + * + * @dev: resource clk device ptr. + */ +void lpass_cdc_unregister_res_clk(struct device *dev) +{ + struct lpass_cdc_priv *priv; + + if (!dev) { + pr_err_ratelimited("%s: dev is NULL\n", __func__); + return; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err_ratelimited(dev, "%s: child device :%pK not added\n", + __func__, dev); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is null\n", __func__); + return; + } + + priv->clk_dev = NULL; + priv->rsc_clk_cb = NULL; +} +EXPORT_SYMBOL(lpass_cdc_unregister_res_clk); + +static u8 lpass_cdc_dmic_clk_div_get(struct snd_soc_component *component, + u32 mode) +{ + struct lpass_cdc_priv* priv = snd_soc_component_get_drvdata(component); + int macro = (mode ? VA_MACRO : TX_MACRO); + int ret = 0; + + if (priv->macro_params[macro].clk_div_get) { + ret = priv->macro_params[macro].clk_div_get(component); + if (ret >= 0) + return ret; + } + + return 1; +} + +int lpass_cdc_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + struct lpass_cdc_priv* priv = snd_soc_component_get_drvdata(component); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg = 0; + s32 *dmic_clk_cnt = NULL; + u8 *dmic_clk_div = NULL; + u8 freq_change_mask = 0; + u8 clk_div = 0; + + dev_dbg(component->dev, "%s: enable: %d, tx_mode:%d, dmic: %d\n", + __func__, enable, tx_mode, dmic); + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(priv->dmic_0_1_clk_cnt); + dmic_clk_div = &(priv->dmic_0_1_clk_div); + dmic_clk_reg = LPASS_CDC_VA_TOP_CSR_DMIC0_CTL; + freq_change_mask = 0x01; + break; + case 2: + case 3: + dmic_clk_cnt = &(priv->dmic_2_3_clk_cnt); + dmic_clk_div = &(priv->dmic_2_3_clk_div); + dmic_clk_reg = LPASS_CDC_VA_TOP_CSR_DMIC1_CTL; + freq_change_mask = 0x02; + break; + case 4: + case 5: + dmic_clk_cnt = &(priv->dmic_4_5_clk_cnt); + dmic_clk_div = &(priv->dmic_4_5_clk_div); + dmic_clk_reg = LPASS_CDC_VA_TOP_CSR_DMIC2_CTL; + freq_change_mask = 0x04; + break; + case 6: + case 7: + dmic_clk_cnt = &(priv->dmic_6_7_clk_cnt); + dmic_clk_div = &(priv->dmic_6_7_clk_div); + dmic_clk_reg = LPASS_CDC_VA_TOP_CSR_DMIC3_CTL; + freq_change_mask = 0x08; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + dev_dbg(component->dev, "%s: DMIC%d dmic_clk_cnt %d\n", + __func__, dmic, *dmic_clk_cnt); + if (enable) { + clk_div = lpass_cdc_dmic_clk_div_get(component, tx_mode); + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } else { + if (*dmic_clk_div > clk_div) { + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } else { + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, 0); + clk_div = 0; + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + } else { + clk_div = lpass_cdc_dmic_clk_div_get(component, tx_mode); + if (*dmic_clk_div > clk_div) { + clk_div = lpass_cdc_dmic_clk_div_get(component, !tx_mode); + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + LPASS_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_dmic_clk_enable); + +bool lpass_cdc_is_va_macro_registered(struct device *dev) +{ + struct lpass_cdc_priv *priv; + + if (!dev) { + pr_err_ratelimited("%s: dev is null\n", __func__); + return false; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err_ratelimited(dev, "%s: child device calling is not added yet\n", + __func__); + return false; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is null\n", __func__); + return false; + } + return priv->macros_supported[VA_MACRO]; +} +EXPORT_SYMBOL(lpass_cdc_is_va_macro_registered); + +/** + * lpass_cdc_register_macro - Registers macro to lpass_cdc + * + * @dev: macro device ptr. + * @macro_id: ID of macro calling this API. + * @ops: macro params to register. + * + * Returns 0 on success or -EINVAL on error. + */ +int lpass_cdc_register_macro(struct device *dev, u16 macro_id, + struct macro_ops *ops) +{ + struct lpass_cdc_priv *priv; + int ret = -EINVAL; + + if (!dev || !ops) { + pr_err("%s: dev or ops is null\n", __func__); + return -EINVAL; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device for macro:%d not added yet\n", + __func__, macro_id); + return -EINVAL; + } + priv = dev_get_drvdata(dev->parent); + if (!priv || (macro_id >= MAX_MACRO)) { + dev_err(dev, "%s: priv is null or invalid macro\n", __func__); + return -EINVAL; + } + + priv->macro_params[macro_id].clk_id_req = ops->clk_id_req; + priv->macro_params[macro_id].default_clk_id = ops->default_clk_id; + priv->macro_params[macro_id].init = ops->init; + priv->macro_params[macro_id].exit = ops->exit; + priv->macro_params[macro_id].io_base = ops->io_base; + priv->macro_params[macro_id].num_dais = ops->num_dais; + priv->macro_params[macro_id].dai_ptr = ops->dai_ptr; + priv->macro_params[macro_id].event_handler = ops->event_handler; + priv->macro_params[macro_id].set_port_map = ops->set_port_map; + priv->macro_params[macro_id].dev = dev; + priv->current_mclk_mux_macro[macro_id] = + lpass_cdc_mclk_mux_tbl[macro_id][MCLK_MUX0]; + if (macro_id == TX_MACRO) { + priv->macro_params[macro_id].reg_wake_irq = ops->reg_wake_irq; + priv->macro_params[macro_id].reg_evt_listener = + ops->reg_evt_listener; + priv->macro_params[macro_id].clk_enable = ops->clk_enable; + } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = ops->clk_div_get; + + if (macro_id == VA_MACRO) + priv->macro_params[macro_id].reg_wake_irq = + ops->reg_wake_irq; + mutex_lock(&priv->macro_lock); + priv->num_dais += ops->num_dais; + priv->num_macros_registered++; + priv->macros_supported[macro_id] = true; + + dev_info(dev, "%s: register macro successful:%d\n", __func__, macro_id); + + if (priv->num_macros_registered == priv->num_macros) { + ret = lpass_cdc_copy_dais_from_macro(priv); + if (ret < 0) { + dev_err(dev, "%s: copy_dais failed\n", __func__); + mutex_unlock(&priv->macro_lock); + return ret; + } + if (priv->macros_supported[TX_MACRO] == false) { + lpass_cdc_mclk_mux_tbl[WSA_MACRO][MCLK_MUX0] = WSA_MACRO; + priv->current_mclk_mux_macro[WSA_MACRO] = WSA_MACRO; + lpass_cdc_mclk_mux_tbl[VA_MACRO][MCLK_MUX0] = VA_MACRO; + priv->current_mclk_mux_macro[VA_MACRO] = VA_MACRO; + } + ret = snd_soc_register_component(dev->parent, &lpass_cdc, + priv->lpass_cdc_dais, priv->num_dais); + if (ret < 0) { + dev_err(dev, "%s: register codec failed\n", __func__); + mutex_unlock(&priv->macro_lock); + return ret; + } + } + mutex_unlock(&priv->macro_lock); + return 0; +} +EXPORT_SYMBOL(lpass_cdc_register_macro); + +/** + * lpass_cdc_unregister_macro - De-Register macro from lpass_cdc + * + * @dev: macro device ptr. + * @macro_id: ID of macro calling this API. + * + */ +void lpass_cdc_unregister_macro(struct device *dev, u16 macro_id) +{ + struct lpass_cdc_priv *priv; + + if (!dev) { + pr_err_ratelimited("%s: dev is null\n", __func__); + return; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err_ratelimited(dev, "%s: macro:%d not in valid registered macro-list\n", + __func__, macro_id); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv || (macro_id >= MAX_MACRO)) { + dev_err_ratelimited(dev, "%s: priv is null or invalid macro\n", __func__); + return; + } + + priv->macro_params[macro_id].init = NULL; + priv->macro_params[macro_id].num_dais = 0; + priv->macro_params[macro_id].dai_ptr = NULL; + priv->macro_params[macro_id].event_handler = NULL; + priv->macro_params[macro_id].dev = NULL; + if (macro_id == TX_MACRO) { + priv->macro_params[macro_id].reg_wake_irq = NULL; + priv->macro_params[macro_id].reg_evt_listener = NULL; + priv->macro_params[macro_id].clk_enable = NULL; + } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = NULL; + + priv->num_dais -= priv->macro_params[macro_id].num_dais; + priv->num_macros_registered--; + + /* UNREGISTER CODEC HERE */ + if (priv->num_macros - 1 == priv->num_macros_registered) + snd_soc_unregister_component(dev->parent); +} +EXPORT_SYMBOL(lpass_cdc_unregister_macro); + +void lpass_cdc_notify_wcd_rx_clk(struct device *dev, bool is_native_on) +{ + struct lpass_cdc_priv *priv; + u32 val; + + if (!dev) { + pr_err_ratelimited("%s: dev is null\n", __func__); + return; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err_ratelimited(dev, "%s: not a valid child dev\n", + __func__); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is null\n", __func__); + return; + } + if (is_native_on) + val = 0x2; /* 11.2896M */ + else + val = 0x0; /* 9.6M */ + + lpass_cdc_notifier_call(priv, + ((val << 16) | LPASS_CDC_WCD_EVT_CLK_NOTIFY)); + +} +EXPORT_SYMBOL(lpass_cdc_notify_wcd_rx_clk); + +void lpass_cdc_wsa_pa_on(struct device *dev, bool adie_lb) +{ + struct lpass_cdc_priv *priv; + + if (!dev) { + pr_err_ratelimited("%s: dev is null\n", __func__); + return; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err_ratelimited(dev, "%s: not a valid child dev\n", + __func__); + return; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err_ratelimited(dev, "%s: priv is null\n", __func__); + return; + } + if (adie_lb) + lpass_cdc_notifier_call(priv, + LPASS_CDC_WCD_EVT_PA_ON_POST_FSCLK_ADIE_LB); + else + lpass_cdc_notifier_call(priv, + LPASS_CDC_WCD_EVT_PA_ON_POST_FSCLK); +} +EXPORT_SYMBOL(lpass_cdc_wsa_pa_on); + +int lpass_cdc_get_version(struct device *dev) +{ + struct lpass_cdc_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return -EINVAL; + } + if (!lpass_cdc_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device for macro not added yet\n", + __func__); + return -EINVAL; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return -EINVAL; + } + return priv->version; +} +EXPORT_SYMBOL(lpass_cdc_get_version); + +static ssize_t lpass_cdc_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct lpass_cdc_priv *priv; + char buffer[LPASS_CDC_VERSION_ENTRY_SIZE]; + int len = 0; + + priv = (struct lpass_cdc_priv *) entry->private_data; + if (!priv) { + pr_err_ratelimited("%s: lpass_cdc priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->version) { + case LPASS_CDC_VERSION_1_0: + len = snprintf(buffer, sizeof(buffer), "LPASS-CDC_1_0\n"); + break; + case LPASS_CDC_VERSION_1_1: + len = snprintf(buffer, sizeof(buffer), "LPASS-CDC_1_1\n"); + break; + case LPASS_CDC_VERSION_1_2: + len = snprintf(buffer, sizeof(buffer), "LPASS-CDC_1_2\n"); + break; + case LPASS_CDC_VERSION_2_1: + len = snprintf(buffer, sizeof(buffer), "LPASS-CDC_2_1\n"); + break; + case LPASS_CDC_VERSION_2_5: + len = snprintf(buffer, sizeof(buffer), "LPASS-CDC_2_5\n"); + break; + case LPASS_CDC_VERSION_2_6: + len = snprintf(buffer, sizeof(buffer), "LPASS-CDC_2_6\n"); + break; + default: + len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + } + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static int lpass_cdc_ssr_enable(struct device *dev, void *data) +{ + struct lpass_cdc_priv *priv = data; + int macro_idx; + + if (priv->initial_boot) { + priv->initial_boot = false; + return 0; + } + + if (priv->rsc_clk_cb) + priv->rsc_clk_cb(priv->clk_dev, LPASS_CDC_MACRO_EVT_SSR_UP); + + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (priv->macro_params[macro_idx].event_handler) + priv->macro_params[macro_idx].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_CLK_RESET, 0x0); + } + + mutex_lock(&priv->clk_lock); + priv->pre_dev_up = true; + mutex_unlock(&priv->clk_lock); + + if (priv->rsc_clk_cb) + priv->rsc_clk_cb(priv->clk_dev, LPASS_CDC_MACRO_EVT_SSR_GFMUX_UP); + + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_PRE_SSR_UP, 0x0); + } + + regcache_cache_only(priv->regmap, false); + mutex_lock(&priv->clk_lock); + priv->dev_up = true; + mutex_unlock(&priv->clk_lock); + regcache_mark_dirty(priv->regmap); + lpass_cdc_clk_rsc_enable_all_clocks(priv->clk_dev, true); + regcache_sync(priv->regmap); + /* Add a 100usec sleep to ensure last register write is done */ + usleep_range(100,110); + lpass_cdc_clk_rsc_enable_all_clocks(priv->clk_dev, false); + /* call ssr event for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_SSR_UP, 0x0); + } + lpass_cdc_notifier_call(priv, LPASS_CDC_WCD_EVT_SSR_UP); + return 0; +} + +static void lpass_cdc_ssr_disable(struct device *dev, void *data) +{ + struct lpass_cdc_priv *priv = data; + int macro_idx; + + if (!priv->dev_up) { + dev_err_ratelimited(priv->dev, + "%s: already disabled\n", __func__); + return; + } + + regcache_cache_only(priv->regmap, true); + + mutex_lock(&priv->clk_lock); + priv->dev_up = false; + priv->pre_dev_up = false; + mutex_unlock(&priv->clk_lock); + if (priv->rsc_clk_cb) + priv->rsc_clk_cb(priv->clk_dev, LPASS_CDC_MACRO_EVT_SSR_DOWN); + /* call ssr event for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler( + priv->component, + LPASS_CDC_MACRO_EVT_SSR_DOWN, 0x0); + } + lpass_cdc_notifier_call(priv, LPASS_CDC_WCD_EVT_SSR_DOWN); +} + +static struct snd_info_entry_ops lpass_cdc_info_ops = { + .read = lpass_cdc_version_read, +}; + +static const struct snd_event_ops lpass_cdc_ssr_ops = { + .enable = lpass_cdc_ssr_enable, + .disable = lpass_cdc_ssr_disable, +}; + +/* + * lpass_cdc_info_create_codec_entry - creates lpass_cdc module + * @codec_root: The parent directory + * @component: Codec component instance + * + * Creates lpass_cdc module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int lpass_cdc_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct lpass_cdc_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:lpass_cdc module already created\n", __func__); + return 0; + } + card = component->card; + priv->entry = snd_info_create_module_entry(codec_root->module, + "lpass-cdc", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create lpass_cdc entry\n", + __func__); + return -ENOMEM; + } + priv->entry->mode = S_IFDIR | 0555; + if (snd_info_register(priv->entry) < 0) { + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + version_entry = snd_info_create_card_entry(card->snd_card, + "version", + priv->entry); + if (!version_entry) { + dev_err_ratelimited(component->dev, "%s: failed to create lpass_cdc version entry\n", + __func__); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + version_entry->private_data = priv; + version_entry->size = LPASS_CDC_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &lpass_cdc_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->version_entry = version_entry; + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_info_create_codec_entry); + +/** + * lpass_cdc_register_wake_irq - Register wake irq of Tx macro + * + * @component: codec component ptr. + * @ipc_wakeup: bool to identify ipc_wakeup to be used or HW interrupt line. + * + * Return: 0 on success or negative error code on failure. + */ +int lpass_cdc_register_wake_irq(struct snd_soc_component *component, + u32 ipc_wakeup) +{ + struct lpass_cdc_priv *priv = NULL; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!lpass_cdc_is_valid_codec_dev(priv->dev)) { + dev_err_ratelimited(component->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + + if (priv->macro_params[VA_MACRO].reg_wake_irq) + priv->macro_params[VA_MACRO].reg_wake_irq( + component, ipc_wakeup); + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_register_wake_irq); + +/** + * lpass_cdc_tx_mclk_enable - Enable/Disable TX Macro mclk + * + * @component: pointer to codec component instance. + * @enable: set true to enable, otherwise false. + * + * Returns 0 on success or -EINVAL on error. + */ +int lpass_cdc_tx_mclk_enable(struct snd_soc_component *component, + bool enable) +{ + struct lpass_cdc_priv *priv = NULL; + int ret = 0; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!lpass_cdc_is_valid_codec_dev(priv->dev)) { + dev_err_ratelimited(component->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + + if (priv->macro_params[TX_MACRO].clk_enable) + ret = priv->macro_params[TX_MACRO].clk_enable(component, + enable); + + return ret; +} +EXPORT_SYMBOL(lpass_cdc_tx_mclk_enable); + +/** + * lpass_cdc_register_event_listener - Register/Deregister to event listener + * + * @component: pointer to codec component instance. + * @enable: when set to 1 registers to event listener otherwise, derigisters + * from the event listener + * + * Returns 0 on success or -EINVAL on error. + */ +int lpass_cdc_register_event_listener(struct snd_soc_component *component, + bool enable) +{ + struct lpass_cdc_priv *priv = NULL; + int ret = 0; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!lpass_cdc_is_valid_codec_dev(priv->dev)) { + dev_err_ratelimited(component->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + + if (priv->macro_params[TX_MACRO].reg_evt_listener) + ret = priv->macro_params[TX_MACRO].reg_evt_listener(component, + enable); + + return ret; +} +EXPORT_SYMBOL(lpass_cdc_register_event_listener); + +static int lpass_cdc_soc_codec_probe(struct snd_soc_component *component) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(component->dev); + int macro_idx, ret = 0; + u8 core_id_0 = 0, core_id_1 = 0, core_id_2 = 0; + + snd_soc_component_init_regmap(component, priv->regmap); + + if (!priv->version) { + /* + * In order for the ADIE RTC to differentiate between targets + * version info is used. + * Assign 1.0 for target with only one macro + * Assign 1.1 for target with two macros + * Assign 1.2 for target with more than two macros + */ + if (priv->num_macros_registered == 1) + priv->version = LPASS_CDC_VERSION_1_0; + else if (priv->num_macros_registered == 2) + priv->version = LPASS_CDC_VERSION_1_1; + else if (priv->num_macros_registered > 2) + priv->version = LPASS_CDC_VERSION_1_2; + } + + /* Assign lpass_cdc version */ + core_id_0 = snd_soc_component_read(component, + LPASS_CDC_VA_TOP_CSR_CORE_ID_0); + core_id_1 = snd_soc_component_read(component, + LPASS_CDC_VA_TOP_CSR_CORE_ID_1); + core_id_2 = snd_soc_component_read(component, + LPASS_CDC_VA_TOP_CSR_CORE_ID_2); + if ((core_id_0 == 0x01) && (core_id_1 == 0x0F)) + priv->version = LPASS_CDC_VERSION_2_0; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0E)) + priv->version = LPASS_CDC_VERSION_2_1; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x50 || core_id_2 == 0x51)) + priv->version = LPASS_CDC_VERSION_2_5; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x60 || core_id_2 == 0x61)) + priv->version = LPASS_CDC_VERSION_2_6; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x70 || core_id_2 == 0x71)) + priv->version = LPASS_CDC_VERSION_2_7; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x80 || core_id_2 == 0x81)) + priv->version = LPASS_CDC_VERSION_2_8; + + /* call init for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (priv->macro_params[macro_idx].init) { + ret = priv->macro_params[macro_idx].init(component); + if (ret < 0) { + dev_err(component->dev, + "%s: init for macro %d failed\n", + __func__, macro_idx); + goto err; + } + } + } + priv->component = component; + + ret = snd_event_client_register(priv->dev, &lpass_cdc_ssr_ops, priv); + if (!ret) { + snd_event_notify(priv->dev, SND_EVENT_UP); + } else { + dev_err(component->dev, + "%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + goto err; + } + + dev_dbg(component->dev, "%s: lpass_cdc soc codec probe success\n", + __func__); +err: + return ret; +} + +static void lpass_cdc_soc_codec_remove(struct snd_soc_component *component) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(component->dev); + int macro_idx; + + snd_event_client_deregister(priv->dev); + /* call exit for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) + if (priv->macro_params[macro_idx].exit) + priv->macro_params[macro_idx].exit(component); + + return; +} + +static const struct snd_soc_component_driver lpass_cdc = { + .name = DRV_NAME, + .probe = lpass_cdc_soc_codec_probe, + .remove = lpass_cdc_soc_codec_remove, +}; + +static void lpass_cdc_add_child_devices(struct work_struct *work) +{ + struct lpass_cdc_priv *priv; + bool split_codec = false; + struct platform_device *pdev; + struct device_node *node; + int ret = 0, count = 0; + struct wcd_ctrl_platform_data *platdata = NULL; + char plat_dev_name[LPASS_CDC_STRING_LEN] = ""; + + priv = container_of(work, struct lpass_cdc_priv, + lpass_cdc_add_child_devices_work); + if (!priv) { + pr_err("%s: Memory for lpass_cdc priv does not exist\n", + __func__); + return; + } + if (!priv->dev || !priv->dev->of_node) { + dev_err(priv->dev, "%s: DT node for lpass_cdc does not exist\n", + __func__); + return; + } + + platdata = &priv->plat_data; + priv->child_count = 0; + + for_each_available_child_of_node(priv->dev->of_node, node) { + split_codec = false; + if (of_find_property(node, "qcom,split-codec", NULL)) { + split_codec = true; + dev_dbg(priv->dev, "%s: split codec slave exists\n", + __func__); + } + + strlcpy(plat_dev_name, node->name, + (LPASS_CDC_STRING_LEN - 1)); + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(priv->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = priv->dev; + pdev->dev.of_node = node; + + priv->dev->platform_data = platdata; + if (split_codec) + priv->wcd_dev = &pdev->dev; + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + platform_device_put(pdev); + goto fail_pdev_add; + } + + if (priv->child_count < LPASS_CDC_CHILD_DEVICES_MAX) + priv->pdev_child_devices[priv->child_count++] = pdev; + else + goto err; + } + return; +fail_pdev_add: + for (count = 0; count < priv->child_count; count++) + platform_device_put(priv->pdev_child_devices[count]); +err: + return; +} + +static int lpass_cdc_probe(struct platform_device *pdev) +{ + struct lpass_cdc_priv *priv; + u32 num_macros = 0; + int ret; + struct clk *lpass_core_hw_vote = NULL; + struct clk *lpass_audio_hw_vote = NULL; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-macros", + &num_macros); + if (ret) { + dev_err(&pdev->dev, + "%s:num-macros property not found\n", + __func__); + return ret; + } + priv->num_macros = num_macros; + if (priv->num_macros > MAX_MACRO) { + dev_err(&pdev->dev, + "%s:num_macros(%d) > MAX_MACRO(%d) than supported\n", + __func__, priv->num_macros, MAX_MACRO); + return -EINVAL; + } + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,lpass-cdc-version", &priv->version); + if (ret) { + dev_dbg(&pdev->dev, "%s:lpass_cdc version not specified\n", + __func__); + ret = 0; + } + + BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier); + priv->dev = &pdev->dev; + priv->dev_up = true; + priv->pre_dev_up = true; + priv->initial_boot = true; + priv->regmap = lpass_cdc_regmap_init(priv->dev, + &lpass_cdc_regmap_config); + if (IS_ERR_OR_NULL((void *)(priv->regmap))) { + dev_err(&pdev->dev, "%s:regmap init failed\n", __func__); + return -EINVAL; + } + + devm_regmap_qti_debugfs_register(priv->dev, priv->regmap); + + priv->read_dev = __lpass_cdc_reg_read; + priv->write_dev = __lpass_cdc_reg_write; + + priv->plat_data.handle = (void *) priv; + priv->plat_data.update_wcd_event = lpass_cdc_update_wcd_event; + priv->plat_data.register_notifier = lpass_cdc_register_notifier; + + priv->core_hw_vote_count = 0; + priv->core_audio_vote_count = 0; + + dev_set_drvdata(&pdev->dev, priv); + mutex_init(&priv->macro_lock); + mutex_init(&priv->io_lock); + mutex_init(&priv->clk_lock); + mutex_init(&priv->vote_lock); + INIT_WORK(&priv->lpass_cdc_add_child_devices_work, + lpass_cdc_add_child_devices); + + /* Register LPASS core hw vote */ + lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote"); + if (IS_ERR(lpass_core_hw_vote)) { + ret = PTR_ERR(lpass_core_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_core_hw_vote", ret); + lpass_core_hw_vote = NULL; + ret = 0; + } + priv->lpass_core_hw_vote = lpass_core_hw_vote; + + /* Register LPASS audio hw vote */ + lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); + if (IS_ERR(lpass_audio_hw_vote)) { + ret = PTR_ERR(lpass_audio_hw_vote); + dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", + __func__, "lpass_audio_hw_vote", ret); + lpass_audio_hw_vote = NULL; + ret = 0; + } + priv->lpass_audio_hw_vote = lpass_audio_hw_vote; + schedule_work(&priv->lpass_cdc_add_child_devices_work); + + return 0; +} + +static int lpass_cdc_remove(struct platform_device *pdev) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(&pdev->dev); + + if (!priv) + return -EINVAL; + + of_platform_depopulate(&pdev->dev); + mutex_destroy(&priv->macro_lock); + mutex_destroy(&priv->io_lock); + mutex_destroy(&priv->clk_lock); + mutex_destroy(&priv->vote_lock); + return 0; +} + +#ifdef CONFIG_PM +int lpass_cdc_runtime_resume(struct device *dev) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(dev->parent); + int ret = 0; + + dev_dbg(dev,"%s, enter\n", __func__); + mutex_lock(&priv->vote_lock); + if (priv->lpass_core_hw_vote == NULL) { + dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__); + goto audio_vote; + } + + if (priv->core_hw_vote_count == 0) { + ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_core_hw_vote, dev); + if (ret < 0) { + dev_err_ratelimited(dev, "%s:lpass core hw enable failed\n", + __func__); + goto audio_vote; + } + } + priv->core_hw_vote_count++; + +audio_vote: + if (priv->lpass_audio_hw_vote == NULL) { + dev_dbg(dev, "%s: Invalid lpass audio hw node\n", __func__); + goto done; + } + + if (priv->core_audio_vote_count == 0) { + ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_audio_hw_vote, dev); + if (ret < 0) { + dev_err_ratelimited(dev, "%s:lpass audio hw enable failed\n", + __func__); + goto core_clk_vote; + } + } + priv->core_audio_vote_count++; + +core_clk_vote: + if (priv->core_clk_vote_count == 0) { + ret = lpass_cdc_clk_rsc_request_clock(dev, TX_CORE_CLK, + TX_CORE_CLK, true); + if (ret < 0) { + dev_err_ratelimited(dev, "%s:lpass Tx core clk enable failed\n", + __func__); + goto done; + } + } + priv->core_clk_vote_count++; + +done: + mutex_unlock(&priv->vote_lock); + dev_dbg(dev, "%s, leave, hw_vote %d, audio_vote %d, core_clk_vote %d\n", + __func__, priv->core_hw_vote_count, + priv->core_audio_vote_count, priv->core_clk_vote_count); + pm_runtime_set_autosuspend_delay(priv->dev, LPASS_CDC_AUTO_SUSPEND_DELAY); + return 0; +} +EXPORT_SYMBOL(lpass_cdc_runtime_resume); + +int lpass_cdc_runtime_suspend(struct device *dev) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(dev->parent); + + dev_dbg(dev,"%s, enter\n", __func__); + mutex_lock(&priv->vote_lock); + if (priv->lpass_core_hw_vote != NULL) { + if (--priv->core_hw_vote_count == 0) + digital_cdc_rsc_mgr_hw_vote_disable( + priv->lpass_core_hw_vote, dev); + if (priv->core_hw_vote_count < 0) + priv->core_hw_vote_count = 0; + } else { + dev_dbg(dev, "%s: Invalid lpass core hw node\n", + __func__); + } + + if (priv->lpass_audio_hw_vote != NULL) { + if (--priv->core_audio_vote_count == 0) + digital_cdc_rsc_mgr_hw_vote_disable( + priv->lpass_audio_hw_vote, dev); + if (priv->core_audio_vote_count < 0) + priv->core_audio_vote_count = 0; + } else { + dev_dbg(dev, "%s: Invalid lpass audio hw node\n", + __func__); + } + + if (--priv->core_clk_vote_count == 0) { + lpass_cdc_clk_rsc_request_clock(dev, TX_CORE_CLK, + TX_CORE_CLK, false); + } + if (priv->core_clk_vote_count < 0) + priv->core_clk_vote_count = 0; + + mutex_unlock(&priv->vote_lock); + dev_dbg(dev, "%s, leave, hw_vote %d, audio_vote %d, core_clk_vote %d\n", + __func__, priv->core_hw_vote_count, + priv->core_audio_vote_count, priv->core_clk_vote_count); + return 0; +} +EXPORT_SYMBOL(lpass_cdc_runtime_suspend); +#endif /* CONFIG_PM */ + +bool lpass_cdc_check_core_votes(struct device *dev) +{ + struct lpass_cdc_priv *priv = dev_get_drvdata(dev->parent); + bool ret = true; + mutex_lock(&priv->vote_lock); + if (!priv->pre_dev_up || + (priv->lpass_core_hw_vote && !priv->core_hw_vote_count) || + (priv->lpass_audio_hw_vote && !priv->core_audio_vote_count)) + ret = false; + mutex_unlock(&priv->vote_lock); + + return ret; +} +EXPORT_SYMBOL(lpass_cdc_check_core_votes); + +static const struct of_device_id lpass_cdc_dt_match[] = { + {.compatible = "qcom,lpass-cdc"}, + {} +}; +MODULE_DEVICE_TABLE(of, lpass_cdc_dt_match); + +static struct platform_driver lpass_cdc_drv = { + .driver = { + .name = "lpass-cdc", + .owner = THIS_MODULE, + .of_match_table = lpass_cdc_dt_match, + .suppress_bind_attrs = true, + }, + .probe = lpass_cdc_probe, + .remove = lpass_cdc_remove, +}; + +static int lpass_cdc_drv_init(void) +{ + return platform_driver_register(&lpass_cdc_drv); +} + +static void lpass_cdc_drv_exit(void) +{ + platform_driver_unregister(&lpass_cdc_drv); +} + +static int __init lpass_cdc_init(void) +{ + lpass_cdc_drv_init(); + lpass_cdc_clk_rsc_mgr_init(); + return 0; +} +module_init(lpass_cdc_init); + +static void __exit lpass_cdc_exit(void) +{ + lpass_cdc_clk_rsc_mgr_exit(); + lpass_cdc_drv_exit(); +} +module_exit(lpass_cdc_exit); + +MODULE_DESCRIPTION("LPASS Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.h b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.h new file mode 100644 index 0000000000..2569dc8244 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.h @@ -0,0 +1,394 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef LPASS_CDC_H +#define LPASS_CDC_H + +#include +#include + +#define LPASS_CDC_VERSION_1_0 0x0001 +#define LPASS_CDC_VERSION_1_1 0x0002 +#define LPASS_CDC_VERSION_1_2 0x0003 +#define LPASS_CDC_VERSION_2_0 0x0004 +#define LPASS_CDC_VERSION_2_1 0x0005 +#define LPASS_CDC_VERSION_2_5 0x0006 +#define LPASS_CDC_VERSION_2_6 0x0007 +#define LPASS_CDC_VERSION_2_7 0x0008 +#define LPASS_CDC_VERSION_2_8 0x0009 + +enum { + START_MACRO, + TX_MACRO = START_MACRO, + RX_MACRO, + WSA_MACRO, + VA_MACRO, + WSA2_MACRO, + MAX_MACRO +}; + +enum mclk_mux { + MCLK_MUX0, + MCLK_MUX1, + MCLK_MUX_MAX +}; + +enum { + LPASS_CDC_ADC0 = 1, + LPASS_CDC_ADC1, + LPASS_CDC_ADC2, + LPASS_CDC_ADC3, + LPASS_CDC_ADC_MAX +}; + +enum { + LPASS_CDC_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */ + LPASS_CDC_MACRO_EVT_IMPED_TRUE, /* for imped true */ + LPASS_CDC_MACRO_EVT_IMPED_FALSE, /* for imped false */ + LPASS_CDC_MACRO_EVT_SSR_DOWN, + LPASS_CDC_MACRO_EVT_SSR_UP, + LPASS_CDC_MACRO_EVT_WAIT_VA_CLK_RESET, + LPASS_CDC_MACRO_EVT_CLK_RESET, + LPASS_CDC_MACRO_EVT_REG_WAKE_IRQ, + LPASS_CDC_MACRO_EVT_RX_COMPANDER_SOFT_RST, + LPASS_CDC_MACRO_EVT_BCS_CLK_OFF, + LPASS_CDC_MACRO_EVT_SSR_GFMUX_UP, + LPASS_CDC_MACRO_EVT_PRE_SSR_UP, + LPASS_CDC_MACRO_EVT_RX_PA_GAIN_UPDATE, + LPASS_CDC_MACRO_EVT_HPHL_HD2_ENABLE, /* Enable HD2 cfg for HPHL */ + LPASS_CDC_MACRO_EVT_HPHR_HD2_ENABLE, /* Enable HD2 cfg for HPHR */ +}; + +enum { + DMIC_TX = 0, + DMIC_VA = 1, + +}; + +struct macro_ops { + int (*init)(struct snd_soc_component *component); + int (*exit)(struct snd_soc_component *component); + u16 num_dais; + struct device *dev; + struct snd_soc_dai_driver *dai_ptr; + int (*mclk_fn)(struct device *dev, bool enable); + int (*event_handler)(struct snd_soc_component *component, u16 event, + u32 data); + int (*reg_wake_irq)(struct snd_soc_component *component, u32 data); + int (*set_port_map)(struct snd_soc_component *component, u32 uc, + u32 size, void *data); + int (*clk_div_get)(struct snd_soc_component *component); + int (*reg_evt_listener)(struct snd_soc_component *component, bool en); + int (*clk_enable)(struct snd_soc_component *c, bool en); + char __iomem *io_base; + u16 clk_id_req; + u16 default_clk_id; +}; + +enum { + G_21_DB = 0, + G_19P5_DB, + G_18_DB, + G_16P5_DB, + G_15_DB, + G_13P5_DB, + G_12_DB, + G_10P5_DB, + G_9_DB, + G_7P5_DB, + G_6_DB, + G_4P5_DB, + G_3_DB, + G_1P5_DB, + G_0_DB, + G_M1P5_DB, + G_M3_DB, + G_M4P5_DB, + G_M6_DB, + G_MAX_DB, +}; + +enum { + EXT_ABOVE_3S, + CONFIG_1S, + CONFIG_2S, + CONFIG_3S, + EXT_1S, + EXT_2S, + EXT_3S, + CONFIG_MAX, +}; + +enum { + WSA_4_OHMS = 0, + WSA_6_OHMS, + WSA_8_OHMS, + WSA_32_OHMS, + WSA_MAX_OHMS, +}; + +/* + * PBR Thresholds from system_gain, bat_cfg, and rload + * EXT_ABOVE_3S: WSA_4_OHMS, WSA_6_OHMS, WSA_8_OHMS, WSA_32_OHMS, CONFIG_1S: ... + */ +static const int pbr_vth1_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + /* G_21_DB */ + { + {0, 0, 0, 0}, {81, 92, 106, 0}, + {121, 148, 144, 0}, {158, 193, 192, 0} + }, + /* G_19P5_DB */ + { + {0, 0, 0, 0}, {96, 109, 126, 0}, + {143, 148, 203, 0}, {188, 198, 255, 0} + }, + /* G_18_DB */ + { + {0, 0, 0, 0}, {106, 130, 150, 0}, + {144, 209, 241, 0}, {192, 255, 255, 0} + }, + /* G_16P5_DB */ + { + {0, 0, 0, 0}, {135, 154, 178, 0}, + {202, 248, 255, 0}, {255, 255, 255, 0} + }, + /* G_15_DB */ + { + {0, 0, 0, 0}, {160, 183, 211, 0}, + {240, 255, 255, 0}, {255, 255, 255, 0} + }, + /* G_13P5_DB */ + { + {0, 0, 0, 0}, {190, 217, 251, 0}, + {255, 255, 255, 0}, {255, 255, 255, 0} + }, + /* G_12_DB */ + { + {0, 0, 0, 0}, {226, 255, 255, 0}, + {225, 255, 255, 0}, {255, 255, 255, 0} + }, +}; +static const int pbr_vth2_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 112, 0}, {0, 0, 151, 0}, {0, 0, 196, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 115, 0, 0}, {0, 155, 0, 0}, {0, 201, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {112, 0, 0, 0}, {150, 0, 0, 0}, {195, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth3_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 118, 0}, {0, 0, 157, 0}, {0, 0, 199, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 122, 0, 0}, {0, 162, 0, 0}, {0, 205, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {118, 0, 0, 0}, {157, 0, 0, 0}, {199, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth4_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 125, 0}, {0, 0, 163, 0}, {0, 0, 202, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 129, 0, 0}, {0, 168, 0, 0}, {0, 208, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {125, 0, 0, 0}, {163, 0, 0, 0}, {202, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth5_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 131, 0}, {0, 0, 170, 0}, {0, 0, 205, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 135, 0, 0}, {0, 175, 0, 0}, {0, 211, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {131, 0, 0, 0}, {170, 0, 0, 0}, {205, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth6_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 138, 0}, {0, 0, 176, 0}, {0, 0, 208, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 142, 0, 0}, {0, 182, 0, 0}, {0, 215, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {138, 0, 0, 0}, {176, 0, 0, 0}, {208, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth7_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 144, 0}, {0, 0, 183, 0}, {0, 0, 212, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 148, 0, 0}, {0, 188, 0, 0}, {0, 218, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {0, 0, 144, 0}, {0, 0, 183, 0}, {0, 0, 212, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth8_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 151, 0}, {0, 0, 189, 0}, {0, 0, 215, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 155, 0, 0}, {0, 195, 0, 0}, {0, 221, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {150, 0, 0, 0}, {189, 0, 0, 0}, {215, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth9_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 157, 0}, {0, 0, 196, 0}, {0, 0, 218, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 162, 0, 0}, {0, 201, 0, 0}, {0, 225, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {157, 0, 0, 0}, {195, 0, 0, 0}, {218, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth10_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 163, 0}, {0, 0, 202, 0}, {0, 0, 221, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 168, 0, 0}, {0, 208, 0, 0}, {0, 228, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {163, 0, 0, 0}, {202, 0, 0, 0}, {221, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth11_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 170, 0}, {0, 0, 208, 0}, {0, 0, 225, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 175, 0, 0}, {0, 215, 0, 0}, {0, 231, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {170, 0, 0, 0}, {208, 0, 0, 0}, {224, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth12_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 176, 0}, {0, 0, 215, 0}, {0, 0, 228, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 182, 0, 0}, {0, 221, 0, 0}, {0, 234, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {176, 0, 0, 0}, {215, 0, 0, 0}, {228, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth13_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 183, 0}, {0, 0, 221, 0}, {0, 0, 231, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 188, 0, 0}, {0, 228, 0, 0}, {0, 238, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {183, 0, 0, 0}, {221, 0, 0, 0}, {231, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth14_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 189, 0}, {0, 0, 228, 0}, {0, 0, 234, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 195, 0, 0}, {0, 234, 0, 0}, {0, 241, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {189, 0, 0, 0}, {228, 0, 0, 0}, {234, 0, 0, 0} }, /* G_18_DB */ +}; + +static const int pbr_vth15_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = { + { {0, 0, 0, 0}, {0, 0, 196, 0}, {0, 0, 234, 0}, {0, 0, 237, 0} }, /* G_21_DB */ + { {0, 0, 0, 0}, {0, 201, 0, 0}, {0, 241, 0, 0}, {0, 244, 0, 0} }, /* G_19P5_DB */ + { {0, 0, 0, 0}, {195, 0, 0, 0}, {234, 0, 0, 0}, {237, 0, 0, 0} }, /* G_18_DB */ +}; + +typedef int (*rsc_clk_cb_t)(struct device *dev, u16 event); + +#if IS_ENABLED(CONFIG_SND_SOC_LPASS_CDC) +int lpass_cdc_register_res_clk(struct device *dev, rsc_clk_cb_t cb); +void lpass_cdc_unregister_res_clk(struct device *dev); +bool lpass_cdc_is_va_macro_registered(struct device *dev); +int lpass_cdc_register_macro(struct device *dev, u16 macro_id, + struct macro_ops *ops); +void lpass_cdc_unregister_macro(struct device *dev, u16 macro_id); +struct device *lpass_cdc_get_device_ptr(struct device *dev, u16 macro_id); +struct device *lpass_cdc_get_rsc_clk_device_ptr(struct device *dev); +int lpass_cdc_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component); +int lpass_cdc_register_wake_irq(struct snd_soc_component *component, u32 data); +void lpass_cdc_clear_amic_tx_hold(struct device *dev, u16 adc_n); +int lpass_cdc_runtime_resume(struct device *dev); +int lpass_cdc_runtime_suspend(struct device *dev); +int lpass_cdc_set_port_map(struct snd_soc_component *component, u32 size, void *data); +int lpass_cdc_register_event_listener(struct snd_soc_component *component, + bool enable); +void lpass_cdc_wsa_pa_on(struct device *dev, bool adie_lb); +void lpass_cdc_notify_wcd_rx_clk(struct device *dev, bool is_native_on); +bool lpass_cdc_check_core_votes(struct device *dev); +int lpass_cdc_tx_mclk_enable(struct snd_soc_component *c, bool enable); +int lpass_cdc_get_version(struct device *dev); +int lpass_cdc_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable); + +/* RX MACRO utilities */ +int lpass_cdc_rx_set_fir_capability(struct snd_soc_component *component, + bool capable); +#else +static inline int lpass_cdc_register_res_clk(struct device *dev, rsc_clk_cb_t cb) +{ + return 0; +} +static inline void lpass_cdc_unregister_res_clk(struct device *dev) +{ +} + +static bool lpass_cdc_is_va_macro_registered(struct device *dev) +{ + return false; +} + +static inline int lpass_cdc_register_macro(struct device *dev, + u16 macro_id, + struct macro_ops *ops) +{ + return 0; +} + +static inline void lpass_cdc_unregister_macro(struct device *dev, u16 macro_id) +{ +} + +static inline struct device *lpass_cdc_get_device_ptr(struct device *dev, + u16 macro_id) +{ + return NULL; +} + +static int lpass_cdc_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} + +static inline void lpass_cdc_clear_amic_tx_hold(struct device *dev, u16 adc_n) +{ +} + +static inline int lpass_cdc_register_wake_irq(struct snd_soc_component *component, + u32 data) +{ + return 0; +} + +static inline int lpass_cdc_runtime_resume(struct device *dev) +{ + return 0; +} + +static int lpass_cdc_runtime_suspend(struct device *dev) +{ + return 0; +} + +static inline int lpass_cdc_set_port_map(struct snd_soc_component *component, + u32 size, void *data) +{ + return 0; +} + +static inline int lpass_cdc_register_event_listener( + struct snd_soc_component *component, + bool enable) +{ + return 0; +} + +static void lpass_cdc_wsa_pa_on(struct device *dev, bool adie_lb) +{ +} + +static void lpass_cdc_notify_wcd_rx_clk(struct device *dev, bool is_native_on) +{ +} + +static inline bool lpass_cdc_check_core_votes(struct device *dev) +{ + return false; +} + +static int lpass_cdc_get_version(struct device *dev) +{ + return 0; +} + +static int lpass_cdc_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + return 0; +} +static int lpass_cdc_tx_mclk_enable(struct snd_soc_component *c, bool enable) +{ + return 0; +} +/* RX MACRO utilities */ +static int lpass_cdc_rx_set_fir_capability(struct snd_soc_component *component, + bool capable) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_LPASS_CDC */ +#endif /* LPASS_CDC_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/msm-cdc-pinctrl.c b/qcom/opensource/audio-kernel/asoc/codecs/msm-cdc-pinctrl.c new file mode 100644 index 0000000000..dfe2652caf --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/msm-cdc-pinctrl.c @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_GPIOS 16 + +struct msm_cdc_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_active; + struct pinctrl_state *pinctrl_sleep; + struct pinctrl_state *pinctrl_alt_active; + int gpio; + bool state; + u32 tlmm_gpio[MAX_GPIOS]; + char __iomem *chip_wakeup_register[MAX_GPIOS]; + u32 chip_wakeup_maskbit[MAX_GPIOS]; + u32 count; + u32 wakeup_reg_count; + bool wakeup_capable; + bool chip_wakeup_reg; +}; + +static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata( + struct device_node *np) +{ + struct platform_device *pdev; + struct msm_cdc_pinctrl_info *gpio_data; + + if (!np) { + pr_err_ratelimited("%s: device node is null\n", __func__); + return NULL; + } + + pdev = of_find_device_by_node(np); + if (!pdev) { + pr_err_ratelimited("%s: platform device not found!\n", __func__); + return NULL; + } + + gpio_data = dev_get_drvdata(&pdev->dev); + if (!gpio_data) + dev_err_ratelimited(&pdev->dev, "%s: cannot find cdc gpio info\n", + __func__); + + return gpio_data; +} + +/* + * msm_cdc_get_gpio_state: select pinctrl sleep state + * @np: pointer to struct device_node + * + * Returns error code for failure and GPIO value on success + */ +int msm_cdc_get_gpio_state(struct device_node *np) +{ + struct msm_cdc_pinctrl_info *gpio_data; + int value = -EINVAL; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return value; + + if (gpio_is_valid(gpio_data->gpio)) + value = gpio_get_value_cansleep(gpio_data->gpio); + + return value; +} +EXPORT_SYMBOL(msm_cdc_get_gpio_state); + +/* + * msm_cdc_pinctrl_select_sleep_state: select pinctrl sleep state + * @np: pointer to struct device_node + * + * Returns error code for failure + */ +int msm_cdc_pinctrl_select_sleep_state(struct device_node *np) +{ + struct msm_cdc_pinctrl_info *gpio_data; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return -EINVAL; + + if (!gpio_data->pinctrl_sleep) { + pr_err_ratelimited("%s: pinctrl sleep state is null\n", __func__); + return -EINVAL; + } + gpio_data->state = false; + + return pinctrl_select_state(gpio_data->pinctrl, + gpio_data->pinctrl_sleep); +} +EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state); + +/* + * msm_cdc_pinctrl_select_alt_active_state: select pinctrl alt_active state + * @np: pointer to struct device_node + * + * Returns error code for failure + */ +int msm_cdc_pinctrl_select_alt_active_state(struct device_node *np) +{ + struct msm_cdc_pinctrl_info *gpio_data; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return -EINVAL; + + if (!gpio_data->pinctrl_alt_active) { + pr_err_ratelimited("%s: pinctrl alt_active state is null\n", __func__); + return -EINVAL; + } + gpio_data->state = true; + + return pinctrl_select_state(gpio_data->pinctrl, + gpio_data->pinctrl_alt_active); +} +EXPORT_SYMBOL(msm_cdc_pinctrl_select_alt_active_state); + +/* + * msm_cdc_pinctrl_select_active_state: select pinctrl active state + * @np: pointer to struct device_node + * + * Returns error code for failure + */ +int msm_cdc_pinctrl_select_active_state(struct device_node *np) +{ + struct msm_cdc_pinctrl_info *gpio_data; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return -EINVAL; + + if (!gpio_data->pinctrl_active) { + pr_err_ratelimited("%s: pinctrl active state is null\n", __func__); + return -EINVAL; + } + gpio_data->state = true; + + return pinctrl_select_state(gpio_data->pinctrl, + gpio_data->pinctrl_active); +} +EXPORT_SYMBOL(msm_cdc_pinctrl_select_active_state); + +/* + * msm_cdc_pinctrl_get_state: get curren pinctrl state + * @np: pointer to struct device_node + * + * Returns 0 for sleep state, 1 for active state, + * error code for failure + */ +int msm_cdc_pinctrl_get_state(struct device_node *np) +{ + struct msm_cdc_pinctrl_info *gpio_data; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return -EINVAL; + + return gpio_data->state; +} +EXPORT_SYMBOL(msm_cdc_pinctrl_get_state); + +/* + * msm_cdc_pinctrl_set_wakeup_capable: Set a pinctrl to wakeup capable + * @np: pointer to struct device_node + * @enable: wakeup capable when set to true + * + * Returns 0 for success and error code for failure + */ +int msm_cdc_pinctrl_set_wakeup_capable(struct device_node *np, bool enable) +{ + struct msm_cdc_pinctrl_info *gpio_data; + int ret = 0; + u32 i = 0, temp = 0; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return -EINVAL; + + if (gpio_data->wakeup_capable) { + for (i = 0; i < gpio_data->count; i++) { + ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio[i], + enable); + if (ret < 0) + goto exit; + } + } + if (gpio_data->chip_wakeup_reg) { + for (i = 0; i < gpio_data->wakeup_reg_count; i++) { + temp = ioread32(gpio_data->chip_wakeup_register[i]); + if (enable) + temp |= (1 << + gpio_data->chip_wakeup_maskbit[i]); + else + temp &= ~(1 << + gpio_data->chip_wakeup_maskbit[i]); + iowrite32(temp, gpio_data->chip_wakeup_register[i]); + } + } +exit: + return ret; +} +EXPORT_SYMBOL(msm_cdc_pinctrl_set_wakeup_capable); + +static int msm_cdc_pinctrl_probe(struct platform_device *pdev) +{ + int ret = 0; + struct msm_cdc_pinctrl_info *gpio_data; + u32 tlmm_gpio[MAX_GPIOS] = {0}; + u32 chip_wakeup_reg[MAX_GPIOS] = {0}; + u32 chip_wakeup_default_val[MAX_GPIOS] = {0}; + u32 i = 0, temp = 0; + int count = 0; + + gpio_data = devm_kzalloc(&pdev->dev, + sizeof(struct msm_cdc_pinctrl_info), + GFP_KERNEL); + if (!gpio_data) + return -ENOMEM; + + gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(gpio_data->pinctrl)) { + dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n", + __func__, PTR_ERR(gpio_data->pinctrl)); + ret = PTR_ERR(gpio_data->pinctrl); + goto err_pctrl_get; + } + + gpio_data->pinctrl_active = pinctrl_lookup_state( + gpio_data->pinctrl, "aud_active"); + if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) { + dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n", + __func__, PTR_ERR(gpio_data->pinctrl_active)); + ret = PTR_ERR(gpio_data->pinctrl_active); + goto err_lookup_state; + } + + gpio_data->pinctrl_sleep = pinctrl_lookup_state( + gpio_data->pinctrl, "aud_sleep"); + if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) { + dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n", + __func__, PTR_ERR(gpio_data->pinctrl_sleep)); + ret = PTR_ERR(gpio_data->pinctrl_sleep); + goto err_lookup_state; + } + + gpio_data->pinctrl_alt_active = pinctrl_lookup_state( + gpio_data->pinctrl, "aud_alt_active"); + if (IS_ERR_OR_NULL(gpio_data->pinctrl_alt_active)) { + dev_dbg(&pdev->dev, "%s: Cannot get aud_alt_active pinctrl state:%ld\n", + __func__, PTR_ERR(gpio_data->pinctrl_alt_active)); + } + + /* skip setting to sleep state for LPI_TLMM GPIOs */ + if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) { + /* Set pinctrl state to aud_sleep by default */ + ret = pinctrl_select_state(gpio_data->pinctrl, + gpio_data->pinctrl_sleep); + if (ret) + dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n", + __func__, ret); + } + + + count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,chip-wakeup-reg"); + if (count <= 0) + goto cdc_tlmm_gpio; + if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,chip-wakeup-reg", + chip_wakeup_reg, count)) { + if (of_property_read_u32_array(pdev->dev.of_node, + "qcom,chip-wakeup-maskbit", + gpio_data->chip_wakeup_maskbit, count)) { + dev_err(&pdev->dev, + "chip-wakeup-maskbit needed if chip-wakeup-reg is defined!\n"); + goto cdc_tlmm_gpio; + } + gpio_data->chip_wakeup_reg = true; + for (i = 0; i < count; i++) { + gpio_data->chip_wakeup_register[i] = + devm_ioremap(&pdev->dev, chip_wakeup_reg[i], 0x4); + } + if (!of_property_read_u32_array(pdev->dev.of_node, + "qcom,chip-wakeup-default-val", + chip_wakeup_default_val, count)) { + for (i = 0; i < count; i++) { + temp = ioread32(gpio_data->chip_wakeup_register[i]); + if (chip_wakeup_default_val[i]) + temp |= (1 << + gpio_data->chip_wakeup_maskbit[i]); + else + temp &= ~(1 << + gpio_data->chip_wakeup_maskbit[i]); + iowrite32(temp, gpio_data->chip_wakeup_register[i]); + } + } + gpio_data->wakeup_reg_count = count; + } + +cdc_tlmm_gpio: + count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,tlmm-pins"); + if (count <= 0) + goto cdc_rst; + if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,tlmm-pins", + tlmm_gpio, count)) { + gpio_data->wakeup_capable = true; + for (i = 0; i < count; i++) + gpio_data->tlmm_gpio[i] = tlmm_gpio[i]; + gpio_data->count = count; + } + +cdc_rst: + gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,cdc-rst-n-gpio", 0); + if (gpio_is_valid(gpio_data->gpio)) { + ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET"); + if (ret) { + dev_err(&pdev->dev, "%s: Failed to request gpio %d\n", + __func__, gpio_data->gpio); + goto err_lookup_state; + } + } + + dev_set_drvdata(&pdev->dev, gpio_data); + return 0; + +err_lookup_state: + devm_pinctrl_put(gpio_data->pinctrl); +err_pctrl_get: + devm_kfree(&pdev->dev, gpio_data); + return ret; +} + +static int msm_cdc_pinctrl_remove(struct platform_device *pdev) +{ + struct msm_cdc_pinctrl_info *gpio_data; + + gpio_data = dev_get_drvdata(&pdev->dev); + + /* to free the requested gpio before exiting */ + if (gpio_data) { + if (gpio_is_valid(gpio_data->gpio)) + gpio_free(gpio_data->gpio); + + if (gpio_data->pinctrl) + devm_pinctrl_put(gpio_data->pinctrl); + } + + devm_kfree(&pdev->dev, gpio_data); + + return 0; +} + +static const struct of_device_id msm_cdc_pinctrl_match[] = { + {.compatible = "qcom,msm-cdc-pinctrl"}, + {} +}; + +static struct platform_driver msm_cdc_pinctrl_driver = { + .driver = { + .name = "msm-cdc-pinctrl", + .owner = THIS_MODULE, + .of_match_table = msm_cdc_pinctrl_match, + .suppress_bind_attrs = true, + }, + .probe = msm_cdc_pinctrl_probe, + .remove = msm_cdc_pinctrl_remove, +}; + +int msm_cdc_pinctrl_drv_init(void) +{ + return platform_driver_register(&msm_cdc_pinctrl_driver); +} + +void msm_cdc_pinctrl_drv_exit(void) +{ + platform_driver_unregister(&msm_cdc_pinctrl_driver); +} +MODULE_DESCRIPTION("MSM CODEC pin control platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/msm-cdc-supply.c b/qcom/opensource/audio-kernel/asoc/codecs/msm-cdc-supply.c new file mode 100644 index 0000000000..b7dbc797c0 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/msm-cdc-supply.c @@ -0,0 +1,932 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CODEC_DT_MAX_PROP_SIZE 40 + +static int msm_cdc_dt_parse_vreg_info(struct device *dev, + struct cdc_regulator *cdc_vreg, + const char *name, bool is_ond) +{ + char prop_name[CODEC_DT_MAX_PROP_SIZE]; + struct device_node *regulator_node = NULL; + const __be32 *prop; + int len, rc; + u32 prop_val; + + /* Parse supply name */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply", name); + + regulator_node = of_parse_phandle(dev->of_node, prop_name, 0); + if (!regulator_node) { + dev_err(dev, "%s: Looking up %s property in node %s failed", + __func__, prop_name, dev->of_node->full_name); + rc = -EINVAL; + goto done; + } + cdc_vreg->name = name; + cdc_vreg->ondemand = is_ond; + + /* Parse supply - voltage */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-voltage", name); + prop = of_get_property(dev->of_node, prop_name, &len); + if (!prop || (len != (2 * sizeof(__be32)))) { + dev_err(dev, "%s: %s %s property\n", __func__, + prop ? "invalid format" : "no", prop_name); + rc = -EINVAL; + goto done; + } else { + cdc_vreg->min_uV = be32_to_cpup(&prop[0]); + cdc_vreg->max_uV = be32_to_cpup(&prop[1]); + } + + /* Parse supply - current */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-current", name); + rc = of_property_read_u32(dev->of_node, prop_name, &prop_val); + if (rc) { + dev_err(dev, "%s: Looking up %s property in node %s failed", + __func__, prop_name, dev->of_node->full_name); + goto done; + } + cdc_vreg->optimum_uA = prop_val; + + /* Parse supply - LPM or NOM mode(default NOM) */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-lpm-supported", name); + rc = of_property_read_u32(dev->of_node, prop_name, &prop_val); + if (rc) { + dev_dbg(dev, "%s: Looking up %s property in node %s failed", + __func__, prop_name, dev->of_node->full_name); + cdc_vreg->lpm_supported = 0; + rc = 0; + } else { + cdc_vreg->lpm_supported = prop_val; + } + + /* Parse supply - retention mode */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-rem-supported", name); + rc = of_property_read_u32(dev->of_node, prop_name, &prop_val); + if (rc) { + dev_dbg(dev, "%s: Looking up %s property in node %s failed", + __func__, prop_name, dev->of_node->full_name); + cdc_vreg->rem_supported = 0; + rc = 0; + } else { + cdc_vreg->rem_supported = prop_val; + } + + dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d lpm %d rem %d\n", + __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV, + cdc_vreg->optimum_uA, cdc_vreg->ondemand, + cdc_vreg->lpm_supported, cdc_vreg->rem_supported); + +done: + return rc; +} + +static int msm_cdc_parse_supplies(struct device *dev, + struct cdc_regulator *cdc_reg, + const char *sup_list, int sup_cnt, + bool is_ond) +{ + int idx, rc = 0; + const char *name = NULL; + + for (idx = 0; idx < sup_cnt; idx++) { + rc = of_property_read_string_index(dev->of_node, sup_list, idx, + &name); + if (rc) { + dev_err(dev, "%s: read string %s[%d] error (%d)\n", + __func__, sup_list, idx, rc); + goto done; + } + + dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n", + __func__, name, sup_list); + + rc = msm_cdc_dt_parse_vreg_info(dev, &cdc_reg[idx], name, + is_ond); + if (rc) { + dev_err(dev, "%s: parse %s vreg info failed (%d)\n", + __func__, name, rc); + goto done; + } + } + +done: + return rc; +} + +static int msm_cdc_check_supply_param(struct device *dev, + struct cdc_regulator *cdc_vreg, + int num_supplies) +{ + if (!dev) { + pr_err_ratelimited("%s: device is NULL\n", __func__); + return -ENODEV; + } + + if (!cdc_vreg || (num_supplies <= 0)) { + dev_err_ratelimited(dev, "%s: supply check failed: vreg: %pK, num_supplies: %d\n", + __func__, cdc_vreg, num_supplies); + return -EINVAL; + } + + return 0; +} + +/* + * msm_cdc_is_ondemand_supply: + * return if ondemand supply true or not + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: supply name to be checked + * + * Return true/false + */ +bool msm_cdc_is_ondemand_supply(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + char *supply_name) +{ + bool rc = false; + int ret, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return rc; + } + /* input parameter validation */ + ret = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (ret) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].ondemand && + !strcmp(cdc_vreg[i].name, supply_name)) + return true; + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_is_ondemand_supply); + +/* + * msm_cdc_supply_supports_retention_mode: + * On certain hardware configurations, This means that the + * PM will disable the supply and remove its power vote + * if the PM enters into a suspended state. + * + * return if supply supports retention mode or not + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: supply name to be checked + * + * Return true/false + */ +bool msm_cdc_supply_supports_retention_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, char *supply_name) +{ + bool rc = false; + int ret, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return rc; + } + /* input parameter validation */ + ret = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (ret) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].rem_supported && + !strcmp(cdc_vreg[i].name, supply_name)) + return true; + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_supply_supports_retention_mode); + +/* + * msm_cdc_check_supply_vote: + * + * return true if supply has voted for regulator enable + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: supply name to be checked + * + * Return true/false + */ +bool msm_cdc_check_supply_vote(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + char *supply_name) +{ + bool rc = false; + int ret, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return rc; + } + + /* input parameter validation */ + ret = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (ret) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (strcmp(cdc_vreg[i].name, supply_name) != 0) + continue; + + return cdc_vreg[i].vote; + } + + dev_err_ratelimited(dev, + "%s: Unable to find vote for supply %s\n", + __func__, supply_name); + + return -EINVAL; +} +EXPORT_SYMBOL(msm_cdc_check_supply_vote); + +/* + * msm_cdc_set_supply_min_voltage: + * Set min supply voltage for particular supply + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: Supply name to change voltage for + * @vval_min: Min voltage to be set in uV + * @override_min_vol: True if override min voltage from default + * Return error code if unable to set voltage + */ +int msm_cdc_set_supply_min_voltage(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, char *supply_name, + int vval_min, bool override_min_vol) +{ + int rc = 0, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + for (i = 0; i < num_supplies; i++) { + if (!strcmp(cdc_vreg[i].name, supply_name)) { + if (override_min_vol) + regulator_set_voltage(supplies[i].consumer, + vval_min, cdc_vreg[i].max_uV); + else + regulator_set_voltage(supplies[i].consumer, + cdc_vreg[i].min_uV, cdc_vreg[i].max_uV); + break; + } + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_set_supply_min_voltage); + +/* + * msm_cdc_disable_ondemand_supply: + * Disable codec ondemand supply + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: Ondemand supply name to be enabled + * + * Return error code if supply disable is failed + */ +int msm_cdc_disable_ondemand_supply(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + char *supply_name) +{ + int rc, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + dev_dbg(dev, "%s: Disabling on-demand supply %s\n", + __func__, supply_name); + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].ondemand && + !strcmp(cdc_vreg[i].name, supply_name)) { + if (!cdc_vreg[i].vote) { + dev_err_ratelimited(dev, + "%s: Attempted to disable already disabled supply %s\n", + __func__, supplies[i].supply); + break; + } + + rc = regulator_disable(supplies[i].consumer); + if (rc) + dev_err_ratelimited(dev, + "%s: failed to disable supply %s, err:%d\n", + __func__, supplies[i].supply, rc); + else + cdc_vreg[i].vote = false; + break; + } + } + if (i == num_supplies) { + dev_err_ratelimited(dev, "%s: not able to find supply %s\n", + __func__, supply_name); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_disable_ondemand_supply); + +/* + * msm_cdc_enable_ondemand_supply: + * Enable codec ondemand supply + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: Ondemand supply name to be enabled + * + * Return error code if supply enable is failed + */ +int msm_cdc_enable_ondemand_supply(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + char *supply_name) +{ + int rc, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + dev_dbg(dev, "%s: Enabling on-demand supply %s\n", + __func__, supply_name); + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].ondemand && + !strcmp(cdc_vreg[i].name, supply_name)) { + if (cdc_vreg[i].vote) { + dev_err_ratelimited(dev, + "%s: Attempted to enable already enabled supply %s\n", + __func__, supplies[i].supply); + break; + } + + rc = regulator_enable(supplies[i].consumer); + if (rc) + dev_err_ratelimited(dev, "%s: failed to enable supply %s, rc: %d\n", + __func__, supplies[i].supply, rc); + else + cdc_vreg[i].vote = true; + break; + } + } + if (i == num_supplies) { + dev_err_ratelimited(dev, "%s: not able to find supply %s\n", + __func__, supply_name); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_enable_ondemand_supply); + +/* + * msm_cdc_set_supplies_lpm_mode: + * Update load for given supply string + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: supply name to be checked + * @min_max: Apply optimum or 0 current + * + * Return error code if set current fail + */ +int msm_cdc_set_supplies_lpm_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + bool flag) +{ + int rc = 0, i; + + if (!supplies) { + pr_err_ratelimited("%s: supplies is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].lpm_supported) { + rc = regulator_set_load( + supplies[i].consumer, + flag ? 0 : cdc_vreg[i].optimum_uA); + if (rc) + dev_err_ratelimited(dev, + "%s: failed to set supply %s to %s, err:%d\n", + __func__, supplies[i].supply, + flag ? "LPM" : "NOM", + rc); + else + dev_dbg(dev, "%s: regulator %s load set to %s\n", + __func__, supplies[i].supply, + flag ? "LPM" : "NOM"); + } + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_set_supplies_lpm_mode); + +/* + * msm_cdc_disable_static_supplies: + * Disable codec static supplies + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * + * Return error code if supply disable is failed + */ +int msm_cdc_disable_static_supplies(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies) +{ + int rc, i; + + if ((!dev) || (!supplies) || (!cdc_vreg)) { + pr_err("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].ondemand) + continue; + + rc = regulator_disable(supplies[i].consumer); + if (rc) + dev_err(dev, "%s: failed to disable supply %s, err:%d\n", + __func__, supplies[i].supply, rc); + else { + cdc_vreg[i].vote = false; + dev_dbg(dev, "%s: disabled regulator %s\n", + __func__, supplies[i].supply); + } + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_disable_static_supplies); + +/* + * msm_cdc_release_supplies: + * Release codec power supplies + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * + * Return error code if supply disable is failed + */ +int msm_cdc_release_supplies(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies) +{ + int rc = 0; + int i; + + if ((!dev) || (!supplies) || (!cdc_vreg)) { + pr_err("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + msm_cdc_disable_static_supplies(dev, supplies, cdc_vreg, + num_supplies); + for (i = 0; i < num_supplies; i++) { + if (regulator_count_voltages(supplies[i].consumer) < 0) + continue; + + regulator_set_voltage(supplies[i].consumer, 0, + cdc_vreg[i].max_uV); + regulator_set_load(supplies[i].consumer, 0); + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_release_supplies); + +/* + * msm_cdc_enable_static_supplies: + * Enable codec static supplies + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * + * Return error code if supply enable is failed + */ +int msm_cdc_enable_static_supplies(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies) +{ + int rc, i; + + if ((!dev) || (!supplies) || (!cdc_vreg)) { + pr_err("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].ondemand) + continue; + + rc = regulator_enable(supplies[i].consumer); + if (rc) { + dev_err(dev, "%s: failed to enable supply %s, rc: %d\n", + __func__, supplies[i].supply, rc); + break; + } else + cdc_vreg[i].vote = true; + } + + if (rc) { + while (i--) { + if (cdc_vreg[i].ondemand) + continue; + + if (regulator_disable(supplies[i].consumer) == 0) + cdc_vreg[i].vote = false; + else + dev_err(dev, "%s: failed to disable supply %s during unwind\n", + __func__, supplies[i].supply); + } + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_enable_static_supplies); + +/* + * msm_cdc_init_supplies: + * Initialize codec static supplies + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * + * Return error code if supply init is failed + */ +int msm_cdc_init_supplies(struct device *dev, + struct regulator_bulk_data **supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies) +{ + return msm_cdc_init_supplies_v2(dev, supplies, cdc_vreg, + num_supplies, false); +} +EXPORT_SYMBOL(msm_cdc_init_supplies); + +/* + * msm_cdc_init_supplies_v2: + * Initialize codec static supplies. + * Initialize codec dynamic supplies based on vote_regulator_on_demand + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @vote_regulator_on_demand: initialize codec dynamic supplies at runtime + * + * Return error code if supply init is failed + */ +int msm_cdc_init_supplies_v2(struct device *dev, + struct regulator_bulk_data **supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, u32 vote_regulator_on_demand) +{ + struct regulator_bulk_data *vsup; + int rc; + int i; + + if (!dev || !cdc_vreg) { + pr_err("%s: device pointer or dce_vreg is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + vsup = devm_kcalloc(dev, num_supplies, + sizeof(struct regulator_bulk_data), + GFP_KERNEL); + if (!vsup) + return -ENOMEM; + + for (i = 0; i < num_supplies; i++) { + if (!cdc_vreg[i].name) { + dev_err(dev, "%s: supply name not defined\n", + __func__); + rc = -EINVAL; + goto err_supply; + } + vsup[i].supply = cdc_vreg[i].name; + } + + rc = devm_regulator_bulk_get(dev, num_supplies, vsup); + if (rc) { + dev_err(dev, "%s: failed to get supplies (%d)\n", + __func__, rc); + goto err_supply; + } + + /* Set voltage and current on regulators */ + for (i = 0; i < num_supplies; i++) { + if (regulator_count_voltages(vsup[i].consumer) < 0) + continue; + + if (cdc_vreg[i].ondemand && vote_regulator_on_demand) + continue; + + cdc_vreg[i].regulator = vsup[i].consumer; + + rc = regulator_set_voltage(vsup[i].consumer, + cdc_vreg[i].min_uV, + cdc_vreg[i].max_uV); + if (rc) { + dev_err(dev, "%s: set regulator voltage failed for %s, err:%d\n", + __func__, vsup[i].supply, rc); + goto err_supply; + } + rc = regulator_set_load(vsup[i].consumer, + cdc_vreg[i].optimum_uA); + if (rc < 0) { + dev_err(dev, "%s: set regulator optimum mode failed for %s, err:%d\n", + __func__, vsup[i].supply, rc); + goto err_supply; + } + } + + *supplies = vsup; + + return 0; + +err_supply: + return rc; +} +EXPORT_SYMBOL(msm_cdc_init_supplies_v2); + +/* + * msm_cdc_get_power_supplies: + * Get codec power supplies from device tree. + * Allocate memory to hold regulator data for + * all power supplies. + * + * @dev: pointer to codec device + * @cdc_vreg: pointer to codec regulator + * @total_num_supplies: total number of supplies read from DT + * + * Return error code if supply disable is failed + */ +int msm_cdc_get_power_supplies(struct device *dev, + struct cdc_regulator **cdc_vreg, + int *total_num_supplies) +{ + const char *static_prop_name = "qcom,cdc-static-supplies"; + const char *ond_prop_name = "qcom,cdc-on-demand-supplies"; + const char *cp_prop_name = "qcom,cdc-cp-supplies"; + int static_sup_cnt = 0; + int ond_sup_cnt = 0; + int cp_sup_cnt = 0; + int num_supplies = 0; + struct cdc_regulator *cdc_reg; + int rc; + + if (!dev) { + pr_err_ratelimited("%s: device pointer is NULL\n", __func__); + return -EINVAL; + } + static_sup_cnt = of_property_count_strings(dev->of_node, + static_prop_name); + if (static_sup_cnt < 0) { + dev_err_ratelimited(dev, "%s: Failed to get static supplies(%d)\n", + __func__, static_sup_cnt); + rc = static_sup_cnt; + goto err_supply_cnt; + } + ond_sup_cnt = of_property_count_strings(dev->of_node, ond_prop_name); + if (ond_sup_cnt < 0) + ond_sup_cnt = 0; + + cp_sup_cnt = of_property_count_strings(dev->of_node, + cp_prop_name); + if (cp_sup_cnt < 0) + cp_sup_cnt = 0; + + num_supplies = static_sup_cnt + ond_sup_cnt + cp_sup_cnt; + if (num_supplies <= 0) { + dev_err_ratelimited(dev, "%s: supply count is 0 or negative\n", __func__); + rc = -EINVAL; + goto err_supply_cnt; + } + + cdc_reg = devm_kcalloc(dev, num_supplies, + sizeof(struct cdc_regulator), + GFP_KERNEL); + if (!cdc_reg) { + rc = -ENOMEM; + goto err_mem_alloc; + } + + rc = msm_cdc_parse_supplies(dev, cdc_reg, static_prop_name, + static_sup_cnt, false); + if (rc) { + dev_err_ratelimited(dev, "%s: failed to parse static supplies(%d)\n", + __func__, rc); + goto err_sup; + } + + rc = msm_cdc_parse_supplies(dev, &cdc_reg[static_sup_cnt], + ond_prop_name, ond_sup_cnt, + true); + if (rc) { + dev_err_ratelimited(dev, "%s: failed to parse demand supplies(%d)\n", + __func__, rc); + goto err_sup; + } + + rc = msm_cdc_parse_supplies(dev, + &cdc_reg[static_sup_cnt + ond_sup_cnt], + cp_prop_name, cp_sup_cnt, true); + if (rc) { + dev_err_ratelimited(dev, "%s: failed to parse cp supplies(%d)\n", + __func__, rc); + goto err_sup; + } + + *cdc_vreg = cdc_reg; + *total_num_supplies = num_supplies; + + return 0; + +err_sup: +err_supply_cnt: +err_mem_alloc: + return rc; +} +EXPORT_SYMBOL(msm_cdc_get_power_supplies); + +/* + * msm_cdc_init_wcd_supply: + * Initialize wcd supply parameters. + * + * @np: device node pointer to codec device + * @name: power supply name + * @cdc_supply: codec supply struct to hold wcd params + * + * Return error code if init failed + */ +int msm_cdc_init_wcd_supply(struct device_node *np, const char *name, + struct cdc_wcd_supply *cdc_supply) +{ + struct platform_device *pdev = NULL; + + if (!np || !cdc_supply) + return -EINVAL; + + pdev = of_find_device_by_node(np); + if (!pdev) + return -EINVAL; + + cdc_supply->dev = &pdev->dev; + cdc_supply->name = name; + cdc_supply->component = snd_soc_lookup_component(&pdev->dev, NULL); + + return 0; +} +EXPORT_SYMBOL(msm_cdc_init_wcd_supply); + +/* + * msm_cdc_enable_wcd_supply: + * Enable/Disable wcd supply. + * + * @cdc_supply: codec supply struct to hold wcd params + * @enable: bool to inform whether to enable or disable + * + * Return error code if enable/disable failed + */ +int msm_cdc_enable_wcd_supply(struct cdc_wcd_supply *cdc_supply, bool enable) +{ + struct snd_soc_component *component = cdc_supply->component; + int rc; + + if (!component) { + pr_err_ratelimited("%s: Component memory is NULL\n", __func__); + return -EINVAL; + } + + if (enable) + rc = snd_soc_dapm_force_enable_pin( + snd_soc_component_get_dapm(component), + cdc_supply->name); + else + rc = snd_soc_dapm_disable_pin( + snd_soc_component_get_dapm(component), + cdc_supply->name); + + if (!rc) + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + else + dev_err_ratelimited(component->dev, "%s: micbias %s force %s pin failed\n", + __func__, cdc_supply->name, (enable ? "enable" : "disable")); + + return rc; +} +EXPORT_SYMBOL(msm_cdc_enable_wcd_supply); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/msm_hdmi_codec_rx.c b/qcom/opensource/audio-kernel/asoc/codecs/msm_hdmi_codec_rx.c new file mode 100644 index 0000000000..1d3b3a54b9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/msm_hdmi_codec_rx.c @@ -0,0 +1,946 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "HDMI_codec" + +#define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000 +#define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT) +#define AUD_EXT_DISP_ACK_CONNECT (AUDIO_ACK_CONNECT) +#define AUD_EXT_DISP_ACK_ENABLE (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE) + +#define SOC_EXT_DISP_AUDIO_TYPE(index) \ + static SOC_ENUM_SINGLE_DECL(ext_disp_audio_type##index, SND_SOC_NOPM, \ + index, ext_disp_audio_type_text) +#define SOC_EXT_DISP_AUDIO_ACK_STATE(index) \ + static SOC_ENUM_SINGLE_DECL(ext_disp_audio_ack_state##index, \ + SND_SOC_NOPM, index, ext_disp_audio_ack_text) + +#define SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type) \ + codec_info.type = type; \ + codec_info.ctrl_id = codec_data->ctl[dai_id]; \ + codec_info.stream_id = codec_data->stream[dai_id]; \ + +enum { + DP_CONTROLLER0 = 0, + DP_CONTROLLER_MAX, +}; + +enum { + DP_STREAM0 = 0, + DP_STREAM1, + HDMI, + DP_STREAM_MAX, +}; + +/* + * Dai id cannot be zero, if component has more than one dai and dai id + * is used to differentiate between them + */ +enum { + DP_DAI1 = 1, + DP_DAI2, + HDMI_DAI, + HDMI_MS_DAI, + DP_DAI_MAX, +}; + +static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"}; +static const char *const ext_disp_audio_ack_text[] = {"Disconnect", "Connect", + "Ack_Enable"}; + +static const struct snd_pcm_hardware dummy_dma_hardware = { + /* Random values to keep userspace happy when checking constraints */ + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .buffer_bytes_max = 128*1024, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = PAGE_SIZE*2, + .periods_min = 2, + .periods_max = 128, +}; + +SOC_EXT_DISP_AUDIO_TYPE(1); +SOC_EXT_DISP_AUDIO_ACK_STATE(1); +SOC_EXT_DISP_AUDIO_TYPE(2); +SOC_EXT_DISP_AUDIO_ACK_STATE(2); +SOC_EXT_DISP_AUDIO_TYPE(3); +SOC_EXT_DISP_AUDIO_ACK_STATE(3); + +struct msm_ext_disp_audio_codec_rx_data { + struct platform_device *ext_disp_core_pdev; + struct msm_ext_disp_audio_codec_ops ext_disp_ops; + struct mutex dp_ops_lock; + int cable_status[DP_DAI_MAX]; + int stream[DP_DAI_MAX]; + int ctl[DP_DAI_MAX]; +}; + +static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_edid_blk edid_blk; + int rc = 0; + struct msm_ext_disp_codec_id codec_info; + int dai_id = kcontrol->private_value; + int type; + + codec_data = snd_soc_component_get_drvdata(component); + if (!codec_data) { + dev_err_ratelimited(component->dev, "%s: codec_data is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__, + codec_data->ctl[dai_id], codec_data->stream[dai_id]); + + mutex_lock(&codec_data->dp_ops_lock); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) { + dev_dbg(component->dev, "%s: get_audio_edid_blk() is NULL\n", + __func__); + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 0; + mutex_unlock(&codec_data->dp_ops_lock); + return 0; + } + + rc = codec_data->ext_disp_ops.get_audio_edid_blk( + codec_data->ext_disp_core_pdev, &edid_blk); + mutex_unlock(&codec_data->dp_ops_lock); + if (rc >= 0) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = edid_blk.audio_data_blk_size + + edid_blk.spk_alloc_data_blk_size; + } + + dev_dbg(component->dev, "%s: count: %d\n", __func__, uinfo->count); + + return rc; +} + +static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + struct msm_ext_disp_audio_edid_blk edid_blk; + struct msm_ext_disp_codec_id codec_info; + int rc = 0; + int dai_id = kcontrol->private_value; + int type; + + codec_data = snd_soc_component_get_drvdata(component); + if (!codec_data) { + dev_err_ratelimited(component->dev, "%s: codec_data is NULL\n", + __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__, + codec_data->ctl[dai_id], codec_data->stream[dai_id]); + + mutex_lock(&codec_data->dp_ops_lock); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) { + dev_err_ratelimited(component->dev, + "%s: codec_data or get_audio_edid_blk() is NULL\n", + __func__); + mutex_unlock(&codec_data->dp_ops_lock); + return -EINVAL; + } + rc = codec_data->ext_disp_ops.get_audio_edid_blk( + codec_data->ext_disp_core_pdev, &edid_blk); + mutex_unlock(&codec_data->dp_ops_lock); + if (rc >= 0) { + if (sizeof(ucontrol->value.bytes.data) < + (edid_blk.audio_data_blk_size + + edid_blk.spk_alloc_data_blk_size)) { + dev_err_ratelimited(component->dev, + "%s: Not enough memory to copy EDID data\n", + __func__); + return -ENOMEM; + } + + memcpy(ucontrol->value.bytes.data, + edid_blk.audio_data_blk, + edid_blk.audio_data_blk_size); + memcpy((ucontrol->value.bytes.data + + edid_blk.audio_data_blk_size), + edid_blk.spk_alloc_data_blk, + edid_blk.spk_alloc_data_blk_size); + + dev_dbg(component->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n", + __func__, edid_blk.audio_data_blk_size, + edid_blk.spk_alloc_data_blk_size); + } + + return rc; +} + +static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + enum msm_ext_disp_cable_state cable_state; + enum msm_ext_disp_type disp_type; + struct msm_ext_disp_codec_id codec_info; + int rc = 0; + int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l; + int type; + + codec_data = snd_soc_component_get_drvdata(component); + if (!codec_data) { + dev_err_ratelimited(component->dev, "%s: codec_data is NULL\n", + __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__, + codec_data->ctl[dai_id], codec_data->stream[dai_id]); + + mutex_lock(&codec_data->dp_ops_lock); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + + if (!codec_data->ext_disp_ops.get_audio_edid_blk || + !codec_data->ext_disp_ops.get_intf_id || rc) { + dev_err_ratelimited(component->dev, "%s: get_audio_edid_blk() or get_intf_id is NULL\n", + __func__); + rc = -EINVAL; + goto cable_err; + } + + cable_state = codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 1); + if (cable_state < 0) { + dev_err_ratelimited(component->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n", + __func__, cable_state); + rc = cable_state; + goto cable_err; + } + + codec_data->cable_status[dai_id] = cable_state; + if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) { + dev_err_ratelimited(component->dev, "%s: Display cable disconnected\n", + __func__); + ucontrol->value.integer.value[0] = 0; + rc = 0; + goto cable_err; + } + + disp_type = codec_data->ext_disp_ops.get_intf_id( + codec_data->ext_disp_core_pdev); + mutex_unlock(&codec_data->dp_ops_lock); + if (disp_type >= 0) { + switch (disp_type) { + case EXT_DISPLAY_TYPE_DP: + ucontrol->value.integer.value[0] = 2; + rc = 0; + break; + case EXT_DISPLAY_TYPE_HDMI: + ucontrol->value.integer.value[0] = 1; + rc = 0; + break; + default: + rc = -EINVAL; + dev_err_ratelimited(component->dev, "%s: Invalid disp_type:%d\n", + __func__, disp_type); + goto done; + } + dev_dbg(component->dev, "%s: Display type: %d\n", + __func__, disp_type); + } else { + dev_err_ratelimited(component->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n", + __func__, disp_type); + rc = disp_type; + } + return rc; + +cable_err: + mutex_unlock(&codec_data->dp_ops_lock); +done: + return rc; +} + +static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + u32 ack_state = 0; + struct msm_ext_disp_codec_id codec_info; + int rc = 0; + int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l; + int type; + + codec_data = snd_soc_component_get_drvdata(component); + if (!codec_data) { + dev_err_ratelimited(component->dev, + "%s: codec_data is NULL\n", + __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__, + codec_data->ctl[dai_id], codec_data->stream[dai_id]); + + mutex_lock(&codec_data->dp_ops_lock); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + + if (!codec_data->ext_disp_ops.acknowledge || rc) { + dev_err_ratelimited(component->dev, + "%s: codec_data ops acknowledge() is NULL\n", + __func__); + rc = -EINVAL; + goto err; + } + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + ack_state = AUD_EXT_DISP_ACK_DISCONNECT; + break; + case 1: + ack_state = AUD_EXT_DISP_ACK_CONNECT; + break; + case 2: + ack_state = AUD_EXT_DISP_ACK_ENABLE; + break; + default: + rc = -EINVAL; + dev_err_ratelimited(component->dev, + "%s: invalid value %d for mixer ctl\n", + __func__, ucontrol->value.enumerated.item[0]); + goto err; + } + dev_dbg(component->dev, "%s: control %d, ack set value 0x%x\n", + __func__, ucontrol->value.enumerated.item[0], ack_state); + + rc = codec_data->ext_disp_ops.acknowledge( + codec_data->ext_disp_core_pdev, ack_state); + mutex_unlock(&codec_data->dp_ops_lock); + if (rc < 0) { + dev_err_ratelimited(component->dev, "%s: error from acknowledge(), err:%d\n", + __func__, rc); + } + return rc; + +err: + mutex_unlock(&codec_data->dp_ops_lock); + return rc; +} + +static int msm_ext_disp_audio_device_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + int rc = 0; + int dai_id = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (dai_id < 0 || dai_id > DP_DAI2) { + dev_err_ratelimited(component->dev, + "%s: invalid dai id: %d\n", __func__, dai_id); + rc = -EINVAL; + goto done; + } + + codec_data = snd_soc_component_get_drvdata(component); + if (!codec_data) { + dev_err_ratelimited(component->dev, + "%s: codec_data or ops acknowledge() is NULL\n", + __func__); + rc = -EINVAL; + goto done; + } + ucontrol->value.integer.value[0] = codec_data->ctl[dai_id]; + ucontrol->value.integer.value[1] = codec_data->stream[dai_id]; + +done: + return rc; +} + +static int msm_ext_disp_audio_device_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct msm_ext_disp_audio_codec_rx_data *codec_data; + int rc = 0; + int dai_id = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + if (dai_id < 0 || dai_id > DP_DAI2) { + dev_err_ratelimited(component->dev, + "%s: invalid dai id: %d\n", __func__, dai_id); + rc = -EINVAL; + goto done; + } + + codec_data = snd_soc_component_get_drvdata(component); + if (!codec_data) { + dev_err_ratelimited(component->dev, + "%s: codec_data or ops acknowledge() is NULL\n", + __func__); + rc = -EINVAL; + goto done; + } + + if ((ucontrol->value.integer.value[0] > (DP_CONTROLLER_MAX - 1)) || + (ucontrol->value.integer.value[1] > (DP_STREAM_MAX - 1)) || + (ucontrol->value.integer.value[0] < 0) || + (ucontrol->value.integer.value[1] < 0)) { + dev_err_ratelimited(component->dev, + "%s: DP audio control index invalid\n", + __func__); + rc = -EINVAL; + goto done; + } + + mutex_lock(&codec_data->dp_ops_lock); + codec_data->ctl[dai_id] = ucontrol->value.integer.value[0]; + codec_data->stream[dai_id] = ucontrol->value.integer.value[1]; + mutex_unlock(&codec_data->dp_ops_lock); + +done: + return rc; +} + +static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "HDMI EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, + .private_value = HDMI_DAI, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "HDMI MS EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, + .private_value = HDMI_MS_DAI, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Display Port EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, + .private_value = DP_DAI1, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Display Port1 EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, + .private_value = DP_DAI2, + }, + SOC_ENUM_EXT("External Display Type", + ext_disp_audio_type1, + msm_ext_disp_audio_type_get, NULL), + SOC_ENUM_EXT("External Display1 Type", + ext_disp_audio_type2, + msm_ext_disp_audio_type_get, NULL), + SOC_ENUM_EXT("External HDMI Type", + ext_disp_audio_type3, + msm_ext_disp_audio_type_get, NULL), + SOC_ENUM_EXT("External Display Audio Ack", + ext_disp_audio_ack_state1, + NULL, msm_ext_disp_audio_ack_set), + SOC_ENUM_EXT("External Display1 Audio Ack", + ext_disp_audio_ack_state2, + NULL, msm_ext_disp_audio_ack_set), + SOC_ENUM_EXT("External HDMI Audio Ack", + ext_disp_audio_ack_state3, + NULL, msm_ext_disp_audio_ack_set), + + SOC_SINGLE_MULTI_EXT("External Display Audio Device", + SND_SOC_NOPM, DP_DAI1, DP_STREAM_MAX - 1, 0, 2, + msm_ext_disp_audio_device_get, + msm_ext_disp_audio_device_set), + SOC_SINGLE_MULTI_EXT("External Display1 Audio Device", + SND_SOC_NOPM, DP_DAI2, DP_STREAM_MAX - 1, 0, 2, + msm_ext_disp_audio_device_get, + msm_ext_disp_audio_device_set), + SOC_SINGLE_MULTI_EXT("External HDMI Device", + SND_SOC_NOPM, HDMI_MS_DAI, DP_STREAM_MAX - 1, 0, 2, + msm_ext_disp_audio_device_get, + msm_ext_disp_audio_device_set), + +}; + +static int msm_ext_disp_audio_codec_rx_dai_startup( + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = 0, rc = 0; + struct msm_ext_disp_codec_id codec_info; + struct msm_ext_disp_audio_codec_rx_data *codec_data = + dev_get_drvdata(dai->component->dev); + int type; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + if (!codec_data) { + dev_err_ratelimited(dai->dev, "%s() codec_data is null\n", + __func__); + return -EINVAL; + } + + if (!rtd->dai_link->no_pcm) + snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); + + dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n", + __func__, + codec_data->ctl[dai->id], codec_data->stream[dai->id]); + + mutex_lock(&codec_data->dp_ops_lock); + if (dai->id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + + if (!codec_data->ext_disp_ops.cable_status || rc) { + dev_err_ratelimited(dai->dev, "%s() cable_status is null\n", + __func__); + mutex_unlock(&codec_data->dp_ops_lock); + return -EINVAL; + } + + codec_data->cable_status[dai->id] = + codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 1); + mutex_unlock(&codec_data->dp_ops_lock); + if (codec_data->cable_status[dai->id] < 0) { + dev_err_ratelimited(dai->dev, + "%s() ext disp core is not ready (ret val = %d)\n", + __func__, codec_data->cable_status[dai->id]); + ret = codec_data->cable_status[dai->id]; + } else if (!codec_data->cable_status[dai->id]) { + dev_err_ratelimited(dai->dev, + "%s() ext disp cable is not connected (ret val = %d)\n", + __func__, codec_data->cable_status[dai->id]); + ret = -ENODEV; + } + + return ret; +} + +static int msm_ext_disp_audio_codec_rx_dai_hw_params( + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u32 channel_allocation = 0; + u32 level_shift = 0; /* 0dB */ + bool down_mix = 0; + u32 num_channels = params_channels(params); + struct msm_ext_disp_codec_id codec_info; + int rc = 0; + struct msm_ext_disp_audio_setup_params audio_setup_params = {0}; + int type; + struct msm_ext_disp_audio_codec_rx_data *codec_data = + dev_get_drvdata(dai->component->dev); + + if (!codec_data) { + dev_err_ratelimited(dai->dev, "%s() codec_data is null\n", + __func__); + return -EINVAL; + } + + dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n", + __func__, + codec_data->ctl[dai->id], codec_data->stream[dai->id]); + + mutex_lock(&codec_data->dp_ops_lock); + if (dai->id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + + if (!codec_data->ext_disp_ops.audio_info_setup || rc) { + dev_err_ratelimited(dai->dev, "%s: audio_info_setup is null\n", + __func__); + mutex_unlock(&codec_data->dp_ops_lock); + return -EINVAL; + } + mutex_unlock(&codec_data->dp_ops_lock); + + if (codec_data->cable_status[dai->id] < 0) { + dev_err_ratelimited(dai->dev, + "%s() ext disp core is not ready (ret val = %d)\n", + __func__, codec_data->cable_status[dai->id]); + return codec_data->cable_status[dai->id]; + } else if (!codec_data->cable_status[dai->id]) { + dev_err_ratelimited(dai->dev, + "%s() ext disp cable is not connected (ret val = %d)\n", + __func__, codec_data->cable_status[dai->id]); + return -ENODEV; + } + + /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/ + switch (num_channels) { + case 2: + channel_allocation = 0; + break; + case 3: + channel_allocation = 0x02;/*default to FL/FR/FC*/ + audio_setup_params.sample_present = 0x3; + break; + case 4: + channel_allocation = 0x06;/*default to FL/FR/FC/RC*/ + audio_setup_params.sample_present = 0x7; + break; + case 5: + channel_allocation = 0x0A;/*default to FL/FR/FC/RR/RL*/ + audio_setup_params.sample_present = 0x7; + break; + case 6: + channel_allocation = 0x0B; + audio_setup_params.sample_present = 0x7; + break; + case 7: + channel_allocation = 0x12;/*default to FL/FR/FC/RL/RR/RRC/RLC*/ + audio_setup_params.sample_present = 0xf; + break; + case 8: + channel_allocation = 0x13; + audio_setup_params.sample_present = 0xf; + break; + default: + dev_err_ratelimited(dai->dev, "invalid Channels = %u\n", num_channels); + return -EINVAL; + } + + dev_dbg(dai->dev, + "%s() num_ch %u samplerate %u channel_allocation = %u\n", + __func__, num_channels, params_rate(params), + channel_allocation); + + audio_setup_params.sample_rate_hz = params_rate(params); + audio_setup_params.num_of_channels = num_channels; + audio_setup_params.channel_allocation = channel_allocation; + audio_setup_params.level_shift = level_shift; + audio_setup_params.down_mix = down_mix; + + mutex_lock(&codec_data->dp_ops_lock); + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + if (rc) + goto end; + rc = codec_data->ext_disp_ops.audio_info_setup( + codec_data->ext_disp_core_pdev, &audio_setup_params); +end: + mutex_unlock(&codec_data->dp_ops_lock); + if (rc < 0) { + dev_err_ratelimited(dai->dev, + "%s() ext disp core is not ready, rc: %d\n", + __func__, rc); + } + + return rc; +} + +static void msm_ext_disp_audio_codec_rx_dai_shutdown( + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int rc = 0; + struct msm_ext_disp_codec_id codec_info; + + struct msm_ext_disp_audio_codec_rx_data *codec_data = + dev_get_drvdata(dai->component->dev); + int type; + + if (!codec_data) { + dev_err_ratelimited(dai->dev, "%s() codec_data is null\n", + __func__); + return; + } + + dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n", + __func__, + codec_data->ctl[dai->id], codec_data->stream[dai->id]); + + mutex_lock(&codec_data->dp_ops_lock); + if (dai->id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); + rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, + &codec_info); + + if (!codec_data->ext_disp_ops.teardown_done || + !codec_data->ext_disp_ops.cable_status || rc) { + dev_err_ratelimited(dai->dev, "%s: teardown_done or cable_status is null\n", + __func__); + mutex_unlock(&codec_data->dp_ops_lock); + return; + } + + rc = codec_data->ext_disp_ops.cable_status( + codec_data->ext_disp_core_pdev, 0); + if (rc < 0) { + dev_err_ratelimited(dai->dev, + "%s: ext disp core had problems releasing audio flag\n", + __func__); + } + + codec_data->ext_disp_ops.teardown_done( + codec_data->ext_disp_core_pdev); + mutex_unlock(&codec_data->dp_ops_lock); +} + +static int msm_ext_disp_audio_codec_rx_probe( + struct snd_soc_component *component) +{ + struct msm_ext_disp_audio_codec_rx_data *codec_data; + struct device_node *of_node_parent = NULL; + + codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data), + GFP_KERNEL); + + if (!codec_data) { + dev_err(component->dev, "%s(): fail to allocate dai data\n", + __func__); + return -ENOMEM; + } + + of_node_parent = of_get_parent(component->dev->of_node); + if (!of_node_parent) { + dev_err(component->dev, "%s(): Parent device tree node not found\n", + __func__); + kfree(codec_data); + return -ENODEV; + } + + codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent); + if (!codec_data->ext_disp_core_pdev) { + dev_err(component->dev, "%s(): can't get parent pdev\n", + __func__); + kfree(codec_data); + return -ENODEV; + } + + if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev, + &codec_data->ext_disp_ops)) { + dev_err(component->dev, "%s(): can't register with ext disp core", + __func__); + kfree(codec_data); + return -ENODEV; + } + + mutex_init(&codec_data->dp_ops_lock); + dev_set_drvdata(component->dev, codec_data); + + dev_dbg(component->dev, "%s(): registered %s with ext disp core\n", + __func__, component->name); + + return 0; +} + +static void msm_ext_disp_audio_codec_rx_remove( + struct snd_soc_component *component) +{ + struct msm_ext_disp_audio_codec_rx_data *codec_data; + + codec_data = dev_get_drvdata(component->dev); + mutex_destroy(&codec_data->dp_ops_lock); + kfree(codec_data); + + return; +} + +static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = { + .startup = msm_ext_disp_audio_codec_rx_dai_startup, + .hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params, + .shutdown = msm_ext_disp_audio_codec_rx_dai_shutdown +}; + +static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = { + { + .name = "msm_hdmi_audio_codec_rx_dai", + .id = HDMI_DAI, + .playback = { + .stream_name = "HDMI Playback", + .channels_min = 1, + .channels_max = 8, + .rate_min = 48000, + .rate_max = 48000, + .rates = MSM_EXT_DISP_PCM_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, + }, + { + .name = "msm_hdmi_ms_audio_codec_rx_dai", + .id = HDMI_MS_DAI, + .playback = { + .stream_name = "HDMI MS Playback", + .channels_min = 1, + .channels_max = 8, + .rate_min = 48000, + .rate_max = 48000, + .rates = MSM_EXT_DISP_PCM_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, + }, + { + .name = "msm_dp_audio_codec_rx_dai", + .id = DP_DAI1, + .playback = { + .stream_name = "Display Port Playback", + .channels_min = 1, + .channels_max = 8, + .rate_min = 32000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_176400, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE, + }, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, + }, + { + .name = "msm_dp_audio_codec_rx1_dai", + .id = DP_DAI2, + .playback = { + .stream_name = "Display Port1 Playback", + .channels_min = 1, + .channels_max = 8, + .rate_min = 48000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE, + }, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, + }, +}; + +static const struct snd_soc_component_driver msm_ext_disp_codec_rx_driver = { + .name = DRV_NAME, + .probe = msm_ext_disp_audio_codec_rx_probe, + .remove = msm_ext_disp_audio_codec_rx_remove, + .controls = msm_ext_disp_codec_rx_controls, + .num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls), +}; + +static int msm_ext_disp_audio_codec_rx_plat_probe( + struct platform_device *pdev) +{ + dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__, + dev_name(&pdev->dev)); + + return snd_soc_register_component(&pdev->dev, + &msm_ext_disp_codec_rx_driver, + msm_ext_disp_audio_codec_rx_dais, + ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais)); +} + +static int msm_ext_disp_audio_codec_rx_plat_remove( + struct platform_device *pdev) +{ + snd_soc_unregister_component(&pdev->dev); + return 0; +} +static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = { + { .compatible = "qcom,msm-ext-disp-audio-codec-rx", }, + {} +}; +MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match); + +static struct platform_driver msm_ext_disp_audio_codec_rx_driver = { + .driver = { + .name = "msm-ext-disp-audio-codec-rx", + .owner = THIS_MODULE, + .of_match_table = msm_ext_disp_audio_codec_rx_dt_match, + .suppress_bind_attrs = true, + }, + .probe = msm_ext_disp_audio_codec_rx_plat_probe, + .remove = msm_ext_disp_audio_codec_rx_plat_remove, +}; + +static int __init msm_ext_disp_audio_codec_rx_init(void) +{ + int rc = 0; + + rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver); + if (rc) { + pr_err("%s: failed to register ext disp codec driver err:%d\n", + __func__, rc); + } + + return rc; +} +module_init(msm_ext_disp_audio_codec_rx_init); + +static void __exit msm_ext_disp_audio_codec_rx_exit(void) +{ + platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver); +} +module_exit(msm_ext_disp_audio_codec_rx_exit); + +MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/msm_stub.c b/qcom/opensource/audio-kernel/asoc/codecs/msm_stub.c new file mode 100644 index 0000000000..34f9dd8392 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/msm_stub.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2011-2014, 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "msm-stub-codec" + +/* A dummy driver useful only to advertise hardware parameters */ +static struct snd_soc_dai_driver msm_stub_dais[] = { + { + .name = "msm-stub-rx", + .playback = { /* Support maximum range */ + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + }, + { + .name = "msm-stub-tx", + .capture = { /* Support maximum range */ + .stream_name = "Record", + .channels_min = 1, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + }, +}; + +static const struct snd_soc_component_driver soc_msm_stub = { + .name = DRV_NAME, +}; + +static int msm_stub_dev_probe(struct platform_device *pdev) +{ + dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev)); + + return snd_soc_register_component(&pdev->dev, + &soc_msm_stub, msm_stub_dais, ARRAY_SIZE(msm_stub_dais)); +} + +static int msm_stub_dev_remove(struct platform_device *pdev) +{ + snd_soc_unregister_component(&pdev->dev); + return 0; +} +static const struct of_device_id msm_stub_codec_dt_match[] = { + { .compatible = "qcom,msm-stub-codec", }, + {} +}; + +static struct platform_driver msm_stub_driver = { + .driver = { + .name = "msm-stub-codec", + .owner = THIS_MODULE, + .of_match_table = msm_stub_codec_dt_match, + .suppress_bind_attrs = true, + }, + .probe = msm_stub_dev_probe, + .remove = msm_stub_dev_remove, +}; + +static int __init msm_stub_init(void) +{ + return platform_driver_register(&msm_stub_driver); +} +module_init(msm_stub_init); + +static void __exit msm_stub_exit(void) +{ + platform_driver_unregister(&msm_stub_driver); +} +module_exit(msm_stub_exit); + +MODULE_DESCRIPTION("Generic MSM CODEC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/Kbuild new file mode 100644 index 0000000000..b59bcb1194 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/Kbuild @@ -0,0 +1,120 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + + + +ifeq ($(KERNEL_BUILD), 1) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.19 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_BENGAL), y) + include $(AUDIO_ROOT)/config/bengalauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.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) + +############ ROULEUR ############ + +# for ROULEUR Codec +ifdef CONFIG_SND_SOC_ROULEUR + ROULEUR_OBJS += rouleur.o + ROULEUR_OBJS += rouleur-regmap.o + ROULEUR_OBJS += rouleur-tables.o + ROULEUR_OBJS += rouleur-mbhc.o +endif + +ifdef CONFIG_PM2250_SPMI + PM2250_SPMI_OBJS += pm2250_spmi.o +endif + +ifdef CONFIG_SND_SOC_ROULEUR_SLAVE + ROULEUR_SLAVE_OBJS += rouleur_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_ROULEUR) += rouleur_dlkm.o +rouleur_dlkm-y := $(ROULEUR_OBJS) + +obj-$(CONFIG_SND_SOC_ROULEUR_SLAVE) += rouleur_slave_dlkm.o +rouleur_slave_dlkm-y := $(ROULEUR_SLAVE_OBJS) + +obj-$(CONFIG_PM2250_SPMI) += pm2250_spmi_dlkm.o +pm2250_spmi_dlkm-y := $(PM2250_SPMI_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/internal.h b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/internal.h new file mode 100644 index 0000000000..834c16d56e --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/internal.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _ROULEUR_INTERNAL_H +#define _ROULEUR_INTERNAL_H + +#include +#include +#include +#include "rouleur-mbhc.h" + +#define ROULEUR_MAX_MICBIAS 3 + +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1600 + v * 50) +#define MAX_PORT 8 +#define MAX_CH_PER_PORT 8 + +extern struct regmap_config rouleur_regmap_config; + +struct codec_port_info { + u32 slave_port_type; + u32 master_port_type; + u32 ch_mask; + u32 num_ch; + u32 ch_rate; +}; + +struct rouleur_priv { + struct device *dev; + + int variant; + struct snd_soc_component *component; + struct device_node *spmi_np; + struct regmap *regmap; + + struct swr_device *rx_swr_dev; + struct swr_device *tx_swr_dev; + + s32 micb_ref[ROULEUR_MAX_MICBIAS]; + s32 pullup_ref[ROULEUR_MAX_MICBIAS]; + + struct fw_info *fw_data; + + struct mutex micb_lock; + s32 dmic_0_1_clk_cnt; + /* mbhc module */ + struct rouleur_mbhc *mbhc; + + bool comp1_enable; + bool comp2_enable; + bool dapm_bias_off; + + 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); + int (*wakeup)(void *handle, bool enable); + u32 version; + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + struct device *spmi_dev; + int reset_reg; + int mbias_cnt; + struct mutex rx_clk_lock; + struct mutex main_bias_lock; + bool dev_up; + bool usbc_hs_status; + struct notifier_block psy_nb; + struct work_struct soc_eval_work; + bool low_soc; + int foundry_id_reg; + int foundry_id; +}; + +struct rouleur_micbias_setting { + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; +}; + +struct rouleur_pdata { + struct device_node *spmi_np; + struct device_node *rx_slave; + struct device_node *tx_slave; + struct rouleur_micbias_setting micbias; + + struct cdc_regulator *regulator; + int num_supplies; + int reset_reg; + int foundry_id_reg; +}; + +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 { + /* INTR_CTRL_INT_MASK_0 */ + ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET = 0, + ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET, + ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET, + ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + ROULEUR_IRQ_MBHC_SW_DET, + ROULEUR_IRQ_HPHR_OCP_INT, + ROULEUR_IRQ_HPHR_CNP_INT, + ROULEUR_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + ROULEUR_IRQ_HPHL_CNP_INT, + ROULEUR_IRQ_EAR_CNP_INT, + ROULEUR_IRQ_EAR_OCP_INT, + ROULEUR_IRQ_LO_CNP_INT, + ROULEUR_IRQ_LO_OCP_INT, + ROULEUR_IRQ_HPHL_PDM_WD_INT, + ROULEUR_IRQ_HPHR_PDM_WD_INT, + ROULEUR_IRQ_RESERVED_0, + + /* INTR_CTRL_INT_MASK_2 */ + ROULEUR_IRQ_RESERVED_1, + ROULEUR_IRQ_RESERVED_2, + ROULEUR_IRQ_HPHL_SURGE_DET_INT, + ROULEUR_IRQ_HPHR_SURGE_DET_INT, + ROULEUR_NUM_IRQS, +}; + +extern void rouleur_disable_bcs_before_slow_insert( + struct snd_soc_component *component, + bool bcs_disable); +extern struct rouleur_mbhc *rouleur_soc_get_mbhc( + struct snd_soc_component *component); +extern int rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int volt, int micb_num); +extern int rouleur_get_micb_vout_ctl_val(u32 micb_mv); +extern int rouleur_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm); +extern int rouleur_global_mbias_enable(struct snd_soc_component *component); +extern int rouleur_global_mbias_disable(struct snd_soc_component *component); +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/pm2250-spmi.h b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/pm2250-spmi.h new file mode 100644 index 0000000000..2eaf28f02c --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/pm2250-spmi.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _PM2250_SPMI_H +#define _PM2250_SPMI_H + +#ifdef CONFIG_PM2250_SPMI +int pm2250_spmi_write(struct device *dev, int reg, int value); +int pm2250_spmi_read(struct device *dev, int reg, int *value); +#else +int pm2250_spmi_write(struct device *dev, int reg, int value) +{ + return 0; +} +int pm2250_spmi_read(struct device *dev, int reg, int *value); +{ + return 0; +} +#endif /* CONFIG_PM2250_SPMI */ + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/pm2250_spmi.c b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/pm2250_spmi.c new file mode 100644 index 0000000000..10a7d109bb --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/pm2250_spmi.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @regmap: regmap used to access PMIC registers + */ +struct pm2250_spmi { + struct regmap *regmap; +}; + +static const struct of_device_id pm2250_id_table[] = { + { .compatible = "qcom,pm2250-spmi" }, + { }, +}; +MODULE_DEVICE_TABLE(of, pm2250_id_table); + +/** + * pm2250_spmi_write: Function to write to PMIC register + * @device: node for rouleur device + * @reg: PMIC register to write value + * @value: Value to be written to PMIC register + */ +int pm2250_spmi_write(struct device *dev, int reg, int value) +{ + int rc; + struct pm2250_spmi *spmi_dd; + + if (!of_device_is_compatible(dev->of_node, "qcom,pm2250-spmi")) { + pr_err("%s: Device node is invalid\n", __func__); + return -EINVAL; + } + + spmi_dd = dev_get_drvdata(dev); + if (!spmi_dd) + return -EINVAL; + + rc = regmap_write(spmi_dd->regmap, reg, value); + if (rc) + dev_err(dev, "%s: Write to PMIC register failed\n", __func__); + + return rc; +} +EXPORT_SYMBOL(pm2250_spmi_write); + +/** + * pm2250_spmi_read: Function to read PMIC register + * @device: node for rouleur device + * @reg: PMIC register to read value + * @value: Pointer to value of reg to be read + */ +int pm2250_spmi_read(struct device *dev, int reg, int *value) +{ + int rc; + struct pm2250_spmi *spmi_dd; + + if (!of_device_is_compatible(dev->of_node, "qcom,pm2250-spmi")) { + pr_err("%s: Device node is invalid\n", __func__); + return -EINVAL; + } + + spmi_dd = dev_get_drvdata(dev); + if (!spmi_dd) + return -EINVAL; + + rc = regmap_read(spmi_dd->regmap, reg, value); + if (rc) + dev_err(dev, "%s: Read from PMIC register failed\n", __func__); + + return rc; +} +EXPORT_SYMBOL(pm2250_spmi_read); + +static int pm2250_spmi_probe(struct platform_device *pdev) +{ + struct pm2250_spmi *spmi_dd; + const struct of_device_id *match; + + match = of_match_node(pm2250_id_table, pdev->dev.of_node); + if (!match) + return -ENXIO; + + spmi_dd = devm_kzalloc(&pdev->dev, sizeof(*spmi_dd), GFP_KERNEL); + if (spmi_dd == NULL) + return -ENOMEM; + + spmi_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!spmi_dd->regmap) { + dev_err(&pdev->dev, "Parent regmap unavailable.\n"); + return -ENXIO; + } + + platform_set_drvdata(pdev, spmi_dd); + + dev_dbg(&pdev->dev, "Probe success !!\n"); + + return 0; +} + +static int pm2250_spmi_remove(struct platform_device *pdev) +{ + of_platform_depopulate(&pdev->dev); + return 0; +} + +static struct platform_driver pm2250_spmi_driver = { + .probe = pm2250_spmi_probe, + .remove = pm2250_spmi_remove, + .driver = { + .name = "pm2250-spmi", + .of_match_table = pm2250_id_table, + }, +}; +module_platform_driver(pm2250_spmi_driver); + +MODULE_ALIAS("platform:pm2250-spmi"); +MODULE_DESCRIPTION("PMIC SPMI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-mbhc.c b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-mbhc.c new file mode 100644 index 0000000000..7edfe1fbdd --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-mbhc.c @@ -0,0 +1,1163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rouleur-registers.h" +#include +#include +#include "internal.h" + +#define ROULEUR_ZDET_SUPPORTED true +/* Z value defined in milliohm */ +#define ROULEUR_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define ROULEUR_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define ROULEUR_ZDET_NUM_MEASUREMENTS 100 +#define ROULEUR_ZDET_RMAX 1280000 +#define ROULEUR_ZDET_C1 7500000 +#define ROULEUR_ZDET_C2 187 +#define ROULEUR_ZDET_C3 4500 + +/* Cross connection thresholds in mV */ +#define ROULEUR_HPHL_CROSS_CONN_THRESHOLD 350 +#define ROULEUR_HPHR_CROSS_CONN_THRESHOLD 350 + +#define IMPED_NUM_RETRY 5 + +static struct wcd_mbhc_register + wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN", + ROULEUR_ANA_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + ROULEUR_ANA_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + ROULEUR_ANA_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + ROULEUR_ANA_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + ROULEUR_ANA_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + ROULEUR_ANA_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + ROULEUR_ANA_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + ROULEUR_ANA_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + ROULEUR_ANA_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + ROULEUR_ANA_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + ROULEUR_ANA_MBHC_CTL_1, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + ROULEUR_ANA_MBHC_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + ROULEUR_ANA_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE", + ROULEUR_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + ROULEUR_ANA_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + ROULEUR_ANA_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + ROULEUR_ANA_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + SND_SOC_NOPM, 0x00, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + ROULEUR_ANA_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + ROULEUR_ANA_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + ROULEUR_ANA_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + SND_SOC_NOPM, 0x00, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + ROULEUR_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", + SND_SOC_NOPM, 0x00, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + ROULEUR_ANA_MBHC_FSM_STATUS, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + ROULEUR_ANA_MBHC_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + ROULEUR_ANA_MBHC_FSM_STATUS, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + SND_SOC_NOPM, 0x00, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + SND_SOC_NOPM, 0x00, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x02, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN", + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS", + ROULEUR_DIG_SWR_INTR_STATUS_0, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS", + ROULEUR_DIG_SWR_INTR_STATUS_0, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN", + ROULEUR_ANA_MBHC_CTL_1, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", ROULEUR_ANA_MBHC_FSM_STATUS, + 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", ROULEUR_ANA_MBHC_FSM_STATUS, + 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", ROULEUR_ANA_MBHC_ADC_RESULT, + 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", + ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0xF8, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE", + ROULEUR_ANA_MBHC_CTL_1, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE", + ROULEUR_ANA_MBHC_CTL_1, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN", + ROULEUR_ANA_MBHC_ZDET, 0x02, 1, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = ROULEUR_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = ROULEUR_IRQ_HPHL_OCP_INT, + .hph_right_ocp = ROULEUR_IRQ_HPHR_OCP_INT, +}; + +struct rouleur_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; +}; + +static int rouleur_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); + + return wcd_request_irq(&rouleur->irq_info, irq, name, handler, data); +} + +static void rouleur_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); + + if (enable) + wcd_enable_irq(&rouleur->irq_info, irq); + else + wcd_disable_irq(&rouleur->irq_info, irq); +} + +static int rouleur_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); + + wcd_free_irq(&rouleur->irq_info, irq, data); + + return 0; +} + +static void rouleur_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1, + 0x80, 0x00); +} + +static int rouleur_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read32(component, ROULEUR_ANA_MBHC_RESULT_3) & + 0x7; +} + +static void rouleur_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT, + 0x01, 0x00); +} + +static void rouleur_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, + ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1 + i, + 0xFC, vth << 2); + dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n", + __func__, i, btn_high[i], vth); + } +} + +static bool rouleur_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + struct snd_soc_component *component = mbhc->component; + struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); + + rouleur->wakeup((void *)rouleur, lock); + return true; +} + +static int rouleur_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct rouleur_mbhc *rouleur_mbhc; + + rouleur_mbhc = container_of(mbhc, struct rouleur_mbhc, wcd_mbhc); + + if (enable) + return blocking_notifier_chain_register(&rouleur_mbhc->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &rouleur_mbhc->notifier, nblock); +} + +static bool rouleur_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, + ROULEUR_ANA_MICBIAS_MICB_1_2_EN) & 0x04) + >> 2); + if (val == 0x01) + return true; + } + return false; +} + +static bool rouleur_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + return (snd_soc_component_read32(component, ROULEUR_ANA_HPHPA_PA_STATUS) + & 0xFF) ? true : false; +} + +static void rouleur_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 < I_OFF || pull_up_cur > I_3P0_UA || + pull_up_cur == I_DEFAULT) + pull_up_cur = I_3P0_UA; + + dev_dbg(component->dev, "%s: HS pull up current:%d\n", + __func__, pull_up_cur); + + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, + 0xC0, pull_up_cur << 6); +} + +static int rouleur_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + int ret = 0; + + ret = rouleur_micbias_control(component, micb_num, req, false); + + return ret; +} + +static void rouleur_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBHC_MICB2_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBHC_MICB2_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBHC_MICB2_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBHC_MICB2_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *rouleur_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct rouleur_mbhc *rouleur_mbhc; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + rouleur_mbhc = container_of(mbhc, struct rouleur_mbhc, wcd_mbhc); + + if (!component) { + pr_err("%s: NULL component pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(rouleur_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 rouleur_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct rouleur_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 = rouleur_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + + return rc; +} + +static void rouleur_mbhc_get_result_params(struct rouleur_priv *rouleur, + struct snd_soc_component *component, + int32_t *zdet) +{ + int i; + int zcode = 0, zcode1 = 0, zdet_cal_result = 0, zdet_est_range = 0; + int noff = 0, ndac = 14; + int zdet_cal_coeff = 0, div_ratio = 0; + int num = 0, denom = 0; + + /* Charge enable and wait for zcode to be updated */ + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < ROULEUR_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &zcode); + if (zcode & 0x80) + break; + usleep_range(200, 210); + } + + /* If zcode updation is not complete, give additional 10ms */ + if (!(zcode & 0x80)) + usleep_range(10000, 10100); + + regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &zcode); + if (!(zcode & 0x80)) { + dev_dbg(rouleur->dev, + "%s: Impedance detect calculation error, zcode=0x%x\n", + __func__, zcode); + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, + 0x20, 0x00); + return; + } + zcode = zcode << 0x8; + zcode = zcode & 0x3FFF; + regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &zcode1); + zcode |= zcode1; + + dev_dbg(rouleur->dev, + "%s: zcode: %d, zcode1: %d\n", __func__, zcode, zcode1); + + /* Calculate calibration coefficient */ + zdet_cal_result = (snd_soc_component_read32(component, + ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)) & 0x1F; + zdet_cal_coeff = ROULEUR_ZDET_C1 / + ((ROULEUR_ZDET_C2 * zdet_cal_result) + ROULEUR_ZDET_C3); + /* Rload calculation */ + zdet_est_range = (snd_soc_component_read32(component, + ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT) & 0x60) >> 5; + + dev_dbg(rouleur->dev, + "%s: zdet_cal_result: %d, zdet_cal_coeff: %d, zdet_est_range: %d\n", + __func__, zdet_cal_result, zdet_cal_coeff, zdet_est_range); + switch (zdet_est_range) { + case 0: + default: + noff = 0; + div_ratio = 320; + break; + case 1: + noff = 0; + div_ratio = 64; + break; + case 2: + noff = 4; + div_ratio = 64; + break; + case 3: + noff = 5; + div_ratio = 40; + break; + } + + num = zdet_cal_coeff * ROULEUR_ZDET_RMAX; + denom = ((zcode * div_ratio * 100) - (1 << (ndac - noff)) * 1000); + dev_dbg(rouleur->dev, + "%s: num: %d, denom: %d\n", __func__, num, denom); + if (denom > 0) + *zdet = (int32_t) ((num / denom) * 1000); + else + *zdet = ROULEUR_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(rouleur->dev, "%s: z_val=%d(milliOhm)\n", + __func__, *zdet); + /* Start discharge */ + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x00); +} + +static void rouleur_mbhc_zdet_start(struct snd_soc_component *component, + int32_t *zl, int32_t *zr) +{ + struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); + int32_t zdet = 0; + + if (!zl) + goto z_right; + + /* HPHL pull down switch to force OFF */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x30, 0x00); + /* Averaging enable for reliable results */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x80); + /* ZDET left measurement enable */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET, 0x80, 0x80); + /* Calculate the left Rload result */ + rouleur_mbhc_get_result_params(rouleur, component, &zdet); + + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET, 0x80, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x30, 0x20); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* HPHR pull down switch to force OFF */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x0C, 0x00); + /* Averaging enable for reliable results */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x80); + /* ZDET right measurement enable */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET, 0x40, 0x40); + + /* Calculate the right Rload result */ + rouleur_mbhc_get_result_params(rouleur, component, &zdet); + + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET, 0x40, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x0C, 0x08); + + *zr = zdet; +} + +static void rouleur_mbhc_impedance_fn(struct snd_soc_component *component, + int32_t *z1L, int32_t *z1R, + int32_t *zl, int32_t *zr) +{ + int i; + for (i = 0; i < IMPED_NUM_RETRY; i++) { + /* Start of left ch impedance calculation */ + rouleur_mbhc_zdet_start(component, z1L, NULL); + if ((*z1L == ROULEUR_ZDET_FLOATING_IMPEDANCE) || + (*z1L > ROULEUR_ZDET_VAL_100K)) + *zl = ROULEUR_ZDET_FLOATING_IMPEDANCE; + else + *zl = *z1L/1000; + + /* Start of right ch impedance calculation */ + rouleur_mbhc_zdet_start(component, NULL, z1R); + if ((*z1R == ROULEUR_ZDET_FLOATING_IMPEDANCE) || + (*z1R > ROULEUR_ZDET_VAL_100K)) + *zr = ROULEUR_ZDET_FLOATING_IMPEDANCE; + else + *zr = *z1R/1000; + } + + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", + __func__, *zl); + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", + __func__, *zr); +} + +static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); + s16 reg0; + int32_t z1L, z1R, z1Ls; + int zMono, z_diff1, z_diff2; + bool is_fsm_disable = false; + + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + reg0 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_ELECT); + + if (reg0 & 0x80) { + is_fsm_disable = true; + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* Enable electrical bias */ + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT, + 0x01, 0x01); + + /* Enable codec main bias */ + rouleur_global_mbias_enable(component); + + /* Enable RCO clock */ + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1, + 0x80, 0x80); + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_MECH, 0x01, 0x00); + + /* + * Disable surge protection before impedance detection. + * This is done to give correct value for high impedance. + */ + snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN, + 0xC0, 0x00); + /* 1ms delay needed after disable surge protection */ + usleep_range(1000, 1010); + + /* + * Call impedance detection routine multiple times + * in order to avoid wrong impedance values. + */ + rouleur_mbhc_impedance_fn(component, &z1L, &z1R, zl, zr); + + /* Mono/stereo detection */ + if ((*zl == ROULEUR_ZDET_FLOATING_IMPEDANCE) && + (*zr == ROULEUR_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == ROULEUR_ZDET_FLOATING_IMPEDANCE) || + (*zr == ROULEUR_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; + } + + z1Ls = z1L/1000; + /* Parallel of left Z and 20 ohm pull down resistor */ + zMono = ((*zl) * 20) / ((*zl) + 20); + 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: + /* Enable surge protection again after impedance detection */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_SURGE_EN, 0xC0, 0xC0); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_MECH, 0x80, 0x80); + + /* Restore electrical bias state */ + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT, 0x01, + reg0 >> 7); + if (is_fsm_disable) + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ELECT, 0x80, 0x80); + rouleur_global_mbias_disable(component); +} + +static void rouleur_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH, + 0x02, 0x00); + } +} + +static void rouleur_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_CNP_CTL_2, + 0x30, 0x20); + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_CNP_CTL_2, + 0x0C, 0x08); + } else { + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_CNP_CTL_2, + 0x30, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_CNP_CTL_2, + 0x0C, 0x00); + } +} + +static void rouleur_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, ROULEUR_ANA_MBHC_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, ROULEUR_ANA_MBHC_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2, + 0x0C, mbhc->moist_rref << 2); +} + +static void rouleur_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, ROULEUR_ANA_MBHC_CTL_2, + 0x0C, mbhc->moist_rref << 2); + else + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2, + 0x0C, R_OFF << 2); +} + +static bool rouleur_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, ROULEUR_ANA_MBHC_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, ROULEUR_ANA_MBHC_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, ROULEUR_ANA_MBHC_CTL_2) & + 0x0C)) + goto done; + + rouleur_mbhc_moisture_detect_en(mbhc, true); + /* Read moisture comparator status */ + ret = ((snd_soc_component_read32(component, ROULEUR_ANA_MBHC_FSM_STATUS) + & 0x20) ? 0 : 1); + +done: + return ret; + +} + +static void rouleur_mbhc_bcs_enable(struct wcd_mbhc *mbhc, + bool bcs_enable) +{ + if (bcs_enable) + rouleur_disable_bcs_before_slow_insert(mbhc->component, false); + else + rouleur_disable_bcs_before_slow_insert(mbhc->component, true); +} + +static void rouleur_mbhc_get_micbias_val(struct wcd_mbhc *mbhc, int *mb) +{ + u8 vout_ctl = 0; + + /* Read MBHC Micbias (Mic Bias2) voltage */ + WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl); + + /* Formula for getting micbias from vout + * micbias = 1.6V + VOUT_CTL * 50mV + */ + *mb = 1600 + (vout_ctl * 50); + pr_debug("%s: vout_ctl: %d, micbias: %d\n", __func__, vout_ctl, *mb); +} + +static void rouleur_mbhc_comp_autozero_control(struct wcd_mbhc *mbhc, + bool az_enable) +{ + if (az_enable) + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_MBHC_CTL_CLK, 0x08, 0x08); + else + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_MBHC_CTL_CLK, 0x08, 0x00); + +} + +static void rouleur_mbhc_surge_control(struct wcd_mbhc *mbhc, + bool surge_enable) +{ + if (surge_enable) + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_SURGE_EN, 0xC0, 0xC0); + else + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_SURGE_EN, 0xC0, 0x00); + +} + +static void rouleur_mbhc_update_cross_conn_thr(struct wcd_mbhc *mbhc) +{ + mbhc->hphl_cross_conn_thr = ROULEUR_HPHL_CROSS_CONN_THRESHOLD; + mbhc->hphr_cross_conn_thr = ROULEUR_HPHR_CROSS_CONN_THRESHOLD; + + pr_debug("%s: Cross connection threshold for hphl: %d, hphr: %d\n", + __func__, mbhc->hphl_cross_conn_thr, + mbhc->hphr_cross_conn_thr); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = rouleur_mbhc_request_irq, + .irq_control = rouleur_mbhc_irq_control, + .free_irq = rouleur_mbhc_free_irq, + .clk_setup = rouleur_mbhc_clk_setup, + .map_btn_code_to_num = rouleur_mbhc_btn_to_num, + .mbhc_bias = rouleur_mbhc_mbhc_bias_control, + .set_btn_thr = rouleur_mbhc_program_btn_thr, + .lock_sleep = rouleur_mbhc_lock_sleep, + .register_notifier = rouleur_mbhc_register_notifier, + .micbias_enable_status = rouleur_mbhc_micb_en_status, + .hph_pa_on_status = rouleur_mbhc_hph_pa_on_status, + .hph_pull_up_control = rouleur_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = rouleur_mbhc_request_micbias, + .mbhc_micb_ramp_control = rouleur_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = rouleur_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = rouleur_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = rouleur_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = rouleur_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = rouleur_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = rouleur_mbhc_moisture_config, + .mbhc_get_moisture_status = rouleur_mbhc_get_moisture_status, + .mbhc_moisture_detect_en = rouleur_mbhc_moisture_detect_en, + .bcs_enable = rouleur_mbhc_bcs_enable, + .get_micbias_val = rouleur_mbhc_get_micbias_val, + .mbhc_comp_autozero_control = rouleur_mbhc_comp_autozero_control, + .mbhc_surge_ctl = rouleur_mbhc_surge_control, + .update_cross_conn_thr = rouleur_mbhc_update_cross_conn_thr, +}; + +static int rouleur_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rouleur_mbhc *rouleur_mbhc = rouleur_soc_get_mbhc(component); + struct wcd_mbhc *mbhc; + + if (!rouleur_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + mbhc = &rouleur_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 rouleur_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t zl = 0, zr = 0; + bool hphr; + struct soc_multi_mixer_control *mc; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rouleur_mbhc *rouleur_mbhc = rouleur_soc_get_mbhc(component); + + if (!rouleur_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(&rouleur_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, + rouleur_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + rouleur_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + rouleur_hph_impedance_get, NULL), +}; + +/* + * rouleur_mbhc_get_impedance: get impedance of headphone + * left and right channels + * @rouleur_mbhc: handle to struct rouleur_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 rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (!rouleur_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(&rouleur_mbhc->wcd_mbhc, zl, zr); +} +EXPORT_SYMBOL(rouleur_mbhc_get_impedance); + +/* + * rouleur_mbhc_hs_detect: starts mbhc insertion/removal functionality + * @component: 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 rouleur_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct rouleur_priv *rouleur = NULL; + struct rouleur_mbhc *rouleur_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + rouleur = snd_soc_component_get_drvdata(component); + if (!rouleur) { + pr_err("%s: rouleur is NULL\n", __func__); + return -EINVAL; + } + + rouleur_mbhc = rouleur->mbhc; + if (!rouleur_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + return wcd_mbhc_start(&rouleur_mbhc->wcd_mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(rouleur_mbhc_hs_detect); + +/* + * rouleur_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void rouleur_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = NULL; + struct rouleur_mbhc *rouleur_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + rouleur = snd_soc_component_get_drvdata(component); + if (!rouleur) { + pr_err("%s: rouleur is NULL\n", __func__); + return; + } + + rouleur_mbhc = rouleur->mbhc; + if (!rouleur_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return; + } + wcd_mbhc_stop(&rouleur_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL(rouleur_mbhc_hs_detect_exit); + +/* + * rouleur_mbhc_ssr_down: stop mbhc during + * rouleur subsystem restart + * @mbhc: pointer to rouleur_mbhc structure + * @component: handle to snd_soc_component * + */ +void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc, + struct snd_soc_component *component) +{ + struct wcd_mbhc *wcd_mbhc = NULL; + + if (!mbhc || !component) + return; + + wcd_mbhc = &mbhc->wcd_mbhc; + if (wcd_mbhc == NULL) { + dev_err(component->dev, "%s: wcd_mbhc is NULL\n", __func__); + return; + } + + rouleur_mbhc_hs_detect_exit(component); + wcd_mbhc_deinit(wcd_mbhc); +} +EXPORT_SYMBOL(rouleur_mbhc_ssr_down); + +/* + * rouleur_mbhc_post_ssr_init: initialize mbhc for + * rouleur post subsystem restart + * @mbhc: poniter to rouleur_mbhc structure + * @component: handle to snd_soc_component * + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int rouleur_mbhc_post_ssr_init(struct rouleur_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; + } + + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH, + 0x20, 0x20); + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, ROULEUR_ZDET_SUPPORTED); + if (ret) + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + + return ret; +} +EXPORT_SYMBOL(rouleur_mbhc_post_ssr_init); + +/* + * rouleur_mbhc_init: initialize mbhc for rouleur + * @mbhc: poniter to rouleur_mbhc struct pointer to store the configs + * @component: 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 rouleur_mbhc_init(struct rouleur_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + struct rouleur_mbhc *rouleur_mbhc = NULL; + struct wcd_mbhc *wcd_mbhc = NULL; + struct rouleur_pdata *pdata; + int ret = 0; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + rouleur_mbhc = devm_kzalloc(component->dev, sizeof(struct rouleur_mbhc), + GFP_KERNEL); + if (!rouleur_mbhc) + return -ENOMEM; + + rouleur_mbhc->fw_data = fw_data; + BLOCKING_INIT_NOTIFIER_HEAD(&rouleur_mbhc->notifier); + wcd_mbhc = &rouleur_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; + + pdata = dev_get_platdata(component->dev); + if (!pdata) { + dev_err(component->dev, "%s: pdata pointer is NULL\n", + __func__); + ret = -EINVAL; + goto err; + } + wcd_mbhc->micb_mv = pdata->micbias.micb2_mv; + + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, + &intr_ids, wcd_mbhc_registers, + ROULEUR_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto err; + } + + (*mbhc) = rouleur_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, rouleur_mbhc); + return ret; +} +EXPORT_SYMBOL(rouleur_mbhc_init); + +/* + * rouleur_mbhc_deinit: deinitialize mbhc for rouleur + * @component: handle to snd_soc_component * + */ +void rouleur_mbhc_deinit(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur; + struct rouleur_mbhc *rouleur_mbhc; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + rouleur = snd_soc_component_get_drvdata(component); + if (!rouleur) { + pr_err("%s: rouleur is NULL\n", __func__); + return; + } + + rouleur_mbhc = rouleur->mbhc; + if (rouleur_mbhc) { + wcd_mbhc_deinit(&rouleur_mbhc->wcd_mbhc); + devm_kfree(component->dev, rouleur_mbhc); + } +} +EXPORT_SYMBOL(rouleur_mbhc_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-mbhc.h b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-mbhc.h new file mode 100644 index 0000000000..40bef376ac --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-mbhc.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +#ifndef __ROULEUR_MBHC_H__ +#define __ROULEUR_MBHC_H__ +#include + +struct rouleur_mbhc { + struct wcd_mbhc wcd_mbhc; + struct blocking_notifier_head notifier; + struct fw_info *fw_data; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_ROULEUR) +extern int rouleur_mbhc_init(struct rouleur_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data); +extern void rouleur_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern int rouleur_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void rouleur_mbhc_deinit(struct snd_soc_component *component); +extern int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc, + struct snd_soc_component *component); +extern void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc, + struct snd_soc_component *component); +extern int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc, + uint32_t *zl, uint32_t *zr); +#else +static inline int rouleur_mbhc_init(struct rouleur_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + return 0; +} +static inline void rouleur_mbhc_hs_detect_exit( + struct snd_soc_component *component) +{ +} +static inline int rouleur_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void rouleur_mbhc_deinit(struct snd_soc_component *component) +{ +} +static inline int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc, + struct snd_soc_component *component) +{ + return 0; +} +static inline void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc, + struct snd_soc_component *component) +{ +} +static inline int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + +#endif /* __ROULEUR_MBHC_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-registers.h new file mode 100644 index 0000000000..d890a2ba44 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-registers.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _ROULEUR_REGISTERS_H +#define _ROULEUR_REGISTERS_H + +#define ROULEUR_ANA_BASE_ADDR 0x3000 +#define ROULEUR_DIG_BASE_ADDR 0x3400 + +#define ROULEUR_REG(reg) ((reg > ROULEUR_DIG_BASE_ADDR) ? \ + (reg - ROULEUR_DIG_BASE_ADDR) : \ + (reg - ROULEUR_ANA_BASE_ADDR)) + +enum { + REG_NO_ACCESS, + RD_REG, + WR_REG, + RD_WR_REG +}; + +#define ROULEUR_ANA_MICBIAS_MICB_1_2_EN (ROULEUR_ANA_BASE_ADDR+0x040) +#define ROULEUR_ANA_MICBIAS_MICB_3_EN (ROULEUR_ANA_BASE_ADDR+0x041) +#define ROULEUR_ANA_MICBIAS_LDO_1_SETTING (ROULEUR_ANA_BASE_ADDR+0x042) +#define ROULEUR_ANA_MICBIAS_LDO_1_CTRL (ROULEUR_ANA_BASE_ADDR+0x043) +#define ROULEUR_ANA_TX_AMIC1 (ROULEUR_ANA_BASE_ADDR+0x047) +#define ROULEUR_ANA_TX_AMIC2 (ROULEUR_ANA_BASE_ADDR+0x048) +#define ROULEUR_ANA_MBHC_MECH (ROULEUR_ANA_BASE_ADDR+0x05A) +#define ROULEUR_ANA_MBHC_ELECT (ROULEUR_ANA_BASE_ADDR+0x05B) +#define ROULEUR_ANA_MBHC_ZDET (ROULEUR_ANA_BASE_ADDR+0x05C) +#define ROULEUR_ANA_MBHC_RESULT_1 (ROULEUR_ANA_BASE_ADDR+0x05D) +#define ROULEUR_ANA_MBHC_RESULT_2 (ROULEUR_ANA_BASE_ADDR+0x05E) +#define ROULEUR_ANA_MBHC_RESULT_3 (ROULEUR_ANA_BASE_ADDR+0x05F) +#define ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1 (ROULEUR_ANA_BASE_ADDR+0x060) +#define ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2 (ROULEUR_ANA_BASE_ADDR+0x061) +#define ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3 (ROULEUR_ANA_BASE_ADDR+0x062) +#define ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400 (ROULEUR_ANA_BASE_ADDR+0x063) +#define ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400 (ROULEUR_ANA_BASE_ADDR+0x064) +#define ROULEUR_ANA_MBHC_MICB2_RAMP (ROULEUR_ANA_BASE_ADDR+0x065) +#define ROULEUR_ANA_MBHC_CTL_1 (ROULEUR_ANA_BASE_ADDR+0x066) +#define ROULEUR_ANA_MBHC_CTL_2 (ROULEUR_ANA_BASE_ADDR+0x067) +#define ROULEUR_ANA_MBHC_PLUG_DETECT_CTL (ROULEUR_ANA_BASE_ADDR+0x068) +#define ROULEUR_ANA_MBHC_ZDET_ANA_CTL (ROULEUR_ANA_BASE_ADDR+0x069) +#define ROULEUR_ANA_MBHC_ZDET_RAMP_CTL (ROULEUR_ANA_BASE_ADDR+0x06A) +#define ROULEUR_ANA_MBHC_FSM_STATUS (ROULEUR_ANA_BASE_ADDR+0x06B) +#define ROULEUR_ANA_MBHC_ADC_RESULT (ROULEUR_ANA_BASE_ADDR+0x06C) +#define ROULEUR_ANA_MBHC_CTL_CLK (ROULEUR_ANA_BASE_ADDR+0x06D) +#define ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT (ROULEUR_ANA_BASE_ADDR+0x072) +#define ROULEUR_ANA_NCP_EN (ROULEUR_ANA_BASE_ADDR+0x077) +#define ROULEUR_ANA_NCP_VCTRL (ROULEUR_ANA_BASE_ADDR+0x07C) +#define ROULEUR_ANA_HPHPA_CNP_CTL_1 (ROULEUR_ANA_BASE_ADDR+0x083) +#define ROULEUR_ANA_HPHPA_CNP_CTL_2 (ROULEUR_ANA_BASE_ADDR+0x084) +#define ROULEUR_ANA_HPHPA_PA_STATUS (ROULEUR_ANA_BASE_ADDR+0x087) +#define ROULEUR_ANA_HPHPA_FSM_CLK (ROULEUR_ANA_BASE_ADDR+0x088) +#define ROULEUR_ANA_HPHPA_L_GAIN (ROULEUR_ANA_BASE_ADDR+0x08B) +#define ROULEUR_ANA_HPHPA_R_GAIN (ROULEUR_ANA_BASE_ADDR+0x08C) +#define ROULEUR_ANA_HPHPA_SPARE_CTL (ROULEUR_ANA_BASE_ADDR+0x08E) +#define ROULEUR_SWR_HPHPA_HD2 (ROULEUR_ANA_BASE_ADDR+0x090) +#define ROULEUR_ANA_SURGE_EN (ROULEUR_ANA_BASE_ADDR+0x097) +#define ROULEUR_ANA_COMBOPA_CTL (ROULEUR_ANA_BASE_ADDR+0x09B) +#define ROULEUR_ANA_COMBOPA_CTL_4 (ROULEUR_ANA_BASE_ADDR+0x09F) +#define ROULEUR_ANA_COMBOPA_CTL_5 (ROULEUR_ANA_BASE_ADDR+0x0A0) +#define ROULEUR_ANA_RXLDO_CTL (ROULEUR_ANA_BASE_ADDR+0x0B2) +#define ROULEUR_ANA_MBIAS_EN (ROULEUR_ANA_BASE_ADDR+0x0B4) + +#define ROULEUR_DIG_SWR_CHIP_ID0 (ROULEUR_DIG_BASE_ADDR+0x001) +#define ROULEUR_DIG_SWR_CHIP_ID1 (ROULEUR_DIG_BASE_ADDR+0x002) +#define ROULEUR_DIG_SWR_CHIP_ID2 (ROULEUR_DIG_BASE_ADDR+0x003) +#define ROULEUR_DIG_SWR_CHIP_ID3 (ROULEUR_DIG_BASE_ADDR+0x004) +#define ROULEUR_DIG_SWR_SWR_TX_CLK_RATE (ROULEUR_DIG_BASE_ADDR+0x040) +#define ROULEUR_DIG_SWR_CDC_RST_CTL (ROULEUR_DIG_BASE_ADDR+0x041) +#define ROULEUR_DIG_SWR_TOP_CLK_CFG (ROULEUR_DIG_BASE_ADDR+0x042) +#define ROULEUR_DIG_SWR_CDC_RX_CLK_CTL (ROULEUR_DIG_BASE_ADDR+0x043) +#define ROULEUR_DIG_SWR_CDC_TX_CLK_CTL (ROULEUR_DIG_BASE_ADDR+0x044) +#define ROULEUR_DIG_SWR_SWR_RST_EN (ROULEUR_DIG_BASE_ADDR+0x045) +#define ROULEUR_DIG_SWR_CDC_RX_RST (ROULEUR_DIG_BASE_ADDR+0x047) +#define ROULEUR_DIG_SWR_CDC_RX0_CTL (ROULEUR_DIG_BASE_ADDR+0x048) +#define ROULEUR_DIG_SWR_CDC_RX1_CTL (ROULEUR_DIG_BASE_ADDR+0x049) +#define ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1 (ROULEUR_DIG_BASE_ADDR+0x04B) +#define ROULEUR_DIG_SWR_CDC_COMP_CTL_0 (ROULEUR_DIG_BASE_ADDR+0x04F) +#define ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL (ROULEUR_DIG_BASE_ADDR+0x052) +#define ROULEUR_DIG_SWR_CDC_RX_GAIN_0 (ROULEUR_DIG_BASE_ADDR+0x053) +#define ROULEUR_DIG_SWR_CDC_RX_GAIN_1 (ROULEUR_DIG_BASE_ADDR+0x054) +#define ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL (ROULEUR_DIG_BASE_ADDR+0x057) +#define ROULEUR_DIG_SWR_CDC_TX0_CTL (ROULEUR_DIG_BASE_ADDR+0x060) +#define ROULEUR_DIG_SWR_CDC_TX1_CTL (ROULEUR_DIG_BASE_ADDR+0x061) +#define ROULEUR_DIG_SWR_CDC_TX_RST (ROULEUR_DIG_BASE_ADDR+0x063) +#define ROULEUR_DIG_SWR_CDC_REQ0_CTL (ROULEUR_DIG_BASE_ADDR+0x064) +#define ROULEUR_DIG_SWR_CDC_REQ1_CTL (ROULEUR_DIG_BASE_ADDR+0x065) +#define ROULEUR_DIG_SWR_CDC_RST (ROULEUR_DIG_BASE_ADDR+0x067) +#define ROULEUR_DIG_SWR_CDC_AMIC_CTL (ROULEUR_DIG_BASE_ADDR+0x06A) +#define ROULEUR_DIG_SWR_CDC_DMIC_CTL (ROULEUR_DIG_BASE_ADDR+0x06B) +#define ROULEUR_DIG_SWR_CDC_DMIC1_CTL (ROULEUR_DIG_BASE_ADDR+0x06C) +#define ROULEUR_DIG_SWR_CDC_DMIC1_RATE (ROULEUR_DIG_BASE_ADDR+0x06D) +#define ROULEUR_DIG_SWR_PDM_WD_CTL0 (ROULEUR_DIG_BASE_ADDR+0x070) +#define ROULEUR_DIG_SWR_PDM_WD_CTL1 (ROULEUR_DIG_BASE_ADDR+0x071) +#define ROULEUR_DIG_SWR_INTR_MODE (ROULEUR_DIG_BASE_ADDR+0x080) +#define ROULEUR_DIG_SWR_INTR_MASK_0 (ROULEUR_DIG_BASE_ADDR+0x081) +#define ROULEUR_DIG_SWR_INTR_MASK_1 (ROULEUR_DIG_BASE_ADDR+0x082) +#define ROULEUR_DIG_SWR_INTR_MASK_2 (ROULEUR_DIG_BASE_ADDR+0x083) +#define ROULEUR_DIG_SWR_INTR_STATUS_0 (ROULEUR_DIG_BASE_ADDR+0x084) +#define ROULEUR_DIG_SWR_INTR_STATUS_1 (ROULEUR_DIG_BASE_ADDR+0x085) +#define ROULEUR_DIG_SWR_INTR_STATUS_2 (ROULEUR_DIG_BASE_ADDR+0x086) +#define ROULEUR_DIG_SWR_INTR_CLEAR_0 (ROULEUR_DIG_BASE_ADDR+0x087) +#define ROULEUR_DIG_SWR_INTR_CLEAR_1 (ROULEUR_DIG_BASE_ADDR+0x088) +#define ROULEUR_DIG_SWR_INTR_CLEAR_2 (ROULEUR_DIG_BASE_ADDR+0x089) +#define ROULEUR_DIG_SWR_INTR_LEVEL_0 (ROULEUR_DIG_BASE_ADDR+0x08A) +#define ROULEUR_DIG_SWR_INTR_LEVEL_1 (ROULEUR_DIG_BASE_ADDR+0x08B) +#define ROULEUR_DIG_SWR_INTR_LEVEL_2 (ROULEUR_DIG_BASE_ADDR+0x08C) +#define ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL (ROULEUR_DIG_BASE_ADDR+0x093) +#define ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL (ROULEUR_DIG_BASE_ADDR+0x094) +#define ROULEUR_DIG_SWR_LOOP_BACK_MODE (ROULEUR_DIG_BASE_ADDR+0x097) +#define ROULEUR_DIG_SWR_DRIVE_STRENGTH_0 (ROULEUR_DIG_BASE_ADDR+0x0A0) +#define ROULEUR_DIG_SWR_DIG_DEBUG_CTL (ROULEUR_DIG_BASE_ADDR+0x0AB) +#define ROULEUR_DIG_SWR_DIG_DEBUG_EN (ROULEUR_DIG_BASE_ADDR+0x0AC) +#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA0 (ROULEUR_DIG_BASE_ADDR+0x0B0) +#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA1 (ROULEUR_DIG_BASE_ADDR+0x0B1) +#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA2 (ROULEUR_DIG_BASE_ADDR+0x0B2) +#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA3 (ROULEUR_DIG_BASE_ADDR+0x0B3) + +#define ROULEUR_ANALOG_REGISTERS_MAX_SIZE (ROULEUR_ANA_BASE_ADDR+0x0B5) +#define ROULEUR_DIGITAL_REGISTERS_MAX_SIZE (ROULEUR_DIG_BASE_ADDR+0x0B4) +#define ROULEUR_ANALOG_MAX_REGISTER (ROULEUR_ANALOG_REGISTERS_MAX_SIZE - 1) +#define ROULEUR_DIGITAL_MAX_REGISTER (ROULEUR_DIGITAL_REGISTERS_MAX_SIZE - 1) +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-regmap.c new file mode 100644 index 0000000000..51ed46a3b2 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-regmap.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "rouleur-registers.h" + +extern const u8 rouleur_reg_access_analog[ + ROULEUR_REG(ROULEUR_ANALOG_REGISTERS_MAX_SIZE)]; +extern const u8 rouleur_reg_access_digital[ + ROULEUR_REG(ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)]; + +static const struct reg_default rouleur_defaults[] = { + { ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x01 }, + { ROULEUR_ANA_MICBIAS_MICB_3_EN, 0x00 }, + { ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0x21 }, + { ROULEUR_ANA_MICBIAS_LDO_1_CTRL, 0x01 }, + { ROULEUR_ANA_TX_AMIC1, 0x00 }, + { ROULEUR_ANA_TX_AMIC2, 0x00 }, + { ROULEUR_ANA_MBHC_MECH, 0x39 }, + { ROULEUR_ANA_MBHC_ELECT, 0x08 }, + { ROULEUR_ANA_MBHC_ZDET, 0x10 }, + { ROULEUR_ANA_MBHC_RESULT_1, 0x00 }, + { ROULEUR_ANA_MBHC_RESULT_2, 0x00 }, + { ROULEUR_ANA_MBHC_RESULT_3, 0x00 }, + { ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1, 0x00 }, + { ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2, 0x10 }, + { ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3, 0x20 }, + { ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400, 0x30 }, + { ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400, 0x40 }, + { ROULEUR_ANA_MBHC_MICB2_RAMP, 0x00 }, + { ROULEUR_ANA_MBHC_CTL_1, 0x02 }, + { ROULEUR_ANA_MBHC_CTL_2, 0x05 }, + { ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0xE9 }, + { ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x0F }, + { ROULEUR_ANA_MBHC_ZDET_RAMP_CTL, 0x00 }, + { ROULEUR_ANA_MBHC_FSM_STATUS, 0x00 }, + { ROULEUR_ANA_MBHC_ADC_RESULT, 0x00 }, + { ROULEUR_ANA_MBHC_CTL_CLK, 0x30 }, + { ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT, 0x00 }, + { ROULEUR_ANA_NCP_EN, 0x00 }, + { ROULEUR_ANA_NCP_VCTRL, 0xA7 }, + { ROULEUR_ANA_HPHPA_CNP_CTL_1, 0x54 }, + { ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x2B }, + { ROULEUR_ANA_HPHPA_PA_STATUS, 0x00 }, + { ROULEUR_ANA_HPHPA_FSM_CLK, 0x12 }, + { ROULEUR_ANA_HPHPA_L_GAIN, 0x00 }, + { ROULEUR_ANA_HPHPA_R_GAIN, 0x00 }, + { ROULEUR_SWR_HPHPA_HD2, 0x1B }, + { ROULEUR_ANA_HPHPA_SPARE_CTL, 0x02 }, + { ROULEUR_ANA_SURGE_EN, 0x38 }, + { ROULEUR_ANA_COMBOPA_CTL, 0x35 }, + { ROULEUR_ANA_COMBOPA_CTL_4, 0x84 }, + { ROULEUR_ANA_COMBOPA_CTL_5, 0x05 }, + { ROULEUR_ANA_RXLDO_CTL, 0x86 }, + { ROULEUR_ANA_MBIAS_EN, 0x00 }, + { ROULEUR_DIG_SWR_CHIP_ID0, 0x00 }, + { ROULEUR_DIG_SWR_CHIP_ID1, 0x00 }, + { ROULEUR_DIG_SWR_CHIP_ID2, 0x0C }, + { ROULEUR_DIG_SWR_CHIP_ID3, 0x01 }, + { ROULEUR_DIG_SWR_SWR_TX_CLK_RATE, 0x00 }, + { ROULEUR_DIG_SWR_CDC_RST_CTL, 0x03 }, + { ROULEUR_DIG_SWR_TOP_CLK_CFG, 0x00 }, + { ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x00 }, + { ROULEUR_DIG_SWR_CDC_TX_CLK_CTL, 0x33 }, + { ROULEUR_DIG_SWR_SWR_RST_EN, 0x00 }, + { ROULEUR_DIG_SWR_CDC_RX_RST, 0x00 }, + { ROULEUR_DIG_SWR_CDC_RX0_CTL, 0xFC }, + { ROULEUR_DIG_SWR_CDC_RX1_CTL, 0xFC }, + { ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1, 0x00 }, + { ROULEUR_DIG_SWR_CDC_COMP_CTL_0, 0x00 }, + { ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL, 0x66 }, + { ROULEUR_DIG_SWR_CDC_RX_GAIN_0, 0x55 }, + { ROULEUR_DIG_SWR_CDC_RX_GAIN_1, 0xA9 }, + { ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, 0x00 }, + { ROULEUR_DIG_SWR_CDC_TX0_CTL, 0x68 }, + { ROULEUR_DIG_SWR_CDC_TX1_CTL, 0x68 }, + { ROULEUR_DIG_SWR_CDC_TX_RST, 0x00 }, + { ROULEUR_DIG_SWR_CDC_REQ0_CTL, 0x01 }, + { ROULEUR_DIG_SWR_CDC_REQ1_CTL, 0x01 }, + { ROULEUR_DIG_SWR_CDC_RST, 0x00 }, + { ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02 }, + { ROULEUR_DIG_SWR_CDC_DMIC_CTL, 0x00 }, + { ROULEUR_DIG_SWR_CDC_DMIC1_CTL, 0x00 }, + { ROULEUR_DIG_SWR_CDC_DMIC1_RATE, 0x01 }, + { ROULEUR_DIG_SWR_PDM_WD_CTL0, 0x00 }, + { ROULEUR_DIG_SWR_PDM_WD_CTL1, 0x00 }, + { ROULEUR_DIG_SWR_INTR_MODE, 0x00 }, + { ROULEUR_DIG_SWR_INTR_MASK_0, 0xFF }, + { ROULEUR_DIG_SWR_INTR_MASK_1, 0x7F }, + { ROULEUR_DIG_SWR_INTR_MASK_2, 0x0C }, + { ROULEUR_DIG_SWR_INTR_STATUS_0, 0x00 }, + { ROULEUR_DIG_SWR_INTR_STATUS_1, 0x00 }, + { ROULEUR_DIG_SWR_INTR_STATUS_2, 0x00 }, + { ROULEUR_DIG_SWR_INTR_CLEAR_0, 0x00 }, + { ROULEUR_DIG_SWR_INTR_CLEAR_1, 0x00 }, + { ROULEUR_DIG_SWR_INTR_CLEAR_2, 0x00 }, + { ROULEUR_DIG_SWR_INTR_LEVEL_0, 0x00 }, + { ROULEUR_DIG_SWR_INTR_LEVEL_1, 0x2A }, + { ROULEUR_DIG_SWR_INTR_LEVEL_2, 0x00 }, + { ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL, 0x00 }, + { ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL, 0x00 }, + { ROULEUR_DIG_SWR_LOOP_BACK_MODE, 0x00 }, + { ROULEUR_DIG_SWR_DRIVE_STRENGTH_0, 0x00 }, + { ROULEUR_DIG_SWR_DIG_DEBUG_CTL, 0x00 }, + { ROULEUR_DIG_SWR_DIG_DEBUG_EN, 0x00 }, + { ROULEUR_DIG_SWR_DEM_BYPASS_DATA0, 0x55 }, + { ROULEUR_DIG_SWR_DEM_BYPASS_DATA1, 0x55 }, + { ROULEUR_DIG_SWR_DEM_BYPASS_DATA2, 0x55 }, + { ROULEUR_DIG_SWR_DEM_BYPASS_DATA3, 0x01 }, +}; + +static bool rouleur_readable_register(struct device *dev, unsigned int reg) +{ + if (reg > ROULEUR_ANA_BASE_ADDR && reg < + ROULEUR_ANALOG_REGISTERS_MAX_SIZE) + return rouleur_reg_access_analog[ROULEUR_REG(reg)] & RD_REG; + if (reg > ROULEUR_DIG_BASE_ADDR && reg < + ROULEUR_DIGITAL_REGISTERS_MAX_SIZE) + return rouleur_reg_access_digital[ROULEUR_REG(reg)] & RD_REG; + return 0; +} + +static bool rouleur_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg > ROULEUR_ANA_BASE_ADDR && reg < + ROULEUR_ANALOG_REGISTERS_MAX_SIZE) + return rouleur_reg_access_analog[ROULEUR_REG(reg)] & WR_REG; + if (reg > ROULEUR_DIG_BASE_ADDR && reg < + ROULEUR_DIGITAL_REGISTERS_MAX_SIZE) + return rouleur_reg_access_digital[ROULEUR_REG(reg)] & WR_REG; + return 0; +} + +static bool rouleur_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg > ROULEUR_ANA_BASE_ADDR && reg < + ROULEUR_ANALOG_REGISTERS_MAX_SIZE) + if ((rouleur_reg_access_analog[ROULEUR_REG(reg)] & RD_REG) + && !(rouleur_reg_access_analog[ROULEUR_REG(reg)] & WR_REG)) + return true; + if (reg > ROULEUR_DIG_BASE_ADDR && reg < + ROULEUR_DIGITAL_REGISTERS_MAX_SIZE) + if ((rouleur_reg_access_digital[ROULEUR_REG(reg)] & RD_REG) + && !(rouleur_reg_access_digital[ROULEUR_REG(reg)] & WR_REG)) + return true; + return 0; +} + +struct regmap_config rouleur_regmap_config = { + .name = "rouleur_csr", + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rouleur_defaults, + .num_reg_defaults = ARRAY_SIZE(rouleur_defaults), + .max_register = ROULEUR_ANALOG_MAX_REGISTER + + ROULEUR_DIGITAL_MAX_REGISTER, + .readable_reg = rouleur_readable_register, + .writeable_reg = rouleur_writeable_register, + .volatile_reg = rouleur_volatile_register, + .can_multi_write = true, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-tables.c new file mode 100644 index 0000000000..63604566ab --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur-tables.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include "rouleur-registers.h" + +const u8 rouleur_reg_access_analog[ROULEUR_REG( + ROULEUR_ANALOG_REGISTERS_MAX_SIZE)] = { + [ROULEUR_REG(ROULEUR_ANA_MICBIAS_MICB_1_2_EN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MICBIAS_MICB_3_EN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MICBIAS_LDO_1_SETTING)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MICBIAS_LDO_1_CTRL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_TX_AMIC1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_TX_AMIC2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_MECH)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_ELECT)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_1)] = RD_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_2)] = RD_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_3)] = RD_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_MICB2_RAMP)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_PLUG_DETECT_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_ANA_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_RAMP_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_FSM_STATUS)] = RD_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_ADC_RESULT)] = RD_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_CLK)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)] = RD_REG, + [ROULEUR_REG(ROULEUR_ANA_NCP_EN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_NCP_VCTRL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_PA_STATUS)] = RD_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_FSM_CLK)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_L_GAIN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_R_GAIN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_SPARE_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_SWR_HPHPA_HD2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_SURGE_EN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL_4)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL_5)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_RXLDO_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBIAS_EN)] = RD_WR_REG, +}; + +const u8 rouleur_reg_access_digital[ROULEUR_REG( + ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)] = { + [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID0)] = RD_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID1)] = RD_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID2)] = RD_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID3)] = RD_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_SWR_TX_CLK_RATE)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RST_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_TOP_CLK_CFG)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_CLK_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_CLK_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_SWR_RST_EN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_RST)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX0_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX1_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_COMP_CTL_0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX0_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX1_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_RST)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_REQ0_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_REQ1_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RST)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_AMIC_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC1_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC1_RATE)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_PDM_WD_CTL0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_PDM_WD_CTL1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MODE)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_0)] = RD_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_1)] = RD_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_2)] = RD_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_LOOP_BACK_MODE)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_DRIVE_STRENGTH_0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_DIG_DEBUG_CTL)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_DIG_DEBUG_EN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA0)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA1)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA2)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA3)] = RD_WR_REG, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur.c b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur.c new file mode 100644 index 0000000000..b8473bc104 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur.c @@ -0,0 +1,2819 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" +#include "rouleur.h" +#include +#include "rouleur-registers.h" +#include "pm2250-spmi.h" +#include +#include +#include +#include +#include "asoc/bolero-slave-internal.h" + +#define DRV_NAME "rouleur_codec" + +#define NUM_SWRS_DT_PARAMS 5 + +#define ROULEUR_VERSION_1_0 1 +#define ROULEUR_VERSION_ENTRY_SIZE 32 + +#define NUM_ATTEMPTS 5 +#define SOC_THRESHOLD_LEVEL 25 +#define LOW_SOC_MBIAS_REG_MIN_VOLTAGE 2850000 + +#define FOUNDRY_ID_SEC 0x5 + +enum { + CODEC_TX = 0, + CODEC_RX, +}; + +enum { + ALLOW_VPOS_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, +}; + +/* TODO: Check on the step values */ +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +static int rouleur_handle_post_irq(void *data); +static int rouleur_reset(struct device *dev, int val); + +static const struct regmap_irq ROULEUR_IRQs[ROULEUR_NUM_IRQS] = { + REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(ROULEUR_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(ROULEUR_IRQ_EAR_OCP_INT, 1, 0x04), + REGMAP_IRQ_REG(ROULEUR_IRQ_LO_CNP_INT, 1, 0x08), + REGMAP_IRQ_REG(ROULEUR_IRQ_LO_OCP_INT, 1, 0x10), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), +}; + +static struct regmap_irq_chip rouleur_regmap_irq_chip = { + .name = "rouleur", + .irqs = ROULEUR_IRQs, + .num_irqs = ARRAY_SIZE(ROULEUR_IRQs), + .num_regs = 3, + .status_base = ROULEUR_DIG_SWR_INTR_STATUS_0, + .mask_base = ROULEUR_DIG_SWR_INTR_MASK_0, + .ack_base = ROULEUR_DIG_SWR_INTR_CLEAR_0, + .use_ack = 1, + .type_base = ROULEUR_DIG_SWR_INTR_LEVEL_0, + .runtime_pm = false, + .handle_post_irq = rouleur_handle_post_irq, + .irq_drv_data = NULL, +}; + +static int rouleur_handle_post_irq(void *data) +{ + struct rouleur_priv *rouleur = data; + u32 status1 = 0, status2 = 0, status3 = 0; + + regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_0, &status1); + regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_1, &status2); + regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_2, &status3); + + rouleur->tx_swr_dev->slave_irq_pending = + ((status1 || status2 || status3) ? true : false); + + return IRQ_HANDLED; +} + +static int rouleur_init_reg(struct snd_soc_component *component) +{ + /* Disable HPH OCP */ + snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_CNP_CTL_2, + 0x03, 0x00); + /* Enable surge protection */ + snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN, + 0xC0, 0xC0); + /* Disable mic bias pull down */ + snd_soc_component_update_bits(component, ROULEUR_ANA_MICBIAS_MICB_1_2_EN, + 0x01, 0x00); + return 0; +} + +static int rouleur_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 = 0; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL; + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + switch (path) { + case CODEC_RX: + map = &rouleur->rx_port_mapping; + num_ports = rouleur->num_rx_ports; + break; + case CODEC_TX: + map = &rouleur->tx_port_mapping; + num_ports = rouleur->num_tx_ports; + break; + default: + dev_err(component->dev, "%s Invalid path: %d\n", + __func__, path); + return -EINVAL; + } + + for (i = 0; i <= num_ports; i++) { + for (j = 0; j < MAX_CH_PER_PORT; j++) { + if ((*map)[i][j].slave_port_type == slv_prt_type) + goto found; + } + } + + dev_err(component->dev, "%s Failed to find slave port for type %u\n", + __func__, slv_prt_type); + return -EINVAL; +found: + *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 rouleur_parse_port_mapping(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, map_length; + u32 port_num = 0, 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 = NULL; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL; + struct rouleur_priv *rouleur = dev_get_drvdata(dev); + + switch (path) { + case CODEC_RX: + map = &rouleur->rx_port_mapping; + num_ports = &rouleur->num_rx_ports; + break; + case CODEC_TX: + map = &rouleur->tx_port_mapping; + num_ports = &rouleur->num_tx_ports; + break; + default: + dev_err(dev, "%s Invalid path: %d\n", + __func__, path); + return -EINVAL; + } + + if (!of_find_property(dev->of_node, prop, + &map_size)) { + dev_err(dev, "missing port mapping prop %s\n", prop); + ret = -EINVAL; + goto err; + } + + map_length = map_size / (NUM_SWRS_DT_PARAMS * sizeof(u32)); + + dt_array = kzalloc(map_size, GFP_KERNEL); + + if (!dt_array) { + ret = -ENOMEM; + goto err; + } + 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); + ret = -EINVAL; + goto err_pdata_fail; + } + + for (i = 0; i < map_length; i++) { + port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; + ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; + ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; + master_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 4]; + + if (port_num != old_port_num) + ch_iter = 0; + + (*map)[port_num][ch_iter].slave_port_type = slave_port_type; + (*map)[port_num][ch_iter].ch_mask = ch_mask; + (*map)[port_num][ch_iter].master_port_type = master_port_type; + (*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask); + (*map)[port_num][ch_iter++].ch_rate = ch_rate; + old_port_num = port_num; + } + *num_ports = port_num; + +err_pdata_fail: + kfree(dt_array); +err: + return ret; +} + +static int rouleur_tx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + u8 port_id; + u8 num_ch; + u8 ch_mask; + u32 ch_rate; + u8 port_type; + u8 num_port = 1; + int ret = 0; + + ret = rouleur_set_port_params(component, slv_port_type, &port_id, + &num_ch, &ch_mask, &ch_rate, + &port_type, CODEC_TX); + + if (ret) { + dev_err(rouleur->dev, "%s:Failed to set port params: %d\n", + __func__, ret); + return ret; + } + + if (enable) + ret = swr_connect_port(rouleur->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + else + ret = swr_disconnect_port(rouleur->tx_swr_dev, &port_id, + num_port, &ch_mask, &port_type); + return ret; + +} +static int rouleur_rx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + u8 port_id; + u8 num_ch; + u8 ch_mask; + u32 ch_rate; + u8 port_type; + u8 num_port = 1; + int ret = 0; + + ret = rouleur_set_port_params(component, slv_port_type, &port_id, + &num_ch, &ch_mask, &ch_rate, + &port_type, CODEC_RX); + + if (ret) { + dev_err(rouleur->dev, "%s:Failed to set port params: %d\n", + __func__, ret); + return ret; + } + + if (enable) + ret = swr_connect_port(rouleur->rx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + else + ret = swr_disconnect_port(rouleur->rx_swr_dev, &port_id, + num_port, &ch_mask, &port_type); + return ret; +} + +int rouleur_global_mbias_enable(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + mutex_lock(&rouleur->main_bias_lock); + if (rouleur->mbias_cnt == 0) { + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBIAS_EN, 0x20, 0x20); + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBIAS_EN, 0x10, 0x10); + usleep_range(1000, 1100); + } + rouleur->mbias_cnt++; + mutex_unlock(&rouleur->main_bias_lock); + + return 0; +} + +int rouleur_global_mbias_disable(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + mutex_lock(&rouleur->main_bias_lock); + if (rouleur->mbias_cnt == 0) { + dev_dbg(rouleur->dev, "%s:mbias already disabled\n", __func__); + mutex_unlock(&rouleur->main_bias_lock); + return 0; + } + rouleur->mbias_cnt--; + if (rouleur->mbias_cnt == 0) { + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBIAS_EN, 0x10, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_MBIAS_EN, 0x20, 0x00); + } + mutex_unlock(&rouleur->main_bias_lock); + + return 0; +} + +static int rouleur_rx_clk_enable(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + mutex_lock(&rouleur->rx_clk_lock); + if (rouleur->rx_clk_cnt == 0) { + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x10); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x20); + usleep_range(5000, 5100); + rouleur_global_mbias_enable(component); + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_FSM_CLK, 0x7F, 0x11); + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x80); + snd_soc_component_update_bits(component, + ROULEUR_ANA_NCP_VCTRL, 0x07, 0x06); + snd_soc_component_update_bits(component, + ROULEUR_ANA_NCP_EN, 0x01, 0x01); + usleep_range(500, 510); + } + rouleur->rx_clk_cnt++; + mutex_unlock(&rouleur->rx_clk_lock); + + return 0; +} + +static int rouleur_rx_clk_disable(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + mutex_lock(&rouleur->rx_clk_lock); + if (rouleur->rx_clk_cnt == 0) { + dev_dbg(rouleur->dev, "%s:clk already disabled\n", __func__); + mutex_unlock(&rouleur->rx_clk_lock); + return 0; + } + rouleur->rx_clk_cnt--; + if (rouleur->rx_clk_cnt == 0) { + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_FSM_CLK, 0x7F, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_NCP_EN, 0x01, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x00); + rouleur_global_mbias_disable(component); + + } + mutex_unlock(&rouleur->rx_clk_lock); + return 0; +} + +/* + * rouleur_soc_get_mbhc: get rouleur_mbhc handle of corresponding component + * @component: handle to snd_soc_component * + * + * return rouleur_mbhc handle or error code in case of failure + */ +struct rouleur_mbhc *rouleur_soc_get_mbhc(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur; + + if (!component) { + pr_err("%s: Invalid params, NULL component\n", __func__); + return NULL; + } + rouleur = snd_soc_component_get_drvdata(component); + + if (!rouleur) { + pr_err("%s: Invalid params, NULL tavil\n", __func__); + return NULL; + } + + return rouleur->mbhc; +} +EXPORT_SYMBOL(rouleur_soc_get_mbhc); + +static int rouleur_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 rouleur_priv *rouleur = 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: + rouleur_rx_clk_enable(component); + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_CNP_CTL_1, + 0x02, 0x02); + snd_soc_component_update_bits(component, + ROULEUR_SWR_HPHPA_HD2, + 0x38, 0x38); + set_bit(HPH_COMP_DELAY, &rouleur->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if (rouleur->comp1_enable) { + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x02, 0x02); + + if (rouleur->comp2_enable) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x01, 0x01); + /* + * 5ms sleep is required after COMP is enabled as per + * HW requirement + */ + if (test_bit(HPH_COMP_DELAY, &rouleur->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_COMP_DELAY, + &rouleur->status_mask); + } + } else { + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x02, 0x00); + } + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX0_CTL, + 0x80, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x04, 0x04); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x01, 0x01); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x04, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX0_CTL, + 0x80, 0x80); + if (rouleur->comp1_enable) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x02, 0x00); + break; + } + + return 0; +} + +static int rouleur_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 rouleur_priv *rouleur = 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: + rouleur_rx_clk_enable(component); + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_CNP_CTL_1, + 0x02, 0x02); + snd_soc_component_update_bits(component, + ROULEUR_SWR_HPHPA_HD2, + 0x07, 0x07); + set_bit(HPH_COMP_DELAY, &rouleur->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if (rouleur->comp2_enable) { + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x01, 0x01); + + if (rouleur->comp1_enable) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x02, 0x02); + /* + * 5ms sleep is required after COMP is enabled as per + * HW requirement + */ + if (test_bit(HPH_COMP_DELAY, &rouleur->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_COMP_DELAY, + &rouleur->status_mask); + } + } else { + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x01, 0x00); + } + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX1_CTL, + 0x80, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x08, 0x08); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x02); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x08, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX1_CTL, + 0x80, 0x80); + if (rouleur->comp2_enable) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x01, 0x00); + break; + + } + + return 0; +} + +static int rouleur_codec_ear_lo_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); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + rouleur_rx_clk_enable(component); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX0_CTL, + 0x80, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, + 0x01, 0x01); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x04, 0x04); + + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x04, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX0_CTL, + 0x80, 0x80); + + break; + }; + return 0; + +} + +static int rouleur_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 rouleur_priv *rouleur = 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: + ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, + rouleur->rx_swr_dev->dev_num, + true); + + set_bit(HPH_PA_DELAY, &rouleur->status_mask); + usleep_range(200, 210); + /* Enable HD2 Config for HPHR if foundry id is SEC */ + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_HPHR_HD2_ENABLE, + 0x04); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL1, + 0x03, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 5ms sleep is required after PA is enabled as per + * HW requirement. + */ + if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_PA_DELAY, &rouleur->status_mask); + } + + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10)); + wcd_enable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHR_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHR_PDM_WD_INT); + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + blocking_notifier_call_chain(&rouleur->mbhc->notifier, + WCD_EVENT_PRE_HPHR_PA_OFF, + &rouleur->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &rouleur->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA is disabled as per + * HW requirement. + */ + if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) { + + usleep_range(5000, 5100); + clear_bit(HPH_PA_DELAY, &rouleur->status_mask); + } + + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_HPHR_HD2_ENABLE, + 0x00); + blocking_notifier_call_chain(&rouleur->mbhc->notifier, + WCD_EVENT_POST_HPHR_PA_OFF, + &rouleur->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL1, + 0x03, 0x00); + break; + }; + return ret; +} + +static int rouleur_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 rouleur_priv *rouleur = 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: + ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, + rouleur->rx_swr_dev->dev_num, + true); + set_bit(HPH_PA_DELAY, &rouleur->status_mask); + usleep_range(200, 210); + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x04); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 5ms sleep is required after PA is enabled as per + * HW requirement. + */ + if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_PA_DELAY, &rouleur->status_mask); + } + + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + blocking_notifier_call_chain(&rouleur->mbhc->notifier, + WCD_EVENT_PRE_HPHL_PA_OFF, + &rouleur->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &rouleur->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA is disabled as per + * HW requirement. + */ + if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_PA_DELAY, &rouleur->status_mask); + } + + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x00); + blocking_notifier_call_chain(&rouleur->mbhc->notifier, + WCD_EVENT_POST_HPHL_PA_OFF, + &rouleur->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x00); + + break; + }; + return ret; +} + +static int rouleur_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 rouleur_priv *rouleur = 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: + ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, + rouleur->rx_swr_dev->dev_num, + true); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_5, + 0x04, 0x00); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x0F); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x40, 0x00); + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x04); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x04); + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + break; + case SND_SOC_DAPM_POST_PMD: + usleep_range(5000, 5100); + if (rouleur->foundry_id == FOUNDRY_ID_SEC) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_HPHL_HD2_ENABLE, + 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x00); + }; + return ret; +} + +static int rouleur_codec_enable_lo_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 rouleur_priv *rouleur = 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: + ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, + rouleur->rx_swr_dev->dev_num, + true); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_5, + 0x04, 0x00); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x0F); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x40, 0x40); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL_4, + 0x0F, 0x04); + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&rouleur->irq_info, + ROULEUR_IRQ_HPHL_PDM_WD_INT); + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x40, 0x00); + usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x00); + }; + return ret; +} + +static int rouleur_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 rouleur_priv *rouleur = 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: + rouleur_rx_connect_port(component, HPH_L, true); + if (rouleur->comp1_enable) + rouleur_rx_connect_port(component, COMP_L, true); + break; + case SND_SOC_DAPM_POST_PMD: + rouleur_rx_connect_port(component, HPH_L, false); + if (rouleur->comp1_enable) + rouleur_rx_connect_port(component, COMP_L, false); + rouleur_rx_clk_disable(component); + break; + }; + return 0; +} + +static int rouleur_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 rouleur_priv *rouleur = 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: + rouleur_rx_connect_port(component, HPH_R, true); + if (rouleur->comp2_enable) + rouleur_rx_connect_port(component, COMP_R, true); + break; + case SND_SOC_DAPM_POST_PMD: + rouleur_rx_connect_port(component, HPH_R, false); + if (rouleur->comp2_enable) + rouleur_rx_connect_port(component, COMP_R, false); + rouleur_rx_clk_disable(component); + break; + }; + + return 0; +} + +static int rouleur_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 rouleur_priv *rouleur = 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, "01"); + + 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 = &(rouleur->dmic_0_1_clk_cnt); + dmic_clk_reg = ROULEUR_DIG_SWR_CDC_DMIC1_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, + ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02, 0x00); + snd_soc_component_update_bits(component, + dmic_clk_reg, 0x08, 0x08); + rouleur_tx_connect_port(component, DMIC0 + (w->shift), true); + break; + case SND_SOC_DAPM_POST_PMD: + rouleur_tx_connect_port(component, DMIC0 + (w->shift), false); + snd_soc_component_update_bits(component, + dmic_clk_reg, 0x08, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02, 0x02); + break; + + }; + return 0; +} + +static int rouleur_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 rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = swr_slvdev_datapath_control(rouleur->tx_swr_dev, + rouleur->tx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = swr_slvdev_datapath_control(rouleur->tx_swr_dev, + rouleur->tx_swr_dev->dev_num, + false); + break; + }; + + return ret; +} + +static int rouleur_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); + struct rouleur_priv *rouleur = + 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: + /* Enable BCS for Headset mic */ + if (w->shift == 1 && !(snd_soc_component_read32(component, + ROULEUR_ANA_TX_AMIC2) & 0x10)) { + rouleur_tx_connect_port(component, MBHC, true); + set_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask); + } + rouleur_tx_connect_port(component, ADC1 + (w->shift), true); + rouleur_global_mbias_enable(component); + if (w->shift) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1, + 0x30, 0x30); + else + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1, + 0x03, 0x03); + break; + case SND_SOC_DAPM_POST_PMD: + rouleur_tx_connect_port(component, ADC1 + (w->shift), false); + if (w->shift == 1 && + test_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask)) { + rouleur_tx_connect_port(component, MBHC, false); + clear_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask); + } + if (w->shift) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1, + 0x30, 0x00); + else + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1, + 0x03, 0x00); + rouleur_global_mbias_disable(component); + break; + }; + + return 0; +} + +/* + * rouleur_get_micb_vout_ctl_val: converts micbias from volts to register value + * @micb_mv: micbias in mv + * + * return register value converted + */ +int rouleur_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1.6V and maximum is 2.85V */ + if (micb_mv < 1600 || micb_mv > 2850) { + pr_err("%s: unsupported micbias voltage\n", __func__); + return -EINVAL; + } + + return (micb_mv - 1600) / 50; +} +EXPORT_SYMBOL(rouleur_get_micb_vout_ctl_val); + +/* + * rouleur_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 rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct rouleur_priv *rouleur = + snd_soc_component_get_drvdata(component); + int cur_vout_ctl, req_vout_ctl; + int micb_reg, micb_val, micb_en; + int ret = 0; + int pullup_mask; + + micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN; + switch (micb_num) { + case MIC_BIAS_1: + micb_val = snd_soc_component_read32(component, micb_reg); + micb_en = (micb_val & 0x40) >> 6; + pullup_mask = 0x20; + break; + case MIC_BIAS_2: + micb_val = snd_soc_component_read32(component, micb_reg); + micb_en = (micb_val & 0x04) >> 2; + pullup_mask = 0x02; + break; + case MIC_BIAS_3: + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + mutex_lock(&rouleur->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. + */ + cur_vout_ctl = (snd_soc_component_read32(component, + ROULEUR_ANA_MICBIAS_LDO_1_SETTING)) & 0xF8; + cur_vout_ctl = cur_vout_ctl >> 3; + req_vout_ctl = rouleur_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, pullup_mask, + pullup_mask); + + snd_soc_component_update_bits(component, + ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0xF8, req_vout_ctl << 3); + + if (micb_en == 0x1) { + snd_soc_component_update_bits(component, micb_reg, + pullup_mask, 0x00); + /* + * Add 2ms delay as per HW requirement after enabling + * micbias + */ + usleep_range(2000, 2100); + } +exit: + mutex_unlock(&rouleur->micb_lock); + return ret; +} +EXPORT_SYMBOL(rouleur_mbhc_micb_adjust_voltage); + +int rouleur_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + + struct rouleur_priv *rouleur = 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; + u8 pullup_mask = 0, enable_mask = 0; + int ret = 0; + + if ((micb_index < 0) || (micb_index > ROULEUR_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 = ROULEUR_ANA_MICBIAS_MICB_1_2_EN; + pullup_mask = 0x20; + enable_mask = 0x40; + break; + case MIC_BIAS_2: + micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN; + pullup_mask = 0x02; + enable_mask = 0x04; + 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 = ROULEUR_ANA_MICBIAS_MICB_3_EN; + pullup_mask = 0x02; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + }; + mutex_lock(&rouleur->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + rouleur->pullup_ref[micb_index]++; + if ((rouleur->pullup_ref[micb_index] == 1) && + (rouleur->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + pullup_mask, pullup_mask); + break; + case MICB_PULLUP_DISABLE: + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + if (rouleur->pullup_ref[micb_index] > 0) + rouleur->pullup_ref[micb_index]--; + if ((rouleur->pullup_ref[micb_index] == 0) && + (rouleur->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + pullup_mask, 0x00); + break; + case MICB_ENABLE: + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + rouleur->micb_ref[micb_index]++; + if (rouleur->micb_ref[micb_index] == 1) { + rouleur_global_mbias_enable(component); + snd_soc_component_update_bits(component, + micb_reg, enable_mask, enable_mask); + if (post_on_event) + blocking_notifier_call_chain( + &rouleur->mbhc->notifier, post_on_event, + &rouleur->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_on && rouleur->mbhc) + blocking_notifier_call_chain( + &rouleur->mbhc->notifier, post_dapm_on, + &rouleur->mbhc->wcd_mbhc); + break; + case MICB_DISABLE: + if (rouleur->micb_ref[micb_index] > 0) + rouleur->micb_ref[micb_index]--; + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + if ((rouleur->micb_ref[micb_index] == 0) && + (rouleur->pullup_ref[micb_index] > 0)) { + snd_soc_component_update_bits(component, micb_reg, + pullup_mask, pullup_mask); + snd_soc_component_update_bits(component, micb_reg, + enable_mask, 0x00); + rouleur_global_mbias_disable(component); + } else if ((rouleur->micb_ref[micb_index] == 0) && + (rouleur->pullup_ref[micb_index] == 0)) { + if (pre_off_event && rouleur->mbhc) + blocking_notifier_call_chain( + &rouleur->mbhc->notifier, pre_off_event, + &rouleur->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, micb_reg, + enable_mask, 0x00); + rouleur_global_mbias_disable(component); + if (post_off_event && rouleur->mbhc) + blocking_notifier_call_chain( + &rouleur->mbhc->notifier, + post_off_event, + &rouleur->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_off && rouleur->mbhc) + blocking_notifier_call_chain( + &rouleur->mbhc->notifier, post_dapm_off, + &rouleur->mbhc->wcd_mbhc); + break; + }; + + dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, rouleur->micb_ref[micb_index], + rouleur->pullup_ref[micb_index]); +done: + mutex_unlock(&rouleur->micb_lock); + return 0; +} +EXPORT_SYMBOL(rouleur_micbias_control); + +void rouleur_disable_bcs_before_slow_insert(struct snd_soc_component *component, + bool bcs_disable) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + if (rouleur->update_wcd_event) { + if (bcs_disable) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 0); + else + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 1); + } +} + +static int rouleur_get_logical_addr(struct swr_device *swr_dev) +{ + int ret = 0; + uint8_t devnum = 0; + int num_retry = NUM_ATTEMPTS; + + do { + 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); + /* retry after 1ms */ + usleep_range(1000, 1010); + } + } while (ret && --num_retry); + swr_dev->dev_num = devnum; + return 0; +} + +static bool get_usbc_hs_status(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + if (mbhc_cfg->enable_usbc_analog) { + if (!(snd_soc_component_read32(component, ROULEUR_ANA_MBHC_MECH) + & 0x20)) + return true; + } + return false; +} + +static int rouleur_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + int ret = 0; + struct rouleur_priv *rouleur = dev_get_drvdata((struct device *)data); + struct snd_soc_component *component = rouleur->component; + struct wcd_mbhc *mbhc; + + switch (event) { + case BOLERO_SLV_EVT_PA_OFF_PRE_SSR: + snd_soc_component_update_bits(component, + ROULEUR_ANA_HPHPA_CNP_CTL_2, + 0xC0, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x40, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x80, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x40, 0x40); + snd_soc_component_update_bits(component, + ROULEUR_ANA_COMBOPA_CTL, + 0x80, 0x00); + break; + case BOLERO_SLV_EVT_SSR_DOWN: + rouleur->dev_up = false; + rouleur->mbhc->wcd_mbhc.deinit_in_progress = true; + mbhc = &rouleur->mbhc->wcd_mbhc; + rouleur->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); + rouleur_mbhc_ssr_down(rouleur->mbhc, component); + rouleur_reset(rouleur->dev, 0x01); + break; + case BOLERO_SLV_EVT_SSR_UP: + rouleur_reset(rouleur->dev, 0x00); + /* allow reset to take effect */ + usleep_range(10000, 10010); + rouleur_get_logical_addr(rouleur->tx_swr_dev); + rouleur_get_logical_addr(rouleur->rx_swr_dev); + + rouleur_init_reg(component); + regcache_mark_dirty(rouleur->regmap); + regcache_sync(rouleur->regmap); + rouleur->dev_up = true; + /* Initialize MBHC module */ + mbhc = &rouleur->mbhc->wcd_mbhc; + ret = rouleur_mbhc_post_ssr_init(rouleur->mbhc, component); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + } else { + rouleur_mbhc_hs_detect(component, mbhc->mbhc_cfg); + if (rouleur->usbc_hs_status) + mdelay(500); + } + rouleur->mbhc->wcd_mbhc.deinit_in_progress = false; + break; + default: + dev_err(component->dev, "%s: invalid event %d\n", __func__, + event); + break; + } + return 0; +} + +static int __rouleur_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 + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Micbias LD0 enable not supported for MicBias 3*/ + if (micb_num == MIC_BIAS_3) + rouleur_micbias_control(component, micb_num, + MICB_PULLUP_ENABLE, true); + else + rouleur_micbias_control(component, micb_num, + MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + if (micb_num == MIC_BIAS_3) + rouleur_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + else + rouleur_micbias_control(component, micb_num, + MICB_DISABLE, true); + break; + }; + + return 0; + +} + +static int rouleur_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __rouleur_codec_enable_micbias(w, event); +} + +static int __rouleur_codec_enable_micbias_pullup(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, "VA MIC BIAS1", sizeof("VA MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + rouleur_micbias_control(component, micb_num, + MICB_PULLUP_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: + rouleur_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + break; + }; + + return 0; + +} + +static int rouleur_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __rouleur_codec_enable_micbias_pullup(w, event); +} + +static int rouleur_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rouleur_priv *rouleur = 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 ? rouleur->comp2_enable : + rouleur->comp1_enable; + return 0; +} + +static int rouleur_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rouleur_priv *rouleur = 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) + rouleur->comp2_enable = value; + else + rouleur->comp1_enable = value; + + return 0; +} + +static int rouleur_codec_enable_pa_vpos(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 rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + struct rouleur_pdata *pdata = NULL; + int ret = 0; + + pdata = dev_get_platdata(rouleur->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: + if (test_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask)) { + dev_dbg(component->dev, + "%s: vpos already in enabled state\n", + __func__); + clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask); + return 0; + } + ret = msm_cdc_enable_ondemand_supply(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-pa-vpos"); + if (ret == -EINVAL) { + dev_err(component->dev, "%s: pa vpos is not enabled\n", + __func__); + return ret; + } + clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask); + /* + * 200us sleep is required after LDO15 is enabled as per + * HW requirement + */ + usleep_range(200, 250); + + break; + case SND_SOC_DAPM_POST_PMD: + set_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask); + ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, + rouleur->rx_swr_dev->dev_num, + false); + break; + } + return 0; +} + +static const struct snd_kcontrol_new rouleur_snd_controls[] = { + SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0, + rouleur_get_compander, rouleur_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0, + rouleur_get_compander, rouleur_set_compander), + + SOC_SINGLE_TLV("HPHL Volume", ROULEUR_ANA_HPHPA_L_GAIN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("HPHR Volume", ROULEUR_ANA_HPHPA_R_GAIN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("ADC1 Volume", ROULEUR_ANA_TX_AMIC1, 0, 8, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", ROULEUR_ANA_TX_AMIC2, 0, 8, 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 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 ear_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new lo_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(ROULEUR_ANA_TX_AMIC2, 4, + 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 struct snd_soc_dapm_widget rouleur_dapm_widgets[] = { + + /*input widgets*/ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + + /*tx widgets*/ + SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, + rouleur_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, + rouleur_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, + &tx_adc2_mux), + + /*tx mixers*/ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, + adc1_switch, ARRAY_SIZE(adc1_switch), + rouleur_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), + rouleur_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, + rouleur_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, + rouleur_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, + rouleur_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("PA_VPOS", SND_SOC_NOPM, 0, 0, + rouleur_codec_enable_pa_vpos, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /*rx widgets*/ + SND_SOC_DAPM_PGA_E("EAR PGA", ROULEUR_ANA_COMBOPA_CTL, 7, 0, NULL, 0, + rouleur_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LO PGA", ROULEUR_ANA_COMBOPA_CTL, 7, 0, NULL, 0, + rouleur_codec_enable_lo_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", ROULEUR_ANA_HPHPA_CNP_CTL_2, 7, 0, NULL, + 0, rouleur_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", ROULEUR_ANA_HPHPA_CNP_CTL_2, 6, 0, NULL, + 0, rouleur_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + rouleur_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, + rouleur_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, + rouleur_codec_ear_lo_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_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, + rouleur_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, + rouleur_enable_rx2, 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("LO_RDAC", SND_SOC_NOPM, 0, 0, + lo_rdac_switch, ARRAY_SIZE(lo_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, + hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, + hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), + + /*output widgets tx*/ + + SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), + + /*output widgets rx*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("LO"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + + /* micbias pull up widgets*/ + SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + rouleur_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + rouleur_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + rouleur_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + rouleur_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, + rouleur_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /*tx mixer widgets*/ + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, + 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), + rouleur_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), + rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /*output widgets*/ + SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), +}; + +static const struct snd_soc_dapm_route rouleur_audio_map[] = { + {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1"}, + {"ADC1", NULL, "AMIC1"}, + + {"ADC2_OUTPUT", NULL, "ADC2_MIXER"}, + {"ADC2_MIXER", "Switch", "ADC2"}, + {"ADC2", NULL, "ADC2 MUX"}, + {"ADC2 MUX", "INP3", "AMIC3"}, + {"ADC2 MUX", "INP2", "AMIC2"}, + + {"IN1_HPHL", NULL, "PA_VPOS"}, + {"RX1", NULL, "IN1_HPHL"}, + {"RDAC1", NULL, "RX1"}, + {"HPHL_RDAC", "Switch", "RDAC1"}, + {"HPHL PGA", NULL, "HPHL_RDAC"}, + {"HPHL", NULL, "HPHL PGA"}, + + {"IN2_HPHR", NULL, "PA_VPOS"}, + {"RX2", NULL, "IN2_HPHR"}, + {"RDAC2", NULL, "RX2"}, + {"HPHR_RDAC", "Switch", "RDAC2"}, + {"HPHR PGA", NULL, "HPHR_RDAC"}, + {"HPHR", NULL, "HPHR PGA"}, + + {"RDAC3", NULL, "RX1"}, + {"EAR_RDAC", "Switch", "RDAC3"}, + {"EAR PGA", NULL, "EAR_RDAC"}, + {"EAR", NULL, "EAR PGA"}, + + {"RDAC3", NULL, "RX1"}, + {"LO_RDAC", "Switch", "RDAC3"}, + {"LO PGA", NULL, "LO_RDAC"}, + {"LO", NULL, "LO PGA"}, + + {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, +}; + +static ssize_t rouleur_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct rouleur_priv *priv; + char buffer[ROULEUR_VERSION_ENTRY_SIZE]; + int len = 0; + + priv = (struct rouleur_priv *) entry->private_data; + if (!priv) { + pr_err("%s: rouleur priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->version) { + case ROULEUR_VERSION_1_0: + len = snprintf(buffer, sizeof(buffer), "ROULEUR_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 rouleur_info_ops = { + .read = rouleur_version_read, +}; + +/* + * rouleur_info_create_codec_entry - creates rouleur module + * @codec_root: The parent directory + * @component: component instance + * + * Creates rouleur module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct rouleur_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:rouleur module already created\n", __func__); + return 0; + } + card = component->card; + priv->entry = snd_info_create_subdir(codec_root->module, + "rouleur", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create rouleur 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 rouleur version entry\n", + __func__); + return -ENOMEM; + } + + version_entry->private_data = priv; + version_entry->size = ROULEUR_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &rouleur_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(rouleur_info_create_codec_entry); + +static int rouleur_set_micbias_data(struct rouleur_priv *rouleur, + struct rouleur_pdata *pdata) +{ + int vout_ctl = 0; + int rc = 0; + + if (!pdata) { + dev_err(rouleur->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl = rouleur_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + if (vout_ctl < 0) { + rc = -EINVAL; + goto done; + } + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MICBIAS_LDO_1_SETTING, + 0xF8, vout_ctl << 3); +done: + return rc; +} + +static int rouleur_battery_supply_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct power_supply *psy = data; + struct rouleur_priv *rouleur = + container_of(nb, struct rouleur_priv, psy_nb); + + if (strcmp(psy->desc->name, "battery")) + return NOTIFY_OK; + queue_work(system_freezable_wq, &rouleur->soc_eval_work); + + return NOTIFY_OK; +} + +static int rouleur_read_battery_soc(struct rouleur_priv *rouleur, int *soc_val) +{ + static struct power_supply *batt_psy; + union power_supply_propval ret = {0,}; + int err = 0; + + *soc_val = 100; + if (!batt_psy) + batt_psy = power_supply_get_by_name("battery"); + if (batt_psy) { + err = power_supply_get_property(batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &ret); + if (err) { + pr_err("%s: battery SoC read error:%d\n", + __func__, err); + return err; + } + *soc_val = ret.intval; + } + pr_debug("%s: soc:%d\n", __func__, *soc_val); + + return err; +} + +static void rouleur_evaluate_soc(struct work_struct *work) +{ + struct rouleur_priv *rouleur = + container_of(work, struct rouleur_priv, soc_eval_work); + int soc_val = 0, ret = 0; + struct rouleur_pdata *pdata = NULL; + + pdata = dev_get_platdata(rouleur->dev); + if (!pdata) { + dev_err(rouleur->dev, "%s: pdata is NULL\n", __func__); + return; + } + + if (rouleur_read_battery_soc(rouleur, &soc_val) < 0) { + dev_err(rouleur->dev, "%s unable to read battery SoC\n", + __func__); + return; + } + + if (soc_val < SOC_THRESHOLD_LEVEL) { + dev_dbg(rouleur->dev, + "%s battery SoC less than threshold soc_val = %d\n", + __func__, soc_val); + /* Reduce PA Gain by 6DB for low SoC */ + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_PA_GAIN_UPDATE, + true); + rouleur->low_soc = true; + ret = msm_cdc_set_supply_min_voltage(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-mic-bias", + LOW_SOC_MBIAS_REG_MIN_VOLTAGE, + true); + if (ret < 0) + dev_err(rouleur->dev, + "%s unable to set mbias min voltage\n", + __func__); + } else { + if (rouleur->low_soc == true) { + /* Reset PA Gain to default for normal SoC */ + if (rouleur->update_wcd_event) + rouleur->update_wcd_event(rouleur->handle, + SLV_BOLERO_EVT_RX_PA_GAIN_UPDATE, + false); + ret = msm_cdc_set_supply_min_voltage(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-mic-bias", + LOW_SOC_MBIAS_REG_MIN_VOLTAGE, + false); + if (ret < 0) + dev_err(rouleur->dev, + "%s unable to set mbias min voltage\n", + __func__); + rouleur->low_soc = false; + } + } +} + +static void rouleur_get_foundry_id(struct rouleur_priv *rouleur) +{ + int ret; + + if (rouleur->foundry_id_reg == 0) { + pr_debug("%s: foundry id not defined\n", __func__); + return; + } + + ret = pm2250_spmi_read(rouleur->spmi_dev, + rouleur->foundry_id_reg, &rouleur->foundry_id); + if (ret == 0) + pr_debug("%s: rouleur foundry id = %x\n", rouleur->foundry_id, + __func__); + else + pr_debug("%s: rouleur error in spmi read ret = %d\n", + __func__, ret); +} + +static int rouleur_soc_codec_probe(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = -EINVAL; + + dev_info(component->dev, "%s()\n", __func__); + rouleur = snd_soc_component_get_drvdata(component); + + if (!rouleur) + return -EINVAL; + + rouleur->component = component; + snd_soc_component_init_regmap(component, rouleur->regmap); + + rouleur->fw_data = devm_kzalloc(component->dev, + sizeof(*(rouleur->fw_data)), + GFP_KERNEL); + if (!rouleur->fw_data) { + dev_err(component->dev, "Failed to allocate fw_data\n"); + ret = -ENOMEM; + goto done; + } + + set_bit(WCD9XXX_MBHC_CAL, rouleur->fw_data->cal_bit); + ret = wcd_cal_create_hwdep(rouleur->fw_data, + WCD9XXX_CODEC_HWDEP_NODE, component); + + if (ret < 0) { + dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret); + goto done; + } + + ret = rouleur_mbhc_init(&rouleur->mbhc, component, rouleur->fw_data); + if (ret) { + pr_err("%s: mbhc initialization failed\n", __func__); + goto done; + } + 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, "IN1_HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "IN2_HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "ADC1_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC2_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "LO"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC1_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "DMIC2_OUTPUT"); + snd_soc_dapm_sync(dapm); + + rouleur_init_reg(component); + /* Get rouleur foundry id */ + rouleur_get_foundry_id(rouleur); + + rouleur->version = ROULEUR_VERSION_1_0; + /* Register event notifier */ + rouleur->nblock.notifier_call = rouleur_event_notify; + if (rouleur->register_notifier) { + ret = rouleur->register_notifier(rouleur->handle, + &rouleur->nblock, + true); + if (ret) { + dev_err(component->dev, + "%s: Failed to register notifier %d\n", + __func__, ret); + return ret; + } + } + rouleur->low_soc = false; + rouleur->dev_up = true; + /* Register notifier to change gain based on state of charge */ + INIT_WORK(&rouleur->soc_eval_work, rouleur_evaluate_soc); + rouleur->psy_nb.notifier_call = rouleur_battery_supply_cb; + if (power_supply_reg_notifier(&rouleur->psy_nb) < 0) + dev_dbg(rouleur->dev, + "%s: could not register pwr supply notifier\n", + __func__); + queue_work(system_freezable_wq, &rouleur->soc_eval_work); +done: + return ret; +} + +static void rouleur_soc_codec_remove(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + if (!rouleur) + return; + + if (rouleur->register_notifier) + rouleur->register_notifier(rouleur->handle, + &rouleur->nblock, + false); +} + +static int rouleur_soc_codec_suspend(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + if (!rouleur) + return 0; + rouleur->dapm_bias_off = true; + return 0; +} + +static int rouleur_soc_codec_resume(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + if (!rouleur) + return 0; + rouleur->dapm_bias_off = false; + return 0; +} + +static const struct snd_soc_component_driver soc_codec_dev_rouleur = { + .name = DRV_NAME, + .probe = rouleur_soc_codec_probe, + .remove = rouleur_soc_codec_remove, + .controls = rouleur_snd_controls, + .num_controls = ARRAY_SIZE(rouleur_snd_controls), + .dapm_widgets = rouleur_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rouleur_dapm_widgets), + .dapm_routes = rouleur_audio_map, + .num_dapm_routes = ARRAY_SIZE(rouleur_audio_map), + .suspend = rouleur_soc_codec_suspend, + .resume = rouleur_soc_codec_resume, +}; + +#ifdef CONFIG_PM_SLEEP +static int rouleur_suspend(struct device *dev) +{ + struct rouleur_priv *rouleur = NULL; + int ret = 0; + struct rouleur_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + rouleur = dev_get_drvdata(dev); + if (!rouleur) + return -EINVAL; + + pdata = dev_get_platdata(rouleur->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask)) { + ret = msm_cdc_disable_ondemand_supply(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-pa-vpos"); + if (ret == -EINVAL) { + dev_err(dev, "%s: pa vpos is not disabled\n", + __func__); + return 0; + } + clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask); + } + if (rouleur->dapm_bias_off) { + msm_cdc_set_supplies_lpm_mode(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + true); + set_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask); + } + return 0; +} + +static int rouleur_resume(struct device *dev) +{ + struct rouleur_priv *rouleur = NULL; + struct rouleur_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + rouleur = dev_get_drvdata(dev); + if (!rouleur) + return -EINVAL; + + pdata = dev_get_platdata(rouleur->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask)) { + msm_cdc_set_supplies_lpm_mode(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + false); + clear_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask); + } + + return 0; +} +#endif + +static int rouleur_reset(struct device *dev, int reset_val) +{ + struct rouleur_priv *rouleur = NULL; + + if (!dev) + return -ENODEV; + + rouleur = dev_get_drvdata(dev); + if (!rouleur) + return -EINVAL; + + pm2250_spmi_write(rouleur->spmi_dev, rouleur->reset_reg, reset_val); + + return 0; +} + +static int rouleur_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 rouleur_dt_parse_micbias_info(struct device *dev, + struct rouleur_micbias_setting *mb) +{ + u32 prop_val = 0; + int rc = 0; + + /* MB1 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv", + NULL)) { + rc = rouleur_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 = rouleur_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 = rouleur_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__); + } +} + +struct rouleur_pdata *rouleur_populate_dt_data(struct device *dev) +{ + struct rouleur_pdata *pdata = NULL; + u32 reg; + int ret = 0; + + pdata = kzalloc(sizeof(struct rouleur_pdata), + GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->spmi_np = of_parse_phandle(dev->of_node, + "qcom,pmic-spmi-node", 0); + if (!pdata->spmi_np) { + dev_err(dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,pmic-spmi-node", + dev->of_node->full_name); + kfree(pdata); + return NULL; + } + + ret = of_property_read_u32(dev->of_node, "qcom,wcd-reset-reg", ®); + if (ret) { + dev_err(dev, "%s: Failed to obtain reset reg value %d\n", + __func__, ret); + kfree(pdata); + return NULL; + } + pdata->reset_reg = reg; + + if (of_property_read_u32(dev->of_node, "qcom,foundry-id-reg", ®)) + dev_dbg(dev, "%s: Failed to obtain foundry id\n", + __func__); + else + pdata->foundry_id_reg = reg; + + /* 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__); + kfree(pdata); + return NULL; + } + + pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-slave", 0); + pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0); + rouleur_dt_parse_micbias_info(dev, &pdata->micbias); + + return pdata; +} + +static int rouleur_wakeup(void *handle, bool enable) +{ + struct rouleur_priv *priv; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + priv = (struct rouleur_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 irqreturn_t rouleur_wd_handle_irq(int irq, void *data) +{ + pr_err_ratelimited("%s: Watchdog interrupt for irq =%d triggered\n", + __func__, irq); + return IRQ_HANDLED; +} + +static int rouleur_bind(struct device *dev) +{ + int ret = 0, i = 0; + struct rouleur_priv *rouleur = NULL; + struct rouleur_pdata *pdata = NULL; + struct wcd_ctrl_platform_data *plat_data = NULL; + struct platform_device *pdev = NULL; + + rouleur = kzalloc(sizeof(struct rouleur_priv), GFP_KERNEL); + if (!rouleur) + return -ENOMEM; + + dev_set_drvdata(dev, rouleur); + + pdata = rouleur_populate_dt_data(dev); + if (!pdata) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); + kfree(rouleur); + return -EINVAL; + } + rouleur->dev = dev; + rouleur->dev->platform_data = pdata; + pdev = of_find_device_by_node(pdata->spmi_np); + if (!pdev) { + dev_err(dev, "%s: platform device from SPMI node is NULL\n", + __func__); + ret = -EINVAL; + goto err_bind_all; + } + + rouleur->spmi_dev = &pdev->dev; + rouleur->reset_reg = pdata->reset_reg; + rouleur->foundry_id_reg = pdata->foundry_id_reg; + ret = msm_cdc_init_supplies(dev, &rouleur->supplies, + pdata->regulator, pdata->num_supplies); + if (!rouleur->supplies) { + dev_err(dev, "%s: Cannot init wcd supplies\n", + __func__); + goto err_bind_all; + } + + plat_data = dev_get_platdata(dev->parent); + if (!plat_data) { + dev_err(dev, "%s: platform data from parent is NULL\n", + __func__); + ret = -EINVAL; + goto err_bind_all; + } + rouleur->handle = (void *)plat_data->handle; + if (!rouleur->handle) { + dev_err(dev, "%s: handle is NULL\n", __func__); + ret = -EINVAL; + goto err_bind_all; + } + rouleur->update_wcd_event = plat_data->update_wcd_event; + if (!rouleur->update_wcd_event) { + dev_err(dev, "%s: update_wcd_event api is null!\n", + __func__); + ret = -EINVAL; + goto err_bind_all; + } + rouleur->register_notifier = plat_data->register_notifier; + if (!rouleur->register_notifier) { + dev_err(dev, "%s: register_notifier api is null!\n", + __func__); + ret = -EINVAL; + goto err_bind_all; + } + + ret = msm_cdc_enable_static_supplies(dev, rouleur->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(dev, "%s: wcd static supply enable failed!\n", + __func__); + goto err_bind_all; + } + + rouleur_reset(dev, 0x01); + usleep_range(20, 30); + rouleur_reset(dev, 0x00); + /* + * Add 5msec delay to provide sufficient time for + * soundwire auto enumeration of slave devices as + * as per HW requirement. + */ + usleep_range(5000, 5010); + rouleur->wakeup = rouleur_wakeup; + + ret = component_bind_all(dev, rouleur); + if (ret) { + dev_err(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + goto err_bind_all; + } + + ret = rouleur_parse_port_mapping(dev, "qcom,rx_swr_ch_map", CODEC_RX); + ret |= rouleur_parse_port_mapping(dev, "qcom,tx_swr_ch_map", CODEC_TX); + + if (ret) { + dev_err(dev, "Failed to read port mapping\n"); + goto err; + } + + rouleur->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave); + if (!rouleur->rx_swr_dev) { + dev_err(dev, "%s: Could not find RX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + + rouleur->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave); + if (!rouleur->tx_swr_dev) { + dev_err(dev, "%s: Could not find TX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + + rouleur->regmap = devm_regmap_init_swr(rouleur->tx_swr_dev, + &rouleur_regmap_config); + if (!rouleur->regmap) { + dev_err(dev, "%s: Regmap init failed\n", + __func__); + goto err; + } + + /* Set all interupts as edge triggered */ + for (i = 0; i < rouleur_regmap_irq_chip.num_regs; i++) + regmap_write(rouleur->regmap, + (ROULEUR_DIG_SWR_INTR_LEVEL_0 + i), 0); + + rouleur_regmap_irq_chip.irq_drv_data = rouleur; + rouleur->irq_info.wcd_regmap_irq_chip = &rouleur_regmap_irq_chip; + rouleur->irq_info.codec_name = "rouleur"; + rouleur->irq_info.regmap = rouleur->regmap; + rouleur->irq_info.dev = dev; + ret = wcd_irq_init(&rouleur->irq_info, &rouleur->virq); + + if (ret) { + dev_err(dev, "%s: IRQ init failed: %d\n", + __func__, ret); + goto err; + } + rouleur->tx_swr_dev->slave_irq = rouleur->virq; + + mutex_init(&rouleur->micb_lock); + mutex_init(&rouleur->main_bias_lock); + mutex_init(&rouleur->rx_clk_lock); + + ret = rouleur_set_micbias_data(rouleur, pdata); + if (ret < 0) { + dev_err(dev, "%s: bad micbias pdata\n", __func__); + goto err_irq; + } + + /* Request for watchdog interrupt */ + wcd_request_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHR_PDM_WD_INT, + "HPHR PDM WD INT", rouleur_wd_handle_irq, NULL); + wcd_request_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHL_PDM_WD_INT, + "HPHL PDM WD INT", rouleur_wd_handle_irq, NULL); + /* Disable watchdog interrupt for HPH */ + wcd_disable_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHR_PDM_WD_INT); + wcd_disable_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHL_PDM_WD_INT); + + ret = snd_soc_register_component(dev, &soc_codec_dev_rouleur, + NULL, 0); + if (ret) { + dev_err(dev, "%s: Codec registration failed\n", + __func__); + goto err_irq; + } + + return ret; +err_irq: + wcd_irq_exit(&rouleur->irq_info, rouleur->virq); + mutex_destroy(&rouleur->micb_lock); + mutex_destroy(&rouleur->main_bias_lock); + mutex_destroy(&rouleur->rx_clk_lock); +err: + component_unbind_all(dev, rouleur); +err_bind_all: + dev_set_drvdata(dev, NULL); + kfree(pdata); + kfree(rouleur); + return ret; +} + +static void rouleur_unbind(struct device *dev) +{ + struct rouleur_priv *rouleur = dev_get_drvdata(dev); + struct rouleur_pdata *pdata = dev_get_platdata(rouleur->dev); + + wcd_irq_exit(&rouleur->irq_info, rouleur->virq); + snd_soc_unregister_component(dev); + component_unbind_all(dev, rouleur); + mutex_destroy(&rouleur->micb_lock); + mutex_destroy(&rouleur->main_bias_lock); + mutex_destroy(&rouleur->rx_clk_lock); + dev_set_drvdata(dev, NULL); + kfree(pdata); + kfree(rouleur); +} + +static const struct of_device_id rouleur_dt_match[] = { + { .compatible = "qcom,rouleur-codec" , .data = "rouleur" }, + {} +}; + +static const struct component_master_ops rouleur_comp_ops = { + .bind = rouleur_bind, + .unbind = rouleur_unbind, +}; + +static int rouleur_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void rouleur_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int rouleur_add_slave_components(struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np, *rx_node, *tx_node; + + np = dev->of_node; + + rx_node = of_parse_phandle(np, "qcom,rx-slave", 0); + if (!rx_node) { + dev_err(dev, "%s: Rx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(rx_node); + component_match_add_release(dev, matchptr, + rouleur_release_of, + rouleur_compare_of, + rx_node); + + tx_node = of_parse_phandle(np, "qcom,tx-slave", 0); + if (!tx_node) { + dev_err(dev, "%s: Tx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(tx_node); + component_match_add_release(dev, matchptr, + rouleur_release_of, + rouleur_compare_of, + tx_node); + return 0; +} + +static int rouleur_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + int ret; + + ret = rouleur_add_slave_components(&pdev->dev, &match); + if (ret) + return ret; + + return component_master_add_with_match(&pdev->dev, + &rouleur_comp_ops, match); +} + +static int rouleur_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &rouleur_comp_ops); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static const struct dev_pm_ops rouleur_dev_pm_ops = { + .suspend_late = rouleur_suspend, + .resume_early = rouleur_resume +}; +#endif + +static struct platform_driver rouleur_codec_driver = { + .probe = rouleur_probe, + .remove = rouleur_remove, + .driver = { + .name = "rouleur_codec", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rouleur_dt_match), +#ifdef CONFIG_PM_SLEEP + .pm = &rouleur_dev_pm_ops, +#endif + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(rouleur_codec_driver); +MODULE_DESCRIPTION("Rouleur Codec driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur.h b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur.h new file mode 100644 index 0000000000..51abff3a3a --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _ROULEUR_H +#define _ROULEUR_H + +#ifdef CONFIG_SND_SOC_ROULEUR +extern int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component); +#else +extern int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_ROULEUR */ + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur_slave.c b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur_slave.c new file mode 100644 index 0000000000..5ea4fe4522 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/rouleur/rouleur_slave.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_DEBUG_FS +#include +#include + +#define SWR_SLV_MAX_REG_ADDR 0x2009 +#define SWR_SLV_START_REG_ADDR 0x40 +#define SWR_SLV_MAX_BUF_LEN 20 +#define BYTES_PER_LINE 12 +#define SWR_SLV_RD_BUF_LEN 8 +#define SWR_SLV_WR_BUF_LEN 32 +#define SWR_SLV_MAX_DEVICES 2 +#endif /* CONFIG_DEBUG_FS */ + +struct rouleur_slave_priv { + struct swr_device *swr_slave; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_rouleur_dent; + struct dentry *debugfs_peek; + struct dentry *debugfs_poke; + struct dentry *debugfs_reg_dump; + unsigned int read_data; +#endif +}; + +#ifdef CONFIG_DEBUG_FS +static int codec_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int get_parameters(char *buf, u32 *param1, int num_of_par) +{ + char *token = NULL; + int base = 0, cnt = 0; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +static bool is_swr_slv_reg_readable(int reg) +{ + int ret = true; + + if (((reg > 0x46) && (reg < 0x4A)) || + ((reg > 0x4A) && (reg < 0x50)) || + ((reg > 0x55) && (reg < 0xD0)) || + ((reg > 0xD0) && (reg < 0xE0)) || + ((reg > 0xE0) && (reg < 0xF0)) || + ((reg > 0xF0) && (reg < 0x100)) || + ((reg > 0x105) && (reg < 0x120)) || + ((reg > 0x205) && (reg < 0x220)) || + ((reg > 0x305) && (reg < 0x320)) || + ((reg > 0x405) && (reg < 0x420)) || + ((reg > 0x128) && (reg < 0x130)) || + ((reg > 0x228) && (reg < 0x230)) || + ((reg > 0x328) && (reg < 0x330)) || + ((reg > 0x428) && (reg < 0x430)) || + ((reg > 0x138) && (reg < 0x205)) || + ((reg > 0x238) && (reg < 0x305)) || + ((reg > 0x338) && (reg < 0x405)) || + ((reg > 0x405) && (reg < 0xF00)) || + ((reg > 0xF05) && (reg < 0xF20)) || + ((reg > 0xF25) && (reg < 0xF30)) || + ((reg > 0xF35) && (reg < 0x2000))) + ret = false; + + return ret; +} + +static ssize_t rouleur_swrslave_reg_show(struct swr_device *pdev, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[SWR_SLV_MAX_BUF_LEN]; + + if (!ubuf || !ppos) + return 0; + + for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR); + i <= SWR_SLV_MAX_REG_ADDR; i++) { + if (!is_swr_slv_reg_readable(i)) + continue; + swr_read(pdev, pdev->dev_num, i, ®_val, 1); + len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, + (reg_val & 0xFF)); + if (len < 0) { + pr_err("%s: fail to fill the buffer\n", __func__); + total = -EFAULT; + goto copy_err; + } + if (((total + len) >= count - 1) || (len < 0)) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + pr_err("%s: fail to copy reg dump\n", __func__); + total = -EFAULT; + goto copy_err; + } + total += len; + *ppos += len; + } + +copy_err: + *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE; + return total; +} + +static ssize_t codec_debug_dump(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct swr_device *pdev; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + return rouleur_swrslave_reg_show(pdev, ubuf, count, ppos); +} + +static ssize_t codec_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char lbuf[SWR_SLV_RD_BUF_LEN]; + struct swr_device *pdev = NULL; + struct rouleur_slave_priv *rouleur_slave = NULL; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + rouleur_slave = swr_get_dev_data(pdev); + if (!rouleur_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + snprintf(lbuf, sizeof(lbuf), "0x%x\n", + (rouleur_slave->read_data & 0xFF)); + + return simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); +} + +static ssize_t codec_debug_peek_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev = NULL; + struct rouleur_slave_priv *rouleur_slave = NULL; + + if (!cnt || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + rouleur_slave = swr_get_dev_data(pdev); + if (!rouleur_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 1); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))) + return -EINVAL; + swr_read(pdev, pdev->dev_num, param[0], &rouleur_slave->read_data, 1); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static ssize_t codec_debug_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev; + + if (!file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 2); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && + (param[1] <= 0xFF) && (rc == 0))) + return -EINVAL; + swr_write(pdev, pdev->dev_num, param[0], ¶m[1]); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static const struct file_operations codec_debug_write_ops = { + .open = codec_debug_open, + .write = codec_debug_write, +}; + +static const struct file_operations codec_debug_read_ops = { + .open = codec_debug_open, + .read = codec_debug_read, + .write = codec_debug_peek_write, +}; + +static const struct file_operations codec_debug_dump_ops = { + .open = codec_debug_open, + .read = codec_debug_dump, +}; +#endif + +static int rouleur_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); + + if (pdev == NULL) { + dev_err(dev, "%s: pdev is NULL\n", __func__); + return -EINVAL; + } + + ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); + if (ret) { + dev_dbg(&pdev->dev, + "%s get devnum %d for dev addr %lx failed\n", + __func__, devnum, pdev->addr); + swr_remove_device(pdev); + return ret; + } + pdev->dev_num = devnum; + + return ret; +} + +static void rouleur_slave_unbind(struct device *dev, + struct device *master, void *data) +{ + struct rouleur_slave_priv *rouleur_slave = NULL; + struct swr_device *pdev = to_swr_device(dev); + + if (pdev == NULL) { + dev_err(dev, "%s: pdev is NULL\n", __func__); + return; + } + + rouleur_slave = swr_get_dev_data(pdev); + if (!rouleur_slave) { + dev_err(&pdev->dev, "%s: rouleur_slave is NULL\n", __func__); + return; + } + +} + +static const struct swr_device_id rouleur_swr_id[] = { + {"rouleur-slave", 0}, + {} +}; + +static const struct of_device_id rouleur_swr_dt_match[] = { + { + .compatible = "qcom,rouleur-slave", + }, + {} +}; + +static const struct component_ops rouleur_slave_comp_ops = { + .bind = rouleur_slave_bind, + .unbind = rouleur_slave_unbind, +}; + +static int rouleur_swr_up(struct swr_device *pdev) +{ + return 0; +} + +static int rouleur_swr_down(struct swr_device *pdev) +{ + return 0; +} + +static int rouleur_swr_reset(struct swr_device *pdev) +{ + return 0; +} + +static int rouleur_swr_probe(struct swr_device *pdev) +{ + struct rouleur_slave_priv *rouleur_slave = NULL; + + rouleur_slave = devm_kzalloc(&pdev->dev, + sizeof(struct rouleur_slave_priv), GFP_KERNEL); + if (!rouleur_slave) + return -ENOMEM; + + swr_set_dev_data(pdev, rouleur_slave); + + rouleur_slave->swr_slave = pdev; +#ifdef CONFIG_DEBUG_FS + if (!rouleur_slave->debugfs_rouleur_dent) { + rouleur_slave->debugfs_rouleur_dent = debugfs_create_dir( + dev_name(&pdev->dev), 0); + if (!IS_ERR(rouleur_slave->debugfs_rouleur_dent)) { + rouleur_slave->debugfs_peek = + debugfs_create_file("swrslave_peek", + S_IFREG | 0444, + rouleur_slave->debugfs_rouleur_dent, + (void *) pdev, + &codec_debug_read_ops); + + rouleur_slave->debugfs_poke = + debugfs_create_file("swrslave_poke", + S_IFREG | 0444, + rouleur_slave->debugfs_rouleur_dent, + (void *) pdev, + &codec_debug_write_ops); + + rouleur_slave->debugfs_reg_dump = + debugfs_create_file( + "swrslave_reg_dump", + S_IFREG | 0444, + rouleur_slave->debugfs_rouleur_dent, + (void *) pdev, + &codec_debug_dump_ops); + } + } +#endif + return component_add(&pdev->dev, &rouleur_slave_comp_ops); +} + +static int rouleur_swr_remove(struct swr_device *pdev) +{ +#ifdef CONFIG_DEBUG_FS + struct rouleur_slave_priv *rouleur_slave = swr_get_dev_data(pdev); + + if (rouleur_slave) { + debugfs_remove_recursive(rouleur_slave->debugfs_rouleur_dent); + rouleur_slave->debugfs_rouleur_dent = NULL; + } +#endif + component_del(&pdev->dev, &rouleur_slave_comp_ops); + swr_set_dev_data(pdev, NULL); + swr_remove_device(pdev); + return 0; +} + +static struct swr_driver rouleur_slave_driver = { + .driver = { + .name = "rouleur-slave", + .owner = THIS_MODULE, + .of_match_table = rouleur_swr_dt_match, + }, + .probe = rouleur_swr_probe, + .remove = rouleur_swr_remove, + .id_table = rouleur_swr_id, + .device_up = rouleur_swr_up, + .device_down = rouleur_swr_down, + .reset_device = rouleur_swr_reset, +}; + +static int __init rouleur_slave_init(void) +{ + return swr_driver_register(&rouleur_slave_driver); +} + +static void __exit rouleur_slave_exit(void) +{ + swr_driver_unregister(&rouleur_slave_driver); +} + +module_init(rouleur_slave_init); +module_exit(rouleur_slave_exit); + +MODULE_DESCRIPTION("Rouleur Swr Slave driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/swr-dmic.c b/qcom/opensource/audio-kernel/asoc/codecs/swr-dmic.c new file mode 100644 index 0000000000..0c484d3029 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/swr-dmic.c @@ -0,0 +1,937 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SND_SOC_WCD939X +#include "wcd939x/wcd939x.h" +#else +#include "wcd938x/wcd938x.h" +#endif +#include "swr-dmic.h" + +#define NUM_ATTEMPTS 5 +#define SWRS_SCP_CONTROL 0x44 + +#define MAX_NAME_LEN 40 + +static int swr_master_channel_map[] = { + ZERO, + SWRM_TX_PCM_OUT, + SWRM_TX1_CH1, + SWRM_TX1_CH2, + SWRM_TX1_CH3, + SWRM_TX1_CH4, + SWRM_TX2_CH1, + SWRM_TX2_CH2, + SWRM_TX2_CH3, + SWRM_TX2_CH4, + SWRM_TX3_CH1, + SWRM_TX3_CH2, + SWRM_TX3_CH3, + SWRM_TX3_CH4, + SWRM_TX_PCM_IN, +}; + +/* + * Private data Structure for swr-dmic. All parameters related to + * external mic codec needs to be defined here. + */ +struct swr_dmic_priv { + struct device *dev; + struct swr_device *swr_slave; + struct snd_soc_component *component; + struct snd_soc_component_driver *driver; + struct snd_soc_dai_driver *dai_driver; + struct snd_soc_component *supply_component; + u32 micb_num; + struct device_node *wcd_handle; + bool is_wcd_supply; + int is_en_supply; + u8 tx_master_port_map[SWR_DMIC_MAX_PORTS]; + struct swr_port_params tx_port_params[SWR_UC_MAX][SWR_DMIC_MAX_PORTS]; + struct swr_dev_frame_config swr_tx_port_params[SWR_UC_MAX]; + struct notifier_block nblock; +}; + +const char *codec_name_list[] = { + "swr-dmic.01", + "swr-dmic.02", + "swr-dmic.03", + "swr-dmic.04", +}; + +const char *dai_name_list[] = { + "swr_dmic_tx0", + "swr_dmic_tx1", + "swr_dmic_tx2", + "swr_dmic_tx3", +}; + +const char *aif_name_list[] = { + "SWR_DMIC_AIF0 Capture", + "SWR_DMIC_AIF1 Capture", + "SWR_DMIC_AIF2 Capture", + "SWR_DMIC_AIF3 Capture", +}; + +static int swr_dmic_reset(struct swr_device *pdev); +static int swr_dmic_up(struct swr_device *pdev); +static int swr_dmic_down(struct swr_device *pdev); +static int swr_dmic_event_notify(struct notifier_block *block, + unsigned long val, + void *data); + +static inline int swr_dmic_tx_get_slave_port_type_idx(const char *wname, + unsigned int *port_idx) +{ + u8 port_type; + + if (strnstr(wname, "HIFI", strlen(wname))) + port_type = SWR_DMIC_HIFI_PORT; + else if (strnstr(wname, "LP", strlen(wname))) + port_type = SWR_DMIC_LP_PORT; + else + return -EINVAL; + + *port_idx = port_type; + return 0; +} + +static inline int swr_dmic_get_master_port_val(int port) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(swr_master_channel_map); i++) + if (port == swr_master_channel_map[i]) + return i; + return 0; +} + +static int swr_dmic_tx_master_port_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct swr_dmic_priv *swr_dmic = NULL; + int ret = 0; + unsigned int slave_port_idx = SWR_DMIC_MAX_PORTS; + + if (NULL == component) { + pr_err_ratelimited("%s: swr dmic component is NULL\n", __func__); + return -EINVAL; + } + + swr_dmic = snd_soc_component_get_drvdata(component); + if (NULL == swr_dmic) { + pr_err_ratelimited("%s: swr_dmic_priv is NULL\n", __func__); + return -EINVAL; + } + + ret = swr_dmic_tx_get_slave_port_type_idx(kcontrol->id.name, + &slave_port_idx); + if (ret) { + dev_dbg(component->dev, "%s: invalid port string\n", __func__); + return ret; + } + + if (slave_port_idx >= SWR_DMIC_MAX_PORTS) { + pr_err_ratelimited("%s: invalid slave port id\n", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = + swr_dmic_get_master_port_val( + swr_dmic->tx_master_port_map[slave_port_idx]); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int swr_dmic_tx_master_port_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct swr_dmic_priv *swr_dmic = NULL; + int ret = 0; + unsigned int slave_port_idx = SWR_DMIC_MAX_PORTS; + unsigned int idx = 0; + + if (NULL == component) { + pr_err_ratelimited("%s: swr dmic component is NULL\n", __func__); + return -EINVAL; + } + + swr_dmic = snd_soc_component_get_drvdata(component); + if (NULL == swr_dmic) { + pr_err_ratelimited("%s: swr_dmic_priv is NULL\n", __func__); + return -EINVAL; + } + + ret = swr_dmic_tx_get_slave_port_type_idx(kcontrol->id.name, + &slave_port_idx); + if (ret) { + dev_dbg(component->dev, "%s: invalid port string\n", __func__); + return ret; + } + + if (slave_port_idx >= SWR_DMIC_MAX_PORTS) { + pr_err_ratelimited("%s: invalid slave port id\n", __func__); + return -EINVAL; + } + + idx = ucontrol->value.enumerated.item[0]; + if (idx < 0 || idx >= ARRAY_SIZE(swr_master_channel_map)) + return -EINVAL; + + swr_dmic->tx_master_port_map[slave_port_idx] = + swr_master_channel_map[idx]; + dev_dbg(component->dev, "%s: slv port id: %d, master_port_type: %d\n", + __func__, slave_port_idx, + swr_dmic->tx_master_port_map[slave_port_idx]); + + return 0; +} + +static int swr_dmic_port_enable(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct swr_dmic_priv *swr_dmic = + snd_soc_component_get_drvdata(component); + + u8 ch_mask = 0x01; /* only DpnChannelEN1 register is available */ + u8 num_port = 1; + u8 port_id = w->shift; + u8 port_type = swr_dmic->tx_master_port_map[port_id]; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret = swr_slvdev_datapath_control(swr_dmic->swr_slave, + swr_dmic->swr_slave->dev_num, true); + break; + case SND_SOC_DAPM_PRE_PMD: + ret = swr_disconnect_port(swr_dmic->swr_slave, + &port_id, num_port, &ch_mask, &port_type); + break; + }; + + return ret; +} + +static int dmic_swr_ctrl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct swr_dmic_priv *swr_dmic = + snd_soc_component_get_drvdata(component); + + u8 num_ch = 1; + u8 ch_mask = 0x01; /* only DpnChannelEN1 register is available */ + u32 ch_rate = SWR_CLK_RATE_4P8MHZ; + u8 num_port = 1; + u8 port_type = 0; + u8 port_id = w->shift; + + if (port_id >= SWR_DMIC_MAX_PORTS) + { + dev_err_ratelimited(component->dev, "%s: invalid port id: %d\n", + __func__, port_id); + return -EINVAL; + } + + /* + * Port 1 is high quality / 2.4 or 3.072 Mbps + * Port 2 is listen low power / 0.6 or 0.768 Mbps + */ + if (port_id == SWR_DMIC_HIFI_PORT) + ch_rate = SWR_CLK_RATE_2P4MHZ; + else + ch_rate = SWR_CLK_RATE_0P6MHZ; + + port_type = swr_dmic->tx_master_port_map[port_id]; + + dev_dbg(component->dev, "%s port_type: %d event: %d\n", __func__, + port_type, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = swr_connect_port(swr_dmic->swr_slave, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + break; + case SND_SOC_DAPM_POST_PMD: + ret = swr_slvdev_datapath_control(swr_dmic->swr_slave, + swr_dmic->swr_slave->dev_num, false); + break; + }; + + return ret; +} + +/* qcom,swr-tx-port-params = , , *UC0* + , , *UC1* + , , *UC2* + , , *UC3 */ +static int swr_dmic_parse_port_params(struct device *dev, + char *prop) +{ + int i, j; + u32 *dt_array, map_size, max_uc; + int ret = 0; + u32 cnt = 0; + struct swr_port_params (*map)[SWR_UC_MAX][SWR_DMIC_MAX_PORTS]; + struct swr_dev_frame_config (*map_uc)[SWR_UC_MAX]; + struct swr_dmic_priv *swr_dmic = dev_get_drvdata(dev); + + map = &swr_dmic->tx_port_params; + map_uc = &swr_dmic->swr_tx_port_params; + + 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; + } + + max_uc = map_size / (SWR_DMIC_MAX_PORTS * SWR_PORT_PARAMS * sizeof(u32)); + + if (max_uc != SWR_UC_MAX) { + dev_err(dev, + "%s:port params not provided for all usecases\n", + __func__); + ret = -EINVAL; + goto err_port_map; + } + 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, + SWR_DMIC_MAX_PORTS * SWR_PORT_PARAMS * max_uc); + 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 < max_uc; i++) { + for (j = 0; j < SWR_DMIC_MAX_PORTS; j++) { + cnt = (i * SWR_DMIC_MAX_PORTS + j) * SWR_PORT_PARAMS; + (*map)[i][j].offset1 = dt_array[cnt]; + (*map)[i][j].lane_ctrl = dt_array[cnt + 1]; + dev_err(dev, "%s: port %d, uc: %d, offset1:%d, lane: %d\n", + __func__, j, i, dt_array[cnt], dt_array[cnt + 1]); + } + (*map_uc)[i].pp = &(*map)[i][0]; + } + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static const char * const tx_master_port_text[] = { + "ZERO", "SWRM_PCM_OUT", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", + "SWRM_TX1_CH4", "SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", + "SWRM_TX2_CH4", "SWRM_TX3_CH1", "SWRM_TX3_CH2", "SWRM_TX3_CH3", + "SWRM_TX3_CH4", "SWRM_PCM_IN", +}; + +static const struct soc_enum tx_master_port_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_master_port_text), + tx_master_port_text); + +static const struct snd_kcontrol_new swr_dmic_snd_controls[] = { + SOC_ENUM_EXT("HIFI PortMap", tx_master_port_enum, + swr_dmic_tx_master_port_get, swr_dmic_tx_master_port_put), + SOC_ENUM_EXT("LP PortMap", tx_master_port_enum, + swr_dmic_tx_master_port_get, swr_dmic_tx_master_port_put), +}; + +static const struct snd_kcontrol_new dmic_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_dmic_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = { + SND_SOC_DAPM_MIXER_E("SWR_DMIC_MIXER", SND_SOC_NOPM, + SWR_DMIC_HIFI_PORT, 0, + dmic_switch, ARRAY_SIZE(dmic_switch), dmic_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("SWR_DMIC_VA_MIXER", SND_SOC_NOPM, + SWR_DMIC_LP_PORT, 0, + va_dmic_switch, ARRAY_SIZE(va_dmic_switch), dmic_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("SWR_DMIC"), + SND_SOC_DAPM_INPUT("VA_SWR_DMIC"), + + SND_SOC_DAPM_OUT_DRV_E("SMIC_PORT_EN", SND_SOC_NOPM, + SWR_DMIC_HIFI_PORT, 0, NULL, 0, + swr_dmic_port_enable, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUT_DRV_E("SMIC_VA_PORT_EN", SND_SOC_NOPM, + SWR_DMIC_LP_PORT, 0, NULL, 0, + swr_dmic_port_enable, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUTPUT("SWR_DMIC_OUTPUT"), + SND_SOC_DAPM_OUTPUT("SWR_DMIC_VA_OUTPUT"), +}; + +static const struct snd_soc_dapm_route swr_dmic_audio_map[] = { + {"SWR_DMIC_MIXER", "Switch", "SWR_DMIC"}, + {"SMIC_PORT_EN", NULL, "SWR_DMIC_MIXER"}, + {"SWR_DMIC_OUTPUT", NULL, "SMIC_PORT_EN"}, + {"SWR_DMIC_VA_MIXER", "Switch", "VA_SWR_DMIC"}, + {"SMIC_VA_PORT_EN", NULL, "SWR_DMIC_VA_MIXER"}, + {"SWR_DMIC_VA_OUTPUT", NULL, "SMIC_VA_PORT_EN"}, +}; + +static int swr_dmic_codec_probe(struct snd_soc_component *component) +{ + struct swr_dmic_priv *swr_dmic = + snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char w_name[MAX_NAME_LEN]; + + if (!swr_dmic) + return -EINVAL; + + swr_dmic->component = component; + if (!component->name_prefix) { + dev_err(component->dev, "%s: component prefix is NULL\n", __func__); + return -EPROBE_DEFER; + } + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " ", sizeof(w_name)); + strlcat(w_name, swr_dmic->dai_driver->capture.stream_name, + sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SWR_DMIC", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SMIC_PORT_EN", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SWR_DMIC_OUTPUT", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " VA_SWR_DMIC", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SMIC_VA_PORT_EN", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, sizeof(w_name)); + strlcpy(w_name, component->name_prefix, sizeof(w_name)); + strlcat(w_name, " SWR_DMIC_VA_OUTPUT", sizeof(w_name)); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + snd_soc_dapm_sync(dapm); + + swr_dmic->nblock.notifier_call = swr_dmic_event_notify; +#ifdef CONFIG_SND_SOC_WCD939X + wcd939x_swr_dmic_register_notifier(swr_dmic->supply_component, + &swr_dmic->nblock, true); +#else + wcd938x_swr_dmic_register_notifier(swr_dmic->supply_component, + &swr_dmic->nblock, true); +#endif + + return 0; +} + +static void swr_dmic_codec_remove(struct snd_soc_component *component) +{ + struct swr_dmic_priv *swr_dmic = + snd_soc_component_get_drvdata(component); + + swr_dmic->component = NULL; + return; +} + +static const struct snd_soc_component_driver soc_codec_dev_swr_dmic = { + .name = NULL, + .probe = swr_dmic_codec_probe, + .remove = swr_dmic_codec_remove, + .controls = swr_dmic_snd_controls, + .num_controls = ARRAY_SIZE(swr_dmic_snd_controls), + .dapm_widgets = swr_dmic_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(swr_dmic_dapm_widgets), + .dapm_routes = swr_dmic_audio_map, + .num_dapm_routes = ARRAY_SIZE(swr_dmic_audio_map), +}; + +static int enable_wcd_codec_supply(struct swr_dmic_priv *swr_dmic, bool enable) +{ + int rc = 0; + int micb_num = swr_dmic->micb_num; + struct snd_soc_component *component = swr_dmic->supply_component; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + dev_dbg(component->dev, "%s: supply %d micbias: %d enable: %d\n", + __func__, swr_dmic->is_en_supply, micb_num, enable); + + if (enable) +#ifdef CONFIG_SND_SOC_WCD939X + rc = wcd939x_codec_force_enable_micbias_v2(component, + SND_SOC_DAPM_PRE_PMU, micb_num); +#else + rc = wcd938x_codec_force_enable_micbias_v2(component, + SND_SOC_DAPM_PRE_PMU, micb_num); +#endif + else +#ifdef CONFIG_SND_SOC_WCD939X + rc = wcd939x_codec_force_enable_micbias_v2(component, + SND_SOC_DAPM_POST_PMD, micb_num); +#else + rc = wcd938x_codec_force_enable_micbias_v2(component, + SND_SOC_DAPM_POST_PMD, micb_num); +#endif + return rc; +} + +static int swr_dmic_parse_supply(struct device_node *np, + struct swr_dmic_priv *swr_dmic) +{ + struct platform_device *pdev = NULL; + + if (!np || !swr_dmic) + return -EINVAL; + + pdev = of_find_device_by_node(np); + if (!pdev) + return -EINVAL; + + swr_dmic->supply_component = snd_soc_lookup_component(&pdev->dev, NULL); + + return 0; +} + +static struct snd_soc_dai_driver swr_dmic_dai[] = { + { + .name = "", + .id = 0, + .capture = { + .stream_name = "", + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + }, +}; + +static int swr_dmic_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + int ret = 0; + struct swr_dmic_priv *swr_dmic = container_of(block, + struct swr_dmic_priv, + nblock); + switch (event) { +#ifdef CONFIG_SND_SOC_WCD939X + case WCD939X_EVT_SSR_DOWN: +#else + case WCD938X_EVT_SSR_DOWN: +#endif + ret = swr_dmic_down(swr_dmic->swr_slave); + break; +#ifdef CONFIG_SND_SOC_WCD939X + case WCD939X_EVT_SSR_UP: +#else + case WCD938X_EVT_SSR_UP: +#endif + ret = swr_dmic_up(swr_dmic->swr_slave); + if (!ret) + ret = swr_dmic_reset(swr_dmic->swr_slave); + break; + } + + return ret; +} + +static int swr_dmic_probe(struct swr_device *pdev) +{ + int ret = 0; + int i = 0; + u8 swr_devnum = 0; + int dev_index = -1; + struct swr_dmic_priv *swr_dmic = NULL; + const char *swr_dmic_codec_name_of = NULL; + struct snd_soc_component *component = NULL; + int num_retry = NUM_ATTEMPTS; + + swr_dmic = devm_kzalloc(&pdev->dev, sizeof(struct swr_dmic_priv), + GFP_KERNEL); + if (!swr_dmic) + return -ENOMEM; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,swr-dmic-supply", + &swr_dmic->micb_num); + if (ret) { + dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,swr-dmic-supply", + pdev->dev.of_node->full_name); + goto err; + } + swr_dmic->wcd_handle = of_parse_phandle(pdev->dev.of_node, + "qcom,wcd-handle", 0); + if (!swr_dmic->wcd_handle) { + dev_dbg(&pdev->dev, "%s: no wcd handle listed\n", + __func__); + swr_dmic->is_wcd_supply = false; + } else { + swr_dmic_parse_supply(swr_dmic->wcd_handle, swr_dmic); + swr_dmic->is_wcd_supply = true; + } + + if (swr_dmic->is_wcd_supply) { + ret = enable_wcd_codec_supply(swr_dmic, true); + if (ret) { + ret = -EPROBE_DEFER; + swr_dmic->is_wcd_supply = false; + swr_dmic->wcd_handle = NULL; + goto err; + } + ++swr_dmic->is_en_supply; + } + + swr_set_dev_data(pdev, swr_dmic); + + swr_dmic->swr_slave = pdev; + + ret = of_property_read_string(pdev->dev.of_node, "qcom,codec-name", + &swr_dmic_codec_name_of); + if (ret) { + dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,codec-name", + pdev->dev.of_node->full_name); + goto dev_err; + } + + ret = swr_dmic_parse_port_params(&pdev->dev, "qcom,swr-tx-port-params"); + if (ret) { + dev_err(&pdev->dev, "%s: Parsing %s failed in node %s\n", + __func__, "qcom,swr-tx-port-params", + pdev->dev.of_node->full_name); + goto dev_err; + } + + /* + * Add 5msec delay to provide sufficient time for + * soundwire auto enumeration of slave devices as + * as per HW requirement. + */ + usleep_range(5000, 5010); + do { + /* Add delay for soundwire enumeration */ + usleep_range(100, 110); + ret = swr_get_logical_dev_num(pdev, pdev->addr, &swr_devnum); + } while (ret && --num_retry); + + if (ret) { + dev_info(&pdev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, swr_devnum, pdev->addr); + ret = -EPROBE_DEFER; + + if (swr_dmic->is_en_supply == 1) { + enable_wcd_codec_supply(swr_dmic, false); + --swr_dmic->is_en_supply; + } + swr_dmic->is_wcd_supply = false; + swr_dmic->wcd_handle = NULL; + goto err; + } + pdev->dev_num = swr_devnum; + swr_init_port_params(pdev, SWR_DMIC_MAX_PORTS, + swr_dmic->swr_tx_port_params); + + swr_dmic->driver = devm_kzalloc(&pdev->dev, + sizeof(struct snd_soc_component_driver), GFP_KERNEL); + if (!swr_dmic->driver) { + ret = -ENOMEM; + goto dev_err; + } + + memcpy(swr_dmic->driver, &soc_codec_dev_swr_dmic, + sizeof(struct snd_soc_component_driver)); + + for (i = 0; i < ARRAY_SIZE(codec_name_list); i++) { + if (!strcmp(swr_dmic_codec_name_of, codec_name_list[i])) { + dev_index = i; + break; + } + } + + if (dev_index < 0) { + ret = -EINVAL; + goto dev_err; + } + + swr_dmic->driver->name = codec_name_list[dev_index]; + + swr_dmic->dai_driver = devm_kzalloc(&pdev->dev, + sizeof(struct snd_soc_dai_driver), GFP_KERNEL); + if (!swr_dmic->dai_driver) { + ret = -ENOMEM; + goto dev_err; + } + + memcpy(swr_dmic->dai_driver, swr_dmic_dai, + sizeof(struct snd_soc_dai_driver)); + swr_dmic->dai_driver->id = dev_index; + swr_dmic->dai_driver->name = dai_name_list[dev_index]; + swr_dmic->dai_driver->capture.stream_name = aif_name_list[dev_index]; + + /* Number of DAI's used is 1 */ + ret = snd_soc_register_component(&pdev->dev, swr_dmic->driver, + swr_dmic->dai_driver, 1); + if (ret) { + dev_err(&pdev->dev, "%s: Codec registration failed\n", + __func__); + goto dev_err; + } + + component = snd_soc_lookup_component(&pdev->dev, + swr_dmic->driver->name); + if (!component) { + dev_err(&pdev->dev, "%s: could not find swr_dmic component\n", + __func__); + goto dev_err; + } + swr_dmic->component = component; + + return 0; + +dev_err: + if (swr_dmic->is_en_supply == 1) { + enable_wcd_codec_supply(swr_dmic, false); + --swr_dmic->is_en_supply; + } + swr_dmic->is_wcd_supply = false; + swr_dmic->wcd_handle = NULL; + swr_remove_device(pdev); +err: + return ret; +} + +static int swr_dmic_remove(struct swr_device *pdev) +{ + struct swr_dmic_priv *swr_dmic; + + swr_dmic = swr_get_dev_data(pdev); + if (!swr_dmic) { + dev_err(&pdev->dev, "%s: swr_dmic is NULL\n", __func__); + return -EINVAL; + } + if (swr_dmic->is_en_supply == 1) { + enable_wcd_codec_supply(swr_dmic, false); + --swr_dmic->is_en_supply; + } + snd_soc_unregister_component(&pdev->dev); + swr_set_dev_data(pdev, NULL); + return 0; +} + +static int swr_dmic_up(struct swr_device *pdev) +{ + int ret = 0; + struct swr_dmic_priv *swr_dmic; + + swr_dmic = swr_get_dev_data(pdev); + if (!swr_dmic) { + dev_err_ratelimited(&pdev->dev, "%s: swr_dmic is NULL\n", __func__); + return -EINVAL; + } + + ++swr_dmic->is_en_supply; + if (swr_dmic->is_en_supply == 1) + ret = enable_wcd_codec_supply(swr_dmic, true); + + return ret; +} + +static int swr_dmic_down(struct swr_device *pdev) +{ + struct swr_dmic_priv *swr_dmic; + int ret = 0; + + swr_dmic = swr_get_dev_data(pdev); + if (!swr_dmic) { + dev_err_ratelimited(&pdev->dev, "%s: swr_dmic is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(&pdev->dev, "%s: is_en_supply: %d\n", + __func__, swr_dmic->is_en_supply); + --swr_dmic->is_en_supply; + if (swr_dmic->is_en_supply < 0) { + dev_warn(&pdev->dev, "%s: mismatch in supply count %d\n", + __func__, swr_dmic->is_en_supply); + swr_dmic->is_en_supply = 0; + goto done; + } + if (!swr_dmic->is_en_supply) + enable_wcd_codec_supply(swr_dmic, false); + +done: + return ret; +} + +static int swr_dmic_reset(struct swr_device *pdev) +{ + struct swr_dmic_priv *swr_dmic; + u8 retry = NUM_ATTEMPTS; + u8 devnum = 0; + + swr_dmic = swr_get_dev_data(pdev); + if (!swr_dmic) { + dev_err_ratelimited(&pdev->dev, "%s: swr_dmic is NULL\n", __func__); + return -EINVAL; + } + + while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) { + /* Retry after 1 msec delay */ + usleep_range(1000, 1100); + } + pdev->dev_num = devnum; + dev_dbg(&pdev->dev, "%s: devnum: %d\n", __func__, devnum); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int swr_dmic_suspend(struct device *dev) +{ + dev_dbg(dev, "%s: system suspend\n", __func__); + return 0; +} + +static int swr_dmic_resume(struct device *dev) +{ + struct swr_dmic_priv *swr_dmic = swr_get_dev_data(to_swr_device(dev)); + + if (!swr_dmic) { + dev_err_ratelimited(dev, "%s: swr_dmic private data is NULL\n", __func__); + return -EINVAL; + } + dev_dbg(dev, "%s: system resume\n", __func__); + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops swr_dmic_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(swr_dmic_suspend, swr_dmic_resume) +}; + +static const struct swr_device_id swr_dmic_id[] = { + {"swr-dmic", 0}, + {} +}; + +static const struct of_device_id swr_dmic_dt_match[] = { + { + .compatible = "qcom,swr-dmic", + }, + {} +}; + +static struct swr_driver swr_dmic_driver = { + .driver = { + .name = "swr-dmic", + .owner = THIS_MODULE, + .pm = &swr_dmic_pm_ops, + .of_match_table = swr_dmic_dt_match, + }, + .probe = swr_dmic_probe, + .remove = swr_dmic_remove, + .id_table = swr_dmic_id, +}; + +static int __init swr_dmic_init(void) +{ + return swr_driver_register(&swr_dmic_driver); +} + +static void __exit swr_dmic_exit(void) +{ + swr_driver_unregister(&swr_dmic_driver); +} + +module_init(swr_dmic_init); +module_exit(swr_dmic_exit); + +MODULE_DESCRIPTION("SWR DMIC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/swr-dmic.h b/qcom/opensource/audio-kernel/asoc/codecs/swr-dmic.h new file mode 100644 index 0000000000..15be708809 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/swr-dmic.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SWR_DMIC_H +#define _SWR_DMIC_H + +#include +#include + +enum { + SWR_DMIC_HIFI_PORT = 0, + SWR_DMIC_LP_PORT, + SWR_DMIC_MAX_PORTS, +}; + +#endif /* _SWR_DMIC_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/swr-haptics.c b/qcom/opensource/audio-kernel/asoc/codecs/swr-haptics.c new file mode 100644 index 0000000000..34dd53e44b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/swr-haptics.c @@ -0,0 +1,787 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HAPTICS_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) + +#define HAPTICS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +/* SWR register definition */ +#define SWR_HAP_ACCESS_BASE 0x3000 +#define FIFO_WR_READY_REG (SWR_HAP_ACCESS_BASE + 0x8) +#define NUM_PAT_SMPL_REG (SWR_HAP_ACCESS_BASE + 0x9) +#define SWR_WR_ACCESS_REG (SWR_HAP_ACCESS_BASE + 0xa) +#define CAL_TLRA_STATUS_MSB_REG (SWR_HAP_ACCESS_BASE + 0xb) +#define CAL_TLRA_STATUS_LSB_REG (SWR_HAP_ACCESS_BASE + 0xc) +#define AUTO_RES_CAL_DONE_REG (SWR_HAP_ACCESS_BASE + 0xd) +#define SWR_READ_DATA_REG (SWR_HAP_ACCESS_BASE + 0x80) +#define SWR_PLAY_REG (SWR_HAP_ACCESS_BASE + 0x81) +#define SWR_VMAX_REG (SWR_HAP_ACCESS_BASE + 0x82) +#define SWR_PLAY_BIT BIT(7) +#define SWR_BRAKE_EN_BIT BIT(3) +#define SWR_PLAY_SRC_MASK GENMASK(2, 0) +#define SWR_PLAY_SRC_VAL_SWR 4 + +#define SWR_HAP_REG_MAX (SWR_HAP_ACCESS_BASE + 0xff) + +enum pmic_type { + PM8350B = 1, + PM8550B = 2, +}; + +enum { + HAP_SSR_RECOVERY = BIT(0), +}; + +static struct reg_default swr_hap_reg_defaults[] = { + {FIFO_WR_READY_REG, 1}, + {NUM_PAT_SMPL_REG, 8}, + {SWR_WR_ACCESS_REG, 1}, + {CAL_TLRA_STATUS_MSB_REG, 0}, + {CAL_TLRA_STATUS_LSB_REG, 0}, + {AUTO_RES_CAL_DONE_REG, 0}, + {SWR_READ_DATA_REG, 0}, + {SWR_PLAY_REG, 4}, + {SWR_VMAX_REG, 0}, +}; + +enum { + PORT_ID_DT_IDX, + NUM_CH_DT_IDX, + CH_MASK_DT_IDX, + CH_RATE_DT_IDX, + PORT_TYPE_DT_IDX, + NUM_SWR_PORT_DT_PARAMS, +}; + +struct swr_port { + u8 port_id; + u8 ch_mask; + u32 ch_rate; + u8 num_ch; + u8 port_type; +}; + +struct swr_haptics_dev { + struct device *dev; + struct swr_device *swr_slave; + struct snd_soc_component *component; + struct regmap *regmap; + struct swr_port port; + struct regulator *slave_vdd; + struct regulator *hpwr_vreg; + struct notifier_block hboost_nb; + u32 hpwr_voltage_mv; + bool slave_enabled; + bool hpwr_vreg_enabled; + bool ssr_recovery; + u8 vmax; + u8 clamped_vmax; + u8 flags; +}; + +static bool swr_hap_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SWR_READ_DATA_REG: + case SWR_PLAY_REG: + case SWR_VMAX_REG: + return 1; + default: + return 0; + } +} + +static bool swr_hap_readable_register(struct device *dev, unsigned int reg) +{ + if (reg <= SWR_HAP_ACCESS_BASE) + return 0; + + return 1; +} + +static bool swr_hap_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg <= SWR_HAP_ACCESS_BASE) + return 0; + + switch (reg) { + case FIFO_WR_READY_REG: + case NUM_PAT_SMPL_REG: + case SWR_WR_ACCESS_REG: + case CAL_TLRA_STATUS_MSB_REG: + case CAL_TLRA_STATUS_LSB_REG: + case AUTO_RES_CAL_DONE_REG: + case SWR_READ_DATA_REG: + return 0; + } + + return 1; +} + +static int swr_hap_enable_hpwr_vreg(struct swr_haptics_dev *swr_hap) +{ + int rc; + + if (swr_hap->hpwr_vreg == NULL || swr_hap->hpwr_vreg_enabled) + return 0; + + rc = regulator_set_voltage(swr_hap->hpwr_vreg, + swr_hap->hpwr_voltage_mv * 1000, INT_MAX); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: Set hpwr voltage failed, rc=%d\n", + __func__, rc); + return rc; + } + + rc = regulator_enable(swr_hap->hpwr_vreg); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: Enable hpwr failed, rc=%d\n", + __func__, rc); + regulator_set_voltage(swr_hap->hpwr_vreg, 0, INT_MAX); + return rc; + } + + dev_dbg(swr_hap->dev, "%s: enabled hpwr_regulator\n", __func__); + swr_hap->hpwr_vreg_enabled = true; + return 0; +} + +static int swr_hap_disable_hpwr_vreg(struct swr_haptics_dev *swr_hap) +{ + int rc; + + if (swr_hap->hpwr_vreg == NULL || !swr_hap->hpwr_vreg_enabled) + return 0; + + rc = regulator_disable(swr_hap->hpwr_vreg); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: Disable hpwr failed, rc=%d\n", + __func__, rc); + return rc; + } + + rc = regulator_set_voltage(swr_hap->hpwr_vreg, 0, INT_MAX); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: Set hpwr voltage failed, rc=%d\n", + __func__, rc); + return rc; + } + + dev_dbg(swr_hap->dev, "%s: disabled hpwr_regulator\n", __func__); + swr_hap->hpwr_vreg_enabled = false; + return 0; +} + +static int swr_haptics_slave_enable(struct swr_haptics_dev *swr_hap) +{ + int rc; + + if (swr_hap->slave_enabled) + return 0; + + rc = regulator_enable(swr_hap->slave_vdd); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: enable swr-slave-vdd failed, rc=%d\n", + __func__, rc); + return rc; + } + + dev_dbg(swr_hap->dev, "%s: enable swr-slave-vdd success\n", __func__); + swr_hap->slave_enabled = true; + return 0; +} + +static int swr_haptics_slave_disable(struct swr_haptics_dev *swr_hap) +{ + int rc; + + if (!swr_hap->slave_enabled) + return 0; + + rc = regulator_disable(swr_hap->slave_vdd); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: disable swr-slave-vdd failed, rc=%d\n", + __func__, rc); + return rc; + } + + dev_dbg(swr_hap->dev, "%s: disable swr-slave-vdd success\n", __func__); + swr_hap->slave_enabled = false; + return 0; +} + +struct regmap_config swr_hap_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = swr_hap_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(swr_hap_reg_defaults), + .max_register = SWR_HAP_REG_MAX, + .volatile_reg = swr_hap_volatile_register, + .readable_reg = swr_hap_readable_register, + .writeable_reg = swr_hap_writeable_register, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .can_multi_write = true, +}; + +static const struct snd_kcontrol_new hap_swr_dac_port[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *swr_hap_comp = + snd_soc_dapm_to_component(w->dapm); + struct swr_haptics_dev *swr_hap; + u8 port_id, ch_mask, num_ch, port_type, num_port; + u8 vmax; + u32 ch_rate; + unsigned int val; + int rc; + + if (!swr_hap_comp) { + pr_err("%s: swr_hap_component is NULL\n", __func__); + return -EINVAL; + } + + swr_hap = snd_soc_component_get_drvdata(swr_hap_comp); + if (!swr_hap) { + pr_err("%s: get swr_haptics_dev failed\n", __func__); + return -ENODEV; + } + + dev_dbg(swr_hap->dev, "%s: %s event %d\n", __func__, w->name, event); + num_port = 1; + port_id = swr_hap->port.port_id; + ch_mask = swr_hap->port.ch_mask; + ch_rate = swr_hap->port.ch_rate; + num_ch = swr_hap->port.num_ch; + port_type = swr_hap->port.port_type; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* If SSR ever happened, toggle swr-slave-vdd for HW recovery */ + if ((swr_hap->flags & HAP_SSR_RECOVERY) + && swr_hap->ssr_recovery) { + swr_haptics_slave_disable(swr_hap); + swr_haptics_slave_enable(swr_hap); + swr_hap->ssr_recovery = false; + } + + vmax = swr_hap->vmax; + if ((swr_hap->clamped_vmax != 0) && (swr_hap->vmax > swr_hap->clamped_vmax)) + vmax = swr_hap->clamped_vmax; + + rc = regmap_write(swr_hap->regmap, SWR_VMAX_REG, vmax); + if (rc) { + dev_err_ratelimited(swr_hap->dev, "%s: SWR_VMAX update failed, rc=%d\n", + __func__, rc); + return rc; + } + regmap_read(swr_hap->regmap, SWR_VMAX_REG, &val); + regmap_read(swr_hap->regmap, SWR_READ_DATA_REG, &val); + dev_dbg(swr_hap->dev, "%s: swr_vmax is set to 0x%x\n", __func__, val); + swr_device_wakeup_vote(swr_hap->swr_slave); + swr_connect_port(swr_hap->swr_slave, &port_id, num_port, + &ch_mask, &ch_rate, &num_ch, &port_type); + break; + case SND_SOC_DAPM_POST_PMU: + rc = swr_hap_enable_hpwr_vreg(swr_hap); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: Enable hpwr_vreg failed, rc=%d\n", + __func__, rc); + swr_device_wakeup_unvote(swr_hap->swr_slave); + return rc; + } + + swr_slvdev_datapath_control(swr_hap->swr_slave, + swr_hap->swr_slave->dev_num, true); + /* trigger SWR play */ + val = SWR_PLAY_BIT | SWR_PLAY_SRC_VAL_SWR; + rc = regmap_write(swr_hap->regmap, SWR_PLAY_REG, val); + if (rc) { + dev_err_ratelimited(swr_hap->dev, "%s: Enable SWR_PLAY failed, rc=%d\n", + __func__, rc); + swr_slvdev_datapath_control(swr_hap->swr_slave, + swr_hap->swr_slave->dev_num, false); + swr_hap_disable_hpwr_vreg(swr_hap); + swr_device_wakeup_unvote(swr_hap->swr_slave); + return rc; + } + swr_device_wakeup_unvote(swr_hap->swr_slave); + break; + case SND_SOC_DAPM_PRE_PMD: + swr_device_wakeup_vote(swr_hap->swr_slave); + /* stop SWR play */ + val = SWR_PLAY_SRC_VAL_SWR; + rc = regmap_write(swr_hap->regmap, SWR_PLAY_REG, val); + if (rc) { + dev_err_ratelimited(swr_hap->dev, "%s: Enable SWR_PLAY failed, rc=%d\n", + __func__, rc); + swr_device_wakeup_unvote(swr_hap->swr_slave); + return rc; + } + + rc = swr_hap_disable_hpwr_vreg(swr_hap); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "%s: Disable hpwr_vreg failed, rc=%d\n", + __func__, rc); + swr_device_wakeup_unvote(swr_hap->swr_slave); + return rc; + } + break; + case SND_SOC_DAPM_POST_PMD: + swr_disconnect_port(swr_hap->swr_slave, &port_id, num_port, + &ch_mask, &port_type); + swr_slvdev_datapath_control(swr_hap->swr_slave, + swr_hap->swr_slave->dev_num, false); + swr_device_wakeup_unvote(swr_hap->swr_slave); + break; + default: + break; + } + + return 0; +} + +static int haptics_vmax_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct swr_haptics_dev *swr_hap = + snd_soc_component_get_drvdata(component); + + pr_debug("%s: vmax %u\n", __func__, swr_hap->vmax); + ucontrol->value.integer.value[0] = swr_hap->vmax; + + return 0; +} + +static int haptics_vmax_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct swr_haptics_dev *swr_hap = + snd_soc_component_get_drvdata(component); + + swr_hap->vmax = ucontrol->value.integer.value[0]; + pr_debug("%s: vmax %u\n", __func__, swr_hap->vmax); + + return 0; +} + +static const struct snd_kcontrol_new haptics_snd_controls[] = { + SOC_SINGLE_EXT("Haptics Amplitude Step", SND_SOC_NOPM, 0, 100, 0, + haptics_vmax_get, haptics_vmax_put), +}; + +static const struct snd_soc_dapm_widget haptics_comp_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("HAP_IN"), + SND_SOC_DAPM_MIXER_E("SWR DAC_Port", SND_SOC_NOPM, 0, 0, + hap_swr_dac_port, ARRAY_SIZE(hap_swr_dac_port), + hap_enable_swr_dac_port, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SPK("HAP_OUT", NULL), +}; + +static const struct snd_soc_dapm_route haptics_comp_dapm_route[] = { + {"SWR DAC_Port", "Switch", "HAP_IN"}, + {"HAP_OUT", NULL, "SWR DAC_Port"}, +}; + +static int haptics_comp_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm; + + struct swr_haptics_dev *swr_hap = + snd_soc_component_get_drvdata(component); + + if (!swr_hap) { + pr_err("%s: get swr_haptics_dev failed\n", __func__); + return -EINVAL; + } + + snd_soc_component_init_regmap(component, swr_hap->regmap); + + dapm = snd_soc_component_get_dapm(component); + if (dapm && dapm->component) { + snd_soc_dapm_ignore_suspend(dapm, "HAP_IN"); + snd_soc_dapm_ignore_suspend(dapm, "HAP_OUT"); + } + + return 0; +} + +static void haptics_comp_remove(struct snd_soc_component *component) +{ +} + +static const struct snd_soc_component_driver swr_haptics_component = { + .name = "swr-haptics", + .probe = haptics_comp_probe, + .remove = haptics_comp_remove, + .controls = haptics_snd_controls, + .num_controls = ARRAY_SIZE(haptics_snd_controls), + .dapm_widgets = haptics_comp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(haptics_comp_dapm_widgets), + .dapm_routes = haptics_comp_dapm_route, + .num_dapm_routes = ARRAY_SIZE(haptics_comp_dapm_route), +}; + +static struct snd_soc_dai_driver haptics_dai[] = { + { + .name = "swr_haptics", + .playback = { + .stream_name = "HAPTICS_AIF Playback", + .rates = HAPTICS_RATES, + .formats = HAPTICS_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + }, +}; + +static int swr_haptics_parse_port_mapping(struct swr_device *sdev) +{ + struct swr_haptics_dev *swr_hap = swr_get_dev_data(sdev); + u32 port_cfg[NUM_SWR_PORT_DT_PARAMS]; + int rc; + + if (!swr_hap) { + dev_err(&sdev->dev, "%s: get swr_haptics_dev failed\n", + __func__); + return -EINVAL; + } + + rc = of_property_read_u32_array(sdev->dev.of_node, "qcom,rx_swr_ch_map", + port_cfg, NUM_SWR_PORT_DT_PARAMS); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Get qcom,rx_swr_ch_map failed, rc=%d\n", + __func__, rc); + return -EINVAL; + } + + swr_hap->port.port_id = (u8) port_cfg[PORT_ID_DT_IDX]; + swr_hap->port.num_ch = (u8) port_cfg[NUM_CH_DT_IDX]; + swr_hap->port.ch_mask = (u8) port_cfg[CH_MASK_DT_IDX]; + swr_hap->port.ch_rate = port_cfg[CH_RATE_DT_IDX]; + swr_hap->port.port_type = (u8) port_cfg[PORT_TYPE_DT_IDX]; + + dev_dbg(swr_hap->dev, "%s: port_id = %d, ch_mask = %d, ch_rate = %d, num_ch = %d, port_type = %d\n", + __func__, swr_hap->port.port_id, + swr_hap->port.ch_mask, swr_hap->port.ch_rate, + swr_hap->port.num_ch, swr_hap->port.port_type); + return 0; +} + +#define MAX_HAPTICS_VMAX_MV 10000 +#define VMAX_STEP_MV 50 +static int hboost_notifier(struct notifier_block *nb, unsigned long event, void *val) +{ + struct swr_haptics_dev *swr_hap = container_of(nb, struct swr_haptics_dev, hboost_nb); + u32 vmax_mv; + + switch (event) { + case VMAX_CLAMP: + vmax_mv = *(u32 *)val; + if (vmax_mv > MAX_HAPTICS_VMAX_MV) { + dev_err_ratelimited(swr_hap->dev, "%s: voted Vmax (%u mv) is higher than maximum (%u mv)\n", + __func__, vmax_mv, MAX_HAPTICS_VMAX_MV); + return -EINVAL; + } + + dev_dbg(swr_hap->dev, "%s: Vmax is clamped at %u mv to support hBoost concurrency\n", + __func__, vmax_mv); + swr_hap->clamped_vmax = vmax_mv / VMAX_STEP_MV; + break; + default: + break; + } + + return 0; +} + +static int swr_haptics_probe(struct swr_device *sdev) +{ + struct swr_haptics_dev *swr_hap; + struct device_node *node = sdev->dev.of_node; + int rc; + u8 devnum; + u32 pmic_type; + int retry = 5; + + swr_hap = devm_kzalloc(&sdev->dev, + sizeof(struct swr_haptics_dev), GFP_KERNEL); + if (!swr_hap) + return -ENOMEM; + + /* VMAX default to 5V */ + swr_hap->vmax = 100; + swr_hap->swr_slave = sdev; + swr_hap->dev = &sdev->dev; + pmic_type = (uintptr_t)of_device_get_match_data(swr_hap->dev); + if (pmic_type == PM8350B) + swr_hap->flags |= HAP_SSR_RECOVERY; + + swr_set_dev_data(sdev, swr_hap); + + rc = swr_haptics_parse_port_mapping(sdev); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: failed to parse swr port mapping, rc=%d\n", + __func__, rc); + goto clean; + } + + swr_hap->slave_vdd = devm_regulator_get(swr_hap->dev, "swr-slave"); + if (IS_ERR(swr_hap->slave_vdd)) { + rc = PTR_ERR(swr_hap->slave_vdd); + if (rc != -EPROBE_DEFER) + dev_err(swr_hap->dev, "%s: get swr-slave-supply failed, rc=%d\n", + __func__, rc); + goto clean; + } + + if (of_find_property(node, "qcom,hpwr-supply", NULL)) { + swr_hap->hpwr_vreg = devm_regulator_get(swr_hap->dev, + "qcom,hpwr"); + if (IS_ERR(swr_hap->hpwr_vreg)) { + rc = PTR_ERR(swr_hap->hpwr_vreg); + if (rc != -EPROBE_DEFER) + dev_err(swr_hap->dev, "%s: Get qcom,hpwr-supply failed, rc=%d\n", + __func__, rc); + goto clean; + } + + rc = of_property_read_u32(node, "qcom,hpwr-voltage-mv", + &swr_hap->hpwr_voltage_mv); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Failed to read qcom,hpwr-voltage-mv, rc=%d\n", + __func__, rc); + goto clean; + } + } + + rc = swr_haptics_slave_enable(swr_hap); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: enable swr-slave-vdd failed, rc=%d\n", + __func__, rc); + goto clean; + } + do { + /* Add delay for soundwire enumeration */ + usleep_range(500, 510); + rc = swr_get_logical_dev_num(sdev, sdev->addr, &devnum); + } while (rc && --retry); + + if (rc) { + dev_err(swr_hap->dev, "%s: failed to get devnum for swr-haptics, rc=%d\n", + __func__, rc); + rc = -EPROBE_DEFER; + goto dev_err; + } + + sdev->dev_num = devnum; + swr_hap->regmap = devm_regmap_init_swr(sdev, &swr_hap_regmap_config); + if (IS_ERR(swr_hap->regmap)) { + rc = PTR_ERR(swr_hap->regmap); + dev_err(swr_hap->dev, "%s: init regmap failed, rc=%d\n", + __func__, rc); + goto dev_err; + } + + rc = snd_soc_register_component(&sdev->dev, + &swr_haptics_component, haptics_dai, ARRAY_SIZE(haptics_dai)); + if (rc) { + dev_err(swr_hap->dev, "%s: register swr_haptics component failed, rc=%d\n", + __func__, rc); + goto dev_err; + } + + swr_hap->hboost_nb.notifier_call = hboost_notifier; + register_hboost_event_notifier(&swr_hap->hboost_nb); + return 0; +dev_err: + swr_haptics_slave_disable(swr_hap); + swr_remove_device(sdev); +clean: + swr_set_dev_data(sdev, NULL); + return rc; +} + +static int swr_haptics_remove(struct swr_device *sdev) +{ + struct swr_haptics_dev *swr_hap; + int rc = 0; + + swr_hap = swr_get_dev_data(sdev); + if (!swr_hap) { + dev_err(&sdev->dev, "%s: no data for swr_hap\n", __func__); + rc = -ENODEV; + goto clean; + } + + unregister_hboost_event_notifier(&swr_hap->hboost_nb); + rc = swr_haptics_slave_disable(swr_hap); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: disable swr-slave failed, rc=%d\n", + __func__, rc); + goto clean; + } +clean: + snd_soc_unregister_component(&sdev->dev); + swr_set_dev_data(sdev, NULL); + return rc; +} + +static int swr_haptics_device_up(struct swr_device *sdev) +{ + struct swr_haptics_dev *swr_hap; + + swr_hap = swr_get_dev_data(sdev); + if (!swr_hap) { + dev_err_ratelimited(&sdev->dev, "%s: no data for swr_hap\n", __func__); + return -ENODEV; + } + + if (swr_hap->flags & HAP_SSR_RECOVERY) + swr_hap->ssr_recovery = true; + + /* Take SWR slave out of reset */ + return swr_haptics_slave_enable(swr_hap); +} + +static int swr_haptics_device_down(struct swr_device *sdev) +{ + struct swr_haptics_dev *swr_hap = swr_get_dev_data(sdev); + int rc; + + if (!swr_hap) { + dev_err_ratelimited(&sdev->dev, "%s: no data for swr_hap\n", __func__); + return -ENODEV; + } + + /* Disable HAP_PWR regulator */ + rc = swr_hap_disable_hpwr_vreg(swr_hap); + if (rc < 0) { + dev_err_ratelimited(swr_hap->dev, "Disable hpwr_vreg failed, rc=%d\n", + rc); + return rc; + } + + /* Put SWR slave into reset */ + return swr_haptics_slave_disable(swr_hap); +} + +static int swr_haptics_suspend(struct device *dev) +{ + struct swr_haptics_dev *swr_hap; + int rc = 0; + + swr_hap = swr_get_dev_data(to_swr_device(dev)); + if (!swr_hap) { + dev_err_ratelimited(dev, "%s: no data for swr_hap\n", __func__); + return -ENODEV; + } + + return rc; +} + +static int swr_haptics_resume(struct device *dev) +{ + struct swr_haptics_dev *swr_hap; + int rc = 0; + + swr_hap = swr_get_dev_data(to_swr_device(dev)); + if (!swr_hap) { + dev_err_ratelimited(dev, "%s: no data for swr_hap\n", __func__); + return -ENODEV; + } + + return rc; +} + +static const struct of_device_id swr_haptics_match_table[] = { + { + .compatible = "qcom,swr-haptics", + .data = NULL, + }, + { + .compatible = "qcom,pm8350b-swr-haptics", + .data = (void *)PM8350B, + }, + { + .compatible = "qcom,pm8550b-swr-haptics", + .data = (void *)PM8550B, + }, + { }, +}; + +static const struct swr_device_id swr_haptics_id[] = { + {"swr-haptics", 0}, + {"pm8350b-swr-haptics", 0}, + {"pm8550b-swr-haptics", 0}, + {}, +}; + +static const struct dev_pm_ops swr_haptics_pm_ops = { + .suspend = swr_haptics_suspend, + .resume = swr_haptics_resume, +}; + +static struct swr_driver swr_haptics_driver = { + .driver = { + .name = "swr-haptics", + .owner = THIS_MODULE, + .pm = &swr_haptics_pm_ops, + .of_match_table = swr_haptics_match_table, + }, + .probe = swr_haptics_probe, + .remove = swr_haptics_remove, + .id_table = swr_haptics_id, + .device_up = swr_haptics_device_up, + .device_down = swr_haptics_device_down, +}; + +static int __init swr_haptics_init(void) +{ + return swr_driver_register(&swr_haptics_driver); +} + +static void __exit swr_haptics_exit(void) +{ + swr_driver_unregister(&swr_haptics_driver); +} + +module_init(swr_haptics_init); +module_exit(swr_haptics_exit); + +MODULE_DESCRIPTION("SWR haptics driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-clsh.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-clsh.c new file mode 100644 index 0000000000..ab1dd21e2f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-clsh.c @@ -0,0 +1,612 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define WCD_USLEEP_RANGE 50 + +static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_component *, + struct wcd_clsh_cdc_info *, + u8 req_state, bool en, int mode); + +static const char *mode_to_str(int mode) +{ + switch (mode) { + case CLS_H_NORMAL: + return WCD_CLSH_STRINGIFY(CLS_H_NORMAL); + case CLS_H_HIFI: + return WCD_CLSH_STRINGIFY(CLS_H_HIFI); + case CLS_H_LOHIFI: + return WCD_CLSH_STRINGIFY(CLS_H_LOHIFI); + case CLS_H_LP: + return WCD_CLSH_STRINGIFY(CLS_H_LP); + case CLS_H_ULP: + return WCD_CLSH_STRINGIFY(CLS_H_ULP); + case CLS_AB: + return WCD_CLSH_STRINGIFY(CLS_AB); + case CLS_AB_HIFI: + return WCD_CLSH_STRINGIFY(CLS_AB_HIFI); + case CLS_AB_LP: + return WCD_CLSH_STRINGIFY(CLS_AB_LP); + case CLS_AB_LOHIFI: + return WCD_CLSH_STRINGIFY(CLS_AB_LOHIFI); + default: + return WCD_CLSH_STRINGIFY(CLS_H_INVALID); + }; +} + +static const char *state_to_str(u8 state, char *buf, size_t buflen) +{ + int i; + int cnt = 0; + /* + * This array of strings should match with enum wcd_clsh_state_bit. + */ + static const char *const states[] = { + "STATE_EAR", + "STATE_HPH_L", + "STATE_HPH_R", + "STATE_AUX", + }; + + if (state == WCD_CLSH_STATE_IDLE) { + snprintf(buf, buflen, "[STATE_IDLE]"); + goto done; + } + + buf[0] = '\0'; + for (i = 0; i < ARRAY_SIZE(states); i++) { + if (!(state & (1 << i))) + continue; + cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf, + buf[0] == '\0' ? "[" : "|", + states[i]); + } + if (cnt > 0) + strlcat(buf + cnt, "]", buflen); + +done: + if (buf[0] == '\0') + snprintf(buf, buflen, "[STATE_UNKNOWN]"); + return buf; +} + +static inline int wcd_clsh_get_int_mode(struct wcd_clsh_cdc_info *clsh_d, + int clsh_state) +{ + int mode; + + if ((clsh_state != WCD_CLSH_STATE_EAR) && + (clsh_state != WCD_CLSH_STATE_HPHL) && + (clsh_state != WCD_CLSH_STATE_HPHR) && + (clsh_state != WCD_CLSH_STATE_AUX)) + mode = CLS_NONE; + else + mode = clsh_d->interpolator_modes[ffs(clsh_state)]; + + return mode; +} + +static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_info *clsh_d, + int clsh_state, int mode) +{ + if ((clsh_state != WCD_CLSH_STATE_EAR) && + (clsh_state != WCD_CLSH_STATE_HPHL) && + (clsh_state != WCD_CLSH_STATE_HPHR) && + (clsh_state != WCD_CLSH_STATE_AUX)) + return; + + clsh_d->interpolator_modes[ffs(clsh_state)] = mode; +} + +static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x08, 0x08); /* set to HIFI */ + else + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x08, 0x00); /* set to default */ +} + +static inline void wcd_clsh_set_flyback_mode( + struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x80); + } else { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x04, 0x00); /* set to Default */ + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x70); + } +} + +static inline void wcd_clsh_force_iq_ctl(struct snd_soc_component *component, + int mode, bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, 0xA0); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_3, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_2, + 0xFF, 0x1C); + if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0xC0); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x02); + } + } else { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0x80); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x06); + } +} + +static void wcd_clsh_buck_ctrl(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + int mode, + bool enable) +{ + /* enable/disable buck */ + if ((enable && (++clsh_d->buck_users == 1)) || + (!enable && (--clsh_d->buck_users == 0))) { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + (1 << 7), (enable << 7)); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 510); + if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP || + mode == CLS_H_HIFI || mode == CLS_H_LP) + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_3, + 0x02, 0x00); + + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_2, + 0xFF, 0x3A); + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); + } + dev_dbg(component->dev, "%s: buck_users %d, enable %d, mode: %s\n", + __func__, clsh_d->buck_users, enable, mode_to_str(mode)); +} + +static void wcd_clsh_flyback_ctrl(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + int mode, + bool enable) +{ + /* enable/disable flyback */ + if ((enable && (++clsh_d->flyback_users == 1)) || + (!enable && (--clsh_d->flyback_users == 0))) { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_1, + 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + (1 << 6), (enable << 6)); + /* + * 100us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, 0xE0); + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); + } + dev_dbg(component->dev, "%s: flyback_users %d, enable %d, mode: %s\n", + __func__, clsh_d->flyback_users, enable, mode_to_str(mode)); +} + +/* + * Function: wcd_clsh_set_hph_mode + * Params: soc component, hph mode class + * Description: + * This function updates class H mode configuration based on + * the input mode. + */ +void wcd_clsh_set_hph_mode(struct snd_soc_component *component, + int mode) +{ + u8 val = 0; + + switch (mode) { + case CLS_H_NORMAL: + val = 0x00; + break; + case CLS_AB: + case CLS_H_ULP: + val = 0x0C; + break; + case CLS_AB_HIFI: + case CLS_H_HIFI: + val = 0x08; + break; + case CLS_H_LP: + case CLS_H_LOHIFI: + case CLS_AB_LP: + case CLS_AB_LOHIFI: + val = 0x04; + break; + default: + dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode); + return; + }; + + snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val); +} +EXPORT_SYMBOL(wcd_clsh_set_hph_mode); + +static void wcd_clsh_set_flyback_current(struct snd_soc_component *component, + int mode) +{ + snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF, + 0x0F, 0x0A); + snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF, + 0xF0, 0xA0); + /* Sleep needed to avoid click and pop as per HW requirement */ + usleep_range(100, 110); +} + +static void wcd_clsh_set_buck_regulator_mode( + struct snd_soc_component *component, + int mode) +{ + snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES, + 0x02, 0x00); +} + +static void wcd_clsh_state_ear_aux(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); +} + +static void wcd_clsh_state_hph_aux(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); +} + +static void wcd_clsh_state_hph_ear(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); +} + +static void wcd_clsh_state_hph_st(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); +} + +static void wcd_clsh_state_hph_r(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); + + if (mode == CLS_H_NORMAL) { + dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + wcd_clsh_set_buck_regulator_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_force_iq_ctl(component, mode, true); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_hph_mode(component, mode); + } else { + wcd_clsh_set_hph_mode(component, CLS_H_NORMAL); + + /* buck and flyback set to default mode and disable */ + wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_l(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); + + if (mode == CLS_H_NORMAL) { + dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + wcd_clsh_set_buck_regulator_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_force_iq_ctl(component, mode, true); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_hph_mode(component, mode); + } else { + wcd_clsh_set_hph_mode(component, CLS_H_NORMAL); + + /* set buck and flyback to Default Mode */ + wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_aux(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), is_enable ? "enable" : "disable"); + + if (is_enable) { + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + } else { + wcd_clsh_buck_ctrl(component, clsh_d, mode, false); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, false); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_ear(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (is_enable) { + wcd_clsh_set_buck_regulator_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_force_iq_ctl(component, mode, true); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_hph_mode(component, mode); + } else { + wcd_clsh_set_hph_mode(component, CLS_H_NORMAL); + + /* set buck and flyback to Default Mode */ + wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_err(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + char msg[128]; + + dev_err(component->dev, + "%s Wrong request for class H state machine requested to %s %s\n", + __func__, is_enable ? "enable" : "disable", + state_to_str(req_state, msg, sizeof(msg))); +} + +/* + * Function: wcd_clsh_is_state_valid + * Params: state + * Description: + * Provides information on valid states of Class H configuration + */ +static bool wcd_clsh_is_state_valid(u8 state) +{ + switch (state) { + case WCD_CLSH_STATE_IDLE: + case WCD_CLSH_STATE_EAR: + case WCD_CLSH_STATE_HPHL: + case WCD_CLSH_STATE_HPHR: + case WCD_CLSH_STATE_HPH_ST: + case WCD_CLSH_STATE_AUX: + case WCD_CLSH_STATE_HPHL_AUX: + case WCD_CLSH_STATE_HPHR_AUX: + case WCD_CLSH_STATE_HPH_ST_AUX: + case WCD_CLSH_STATE_EAR_AUX: + case WCD_CLSH_STATE_HPHL_EAR: + case WCD_CLSH_STATE_HPHR_EAR: + case WCD_CLSH_STATE_HPH_ST_EAR: + return true; + default: + return false; + }; +} + +/* + * Function: wcd_cls_h_fsm + * Params: component, cdc_clsh_d, req_state, req_type, clsh_event + * Description: + * This function handles PRE DAC and POST DAC conditions of different devices + * and updates class H configuration of different combination of devices + * based on validity of their states. cdc_clsh_d will contain current + * class h state information + */ +void wcd_cls_h_fsm(struct snd_soc_component *component, + struct wcd_clsh_cdc_info *cdc_clsh_d, + u8 clsh_event, u8 req_state, + int int_mode) +{ + u8 old_state, new_state; + char msg0[128], msg1[128]; + + switch (clsh_event) { + case WCD_CLSH_EVENT_PRE_DAC: + old_state = cdc_clsh_d->state; + new_state = old_state | req_state; + + if (!wcd_clsh_is_state_valid(new_state)) { + dev_err(component->dev, + "%s: Class-H not a valid new state: %s\n", + __func__, + state_to_str(new_state, msg0, sizeof(msg0))); + return; + } + if (new_state == old_state) { + dev_err(component->dev, + "%s: Class-H already in requested state: %s\n", + __func__, + state_to_str(new_state, msg0, sizeof(msg0))); + return; + } + cdc_clsh_d->state = new_state; + wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode); + (*clsh_state_fp[new_state]) (component, cdc_clsh_d, req_state, + CLSH_REQ_ENABLE, int_mode); + dev_dbg(component->dev, + "%s: ClassH state transition from %s to %s\n", + __func__, state_to_str(old_state, msg0, sizeof(msg0)), + state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1))); + break; + case WCD_CLSH_EVENT_POST_PA: + old_state = cdc_clsh_d->state; + new_state = old_state & (~req_state); + if (new_state < NUM_CLSH_STATES) { + if (!wcd_clsh_is_state_valid(old_state)) { + dev_err(component->dev, + "%s:Invalid old state:%s\n", + __func__, + state_to_str(old_state, msg0, + sizeof(msg0))); + return; + } + if (new_state == old_state) { + dev_err(component->dev, + "%s: Class-H already in requested state: %s\n", + __func__, + state_to_str(new_state, msg0, + sizeof(msg0))); + return; + } + (*clsh_state_fp[old_state]) (component, cdc_clsh_d, + req_state, CLSH_REQ_DISABLE, + int_mode); + cdc_clsh_d->state = new_state; + wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE); + dev_dbg(component->dev, "%s: ClassH state transition from %s to %s\n", + __func__, state_to_str(old_state, msg0, + sizeof(msg0)), + state_to_str(cdc_clsh_d->state, msg1, + sizeof(msg1))); + } + break; + }; +} +EXPORT_SYMBOL(wcd_cls_h_fsm); + +/* + * wcd_cls_h_init: Called to init clsh info + * + * @clsh: pointer for clsh state information. + */ +void wcd_cls_h_init(struct wcd_clsh_cdc_info *clsh) +{ + int i; + + clsh->state = WCD_CLSH_STATE_IDLE; + + for (i = 0; i < NUM_CLSH_STATES; i++) + clsh_state_fp[i] = wcd_clsh_state_err; + + clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear; + clsh_state_fp[WCD_CLSH_STATE_HPHL] = wcd_clsh_state_hph_l; + clsh_state_fp[WCD_CLSH_STATE_HPHR] = wcd_clsh_state_hph_r; + clsh_state_fp[WCD_CLSH_STATE_HPH_ST] = wcd_clsh_state_hph_st; + clsh_state_fp[WCD_CLSH_STATE_AUX] = wcd_clsh_state_aux; + clsh_state_fp[WCD_CLSH_STATE_HPHL_AUX] = wcd_clsh_state_hph_aux; + clsh_state_fp[WCD_CLSH_STATE_HPHR_AUX] = wcd_clsh_state_hph_aux; + clsh_state_fp[WCD_CLSH_STATE_HPH_ST_AUX] = + wcd_clsh_state_hph_aux; + clsh_state_fp[WCD_CLSH_STATE_EAR_AUX] = wcd_clsh_state_ear_aux; + clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] = wcd_clsh_state_hph_ear; + clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] = wcd_clsh_state_hph_ear; + clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] = wcd_clsh_state_hph_ear; + /* Set interpolaotr modes to NONE */ + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE); + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE); + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE); + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_AUX, CLS_NONE); + clsh->flyback_users = 0; + clsh->buck_users = 0; +} +EXPORT_SYMBOL(wcd_cls_h_init); + +MODULE_DESCRIPTION("WCD Class-H Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-mgr.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-mgr.c new file mode 100644 index 0000000000..a6acc2da62 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-mgr.c @@ -0,0 +1,1327 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd-dsp-utils.h" + +/* Forward declarations */ +static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type); + +/* Component related macros */ +#define WDSP_GET_COMPONENT(wdsp, x) ((x >= WDSP_CMPNT_TYPE_MAX || x < 0) ? \ + NULL : (&(wdsp->cmpnts[x]))) +#define WDSP_GET_CMPNT_TYPE_STR(x) wdsp_get_cmpnt_type_string(x) + +/* + * These #defines indicate the bit number in status field + * for each of the status. If bit is set, it indicates + * the status as done, else if bit is not set, it indicates + * the status is either failed or not done. + */ +#define WDSP_STATUS_INITIALIZED BIT(0) +#define WDSP_STATUS_CODE_DLOADED BIT(1) +#define WDSP_STATUS_DATA_DLOADED BIT(2) +#define WDSP_STATUS_BOOTED BIT(3) + +/* Helper macros for printing wdsp messages */ +#define WDSP_ERR(wdsp, fmt, ...) \ + dev_err(wdsp->mdev, "%s: " fmt "\n", __func__, ##__VA_ARGS__) +#define WDSP_DBG(wdsp, fmt, ...) \ + dev_dbg(wdsp->mdev, "%s: " fmt "\n", __func__, ##__VA_ARGS__) + +/* Helper macros for locking */ +#define WDSP_MGR_MUTEX_LOCK(wdsp, lock) \ +{ \ + WDSP_DBG(wdsp, "mutex_lock(%s)", \ + __stringify_1(lock)); \ + mutex_lock(&lock); \ +} + +#define WDSP_MGR_MUTEX_UNLOCK(wdsp, lock) \ +{ \ + WDSP_DBG(wdsp, "mutex_unlock(%s)", \ + __stringify_1(lock)); \ + mutex_unlock(&lock); \ +} + +/* Helper macros for using status mask */ +#define WDSP_SET_STATUS(wdsp, state) \ +{ \ + wdsp->status |= state; \ + WDSP_DBG(wdsp, "set 0x%lx, new_state = 0x%x", \ + state, wdsp->status); \ +} + +#define WDSP_CLEAR_STATUS(wdsp, state) \ +{ \ + wdsp->status &= (~state); \ + WDSP_DBG(wdsp, "clear 0x%lx, new_state = 0x%x", \ + state, wdsp->status); \ +} + +#define WDSP_STATUS_IS_SET(wdsp, state) (wdsp->status & state) + +/* SSR relate status macros */ +#define WDSP_SSR_STATUS_WDSP_READY BIT(0) +#define WDSP_SSR_STATUS_CDC_READY BIT(1) +#define WDSP_SSR_STATUS_READY \ + (WDSP_SSR_STATUS_WDSP_READY | WDSP_SSR_STATUS_CDC_READY) +#define WDSP_SSR_READY_WAIT_TIMEOUT (10 * HZ) + +enum wdsp_ssr_type { + + /* Init value, indicates there is no SSR in progress */ + WDSP_SSR_TYPE_NO_SSR = 0, + + /* + * Indicates WDSP crashed. The manager driver internally + * decides when to perform WDSP restart based on the + * users of wdsp. Hence there is no explicit WDSP_UP. + */ + WDSP_SSR_TYPE_WDSP_DOWN, + + /* Indicates codec hardware is down */ + WDSP_SSR_TYPE_CDC_DOWN, + + /* Indicates codec hardware is up, trigger to restart WDSP */ + WDSP_SSR_TYPE_CDC_UP, +}; + +struct wdsp_cmpnt { + + /* OF node of the phandle */ + struct device_node *np; + + /* + * Child component's dev_name, should be set in DT for the child's + * phandle if child's dev->of_node does not match the phandle->of_node + */ + const char *cdev_name; + + /* Child component's device node */ + struct device *cdev; + + /* Private data that component may want back on callbacks */ + void *priv_data; + + /* Child ops */ + struct wdsp_cmpnt_ops *ops; +}; + +struct wdsp_ramdump_data { + + /* Ramdump device */ + void *rd_dev; + + /* DMA address of the dump */ + dma_addr_t rd_addr; + + /* Virtual address of the dump */ + void *rd_v_addr; + + /* Data provided through error interrupt */ + struct wdsp_err_signal_arg err_data; +}; + +struct wdsp_mgr_priv { + + /* Manager driver's struct device pointer */ + struct device *mdev; + + /* Match struct for component framework */ + struct component_match *match; + + /* Manager's ops/function callbacks */ + struct wdsp_mgr_ops *ops; + + /* Array to store information for all expected components */ + struct wdsp_cmpnt cmpnts[WDSP_CMPNT_TYPE_MAX]; + + /* The filename of image to be downloaded */ + const char *img_fname; + + /* Keeps track of current state of manager driver */ + u32 status; + + /* Work to load the firmware image after component binding */ + struct work_struct load_fw_work; + + /* List of segments in image to be downloaded */ + struct list_head *seg_list; + + /* Base address of the image in memory */ + u32 base_addr; + + /* Instances using dsp */ + int dsp_users; + + /* Lock for serializing ops called by components */ + struct mutex api_mutex; + + struct wdsp_ramdump_data dump_data; + + /* SSR related */ + enum wdsp_ssr_type ssr_type; + struct mutex ssr_mutex; + struct work_struct ssr_work; + u16 ready_status; + struct completion ready_compl; + + /* Debugfs related */ + struct dentry *entry; + bool panic_on_error; +}; + +static char *wdsp_get_ssr_type_string(enum wdsp_ssr_type type) +{ + switch (type) { + case WDSP_SSR_TYPE_NO_SSR: + return "NO_SSR"; + case WDSP_SSR_TYPE_WDSP_DOWN: + return "WDSP_DOWN"; + case WDSP_SSR_TYPE_CDC_DOWN: + return "CDC_DOWN"; + case WDSP_SSR_TYPE_CDC_UP: + return "CDC_UP"; + default: + pr_err("%s: Invalid ssr_type %d\n", + __func__, type); + return "Invalid"; + } +} + +static char *wdsp_get_cmpnt_type_string(enum wdsp_cmpnt_type type) +{ + switch (type) { + case WDSP_CMPNT_CONTROL: + return "control"; + case WDSP_CMPNT_IPC: + return "ipc"; + case WDSP_CMPNT_TRANSPORT: + return "transport"; + default: + pr_err("%s: Invalid component type %d\n", + __func__, type); + return "Invalid"; + } +} + +static void __wdsp_clr_ready_locked(struct wdsp_mgr_priv *wdsp, + u16 value) +{ + wdsp->ready_status &= ~(value); + WDSP_DBG(wdsp, "ready_status = 0x%x", wdsp->ready_status); +} + +static void __wdsp_set_ready_locked(struct wdsp_mgr_priv *wdsp, + u16 value, bool mark_complete) +{ + wdsp->ready_status |= value; + WDSP_DBG(wdsp, "ready_status = 0x%x", wdsp->ready_status); + + if (mark_complete && + wdsp->ready_status == WDSP_SSR_STATUS_READY) { + WDSP_DBG(wdsp, "marking ready completion"); + complete(&wdsp->ready_compl); + } +} + +static void wdsp_broadcast_event_upseq(struct wdsp_mgr_priv *wdsp, + enum wdsp_event_type event, + void *data) +{ + struct wdsp_cmpnt *cmpnt; + int i; + + for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) { + cmpnt = WDSP_GET_COMPONENT(wdsp, i); + if (cmpnt && cmpnt->ops && cmpnt->ops->event_handler) + cmpnt->ops->event_handler(cmpnt->cdev, cmpnt->priv_data, + event, data); + } +} + +static void wdsp_broadcast_event_downseq(struct wdsp_mgr_priv *wdsp, + enum wdsp_event_type event, + void *data) +{ + struct wdsp_cmpnt *cmpnt; + int i; + + for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) { + cmpnt = WDSP_GET_COMPONENT(wdsp, i); + if (cmpnt && cmpnt->ops && cmpnt->ops->event_handler) + cmpnt->ops->event_handler(cmpnt->cdev, cmpnt->priv_data, + event, data); + } +} + +static int wdsp_unicast_event(struct wdsp_mgr_priv *wdsp, + enum wdsp_cmpnt_type type, + enum wdsp_event_type event, + void *data) +{ + struct wdsp_cmpnt *cmpnt; + int ret; + + cmpnt = WDSP_GET_COMPONENT(wdsp, type); + if (cmpnt && cmpnt->ops && cmpnt->ops->event_handler) { + ret = cmpnt->ops->event_handler(cmpnt->cdev, cmpnt->priv_data, + event, data); + } else { + WDSP_ERR(wdsp, "not valid event_handler for %s", + WDSP_GET_CMPNT_TYPE_STR(type)); + ret = -EINVAL; + } + + return ret; +} + +static void wdsp_deinit_components(struct wdsp_mgr_priv *wdsp) +{ + struct wdsp_cmpnt *cmpnt; + int i; + + for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) { + cmpnt = WDSP_GET_COMPONENT(wdsp, i); + if (cmpnt && cmpnt->ops && cmpnt->ops->deinit) + cmpnt->ops->deinit(cmpnt->cdev, cmpnt->priv_data); + } +} + +static int wdsp_init_components(struct wdsp_mgr_priv *wdsp) +{ + struct wdsp_cmpnt *cmpnt; + int fail_idx = WDSP_CMPNT_TYPE_MAX; + int i, ret = 0; + + for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) { + + cmpnt = WDSP_GET_COMPONENT(wdsp, i); + + /* Init is allowed to be NULL */ + if (!cmpnt->ops || !cmpnt->ops->init) + continue; + ret = cmpnt->ops->init(cmpnt->cdev, cmpnt->priv_data); + if (ret) { + WDSP_ERR(wdsp, "Init failed (%d) for component %s", + ret, WDSP_GET_CMPNT_TYPE_STR(i)); + fail_idx = i; + break; + } + } + + if (fail_idx < WDSP_CMPNT_TYPE_MAX) { + /* Undo init for already initialized components */ + for (i = fail_idx - 1; i >= 0; i--) { + struct wdsp_cmpnt *cmpnt = WDSP_GET_COMPONENT(wdsp, i); + + if (cmpnt->ops && cmpnt->ops->deinit) + cmpnt->ops->deinit(cmpnt->cdev, + cmpnt->priv_data); + } + } else { + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_INIT, NULL); + } + + return ret; +} + +static int wdsp_load_each_segment(struct wdsp_mgr_priv *wdsp, + struct wdsp_img_segment *seg) +{ + struct wdsp_img_section img_section; + int ret; + + WDSP_DBG(wdsp, + "base_addr 0x%x, split_fname %s, load_addr 0x%x, size 0x%zx", + wdsp->base_addr, seg->split_fname, seg->load_addr, seg->size); + + if (seg->load_addr < wdsp->base_addr) { + WDSP_ERR(wdsp, "Invalid addr 0x%x, base_addr = 0x%x", + seg->load_addr, wdsp->base_addr); + return -EINVAL; + } + + img_section.addr = seg->load_addr - wdsp->base_addr; + img_section.size = seg->size; + img_section.data = seg->data; + + ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_TRANSPORT, + WDSP_EVENT_DLOAD_SECTION, + &img_section); + if (ret < 0) + WDSP_ERR(wdsp, + "Failed, err = %d for base_addr = 0x%x split_fname = %s, load_addr = 0x%x, size = 0x%zx", + ret, wdsp->base_addr, seg->split_fname, + seg->load_addr, seg->size); + return ret; +} + +static int wdsp_download_segments(struct wdsp_mgr_priv *wdsp, + unsigned int type) +{ + struct wdsp_cmpnt *ctl; + struct wdsp_img_segment *seg = NULL; + enum wdsp_event_type pre, post; + long status; + int ret; + + ctl = WDSP_GET_COMPONENT(wdsp, WDSP_CMPNT_CONTROL); + + if (type == WDSP_ELF_FLAG_RE) { + pre = WDSP_EVENT_PRE_DLOAD_CODE; + post = WDSP_EVENT_POST_DLOAD_CODE; + status = WDSP_STATUS_CODE_DLOADED; + } else if (type == WDSP_ELF_FLAG_WRITE) { + pre = WDSP_EVENT_PRE_DLOAD_DATA; + post = WDSP_EVENT_POST_DLOAD_DATA; + status = WDSP_STATUS_DATA_DLOADED; + } else { + WDSP_ERR(wdsp, "Invalid type %u", type); + return -EINVAL; + } + + ret = wdsp_get_segment_list(ctl->cdev, wdsp->img_fname, + type, wdsp->seg_list, &wdsp->base_addr); + if (ret < 0 || + list_empty(wdsp->seg_list)) { + WDSP_ERR(wdsp, "Error %d to get image segments for type %d", + ret, type); + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_DLOAD_FAILED, + NULL); + goto done; + } + + /* Notify all components that image is about to be downloaded */ + wdsp_broadcast_event_upseq(wdsp, pre, NULL); + + /* Go through the list of segments and download one by one */ + list_for_each_entry(seg, wdsp->seg_list, list) { + ret = wdsp_load_each_segment(wdsp, seg); + if (ret) + goto dload_error; + } + + /* Flush the list before setting status and notifying components */ + wdsp_flush_segment_list(wdsp->seg_list); + + WDSP_SET_STATUS(wdsp, status); + + /* Notify all components that image is downloaded */ + wdsp_broadcast_event_downseq(wdsp, post, NULL); +done: + return ret; + +dload_error: + wdsp_flush_segment_list(wdsp->seg_list); + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_DLOAD_FAILED, NULL); + return ret; +} + +static int wdsp_init_and_dload_code_sections(struct wdsp_mgr_priv *wdsp) +{ + int ret; + bool is_initialized; + + is_initialized = WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_INITIALIZED); + + if (!is_initialized) { + /* Components are not initialized yet, initialize them */ + ret = wdsp_init_components(wdsp); + if (ret < 0) { + WDSP_ERR(wdsp, "INIT failed, err = %d", ret); + goto done; + } + WDSP_SET_STATUS(wdsp, WDSP_STATUS_INITIALIZED); + } + + /* Download the read-execute sections of image */ + ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_RE); + if (ret < 0) { + WDSP_ERR(wdsp, "Error %d to download code sections", ret); + goto done; + } +done: + return ret; +} + +static void wdsp_load_fw_image(struct work_struct *work) +{ + struct wdsp_mgr_priv *wdsp; + int ret; + + wdsp = container_of(work, struct wdsp_mgr_priv, load_fw_work); + if (!wdsp) { + pr_err("%s: Invalid private_data\n", __func__); + return; + } + + ret = wdsp_init_and_dload_code_sections(wdsp); + if (ret < 0) + WDSP_ERR(wdsp, "dload code sections failed, err = %d", ret); +} + +static int wdsp_enable_dsp(struct wdsp_mgr_priv *wdsp) +{ + int ret; + + /* Make sure wdsp is in good state */ + if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_CODE_DLOADED)) { + WDSP_ERR(wdsp, "WDSP in invalid state 0x%x", wdsp->status); + return -EINVAL; + } + + /* + * Acquire SSR mutex lock to make sure enablement of DSP + * does not race with SSR handling. + */ + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex); + /* Download the read-write sections of image */ + ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_WRITE); + if (ret < 0) { + WDSP_ERR(wdsp, "Data section download failed, err = %d", ret); + goto done; + } + + wdsp_broadcast_event_upseq(wdsp, WDSP_EVENT_PRE_BOOTUP, NULL); + + ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL, + WDSP_EVENT_DO_BOOT, NULL); + if (ret < 0) { + WDSP_ERR(wdsp, "Failed to boot dsp, err = %d", ret); + WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED); + goto done; + } + + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_BOOTUP, NULL); + WDSP_SET_STATUS(wdsp, WDSP_STATUS_BOOTED); +done: + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); + return ret; +} + +static int wdsp_disable_dsp(struct wdsp_mgr_priv *wdsp) +{ + int ret; + + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex); + + /* + * If Disable happened while SSR is in progress, then set the SSR + * ready status indicating WDSP is now ready. Ignore the disable + * event here and let the SSR handler go through shutdown. + */ + if (wdsp->ssr_type != WDSP_SSR_TYPE_NO_SSR) { + __wdsp_set_ready_locked(wdsp, WDSP_SSR_STATUS_WDSP_READY, true); + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); + return 0; + } + + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); + + /* Make sure wdsp is in good state */ + if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_BOOTED)) { + WDSP_ERR(wdsp, "wdsp in invalid state 0x%x", wdsp->status); + ret = -EINVAL; + goto done; + } + + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_PRE_SHUTDOWN, NULL); + ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL, + WDSP_EVENT_DO_SHUTDOWN, NULL); + if (ret < 0) { + WDSP_ERR(wdsp, "Failed to shutdown dsp, err = %d", ret); + goto done; + } + + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_SHUTDOWN, NULL); + WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_BOOTED); + + /* Data sections are to be downloaded per boot */ + WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED); +done: + return ret; +} + +static int wdsp_register_cmpnt_ops(struct device *wdsp_dev, + struct device *cdev, + void *priv_data, + struct wdsp_cmpnt_ops *ops) +{ + struct wdsp_mgr_priv *wdsp; + struct wdsp_cmpnt *cmpnt; + int i, ret; + + if (!wdsp_dev || !cdev || !ops) + return -EINVAL; + + wdsp = dev_get_drvdata(wdsp_dev); + + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->api_mutex); + + for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) { + cmpnt = WDSP_GET_COMPONENT(wdsp, i); + if ((cdev->of_node && cdev->of_node == cmpnt->np) || + (cmpnt->cdev_name && + !strcmp(dev_name(cdev), cmpnt->cdev_name))) { + break; + } + } + + if (i == WDSP_CMPNT_TYPE_MAX) { + WDSP_ERR(wdsp, "Failed to register component dev %s", + dev_name(cdev)); + ret = -EINVAL; + goto done; + } + + cmpnt->cdev = cdev; + cmpnt->ops = ops; + cmpnt->priv_data = priv_data; +done: + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->api_mutex); + return 0; +} + +static struct device *wdsp_get_dev_for_cmpnt(struct device *wdsp_dev, + enum wdsp_cmpnt_type type) +{ + struct wdsp_mgr_priv *wdsp; + struct wdsp_cmpnt *cmpnt; + + if (!wdsp_dev || type >= WDSP_CMPNT_TYPE_MAX) + return NULL; + + wdsp = dev_get_drvdata(wdsp_dev); + cmpnt = WDSP_GET_COMPONENT(wdsp, type); + + return cmpnt->cdev; +} + +static int wdsp_get_devops_for_cmpnt(struct device *wdsp_dev, + enum wdsp_cmpnt_type type, + void *data) +{ + struct wdsp_mgr_priv *wdsp; + int ret = 0; + + if (!wdsp_dev || type >= WDSP_CMPNT_TYPE_MAX) + return -EINVAL; + + wdsp = dev_get_drvdata(wdsp_dev); + ret = wdsp_unicast_event(wdsp, type, + WDSP_EVENT_GET_DEVOPS, data); + if (ret) + WDSP_ERR(wdsp, "get_dev_ops failed for cmpnt type %d", + type); + return ret; +} + +static void wdsp_collect_ramdumps(struct wdsp_mgr_priv *wdsp) +{ + struct wdsp_img_section img_section; + struct wdsp_err_signal_arg *data = &wdsp->dump_data.err_data; + struct ramdump_segment rd_seg; + int ret = 0; + + if (wdsp->ssr_type != WDSP_SSR_TYPE_WDSP_DOWN || + !data->mem_dumps_enabled) { + WDSP_DBG(wdsp, "cannot dump memory, ssr_type %s, dumps %s", + wdsp_get_ssr_type_string(wdsp->ssr_type), + !(data->mem_dumps_enabled) ? "disabled" : "enabled"); + goto done; + } + + if (data->dump_size == 0 || + data->remote_start_addr < wdsp->base_addr) { + WDSP_ERR(wdsp, "Invalid start addr 0x%x or dump_size 0x%zx", + data->remote_start_addr, data->dump_size); + goto done; + } + + if (!wdsp->dump_data.rd_dev) { + WDSP_ERR(wdsp, "Ramdump device is not setup"); + goto done; + } + + WDSP_DBG(wdsp, "base_addr 0x%x, dump_start_addr 0x%x, dump_size 0x%zx", + wdsp->base_addr, data->remote_start_addr, data->dump_size); + + /* Allocate memory for dumps */ + wdsp->dump_data.rd_v_addr = dma_alloc_coherent(wdsp->mdev, + data->dump_size, + &wdsp->dump_data.rd_addr, + GFP_KERNEL); + if (!wdsp->dump_data.rd_v_addr) + goto done; + + img_section.addr = data->remote_start_addr - wdsp->base_addr; + img_section.size = data->dump_size; + img_section.data = wdsp->dump_data.rd_v_addr; + + ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_TRANSPORT, + WDSP_EVENT_READ_SECTION, + &img_section); + if (ret < 0) { + WDSP_ERR(wdsp, "Failed to read dumps, size 0x%zx at addr 0x%x", + img_section.size, img_section.addr); + goto err_read_dumps; + } + + /* + * If panic_on_error flag is explicitly set through the debugfs, + * then cause a BUG here to aid debugging. + */ + BUG_ON(wdsp->panic_on_error); + + rd_seg.address = (unsigned long) wdsp->dump_data.rd_v_addr; + rd_seg.size = img_section.size; + rd_seg.v_address = wdsp->dump_data.rd_v_addr; + + ret = do_ramdump(wdsp->dump_data.rd_dev, &rd_seg, 1); + if (ret < 0) + WDSP_ERR(wdsp, "do_ramdump failed with error %d", ret); + +err_read_dumps: + dma_free_coherent(wdsp->mdev, data->dump_size, + wdsp->dump_data.rd_v_addr, wdsp->dump_data.rd_addr); +done: + return; +} + +static void wdsp_ssr_work_fn(struct work_struct *work) +{ + struct wdsp_mgr_priv *wdsp; + int ret; + + wdsp = container_of(work, struct wdsp_mgr_priv, ssr_work); + if (!wdsp) { + pr_err("%s: Invalid private_data\n", __func__); + return; + } + + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex); + + /* Issue ramdumps and shutdown only if DSP is currently booted */ + if (WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_BOOTED)) { + wdsp_collect_ramdumps(wdsp); + ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_CONTROL, + WDSP_EVENT_DO_SHUTDOWN, NULL); + if (ret < 0) + WDSP_ERR(wdsp, "Failed WDSP shutdown, err = %d", ret); + + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_SHUTDOWN, + NULL); + WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_BOOTED); + } + + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); + ret = wait_for_completion_timeout(&wdsp->ready_compl, + WDSP_SSR_READY_WAIT_TIMEOUT); + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex); + if (ret == 0) { + WDSP_ERR(wdsp, "wait_for_ready timed out, status = 0x%x", + wdsp->ready_status); + goto done; + } + + /* Data sections are to downloaded per WDSP boot */ + WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_DATA_DLOADED); + + /* + * Even though code section could possible be retained on DSP + * crash, go ahead and still re-download just to avoid any + * memory corruption from previous crash. + */ + WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_CODE_DLOADED); + + /* If codec restarted, then all components must be re-initialized */ + if (wdsp->ssr_type == WDSP_SSR_TYPE_CDC_UP) { + wdsp_deinit_components(wdsp); + WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_INITIALIZED); + } + + ret = wdsp_init_and_dload_code_sections(wdsp); + if (ret < 0) { + WDSP_ERR(wdsp, "Failed to dload code sections err = %d", + ret); + goto done; + } + + /* SSR handling is finished, mark SSR type as NO_SSR */ + wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR; +done: + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); +} + +static int wdsp_ssr_handler(struct wdsp_mgr_priv *wdsp, void *arg, + enum wdsp_ssr_type ssr_type) +{ + enum wdsp_ssr_type current_ssr_type; + struct wdsp_err_signal_arg *err_data; + + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex); + + current_ssr_type = wdsp->ssr_type; + WDSP_DBG(wdsp, "Current ssr_type %s, handling ssr_type %s", + wdsp_get_ssr_type_string(current_ssr_type), + wdsp_get_ssr_type_string(ssr_type)); + wdsp->ssr_type = ssr_type; + + if (arg) { + err_data = (struct wdsp_err_signal_arg *) arg; + memcpy(&wdsp->dump_data.err_data, err_data, + sizeof(*err_data)); + } else { + memset(&wdsp->dump_data.err_data, 0, + sizeof(wdsp->dump_data.err_data)); + } + + switch (ssr_type) { + + case WDSP_SSR_TYPE_WDSP_DOWN: + __wdsp_clr_ready_locked(wdsp, WDSP_SSR_STATUS_WDSP_READY); + wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_PRE_SHUTDOWN, + NULL); + reinit_completion(&wdsp->ready_compl); + schedule_work(&wdsp->ssr_work); + break; + + case WDSP_SSR_TYPE_CDC_DOWN: + __wdsp_clr_ready_locked(wdsp, WDSP_SSR_STATUS_CDC_READY); + /* + * If DSP is booted when CDC_DOWN is received, it needs + * to be shutdown. + */ + if (WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_BOOTED)) { + __wdsp_clr_ready_locked(wdsp, + WDSP_SSR_STATUS_WDSP_READY); + wdsp_broadcast_event_downseq(wdsp, + WDSP_EVENT_PRE_SHUTDOWN, + NULL); + } + reinit_completion(&wdsp->ready_compl); + schedule_work(&wdsp->ssr_work); + break; + + case WDSP_SSR_TYPE_CDC_UP: + __wdsp_set_ready_locked(wdsp, WDSP_SSR_STATUS_CDC_READY, true); + break; + + default: + WDSP_ERR(wdsp, "undefined ssr_type %d\n", ssr_type); + /* Revert back the ssr_type for undefined events */ + wdsp->ssr_type = current_ssr_type; + break; + } + + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static int __wdsp_dbg_dump_locked(struct wdsp_mgr_priv *wdsp, void *arg) +{ + struct wdsp_err_signal_arg *err_data; + int ret = 0; + + /* If there is no SSR, set the SSR type to collect ramdumps */ + if (wdsp->ssr_type == WDSP_SSR_TYPE_NO_SSR) { + wdsp->ssr_type = WDSP_SSR_TYPE_WDSP_DOWN; + } else { + WDSP_DBG(wdsp, "SSR handling is running, skip debug ramdump"); + ret = 0; + goto done; + } + + if (arg) { + err_data = (struct wdsp_err_signal_arg *) arg; + memcpy(&wdsp->dump_data.err_data, err_data, + sizeof(*err_data)); + } else { + WDSP_DBG(wdsp, "Invalid input, arg is NULL"); + ret = -EINVAL; + goto done; + } + wdsp_collect_ramdumps(wdsp); + wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR; +done: + return ret; +} +static int wdsp_debug_dump_handler(struct wdsp_mgr_priv *wdsp, void *arg) +{ + int ret = 0; + + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex); + ret = __wdsp_dbg_dump_locked(wdsp, arg); + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); + + return ret; +} +#else +static int __wdsp_dbg_dump_locked(struct wdsp_mgr_priv *wdsp, void *arg) +{ + return 0; +} + +static int wdsp_debug_dump_handler(struct wdsp_mgr_priv *wdsp, void *arg) +{ + return 0; +} +#endif + +static int wdsp_signal_handler(struct device *wdsp_dev, + enum wdsp_signal signal, void *arg) +{ + struct wdsp_mgr_priv *wdsp; + int ret; + + if (!wdsp_dev) + return -EINVAL; + + wdsp = dev_get_drvdata(wdsp_dev); + +#ifdef CONFIG_DEBUG_FS + if (signal != WDSP_DEBUG_DUMP_INTERNAL) + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->api_mutex); +#else + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->api_mutex); +#endif + + WDSP_DBG(wdsp, "Raised signal %d", signal); + + switch (signal) { + case WDSP_IPC1_INTR: + ret = wdsp_unicast_event(wdsp, WDSP_CMPNT_IPC, + WDSP_EVENT_IPC1_INTR, NULL); + break; + case WDSP_ERR_INTR: + ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_WDSP_DOWN); + break; + case WDSP_CDC_DOWN_SIGNAL: + ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_CDC_DOWN); + break; + case WDSP_CDC_UP_SIGNAL: + ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_CDC_UP); + break; + case WDSP_DEBUG_DUMP: + ret = wdsp_debug_dump_handler(wdsp, arg); + break; + case WDSP_DEBUG_DUMP_INTERNAL: + ret = __wdsp_dbg_dump_locked(wdsp, arg); + break; + default: + ret = -EINVAL; + break; + } + + if (ret < 0) + WDSP_ERR(wdsp, "handling signal %d failed with error %d", + signal, ret); + +#ifdef CONFIG_DEBUG_FS + if (signal != WDSP_DEBUG_DUMP_INTERNAL) + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->api_mutex); +#else + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->api_mutex); +#endif + + return ret; +} + +static int wdsp_vote_for_dsp(struct device *wdsp_dev, + bool vote) +{ + struct wdsp_mgr_priv *wdsp; + int ret = 0; + + if (!wdsp_dev) + return -EINVAL; + + wdsp = dev_get_drvdata(wdsp_dev); + + WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->api_mutex); + WDSP_DBG(wdsp, "request %s, current users = %d", + vote ? "enable" : "disable", wdsp->dsp_users); + + if (vote) { + wdsp->dsp_users++; + if (wdsp->dsp_users == 1) + ret = wdsp_enable_dsp(wdsp); + } else { + if (wdsp->dsp_users == 0) + goto done; + + wdsp->dsp_users--; + if (wdsp->dsp_users == 0) + ret = wdsp_disable_dsp(wdsp); + } + + if (ret < 0) + WDSP_DBG(wdsp, "wdsp %s failed, err = %d", + vote ? "enable" : "disable", ret); + +done: + WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->api_mutex); + return ret; +} + +static int wdsp_suspend(struct device *wdsp_dev) +{ + struct wdsp_mgr_priv *wdsp; + int rc = 0, i; + + if (!wdsp_dev) { + pr_err("%s: Invalid handle to device\n", __func__); + return -EINVAL; + } + + wdsp = dev_get_drvdata(wdsp_dev); + + for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) { + rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_SUSPEND, NULL); + if (rc < 0) { + WDSP_ERR(wdsp, "component %s failed to suspend\n", + WDSP_GET_CMPNT_TYPE_STR(i)); + break; + } + } + + return rc; +} + +static int wdsp_resume(struct device *wdsp_dev) +{ + struct wdsp_mgr_priv *wdsp; + int rc = 0, i; + + if (!wdsp_dev) { + pr_err("%s: Invalid handle to device\n", __func__); + return -EINVAL; + } + + wdsp = dev_get_drvdata(wdsp_dev); + + for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) { + rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_RESUME, NULL); + if (rc < 0) { + WDSP_ERR(wdsp, "component %s failed to resume\n", + WDSP_GET_CMPNT_TYPE_STR(i)); + break; + } + } + + return rc; +} + +static struct wdsp_mgr_ops wdsp_ops = { + .register_cmpnt_ops = wdsp_register_cmpnt_ops, + .get_dev_for_cmpnt = wdsp_get_dev_for_cmpnt, + .get_devops_for_cmpnt = wdsp_get_devops_for_cmpnt, + .signal_handler = wdsp_signal_handler, + .vote_for_dsp = wdsp_vote_for_dsp, + .suspend = wdsp_suspend, + .resume = wdsp_resume, +}; + +static int wdsp_mgr_compare_of(struct device *dev, void *data) +{ + struct wdsp_cmpnt *cmpnt = data; + + /* + * First try to match based on of_node, if of_node is not + * present, try to match on the dev_name + */ + return ((dev->of_node && dev->of_node == cmpnt->np) || + (cmpnt->cdev_name && + !strcmp(dev_name(dev), cmpnt->cdev_name))); +} + +static void wdsp_mgr_debugfs_init(struct wdsp_mgr_priv *wdsp) +{ + wdsp->entry = debugfs_create_dir("wdsp_mgr", NULL); + if (IS_ERR_OR_NULL(wdsp->entry)) + return; + + debugfs_create_bool("panic_on_error", 0644, + wdsp->entry, &wdsp->panic_on_error); +} + +static void wdsp_mgr_debugfs_remove(struct wdsp_mgr_priv *wdsp) +{ + debugfs_remove_recursive(wdsp->entry); + wdsp->entry = NULL; +} + +static int wdsp_mgr_bind(struct device *dev) +{ + struct wdsp_mgr_priv *wdsp = dev_get_drvdata(dev); + struct wdsp_cmpnt *cmpnt; + int ret, idx; + + wdsp->ops = &wdsp_ops; + + /* Setup ramdump device */ + wdsp->dump_data.rd_dev = create_ramdump_device("wdsp", dev); + if (!wdsp->dump_data.rd_dev) + dev_info(dev, "%s: create_ramdump_device failed\n", __func__); + + ret = component_bind_all(dev, wdsp->ops); + if (ret < 0) { + WDSP_ERR(wdsp, "component_bind_all failed %d\n", ret); + return ret; + } + + /* Make sure all components registered ops */ + for (idx = 0; idx < WDSP_CMPNT_TYPE_MAX; idx++) { + cmpnt = WDSP_GET_COMPONENT(wdsp, idx); + if (!cmpnt->cdev || !cmpnt->ops) { + WDSP_ERR(wdsp, "%s did not register ops\n", + WDSP_GET_CMPNT_TYPE_STR(idx)); + ret = -EINVAL; + component_unbind_all(dev, wdsp->ops); + break; + } + } + + wdsp_mgr_debugfs_init(wdsp); + + /* Schedule the work to download image if binding was successful. */ + if (!ret) + schedule_work(&wdsp->load_fw_work); + + return ret; +} + +static void wdsp_mgr_unbind(struct device *dev) +{ + struct wdsp_mgr_priv *wdsp = dev_get_drvdata(dev); + struct wdsp_cmpnt *cmpnt; + int idx; + + cancel_work_sync(&wdsp->load_fw_work); + + component_unbind_all(dev, wdsp->ops); + + wdsp_mgr_debugfs_remove(wdsp); + + if (wdsp->dump_data.rd_dev) { + destroy_ramdump_device(wdsp->dump_data.rd_dev); + wdsp->dump_data.rd_dev = NULL; + } + + /* Clear all status bits */ + wdsp->status = 0x00; + + /* clean up the components */ + for (idx = 0; idx < WDSP_CMPNT_TYPE_MAX; idx++) { + cmpnt = WDSP_GET_COMPONENT(wdsp, idx); + cmpnt->cdev = NULL; + cmpnt->ops = NULL; + cmpnt->priv_data = NULL; + } +} + +static const struct component_master_ops wdsp_master_ops = { + .bind = wdsp_mgr_bind, + .unbind = wdsp_mgr_unbind, +}; + +static void *wdsp_mgr_parse_phandle(struct wdsp_mgr_priv *wdsp, + int index) +{ + struct device *mdev = wdsp->mdev; + struct device_node *np; + struct wdsp_cmpnt *cmpnt = NULL; + struct of_phandle_args pargs; + u32 value; + int ret; + + ret = of_parse_phandle_with_fixed_args(mdev->of_node, + "qcom,wdsp-components", 1, + index, &pargs); + if (ret) { + WDSP_ERR(wdsp, "parse_phandle at index %d failed %d", + index, ret); + return NULL; + } + + np = pargs.np; + value = pargs.args[0]; + + if (value >= WDSP_CMPNT_TYPE_MAX) { + WDSP_ERR(wdsp, "invalid phandle_arg to of_node %s", np->name); + goto done; + } + + cmpnt = WDSP_GET_COMPONENT(wdsp, value); + if (cmpnt->np || cmpnt->cdev_name) { + WDSP_ERR(wdsp, "cmpnt %d already added", value); + cmpnt = NULL; + goto done; + } + + cmpnt->np = np; + of_property_read_string(np, "qcom,wdsp-cmpnt-dev-name", + &cmpnt->cdev_name); +done: + of_node_put(np); + return cmpnt; +} + +static int wdsp_mgr_parse_dt_entries(struct wdsp_mgr_priv *wdsp) +{ + struct device *dev = wdsp->mdev; + void *match_data; + int ph_idx, ret; + + ret = of_property_read_string(dev->of_node, "qcom,img-filename", + &wdsp->img_fname); + if (ret < 0) { + WDSP_ERR(wdsp, "Reading property %s failed, error = %d", + "qcom,img-filename", ret); + return ret; + } + + ret = of_count_phandle_with_args(dev->of_node, + "qcom,wdsp-components", + NULL); + if (ret == -ENOENT) { + WDSP_ERR(wdsp, "Property %s not defined in DT", + "qcom,wdsp-components"); + goto done; + } else if (ret != WDSP_CMPNT_TYPE_MAX * 2) { + WDSP_ERR(wdsp, "Invalid phandle + arg count %d, expected %d", + ret, WDSP_CMPNT_TYPE_MAX * 2); + ret = -EINVAL; + goto done; + } + + ret = 0; + + for (ph_idx = 0; ph_idx < WDSP_CMPNT_TYPE_MAX; ph_idx++) { + + match_data = wdsp_mgr_parse_phandle(wdsp, ph_idx); + if (!match_data) { + WDSP_ERR(wdsp, "component not found at idx %d", ph_idx); + ret = -EINVAL; + goto done; + } + + component_match_add(dev, &wdsp->match, + wdsp_mgr_compare_of, match_data); + } + +done: + return ret; +} + +static int wdsp_mgr_probe(struct platform_device *pdev) +{ + struct wdsp_mgr_priv *wdsp; + struct device *mdev = &pdev->dev; + int ret; + + wdsp = devm_kzalloc(mdev, sizeof(*wdsp), GFP_KERNEL); + if (!wdsp) + return -ENOMEM; + wdsp->mdev = mdev; + wdsp->seg_list = devm_kzalloc(mdev, sizeof(struct list_head), + GFP_KERNEL); + if (!wdsp->seg_list) { + devm_kfree(mdev, wdsp); + return -ENOMEM; + } + + ret = wdsp_mgr_parse_dt_entries(wdsp); + if (ret) + goto err_dt_parse; + + INIT_WORK(&wdsp->load_fw_work, wdsp_load_fw_image); + INIT_LIST_HEAD(wdsp->seg_list); + mutex_init(&wdsp->api_mutex); + mutex_init(&wdsp->ssr_mutex); + wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR; + wdsp->ready_status = WDSP_SSR_STATUS_READY; + INIT_WORK(&wdsp->ssr_work, wdsp_ssr_work_fn); + init_completion(&wdsp->ready_compl); + arch_setup_dma_ops(wdsp->mdev, 0, 0, NULL, 0); + dev_set_drvdata(mdev, wdsp); + + ret = component_master_add_with_match(mdev, &wdsp_master_ops, + wdsp->match); + if (ret < 0) { + WDSP_ERR(wdsp, "Failed to add master, err = %d", ret); + goto err_master_add; + } + + return 0; + +err_master_add: + mutex_destroy(&wdsp->api_mutex); + mutex_destroy(&wdsp->ssr_mutex); +err_dt_parse: + devm_kfree(mdev, wdsp->seg_list); + devm_kfree(mdev, wdsp); + dev_set_drvdata(mdev, NULL); + + return ret; +} + +static int wdsp_mgr_remove(struct platform_device *pdev) +{ + struct device *mdev = &pdev->dev; + struct wdsp_mgr_priv *wdsp = dev_get_drvdata(mdev); + + component_master_del(mdev, &wdsp_master_ops); + + mutex_destroy(&wdsp->api_mutex); + mutex_destroy(&wdsp->ssr_mutex); + devm_kfree(mdev, wdsp->seg_list); + devm_kfree(mdev, wdsp); + dev_set_drvdata(mdev, NULL); + + return 0; +}; + +static const struct of_device_id wdsp_mgr_dt_match[] = { + {.compatible = "qcom,wcd-dsp-mgr" }, + { } +}; + +static struct platform_driver wdsp_mgr_driver = { + .driver = { + .name = "wcd-dsp-mgr", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wdsp_mgr_dt_match), + .suppress_bind_attrs = true, + }, + .probe = wdsp_mgr_probe, + .remove = wdsp_mgr_remove, +}; + +int wcd_dsp_mgr_init(void) +{ + return platform_driver_register(&wdsp_mgr_driver); +} + +void wcd_dsp_mgr_exit(void) +{ + platform_driver_unregister(&wdsp_mgr_driver); +} + +MODULE_DESCRIPTION("WCD DSP manager driver"); +MODULE_DEVICE_TABLE(of, wdsp_mgr_dt_match); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-utils.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-utils.c new file mode 100644 index 0000000000..f0ec48e3df --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-utils.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "wcd-dsp-utils.h" + +static bool wdsp_is_valid_elf_hdr(const struct elf32_hdr *ehdr, + size_t fw_size) +{ + if (fw_size < sizeof(*ehdr)) { + pr_err_ratelimited("%s: Firmware too small\n", __func__); + goto elf_check_fail; + } + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { + pr_err_ratelimited("%s: Not an ELF file\n", __func__); + goto elf_check_fail; + } + + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { + pr_err_ratelimited("%s: Not an executable image\n", __func__); + goto elf_check_fail; + } + + if (ehdr->e_phnum == 0) { + pr_err_ratelimited("%s: no segments to load\n", __func__); + goto elf_check_fail; + } + + if (sizeof(struct elf32_phdr) * ehdr->e_phnum + + sizeof(struct elf32_hdr) > fw_size) { + pr_err_ratelimited("%s: Too small MDT file\n", __func__); + goto elf_check_fail; + } + + return true; + +elf_check_fail: + return false; +} + +static int wdsp_add_segment_to_list(struct device *dev, + const char *img_fname, + const struct elf32_phdr *phdr, + int phdr_idx, + struct list_head *seg_list) +{ + struct wdsp_img_segment *seg; + int ret = 0; + + /* Do not load segments with zero size */ + if (phdr->p_filesz == 0 || phdr->p_memsz == 0) + goto done; + + seg = kzalloc(sizeof(*seg), GFP_KERNEL); + if (!seg) { + ret = -ENOMEM; + goto done; + } + + snprintf(seg->split_fname, sizeof(seg->split_fname), + "%s.b%02d", img_fname, phdr_idx); + ret = request_firmware(&seg->split_fw, seg->split_fname, dev); + if (ret < 0) { + dev_err_ratelimited(dev, "%s: firmware %s not found\n", + __func__, seg->split_fname); + goto bad_seg; + } + + if (phdr->p_filesz != seg->split_fw->size) { + dev_err_ratelimited(dev, + "%s: %s size mismatch, phdr_size: 0x%x fw_size: 0x%zx", + __func__, seg->split_fname, phdr->p_filesz, + seg->split_fw->size); + ret = -EINVAL; + goto bad_elf; + } + + seg->load_addr = phdr->p_paddr; + seg->size = phdr->p_filesz; + seg->data = (u8 *) seg->split_fw->data; + + list_add_tail(&seg->list, seg_list); +done: + return ret; +bad_elf: + release_firmware(seg->split_fw); +bad_seg: + kfree(seg); + return ret; +} + +/* + * wdsp_flush_segment_list: Flush the list of segments + * @seg_list: List of segments to be flushed + * This API will traverse through the list of segments provided in + * seg_list, release the firmware for each segment and delete the + * segment from the list. + */ +void wdsp_flush_segment_list(struct list_head *seg_list) +{ + struct wdsp_img_segment *seg, *next; + + list_for_each_entry_safe(seg, next, seg_list, list) { + release_firmware(seg->split_fw); + list_del(&seg->list); + kfree(seg); + } +} +EXPORT_SYMBOL(wdsp_flush_segment_list); + +/* + * wdsp_get_segment_list: Get the list of requested segments + * @dev: struct device pointer of caller + * @img_fname: Image name for the mdt and split firmware files + * @segment_type: Requested segment type, should be either + * WDSP_ELF_FLAG_RE or WDSP_ELF_FLAG_WRITE + * @seg_list: An initialized head for list of segmented to be returned + * @entry_point: Pointer to return the entry point of the image + * This API will parse the mdt file for img_fname and create + * an struct wdsp_img_segment for each segment that matches segment_type + * and add this structure to list pointed by seg_list + */ +int wdsp_get_segment_list(struct device *dev, + const char *img_fname, + unsigned int segment_type, + struct list_head *seg_list, + u32 *entry_point) +{ + const struct firmware *fw; + const struct elf32_hdr *ehdr; + const struct elf32_phdr *phdr; + const u8 *elf_ptr; + char mdt_name[WDSP_IMG_NAME_LEN_MAX]; + int ret, phdr_idx; + bool segment_match; + + if (!dev) { + ret = -EINVAL; + pr_err_ratelimited("%s: Invalid device handle\n", __func__); + goto done; + } + + if (!img_fname || !seg_list || !entry_point) { + ret = -EINVAL; + dev_err_ratelimited(dev, "%s: Invalid input params\n", + __func__); + goto done; + } + + if (segment_type != WDSP_ELF_FLAG_RE && + segment_type != WDSP_ELF_FLAG_WRITE) { + dev_err_ratelimited(dev, "%s: Invalid request for segment_type %d\n", + __func__, segment_type); + ret = -EINVAL; + goto done; + } + + snprintf(mdt_name, sizeof(mdt_name), "%s.mdt", img_fname); + ret = request_firmware(&fw, mdt_name, dev); + if (ret < 0) { + dev_err_ratelimited(dev, "%s: firmware %s not found\n", + __func__, mdt_name); + goto done; + } + + ehdr = (struct elf32_hdr *) fw->data; + *entry_point = ehdr->e_entry; + if (!wdsp_is_valid_elf_hdr(ehdr, fw->size)) { + dev_err_ratelimited(dev, "%s: fw mdt %s is invalid\n", + __func__, mdt_name); + ret = -EINVAL; + goto bad_elf; + } + + elf_ptr = fw->data + sizeof(*ehdr); + for (phdr_idx = 0; phdr_idx < ehdr->e_phnum; phdr_idx++) { + phdr = (struct elf32_phdr *) elf_ptr; + segment_match = false; + + switch (segment_type) { + case WDSP_ELF_FLAG_RE: + /* + * Flag can be READ or EXECUTE or both but + * WRITE flag should not be set. + */ + if ((phdr->p_flags & segment_type) && + !(phdr->p_flags & WDSP_ELF_FLAG_WRITE)) + segment_match = true; + break; + case WDSP_ELF_FLAG_WRITE: + /* + * If WRITE flag is set, other flags do not + * matter. + */ + if (phdr->p_flags & segment_type) + segment_match = true; + break; + } + + if (segment_match) { + ret = wdsp_add_segment_to_list(dev, img_fname, phdr, + phdr_idx, seg_list); + if (ret < 0) { + wdsp_flush_segment_list(seg_list); + goto bad_elf; + } + } + elf_ptr = elf_ptr + sizeof(*phdr); + } + +bad_elf: + release_firmware(fw); +done: + return ret; +} +EXPORT_SYMBOL(wdsp_get_segment_list); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-utils.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-utils.h new file mode 100644 index 0000000000..3fb42e4583 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-dsp-utils.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD_DSP_UTILS_H__ +#define __WCD_DSP_UTILS_H__ + +#define WDSP_IMG_NAME_LEN_MAX 64 + +#define WDSP_ELF_FLAG_EXECUTE (1 << 0) +#define WDSP_ELF_FLAG_WRITE (1 << 1) +#define WDSP_ELF_FLAG_READ (1 << 2) + +#define WDSP_ELF_FLAG_RE (WDSP_ELF_FLAG_READ | WDSP_ELF_FLAG_EXECUTE) + +struct wdsp_img_segment { + + /* Firmware for the slit image */ + const struct firmware *split_fw; + + /* Name of the split firmware file */ + char split_fname[WDSP_IMG_NAME_LEN_MAX]; + + /* Address where the segment is to be loaded */ + u32 load_addr; + + /* Buffer to hold the data to be loaded */ + u8 *data; + + /* Size of the data to be loaded */ + size_t size; + + /* List node pointing to next segment */ + struct list_head list; +}; + +int wdsp_get_segment_list(struct device *dev, const char *img_fname, + unsigned int segment_type, struct list_head *seg_list, + u32 *entry_point); +void wdsp_flush_segment_list(struct list_head *seg_list); + +#endif /* __WCD_DSP_UTILS_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-irq.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-irq.c new file mode 100644 index 0000000000..ed4ab385a2 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-irq.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int wcd_map_irq(struct wcd_irq_info *irq_info, int irq) +{ + if (!irq_info) { + pr_err("%s: Null IRQ handle\n", __func__); + return -EINVAL; + } + return regmap_irq_get_virq(irq_info->irq_chip, irq); +} + +/** + * wcd_request_irq: Request a thread handler for the given IRQ + * @irq_info: pointer to IRQ info structure + * @irq: irq number + * @name: name for the IRQ thread + * @handler: irq handler + * @data: data pointer + * + * Returns 0 on success or error on failure + */ +int wcd_request_irq(struct wcd_irq_info *irq_info, int irq, const char *name, + irq_handler_t handler, void *data) +{ + if (!irq_info) { + pr_err("%s: Null IRQ handle\n", __func__); + return -EINVAL; + } + irq = wcd_map_irq(irq_info, irq); + if (irq < 0) + return irq; + + return devm_request_threaded_irq(irq_info->dev, irq, NULL, handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + name, data); +} +EXPORT_SYMBOL(wcd_request_irq); + +/** + * wcd_free_irq: Free the IRQ resources allocated during request_irq + * @irq_info: pointer to IRQ info structure + * @irq: irq number + * @data: data pointer + */ +void wcd_free_irq(struct wcd_irq_info *irq_info, int irq, void *data) +{ + if (!irq_info) { + pr_err("%s: Null IRQ handle\n", __func__); + return; + } + + irq = wcd_map_irq(irq_info, irq); + if (irq < 0) + return; + + devm_free_irq(irq_info->dev, irq, data); +} +EXPORT_SYMBOL(wcd_free_irq); + +/** + * wcd_enable_irq: Enable the given IRQ + * @irq_info: pointer to IRQ info structure + * @irq: irq number + */ +void wcd_enable_irq(struct wcd_irq_info *irq_info, int irq) +{ + if (!irq_info) + pr_err("%s: Null IRQ handle\n", __func__); + else + enable_irq(wcd_map_irq(irq_info, irq)); +} +EXPORT_SYMBOL(wcd_enable_irq); + +/** + * wcd_disable_irq: Disable the given IRQ + * @irq_info: pointer to IRQ info structure + * @irq: irq number + */ +void wcd_disable_irq(struct wcd_irq_info *irq_info, int irq) +{ + if (!irq_info) + pr_err("%s: Null IRQ handle\n", __func__); + else + disable_irq_nosync(wcd_map_irq(irq_info, irq)); +} +EXPORT_SYMBOL(wcd_disable_irq); + +static void wcd_irq_chip_disable(struct irq_data *data) +{ +} + +static void wcd_irq_chip_enable(struct irq_data *data) +{ +} + +static struct irq_chip wcd_irq_chip = { + .name = NULL, + .irq_disable = wcd_irq_chip_disable, + .irq_enable = wcd_irq_chip_enable, +}; + +static struct lock_class_key wcd_irq_lock_class; +static struct lock_class_key wcd_irq_lock_requested_class; + +static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq); + irq_set_lockdep_class(virq, &wcd_irq_lock_class, + &wcd_irq_lock_requested_class); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops wcd_domain_ops = { + .map = wcd_irq_chip_map, +}; + +/** + * wcd_irq_init: Initializes IRQ module + * @irq_info: pointer to IRQ info structure + * + * Returns 0 on success or error on failure + */ +int wcd_irq_init(struct wcd_irq_info *irq_info, struct irq_domain **virq) +{ + int ret = 0; + + if (!irq_info) { + pr_err("%s: Null IRQ handle\n", __func__); + return -EINVAL; + } + + wcd_irq_chip.name = irq_info->codec_name; + + *virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + if (!(*virq)) { + pr_err("%s: Failed to add IRQ domain\n", __func__); + return -EINVAL; + } + + ret = devm_regmap_add_irq_chip(irq_info->dev, irq_info->regmap, + irq_create_mapping(*virq, 0), + IRQF_ONESHOT, 0, irq_info->wcd_regmap_irq_chip, + &irq_info->irq_chip); + if (ret) + pr_err("%s: Failed to add IRQs: %d\n", + __func__, ret); + + return ret; +} +EXPORT_SYMBOL(wcd_irq_init); + +/** + * wcd_irq_exit: Uninitialize regmap IRQ and free IRQ resources + * @irq_info: pointer to IRQ info structure + * + * Returns 0 on success or error on failure + */ +int wcd_irq_exit(struct wcd_irq_info *irq_info, struct irq_domain *virq) +{ + if (!irq_info) { + pr_err("%s: Null pointer handle\n", __func__); + return -EINVAL; + } + + devm_regmap_del_irq_chip(irq_info->dev, irq_find_mapping(virq, 0), + irq_info->irq_chip); + + return 0; +} +EXPORT_SYMBOL(wcd_irq_exit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-adc.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-adc.c new file mode 100644 index 0000000000..6322284c6f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-adc.c @@ -0,0 +1,1206 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd-mbhc-adc.h" +#include +#include + +#define WCD_MBHC_ADC_HS_THRESHOLD_MV 1700 +#define WCD_MBHC_ADC_HPH_THRESHOLD_MV 75 +#define WCD_MBHC_ADC_MICBIAS_MV 1800 +#define WCD_MBHC_FAKE_INS_RETRY 4 + +static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc) +{ + int micbias = 0; + u8 vout_ctl = 0; + + if (mbhc->mbhc_cb->get_micbias_val) { + mbhc->mbhc_cb->get_micbias_val(mbhc, &micbias); + pr_debug("%s: micbias: %d\n", __func__, micbias); + } else { + /* Read MBHC Micbias (Mic Bias2) voltage */ + WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl); + + /* Formula for getting micbias from vout + * micbias = 1.0V + VOUT_CTL * 50mV + */ + micbias = 1000 + (vout_ctl * 50); + pr_debug("%s: vout_ctl: %d, micbias: %d\n", + __func__, vout_ctl, micbias); + } + return micbias; +} + +static int wcd_get_voltage_from_adc(u8 val, int micbias) +{ + /* Formula for calculating voltage from ADC + * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8 + */ + return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10)); +} + +static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc) +{ + u8 adc_result = 0; + int output_mv = 0; + int retry = 3; + u8 adc_en = 0; + + pr_debug("%s: enter\n", __func__); + + /* Pre-requisites for ADC continuous measurement */ + /* Read legacy electircal detection and disable */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00); + /* Set ADC to continuous measurement */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 1); + /* Read ADC Enable bit to restore after adc measurement */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en); + /* Disable ADC_ENABLE bit */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); + /* Disable MBHC FSM */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + /* Set the MUX selection to IN2P */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_IN2P); + + /* + * Current source mode requires Auto zeroing to be enabled + * automatically. If HW doesn't do it, SW has to take care of this + * for button interrupts to work fine and to avoid + * fake electrical removal interrupts by enabling autozero before FSM + * enable and disable it after FSM enable + */ + if (mbhc->mbhc_cb->mbhc_comp_autozero_control) + mbhc->mbhc_cb->mbhc_comp_autozero_control(mbhc, + true); + /* Enable MBHC FSM */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + if (mbhc->mbhc_cb->mbhc_comp_autozero_control) + mbhc->mbhc_cb->mbhc_comp_autozero_control(mbhc, + false); + /* Enable ADC_ENABLE bit */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1); + + while (retry--) { + /* wait for 3 msec before reading ADC result */ + usleep_range(3000, 3100); + + /* Read ADC result */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_RESULT, adc_result); + } + + /* Restore ADC Enable */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en); + /* Get voltage from ADC result */ + output_mv = wcd_get_voltage_from_adc(adc_result, + wcd_mbhc_get_micbias(mbhc)); + pr_debug("%s: adc_result: 0x%x, output_mv: %d\n", + __func__, adc_result, output_mv); + + return output_mv; +} + +static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl) +{ + u8 adc_timeout = 0; + u8 adc_complete = 0; + u8 adc_result = 0; + int retry = 6; + int ret = 0; + int output_mv = 0; + u8 adc_en = 0; + + pr_debug("%s: enter\n", __func__); + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0); + /* Read ADC Enable bit to restore after adc measurement */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en); + /* Trigger ADC one time measurement */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + /* Set the appropriate MUX selection */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, mux_ctl); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1); + + while (retry--) { + /* wait for 600usec to get adc results */ + usleep_range(600, 610); + + /* check for ADC Timeout */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_TIMEOUT, adc_timeout); + if (adc_timeout) + continue; + + /* Read ADC complete bit */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_COMPLETE, adc_complete); + if (!adc_complete) + continue; + + /* Read ADC result */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_RESULT, adc_result); + + pr_debug("%s: ADC result: 0x%x\n", __func__, adc_result); + /* Get voltage from ADC result */ + output_mv = wcd_get_voltage_from_adc(adc_result, + wcd_mbhc_get_micbias(mbhc)); + break; + } + + /* Restore ADC Enable */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en); + + if (retry <= 0) { + pr_err("%s: adc complete: %d, adc timeout: %d\n", + __func__, adc_complete, adc_timeout); + ret = -EINVAL; + } else { + pr_debug("%s: adc complete: %d, adc timeout: %d output_mV: %d\n", + __func__, adc_complete, adc_timeout, output_mv); + ret = output_mv; + } + + pr_debug("%s: leave\n", __func__); + + return ret; +} + +static bool wcd_mbhc_adc_detect_anc_plug_type(struct wcd_mbhc *mbhc) +{ + bool anc_mic_found = false; + u16 fsm_en = 0; + u8 det = 0; + unsigned long retry = 0; + int valid_plug_cnt = 0, invalid_plug_cnt = 0; + int ret = 0; + u8 elect_ctl = 0; + u8 adc_mode = 0; + u8 vref = 0; + int vref_mv[] = {1650, 1500, 1600, 1700}; + + if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 || + mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4) + return false; + + if (!mbhc->mbhc_cb->mbhc_micbias_control) + return false; + + /* Disable Detection done for ADC operation */ + WCD_MBHC_REG_READ(WCD_MBHC_DETECTION_DONE, det); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0); + + /* Mask ADC COMPLETE interrupt */ + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false); + + WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component, + mbhc->mbhc_cfg->anc_micbias, + MICB_ENABLE); + + /* Read legacy electircal detection and disable */ + WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00); + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1); + WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode); + + /* + * wait for button debounce time 20ms. If 4-pole plug is inserted + * into 5-pole jack, then there will be a button press interrupt + * during anc plug detection. In that case though Hs_comp_res is 0, + * it should not be declared as ANC plug type + */ + usleep_range(20000, 20100); + + /* + * After enabling FSM, to handle slow insertion scenarios, + * check IN3 voltage is below the Vref + */ + WCD_MBHC_REG_READ(WCD_MBHC_HS_VREF, vref); + + do { + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low\n", __func__); + goto done; + } + pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1); + ret = wcd_measure_adc_once(mbhc, MUX_CTL_IN3P); + /* TODO - check the logic */ + if (ret && (ret < vref_mv[vref])) + valid_plug_cnt++; + else + invalid_plug_cnt++; + retry++; + } while (retry < ANC_DETECT_RETRY_CNT); + + pr_debug("%s: valid: %d, invalid: %d\n", __func__, valid_plug_cnt, + invalid_plug_cnt); + + /* decision logic */ + if (valid_plug_cnt > invalid_plug_cnt) + anc_mic_found = true; +done: + /* Restore ADC mode */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, adc_mode); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + /* Set the MUX selection to AUTO */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en); + /* Restore detection done */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, det); + + /* Restore electrical detection */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); + + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component, + mbhc->mbhc_cfg->anc_micbias, + MICB_DISABLE); + pr_debug("%s: anc mic %sfound\n", __func__, + anc_mic_found ? "" : "not "); + + return anc_mic_found; +} + +/* To determine if cross connection occurred */ +static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) +{ + enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE; + int hphl_adc_res = 0, hphr_adc_res = 0; + u8 fsm_en = 0; + int ret = 0; + u8 adc_mode = 0; + u8 elect_ctl = 0; + u8 adc_en = 0; + + pr_debug("%s: enter\n", __func__); + /* Check for button press and plug detection */ + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low\n", __func__); + return -EINVAL; + } + + /* If PA is enabled, dont check for cross-connection */ + if (mbhc->mbhc_cb->hph_pa_on_status) + if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->component)) + return -EINVAL; + + /* Read legacy electircal detection and disable */ + WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00); + + /* Disable surge detection before ADC measurement */ + if (mbhc->mbhc_cb->mbhc_surge_ctl) + mbhc->mbhc_cb->mbhc_surge_ctl(mbhc, false); + + /* Read and set ADC to single measurement */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode); + /* Read ADC Enable bit to restore after adc measurement */ + WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en); + /* Read FSM status */ + WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); + + /* Get adc result for HPH L */ + hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L); + if (hphl_adc_res < 0) { + pr_err("%s: hphl_adc_res adc measurement failed\n", __func__); + ret = hphl_adc_res; + goto done; + } + + /* Get adc result for HPH R in mV */ + hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R); + if (hphr_adc_res < 0) { + pr_err("%s: hphr_adc_res adc measurement failed\n", __func__); + ret = hphr_adc_res; + goto done; + } + + /* Update cross connection threshold voltages if needed */ + if (mbhc->mbhc_cb->update_cross_conn_thr) + mbhc->mbhc_cb->update_cross_conn_thr(mbhc); + + if (hphl_adc_res > mbhc->hphl_cross_conn_thr && + hphr_adc_res > mbhc->hphr_cross_conn_thr) { + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + pr_debug("%s: Cross connection identified\n", __func__); + } else { + pr_debug("%s: No Cross connection found\n", __func__); + } + +done: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + /* Set the MUX selection to Auto */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + + /* Restore ADC Enable */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en); + + /* Restore ADC mode */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, adc_mode); + + /* Restore FSM state */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en); + + /* Restore surge detection */ + if (mbhc->mbhc_cb->mbhc_surge_ctl) + mbhc->mbhc_cb->mbhc_surge_ctl(mbhc, true); + + /* Restore electrical detection */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); + + pr_debug("%s: leave, plug type: %d\n", __func__, plug_type); + + return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false; +} + +static int wcd_mbhc_adc_get_spl_hs_thres(struct wcd_mbhc *mbhc) +{ + int hs_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->hs_thr && mbhc->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) { + if (mbhc->micb_mv == micbias_mv) + hs_threshold = mbhc->hs_thr; + else + hs_threshold = (mbhc->hs_thr * + micbias_mv) / mbhc->micb_mv; + } else { + hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hs_threshold; +} + +static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc) +{ + int hs_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->hs_thr) { + if (mbhc->micb_mv == micbias_mv) + hs_threshold = mbhc->hs_thr; + else + hs_threshold = (mbhc->hs_thr * + micbias_mv) / mbhc->micb_mv; + } else { + hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hs_threshold; +} + +static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc) +{ + int hph_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->hph_thr) { + if (mbhc->micb_mv == micbias_mv) + hph_threshold = mbhc->hph_thr; + else + hph_threshold = (mbhc->hph_thr * + micbias_mv) / mbhc->micb_mv; + } else { + hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hph_threshold; +} + +static bool wcd_mbhc_adc_check_for_spl_headset(struct wcd_mbhc *mbhc, + int *spl_hs_cnt) +{ + bool spl_hs = false; + int output_mv = 0; + int adc_threshold = 0, adc_hph_threshold = 0; + + pr_debug("%s: enter\n", __func__); + if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + goto exit; + + /* Bump up MB2 to 2.7V */ + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, + mbhc->mbhc_cfg->mbhc_micbias, true); + usleep_range(10000, 10100); + + /* + * Use ADC single mode to minimize the chance of missing out + * btn press/relesae for HEADSET type during correct work. + */ + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + adc_threshold = wcd_mbhc_adc_get_spl_hs_thres(mbhc); + adc_hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc); + + if (output_mv > adc_threshold || output_mv < adc_hph_threshold) { + spl_hs = false; + } else { + spl_hs = true; + if (spl_hs_cnt) + *spl_hs_cnt += 1; + } + + /* MB2 back to 1.8v if the type is not special headset */ + if (spl_hs_cnt && (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT)) { + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, + mbhc->mbhc_cfg->mbhc_micbias, false); + /* Add 10ms delay for micbias to settle */ + usleep_range(10000, 10100); + } + +exit: + pr_debug("%s: leave\n", __func__); + return spl_hs; +} + +static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) +{ + int delay = 0; + bool ret = false; + bool is_spl_hs = false; + int output_mv = 0; + int adc_threshold = 0; + + /* + * Increase micbias to 2.7V to detect headsets with + * threshold on microphone + */ + if (mbhc->mbhc_cb->mbhc_micbias_control && + !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { + pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n", + __func__); + return false; + } else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { + ret = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, + MIC_BIAS_2, true); + if (ret) { + pr_err("%s: mbhc_micb_ctrl_thr_mic failed, ret: %d\n", + __func__, ret); + return false; + } + } + adc_threshold = wcd_mbhc_adc_get_spl_hs_thres(mbhc); + + while (!is_spl_hs) { + if (mbhc->hs_detect_work_stop) { + pr_debug("%s: stop requested: %d\n", __func__, + mbhc->hs_detect_work_stop); + break; + } + delay += 50; + /* Wait for 50ms for FSM to update result */ + msleep(50); + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + if (output_mv <= adc_threshold) { + pr_debug("%s: Special headset detected in %d msecs\n", + __func__, delay); + is_spl_hs = true; + } + + if (delay == SPECIAL_HS_DETECT_TIME_MS) { + pr_debug("%s: Spl headset not found in 2 sec\n", + __func__); + break; + } + } + if (is_spl_hs) { + pr_debug("%s: Headset with threshold found\n", __func__); + mbhc->micbias_enable = true; + ret = true; + } + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic && + !mbhc->micbias_enable) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, + MIC_BIAS_2, + false); + pr_debug("%s: leave, micb_enable: %d\n", __func__, + mbhc->micbias_enable); + + return ret; +} + +static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc, + enum wcd_mbhc_plug_type plug_type) +{ + bool micbias2; + + micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_2); + switch (plug_type) { + case MBHC_PLUG_TYPE_HEADPHONE: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); + break; + case MBHC_PLUG_TYPE_HEADSET: + case MBHC_PLUG_TYPE_ANC_HEADPHONE: + if (!mbhc->is_hs_recording && !micbias2) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); + break; + default: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + break; + + }; +} + +/* should be called under interrupt context that hold suspend */ +static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc, + struct work_struct *work) +{ + pr_debug("%s: scheduling correct_swch_plug\n", __func__); + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + mbhc->hs_detect_work_stop = false; + mbhc->mbhc_cb->lock_sleep(mbhc, true); + schedule_work(work); +} + +/* called under codec_resource_lock acquisition */ +static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc, + struct work_struct *work) +{ + pr_debug("%s: Canceling correct_plug_swch\n", __func__); + mbhc->hs_detect_work_stop = true; + WCD_MBHC_RSC_UNLOCK(mbhc); + if (cancel_work_sync(work)) { + pr_debug("%s: correct_plug_swch is canceled\n", + __func__); + mbhc->mbhc_cb->lock_sleep(mbhc, false); + } + WCD_MBHC_RSC_LOCK(mbhc); +} + +/* called under codec_resource_lock acquisition */ +static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + + pr_debug("%s: enter\n", __func__); + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + if (mbhc->mbhc_cb->hph_pull_down_ctrl) + mbhc->mbhc_cb->hph_pull_down_ctrl(component, false); + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0); + + if (mbhc->mbhc_cb->mbhc_micbias_control) { + mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, + MICB_ENABLE); + } else { + pr_err("%s: Mic Bias is not enabled\n", __func__); + return; + } + + /* Re-initialize button press completion object */ + reinit_completion(&mbhc->btn_press_compl); + wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); + pr_debug("%s: leave\n", __func__); +} + +static void wcd_micbias_disable(struct wcd_mbhc *mbhc) +{ + if (mbhc->micbias_enable) { + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + mbhc->component, MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) + mbhc->mbhc_cb->set_micbias_value( + mbhc->component); + mbhc->micbias_enable = false; + } +} + +static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result) + +{ + enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; + u32 hph_thr = 0, hs_thr = 0; + + hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc); + hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc); + + if (adc_result < hph_thr) + plug_type = MBHC_PLUG_TYPE_HEADPHONE; + else if (adc_result > hs_thr) + plug_type = MBHC_PLUG_TYPE_HIGH_HPH; + else + plug_type = MBHC_PLUG_TYPE_HEADSET; + pr_debug("%s: plug type is %d found\n", __func__, plug_type); + + return plug_type; +} + +static void wcd_correct_swch_plug(struct work_struct *work) +{ + struct wcd_mbhc *mbhc; + struct snd_soc_component *component; + enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; + unsigned long timeout; + bool wrk_complete = false; + int pt_gnd_mic_swap_cnt = 0; + int no_gnd_mic_swap_cnt = 0; + bool is_pa_on = false, spl_hs = false, spl_hs_reported = false; + int ret = 0; + int spl_hs_count = 0; + int output_mv = 0; + int cross_conn; + int try = 0; + int hs_threshold, micbias_mv; + + pr_debug("%s: enter\n", __func__); + + mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); + component = mbhc->component; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); + + WCD_MBHC_RSC_LOCK(mbhc); + /* Mask ADC COMPLETE interrupt */ + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false); + WCD_MBHC_RSC_UNLOCK(mbhc); + + /* Check for cross connection */ + do { + cross_conn = wcd_check_cross_conn(mbhc); + try++; + } while (try < mbhc->swap_thr); + + if (cross_conn > 0) { + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + pr_debug("%s: cross connection found, Plug type %d\n", + __func__, plug_type); + goto correct_plug_type; + } + /* Find plug type */ + output_mv = wcd_measure_adc_continuous(mbhc); + plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); + + /* + * Report plug type if it is either headset or headphone + * else start the 3 sec loop + */ + if ((plug_type == MBHC_PLUG_TYPE_HEADSET || + plug_type == MBHC_PLUG_TYPE_HEADPHONE) && + (!wcd_swch_level_remove(mbhc))) { + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_find_plug_and_report(mbhc, plug_type); + WCD_MBHC_RSC_UNLOCK(mbhc); + } + + /* + * Set DETECTION_DONE bit for HEADSET and ANC_HEADPHONE, + * so that btn press/release interrupt can be generated. + */ + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET || + mbhc->current_plug == MBHC_PLUG_TYPE_ANC_HEADPHONE) { + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1); + } + +correct_plug_type: + /* + * Callback to disable BCS slow insertion detection + */ + if (mbhc->mbhc_cb->bcs_enable) + mbhc->mbhc_cb->bcs_enable(mbhc, false); + + timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS); + while (!time_after(jiffies, timeout)) { + if (mbhc->hs_detect_work_stop) { + pr_debug("%s: stop requested: %d\n", __func__, + mbhc->hs_detect_work_stop); + wcd_micbias_disable(mbhc); + goto exit; + } + + /* allow sometime and re-check stop requested again */ + msleep(20); + if (mbhc->hs_detect_work_stop) { + pr_debug("%s: stop requested: %d\n", __func__, + mbhc->hs_detect_work_stop); + wcd_micbias_disable(mbhc); + goto exit; + } + + msleep(180); + /* + * Use ADC single mode to minimize the chance of missing out + * btn press/release for HEADSET type during correct work. + */ + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + + /* + * instead of hogging system by contineous polling, wait for + * sometime and re-check stop request again. + */ + plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); + + if ((output_mv > hs_threshold) && + (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) { + spl_hs = wcd_mbhc_adc_check_for_spl_headset(mbhc, + &spl_hs_count); + if (spl_hs) + pr_debug("%s: Detected special HS (%d)\n", + __func__, spl_hs); + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + + if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) { + hs_threshold = (hs_threshold * + wcd_mbhc_get_micbias(mbhc)) / micbias_mv; + spl_hs = true; + mbhc->micbias_enable = true; + } + } + + if (mbhc->mbhc_cb->hph_pa_on_status) + is_pa_on = mbhc->mbhc_cb->hph_pa_on_status( + mbhc->component); + + if ((output_mv <= hs_threshold) && + (!is_pa_on)) { + /* Check for cross connection*/ + ret = wcd_check_cross_conn(mbhc); + if (ret < 0) + continue; + else if (ret > 0) { + pt_gnd_mic_swap_cnt++; + no_gnd_mic_swap_cnt = 0; + if (pt_gnd_mic_swap_cnt < + mbhc->swap_thr) { + continue; + } else if (pt_gnd_mic_swap_cnt > + mbhc->swap_thr) { + /* + * This is due to GND/MIC switch didn't + * work, Report unsupported plug. + */ + pr_debug("%s: switch did not work\n", + __func__); + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + goto report; + } else { + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + } + } else { + no_gnd_mic_swap_cnt++; + pt_gnd_mic_swap_cnt = 0; + plug_type = wcd_mbhc_get_plug_from_adc( + mbhc, output_mv); + if ((no_gnd_mic_swap_cnt < + mbhc->swap_thr) && + (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) { + continue; + } else { + no_gnd_mic_swap_cnt = 0; + } + } + if ((pt_gnd_mic_swap_cnt == mbhc->swap_thr) && + (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) { + /* + * if switch is toggled, check again, + * otherwise report unsupported plug + */ + if (mbhc->mbhc_cfg->swap_gnd_mic && + mbhc->mbhc_cfg->swap_gnd_mic(component, + true)) { + pr_debug("%s: US_EU gpio present,flip switch\n" + , __func__); + continue; + } + } + } + + if (output_mv > hs_threshold) { + pr_debug("%s: cable is extension cable\n", __func__); + plug_type = MBHC_PLUG_TYPE_HIGH_HPH; + wrk_complete = true; + } else { + pr_debug("%s: cable might be headset: %d\n", __func__, + plug_type); + if (plug_type != MBHC_PLUG_TYPE_GND_MIC_SWAP) { + plug_type = wcd_mbhc_get_plug_from_adc( + mbhc, output_mv); + if (!spl_hs_reported && + spl_hs_count == WCD_MBHC_SPL_HS_CNT) { + spl_hs_reported = true; + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_find_plug_and_report(mbhc, + plug_type); + WCD_MBHC_RSC_UNLOCK(mbhc); + continue; + } else if (spl_hs_reported) + continue; + /* + * Report headset only if not already reported + * and if there is not button press without + * release + */ + if ((mbhc->current_plug != + MBHC_PLUG_TYPE_HEADSET) && + (mbhc->current_plug != + MBHC_PLUG_TYPE_ANC_HEADPHONE) && + !wcd_swch_level_remove(mbhc)) { + pr_debug("%s: cable is %s headset\n", + __func__, + ((spl_hs_count == + WCD_MBHC_SPL_HS_CNT) ? + "special ":"")); + goto report; + } + } + wrk_complete = false; + } + } + if (!wrk_complete) { + /* + * If plug_tye is headset, we might have already reported either + * in detect_plug-type or in above while loop, no need to report + * again + */ + if ((plug_type == MBHC_PLUG_TYPE_HEADSET) || + (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE)) { + pr_debug("%s: plug_type:0x%x current_plug: 0x%x already reported\n", + __func__, plug_type, mbhc->current_plug); + if (mbhc->current_plug != plug_type) + goto report; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); + goto enable_supply; + } + } + if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) { + if (wcd_is_special_headset(mbhc)) { + pr_debug("%s: Special headset found %d\n", + __func__, plug_type); + plug_type = MBHC_PLUG_TYPE_HEADSET; + } else { + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 1); + } + } + +report: + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low\n", __func__); + goto exit; + } + + pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n", + __func__, plug_type, wrk_complete, + mbhc->btn_press_intr); + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); + + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_find_plug_and_report(mbhc, plug_type); + WCD_MBHC_RSC_UNLOCK(mbhc); +enable_supply: + /* + * Set DETECTION_DONE bit for HEADSET and ANC_HEADPHONE, + * so that btn press/release interrupt can be generated. + * For other plug type, clear the bit. + */ + if (plug_type == MBHC_PLUG_TYPE_HEADSET || + plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1); + else + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0); + + if (mbhc->mbhc_cb->bcs_enable) + mbhc->mbhc_cb->bcs_enable(mbhc, true); + + if (mbhc->mbhc_cb->mbhc_micbias_control) + wcd_mbhc_adc_update_fsm_source(mbhc, plug_type); +exit: + if (mbhc->mbhc_cb->mbhc_micbias_control && + !mbhc->micbias_enable) + mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, + MICB_DISABLE); + + /* + * If plug type is corrected from special headset to headphone, + * clear the micbias enable flag, set micbias back to 1.8V and + * disable micbias. + */ + if (plug_type == MBHC_PLUG_TYPE_HEADPHONE && + mbhc->micbias_enable) { + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control( + component, MIC_BIAS_2, + MICB_DISABLE); + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + component, + MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value(component); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0); + } + mbhc->micbias_enable = false; + } + + if (mbhc->mbhc_cfg->detect_extn_cable && + ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) || + (plug_type == MBHC_PLUG_TYPE_HEADSET)) && + !mbhc->hs_detect_work_stop) { + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true); + WCD_MBHC_RSC_UNLOCK(mbhc); + } + + /* + * Enable ADC COMPLETE interrupt for HEADPHONE. + * Btn release may happen after the correct work, ADC COMPLETE + * interrupt needs to be captured to correct plug type. + */ + if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) { + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, + true); + WCD_MBHC_RSC_UNLOCK(mbhc); + } + + if (mbhc->mbhc_cb->hph_pull_down_ctrl) + mbhc->mbhc_cb->hph_pull_down_ctrl(component, true); + + mbhc->mbhc_cb->lock_sleep(mbhc, false); + pr_debug("%s: leave\n", __func__); +} + +static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + unsigned long timeout; + int adc_threshold, output_mv, retry = 0; + bool hphpa_on = false; + u8 moisture_status = 0; + + pr_debug("%s: enter\n", __func__); + WCD_MBHC_RSC_LOCK(mbhc); + + timeout = jiffies + + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); + adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); + + /* Enable MICBIAS before checking for ADC Voltage */ + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component, + MIC_BIAS_2, MICB_ENABLE); + + do { + retry++; + /* + * read output_mv every 10ms to look for + * any change in IN2_P + */ + usleep_range(10000, 10100); + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + + pr_debug("%s: Check for fake removal: output_mv %d\n", + __func__, output_mv); + if ((output_mv <= adc_threshold) && + retry > FAKE_REM_RETRY_ATTEMPTS) { + pr_debug("%s: headset is NOT actually removed\n", + __func__); + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control( + mbhc->component, MIC_BIAS_2, + MICB_DISABLE); + goto exit; + } + } while (!time_after(jiffies, timeout)); + + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component, MIC_BIAS_2, + MICB_DISABLE); + + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low ", __func__); + goto exit; + } + + if (!(test_bit(WCD_MBHC_ELEC_HS_REM, &mbhc->intr_status))) { + pr_debug("%s: plug removal already reported.\n", __func__); + goto exit; + } + + if (mbhc->mbhc_cfg->moisture_en || + mbhc->mbhc_cfg->moisture_duty_cycle_en) { + if (mbhc->mbhc_cb->hph_pa_on_status) + if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->component)) { + hphpa_on = true; + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_HPH_PA_EN, 0); + } + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_GND, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_GND, 1); + /* wait for 50ms to get moisture status */ + usleep_range(50000, 50100); + + WCD_MBHC_REG_READ(WCD_MBHC_MOISTURE_STATUS, moisture_status); + } + + if ((mbhc->mbhc_cfg->moisture_en || + mbhc->mbhc_cfg->moisture_duty_cycle_en) && !moisture_status) { + pr_debug("%s: moisture present in jack\n", __func__); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) { + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); + extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 0); + } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); + extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 0); + } else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) { +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED); +#endif /* CONFIG_AUDIO_QGKI */ + extcon_set_state_sync(mbhc->extdev, EXTCON_MECHANICAL, 0); + } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) { + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT); + extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 0); + } + } else { + /* + * ADC COMPLETE and ELEC_REM interrupts are both enabled for + * HEADPHONE, need to reject the ADC COMPLETE interrupt which + * follows ELEC_REM one when HEADPHONE is removed. + */ + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) + mbhc->extn_cable_hph_rem = true; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); + wcd_mbhc_elec_hs_report_unplug(mbhc); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + + if (hphpa_on) { + hphpa_on = false; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 3); + } + } +exit: + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + u8 clamp_state = 0; + u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY; + + pr_debug("%s: enter\n", __func__); + + /* + * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE, + * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one + * when HEADPHONE is removed. + */ + if (mbhc->extn_cable_hph_rem == true) { + mbhc->extn_cable_hph_rem = false; + pr_debug("%s: leave\n", __func__); + return IRQ_HANDLED; + } + + do { + WCD_MBHC_REG_READ(WCD_MBHC_IN2P_CLAMP_STATE, clamp_state); + if (clamp_state) { + pr_debug("%s: fake insertion irq, leave\n", __func__); + return IRQ_HANDLED; + } + /* + * check clamp for 120ms but at 30ms chunks to leave + * room for other interrupts to be processed + */ + usleep_range(30000, 30100); + } while (--clamp_retry); + + WCD_MBHC_RSC_LOCK(mbhc); + + if (!(test_bit(WCD_MBHC_ELEC_HS_INS, &mbhc->intr_status))) { + WCD_MBHC_RSC_UNLOCK(mbhc); + return IRQ_HANDLED; + } + /* + * If current plug is headphone then there is no chance to + * get ADC complete interrupt, so connected cable should be + * headset not headphone. + */ + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1); + wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET); + WCD_MBHC_RSC_UNLOCK(mbhc); + return IRQ_HANDLED; + } + + if (!mbhc->mbhc_cfg->detect_extn_cable) { + pr_debug("%s: Returning as Extension cable feature not enabled\n", + __func__); + WCD_MBHC_RSC_UNLOCK(mbhc); + return IRQ_HANDLED; + } + + pr_debug("%s: Disable electrical headset insertion interrupt\n", + __func__); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0); + mbhc->is_extn_cable = true; + mbhc->btn_press_intr = false; + mbhc->force_linein = false; + wcd_mbhc_adc_detect_plug_type(mbhc); + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); + return IRQ_HANDLED; +} + +static struct wcd_mbhc_fn mbhc_fn = { + .wcd_mbhc_hs_ins_irq = wcd_mbhc_adc_hs_ins_irq, + .wcd_mbhc_hs_rem_irq = wcd_mbhc_adc_hs_rem_irq, + .wcd_mbhc_detect_plug_type = wcd_mbhc_adc_detect_plug_type, + .wcd_mbhc_detect_anc_plug_type = wcd_mbhc_adc_detect_anc_plug_type, + .wcd_cancel_hs_detect_plug = wcd_cancel_hs_detect_plug, +}; + +/* Function: wcd_mbhc_adc_init + * @mbhc: MBHC function pointer + * Description: Initialize MBHC ADC related function pointers to MBHC structure + */ +void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc) +{ + if (!mbhc) { + pr_err("%s: mbhc is NULL\n", __func__); + return; + } + mbhc->mbhc_fn = &mbhc_fn; + INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug); +} +EXPORT_SYMBOL(wcd_mbhc_adc_init); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-adc.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-adc.h new file mode 100644 index 0000000000..97fd12d8a0 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-adc.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef __WCD_MBHC_ADC_H__ +#define __WCD_MBHC_ADC_H__ + +#include + +enum wcd_mbhc_adc_mux_ctl { + MUX_CTL_AUTO = 0, + MUX_CTL_IN2P, + MUX_CTL_IN3P, + MUX_CTL_IN4P, + MUX_CTL_HPH_L, + MUX_CTL_HPH_R, + MUX_CTL_NONE, +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD_MBHC_ADC) +void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc); +#else +static inline void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc) +{ + +} +#endif +#endif /* __WCD_MBHC_ADC_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-legacy.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-legacy.c new file mode 100644 index 0000000000..ed26fb309e --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-legacy.c @@ -0,0 +1,1037 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd-mbhc-legacy.h" +#include + +static int det_extn_cable_en; +module_param(det_extn_cable_en, int, 0664); +MODULE_PARM_DESC(det_extn_cable_en, "enable/disable extn cable detect"); + +static bool wcd_mbhc_detect_anc_plug_type(struct wcd_mbhc *mbhc) +{ + bool anc_mic_found = false; + u16 val, hs_comp_res, btn_status = 0; + unsigned long retry = 0; + int valid_plug_cnt = 0, invalid_plug_cnt = 0; + int btn_status_cnt = 0; + bool is_check_btn_press = false; + + + if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 || + mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4) + return false; + + if (!mbhc->mbhc_cb->mbhc_micbias_control) + return false; + + WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, val); + + if (val) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component, + mbhc->mbhc_cfg->anc_micbias, + MICB_ENABLE); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x2); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + /* + * wait for button debounce time 20ms. If 4-pole plug is inserted + * into 5-pole jack, then there will be a button press interrupt + * during anc plug detection. In that case though Hs_comp_res is 0, + * it should not be declared as ANC plug type + */ + usleep_range(20000, 20100); + + /* + * After enabling FSM, to handle slow insertion scenarios, + * check hs_comp_result for few times to see if the IN3 voltage + * is below the Vref + */ + do { + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low\n", __func__); + goto exit; + } + pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1); + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res); + + if (!hs_comp_res) { + valid_plug_cnt++; + is_check_btn_press = true; + } else + invalid_plug_cnt++; + /* Wait 1ms before taking another reading */ + usleep_range(1000, 1100); + + WCD_MBHC_REG_READ(WCD_MBHC_FSM_STATUS, btn_status); + if (btn_status) + btn_status_cnt++; + + retry++; + } while (retry < ANC_DETECT_RETRY_CNT); + + pr_debug("%s: valid: %d, invalid: %d, btn_status_cnt: %d\n", + __func__, valid_plug_cnt, invalid_plug_cnt, btn_status_cnt); + + /* decision logic */ + if ((valid_plug_cnt > invalid_plug_cnt) && is_check_btn_press && + (btn_status_cnt == 0)) + anc_mic_found = true; +exit: + if (!val) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0); + + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component, + mbhc->mbhc_cfg->anc_micbias, + MICB_DISABLE); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x0); + pr_debug("%s: anc mic %sfound\n", __func__, + anc_mic_found ? "" : "not "); + return anc_mic_found; +} + +/* To determine if cross connection occurred */ +static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) +{ + u16 swap_res = 0; + enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE; + s16 reg1 = 0; + bool hphl_sch_res = 0, hphr_sch_res = 0; + + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low\n", __func__); + return -EINVAL; + } + + /* If PA is enabled, dont check for cross-connection */ + if (mbhc->mbhc_cb->hph_pa_on_status) + if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->component)) + return false; + + WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, reg1); + /* + * Check if there is any cross connection, + * Micbias and schmitt trigger (HPHL-HPHR) + * needs to be enabled. For some codecs like wcd9335, + * pull-up will already be enabled when this function + * is called for cross-connection identification. No + * need to enable micbias in that case. + */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 2); + + WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, swap_res); + pr_debug("%s: swap_res%x\n", __func__, swap_res); + + /* + * Read reg hphl and hphr schmitt result with cross connection + * bit. These bits will both be "0" in case of cross connection + * otherwise, they stay at 1 + */ + WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch_res); + WCD_MBHC_REG_READ(WCD_MBHC_HPHR_SCHMT_RESULT, hphr_sch_res); + if (!(hphl_sch_res || hphr_sch_res)) { + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + pr_debug("%s: Cross connection identified\n", __func__); + } else { + pr_debug("%s: No Cross connection found\n", __func__); + } + + /* Disable schmitt trigger and restore micbias */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, reg1); + pr_debug("%s: leave, plug type: %d\n", __func__, plug_type); + + return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false; +} + +static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + int delay = 0, rc; + bool ret = false; + u16 hs_comp_res; + bool is_spl_hs = false; + + /* + * Increase micbias to 2.7V to detect headsets with + * threshold on microphone + */ + if (mbhc->mbhc_cb->mbhc_micbias_control && + !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { + pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n", + __func__); + return false; + } else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) { + rc = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, + MIC_BIAS_2, true); + if (rc) { + pr_err("%s: Micbias control for thr mic failed, rc: %d\n", + __func__, rc); + return false; + } + } + + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + + pr_debug("%s: special headset, start register writes\n", __func__); + + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res); + while (!is_spl_hs) { + if (mbhc->hs_detect_work_stop) { + pr_debug("%s: stop requested: %d\n", __func__, + mbhc->hs_detect_work_stop); + break; + } + delay = delay + 50; + if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) { + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_PRECHARGE, + true); + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_SET_VAL, + true); + } + /* Wait for 50msec for MICBIAS to settle down */ + msleep(50); + if (mbhc->mbhc_cb->set_auto_zeroing) + mbhc->mbhc_cb->set_auto_zeroing(component, true); + /* Wait for 50msec for FSM to update result values */ + msleep(50); + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res); + if (!(hs_comp_res)) { + pr_debug("%s: Special headset detected in %d msecs\n", + __func__, (delay * 2)); + is_spl_hs = true; + } + if (delay == SPECIAL_HS_DETECT_TIME_MS) { + pr_debug("%s: Spl headset didn't get detect in 4 sec\n", + __func__); + break; + } + } + if (is_spl_hs) { + pr_debug("%s: Headset with threshold found\n", __func__); + mbhc->micbias_enable = true; + ret = true; + } + if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_PRECHARGE, + false); + if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable) + mbhc->mbhc_cb->set_micbias_value(component); + if (mbhc->mbhc_cb->set_auto_zeroing) + mbhc->mbhc_cb->set_auto_zeroing(component, false); + + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic && + !mbhc->micbias_enable) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, + false); + + pr_debug("%s: leave, micb_enable: %d\n", __func__, + mbhc->micbias_enable); + return ret; +} + +static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc, + enum wcd_mbhc_plug_type plug_type) +{ + bool micbias2; + + micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_2); + switch (plug_type) { + case MBHC_PLUG_TYPE_HEADPHONE: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); + break; + case MBHC_PLUG_TYPE_HEADSET: + case MBHC_PLUG_TYPE_ANC_HEADPHONE: + if (!mbhc->is_hs_recording && !micbias2) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); + break; + default: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + break; + + }; +} + +static void wcd_enable_mbhc_supply(struct wcd_mbhc *mbhc, + enum wcd_mbhc_plug_type plug_type) +{ + + struct snd_soc_component *component = mbhc->component; + + /* + * Do not disable micbias if recording is going on or + * headset is inserted on the other side of the extn + * cable. If headset has been detected current source + * needs to be kept enabled for button detection to work. + * If the accessory type is invalid or unsupported, we + * dont need to enable either of them. + */ + if (det_extn_cable_en && mbhc->is_extn_cable && + mbhc->mbhc_cb && mbhc->mbhc_cb->extn_use_mb && + mbhc->mbhc_cb->extn_use_mb(component)) { + if (plug_type == MBHC_PLUG_TYPE_HEADPHONE || + plug_type == MBHC_PLUG_TYPE_HEADSET) + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + } else { + if (plug_type == MBHC_PLUG_TYPE_HEADSET) { + if (mbhc->is_hs_recording || mbhc->micbias_enable) { + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + } else if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, + &mbhc->event_state)) || + (test_bit(WCD_MBHC_EVENT_PA_HPHR, + &mbhc->event_state))) { + wcd_enable_curr_micbias(mbhc, + WCD_MBHC_EN_PULLUP); + } else { + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS); + } + } else if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS); + } else { + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE); + } + } +} + +static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc, + int *spl_hs_cnt) +{ + u16 hs_comp_res_1_8v = 0, hs_comp_res_2_7v = 0; + bool spl_hs = false; + + if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + goto done; + + if (!spl_hs_cnt) { + pr_err("%s: spl_hs_cnt is NULL\n", __func__); + goto done; + } + /* Read back hs_comp_res @ 1.8v Micbias */ + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_1_8v); + if (!hs_comp_res_1_8v) { + spl_hs = false; + goto done; + } + + /* Bump up MB2 to 2.7v */ + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, + mbhc->mbhc_cfg->mbhc_micbias, true); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + usleep_range(10000, 10100); + + /* Read back HS_COMP_RESULT */ + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_2_7v); + if (!hs_comp_res_2_7v && hs_comp_res_1_8v) + spl_hs = true; + + if (spl_hs) + *spl_hs_cnt += 1; + + /* MB2 back to 1.8v */ + if (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT) { + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, + mbhc->mbhc_cfg->mbhc_micbias, false); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + usleep_range(10000, 10100); + } + + if (spl_hs) + pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs); + +done: + return spl_hs; +} + +/* should be called under interrupt context that hold suspend */ +static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc, + struct work_struct *work) +{ + pr_debug("%s: scheduling correct_swch_plug\n", __func__); + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + mbhc->hs_detect_work_stop = false; + mbhc->mbhc_cb->lock_sleep(mbhc, true); + schedule_work(work); +} + +/* called under codec_resource_lock acquisition */ +static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc, + struct work_struct *work) +{ + pr_debug("%s: Canceling correct_plug_swch\n", __func__); + mbhc->hs_detect_work_stop = true; + WCD_MBHC_RSC_UNLOCK(mbhc); + if (cancel_work_sync(work)) { + pr_debug("%s: correct_plug_swch is canceled\n", + __func__); + mbhc->mbhc_cb->lock_sleep(mbhc, false); + } + WCD_MBHC_RSC_LOCK(mbhc); +} + +/* called under codec_resource_lock acquisition */ +static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + bool micbias1 = false; + + pr_debug("%s: enter\n", __func__); + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + if (mbhc->mbhc_cb->hph_pull_down_ctrl) + mbhc->mbhc_cb->hph_pull_down_ctrl(component, false); + + if (mbhc->mbhc_cb->micbias_enable_status) + micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_1); + + if (mbhc->mbhc_cb->set_cap_mode) + mbhc->mbhc_cb->set_cap_mode(component, micbias1, true); + + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, + MICB_ENABLE); + else + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + + /* Re-initialize button press completion object */ + reinit_completion(&mbhc->btn_press_compl); + wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); + pr_debug("%s: leave\n", __func__); +} + +static void wcd_correct_swch_plug(struct work_struct *work) +{ + struct wcd_mbhc *mbhc; + struct snd_soc_component *component; + enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; + unsigned long timeout; + u16 hs_comp_res = 0, hphl_sch = 0, mic_sch = 0, btn_result = 0; + bool wrk_complete = false; + int pt_gnd_mic_swap_cnt = 0; + int no_gnd_mic_swap_cnt = 0; + bool is_pa_on = false, spl_hs = false, spl_hs_reported = false; + bool micbias2 = false; + bool micbias1 = false; + int ret = 0; + int rc, spl_hs_count = 0; + int cross_conn; + int try = 0; + + pr_debug("%s: enter\n", __func__); + + mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); + component = mbhc->component; + + /* + * Enable micbias/pullup for detection in correct work. + * This work will get scheduled from detect_plug_type which + * will already request for pullup/micbias. If the pullup/micbias + * is handled with ref-counts by individual codec drivers, there is + * no need to enabale micbias/pullup here + */ + + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + + /* Enable HW FSM */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + /* + * Check for any button press interrupts before starting 3-sec + * loop. + */ + rc = wait_for_completion_timeout(&mbhc->btn_press_compl, + msecs_to_jiffies(WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS)); + + WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result); + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res); + + if (!rc) { + pr_debug("%s No btn press interrupt\n", __func__); + if (!btn_result && !hs_comp_res) + plug_type = MBHC_PLUG_TYPE_HEADSET; + else if (!btn_result && hs_comp_res) + plug_type = MBHC_PLUG_TYPE_HIGH_HPH; + else + plug_type = MBHC_PLUG_TYPE_INVALID; + } else { + if (!btn_result && !hs_comp_res) + plug_type = MBHC_PLUG_TYPE_HEADPHONE; + else + plug_type = MBHC_PLUG_TYPE_INVALID; + } + + do { + cross_conn = wcd_check_cross_conn(mbhc); + try++; + } while (try < mbhc->swap_thr); + + /* + * Check for cross connection 4 times. + * Consider the result of the fourth iteration. + */ + if (cross_conn > 0) { + pr_debug("%s: cross con found, start polling\n", + __func__); + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + pr_debug("%s: Plug found, plug type is %d\n", + __func__, plug_type); + goto correct_plug_type; + } + + if ((plug_type == MBHC_PLUG_TYPE_HEADSET || + plug_type == MBHC_PLUG_TYPE_HEADPHONE) && + (!wcd_swch_level_remove(mbhc))) { + WCD_MBHC_RSC_LOCK(mbhc); + if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, + 0); + wcd_mbhc_find_plug_and_report(mbhc, plug_type); + WCD_MBHC_RSC_UNLOCK(mbhc); + } + +correct_plug_type: + + timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS); + while (!time_after(jiffies, timeout)) { + if (mbhc->hs_detect_work_stop) { + pr_debug("%s: stop requested: %d\n", __func__, + mbhc->hs_detect_work_stop); + wcd_enable_curr_micbias(mbhc, + WCD_MBHC_EN_NONE); + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic && + mbhc->micbias_enable) { + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + mbhc->component, MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) + mbhc->mbhc_cb->set_micbias_value( + mbhc->component); + mbhc->micbias_enable = false; + } + goto exit; + } + if (mbhc->btn_press_intr) { + wcd_cancel_btn_work(mbhc); + mbhc->btn_press_intr = false; + } + /* Toggle FSM */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + + /* allow sometime and re-check stop requested again */ + msleep(20); + if (mbhc->hs_detect_work_stop) { + pr_debug("%s: stop requested: %d\n", __func__, + mbhc->hs_detect_work_stop); + wcd_enable_curr_micbias(mbhc, + WCD_MBHC_EN_NONE); + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic && + mbhc->micbias_enable) { + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + mbhc->component, MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) + mbhc->mbhc_cb->set_micbias_value( + mbhc->component); + mbhc->micbias_enable = false; + } + goto exit; + } + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res); + + pr_debug("%s: hs_comp_res: %x\n", __func__, hs_comp_res); + if (mbhc->mbhc_cb->hph_pa_on_status) + is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(component); + + /* + * instead of hogging system by contineous polling, wait for + * sometime and re-check stop request again. + */ + msleep(180); + if (hs_comp_res && (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) { + spl_hs = wcd_mbhc_check_for_spl_headset(mbhc, + &spl_hs_count); + + if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) { + hs_comp_res = 0; + spl_hs = true; + mbhc->micbias_enable = true; + } + } + + if ((!hs_comp_res) && (!is_pa_on)) { + /* Check for cross connection*/ + ret = wcd_check_cross_conn(mbhc); + if (ret < 0) { + continue; + } else if (ret > 0) { + pt_gnd_mic_swap_cnt++; + no_gnd_mic_swap_cnt = 0; + if (pt_gnd_mic_swap_cnt < + mbhc->swap_thr) { + continue; + } else if (pt_gnd_mic_swap_cnt > + mbhc->swap_thr) { + /* + * This is due to GND/MIC switch didn't + * work, Report unsupported plug. + */ + pr_debug("%s: switch didn't work\n", + __func__); + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + goto report; + } else { + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + } + } else { + no_gnd_mic_swap_cnt++; + pt_gnd_mic_swap_cnt = 0; + plug_type = MBHC_PLUG_TYPE_HEADSET; + if ((no_gnd_mic_swap_cnt < + GND_MIC_SWAP_THRESHOLD) && + (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) { + continue; + } else { + no_gnd_mic_swap_cnt = 0; + } + } + if ((pt_gnd_mic_swap_cnt == mbhc->swap_thr) && + (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) { + /* + * if switch is toggled, check again, + * otherwise report unsupported plug + */ + if (mbhc->mbhc_cfg->swap_gnd_mic && + mbhc->mbhc_cfg->swap_gnd_mic(component, + true)) { + pr_debug("%s: US_EU gpio present,flip switch\n" + , __func__); + continue; + } + } + } + + WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch); + WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch); + if (hs_comp_res && !(hphl_sch || mic_sch)) { + pr_debug("%s: cable is extension cable\n", __func__); + plug_type = MBHC_PLUG_TYPE_HIGH_HPH; + wrk_complete = true; + } else { + pr_debug("%s: cable might be headset: %d\n", __func__, + plug_type); + if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) { + plug_type = MBHC_PLUG_TYPE_HEADSET; + if (!spl_hs_reported && + spl_hs_count == WCD_MBHC_SPL_HS_CNT) { + spl_hs_reported = true; + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_find_plug_and_report(mbhc, + plug_type); + WCD_MBHC_RSC_UNLOCK(mbhc); + continue; + } else if (spl_hs_reported) + continue; + /* + * Report headset only if not already reported + * and if there is not button press without + * release + */ + if (((mbhc->current_plug != + MBHC_PLUG_TYPE_HEADSET) && + (mbhc->current_plug != + MBHC_PLUG_TYPE_ANC_HEADPHONE)) && + !wcd_swch_level_remove(mbhc) && + !mbhc->btn_press_intr) { + pr_debug("%s: cable is %sheadset\n", + __func__, + ((spl_hs_count == + WCD_MBHC_SPL_HS_CNT) ? + "special ":"")); + goto report; + } + } + wrk_complete = false; + } + } + if (!wrk_complete && mbhc->btn_press_intr) { + pr_debug("%s: Can be slow insertion of headphone\n", __func__); + wcd_cancel_btn_work(mbhc); + /* Report as headphone only if previously + * not reported as lineout + */ + if (!mbhc->force_linein) + plug_type = MBHC_PLUG_TYPE_HEADPHONE; + } + /* + * If plug_tye is headset, we might have already reported either in + * detect_plug-type or in above while loop, no need to report again + */ + if (!wrk_complete && ((plug_type == MBHC_PLUG_TYPE_HEADSET) || + (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE))) { + pr_debug("%s: plug_type:0x%x already reported\n", + __func__, mbhc->current_plug); + goto enable_supply; + } + + if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH && + (!det_extn_cable_en)) { + if (wcd_is_special_headset(mbhc)) { + pr_debug("%s: Special headset found %d\n", + __func__, plug_type); + plug_type = MBHC_PLUG_TYPE_HEADSET; + goto report; + } + } + +report: + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low\n", __func__); + goto exit; + } + if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP && mbhc->btn_press_intr) { + pr_debug("%s: insertion of headphone with swap\n", __func__); + wcd_cancel_btn_work(mbhc); + plug_type = MBHC_PLUG_TYPE_HEADPHONE; + } + pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n", + __func__, plug_type, wrk_complete, + mbhc->btn_press_intr); + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_find_plug_and_report(mbhc, plug_type); + WCD_MBHC_RSC_UNLOCK(mbhc); +enable_supply: + if (mbhc->mbhc_cb->mbhc_micbias_control) + wcd_mbhc_update_fsm_source(mbhc, plug_type); + else + wcd_enable_mbhc_supply(mbhc, plug_type); +exit: + if (mbhc->mbhc_cb->mbhc_micbias_control && + !mbhc->micbias_enable) + mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, + MICB_DISABLE); + + /* + * If plug type is corrected from special headset to headphone, + * clear the micbias enable flag, set micbias back to 1.8V and + * disable micbias. + */ + if (plug_type == MBHC_PLUG_TYPE_HEADPHONE && + mbhc->micbias_enable) { + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control( + component, MIC_BIAS_2, + MICB_DISABLE); + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + component, + MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value(component); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0); + } + mbhc->micbias_enable = false; + } + + if (mbhc->mbhc_cb->micbias_enable_status) { + micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_1); + micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_2); + } + + if (mbhc->mbhc_cfg->detect_extn_cable && + ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) || + (plug_type == MBHC_PLUG_TYPE_HEADSET)) && + !mbhc->hs_detect_work_stop) { + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true); + WCD_MBHC_RSC_UNLOCK(mbhc); + } + if (mbhc->mbhc_cb->set_cap_mode) + mbhc->mbhc_cb->set_cap_mode(component, micbias1, micbias2); + + if (mbhc->mbhc_cb->hph_pull_down_ctrl) + mbhc->mbhc_cb->hph_pull_down_ctrl(component, true); + + mbhc->mbhc_cb->lock_sleep(mbhc, false); + pr_debug("%s: leave\n", __func__); +} + +static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + u8 hs_comp_result = 0, hphl_sch = 0, mic_sch = 0; + static u16 hphl_trigerred; + static u16 mic_trigerred; + unsigned long timeout; + bool removed = true; + int retry = 0; + bool hphpa_on = false; + u8 moisture_status = 0; + + pr_debug("%s: enter\n", __func__); + + WCD_MBHC_RSC_LOCK(mbhc); + + timeout = jiffies + + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); + do { + retry++; + /* + * read the result register every 10ms to look for + * any change in HS_COMP_RESULT bit + */ + usleep_range(10000, 10100); + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result); + pr_debug("%s: Check result reg for fake removal: hs_comp_res %x\n", + __func__, hs_comp_result); + if ((!hs_comp_result) && + retry > FAKE_REM_RETRY_ATTEMPTS) { + removed = false; + break; + } + } while (!time_after(jiffies, timeout)); + + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low ", __func__); + goto exit; + } + pr_debug("%s: headset %s actually removed\n", __func__, + removed ? "" : "not "); + + WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch); + WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch); + WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result); + + if (removed) { + if (mbhc->mbhc_cfg->moisture_en) { + if (mbhc->mbhc_cb->hph_pa_on_status) + if ( + mbhc->mbhc_cb->hph_pa_on_status( + mbhc->component)) { + hphpa_on = true; + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_HPHL_PA_EN, 0); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_HPH_PA_EN, 0); + } + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_GND, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_GND, 1); + /* wait for 50ms to get moisture status */ + usleep_range(50000, 50100); + + WCD_MBHC_REG_READ( + WCD_MBHC_MOISTURE_STATUS, moisture_status); + } + + if (mbhc->mbhc_cfg->moisture_en && !moisture_status) { + pr_debug("%s: moisture present in jack\n", __func__); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_MECH_DETECTION_TYPE, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) { + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_HEADSET); + extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 0); + } else if (mbhc->current_plug == + MBHC_PLUG_TYPE_HEADPHONE) + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_HEADPHONE); + extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 0); + } else if (mbhc->current_plug == + MBHC_PLUG_TYPE_GND_MIC_SWAP) +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_UNSUPPORTED); +#endif /* CONFIG_AUDIO_QGKI */ + extcon_set_state_sync(mbhc->extdev, EXTCON_MECHANICAL, 0); + } else if (mbhc->current_plug == + MBHC_PLUG_TYPE_HIGH_HPH) { + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_LINEOUT); + extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 0); + } + } else { + if (!(hphl_sch && mic_sch && hs_comp_result)) { + /* + * extension cable is still plugged in + * report it as LINEOUT device + */ + goto report_unplug; + } else { + if (!mic_sch) { + mic_trigerred++; + pr_debug( + "%s: Removal MIC trigerred %d\n", + __func__, mic_trigerred); + } + if (!hphl_sch) { + hphl_trigerred++; + pr_debug( + "%s: Removal HPHL trigerred %d\n", + __func__, hphl_trigerred); + } + if (mic_trigerred && hphl_trigerred) { + /* + * extension cable is still plugged in + * report it as LINEOUT device + */ + goto report_unplug; + } + } + } + } +exit: + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); + return IRQ_HANDLED; + +report_unplug: + wcd_mbhc_elec_hs_report_unplug(mbhc); + if (hphpa_on) { + hphpa_on = false; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1); + } + hphl_trigerred = 0; + mic_trigerred = 0; + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_hs_ins_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + bool detection_type = 0, hphl_sch = 0, mic_sch = 0; + u16 elect_result = 0; + static u16 hphl_trigerred; + static u16 mic_trigerred; + + pr_debug("%s: enter\n", __func__); + if (!mbhc->mbhc_cfg->detect_extn_cable) { + pr_debug("%s: Returning as Extension cable feature not enabled\n", + __func__); + return IRQ_HANDLED; + } + WCD_MBHC_RSC_LOCK(mbhc); + + WCD_MBHC_REG_READ(WCD_MBHC_ELECT_DETECTION_TYPE, detection_type); + WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, elect_result); + + pr_debug("%s: detection_type %d, elect_result %x\n", __func__, + detection_type, elect_result); + if (detection_type) { + /* check if both Left and MIC Schmitt triggers are triggered */ + WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch); + WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch); + if (hphl_sch && mic_sch) { + /* Go for plug type determination */ + pr_debug("%s: Go for plug type determination\n", + __func__); + goto determine_plug; + + } else { + if (mic_sch) { + mic_trigerred++; + pr_debug("%s: Insertion MIC trigerred %d\n", + __func__, mic_trigerred); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_ELECT_SCHMT_ISRC, + 0); + msleep(20); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_ELECT_SCHMT_ISRC, + 1); + } + if (hphl_sch) { + hphl_trigerred++; + pr_debug("%s: Insertion HPHL trigerred %d\n", + __func__, hphl_trigerred); + } + if (mic_trigerred && hphl_trigerred) { + /* Go for plug type determination */ + pr_debug("%s: Go for plug type determination\n", + __func__); + goto determine_plug; + } + } + } + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); + return IRQ_HANDLED; + +determine_plug: + /* + * Disable HPHL trigger and MIC Schmitt triggers. + * Setup for insertion detection. + */ + pr_debug("%s: Disable insertion interrupt\n", __func__); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, + false); + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); + hphl_trigerred = 0; + mic_trigerred = 0; + mbhc->is_extn_cable = true; + mbhc->btn_press_intr = false; + wcd_mbhc_detect_plug_type(mbhc); + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); + return IRQ_HANDLED; +} + +static struct wcd_mbhc_fn mbhc_fn = { + .wcd_mbhc_hs_ins_irq = wcd_mbhc_hs_ins_irq, + .wcd_mbhc_hs_rem_irq = wcd_mbhc_hs_rem_irq, + .wcd_mbhc_detect_plug_type = wcd_mbhc_detect_plug_type, + .wcd_mbhc_detect_anc_plug_type = wcd_mbhc_detect_anc_plug_type, + .wcd_cancel_hs_detect_plug = wcd_cancel_hs_detect_plug, +}; + +/* Function: wcd_mbhc_legacy_init + * @mbhc: MBHC function pointer + * Description: Initialize MBHC legacy based function pointers to MBHC structure + */ +void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc) +{ + if (!mbhc) { + pr_err("%s: mbhc is NULL\n", __func__); + return; + } + mbhc->mbhc_fn = &mbhc_fn; + INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug); +} +EXPORT_SYMBOL(wcd_mbhc_legacy_init); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-legacy.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-legacy.h new file mode 100644 index 0000000000..314bb1332c --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-legacy.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + */ +#ifndef __WCD_MBHC_LEGACY_H__ +#define __WCD_MBHC_LEGACY_H__ + +#include +#include + +#if IS_ENABLED(CONFIG_SND_SOC_WCD_MBHC_LEGACY) +void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc); +#else +static inline void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc) +{ +} +#endif + +#endif /* __WCD_MBHC_LEGACY_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-v2.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-v2.c new file mode 100644 index 0000000000..3e5e95d966 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-mbhc-v2.c @@ -0,0 +1,2271 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) +#include +#endif +#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C) +#include +#endif +#include +#include +#include +#include +#include +#include "wcd-mbhc-legacy.h" +#include "wcd-mbhc-adc.h" +#include + +static const unsigned int mbhc_ext_dev_supported_table[] = { + EXTCON_JACK_MICROPHONE, + EXTCON_JACK_HEADPHONE, + EXTCON_JACK_LINE_OUT, + EXTCON_MECHANICAL, + EXTCON_NONE, +}; + +struct mutex hphl_pa_lock; +struct mutex hphr_pa_lock; + +void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc, + struct snd_soc_jack *jack, int status, int mask) +{ + snd_soc_jack_report(jack, status, mask); +} +EXPORT_SYMBOL(wcd_mbhc_jack_report); + +#if IS_ENABLED(CONFIG_AUDIO_QGKI) +static void __hphocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status, + int irq) +{ + struct snd_soc_component *component = mbhc->component; + + dev_dbg(component->dev, "%s: clear ocp status %x\n", + __func__, jack_status); + + if (mbhc->hph_status & jack_status) { + mbhc->hph_status &= ~jack_status; + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + mbhc->hph_status, WCD_MBHC_JACK_MASK); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1); + /* + * reset retry counter as PA is turned off signifying + * start of new OCP detection session + */ + if (mbhc->intr_ids->hph_left_ocp) + mbhc->hphlocp_cnt = 0; + else + mbhc->hphrocp_cnt = 0; + mbhc->mbhc_cb->irq_control(component, irq, true); + } +} + +static void hphrocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status) +{ + __hphocp_off_report(mbhc, SND_JACK_OC_HPHR, + mbhc->intr_ids->hph_right_ocp); +} + +static void hphlocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status) +{ + __hphocp_off_report(mbhc, SND_JACK_OC_HPHL, + mbhc->intr_ids->hph_left_ocp); +} +#endif /* CONFIG_AUDIO_QGKI */ + +static void wcd_program_hs_vref(struct wcd_mbhc *mbhc) +{ + struct wcd_mbhc_plug_type_cfg *plug_type_cfg; + struct snd_soc_component *component = mbhc->component; + u32 reg_val; + + plug_type_cfg = WCD_MBHC_CAL_PLUG_TYPE_PTR( + mbhc->mbhc_cfg->calibration); + reg_val = ((plug_type_cfg->v_hs_max - HS_VREF_MIN_VAL) / 100); + + dev_dbg(component->dev, "%s: reg_val = %x\n", + __func__, reg_val); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_VREF, reg_val); +} + +static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias) +{ + struct wcd_mbhc_btn_detect_cfg *btn_det; + struct snd_soc_component *component = mbhc->component; + struct snd_soc_card *card = component->card; + s16 *btn_low, *btn_high; + + if (mbhc->mbhc_cfg->calibration == NULL) { + dev_err(card->dev, "%s: calibration data is NULL\n", __func__); + return; + } + + btn_det = WCD_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration); + btn_low = btn_det->_v_btn_low; + btn_high = ((void *)&btn_det->_v_btn_low) + + (sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn); + + mbhc->mbhc_cb->set_btn_thr(component, btn_low, btn_high, + btn_det->num_btn, micbias); +} + +void wcd_enable_curr_micbias(const struct wcd_mbhc *mbhc, + const enum wcd_mbhc_cs_mb_en_flag cs_mb_en) +{ + + /* + * Some codecs handle micbias/pullup enablement in codec + * drivers itself and micbias is not needed for regular + * plug type detection. So if micbias_control callback function + * is defined, just return. + */ + if (mbhc->mbhc_cb->mbhc_micbias_control) + return; + + pr_debug("%s: enter, cs_mb_en: %d\n", __func__, cs_mb_en); + + switch (cs_mb_en) { + case WCD_MBHC_EN_CS: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); + /* Program Button threshold registers as per CS */ + wcd_program_btn_threshold(mbhc, false); + break; + case WCD_MBHC_EN_MB: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + + /* Disable PULL_UP_EN & enable MICBIAS */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 2); + /* Program Button threshold registers as per MICBIAS */ + wcd_program_btn_threshold(mbhc, true); + break; + case WCD_MBHC_EN_PULLUP: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 1); + /* Program Button threshold registers as per MICBIAS */ + wcd_program_btn_threshold(mbhc, true); + break; + case WCD_MBHC_EN_NONE: + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0); + break; + default: + pr_debug("%s: Invalid parameter", __func__); + break; + } + + pr_debug("%s: exit\n", __func__); +} +EXPORT_SYMBOL(wcd_enable_curr_micbias); + +static const char *wcd_mbhc_get_event_string(int event) +{ + switch (event) { + case WCD_EVENT_PRE_MICBIAS_2_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_OFF); + case WCD_EVENT_POST_MICBIAS_2_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_OFF); + case WCD_EVENT_PRE_MICBIAS_2_ON: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_ON); + case WCD_EVENT_POST_MICBIAS_2_ON: + return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_ON); + case WCD_EVENT_PRE_HPHL_PA_ON: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_ON); + case WCD_EVENT_POST_HPHL_PA_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHL_PA_OFF); + case WCD_EVENT_PRE_HPHR_PA_ON: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_ON); + case WCD_EVENT_POST_HPHR_PA_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHR_PA_OFF); + case WCD_EVENT_PRE_HPHR_PA_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_OFF); + case WCD_EVENT_PRE_HPHL_PA_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_OFF); + case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: + return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_ON); + case WCD_EVENT_PRE_DAPM_MICBIAS_2_ON: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_ON); + case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); + case WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF); + case WCD_EVENT_OCP_OFF: + return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_OFF); + case WCD_EVENT_OCP_ON: + return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_ON); + case WCD_EVENT_INVALID: + default: + return WCD_MBHC_STRINGIFY(WCD_EVENT_INVALID); + } +} + +static int wcd_event_notify(struct notifier_block *self, unsigned long val, + void *data) +{ + struct wcd_mbhc *mbhc = (struct wcd_mbhc *)data; + enum wcd_notify_event event = (enum wcd_notify_event)val; + struct snd_soc_component *component = mbhc->component; + bool micbias2 = false; + bool micbias1 = false; + u8 fsm_en = 0; + + pr_debug("%s: event %s (%d)\n", __func__, + wcd_mbhc_get_event_string(event), event); + if (mbhc->mbhc_cb->micbias_enable_status) { + micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_2); + micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_1); + } + switch (event) { + /* MICBIAS usage change */ + case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: + mbhc->is_hs_recording = true; + pr_debug("%s: is_capture: %d\n", __func__, + mbhc->is_hs_recording); + break; + case WCD_EVENT_POST_MICBIAS_2_ON: + if (!mbhc->micbias_enable) + goto out_micb_en; + if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) { + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_PRECHARGE, + true); + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_SET_VAL, + true); + /* + * Special headset needs MICBIAS as 2.7V so wait for + * 50 msec for the MICBIAS to reach 2.7 volts. + */ + msleep(50); + } + if (mbhc->mbhc_cb->set_auto_zeroing) + mbhc->mbhc_cb->set_auto_zeroing(component, true); + if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_PRECHARGE, + false); +out_micb_en: + /* Disable current source if micbias enabled */ + if (mbhc->mbhc_cb->mbhc_micbias_control) { + WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); + if (fsm_en) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, + 0); + } else { + mbhc->is_hs_recording = true; + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + } + /* configure cap settings properly when micbias is enabled */ + if (mbhc->mbhc_cb->set_cap_mode) + mbhc->mbhc_cb->set_cap_mode(component, micbias1, true); + break; + case WCD_EVENT_PRE_MICBIAS_2_OFF: + /* + * Before MICBIAS_2 is turned off, if FSM is enabled, + * make sure current source is enabled so as to detect + * button press/release events + */ + if (mbhc->mbhc_cb->mbhc_micbias_control && + !mbhc->micbias_enable) { + WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); + if (fsm_en) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, + 3); + } + break; + /* MICBIAS usage change */ + case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: + mbhc->is_hs_recording = false; + pr_debug("%s: is_capture: %d\n", __func__, + mbhc->is_hs_recording); + break; + case WCD_EVENT_POST_MICBIAS_2_OFF: + if (!mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->is_hs_recording = false; + if (mbhc->micbias_enable) { + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + break; + } + + if (mbhc->mbhc_cb->set_auto_zeroing) + mbhc->mbhc_cb->set_auto_zeroing(component, false); + if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable) + mbhc->mbhc_cb->set_micbias_value(component); + /* Enable PULL UP if PA's are enabled */ + if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) || + (test_bit(WCD_MBHC_EVENT_PA_HPHR, + &mbhc->event_state))) + /* enable pullup and cs, disable mb */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP); + else + /* enable current source and disable mb, pullup*/ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS); + + /* configure cap settings properly when micbias is disabled */ + if (mbhc->mbhc_cb->set_cap_mode) + mbhc->mbhc_cb->set_cap_mode(component, micbias1, false); + break; + case WCD_EVENT_PRE_HPHL_PA_OFF: + break; + case WCD_EVENT_POST_HPHL_PA_OFF: + mutex_lock(&hphl_pa_lock); + clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + if (mbhc->hph_status & SND_JACK_OC_HPHL) + hphlocp_off_report(mbhc, SND_JACK_OC_HPHL); +#endif /* CONFIG_AUDIO_QGKI */ + clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, pullup & enable cs */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS); + mutex_unlock(&hphl_pa_lock); + clear_bit(WCD_MBHC_ANC0_OFF_ACK, &mbhc->hph_anc_state); + break; + case WCD_EVENT_PRE_HPHR_PA_OFF: + break; + case WCD_EVENT_POST_HPHR_PA_OFF: + mutex_lock(&hphr_pa_lock); + clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + if (mbhc->hph_status & SND_JACK_OC_HPHR) + hphrocp_off_report(mbhc, SND_JACK_OC_HPHR); +#endif /* CONFIG_AUDIO_QGKI */ + clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, pullup & enable cs */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS); + mutex_unlock(&hphr_pa_lock); + clear_bit(WCD_MBHC_ANC1_OFF_ACK, &mbhc->hph_anc_state); + break; + case WCD_EVENT_PRE_HPHL_PA_ON: + set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, enable pullup & cs */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP); + break; + case WCD_EVENT_PRE_HPHR_PA_ON: + set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, enable pullup & cs */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP); + break; + case WCD_EVENT_OCP_OFF: + mbhc->mbhc_cb->irq_control(mbhc->component, + mbhc->intr_ids->hph_left_ocp, + false); + break; + case WCD_EVENT_OCP_ON: + mbhc->mbhc_cb->irq_control(mbhc->component, + mbhc->intr_ids->hph_left_ocp, + true); + break; + default: + break; + } + return 0; +} + +int wcd_cancel_btn_work(struct wcd_mbhc *mbhc) +{ + int r; + + r = cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork); + /* + * if scheduled mbhc.mbhc_btn_dwork is canceled from here, + * we have to unlock from here instead btn_work + */ + if (r) + mbhc->mbhc_cb->lock_sleep(mbhc, false); + return r; +} +EXPORT_SYMBOL(wcd_cancel_btn_work); + +bool wcd_swch_level_remove(struct wcd_mbhc *mbhc) +{ + u16 result2 = 0; + + WCD_MBHC_REG_READ(WCD_MBHC_SWCH_LEVEL_REMOVE, result2); + return (result2) ? true : false; +} +EXPORT_SYMBOL(wcd_swch_level_remove); + +static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc) +{ + bool pa_turned_on = false; + u8 wg_time = 0; + + WCD_MBHC_REG_READ(WCD_MBHC_HPH_CNP_WG_TIME, wg_time); + wg_time += 1; + + mutex_lock(&hphr_pa_lock); + if (test_and_clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, + &mbhc->hph_pa_dac_state)) { + pr_debug("%s: HPHR clear flag and enable PA\n", __func__); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1); + pa_turned_on = true; + } + mutex_unlock(&hphr_pa_lock); + mutex_lock(&hphl_pa_lock); + if (test_and_clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, + &mbhc->hph_pa_dac_state)) { + pr_debug("%s: HPHL clear flag and enable PA\n", __func__); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1); + pa_turned_on = true; + } + mutex_unlock(&hphl_pa_lock); + + if (pa_turned_on) { + pr_debug("%s: PA was turned on by MBHC and not by DAPM\n", + __func__); + usleep_range(wg_time * 1000, wg_time * 1000 + 50); + } + + if (test_and_clear_bit(WCD_MBHC_ANC0_OFF_ACK, + &mbhc->hph_anc_state)) { + usleep_range(20000, 20100); + pr_debug("%s: HPHL ANC clear flag and enable ANC_EN\n", + __func__); + if (mbhc->mbhc_cb->update_anc_state) + mbhc->mbhc_cb->update_anc_state(mbhc->component, + true, 0); + } + + if (test_and_clear_bit(WCD_MBHC_ANC1_OFF_ACK, + &mbhc->hph_anc_state)) { + usleep_range(20000, 20100); + pr_debug("%s: HPHR ANC clear flag and enable ANC_EN\n", + __func__); + if (mbhc->mbhc_cb->update_anc_state) + mbhc->mbhc_cb->update_anc_state(mbhc->component, + true, 1); + } + +} + +static bool wcd_mbhc_is_hph_pa_on(struct wcd_mbhc *mbhc) +{ + bool hph_pa_on = false; + + WCD_MBHC_REG_READ(WCD_MBHC_HPH_PA_EN, hph_pa_on); + + return (hph_pa_on) ? true : false; +} + +static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc) +{ + u8 wg_time = 0; + + WCD_MBHC_REG_READ(WCD_MBHC_HPH_CNP_WG_TIME, wg_time); + wg_time += 1; + + /* If headphone PA is on, check if userspace receives + * removal event to sync-up PA's state + */ + if (wcd_mbhc_is_hph_pa_on(mbhc)) { + pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__); + set_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state); + set_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 0); + } else { + pr_debug("%s PA is off\n", __func__); + } + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 0); + usleep_range(wg_time * 1000, wg_time * 1000 + 50); + + + if (mbhc->mbhc_cb->is_anc_on && mbhc->mbhc_cb->is_anc_on(mbhc)) { + usleep_range(20000, 20100); + pr_debug("%s ANC is on, setting ANC_OFF_ACK\n", __func__); + set_bit(WCD_MBHC_ANC0_OFF_ACK, &mbhc->hph_anc_state); + set_bit(WCD_MBHC_ANC1_OFF_ACK, &mbhc->hph_anc_state); + if (mbhc->mbhc_cb->update_anc_state) { + mbhc->mbhc_cb->update_anc_state(mbhc->component, + false, 0); + mbhc->mbhc_cb->update_anc_state(mbhc->component, + false, 1); + } else { + pr_debug("%s ANC is off\n", __func__); + } + } +} + +int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + *zl = mbhc->zl; + *zr = mbhc->zr; + + if (*zl && *zr) + return 0; + else + return -EINVAL; +} +EXPORT_SYMBOL(wcd_mbhc_get_impedance); + +void wcd_mbhc_hs_elec_irq(struct wcd_mbhc *mbhc, int irq_type, + bool enable) +{ + int irq; + + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + if (irq_type == WCD_MBHC_ELEC_HS_INS) + irq = mbhc->intr_ids->mbhc_hs_ins_intr; + else if (irq_type == WCD_MBHC_ELEC_HS_REM) + irq = mbhc->intr_ids->mbhc_hs_rem_intr; + else { + pr_debug("%s: irq_type: %d, enable: %d\n", + __func__, irq_type, enable); + return; + } + + pr_debug("%s: irq: %d, enable: %d, intr_status:%lu\n", + __func__, irq, enable, mbhc->intr_status); + if ((test_bit(irq_type, &mbhc->intr_status)) != enable) { + mbhc->mbhc_cb->irq_control(mbhc->component, irq, enable); + if (enable) + set_bit(irq_type, &mbhc->intr_status); + else + clear_bit(irq_type, &mbhc->intr_status); + } +} +EXPORT_SYMBOL(wcd_mbhc_hs_elec_irq); + +void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, + enum snd_jack_types jack_type) +{ + struct snd_soc_component *component = mbhc->component; + bool is_pa_on = false; + u8 fsm_en = 0; + int extdev_type = 0; + + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + pr_debug("%s: enter insertion %d hph_status %x\n", + __func__, insertion, mbhc->hph_status); + if (!insertion) { + /* Report removal */ + mbhc->hph_status &= ~jack_type; + /* + * cancel possibly scheduled btn work and + * report release if we reported button press + */ + if (wcd_cancel_btn_work(mbhc)) { + pr_debug("%s: button press is canceled\n", __func__); + } else if (mbhc->buttons_pressed) { + pr_debug("%s: release of button press%d\n", + __func__, jack_type); + wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, 0, + mbhc->buttons_pressed); + mbhc->buttons_pressed &= + ~WCD_MBHC_JACK_BUTTON_MASK; + } + + if (mbhc->micbias_enable) { + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control( + component, MIC_BIAS_2, + MICB_DISABLE); + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + component, + MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value(component); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0); + } + mbhc->micbias_enable = false; + } + + mbhc->hph_type = WCD_MBHC_HPH_NONE; + mbhc->zl = mbhc->zr = 0; + pr_debug("%s: Reporting removal %d(%x)\n", __func__, + jack_type, mbhc->hph_status); + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + mbhc->hph_status, WCD_MBHC_JACK_MASK); + wcd_mbhc_set_and_turnoff_hph_padac(mbhc); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + hphrocp_off_report(mbhc, SND_JACK_OC_HPHR); + hphlocp_off_report(mbhc, SND_JACK_OC_HPHL); +#endif /* CONFIG_AUDIO_QGKI */ + mbhc->current_plug = MBHC_PLUG_TYPE_NONE; + mbhc->force_linein = false; + } else { + /* + * Report removal of current jack type. + * Headphone to headset shouldn't report headphone + * removal. + */ + if (mbhc->mbhc_cfg->detect_extn_cable && + (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH || + jack_type == SND_JACK_LINEOUT) && + (mbhc->hph_status && mbhc->hph_status != jack_type)) { + + if (mbhc->micbias_enable && + mbhc->hph_status == SND_JACK_HEADSET) { + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control( + component, MIC_BIAS_2, + MICB_DISABLE); + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + component, + MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value( + component); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_MICB_CTRL, 0); + } + mbhc->micbias_enable = false; + } + mbhc->hph_type = WCD_MBHC_HPH_NONE; + mbhc->zl = mbhc->zr = 0; + if (!mbhc->force_linein) { + pr_debug("%s: Reporting removal (%x)\n", + __func__, mbhc->hph_status); + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + 0, WCD_MBHC_JACK_MASK); + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) + extdev_type = EXTCON_JACK_HEADPHONE; + else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) + extdev_type = EXTCON_JACK_MICROPHONE; + else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) + extdev_type = EXTCON_JACK_LINE_OUT; + else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) + extdev_type = EXTCON_MECHANICAL; + + extcon_set_state_sync(mbhc->extdev, extdev_type, 0); + } + if (mbhc->hph_status == SND_JACK_LINEOUT) { + + pr_debug("%s: Enable micbias\n", __func__); + /* Disable current source and enable micbias */ + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + pr_debug("%s: set up elec removal detection\n", + __func__); + usleep_range(200, 210); + wcd_mbhc_hs_elec_irq(mbhc, + WCD_MBHC_ELEC_HS_REM, + true); + } +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT | + SND_JACK_UNSUPPORTED); +#else + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT); +#endif /* CONFIG_AUDIO_QGKI */ + } + + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET && + jack_type == SND_JACK_HEADPHONE) + mbhc->hph_status &= ~SND_JACK_HEADSET; + + /* Report insertion */ + if (jack_type == SND_JACK_HEADPHONE) + mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE; +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + else if (jack_type == SND_JACK_UNSUPPORTED) + mbhc->current_plug = MBHC_PLUG_TYPE_GND_MIC_SWAP; +#endif /* CONFIG_AUDIO_QGKI */ + else if (jack_type == SND_JACK_HEADSET) { + mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET; + mbhc->jiffies_atreport = jiffies; + } else if (jack_type == SND_JACK_LINEOUT) + mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; + else { + pr_debug("%s: invalid Jack type %d\n",__func__, jack_type); + } + + if (mbhc->mbhc_cb->hph_pa_on_status) + is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(component); + + if (mbhc->impedance_detect && + mbhc->mbhc_cb->compute_impedance && + (mbhc->mbhc_cfg->linein_th != 0) && + (!is_pa_on)) { + /* Set MUX_CTL to AUTO for Z-det */ + WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, + MUX_CTL_AUTO); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + mbhc->mbhc_cb->compute_impedance(mbhc, + &mbhc->zl, &mbhc->zr); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, + fsm_en); + if ((mbhc->zl > mbhc->mbhc_cfg->linein_th) && + (mbhc->zr > mbhc->mbhc_cfg->linein_th) && + (jack_type == SND_JACK_HEADPHONE)) { + jack_type = SND_JACK_LINEOUT; + mbhc->force_linein = true; + mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; + if (mbhc->hph_status) { +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT | + SND_JACK_UNSUPPORTED); +#else + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT); +#endif /* CONFIG_AUDIO_QGKI */ + wcd_mbhc_jack_report(mbhc, + &mbhc->headset_jack, + mbhc->hph_status, + WCD_MBHC_JACK_MASK); + } + pr_debug("%s: Marking jack type as SND_JACK_LINEOUT\n", + __func__); + } + } + + /* Do not calculate impedance again for lineout + * as during playback pa is on and impedance values + * will not be correct resulting in lineout detected + * as headphone. + */ + if ((is_pa_on) && mbhc->force_linein == true) { + jack_type = SND_JACK_LINEOUT; + mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; + if (mbhc->hph_status) { +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT | + SND_JACK_UNSUPPORTED); +#else + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT); +#endif /* CONFIG_AUDIO_QGKI */ + wcd_mbhc_jack_report(mbhc, + &mbhc->headset_jack, + mbhc->hph_status, + WCD_MBHC_JACK_MASK); + } + } + + mbhc->hph_status |= jack_type; + + if (jack_type == SND_JACK_HEADPHONE && + mbhc->mbhc_cb->mbhc_micb_ramp_control) + mbhc->mbhc_cb->mbhc_micb_ramp_control(component, false); + + pr_debug("%s: Reporting insertion %d(%x)\n", __func__, + jack_type, mbhc->hph_status); + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + (mbhc->hph_status | SND_JACK_MECHANICAL), + WCD_MBHC_JACK_MASK); + wcd_mbhc_clr_and_turnon_hph_padac(mbhc); + } + pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status); +} +EXPORT_SYMBOL(wcd_mbhc_report_plug); + +void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc) +{ + /* cancel pending button press */ + if (wcd_cancel_btn_work(mbhc)) + pr_debug("%s: button press is canceled\n", __func__); + /* cancel correct work function */ + if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug) + mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc, + &mbhc->correct_plug_swch); + else + pr_info("%s: hs_detect_plug work not cancelled\n", __func__); + + pr_debug("%s: Report extension cable\n", __func__); + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); + extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 1); + /* + * If PA is enabled HPHL schmitt trigger can + * be unreliable, make sure to disable it + */ + if (test_bit(WCD_MBHC_EVENT_PA_HPHL, + &mbhc->event_state)) + wcd_mbhc_set_and_turnoff_hph_padac(mbhc); + /* + * Disable HPHL trigger and MIC Schmitt triggers. + * Setup for insertion detection. + */ + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, + false); + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE); + /* Disable HW FSM */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 3); + + /* Set the detection type appropriately */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, 1); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, + true); +} +EXPORT_SYMBOL(wcd_mbhc_elec_hs_report_unplug); + +void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc, + enum wcd_mbhc_plug_type plug_type) +{ + bool anc_mic_found = false; + enum snd_jack_types jack_type; + int ret = 0; + + if (mbhc->deinit_in_progress) { + pr_info("%s: mbhc deinit in progess: ignore report\n", __func__); + return; + } + + pr_debug("%s: enter current_plug(%d) new_plug(%d)\n", + __func__, mbhc->current_plug, plug_type); + + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + if (mbhc->current_plug == plug_type) { + pr_debug("%s: cable already reported, exit\n", __func__); + goto exit; + } + + if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) { + /* + * Nothing was reported previously + * report a headphone or unsupported + */ + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE); + ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 1); + } else if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) { + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); + ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_HEADPHONE, 0); + } + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) { + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); + ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 0); + } +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED); +#endif /* CONFIG_AUDIO_QGKI */ + ret = extcon_set_state_sync(mbhc->extdev, EXTCON_MECHANICAL, 1); + } else if (plug_type == MBHC_PLUG_TYPE_HEADSET) { + if (mbhc->mbhc_cfg->enable_anc_mic_detect && + mbhc->mbhc_fn->wcd_mbhc_detect_anc_plug_type) + anc_mic_found = + mbhc->mbhc_fn->wcd_mbhc_detect_anc_plug_type(mbhc); + jack_type = SND_JACK_HEADSET; + + /* + * If Headphone was reported previously, this will + * only report the mic line + */ + wcd_mbhc_report_plug(mbhc, 1, jack_type); + ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_MICROPHONE, 1); + } else if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) { + if (mbhc->mbhc_cfg->detect_extn_cable) { + /* High impedance device found. Report as LINEOUT */ + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); + ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 1); + pr_debug("%s: setup mic trigger for further detection\n", + __func__); + + /* Disable HW FSM and current source */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + /* Setup for insertion detection */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, + 1); + /* + * Enable HPHL trigger and MIC Schmitt triggers + * and request for elec insertion interrupts + */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, + 3); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, + true); + } else { + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); + ret = extcon_set_state_sync(mbhc->extdev, EXTCON_JACK_LINE_OUT, 1); + } + } else { + WARN(1, "Unexpected current plug_type %d, plug_type %d\n", + mbhc->current_plug, plug_type); + } +exit: + pr_debug("%s: leave\n", __func__); +} +EXPORT_SYMBOL(wcd_mbhc_find_plug_and_report); + +static bool wcd_mbhc_moisture_detect(struct wcd_mbhc *mbhc, bool detection_type) +{ + bool ret = false; + + if (!mbhc->mbhc_cfg->moisture_en && + !mbhc->mbhc_cfg->moisture_duty_cycle_en) + return ret; + + if (!mbhc->mbhc_cb->mbhc_get_moisture_status || + !mbhc->mbhc_cb->mbhc_moisture_polling_ctrl || + !mbhc->mbhc_cb->mbhc_moisture_detect_en) + return ret; + + if (mbhc->mbhc_cb->mbhc_get_moisture_status(mbhc)) { + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_DET_EN, 0); + mbhc->mbhc_cb->mbhc_moisture_polling_ctrl(mbhc, true); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE, + detection_type); + ret = true; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + if (mbhc->mbhc_cfg->gnd_det_en) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_DET_EN, 1); + } else { + mbhc->mbhc_cb->mbhc_moisture_polling_ctrl(mbhc, false); + mbhc->mbhc_cb->mbhc_moisture_detect_en(mbhc, false); + } + + return ret; +} + +static void wcd_mbhc_set_hsj_connect(struct wcd_mbhc *mbhc, bool connect) +{ + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + struct snd_soc_component *component = mbhc->component; + if (mbhc->wcd_usbss_aatc_dev_np) { + if (connect) { + if (mbhc->mbhc_cb && mbhc->mbhc_cb->zdet_leakage_resistance) { + /* enable 1M pull-up */ + mbhc->mbhc_cb->zdet_leakage_resistance(mbhc, false); + } + + if (of_find_property(component->card->dev->of_node, + "qcom,usbss-hsj-connect-enabled", NULL)) + wcd_usbss_switch_update(WCD_USBSS_HSJ_CONNECT, + WCD_USBSS_CABLE_CONNECT); + } else { + if (of_find_property(component->card->dev->of_node, + "qcom,usbss-hsj-connect-enabled", NULL)) + wcd_usbss_switch_update(WCD_USBSS_HSJ_CONNECT, + WCD_USBSS_CABLE_DISCONNECT); + + if (mbhc->mbhc_cb && mbhc->mbhc_cb->zdet_leakage_resistance) { + /* disable 1M pull-up */ + mbhc->mbhc_cb->zdet_leakage_resistance(mbhc, true); + } + } + } +#endif +} + +static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) +{ + bool detection_type = 0; + bool micbias1 = false; + struct snd_soc_component *component = mbhc->component; + enum snd_jack_types jack_type; + int extdev_type = 0; + + dev_dbg(component->dev, "%s: enter\n", __func__); + WCD_MBHC_RSC_LOCK(mbhc); + mbhc->in_swch_irq_handler = true; + + /* cancel pending button press */ + if (wcd_cancel_btn_work(mbhc)) + pr_debug("%s: button press is canceled\n", __func__); + + WCD_MBHC_REG_READ(WCD_MBHC_MECH_DETECTION_TYPE, detection_type); + + /* Set the detection type appropriately */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE, + !detection_type); + + pr_debug("%s: mbhc->current_plug: %d detection_type: %d\n", __func__, + mbhc->current_plug, detection_type); + if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug) + mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc, + &mbhc->correct_plug_swch); + else + pr_info("%s: hs_detect_plug work not cancelled\n", __func__); + + /* Enable micbias ramp */ + if (mbhc->mbhc_cb->mbhc_micb_ramp_control) + mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true); + + if (mbhc->mbhc_cb->micbias_enable_status) + micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, + MIC_BIAS_1); + + if ((mbhc->current_plug == MBHC_PLUG_TYPE_NONE) && + detection_type) { + + wcd_mbhc_set_hsj_connect(mbhc, 1); + /* If moisture is present, then enable polling, disable + * moisture detection and wait for interrupt + */ + if (wcd_mbhc_moisture_detect(mbhc, detection_type)) + goto done; + + /* Make sure MASTER_BIAS_CTL is enabled */ + mbhc->mbhc_cb->mbhc_bias(component, true); + + if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_TAIL_CURR, true); + + if (!mbhc->mbhc_cfg->hs_ext_micbias && + mbhc->mbhc_cb->micb_internal) + /* + * Enable Tx2 RBias if the headset + * is using internal micbias + */ + mbhc->mbhc_cb->micb_internal(component, 1, true); + + /* Remove micbias pulldown */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 0); + /* Apply trim if needed on the device */ + if (mbhc->mbhc_cb->trim_btn_reg) + mbhc->mbhc_cb->trim_btn_reg(component); + /* Enable external voltage source to micbias if present */ + if (mbhc->mbhc_cb->enable_mb_source) + mbhc->mbhc_cb->enable_mb_source(mbhc, true); + mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; + if (mbhc->mbhc_fn) + mbhc->mbhc_fn->wcd_mbhc_detect_plug_type(mbhc); + } else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE) + && !detection_type) { + /* Disable external voltage source to micbias if present */ + if (mbhc->mbhc_cb->enable_mb_source) + mbhc->mbhc_cb->enable_mb_source(mbhc, false); + /* Disable HW FSM */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) + mbhc->mbhc_cb->mbhc_common_micb_ctrl(component, + MBHC_COMMON_MICB_TAIL_CURR, false); + + if (mbhc->mbhc_cb->set_cap_mode) + mbhc->mbhc_cb->set_cap_mode(component, micbias1, false); + + mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; + switch (mbhc->current_plug) { + case MBHC_PLUG_TYPE_HEADPHONE: + jack_type = SND_JACK_HEADPHONE; + extdev_type = EXTCON_JACK_HEADPHONE; + break; + case MBHC_PLUG_TYPE_GND_MIC_SWAP: +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + jack_type = SND_JACK_UNSUPPORTED; +#else + jack_type = SND_JACK_HEADPHONE; +#endif /* CONFIG_AUDIO_QGKI */ + extdev_type = EXTCON_MECHANICAL; + break; + case MBHC_PLUG_TYPE_HEADSET: + /* make sure to turn off Rbias */ + if (mbhc->mbhc_cb->micb_internal) + mbhc->mbhc_cb->micb_internal(component, + 1, false); + /* Pulldown micbias */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 1); + jack_type = SND_JACK_HEADSET; + extdev_type = EXTCON_JACK_MICROPHONE; + break; + case MBHC_PLUG_TYPE_HIGH_HPH: + if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0); + mbhc->is_extn_cable = false; + jack_type = SND_JACK_LINEOUT; + extdev_type = EXTCON_JACK_LINE_OUT; + break; + default: + pr_info("%s: Invalid current plug: %d\n", + __func__, mbhc->current_plug); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + jack_type = SND_JACK_UNSUPPORTED; +#else + jack_type = SND_JACK_HEADPHONE; +#endif /* CONFIG_AUDIO_QGKI */ + extdev_type = EXTCON_MECHANICAL; + break; + } + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); + mbhc->extn_cable_hph_rem = false; + wcd_mbhc_report_plug(mbhc, 0, jack_type); + extcon_set_state_sync(mbhc->extdev, extdev_type, 0); + + if (mbhc->mbhc_cfg->enable_usbc_analog) { + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + if (mbhc->mbhc_cb->clk_setup) + mbhc->mbhc_cb->clk_setup( + mbhc->component, false); + } + + if (mbhc->mbhc_cfg->moisture_en || + mbhc->mbhc_cfg->moisture_duty_cycle_en) { + if (mbhc->mbhc_cb->mbhc_moisture_polling_ctrl) + mbhc->mbhc_cb->mbhc_moisture_polling_ctrl(mbhc, + false); + if (mbhc->mbhc_cb->mbhc_moisture_detect_en) + mbhc->mbhc_cb->mbhc_moisture_detect_en(mbhc, + false); + } + wcd_mbhc_set_hsj_connect(mbhc, 0); + + } else if (!detection_type) { + /* Disable external voltage source to micbias if present */ + if (mbhc->mbhc_cb->enable_mb_source) + mbhc->mbhc_cb->enable_mb_source(mbhc, false); + /* Disable HW FSM */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->extn_cable_hph_rem = false; + } + +done: + mbhc->in_swch_irq_handler = false; + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); +} + +static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data) +{ + int r = IRQ_HANDLED; + struct wcd_mbhc *mbhc = data; + + pr_debug("%s: enter\n", __func__); + + if (mbhc == NULL) { + pr_err("%s: NULL irq data\n", __func__); + return IRQ_NONE; + } + /* WCD939x USB AATC did not required mech plug detection, will receive + * insertion/removal events from UCSI layer + */ + if (mbhc->mbhc_cfg->enable_usbc_analog && mbhc->wcd_usbss_aatc_dev_np) { + pr_debug("%s: leave, (irq_none)\n", __func__); + return IRQ_NONE; + } + + if (unlikely((mbhc->mbhc_cb->lock_sleep(mbhc, true)) == false)) { + pr_warn("%s: failed to hold suspend\n", __func__); + r = IRQ_NONE; + } else { + /* Call handler */ + wcd_mbhc_swch_irq_handler(mbhc); + mbhc->mbhc_cb->lock_sleep(mbhc, false); + } + pr_debug("%s: leave %d\n", __func__, r); + return r; +} + +int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc) +{ + int mask = 0; + int btn; + + btn = mbhc->mbhc_cb->map_btn_code_to_num(mbhc->component); + + switch (btn) { + case 0: + mask = SND_JACK_BTN_0; + break; + case 1: + mask = SND_JACK_BTN_1; + break; + case 2: + mask = SND_JACK_BTN_2; + break; + case 3: + mask = SND_JACK_BTN_3; + break; + case 4: + mask = SND_JACK_BTN_4; + break; + case 5: + mask = SND_JACK_BTN_5; + break; + default: + break; + } + + return mask; +} +EXPORT_SYMBOL(wcd_mbhc_get_button_mask); + +static void wcd_btn_lpress_fn(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wcd_mbhc *mbhc; + s16 btn_result = 0; + + pr_debug("%s: Enter\n", __func__); + + dwork = to_delayed_work(work); + mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork); + + WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result); + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) { + pr_debug("%s: Reporting long button press event, btn_result: %d\n", + __func__, btn_result); + wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, + mbhc->buttons_pressed, mbhc->buttons_pressed); + } + pr_debug("%s: leave\n", __func__); + mbhc->mbhc_cb->lock_sleep(mbhc, false); +} + +static bool wcd_mbhc_fw_validate(const void *data, size_t size) +{ + u32 cfg_offset; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + struct firmware_cal fw; + + fw.data = (void *)data; + fw.size = size; + + if (fw.size < WCD_MBHC_CAL_MIN_SIZE) + return false; + + /* + * Previous check guarantees that there is enough fw data up + * to num_btn + */ + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(fw.data); + cfg_offset = (u32) ((void *) btn_cfg - (void *) fw.data); + if (fw.size < (cfg_offset + WCD_MBHC_CAL_BTN_SZ(btn_cfg))) + return false; + + return true; +} + +static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + int mask; + unsigned long msec_val; + + pr_debug("%s: enter\n", __func__); + complete(&mbhc->btn_press_compl); + WCD_MBHC_RSC_LOCK(mbhc); + wcd_cancel_btn_work(mbhc); + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low ", __func__); + goto done; + } + + mbhc->is_btn_press = true; + msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport); + pr_debug("%s: msec_val = %ld\n", __func__, msec_val); + if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) { + pr_debug("%s: Too short, ignore button press\n", __func__); + goto done; + } + + /* If switch interrupt already kicked in, ignore button press */ + if (mbhc->in_swch_irq_handler) { + pr_debug("%s: Swtich level changed, ignore button press\n", + __func__); + goto done; + } + mask = wcd_mbhc_get_button_mask(mbhc); + if (mask == SND_JACK_BTN_0) + mbhc->btn_press_intr = true; + + if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) { + pr_debug("%s: Plug isn't headset, ignore button press\n", + __func__); + goto done; + } + mbhc->buttons_pressed |= mask; + mbhc->mbhc_cb->lock_sleep(mbhc, true); + if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, + msecs_to_jiffies(400)) == 0) { + WARN(1, "Button pressed twice without release event\n"); + mbhc->mbhc_cb->lock_sleep(mbhc, false); + } +done: + pr_debug("%s: leave\n", __func__); + WCD_MBHC_RSC_UNLOCK(mbhc); + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_release_handler(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + int ret; + + pr_debug("%s: enter\n", __func__); + WCD_MBHC_RSC_LOCK(mbhc); + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low ", __func__); + goto exit; + } + + if (mbhc->is_btn_press) { + mbhc->is_btn_press = false; + } else { + pr_debug("%s: This release is for fake btn press\n", __func__); + goto exit; + } + + /* + * If current plug is headphone then there is no chance to + * get btn release interrupt, so connected cable should be + * headset not headphone. + * For ADC MBHC, ADC_COMPLETE interrupt will be generated + * in this case. So skip the check here. + */ + if (mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY && + mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET); + goto exit; + + } + if (mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK) { + ret = wcd_cancel_btn_work(mbhc); + if (ret == 0) { + pr_debug("%s: Reporting long button release event\n", + __func__); + wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, + 0, mbhc->buttons_pressed); + } else { + if (mbhc->in_swch_irq_handler) { + pr_debug("%s: Switch irq kicked in, ignore\n", + __func__); + } else { + pr_debug("%s: Reporting btn press\n", + __func__); + wcd_mbhc_jack_report(mbhc, + &mbhc->button_jack, + mbhc->buttons_pressed, + mbhc->buttons_pressed); + pr_debug("%s: Reporting btn release\n", + __func__); + wcd_mbhc_jack_report(mbhc, + &mbhc->button_jack, + 0, mbhc->buttons_pressed); + } + } + mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK; + } +exit: + pr_debug("%s: leave\n", __func__); + WCD_MBHC_RSC_UNLOCK(mbhc); + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + int val; + + pr_debug("%s: received HPHL OCP irq\n", __func__); + if (mbhc) { + if (mbhc->mbhc_cb->hph_register_recovery) { + if (mbhc->mbhc_cb->hph_register_recovery(mbhc)) { + WCD_MBHC_REG_READ(WCD_MBHC_HPHR_OCP_STATUS, + val); + if ((val != -EINVAL) && val) + mbhc->is_hph_ocp_pending = true; + goto done; + } + } + + if (mbhc->hphlocp_cnt < OCP_ATTEMPT) { + mbhc->hphlocp_cnt++; + pr_debug("%s: retry, hphlocp_cnt: %d\n", __func__, + mbhc->hphlocp_cnt); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1); + } else { + mbhc->mbhc_cb->irq_control(mbhc->component, + mbhc->intr_ids->hph_left_ocp, + false); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + mbhc->hph_status |= SND_JACK_OC_HPHL; +#endif /* CONFIG_AUDIO_QGKI */ + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + mbhc->hph_status, + WCD_MBHC_JACK_MASK); + } + } else { + pr_err("%s: Bad wcd9xxx_spmi private data\n", __func__); + } +done: + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + + pr_debug("%s: received HPHR OCP irq\n", __func__); + + if (!mbhc) { + pr_err("%s: Bad mbhc private data\n", __func__); + goto done; + } + + if (mbhc->is_hph_ocp_pending) { + mbhc->is_hph_ocp_pending = false; + goto done; + } + + if (mbhc->mbhc_cb->hph_register_recovery) { + if (mbhc->mbhc_cb->hph_register_recovery(mbhc)) + /* register corruption, hence reset registers */ + goto done; + } + if (mbhc->hphrocp_cnt < OCP_ATTEMPT) { + mbhc->hphrocp_cnt++; + pr_debug("%s: retry, hphrocp_cnt: %d\n", __func__, + mbhc->hphrocp_cnt); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1); + } else { + mbhc->mbhc_cb->irq_control(mbhc->component, + mbhc->intr_ids->hph_right_ocp, + false); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + mbhc->hph_status |= SND_JACK_OC_HPHR; +#endif /* CONFIG_AUDIO_QGKI */ + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + mbhc->hph_status, WCD_MBHC_JACK_MASK); + } +done: + return IRQ_HANDLED; +} + +static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) +{ + int ret = 0; + struct snd_soc_component *component = mbhc->component; + + pr_debug("%s: enter\n", __func__); + WCD_MBHC_RSC_LOCK(mbhc); + + /* enable HS detection */ + if (mbhc->mbhc_cb->hph_pull_up_control_v2) + mbhc->mbhc_cb->hph_pull_up_control_v2(component, + HS_PULLUP_I_DEFAULT); + else if (mbhc->mbhc_cb->hph_pull_up_control) + mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT); + else + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3); + + /* Configure for moisture detection when duty cycle is not enabled. + * Otherwise disable moisture detection. + */ + if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config + && !mbhc->mbhc_cfg->moisture_duty_cycle_en) + mbhc->mbhc_cb->mbhc_moisture_config(mbhc); + else if (mbhc->mbhc_cb->mbhc_moisture_detect_en) + mbhc->mbhc_cb->mbhc_moisture_detect_en(mbhc, false); + + /* + * For USB analog we need to override the switch configuration. + * Also, disable hph_l pull-up current source as HS_DET_L is driven + * by an external source + */ + if (mbhc->mbhc_cfg->enable_usbc_analog) { + if (mbhc->mbhc_cb->hph_pull_up_control_v2) + mbhc->mbhc_cb->hph_pull_up_control_v2(component, + HS_PULLUP_I_OFF); + else if (mbhc->mbhc_cb->hph_pull_up_control) + mbhc->mbhc_cb->hph_pull_up_control(component, I_OFF); + else + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, + 0); + } + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1); + if (mbhc->mbhc_cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl) + mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1); + + /* + * Disable L_DET for USB-C analog audio to avoid spurious interrupts + * when a non-audio accessory is inserted. L_DET_EN sets to 1 when FSA + * I2C driver notifies that ANALOG_AUDIO_ADAPTER is inserted + */ + if (mbhc->mbhc_cfg->enable_usbc_analog) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + else + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + + if (mbhc->mbhc_cfg->enable_usbc_analog) { + /* Insertion debounce set to 48ms */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 4); + } else { + /* Insertion debounce set to 96ms */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6); + } + + /* Button Debounce set to 16ms */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2); + + /* enable bias */ + mbhc->mbhc_cb->mbhc_bias(component, true); + /* enable MBHC clock */ + if (mbhc->mbhc_cb->clk_setup) { + if (mbhc->mbhc_cfg->enable_usbc_analog) + mbhc->mbhc_cb->clk_setup(component, false); + else + mbhc->mbhc_cb->clk_setup(component, true); + } + + /* program HS_VREF value */ + wcd_program_hs_vref(mbhc); + + wcd_program_btn_threshold(mbhc, false); + + + reinit_completion(&mbhc->btn_press_compl); + + WCD_MBHC_RSC_UNLOCK(mbhc); + pr_debug("%s: leave\n", __func__); + return ret; +} + +static void wcd_mbhc_fw_read(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wcd_mbhc *mbhc; + struct snd_soc_component *component; + const struct firmware *fw; + struct firmware_cal *fw_data = NULL; + int ret = -1, retry = 0; + bool use_default_cal = false; + + dwork = to_delayed_work(work); + mbhc = container_of(dwork, struct wcd_mbhc, mbhc_firmware_dwork); + component = mbhc->component; + + while (retry < FW_READ_ATTEMPTS) { + retry++; + pr_debug("%s:Attempt %d to request MBHC firmware\n", + __func__, retry); + if (mbhc->mbhc_cb->get_hwdep_fw_cal) + fw_data = mbhc->mbhc_cb->get_hwdep_fw_cal(mbhc, + WCD9XXX_MBHC_CAL); + if (!fw_data) + ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin", + component->dev); + /* + * if request_firmware and hwdep cal both fail then + * sleep for 4sec for the userspace to send data to kernel + * retry for few times before bailing out + */ + if ((ret != 0) && !fw_data) { + usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT + + WCD_MBHC_USLEEP_RANGE_MARGIN_US); + } else { + pr_debug("%s: MBHC Firmware read successful\n", + __func__); + break; + } + } + if (!fw_data) + pr_debug("%s: using request_firmware\n", __func__); + else + pr_debug("%s: using hwdep cal\n", __func__); + + if (ret != 0 && !fw_data) { + pr_err("%s: Cannot load MBHC firmware use default cal\n", + __func__); + use_default_cal = true; + } + if (!use_default_cal) { + const void *data; + size_t size; + + if (fw_data) { + data = fw_data->data; + size = fw_data->size; + } else { + data = fw->data; + size = fw->size; + } + if (wcd_mbhc_fw_validate(data, size) == false) { + pr_err("%s: Invalid MBHC cal data size use default cal\n", + __func__); + if (!fw_data) + release_firmware(fw); + } else { + if (fw_data) { + mbhc->mbhc_cfg->calibration = + (void *)fw_data->data; + mbhc->mbhc_cal = fw_data; + } else { + mbhc->mbhc_cfg->calibration = + (void *)fw->data; + mbhc->mbhc_fw = fw; + } + } + + } + + (void) wcd_mbhc_initialise(mbhc); +} + +static int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc) +{ + enum snd_jack_types type; + int i, ret, result = 0; + int *btn_key_code; + + btn_key_code = mbhc->mbhc_cfg->key_code; + + for (i = 0 ; i < WCD_MBHC_KEYCODE_NUM ; i++) { + if (btn_key_code[i] != 0) { + switch (i) { + case 0: + type = SND_JACK_BTN_0; + break; + case 1: + type = SND_JACK_BTN_1; + break; + case 2: + type = SND_JACK_BTN_2; + break; + case 3: + type = SND_JACK_BTN_3; + break; + case 4: + type = SND_JACK_BTN_4; + break; + case 5: + type = SND_JACK_BTN_5; + break; + default: + WARN_ONCE(1, "Wrong button number:%d\n", i); + result = -1; + return result; + } + ret = snd_jack_set_key(mbhc->button_jack.jack, + type, + btn_key_code[i]); + if (ret) { + pr_err("%s: Failed to set code for %d\n", + __func__, btn_key_code[i]); + result = -1; + return result; + } + input_set_capability( + mbhc->button_jack.jack->input_dev, + EV_KEY, btn_key_code[i]); + pr_debug("%s: set btn%d key code:%d\n", __func__, + i, btn_key_code[i]); + } + } + if (btn_key_code[0]) + mbhc->is_btn_already_regd = true; + return result; +} + +#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C) || IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) +static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, + unsigned long mode, void *ptr) +{ + struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, aatc_dev_nb); +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + int l_det_en = 0, detection_type = 0; + bool *cable_status = (bool*) ptr; +#endif + + if (!mbhc) + return -EINVAL; + + + if (mode == TYPEC_ACCESSORY_AUDIO) { + dev_dbg(mbhc->component->dev, "enter, %s: mode = %lu\n", __func__, mode); +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (mbhc->wcd_usbss_aatc_dev_np) { + if (cable_status == NULL) + wcd_usbss_switch_update(WCD_USBSS_AATC, WCD_USBSS_CABLE_CONNECT); + else { + if (!*cable_status) + wcd_usbss_switch_update(WCD_USBSS_AATC, + WCD_USBSS_CABLE_CONNECT); + else + dev_dbg(mbhc->component->dev, + "skip AATC switch settings, cable_status= %d", + *cable_status); + } + } +#endif + if (mbhc->mbhc_cb->clk_setup) + mbhc->mbhc_cb->clk_setup(mbhc->component, true); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (mbhc->wcd_usbss_aatc_dev_np) { + if (unlikely((mbhc->mbhc_cb->lock_sleep(mbhc, true)) == false)) + pr_warn("%s: failed to hold suspend\n", __func__); + else { + if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE) + wcd_mbhc_swch_irq_handler(mbhc); + mbhc->mbhc_cb->lock_sleep(mbhc, false); + } + } +#endif + } else if (mode < TYPEC_MAX_ACCESSORY) { +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (mbhc->wcd_usbss_aatc_dev_np) { + WCD_MBHC_REG_READ(WCD_MBHC_L_DET_EN, l_det_en); + WCD_MBHC_REG_READ(WCD_MBHC_MECH_DETECTION_TYPE, detection_type); + if ((mode == TYPEC_ACCESSORY_NONE) && !detection_type) { + if (unlikely((mbhc->mbhc_cb->lock_sleep(mbhc, true)) == false)) + pr_warn("%s: failed to hold suspend\n", __func__); + else { + wcd_mbhc_swch_irq_handler(mbhc); + mbhc->mbhc_cb->lock_sleep(mbhc, false); + } + wcd_usbss_switch_update(WCD_USBSS_AATC, WCD_USBSS_CABLE_DISCONNECT); + dev_dbg(mbhc->component->dev, "leave, %s: mode = %lu\n", + __func__, mode); + } + } +#endif + } else if (mode == TYPEC_MAX_ACCESSORY) { + if (mbhc->mbhc_cb->surge_reset_routine) + mbhc->mbhc_cb->surge_reset_routine(mbhc); + } + return 0; +} +#else +static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, + unsigned long mode, void *ptr) +{ + pr_info("%s: mode = %lu, handler not implemented\n", __func__, mode); + return 0; +} +#endif + +int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) +{ + int rc = 0; + struct snd_soc_component *component; + struct snd_soc_card *card; + const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported"; + + if (!mbhc || !mbhc_cfg) + return -EINVAL; + + component = mbhc->component; + card = component->card; + + /* update the mbhc config */ + mbhc->mbhc_cfg = mbhc_cfg; + + dev_dbg(mbhc->component->dev, "%s: enter\n", __func__); + + /* check if USB C analog is defined on device tree */ + mbhc_cfg->enable_usbc_analog = 0; + if (of_find_property(card->dev->of_node, usb_c_dt, NULL)) { + rc = of_property_read_u32(card->dev->of_node, usb_c_dt, + &mbhc_cfg->enable_usbc_analog); + } + if (mbhc_cfg->enable_usbc_analog == 0 || rc != 0) { + dev_dbg(card->dev, + "%s: %s in dt node is missing or false\n", + __func__, usb_c_dt); + dev_dbg(card->dev, + "%s: skipping USB c analog configuration\n", __func__); + } + + /* Parse wcd_usbss/fsa switch handle */ + if (mbhc_cfg->enable_usbc_analog) { + dev_dbg(mbhc->component->dev, "%s: usbc analog enabled\n", + __func__); + mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD; + if (!mbhc->wcd_usbss_aatc_dev_np && !mbhc->fsa_aatc_dev_np) { + dev_err(card->dev, "%s: wcd939x or fsa i2c node not found\n", + __func__); + rc = -EINVAL; + goto err; + } + } + + /* Disable moisture detect and duty cycle for WCD USB AATC HS*/ + if (mbhc_cfg->enable_usbc_analog) { + mbhc_cfg->moisture_en = false; + mbhc_cfg->moisture_duty_cycle_en = false; + pr_debug("%s: Disable moisture detect and duty cycle of AATC", + __func__); + } + + /* Set btn key code */ + if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc)) + pr_err("Set btn key code error!!!\n"); + + if (!mbhc->mbhc_cfg->read_fw_bin || + (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) || + (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) { + rc = wcd_mbhc_initialise(mbhc); + if (rc) { + dev_err(card->dev, "%s: wcd mbhc initialize failed\n", + __func__); + goto err; + } + } else { + if (!mbhc->mbhc_fw || !mbhc->mbhc_cal) + schedule_delayed_work(&mbhc->mbhc_firmware_dwork, + usecs_to_jiffies(FW_READ_TIMEOUT)); + else + pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n", + __func__, mbhc->mbhc_fw, mbhc->mbhc_cal); + } + + if (mbhc_cfg->enable_usbc_analog) { + mbhc->aatc_dev_nb.notifier_call = wcd_mbhc_usbc_ana_event_handler; + mbhc->aatc_dev_nb.priority = 0; +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (mbhc->wcd_usbss_aatc_dev_np) + rc = wcd_usbss_reg_notifier(&mbhc->aatc_dev_nb, + mbhc->wcd_usbss_aatc_dev_np); +#endif +#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C) + if (mbhc->fsa_aatc_dev_np) + rc = fsa4480_reg_notifier(&mbhc->aatc_dev_nb, mbhc->fsa_aatc_dev_np); +#endif + } + + return rc; +err: + dev_dbg(mbhc->component->dev, "%s: leave %d\n", __func__, rc); + return rc; +} +EXPORT_SYMBOL(wcd_mbhc_start); + +void wcd_mbhc_stop(struct wcd_mbhc *mbhc) +{ + pr_debug("%s: enter\n", __func__); + + if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) { + if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect) + mbhc->mbhc_cb->skip_imped_detect(mbhc->component); + } + mbhc->current_plug = MBHC_PLUG_TYPE_NONE; + mbhc->hph_status = 0; + if (mbhc->mbhc_cb && mbhc->mbhc_cb->irq_control) { + mbhc->mbhc_cb->irq_control(mbhc->component, + mbhc->intr_ids->hph_left_ocp, + false); + mbhc->mbhc_cb->irq_control(mbhc->component, + mbhc->intr_ids->hph_right_ocp, + false); + } + if (mbhc->mbhc_fw || mbhc->mbhc_cal) { + cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork); + if (!mbhc->mbhc_cal) + release_firmware(mbhc->mbhc_fw); + mbhc->mbhc_fw = NULL; + mbhc->mbhc_cal = NULL; + } + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (mbhc->mbhc_cfg->enable_usbc_analog && mbhc->wcd_usbss_aatc_dev_np) + wcd_usbss_unreg_notifier(&mbhc->aatc_dev_nb, mbhc->wcd_usbss_aatc_dev_np); +#endif + +#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C) + if (mbhc->mbhc_cfg->enable_usbc_analog && mbhc->fsa_aatc_dev_np) + fsa4480_unreg_notifier(&mbhc->aatc_dev_nb, mbhc->fsa_aatc_dev_np); +#endif + + pr_debug("%s: leave\n", __func__); +} +EXPORT_SYMBOL(wcd_mbhc_stop); + +/* + * wcd_mbhc_init : initialize MBHC internal structures. + * + * NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used + */ +int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_component *component, + const struct wcd_mbhc_cb *mbhc_cb, + const struct wcd_mbhc_intr *mbhc_cdc_intr_ids, + struct wcd_mbhc_register *wcd_mbhc_regs, + bool impedance_det_en) +{ + int ret = 0; + int hph_swh = 0; + int gnd_swh = 0; + u32 hph_moist_config[3]; + struct snd_soc_card *card = component->card; + const char *hph_switch = "qcom,msm-mbhc-hphl-swh"; + const char *gnd_switch = "qcom,msm-mbhc-gnd-swh"; + const char *hs_thre = "qcom,msm-mbhc-hs-mic-max-threshold-mv"; + const char *hph_thre = "qcom,msm-mbhc-hs-mic-min-threshold-mv"; + + pr_debug("%s: enter\n", __func__); + + ret = of_property_read_u32(card->dev->of_node, hph_switch, &hph_swh); + if (ret) { + dev_err(card->dev, + "%s: missing %s in dt node\n", __func__, hph_switch); + goto err; + } + + ret = of_property_read_u32(card->dev->of_node, gnd_switch, &gnd_swh); + if (ret) { + dev_err(card->dev, + "%s: missing %s in dt node\n", __func__, gnd_switch); + goto err; + } + + ret = of_property_read_u32(card->dev->of_node, hs_thre, + &(mbhc->hs_thr)); + if (ret) + dev_dbg(card->dev, + "%s: missing %s in dt node\n", __func__, hs_thre); + + ret = of_property_read_u32(card->dev->of_node, hph_thre, + &(mbhc->hph_thr)); + if (ret) + dev_dbg(card->dev, + "%s: missing %s in dt node\n", __func__, hph_thre); + + ret = of_property_read_u32_array(card->dev->of_node, + "qcom,msm-mbhc-moist-cfg", + hph_moist_config, 3); + if (ret) { + dev_dbg(card->dev, "%s: no qcom,msm-mbhc-moist-cfg in DT\n", + __func__); + mbhc->moist_vref = V_45_MV; + mbhc->moist_iref = I_3P0_UA; + mbhc->moist_rref = R_24_KOHM; + } else { + mbhc->moist_vref = hph_moist_config[0]; + mbhc->moist_iref = hph_moist_config[1]; + mbhc->moist_rref = hph_moist_config[2]; + } + + mbhc->wcd_usbss_aatc_dev_np = of_parse_phandle(card->dev->of_node, + "wcd939x-i2c-handle", 0); + mbhc->fsa_aatc_dev_np = of_parse_phandle(card->dev->of_node, + "fsa4480-i2c-handle", 0); + + mbhc->in_swch_irq_handler = false; + mbhc->current_plug = MBHC_PLUG_TYPE_NONE; + mbhc->is_btn_press = false; + mbhc->component = component; + mbhc->intr_ids = mbhc_cdc_intr_ids; + mbhc->impedance_detect = impedance_det_en; + mbhc->hphl_swh = hph_swh; + mbhc->gnd_swh = gnd_swh; + mbhc->micbias_enable = false; + mbhc->mbhc_cb = mbhc_cb; + mbhc->btn_press_intr = false; + mbhc->is_hs_recording = false; + mbhc->is_extn_cable = false; + mbhc->extn_cable_hph_rem = false; + mbhc->hph_type = WCD_MBHC_HPH_NONE; + mbhc->wcd_mbhc_regs = wcd_mbhc_regs; + mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD; + mbhc->hphl_cross_conn_thr = HPHL_CROSS_CONN_THRESHOLD; + mbhc->hphr_cross_conn_thr = HPHR_CROSS_CONN_THRESHOLD; + + if (mbhc->intr_ids == NULL) { + pr_err("%s: Interrupt mapping not provided\n", __func__); + return -EINVAL; + } + if (!mbhc->wcd_mbhc_regs) { + dev_err(component->dev, "%s: mbhc registers are not defined\n", + __func__); + return -EINVAL; + } + + /* Check if IRQ and other required callbacks are defined or not */ + if (!mbhc_cb || !mbhc_cb->request_irq || !mbhc_cb->irq_control || + !mbhc_cb->free_irq || !mbhc_cb->map_btn_code_to_num || + !mbhc_cb->lock_sleep || !mbhc_cb->mbhc_bias || + !mbhc_cb->set_btn_thr) { + dev_err(component->dev, "%s: required mbhc callbacks are not defined\n", + __func__); + return -EINVAL; + } + + /* No need to create new sound card jacks if is is already created */ + if (mbhc->headset_jack.jack == NULL) { + ret = snd_soc_card_jack_new(component->card, + "Headset Jack", WCD_MBHC_JACK_MASK, + &mbhc->headset_jack); + if (ret) { + pr_err("%s: Failed to create new jack\n", __func__); + return ret; + } + + ret = snd_soc_card_jack_new(component->card, + "Button Jack", + WCD_MBHC_JACK_BUTTON_MASK, + &mbhc->button_jack); + if (ret) { + pr_err("Failed to create new jack\n"); + return ret; + } + + ret = snd_jack_set_key(mbhc->button_jack.jack, + SND_JACK_BTN_0, + KEY_MEDIA); + if (ret) { + pr_err("%s: Failed to set code for btn-0\n", + __func__); + return ret; + } + + INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork, + wcd_mbhc_fw_read); + INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_lpress_fn); + } + init_completion(&mbhc->btn_press_compl); + + /* Register event notifier */ + mbhc->nblock.notifier_call = wcd_event_notify; + if (mbhc->mbhc_cb->register_notifier) { + ret = mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, + true); + if (ret) { + pr_err("%s: Failed to register notifier %d\n", + __func__, ret); + return ret; + } + } + + init_waitqueue_head(&mbhc->wait_btn_press); + mutex_init(&mbhc->codec_resource_lock); + + switch (mbhc->mbhc_detection_logic) { + case WCD_DETECTION_LEGACY: + wcd_mbhc_legacy_init(mbhc); + break; + case WCD_DETECTION_ADC: + wcd_mbhc_adc_init(mbhc); + break; + default: + pr_err("%s: Unknown detection logic type %d\n", + __func__, mbhc->mbhc_detection_logic); + break; + } + + if (!mbhc->mbhc_fn || + !mbhc->mbhc_fn->wcd_mbhc_hs_ins_irq || + !mbhc->mbhc_fn->wcd_mbhc_hs_rem_irq || + !mbhc->mbhc_fn->wcd_mbhc_detect_plug_type || + !mbhc->mbhc_fn->wcd_cancel_hs_detect_plug) { + pr_err("%s: mbhc function pointer is NULL\n", __func__); + goto err_mbhc_sw_irq; + } + ret = mbhc->mbhc_cb->request_irq(component, + mbhc->intr_ids->mbhc_sw_intr, + wcd_mbhc_mech_plug_detect_irq, + "mbhc sw intr", mbhc); + if (ret) { + pr_err("%s: Failed to request irq %d, ret = %d\n", __func__, + mbhc->intr_ids->mbhc_sw_intr, ret); + goto err_mbhc_sw_irq; + } + + ret = mbhc->mbhc_cb->request_irq(component, + mbhc->intr_ids->mbhc_btn_press_intr, + wcd_mbhc_btn_press_handler, + "Button Press detect", mbhc); + if (ret) { + pr_err("%s: Failed to request irq %d\n", __func__, + mbhc->intr_ids->mbhc_btn_press_intr); + goto err_btn_press_irq; + } + + ret = mbhc->mbhc_cb->request_irq(component, + mbhc->intr_ids->mbhc_btn_release_intr, + wcd_mbhc_release_handler, + "Button Release detect", mbhc); + if (ret) { + pr_err("%s: Failed to request irq %d\n", __func__, + mbhc->intr_ids->mbhc_btn_release_intr); + goto err_btn_release_irq; + } + + ret = mbhc->mbhc_cb->request_irq(component, + mbhc->intr_ids->mbhc_hs_ins_intr, + mbhc->mbhc_fn->wcd_mbhc_hs_ins_irq, + "Elect Insert", mbhc); + if (ret) { + pr_err("%s: Failed to request irq %d\n", __func__, + mbhc->intr_ids->mbhc_hs_ins_intr); + goto err_mbhc_hs_ins_irq; + } + mbhc->mbhc_cb->irq_control(component, mbhc->intr_ids->mbhc_hs_ins_intr, + false); + clear_bit(WCD_MBHC_ELEC_HS_INS, &mbhc->intr_status); + + ret = mbhc->mbhc_cb->request_irq(component, + mbhc->intr_ids->mbhc_hs_rem_intr, + mbhc->mbhc_fn->wcd_mbhc_hs_rem_irq, + "Elect Remove", mbhc); + if (ret) { + pr_err("%s: Failed to request irq %d\n", __func__, + mbhc->intr_ids->mbhc_hs_rem_intr); + goto err_mbhc_hs_rem_irq; + } + mbhc->mbhc_cb->irq_control(component, mbhc->intr_ids->mbhc_hs_rem_intr, + false); + clear_bit(WCD_MBHC_ELEC_HS_REM, &mbhc->intr_status); + + ret = mbhc->mbhc_cb->request_irq(component, + mbhc->intr_ids->hph_left_ocp, + wcd_mbhc_hphl_ocp_irq, "HPH_L OCP detect", + mbhc); + if (ret) { + pr_err("%s: Failed to request irq %d\n", __func__, + mbhc->intr_ids->hph_left_ocp); + goto err_hphl_ocp_irq; + } + + ret = mbhc->mbhc_cb->request_irq(component, + mbhc->intr_ids->hph_right_ocp, + wcd_mbhc_hphr_ocp_irq, "HPH_R OCP detect", + mbhc); + if (ret) { + pr_err("%s: Failed to request irq %d\n", __func__, + mbhc->intr_ids->hph_right_ocp); + goto err_hphr_ocp_irq; + } + if (!mbhc->extdev) { + mbhc->extdev = + devm_extcon_dev_allocate(component->dev, + mbhc_ext_dev_supported_table); + if (IS_ERR(mbhc->extdev)) { + goto err_ext_dev; + ret = PTR_ERR(mbhc->extdev); + } + ret = devm_extcon_dev_register(component->dev, mbhc->extdev); + if (ret) { + pr_err("%s:audio registration failed\n", __func__); + goto err_ext_dev; + } + } + mbhc->deinit_in_progress = false; + pr_debug("%s: leave ret %d\n", __func__, ret); + return ret; + +err_ext_dev: + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->hph_right_ocp, mbhc); +err_hphr_ocp_irq: + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->hph_left_ocp, mbhc); +err_hphl_ocp_irq: + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_hs_rem_intr, + mbhc); +err_mbhc_hs_rem_irq: + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_hs_ins_intr, + mbhc); +err_mbhc_hs_ins_irq: + mbhc->mbhc_cb->free_irq(component, + mbhc->intr_ids->mbhc_btn_release_intr, + mbhc); +err_btn_release_irq: + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_btn_press_intr, + mbhc); +err_btn_press_irq: + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_sw_intr, mbhc); +err_mbhc_sw_irq: + if (mbhc->mbhc_cb->register_notifier) + mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false); + mutex_destroy(&mbhc->codec_resource_lock); +err: + pr_debug("%s: leave ret %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL(wcd_mbhc_init); + +void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_sw_intr, mbhc); + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_btn_press_intr, + mbhc); + mbhc->mbhc_cb->free_irq(component, + mbhc->intr_ids->mbhc_btn_release_intr, + mbhc); + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_hs_ins_intr, + mbhc); + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->mbhc_hs_rem_intr, + mbhc); + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->hph_left_ocp, mbhc); + mbhc->mbhc_cb->free_irq(component, mbhc->intr_ids->hph_right_ocp, mbhc); + if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier) + mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false); + if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug) { + WCD_MBHC_RSC_LOCK(mbhc); + mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc, + &mbhc->correct_plug_swch); + WCD_MBHC_RSC_UNLOCK(mbhc); + } + mutex_destroy(&mbhc->codec_resource_lock); +} +EXPORT_SYMBOL(wcd_mbhc_deinit); + +static int __init mbhc_init(void) +{ + mutex_init(&hphl_pa_lock); + mutex_init(&hphr_pa_lock); + return 0; +} + +static void __exit mbhc_exit(void) +{ + mutex_destroy(&hphl_pa_lock); + mutex_destroy(&hphr_pa_lock); +} + +module_init(mbhc_init); +module_exit(mbhc_exit); + +MODULE_DESCRIPTION("wcd MBHC v2 module"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-spi-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd-spi-registers.h new file mode 100644 index 0000000000..e0d9612af0 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-spi-registers.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD_SPI_REGISTERS_H__ +#define __WCD_SPI_REGISTERS_H__ + +#include + +#define WCD_SPI_SLAVE_SANITY (0x00) +#define WCD_SPI_SLAVE_DEVICE_ID (0x04) +#define WCD_SPI_SLAVE_STATUS (0x08) +#define WCD_SPI_SLAVE_CONFIG (0x0c) +#define WCD_SPI_SLAVE_SW_RESET (0x10) +#define WCD_SPI_SLAVE_IRQ_STATUS (0x14) +#define WCD_SPI_SLAVE_IRQ_EN (0x18) +#define WCD_SPI_SLAVE_IRQ_CLR (0x1c) +#define WCD_SPI_SLAVE_IRQ_FORCE (0x20) +#define WCD_SPI_SLAVE_TX (0x24) +#define WCD_SPI_SLAVE_TEST_BUS_DATA (0x2c) +#define WCD_SPI_SLAVE_TEST_BUS_CTRL (0x30) +#define WCD_SPI_SLAVE_SW_RST_IRQ (0x34) +#define WCD_SPI_SLAVE_CHAR_CFG (0x38) +#define WCD_SPI_SLAVE_CHAR_DATA_MOSI (0x3c) +#define WCD_SPI_SLAVE_CHAR_DATA_CS_N (0x40) +#define WCD_SPI_SLAVE_CHAR_DATA_MISO (0x44) +#define WCD_SPI_SLAVE_TRNS_BYTE_CNT (0x4c) +#define WCD_SPI_SLAVE_TRNS_LEN (0x50) +#define WCD_SPI_SLAVE_FIFO_LEVEL (0x54) +#define WCD_SPI_SLAVE_GENERICS (0x58) +#define WCD_SPI_SLAVE_EXT_BASE_ADDR (0x5c) +#define WCD_SPI_MAX_REGISTER (0x5F) + +#endif /* End __WCD_SPI_REGISTERS_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd-spi.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd-spi.c new file mode 100644 index 0000000000..4c7a85338e --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd-spi.c @@ -0,0 +1,1674 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd-spi-registers.h" + +/* Byte manipulations */ +#define SHIFT_1_BYTES (8) +#define SHIFT_2_BYTES (16) +#define SHIFT_3_BYTES (24) + +/* Command opcodes */ +#define WCD_SPI_CMD_NOP (0x00) +#define WCD_SPI_CMD_WREN (0x06) +#define WCD_SPI_CMD_CLKREQ (0xDA) +#define WCD_SPI_CMD_RDSR (0x05) +#define WCD_SPI_CMD_IRR (0x81) +#define WCD_SPI_CMD_IRW (0x82) +#define WCD_SPI_CMD_MIOR (0x83) +#define WCD_SPI_CMD_FREAD (0x0B) +#define WCD_SPI_CMD_MIOW (0x02) +#define WCD_SPI_WRITE_FRAME_OPCODE \ + (WCD_SPI_CMD_MIOW << SHIFT_3_BYTES) +#define WCD_SPI_READ_FRAME_OPCODE \ + (WCD_SPI_CMD_MIOR << SHIFT_3_BYTES) +#define WCD_SPI_FREAD_FRAME_OPCODE \ + (WCD_SPI_CMD_FREAD << SHIFT_3_BYTES) + +/* Command lengths */ +#define WCD_SPI_OPCODE_LEN (0x01) +#define WCD_SPI_CMD_NOP_LEN (0x01) +#define WCD_SPI_CMD_WREN_LEN (0x01) +#define WCD_SPI_CMD_CLKREQ_LEN (0x04) +#define WCD_SPI_CMD_IRR_LEN (0x04) +#define WCD_SPI_CMD_IRW_LEN (0x06) +#define WCD_SPI_WRITE_SINGLE_LEN (0x08) +#define WCD_SPI_READ_SINGLE_LEN (0x13) +#define WCD_SPI_CMD_FREAD_LEN (0x13) + +/* Command delays */ +#define WCD_SPI_CLKREQ_DELAY_USECS (500) +#define WCD_SPI_CLK_OFF_TIMER_MS (500) +#define WCD_SPI_RESUME_TIMEOUT_MS 100 + +/* Command masks */ +#define WCD_CMD_ADDR_MASK \ + (0xFF | \ + (0xFF << SHIFT_1_BYTES) | \ + (0xFF << SHIFT_2_BYTES)) + +/* Clock ctrl request related */ +#define WCD_SPI_CLK_ENABLE true +#define WCD_SPI_CLK_DISABLE false +#define WCD_SPI_CLK_FLAG_DELAYED (1 << 0) +#define WCD_SPI_CLK_FLAG_IMMEDIATE (1 << 1) + +/* Internal addresses */ +#define WCD_SPI_ADDR_IPC_CTL_HOST (0x012014) + +/* Word sizes and min/max lengths */ +#define WCD_SPI_WORD_BYTE_CNT (4) +#define WCD_SPI_RW_MULTI_MIN_LEN (16) + +/* Max size is 32 bytes less than 64Kbytes */ +#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 32) + +/* + * Max size for the pre-allocated buffers is the max + * possible read/write length + 32 bytes for the SPI + * read/write command header itself. + */ +#define WCD_SPI_RW_MAX_BUF_SIZE (WCD_SPI_RW_MULTI_MAX_LEN + 32) + +/* Alignment requirements */ +#define WCD_SPI_RW_MIN_ALIGN WCD_SPI_WORD_BYTE_CNT +#define WCD_SPI_RW_MULTI_ALIGN (16) + +/* Status mask bits */ +#define WCD_SPI_CLK_STATE_ENABLED BIT(0) +#define WCD_SPI_IS_SUSPENDED BIT(1) + +/* Locking related */ +#define WCD_SPI_MUTEX_LOCK(spi, lock) \ +{ \ + dev_vdbg(&spi->dev, "%s: mutex_lock(%s)\n", \ + __func__, __stringify_1(lock)); \ + mutex_lock(&lock); \ +} + +#define WCD_SPI_MUTEX_UNLOCK(spi, lock) \ +{ \ + dev_vdbg(&spi->dev, "%s: mutex_unlock(%s)\n", \ + __func__, __stringify_1(lock)); \ + mutex_unlock(&lock); \ +} + +struct wcd_spi_debug_data { + struct dentry *dir; + u32 addr; + u32 size; +}; + +struct wcd_spi_priv { + struct spi_device *spi; + u32 mem_base_addr; + + struct regmap *regmap; + + /* Message for single transfer */ + struct spi_message msg1; + struct spi_transfer xfer1; + + /* Message for two transfers */ + struct spi_message msg2; + struct spi_transfer xfer2[2]; + + /* Register access related */ + u32 reg_bytes; + u32 val_bytes; + + /* Clock requests related */ + struct mutex clk_mutex; + int clk_users; + unsigned long status_mask; + struct delayed_work clk_dwork; + + /* Transaction related */ + struct mutex xfer_mutex; + + struct device *m_dev; + struct wdsp_mgr_ops *m_ops; + + /* Debugfs related information */ + struct wcd_spi_debug_data debug_data; + + /* Completion object to indicate system resume completion */ + struct completion resume_comp; + + /* Buffers to hold memory used for transfers */ + void *tx_buf; + void *rx_buf; + + /* DMA handles for transfer buffers */ + dma_addr_t tx_dma; + dma_addr_t rx_dma; + /* Handle to child (qmi client) device */ + struct device *ac_dev; +}; + +enum xfer_request { + WCD_SPI_XFER_WRITE, + WCD_SPI_XFER_READ, +}; + + +static char *wcd_spi_xfer_req_str(enum xfer_request req) +{ + if (req == WCD_SPI_XFER_WRITE) + return "xfer_write"; + else if (req == WCD_SPI_XFER_READ) + return "xfer_read"; + else + return "xfer_invalid"; +} + +static void wcd_spi_reinit_xfer(struct spi_transfer *xfer) +{ + xfer->tx_buf = NULL; + xfer->rx_buf = NULL; + xfer->delay_usecs = 0; + xfer->len = 0; +} + +static bool wcd_spi_is_suspended(struct wcd_spi_priv *wcd_spi) +{ + return test_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask); +} + +static bool wcd_spi_can_suspend(struct wcd_spi_priv *wcd_spi) +{ + struct spi_device *spi = wcd_spi->spi; + + if (wcd_spi->clk_users > 0 || + test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) { + dev_err(&spi->dev, "%s: cannot suspend, clk_users = %d\n", + __func__, wcd_spi->clk_users); + return false; + } + + return true; +} + +static int wcd_spi_wait_for_resume(struct wcd_spi_priv *wcd_spi) +{ + struct spi_device *spi = wcd_spi->spi; + int rc = 0; + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + /* If the system is already in resumed state, return right away */ + if (!wcd_spi_is_suspended(wcd_spi)) + goto done; + + /* If suspended then wait for resume to happen */ + reinit_completion(&wcd_spi->resume_comp); + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + rc = wait_for_completion_timeout(&wcd_spi->resume_comp, + msecs_to_jiffies(WCD_SPI_RESUME_TIMEOUT_MS)); + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (rc == 0) { + dev_err(&spi->dev, "%s: failed to resume in %u msec\n", + __func__, WCD_SPI_RESUME_TIMEOUT_MS); + rc = -EIO; + goto done; + } + + dev_dbg(&spi->dev, "%s: resume successful\n", __func__); + rc = 0; +done: + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + return rc; +} + +static int wcd_spi_read_single(struct spi_device *spi, + u32 remote_addr, u32 *val) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0]; + struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1]; + u8 *tx_buf = wcd_spi->tx_buf; + u8 *rx_buf = wcd_spi->rx_buf; + u32 frame = 0; + int ret; + + dev_dbg(&spi->dev, "%s: remote_addr = 0x%x\n", + __func__, remote_addr); + + if (!tx_buf) { + dev_err(&spi->dev, "%s: tx_buf not allocated\n", + __func__); + return -ENOMEM; + } + + frame |= WCD_SPI_READ_FRAME_OPCODE; + frame |= remote_addr & WCD_CMD_ADDR_MASK; + + wcd_spi_reinit_xfer(tx_xfer); + frame = cpu_to_be32(frame); + memcpy(tx_buf, &frame, sizeof(frame)); + tx_xfer->tx_buf = tx_buf; + tx_xfer->len = WCD_SPI_READ_SINGLE_LEN; + + wcd_spi_reinit_xfer(rx_xfer); + rx_xfer->rx_buf = rx_buf; + rx_xfer->len = sizeof(*val); + + ret = spi_sync(spi, &wcd_spi->msg2); + if (ret) + dev_err(&spi->dev, "%s: spi_sync failed, err %d\n", + __func__, ret); + else + memcpy((u8*) val, rx_buf, sizeof(*val)); + + return ret; +} + +static int wcd_spi_read_multi(struct spi_device *spi, + u32 remote_addr, u8 *data, + size_t len) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct spi_transfer *xfer = &wcd_spi->xfer1; + u8 *tx_buf = wcd_spi->tx_buf; + u8 *rx_buf = wcd_spi->rx_buf; + u32 frame = 0; + int ret; + + dev_dbg(&spi->dev, "%s: addr 0x%x, len = %zd\n", + __func__, remote_addr, len); + + frame |= WCD_SPI_FREAD_FRAME_OPCODE; + frame |= remote_addr & WCD_CMD_ADDR_MASK; + + if (!tx_buf || !rx_buf) { + dev_err(&spi->dev, "%s: %s not allocated\n", __func__, + (!tx_buf) ? "tx_buf" : "rx_buf"); + return -ENOMEM; + } + + wcd_spi_reinit_xfer(xfer); + frame = cpu_to_be32(frame); + memcpy(tx_buf, &frame, sizeof(frame)); + xfer->tx_buf = tx_buf; + xfer->rx_buf = rx_buf; + xfer->len = WCD_SPI_CMD_FREAD_LEN + len; + + ret = spi_sync(spi, &wcd_spi->msg1); + if (ret) { + dev_err(&spi->dev, "%s: failed, err = %d\n", + __func__, ret); + goto done; + } + + memcpy(data, rx_buf + WCD_SPI_CMD_FREAD_LEN, len); +done: + return ret; +} + +static int wcd_spi_write_single(struct spi_device *spi, + u32 remote_addr, u32 val) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct spi_transfer *xfer = &wcd_spi->xfer1; + u8 *tx_buf = wcd_spi->tx_buf; + u32 frame = 0; + + dev_dbg(&spi->dev, "%s: remote_addr = 0x%x, val = 0x%x\n", + __func__, remote_addr, val); + + memset(tx_buf, 0, WCD_SPI_WRITE_SINGLE_LEN); + frame |= WCD_SPI_WRITE_FRAME_OPCODE; + frame |= (remote_addr & WCD_CMD_ADDR_MASK); + + frame = cpu_to_be32(frame); + memcpy(tx_buf, &frame, sizeof(frame)); + memcpy(tx_buf + sizeof(frame), &val, sizeof(val)); + + wcd_spi_reinit_xfer(xfer); + xfer->tx_buf = tx_buf; + xfer->len = WCD_SPI_WRITE_SINGLE_LEN; + + return spi_sync(spi, &wcd_spi->msg1); +} + +static int wcd_spi_write_multi(struct spi_device *spi, + u32 remote_addr, u8 *data, + size_t len) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct spi_transfer *xfer = &wcd_spi->xfer1; + u32 frame = 0; + u8 *tx_buf = wcd_spi->tx_buf; + int xfer_len, ret; + + dev_dbg(&spi->dev, "%s: addr = 0x%x len = %zd\n", + __func__, remote_addr, len); + + frame |= WCD_SPI_WRITE_FRAME_OPCODE; + frame |= (remote_addr & WCD_CMD_ADDR_MASK); + + frame = cpu_to_be32(frame); + xfer_len = len + sizeof(frame); + + if (!tx_buf) { + dev_err(&spi->dev, "%s: tx_buf not allocated\n", + __func__); + return -ENOMEM; + } + + memcpy(tx_buf, &frame, sizeof(frame)); + memcpy(tx_buf + sizeof(frame), data, len); + + wcd_spi_reinit_xfer(xfer); + xfer->tx_buf = tx_buf; + xfer->len = xfer_len; + + ret = spi_sync(spi, &wcd_spi->msg1); + if (ret < 0) + dev_err(&spi->dev, + "%s: Failed, addr = 0x%x, len = %zd\n", + __func__, remote_addr, len); + return ret; +} + +static int wcd_spi_transfer_split(struct spi_device *spi, + struct wcd_spi_msg *data_msg, + enum xfer_request xfer_req) +{ + u32 addr = data_msg->remote_addr; + u8 *data = data_msg->data; + int remain_size = data_msg->len; + int to_xfer, loop_cnt, ret = 0; + + /* Perform single writes until multi word alignment is met */ + loop_cnt = 1; + while (remain_size && + !IS_ALIGNED(addr, WCD_SPI_RW_MULTI_ALIGN)) { + if (xfer_req == WCD_SPI_XFER_WRITE) + ret = wcd_spi_write_single(spi, addr, + (*(u32 *)data)); + else + ret = wcd_spi_read_single(spi, addr, + (u32 *)data); + if (ret < 0) { + dev_err(&spi->dev, + "%s: %s fail iter(%d) start-word addr (0x%x)\n", + __func__, wcd_spi_xfer_req_str(xfer_req), + loop_cnt, addr); + goto done; + } + + addr += WCD_SPI_WORD_BYTE_CNT; + data += WCD_SPI_WORD_BYTE_CNT; + remain_size -= WCD_SPI_WORD_BYTE_CNT; + loop_cnt++; + } + + /* Perform multi writes for max allowed multi writes */ + loop_cnt = 1; + while (remain_size >= WCD_SPI_RW_MULTI_MAX_LEN) { + if (xfer_req == WCD_SPI_XFER_WRITE) + ret = wcd_spi_write_multi(spi, addr, data, + WCD_SPI_RW_MULTI_MAX_LEN); + else + ret = wcd_spi_read_multi(spi, addr, data, + WCD_SPI_RW_MULTI_MAX_LEN); + if (ret < 0) { + dev_err(&spi->dev, + "%s: %s fail iter(%d) max-write addr (0x%x)\n", + __func__, wcd_spi_xfer_req_str(xfer_req), + loop_cnt, addr); + goto done; + } + + addr += WCD_SPI_RW_MULTI_MAX_LEN; + data += WCD_SPI_RW_MULTI_MAX_LEN; + remain_size -= WCD_SPI_RW_MULTI_MAX_LEN; + loop_cnt++; + } + + /* + * Perform write for max possible data that is multiple + * of the minimum size for multi-write commands. + */ + to_xfer = remain_size - (remain_size % WCD_SPI_RW_MULTI_MIN_LEN); + if (remain_size >= WCD_SPI_RW_MULTI_MIN_LEN && + to_xfer > 0) { + if (xfer_req == WCD_SPI_XFER_WRITE) + ret = wcd_spi_write_multi(spi, addr, data, to_xfer); + else + ret = wcd_spi_read_multi(spi, addr, data, to_xfer); + if (ret < 0) { + dev_err(&spi->dev, + "%s: %s fail write addr (0x%x), size (0x%x)\n", + __func__, wcd_spi_xfer_req_str(xfer_req), + addr, to_xfer); + goto done; + } + + addr += to_xfer; + data += to_xfer; + remain_size -= to_xfer; + } + + /* Perform single writes for the last remaining data */ + loop_cnt = 1; + while (remain_size > 0) { + if (xfer_req == WCD_SPI_XFER_WRITE) + ret = wcd_spi_write_single(spi, addr, (*((u32 *)data))); + else + ret = wcd_spi_read_single(spi, addr, (u32 *) data); + if (ret < 0) { + dev_err(&spi->dev, + "%s: %s fail iter(%d) end-write addr (0x%x)\n", + __func__, wcd_spi_xfer_req_str(xfer_req), + loop_cnt, addr); + goto done; + } + + addr += WCD_SPI_WORD_BYTE_CNT; + data += WCD_SPI_WORD_BYTE_CNT; + remain_size -= WCD_SPI_WORD_BYTE_CNT; + loop_cnt++; + } + +done: + return ret; +} + +static int wcd_spi_cmd_nop(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + u8 *tx_buf = wcd_spi->tx_buf; + + tx_buf[0] = WCD_SPI_CMD_NOP; + + return spi_write(spi, tx_buf, WCD_SPI_CMD_NOP_LEN); +} + +static int wcd_spi_cmd_clkreq(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct spi_transfer *xfer = &wcd_spi->xfer1; + u8 *tx_buf = wcd_spi->tx_buf; + u8 cmd[WCD_SPI_CMD_CLKREQ_LEN] = { + WCD_SPI_CMD_CLKREQ, + 0xBA, 0x80, 0x00}; + + memcpy(tx_buf, cmd, WCD_SPI_CMD_CLKREQ_LEN); + wcd_spi_reinit_xfer(xfer); + xfer->tx_buf = tx_buf; + xfer->len = WCD_SPI_CMD_CLKREQ_LEN; + xfer->delay_usecs = WCD_SPI_CLKREQ_DELAY_USECS; + + return spi_sync(spi, &wcd_spi->msg1); +} + +static int wcd_spi_cmd_wr_en(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + u8 *tx_buf = wcd_spi->tx_buf; + + tx_buf[0] = WCD_SPI_CMD_WREN; + + return spi_write(spi, tx_buf, WCD_SPI_CMD_WREN_LEN); +} + +static int wcd_spi_cmd_rdsr(struct spi_device *spi, + u32 *rdsr_status) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0]; + struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1]; + u8 *tx_buf = wcd_spi->tx_buf; + u8 *rx_buf = wcd_spi->rx_buf; + int ret; + + tx_buf[0] = WCD_SPI_CMD_RDSR; + wcd_spi_reinit_xfer(tx_xfer); + tx_xfer->tx_buf = tx_buf; + tx_xfer->len = WCD_SPI_OPCODE_LEN; + + memset(rx_buf, 0, sizeof(*rdsr_status)); + wcd_spi_reinit_xfer(rx_xfer); + rx_xfer->rx_buf = rx_buf; + rx_xfer->len = sizeof(*rdsr_status); + + ret = spi_sync(spi, &wcd_spi->msg2); + if (ret < 0) { + dev_err(&spi->dev, "%s: RDSR failed, err = %d\n", + __func__, ret); + goto done; + } + + *rdsr_status = be32_to_cpu(*((u32*)rx_buf)); + + dev_dbg(&spi->dev, "%s: RDSR success, value = 0x%x\n", + __func__, *rdsr_status); +done: + return ret; +} + +static int wcd_spi_clk_enable(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int ret; + u32 rd_status = 0; + + /* Get the SPI access first */ + if (wcd_spi->ac_dev) { + ret = wcd_spi_access_ctl(wcd_spi->ac_dev, + WCD_SPI_ACCESS_REQUEST, + WCD_SPI_AC_DATA_TRANSFER); + if (ret) { + dev_err(&spi->dev, + "%s: Can't get spi access, err = %d\n", + __func__, ret); + return ret; + } + } + + ret = wcd_spi_cmd_nop(spi); + if (ret < 0) { + dev_err(&spi->dev, "%s: NOP1 failed, err = %d\n", + __func__, ret); + goto done; + } + + ret = wcd_spi_cmd_clkreq(spi); + if (ret < 0) { + dev_err(&spi->dev, "%s: CLK_REQ failed, err = %d\n", + __func__, ret); + goto done; + } + + ret = wcd_spi_cmd_nop(spi); + if (ret < 0) { + dev_err(&spi->dev, "%s: NOP2 failed, err = %d\n", + __func__, ret); + goto done; + } + wcd_spi_cmd_rdsr(spi, &rd_status); + /* + * Read status zero means reads are not + * happenning on the bus, possibly because + * clock request failed. + */ + if (rd_status) { + set_bit(WCD_SPI_CLK_STATE_ENABLED, + &wcd_spi->status_mask); + } else { + dev_err(&spi->dev, "%s: RDSR status is zero\n", + __func__); + ret = -EIO; + } +done: + return ret; +} + +static int wcd_spi_clk_disable(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int ret; + + ret = wcd_spi_write_single(spi, WCD_SPI_ADDR_IPC_CTL_HOST, 0x01); + if (ret < 0) + dev_err(&spi->dev, "%s: Failed, err = %d\n", + __func__, ret); + /* + * clear this bit even if clock disable failed + * as the source clocks might get turned off. + */ + clear_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask); + + /* once the clock is released, SPI access can be released as well */ + if (wcd_spi->ac_dev) { + ret = wcd_spi_access_ctl(wcd_spi->ac_dev, + WCD_SPI_ACCESS_RELEASE, + WCD_SPI_AC_DATA_TRANSFER); + if (ret) + dev_err(&spi->dev, + "%s: SPI access release failed, err = %d\n", + __func__, ret); + } + + return ret; +} + +static int wcd_spi_clk_ctrl(struct spi_device *spi, + bool request, u32 flags) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int ret = 0; + const char *delay_str; + + delay_str = (flags == WCD_SPI_CLK_FLAG_DELAYED) ? + "delayed" : "immediate"; + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + + /* Reject any unbalanced disable request */ + if (wcd_spi->clk_users < 0 || + (!request && wcd_spi->clk_users == 0)) { + dev_err(&spi->dev, "%s: Unbalanced clk_users %d for %s\n", + __func__, wcd_spi->clk_users, + request ? "enable" : "disable"); + ret = -EINVAL; + + /* Reset the clk_users to 0 */ + wcd_spi->clk_users = 0; + + goto done; + } + + if (request == WCD_SPI_CLK_ENABLE) { + /* + * If the SPI bus is suspended, then return error + * as the transaction cannot be completed. + */ + if (wcd_spi_is_suspended(wcd_spi)) { + dev_err(&spi->dev, + "%s: SPI suspended, cannot enable clk\n", + __func__); + ret = -EIO; + goto done; + } + + /* Cancel the disable clk work */ + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + cancel_delayed_work_sync(&wcd_spi->clk_dwork); + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + + wcd_spi->clk_users++; + + /* + * If clk state is already set, + * then clk wasnt really disabled + */ + if (test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) + goto done; + else if (wcd_spi->clk_users == 1) + ret = wcd_spi_clk_enable(spi); + + } else { + wcd_spi->clk_users--; + + /* Clock is still voted for */ + if (wcd_spi->clk_users > 0) + goto done; + + /* + * If we are here, clk_users must be 0 and needs + * to be disabled. Call the disable based on the + * flags. + */ + if (flags == WCD_SPI_CLK_FLAG_DELAYED) { + schedule_delayed_work(&wcd_spi->clk_dwork, + msecs_to_jiffies(WCD_SPI_CLK_OFF_TIMER_MS)); + } else { + ret = wcd_spi_clk_disable(spi); + if (ret < 0) + dev_err(&spi->dev, + "%s: Failed to disable clk err = %d\n", + __func__, ret); + } + } + +done: + dev_dbg(&spi->dev, "%s: updated clk_users = %d, request_%s %s\n", + __func__, wcd_spi->clk_users, request ? "enable" : "disable", + request ? "" : delay_str); + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + + return ret; +} + +static int wcd_spi_init(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int ret; + + ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE, + WCD_SPI_CLK_FLAG_IMMEDIATE); + if (ret < 0) + goto done; + + ret = wcd_spi_cmd_wr_en(spi); + if (ret < 0) + goto err_wr_en; + + /* + * In case spi_init is called after component deinit, + * it is possible hardware register state is also reset. + * Sync the regcache here so hardware state is updated + * to reflect the cache. + */ + regcache_sync(wcd_spi->regmap); + + regmap_write(wcd_spi->regmap, WCD_SPI_SLAVE_CONFIG, + 0x0F3D0800); + + /* Write the MTU to max allowed size */ + regmap_update_bits(wcd_spi->regmap, + WCD_SPI_SLAVE_TRNS_LEN, + 0xFFFF0000, 0xFFFF0000); +err_wr_en: + wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE, + WCD_SPI_CLK_FLAG_IMMEDIATE); +done: + return ret; +} + +static void wcd_spi_clk_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wcd_spi_priv *wcd_spi; + struct spi_device *spi; + int ret; + + dwork = to_delayed_work(work); + wcd_spi = container_of(dwork, struct wcd_spi_priv, clk_dwork); + spi = wcd_spi->spi; + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + ret = wcd_spi_clk_disable(spi); + if (ret < 0) + dev_err(&spi->dev, + "%s: Failed to disable clk, err = %d\n", + __func__, ret); + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); +} + +static int __wcd_spi_data_xfer(struct spi_device *spi, + struct wcd_spi_msg *msg, + enum xfer_request xfer_req) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int ret; + + /* Check for minimum alignment requirements */ + if (!IS_ALIGNED(msg->remote_addr, WCD_SPI_RW_MIN_ALIGN)) { + dev_err(&spi->dev, + "%s addr 0x%x is not aligned to 0x%x\n", + __func__, msg->remote_addr, WCD_SPI_RW_MIN_ALIGN); + return -EINVAL; + } else if (msg->len % WCD_SPI_WORD_BYTE_CNT) { + dev_err(&spi->dev, + "%s len 0x%zx is not multiple of %d\n", + __func__, msg->len, WCD_SPI_WORD_BYTE_CNT); + return -EINVAL; + } + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (wcd_spi_is_suspended(wcd_spi)) { + dev_dbg(&spi->dev, + "%s: SPI suspended, cannot perform transfer\n", + __func__); + ret = -EIO; + goto done; + } + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->xfer_mutex); + if (msg->len == WCD_SPI_WORD_BYTE_CNT) { + if (xfer_req == WCD_SPI_XFER_WRITE) + ret = wcd_spi_write_single(spi, msg->remote_addr, + (*((u32 *)msg->data))); + else + ret = wcd_spi_read_single(spi, msg->remote_addr, + (u32 *) msg->data); + } else { + ret = wcd_spi_transfer_split(spi, msg, xfer_req); + } + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->xfer_mutex); +done: + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + return ret; +} + +static int wcd_spi_data_xfer(struct spi_device *spi, + struct wcd_spi_msg *msg, + enum xfer_request req) +{ + int ret, ret1; + + if (msg->len <= 0) { + dev_err(&spi->dev, "%s: Invalid size %zd\n", + __func__, msg->len); + return -EINVAL; + } + + /* Request for clock */ + ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE, + WCD_SPI_CLK_FLAG_IMMEDIATE); + if (ret < 0) { + dev_err(&spi->dev, "%s: clk enable failed %d\n", + __func__, ret); + goto done; + } + + /* Perform the transaction */ + ret = __wcd_spi_data_xfer(spi, msg, req); + if (ret < 0) + dev_err(&spi->dev, + "%s: Failed %s, addr = 0x%x, size = 0x%zx, err = %d\n", + __func__, wcd_spi_xfer_req_str(req), + msg->remote_addr, msg->len, ret); + + /* Release the clock even if xfer failed */ + ret1 = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE, + WCD_SPI_CLK_FLAG_DELAYED); + if (ret1 < 0) + dev_err(&spi->dev, "%s: clk disable failed %d\n", + __func__, ret1); +done: + return ret; +} + +/* + * wcd_spi_data_write: Write data to WCD SPI + * @spi: spi_device struct + * @msg: msg that needs to be written to WCD + * + * This API writes length of data to address specified. These details + * about the write are encapsulated in @msg. Write size should be multiple + * of 4 bytes and write address should be 4-byte aligned. + */ +static int wcd_spi_data_write(struct spi_device *spi, + struct wcd_spi_msg *msg) +{ + if (!spi || !msg) { + pr_err("%s: Invalid %s\n", __func__, + (!spi) ? "spi device" : "msg"); + return -EINVAL; + } + + dev_dbg_ratelimited(&spi->dev, "%s: addr = 0x%x, len = %zu\n", + __func__, msg->remote_addr, msg->len); + return wcd_spi_data_xfer(spi, msg, WCD_SPI_XFER_WRITE); +} + +/* + * wcd_spi_data_read: Read data from WCD SPI + * @spi: spi_device struct + * @msg: msg that needs to be read from WCD + * + * This API reads length of data from address specified. These details + * about the read are encapsulated in @msg. Read size should be multiple + * of 4 bytes and read address should be 4-byte aligned. + */ +static int wcd_spi_data_read(struct spi_device *spi, + struct wcd_spi_msg *msg) +{ + if (!spi || !msg) { + pr_err("%s: Invalid %s\n", __func__, + (!spi) ? "spi device" : "msg"); + return -EINVAL; + } + + dev_dbg_ratelimited(&spi->dev, "%s: addr = 0x%x,len = %zu\n", + __func__, msg->remote_addr, msg->len); + return wcd_spi_data_xfer(spi, msg, WCD_SPI_XFER_READ); +} + +static int wdsp_spi_dload_section(struct spi_device *spi, + void *data) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct wdsp_img_section *sec = data; + struct wcd_spi_msg msg; + int ret; + + dev_dbg(&spi->dev, "%s: addr = 0x%x, size = 0x%zx\n", + __func__, sec->addr, sec->size); + + msg.remote_addr = sec->addr + wcd_spi->mem_base_addr; + msg.data = sec->data; + msg.len = sec->size; + + ret = __wcd_spi_data_xfer(spi, &msg, WCD_SPI_XFER_WRITE); + if (ret < 0) + dev_err(&spi->dev, "%s: fail addr (0x%x) size (0x%zx)\n", + __func__, msg.remote_addr, msg.len); + return ret; +} + +static int wdsp_spi_read_section(struct spi_device *spi, void *data) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct wdsp_img_section *sec = data; + struct wcd_spi_msg msg; + int ret; + + msg.remote_addr = sec->addr + wcd_spi->mem_base_addr; + msg.data = sec->data; + msg.len = sec->size; + + dev_dbg(&spi->dev, "%s: addr = 0x%x, size = 0x%zx\n", + __func__, msg.remote_addr, msg.len); + + ret = wcd_spi_data_xfer(spi, &msg, WCD_SPI_XFER_READ); + if (ret < 0) + dev_err(&spi->dev, "%s: fail addr (0x%x) size (0x%zx)\n", + __func__, msg.remote_addr, msg.len); + return ret; +} + +static int wdsp_spi_event_handler(struct device *dev, void *priv_data, + enum wdsp_event_type event, + void *data) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct wcd_spi_ops *spi_ops; + int ret = 0; + + dev_dbg(&spi->dev, "%s: event type %d\n", + __func__, event); + + switch (event) { + case WDSP_EVENT_PRE_SHUTDOWN: + if (wcd_spi->ac_dev) { + ret = wcd_spi_access_ctl(wcd_spi->ac_dev, + WCD_SPI_ACCESS_REQUEST, + WCD_SPI_AC_REMOTE_DOWN); + if (ret) + dev_err(&spi->dev, + "%s: request access failed %d\n", + __func__, ret); + } + break; + + case WDSP_EVENT_POST_SHUTDOWN: + cancel_delayed_work_sync(&wcd_spi->clk_dwork); + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) + wcd_spi_clk_disable(spi); + wcd_spi->clk_users = 0; + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + break; + + case WDSP_EVENT_POST_BOOTUP: + if (wcd_spi->ac_dev) { + ret = wcd_spi_access_ctl(wcd_spi->ac_dev, + WCD_SPI_ACCESS_RELEASE, + WCD_SPI_AC_REMOTE_DOWN); + if (ret) + dev_err(&spi->dev, + "%s: release access failed %d\n", + __func__, ret); + } + break; + + case WDSP_EVENT_PRE_DLOAD_CODE: + case WDSP_EVENT_PRE_DLOAD_DATA: + ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE, + WCD_SPI_CLK_FLAG_IMMEDIATE); + if (ret < 0) + dev_err(&spi->dev, "%s: clk_req failed %d\n", + __func__, ret); + break; + + case WDSP_EVENT_POST_DLOAD_CODE: + case WDSP_EVENT_POST_DLOAD_DATA: + case WDSP_EVENT_DLOAD_FAILED: + + ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE, + WCD_SPI_CLK_FLAG_IMMEDIATE); + if (ret < 0) + dev_err(&spi->dev, "%s: clk unvote failed %d\n", + __func__, ret); + break; + + case WDSP_EVENT_DLOAD_SECTION: + ret = wdsp_spi_dload_section(spi, data); + break; + + case WDSP_EVENT_READ_SECTION: + ret = wdsp_spi_read_section(spi, data); + break; + + case WDSP_EVENT_SUSPEND: + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (!wcd_spi_can_suspend(wcd_spi)) + ret = -EBUSY; + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + break; + + case WDSP_EVENT_RESUME: + ret = wcd_spi_wait_for_resume(wcd_spi); + break; + + case WDSP_EVENT_GET_DEVOPS: + if (!data) { + dev_err(&spi->dev, "%s: invalid data\n", + __func__); + ret = -EINVAL; + break; + } + + spi_ops = (struct wcd_spi_ops *) data; + spi_ops->spi_dev = spi; + spi_ops->read_dev = wcd_spi_data_read; + spi_ops->write_dev = wcd_spi_data_write; + break; + + default: + dev_dbg(&spi->dev, "%s: Unhandled event %d\n", + __func__, event); + break; + } + + return ret; +} + +static int wcd_spi_bus_gwrite(void *context, const void *reg, + size_t reg_len, const void *val, + size_t val_len) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + u8 *tx_buf = wcd_spi->tx_buf; + + if (!reg || !val || reg_len != wcd_spi->reg_bytes || + val_len != wcd_spi->val_bytes) { + dev_err(&spi->dev, + "%s: Invalid input, reg_len = %zd, val_len = %zd", + __func__, reg_len, val_len); + return -EINVAL; + } + + memset(tx_buf, 0, WCD_SPI_CMD_IRW_LEN); + tx_buf[0] = WCD_SPI_CMD_IRW; + tx_buf[1] = *((u8 *)reg); + memcpy(tx_buf + WCD_SPI_OPCODE_LEN + reg_len, + val, val_len); + + return spi_write(spi, tx_buf, WCD_SPI_CMD_IRW_LEN); +} + +static int wcd_spi_bus_write(void *context, const void *data, + size_t count) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + + if (count < (wcd_spi->reg_bytes + wcd_spi->val_bytes)) { + dev_err(&spi->dev, "%s: Invalid size %zd\n", + __func__, count); + WARN_ON(1); + return -EINVAL; + } + + return wcd_spi_bus_gwrite(context, data, wcd_spi->reg_bytes, + data + wcd_spi->reg_bytes, + count - wcd_spi->reg_bytes); +} + +static int wcd_spi_bus_read(void *context, const void *reg, + size_t reg_len, void *val, + size_t val_len) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0]; + struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1]; + u8 *tx_buf = wcd_spi->tx_buf; + u8 *rx_buf = wcd_spi->rx_buf; + int ret = 0; + + if (!reg || !val || reg_len != wcd_spi->reg_bytes || + val_len != wcd_spi->val_bytes) { + dev_err(&spi->dev, + "%s: Invalid input, reg_len = %zd, val_len = %zd", + __func__, reg_len, val_len); + return -EINVAL; + } + + memset(tx_buf, 0, WCD_SPI_CMD_IRR_LEN); + tx_buf[0] = WCD_SPI_CMD_IRR; + tx_buf[1] = *((u8 *)reg); + + wcd_spi_reinit_xfer(tx_xfer); + tx_xfer->tx_buf = tx_buf; + tx_xfer->rx_buf = NULL; + tx_xfer->len = WCD_SPI_CMD_IRR_LEN; + + wcd_spi_reinit_xfer(rx_xfer); + rx_xfer->tx_buf = NULL; + rx_xfer->rx_buf = rx_buf; + rx_xfer->len = val_len; + + ret = spi_sync(spi, &wcd_spi->msg2); + if (ret) { + dev_err(&spi->dev, "%s: spi_sync failed, err %d\n", + __func__, ret); + goto done; + } + + memcpy(val, rx_buf, val_len); + +done: + return ret; +} + +static struct regmap_bus wcd_spi_regmap_bus = { + .write = wcd_spi_bus_write, + .gather_write = wcd_spi_bus_gwrite, + .read = wcd_spi_bus_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_BIG, +}; + +static int wcd_spi_state_show(struct seq_file *f, void *ptr) +{ + struct spi_device *spi = f->private; + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + const char *clk_state, *clk_mutex, *xfer_mutex; + + if (test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) + clk_state = "enabled"; + else + clk_state = "disabled"; + + clk_mutex = mutex_is_locked(&wcd_spi->clk_mutex) ? + "locked" : "unlocked"; + + xfer_mutex = mutex_is_locked(&wcd_spi->xfer_mutex) ? + "locked" : "unlocked"; + + seq_printf(f, "clk_state = %s\nclk_users = %d\n" + "clk_mutex = %s\nxfer_mutex = %s\n", + clk_state, wcd_spi->clk_users, clk_mutex, + xfer_mutex); + return 0; +} + +static int wcd_spi_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, wcd_spi_state_show, inode->i_private); +} + +static const struct file_operations state_fops = { + .open = wcd_spi_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t wcd_spi_debugfs_mem_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct spi_device *spi = file->private_data; + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data; + struct wcd_spi_msg msg; + ssize_t buf_size, read_count = 0; + char *buf; + int ret; + + if (*ppos < 0 || !count) + return -EINVAL; + + if (dbg_data->size == 0 || dbg_data->addr == 0) { + dev_err(&spi->dev, + "%s: Invalid request, size = %u, addr = 0x%x\n", + __func__, dbg_data->size, dbg_data->addr); + return 0; + } + + buf_size = count < dbg_data->size ? count : dbg_data->size; + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + msg.data = buf; + msg.remote_addr = dbg_data->addr; + msg.len = buf_size; + msg.flags = 0; + + ret = wcd_spi_data_read(spi, &msg); + if (ret < 0) { + dev_err(&spi->dev, + "%s: Failed to read %zu bytes from addr 0x%x\n", + __func__, buf_size, msg.remote_addr); + goto done; + } + + read_count = simple_read_from_buffer(ubuf, count, ppos, buf, buf_size); + +done: + kfree(buf); + if (ret < 0) + return ret; + else + return read_count; +} + +static const struct file_operations mem_read_fops = { + .open = simple_open, + .read = wcd_spi_debugfs_mem_read, +}; + +static int wcd_spi_debugfs_init(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data; + int rc = 0; + + dbg_data->dir = debugfs_create_dir("wcd_spi", NULL); + if (IS_ERR_OR_NULL(dbg_data->dir)) { + dbg_data->dir = NULL; + rc = -ENODEV; + goto done; + } + + debugfs_create_file("state", 0444, dbg_data->dir, spi, &state_fops); + debugfs_create_u32("addr", 0644, dbg_data->dir, + &dbg_data->addr); + debugfs_create_u32("size", 0644, dbg_data->dir, + &dbg_data->size); + + debugfs_create_file("mem_read", 0444, dbg_data->dir, + spi, &mem_read_fops); +done: + return rc; +} + + +static const struct reg_default wcd_spi_defaults[] = { + {WCD_SPI_SLAVE_SANITY, 0xDEADBEEF}, + {WCD_SPI_SLAVE_DEVICE_ID, 0x00500000}, + {WCD_SPI_SLAVE_STATUS, 0x80100000}, + {WCD_SPI_SLAVE_CONFIG, 0x0F200808}, + {WCD_SPI_SLAVE_SW_RESET, 0x00000000}, + {WCD_SPI_SLAVE_IRQ_STATUS, 0x00000000}, + {WCD_SPI_SLAVE_IRQ_EN, 0x00000000}, + {WCD_SPI_SLAVE_IRQ_CLR, 0x00000000}, + {WCD_SPI_SLAVE_IRQ_FORCE, 0x00000000}, + {WCD_SPI_SLAVE_TX, 0x00000000}, + {WCD_SPI_SLAVE_TEST_BUS_DATA, 0x00000000}, + {WCD_SPI_SLAVE_TEST_BUS_CTRL, 0x00000000}, + {WCD_SPI_SLAVE_SW_RST_IRQ, 0x00000000}, + {WCD_SPI_SLAVE_CHAR_CFG, 0x00000000}, + {WCD_SPI_SLAVE_CHAR_DATA_MOSI, 0x00000000}, + {WCD_SPI_SLAVE_CHAR_DATA_CS_N, 0x00000000}, + {WCD_SPI_SLAVE_CHAR_DATA_MISO, 0x00000000}, + {WCD_SPI_SLAVE_TRNS_BYTE_CNT, 0x00000000}, + {WCD_SPI_SLAVE_TRNS_LEN, 0x00000000}, + {WCD_SPI_SLAVE_FIFO_LEVEL, 0x00000000}, + {WCD_SPI_SLAVE_GENERICS, 0x80000000}, + {WCD_SPI_SLAVE_EXT_BASE_ADDR, 0x00000000}, +}; + +static bool wcd_spi_is_volatile_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case WCD_SPI_SLAVE_SANITY: + case WCD_SPI_SLAVE_STATUS: + case WCD_SPI_SLAVE_IRQ_STATUS: + case WCD_SPI_SLAVE_TX: + case WCD_SPI_SLAVE_SW_RST_IRQ: + case WCD_SPI_SLAVE_TRNS_BYTE_CNT: + case WCD_SPI_SLAVE_FIFO_LEVEL: + case WCD_SPI_SLAVE_GENERICS: + return true; + } + + return false; +} + +static bool wcd_spi_is_readable_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case WCD_SPI_SLAVE_SW_RESET: + case WCD_SPI_SLAVE_IRQ_CLR: + case WCD_SPI_SLAVE_IRQ_FORCE: + return false; + } + + return true; +} + +static struct regmap_config wcd_spi_regmap_cfg = { + .reg_bits = 8, + .val_bits = 32, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd_spi_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd_spi_defaults), + .max_register = WCD_SPI_MAX_REGISTER, + .volatile_reg = wcd_spi_is_volatile_reg, + .readable_reg = wcd_spi_is_readable_reg, +}; + +static int wcd_spi_add_ac_dev(struct device *dev, + struct device_node *node) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct platform_device *pdev; + int ret = 0; + + pdev = platform_device_alloc("wcd-spi-ac", -1); + if (IS_ERR_OR_NULL(pdev)) { + ret = PTR_ERR(pdev); + dev_err(dev, "%s: pdev alloc failed, ret = %d\n", + __func__, ret); + return ret; + } + + pdev->dev.parent = dev; + pdev->dev.of_node = node; + + ret = platform_device_add(pdev); + if (ret) { + dev_err(dev, "%s: pdev add failed, ret = %d\n", + __func__, ret); + goto dealloc_pdev; + } + + wcd_spi->ac_dev = &pdev->dev; + return 0; + +dealloc_pdev: + platform_device_put(pdev); + return ret; +} + +static int wdsp_spi_init(struct device *dev, void *priv_data) +{ + struct spi_device *spi = to_spi_device(dev); + int ret; + struct device_node *node; + + for_each_child_of_node(dev->of_node, node) { + if (!strcmp(node->name, "wcd_spi_ac")) + wcd_spi_add_ac_dev(dev, node); + } + + ret = wcd_spi_init(spi); + if (ret < 0) + dev_err(&spi->dev, "%s: Init failed, err = %d\n", + __func__, ret); + return ret; +} + +static int wdsp_spi_deinit(struct device *dev, void *priv_data) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + + /* + * Deinit means the hardware is reset. Mark the cache + * as dirty here, so init will sync the cache + */ + regcache_mark_dirty(wcd_spi->regmap); + + return 0; +} + +static struct wdsp_cmpnt_ops wdsp_spi_ops = { + .init = wdsp_spi_init, + .deinit = wdsp_spi_deinit, + .event_handler = wdsp_spi_event_handler, +}; + +static int wcd_spi_component_bind(struct device *dev, + struct device *master, + void *data) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int ret = 0; + + wcd_spi->m_dev = master; + wcd_spi->m_ops = data; + + if (wcd_spi->m_ops && + wcd_spi->m_ops->register_cmpnt_ops) + ret = wcd_spi->m_ops->register_cmpnt_ops(master, dev, + wcd_spi, + &wdsp_spi_ops); + if (ret) { + dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n", + __func__, ret); + goto done; + } + + wcd_spi->reg_bytes = DIV_ROUND_UP(wcd_spi_regmap_cfg.reg_bits, 8); + wcd_spi->val_bytes = DIV_ROUND_UP(wcd_spi_regmap_cfg.val_bits, 8); + + wcd_spi->regmap = devm_regmap_init(&spi->dev, &wcd_spi_regmap_bus, + &spi->dev, &wcd_spi_regmap_cfg); + if (IS_ERR(wcd_spi->regmap)) { + ret = PTR_ERR(wcd_spi->regmap); + dev_err(&spi->dev, "%s: Failed to allocate regmap, err = %d\n", + __func__, ret); + goto done; + } + + if (wcd_spi_debugfs_init(spi)) + dev_err(&spi->dev, "%s: Failed debugfs init\n", __func__); + + spi_message_init(&wcd_spi->msg1); + spi_message_add_tail(&wcd_spi->xfer1, &wcd_spi->msg1); + + spi_message_init(&wcd_spi->msg2); + spi_message_add_tail(&wcd_spi->xfer2[0], &wcd_spi->msg2); + spi_message_add_tail(&wcd_spi->xfer2[1], &wcd_spi->msg2); + + /* Pre-allocate the buffers */ + wcd_spi->tx_buf = dma_zalloc_coherent(&spi->dev, + WCD_SPI_RW_MAX_BUF_SIZE, + &wcd_spi->tx_dma, GFP_KERNEL); + if (!wcd_spi->tx_buf) { + ret = -ENOMEM; + goto done; + } + + wcd_spi->rx_buf = dma_zalloc_coherent(&spi->dev, + WCD_SPI_RW_MAX_BUF_SIZE, + &wcd_spi->rx_dma, GFP_KERNEL); + if (!wcd_spi->rx_buf) { + dma_free_coherent(&spi->dev, WCD_SPI_RW_MAX_BUF_SIZE, + wcd_spi->tx_buf, wcd_spi->tx_dma); + wcd_spi->tx_buf = NULL; + ret = -ENOMEM; + goto done; + } +done: + return ret; +} + +static void wcd_spi_component_unbind(struct device *dev, + struct device *master, + void *data) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data; + + debugfs_remove_recursive(dbg_data->dir); + dbg_data->dir = NULL; + + wcd_spi->m_dev = NULL; + wcd_spi->m_ops = NULL; + + spi_transfer_del(&wcd_spi->xfer1); + spi_transfer_del(&wcd_spi->xfer2[0]); + spi_transfer_del(&wcd_spi->xfer2[1]); + + dma_free_coherent(&spi->dev, WCD_SPI_RW_MAX_BUF_SIZE, + wcd_spi->tx_buf, wcd_spi->tx_dma); + dma_free_coherent(&spi->dev, WCD_SPI_RW_MAX_BUF_SIZE, + wcd_spi->rx_buf, wcd_spi->rx_dma); + wcd_spi->tx_buf = NULL; + wcd_spi->rx_buf = NULL; +} + +static const struct component_ops wcd_spi_component_ops = { + .bind = wcd_spi_component_bind, + .unbind = wcd_spi_component_unbind, +}; + +static int wcd_spi_probe(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi; + int ret = 0; + + wcd_spi = devm_kzalloc(&spi->dev, sizeof(*wcd_spi), + GFP_KERNEL); + if (!wcd_spi) + return -ENOMEM; + + ret = of_property_read_u32(spi->dev.of_node, + "qcom,mem-base-addr", + &wcd_spi->mem_base_addr); + if (ret < 0) { + dev_err(&spi->dev, "%s: Missing %s DT entry", + __func__, "qcom,mem-base-addr"); + goto err_ret; + } + + dev_dbg(&spi->dev, + "%s: mem_base_addr 0x%x\n", __func__, wcd_spi->mem_base_addr); + + mutex_init(&wcd_spi->clk_mutex); + mutex_init(&wcd_spi->xfer_mutex); + INIT_DELAYED_WORK(&wcd_spi->clk_dwork, wcd_spi_clk_work); + init_completion(&wcd_spi->resume_comp); + arch_setup_dma_ops(&spi->dev, 0, 0, NULL, true); + + wcd_spi->spi = spi; + spi_set_drvdata(spi, wcd_spi); + + ret = component_add(&spi->dev, &wcd_spi_component_ops); + if (ret) { + dev_err(&spi->dev, "%s: component_add failed err = %d\n", + __func__, ret); + goto err_component_add; + } + + return ret; + +err_component_add: + mutex_destroy(&wcd_spi->clk_mutex); + mutex_destroy(&wcd_spi->xfer_mutex); +err_ret: + devm_kfree(&spi->dev, wcd_spi); + spi_set_drvdata(spi, NULL); + return ret; +} + +static int wcd_spi_remove(struct spi_device *spi) +{ + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + + component_del(&spi->dev, &wcd_spi_component_ops); + + mutex_destroy(&wcd_spi->clk_mutex); + mutex_destroy(&wcd_spi->xfer_mutex); + + devm_kfree(&spi->dev, wcd_spi); + spi_set_drvdata(spi, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int wcd_spi_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int rc = 0; + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (!wcd_spi_can_suspend(wcd_spi)) { + rc = -EBUSY; + goto done; + } + + /* + * If we are here, it is okay to let the suspend go + * through for this driver. But, still need to notify + * the master to make sure all other components can suspend + * as well. + */ + if (wcd_spi->m_dev && wcd_spi->m_ops && + wcd_spi->m_ops->suspend) { + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + rc = wcd_spi->m_ops->suspend(wcd_spi->m_dev); + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + } + + if (rc == 0) + set_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask); + else + dev_dbg(&spi->dev, "%s: cannot suspend, err = %d\n", + __func__, rc); +done: + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + return rc; +} + +static int wcd_spi_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + clear_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask); + complete(&wcd_spi->resume_comp); + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + + return 0; +} + +static const struct dev_pm_ops wcd_spi_pm_ops = { + .suspend = wcd_spi_suspend, + .resume = wcd_spi_resume, +}; +#endif + +static const struct of_device_id wcd_spi_of_match[] = { + { .compatible = "qcom,wcd-spi-v2", }, + { } +}; +MODULE_DEVICE_TABLE(of, wcd_spi_of_match); + +static struct spi_driver wcd_spi_driver = { + .driver = { + .name = "wcd-spi-v2", + .of_match_table = wcd_spi_of_match, +#ifdef CONFIG_PM + .pm = &wcd_spi_pm_ops, +#endif + }, + .probe = wcd_spi_probe, + .remove = wcd_spi_remove, +}; + +module_spi_driver(wcd_spi_driver); + +MODULE_DESCRIPTION("WCD SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9335-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335-regmap.c new file mode 100644 index 0000000000..14e0561dcf --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335-regmap.c @@ -0,0 +1,1603 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "wcd9335_registers.h" + +static const struct reg_sequence wcd9335_1_x_defaults[] = { + { WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x00 }, + { WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN, 0x1f, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, 0x00, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x00, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG, 0x00, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG, 0x00, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG, 0x00, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG, 0x00, 0x00 }, + { WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x14, 0x00 }, + { WCD9335_CPE_SS_SS_ERROR_INT_MASK, 0x3f, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL, 0x00, 0x00 }, + { WCD9335_BIAS_VBG_FINE_ADJ, 0x55, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_2, 0x6c, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_3, 0x2d, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_8, 0x6c, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_10, 0x6c, 0x00 }, + { WCD9335_SIDO_SIDO_DRIVER_2, 0x77, 0x00 }, + { WCD9335_SIDO_SIDO_DRIVER_3, 0x77, 0x00 }, + { WCD9335_SIDO_SIDO_TEST_2, 0x00, 0x00 }, + { WCD9335_MBHC_ZDET_ANA_CTL, 0x00, 0x00 }, + { WCD9335_MBHC_FSM_DEBUG, 0xc0, 0x00 }, + { WCD9335_TX_1_2_ATEST_REFCTL, 0x08, 0x00 }, + { WCD9335_TX_3_4_ATEST_REFCTL, 0x08, 0x00 }, + { WCD9335_TX_5_6_ATEST_REFCTL, 0x08, 0x00 }, + { WCD9335_FLYBACK_VNEG_CTRL_1, 0x67, 0x00 }, + { WCD9335_FLYBACK_VNEG_CTRL_4, 0x5f, 0x00 }, + { WCD9335_FLYBACK_VNEG_CTRL_9, 0x50, 0x00 }, + { WCD9335_FLYBACK_VNEG_DAC_CTRL_1, 0x65, 0x00 }, + { WCD9335_FLYBACK_VNEG_DAC_CTRL_4, 0x40, 0x00 }, + { WCD9335_RX_BIAS_HPH_PA, 0xaa, 0x00 }, + { WCD9335_RX_BIAS_HPH_LOWPOWER, 0x62, 0x00 }, + { WCD9335_HPH_PA_CTL2, 0x40, 0x00 }, + { WCD9335_HPH_L_EN, 0x00, 0x00 }, + { WCD9335_HPH_R_EN, 0x00, 0x00 }, + { WCD9335_HPH_R_ATEST, 0x50, 0x00 }, + { WCD9335_HPH_RDAC_LDO_CTL, 0x00, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_CFG0, 0x00, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_CFG1, 0x00, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC2, 0x00, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC3, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER1_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER2_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER3_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER4_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER5_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER6_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER7_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_COMPANDER8_CTL7, 0x0c, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_CFG1, 0x04, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x0e, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC0, 0x00, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC1, 0x00, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x00, 0x00 }, + { WCD9335_SPLINE_SRC0_CLK_RST_CTL_0, 0x00, 0x00 }, + { WCD9335_SPLINE_SRC1_CLK_RST_CTL_0, 0x00, 0x00 }, + { WCD9335_SPLINE_SRC2_CLK_RST_CTL_0, 0x00, 0x00 }, + { WCD9335_SPLINE_SRC3_CLK_RST_CTL_0, 0x00, 0x00 }, + { WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00, 0x00 }, + { WCD9335_TEST_DEBUG_NPL_DLY_TEST_1, 0x00, 0x00 }, + { WCD9335_TEST_DEBUG_NPL_DLY_TEST_2, 0x00, 0x00 }, +}; + +static const struct reg_sequence wcd9335_2_0_defaults[] = { + { WCD9335_CODEC_RPM_CLK_GATE, 0x07, 0x00 }, + { WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN, 0x3f, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, 0x01, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x10, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG, 0x08, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG, 0x08, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG, 0x08, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG, 0x08, 0x00 }, + { WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x13, 0x00 }, + { WCD9335_CPE_SS_SS_ERROR_INT_MASK, 0xff, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL, 0x40, 0x00 }, + { WCD9335_BIAS_VBG_FINE_ADJ, 0xc5, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_2, 0x92, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_3, 0x35, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_8, 0x6e, 0x00 }, + { WCD9335_SIDO_SIDO_CCL_10, 0x6e, 0x00 }, + { WCD9335_SIDO_SIDO_DRIVER_2, 0x55, 0x00 }, + { WCD9335_SIDO_SIDO_DRIVER_3, 0x55, 0x00 }, + { WCD9335_SIDO_SIDO_TEST_2, 0x0f, 0x00 }, + { WCD9335_MBHC_ZDET_ANA_CTL, 0x0f, 0x00 }, + { WCD9335_TX_1_2_ATEST_REFCTL, 0x0a, 0x00 }, + { WCD9335_TX_3_4_ATEST_REFCTL, 0x0a, 0x00 }, + { WCD9335_TX_5_6_ATEST_REFCTL, 0x0a, 0x00 }, + { WCD9335_FLYBACK_VNEG_CTRL_1, 0xeb, 0x00 }, + { WCD9335_FLYBACK_VNEG_CTRL_4, 0x7f, 0x00 }, + { WCD9335_FLYBACK_VNEG_CTRL_9, 0x64, 0x00 }, + { WCD9335_FLYBACK_VNEG_DAC_CTRL_1, 0xed, 0x00 }, + { WCD9335_RX_BIAS_HPH_PA, 0x9a, 0x00 }, + { WCD9335_RX_BIAS_HPH_LOWPOWER, 0x82, 0x00 }, + { WCD9335_HPH_PA_CTL2, 0x50, 0x00 }, + { WCD9335_HPH_L_EN, 0x80, 0x00 }, + { WCD9335_HPH_R_EN, 0x80, 0x00 }, + { WCD9335_HPH_R_ATEST, 0x54, 0x00 }, + { WCD9335_HPH_RDAC_LDO_CTL, 0x33, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_CFG0, 0x10, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_CFG1, 0x02, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC2, 0x01, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC3, 0x3c, 0x00 }, + { WCD9335_CDC_COMPANDER1_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_COMPANDER2_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_COMPANDER3_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_COMPANDER4_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_COMPANDER5_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_COMPANDER6_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_COMPANDER7_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_COMPANDER8_CTL7, 0x08, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_CFG1, 0x44, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x1e, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC0, 0xfc, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC1, 0x08, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x08, 0x00 }, + { WCD9335_SPLINE_SRC0_CLK_RST_CTL_0, 0x20, 0x00 }, + { WCD9335_SPLINE_SRC1_CLK_RST_CTL_0, 0x20, 0x00 }, + { WCD9335_SPLINE_SRC2_CLK_RST_CTL_0, 0x20, 0x00 }, + { WCD9335_SPLINE_SRC3_CLK_RST_CTL_0, 0x20, 0x00 }, + { WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x0c, 0x00 }, + { WCD9335_TEST_DEBUG_NPL_DLY_TEST_1, 0x10, 0x00 }, + { WCD9335_TEST_DEBUG_NPL_DLY_TEST_2, 0x60, 0x00 }, + { WCD9335_DATA_HUB_NATIVE_FIFO_SYNC, 0x00, 0x00 }, + { WCD9335_DATA_HUB_NATIVE_FIFO_STATUS, 0x00, 0x00 }, + { WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD, 0x60, 0x00 }, + { WCD9335_CPE_SS_TX_PP_CFG, 0x3C, 0x00 }, + { WCD9335_CPE_SS_SVA_CFG, 0x00, 0x00 }, + { WCD9335_MBHC_FSM_STATUS, 0x00, 0x00 }, + { WCD9335_FLYBACK_CTRL_1, 0x45, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC7, 0x25, 0x00 }, + { WCD9335_SPLINE_SRC0_STATUS, 0x00, 0x00 }, + { WCD9335_SPLINE_SRC1_STATUS, 0x00, 0x00 }, + { WCD9335_SPLINE_SRC2_STATUS, 0x00, 0x00 }, + { WCD9335_SPLINE_SRC3_STATUS, 0x00, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT, 0x00, 0x00 }, +}; + +static const struct reg_default wcd9335_defaults[] = { + /* Page #0 registers */ + { WCD9335_PAGE0_PAGE_REGISTER, 0x00 }, + { WCD9335_CODEC_RPM_CLK_BYPASS, 0x00 }, + { WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x00 }, + { WCD9335_CODEC_RPM_RST_CTL, 0x00 }, + { WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x07 }, + { WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1, 0x00 }, + { WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2, 0x00 }, + { WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3, 0x00 }, + { WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN, 0x01 }, + { WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1, 0xff }, + { WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2, 0xff }, + { WCD9335_CODEC_RPM_INT_MASK, 0x3f }, + { WCD9335_CODEC_RPM_INT_STATUS, 0x00 }, + { WCD9335_CODEC_RPM_INT_CLEAR, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2, 0x07 }, + { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3, 0x01 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO, 0x0d }, + { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL, 0xCC }, + { WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL, 0x06 }, + { WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL, 0x06 }, + { WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL, 0x06 }, + { WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB, 0x00 }, + { WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, 0x0c }, + { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, 0x0c }, + { WCD9335_DATA_HUB_DATA_HUB_I2S_CLK, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG, 0x00 }, + { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG, 0x00 }, + { WCD9335_INTR_CFG, 0x00 }, + { WCD9335_INTR_CLR_COMMIT, 0x00 }, + { WCD9335_INTR_PIN1_MASK0, 0xff }, + { WCD9335_INTR_PIN1_MASK1, 0xff }, + { WCD9335_INTR_PIN1_MASK2, 0xff }, + { WCD9335_INTR_PIN1_MASK3, 0xff }, + { WCD9335_INTR_PIN1_STATUS0, 0x00 }, + { WCD9335_INTR_PIN1_STATUS1, 0x00 }, + { WCD9335_INTR_PIN1_STATUS2, 0x00 }, + { WCD9335_INTR_PIN1_STATUS3, 0x00 }, + { WCD9335_INTR_PIN1_CLEAR0, 0x00 }, + { WCD9335_INTR_PIN1_CLEAR1, 0x00 }, + { WCD9335_INTR_PIN1_CLEAR2, 0x00 }, + { WCD9335_INTR_PIN1_CLEAR3, 0x00 }, + { WCD9335_INTR_PIN2_MASK0, 0xff }, + { WCD9335_INTR_PIN2_MASK1, 0xff }, + { WCD9335_INTR_PIN2_MASK2, 0xff }, + { WCD9335_INTR_PIN2_MASK3, 0xff }, + { WCD9335_INTR_PIN2_STATUS0, 0x00 }, + { WCD9335_INTR_PIN2_STATUS1, 0x00 }, + { WCD9335_INTR_PIN2_STATUS2, 0x00 }, + { WCD9335_INTR_PIN2_STATUS3, 0x00 }, + { WCD9335_INTR_PIN2_CLEAR0, 0x00 }, + { WCD9335_INTR_PIN2_CLEAR1, 0x00 }, + { WCD9335_INTR_PIN2_CLEAR2, 0x00 }, + { WCD9335_INTR_PIN2_CLEAR3, 0x00 }, + { WCD9335_INTR_LEVEL0, 0x03 }, + { WCD9335_INTR_LEVEL1, 0xe0 }, + { WCD9335_INTR_LEVEL2, 0x10 }, + { WCD9335_INTR_LEVEL3, 0x80 }, + { WCD9335_INTR_BYPASS0, 0x00 }, + { WCD9335_INTR_BYPASS1, 0x00 }, + { WCD9335_INTR_BYPASS2, 0x00 }, + { WCD9335_INTR_BYPASS3, 0x00 }, + { WCD9335_INTR_SET0, 0x00 }, + { WCD9335_INTR_SET1, 0x00 }, + { WCD9335_INTR_SET2, 0x00 }, + { WCD9335_INTR_SET3, 0x00 }, + /* Page #1 registers */ + { WCD9335_PAGE1_PAGE_REGISTER, 0x00 }, + { WCD9335_CPE_FLL_USER_CTL_0, 0x71 }, + { WCD9335_CPE_FLL_USER_CTL_1, 0x34 }, + { WCD9335_CPE_FLL_USER_CTL_2, 0x0b }, + { WCD9335_CPE_FLL_USER_CTL_3, 0x02 }, + { WCD9335_CPE_FLL_USER_CTL_4, 0x04 }, + { WCD9335_CPE_FLL_USER_CTL_5, 0x02 }, + { WCD9335_CPE_FLL_USER_CTL_6, 0x64 }, + { WCD9335_CPE_FLL_USER_CTL_7, 0x00 }, + { WCD9335_CPE_FLL_USER_CTL_8, 0x94 }, + { WCD9335_CPE_FLL_USER_CTL_9, 0x70 }, + { WCD9335_CPE_FLL_L_VAL_CTL_0, 0x40 }, + { WCD9335_CPE_FLL_L_VAL_CTL_1, 0x00 }, + { WCD9335_CPE_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD9335_CPE_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD9335_CPE_FLL_CONFIG_CTL_0, 0x6b }, + { WCD9335_CPE_FLL_CONFIG_CTL_1, 0x05 }, + { WCD9335_CPE_FLL_CONFIG_CTL_2, 0x08 }, + { WCD9335_CPE_FLL_CONFIG_CTL_3, 0x00 }, + { WCD9335_CPE_FLL_CONFIG_CTL_4, 0x10 }, + { WCD9335_CPE_FLL_TEST_CTL_0, 0x00 }, + { WCD9335_CPE_FLL_TEST_CTL_1, 0x00 }, + { WCD9335_CPE_FLL_TEST_CTL_2, 0x00 }, + { WCD9335_CPE_FLL_TEST_CTL_3, 0x00 }, + { WCD9335_CPE_FLL_TEST_CTL_4, 0x00 }, + { WCD9335_CPE_FLL_TEST_CTL_5, 0x00 }, + { WCD9335_CPE_FLL_TEST_CTL_6, 0x00 }, + { WCD9335_CPE_FLL_TEST_CTL_7, 0x33 }, + { WCD9335_CPE_FLL_FREQ_CTL_0, 0x00 }, + { WCD9335_CPE_FLL_FREQ_CTL_1, 0x00 }, + { WCD9335_CPE_FLL_FREQ_CTL_2, 0x00 }, + { WCD9335_CPE_FLL_FREQ_CTL_3, 0x00 }, + { WCD9335_CPE_FLL_SSC_CTL_0, 0x00 }, + { WCD9335_CPE_FLL_SSC_CTL_1, 0x00 }, + { WCD9335_CPE_FLL_SSC_CTL_2, 0x00 }, + { WCD9335_CPE_FLL_SSC_CTL_3, 0x00 }, + { WCD9335_CPE_FLL_FLL_MODE, 0x20 }, + { WCD9335_CPE_FLL_STATUS_0, 0x00 }, + { WCD9335_CPE_FLL_STATUS_1, 0x00 }, + { WCD9335_CPE_FLL_STATUS_2, 0x00 }, + { WCD9335_CPE_FLL_STATUS_3, 0x00 }, + { WCD9335_I2S_FLL_USER_CTL_0, 0x41 }, + { WCD9335_I2S_FLL_USER_CTL_1, 0x94 }, + { WCD9335_I2S_FLL_USER_CTL_2, 0x08 }, + { WCD9335_I2S_FLL_USER_CTL_3, 0x02 }, + { WCD9335_I2S_FLL_USER_CTL_4, 0x04 }, + { WCD9335_I2S_FLL_USER_CTL_5, 0x02 }, + { WCD9335_I2S_FLL_USER_CTL_6, 0x40 }, + { WCD9335_I2S_FLL_USER_CTL_7, 0x00 }, + { WCD9335_I2S_FLL_USER_CTL_8, 0x5f }, + { WCD9335_I2S_FLL_USER_CTL_9, 0x02 }, + { WCD9335_I2S_FLL_L_VAL_CTL_0, 0x40 }, + { WCD9335_I2S_FLL_L_VAL_CTL_1, 0x00 }, + { WCD9335_I2S_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD9335_I2S_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD9335_I2S_FLL_CONFIG_CTL_0, 0x6b }, + { WCD9335_I2S_FLL_CONFIG_CTL_1, 0x05 }, + { WCD9335_I2S_FLL_CONFIG_CTL_2, 0x08 }, + { WCD9335_I2S_FLL_CONFIG_CTL_3, 0x00 }, + { WCD9335_I2S_FLL_CONFIG_CTL_4, 0x30 }, + { WCD9335_I2S_FLL_TEST_CTL_0, 0x80 }, + { WCD9335_I2S_FLL_TEST_CTL_1, 0x00 }, + { WCD9335_I2S_FLL_TEST_CTL_2, 0x00 }, + { WCD9335_I2S_FLL_TEST_CTL_3, 0x00 }, + { WCD9335_I2S_FLL_TEST_CTL_4, 0x00 }, + { WCD9335_I2S_FLL_TEST_CTL_5, 0x00 }, + { WCD9335_I2S_FLL_TEST_CTL_6, 0x00 }, + { WCD9335_I2S_FLL_TEST_CTL_7, 0xff }, + { WCD9335_I2S_FLL_FREQ_CTL_0, 0x00 }, + { WCD9335_I2S_FLL_FREQ_CTL_1, 0x00 }, + { WCD9335_I2S_FLL_FREQ_CTL_2, 0x00 }, + { WCD9335_I2S_FLL_FREQ_CTL_3, 0x00 }, + { WCD9335_I2S_FLL_SSC_CTL_0, 0x00 }, + { WCD9335_I2S_FLL_SSC_CTL_1, 0x00 }, + { WCD9335_I2S_FLL_SSC_CTL_2, 0x00 }, + { WCD9335_I2S_FLL_SSC_CTL_3, 0x00 }, + { WCD9335_I2S_FLL_FLL_MODE, 0x00 }, + { WCD9335_I2S_FLL_STATUS_0, 0x00 }, + { WCD9335_I2S_FLL_STATUS_1, 0x00 }, + { WCD9335_I2S_FLL_STATUS_2, 0x00 }, + { WCD9335_I2S_FLL_STATUS_3, 0x00 }, + { WCD9335_SB_FLL_USER_CTL_0, 0x41 }, + { WCD9335_SB_FLL_USER_CTL_1, 0x94 }, + { WCD9335_SB_FLL_USER_CTL_2, 0x08 }, + { WCD9335_SB_FLL_USER_CTL_3, 0x02 }, + { WCD9335_SB_FLL_USER_CTL_4, 0x04 }, + { WCD9335_SB_FLL_USER_CTL_5, 0x02 }, + { WCD9335_SB_FLL_USER_CTL_6, 0x40 }, + { WCD9335_SB_FLL_USER_CTL_7, 0x00 }, + { WCD9335_SB_FLL_USER_CTL_8, 0x5e }, + { WCD9335_SB_FLL_USER_CTL_9, 0x01 }, + { WCD9335_SB_FLL_L_VAL_CTL_0, 0x40 }, + { WCD9335_SB_FLL_L_VAL_CTL_1, 0x00 }, + { WCD9335_SB_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD9335_SB_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD9335_SB_FLL_CONFIG_CTL_0, 0x6b }, + { WCD9335_SB_FLL_CONFIG_CTL_1, 0x05 }, + { WCD9335_SB_FLL_CONFIG_CTL_2, 0x08 }, + { WCD9335_SB_FLL_CONFIG_CTL_3, 0x00 }, + { WCD9335_SB_FLL_CONFIG_CTL_4, 0x10 }, + { WCD9335_SB_FLL_TEST_CTL_0, 0x00 }, + { WCD9335_SB_FLL_TEST_CTL_1, 0x00 }, + { WCD9335_SB_FLL_TEST_CTL_2, 0x00 }, + { WCD9335_SB_FLL_TEST_CTL_3, 0x00 }, + { WCD9335_SB_FLL_TEST_CTL_4, 0x00 }, + { WCD9335_SB_FLL_TEST_CTL_5, 0x00 }, + { WCD9335_SB_FLL_TEST_CTL_6, 0x00 }, + { WCD9335_SB_FLL_TEST_CTL_7, 0xff }, + { WCD9335_SB_FLL_FREQ_CTL_0, 0x00 }, + { WCD9335_SB_FLL_FREQ_CTL_1, 0x00 }, + { WCD9335_SB_FLL_FREQ_CTL_2, 0x00 }, + { WCD9335_SB_FLL_FREQ_CTL_3, 0x00 }, + { WCD9335_SB_FLL_SSC_CTL_0, 0x00 }, + { WCD9335_SB_FLL_SSC_CTL_1, 0x00 }, + { WCD9335_SB_FLL_SSC_CTL_2, 0x00 }, + { WCD9335_SB_FLL_SSC_CTL_3, 0x00 }, + { WCD9335_SB_FLL_FLL_MODE, 0x00 }, + { WCD9335_SB_FLL_STATUS_0, 0x00 }, + { WCD9335_SB_FLL_STATUS_1, 0x00 }, + { WCD9335_SB_FLL_STATUS_2, 0x00 }, + { WCD9335_SB_FLL_STATUS_3, 0x00 }, + /* Page #2 registers */ + { WCD9335_PAGE2_PAGE_REGISTER, 0x00 }, + { WCD9335_CPE_SS_MEM_PTR_0, 0x00 }, + { WCD9335_CPE_SS_MEM_PTR_1, 0x00 }, + { WCD9335_CPE_SS_MEM_PTR_2, 0x00 }, + { WCD9335_CPE_SS_MEM_CTRL, 0x08 }, + { WCD9335_CPE_SS_MEM_BANK_0, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_1, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_2, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_3, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_4, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_5, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_6, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_7, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_8, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_9, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_10, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_11, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_12, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_13, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_14, 0x00 }, + { WCD9335_CPE_SS_MEM_BANK_15, 0x00 }, + { WCD9335_CPE_SS_INBOX1_TRG, 0x00 }, + { WCD9335_CPE_SS_INBOX2_TRG, 0x00 }, + { WCD9335_CPE_SS_INBOX1_0, 0x00 }, + { WCD9335_CPE_SS_INBOX1_1, 0x00 }, + { WCD9335_CPE_SS_INBOX1_2, 0x00 }, + { WCD9335_CPE_SS_INBOX1_3, 0x00 }, + { WCD9335_CPE_SS_INBOX1_4, 0x00 }, + { WCD9335_CPE_SS_INBOX1_5, 0x00 }, + { WCD9335_CPE_SS_INBOX1_6, 0x00 }, + { WCD9335_CPE_SS_INBOX1_7, 0x00 }, + { WCD9335_CPE_SS_INBOX1_8, 0x00 }, + { WCD9335_CPE_SS_INBOX1_9, 0x00 }, + { WCD9335_CPE_SS_INBOX1_10, 0x00 }, + { WCD9335_CPE_SS_INBOX1_11, 0x00 }, + { WCD9335_CPE_SS_INBOX1_12, 0x00 }, + { WCD9335_CPE_SS_INBOX1_13, 0x00 }, + { WCD9335_CPE_SS_INBOX1_14, 0x00 }, + { WCD9335_CPE_SS_INBOX1_15, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_0, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_1, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_2, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_3, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_4, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_5, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_6, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_7, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_8, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_9, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_10, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_11, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_12, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_13, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_14, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_15, 0x00 }, + { WCD9335_CPE_SS_INBOX2_0, 0x00 }, + { WCD9335_CPE_SS_INBOX2_1, 0x00 }, + { WCD9335_CPE_SS_INBOX2_2, 0x00 }, + { WCD9335_CPE_SS_INBOX2_3, 0x00 }, + { WCD9335_CPE_SS_INBOX2_4, 0x00 }, + { WCD9335_CPE_SS_INBOX2_5, 0x00 }, + { WCD9335_CPE_SS_INBOX2_6, 0x00 }, + { WCD9335_CPE_SS_INBOX2_7, 0x00 }, + { WCD9335_CPE_SS_INBOX2_8, 0x00 }, + { WCD9335_CPE_SS_INBOX2_9, 0x00 }, + { WCD9335_CPE_SS_INBOX2_10, 0x00 }, + { WCD9335_CPE_SS_INBOX2_11, 0x00 }, + { WCD9335_CPE_SS_INBOX2_12, 0x00 }, + { WCD9335_CPE_SS_INBOX2_13, 0x00 }, + { WCD9335_CPE_SS_INBOX2_14, 0x00 }, + { WCD9335_CPE_SS_INBOX2_15, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_0, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_1, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_2, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_3, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_4, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_5, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_6, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_7, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_8, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_9, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_10, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_11, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_12, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_13, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_14, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_15, 0x00 }, + { WCD9335_CPE_SS_OUTBOX1_ACK, 0x00 }, + { WCD9335_CPE_SS_OUTBOX2_ACK, 0x00 }, + { WCD9335_CPE_SS_EC_BUF_INT_PERIOD, 0x3c }, + { WCD9335_CPE_SS_US_BUF_INT_PERIOD, 0x60 }, + { WCD9335_CPE_SS_CFG, 0x41 }, + { WCD9335_CPE_SS_US_EC_MUX_CFG, 0x00 }, + { WCD9335_CPE_SS_MAD_CTL, 0x00 }, + { WCD9335_CPE_SS_CPAR_CTL, 0x00 }, + { WCD9335_CPE_SS_DMIC0_CTL, 0x00 }, + { WCD9335_CPE_SS_DMIC1_CTL, 0x00 }, + { WCD9335_CPE_SS_DMIC2_CTL, 0x00 }, + { WCD9335_CPE_SS_DMIC_CFG, 0x80 }, + { WCD9335_CPE_SS_CPAR_CFG, 0x00 }, + { WCD9335_CPE_SS_WDOG_CFG, 0x01 }, + { WCD9335_CPE_SS_BACKUP_INT, 0x00 }, + { WCD9335_CPE_SS_STATUS, 0x00 }, + { WCD9335_CPE_SS_CPE_OCD_CFG, 0x00 }, + { WCD9335_CPE_SS_SS_ERROR_INT_STATUS, 0x00 }, + { WCD9335_CPE_SS_SS_ERROR_INT_CLEAR, 0x00 }, + { WCD9335_SOC_MAD_MAIN_CTL_1, 0x00 }, + { WCD9335_SOC_MAD_MAIN_CTL_2, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_1, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_2, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_3, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_4, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_5, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_6, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_7, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_CTL_8, 0x00 }, + { WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR, 0x00 }, + { WCD9335_SOC_MAD_ULTR_CTL_1, 0x00 }, + { WCD9335_SOC_MAD_ULTR_CTL_2, 0x00 }, + { WCD9335_SOC_MAD_ULTR_CTL_3, 0x00 }, + { WCD9335_SOC_MAD_ULTR_CTL_4, 0x00 }, + { WCD9335_SOC_MAD_ULTR_CTL_5, 0x00 }, + { WCD9335_SOC_MAD_ULTR_CTL_6, 0x00 }, + { WCD9335_SOC_MAD_ULTR_CTL_7, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_1, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_2, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_3, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_4, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_5, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_6, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_7, 0x00 }, + { WCD9335_SOC_MAD_BEACON_CTL_8, 0x00 }, + { WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR, 0x00 }, + { WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL, 0x00 }, + { WCD9335_SOC_MAD_INP_SEL, 0x00 }, + /* Page #6 registers */ + { WCD9335_PAGE6_PAGE_REGISTER, 0x00 }, + { WCD9335_ANA_BIAS, 0x00 }, + { WCD9335_ANA_CLK_TOP, 0x00 }, + { WCD9335_ANA_RCO, 0x30 }, + { WCD9335_ANA_BUCK_VOUT_A, 0xb4 }, + { WCD9335_ANA_BUCK_VOUT_D, 0xb4 }, + { WCD9335_ANA_BUCK_CTL, 0x00 }, + { WCD9335_ANA_BUCK_STATUS, 0xe0 }, + { WCD9335_ANA_RX_SUPPLIES, 0x00 }, + { WCD9335_ANA_HPH, 0x00 }, + { WCD9335_ANA_EAR, 0x00 }, + { WCD9335_ANA_LO_1_2, 0x00 }, + { WCD9335_ANA_LO_3_4, 0x00 }, + { WCD9335_ANA_MAD_SETUP, 0x81 }, + { WCD9335_ANA_AMIC1, 0x20 }, + { WCD9335_ANA_AMIC2, 0x00 }, + { WCD9335_ANA_AMIC3, 0x20 }, + { WCD9335_ANA_AMIC4, 0x00 }, + { WCD9335_ANA_AMIC5, 0x20 }, + { WCD9335_ANA_AMIC6, 0x00 }, + { WCD9335_ANA_MBHC_MECH, 0x39 }, + { WCD9335_ANA_MBHC_ELECT, 0x08 }, + { WCD9335_ANA_MBHC_ZDET, 0x00 }, + { WCD9335_ANA_MBHC_RESULT_1, 0x00 }, + { WCD9335_ANA_MBHC_RESULT_2, 0x00 }, + { WCD9335_ANA_MBHC_RESULT_3, 0x00 }, + { WCD9335_ANA_MBHC_BTN0, 0x00 }, + { WCD9335_ANA_MBHC_BTN1, 0x10 }, + { WCD9335_ANA_MBHC_BTN2, 0x20 }, + { WCD9335_ANA_MBHC_BTN3, 0x30 }, + { WCD9335_ANA_MBHC_BTN4, 0x40 }, + { WCD9335_ANA_MBHC_BTN5, 0x50 }, + { WCD9335_ANA_MBHC_BTN6, 0x60 }, + { WCD9335_ANA_MBHC_BTN7, 0x70 }, + { WCD9335_ANA_MICB1, 0x10 }, + { WCD9335_ANA_MICB2, 0x10 }, + { WCD9335_ANA_MICB2_RAMP, 0x00 }, + { WCD9335_ANA_MICB3, 0x10 }, + { WCD9335_ANA_MICB4, 0x10 }, + { WCD9335_ANA_VBADC, 0x00 }, + { WCD9335_BIAS_CTL, 0x28 }, + { WCD9335_CLOCK_TEST_CTL, 0x00 }, + { WCD9335_RCO_CTRL_1, 0x44 }, + { WCD9335_RCO_CTRL_2, 0x44 }, + { WCD9335_RCO_CAL, 0x00 }, + { WCD9335_RCO_CAL_1, 0x00 }, + { WCD9335_RCO_CAL_2, 0x00 }, + { WCD9335_RCO_TEST_CTRL, 0x00 }, + { WCD9335_RCO_CAL_OUT_1, 0x00 }, + { WCD9335_RCO_CAL_OUT_2, 0x00 }, + { WCD9335_RCO_CAL_OUT_3, 0x00 }, + { WCD9335_RCO_CAL_OUT_4, 0x00 }, + { WCD9335_RCO_CAL_OUT_5, 0x00 }, + { WCD9335_SIDO_SIDO_MODE_1, 0x84 }, + { WCD9335_SIDO_SIDO_MODE_2, 0xfe }, + { WCD9335_SIDO_SIDO_MODE_3, 0xf6 }, + { WCD9335_SIDO_SIDO_MODE_4, 0x56 }, + { WCD9335_SIDO_SIDO_VCL_1, 0x00 }, + { WCD9335_SIDO_SIDO_VCL_2, 0x6c }, + { WCD9335_SIDO_SIDO_VCL_3, 0x44 }, + { WCD9335_SIDO_SIDO_CCL_1, 0x57 }, + { WCD9335_SIDO_SIDO_CCL_4, 0x61 }, + { WCD9335_SIDO_SIDO_CCL_5, 0x6d }, + { WCD9335_SIDO_SIDO_CCL_6, 0x60 }, + { WCD9335_SIDO_SIDO_CCL_7, 0x6f }, + { WCD9335_SIDO_SIDO_CCL_9, 0x6e }, + { WCD9335_SIDO_SIDO_FILTER_1, 0x92 }, + { WCD9335_SIDO_SIDO_FILTER_2, 0x54 }, + { WCD9335_SIDO_SIDO_DRIVER_1, 0x77 }, + { WCD9335_SIDO_SIDO_CAL_CODE_EXT_1, 0x9c }, + { WCD9335_SIDO_SIDO_CAL_CODE_EXT_2, 0x82 }, + { WCD9335_SIDO_SIDO_CAL_CODE_OUT_1, 0x00 }, + { WCD9335_SIDO_SIDO_CAL_CODE_OUT_2, 0x00 }, + { WCD9335_SIDO_SIDO_TEST_1, 0x00 }, + { WCD9335_MBHC_CTL_1, 0x32 }, + { WCD9335_MBHC_CTL_2, 0x01 }, + { WCD9335_MBHC_PLUG_DETECT_CTL, 0x69 }, + { WCD9335_MBHC_ZDET_RAMP_CTL, 0x00 }, + { WCD9335_MBHC_TEST_CTL, 0x00 }, + { WCD9335_VBADC_SUBBLOCK_EN, 0xfe }, + { WCD9335_VBADC_IBIAS_FE, 0x54 }, + { WCD9335_VBADC_BIAS_ADC, 0x51 }, + { WCD9335_VBADC_FE_CTRL, 0x1c }, + { WCD9335_VBADC_ADC_REF, 0x20 }, + { WCD9335_VBADC_ADC_IO, 0x80 }, + { WCD9335_VBADC_ADC_SAR, 0xff }, + { WCD9335_VBADC_DEBUG, 0x00 }, + { WCD9335_VBADC_ADC_DOUTMSB, 0x00 }, + { WCD9335_VBADC_ADC_DOUTLSB, 0x00 }, + { WCD9335_LDOH_MODE, 0x2b }, + { WCD9335_LDOH_BIAS, 0x68 }, + { WCD9335_LDOH_STB_LOADS, 0x00 }, + { WCD9335_LDOH_SLOWRAMP, 0x50 }, + { WCD9335_MICB1_TEST_CTL_1, 0x1a }, + { WCD9335_MICB1_TEST_CTL_2, 0x18 }, + { WCD9335_MICB1_TEST_CTL_3, 0xa4 }, + { WCD9335_MICB2_TEST_CTL_1, 0x1a }, + { WCD9335_MICB2_TEST_CTL_2, 0x18 }, + { WCD9335_MICB2_TEST_CTL_3, 0x24 }, + { WCD9335_MICB3_TEST_CTL_1, 0x1a }, + { WCD9335_MICB3_TEST_CTL_2, 0x18 }, + { WCD9335_MICB3_TEST_CTL_3, 0xa4 }, + { WCD9335_MICB4_TEST_CTL_1, 0x1a }, + { WCD9335_MICB4_TEST_CTL_2, 0x18 }, + { WCD9335_MICB4_TEST_CTL_3, 0xa4 }, + { WCD9335_TX_COM_ADC_VCM, 0x39 }, + { WCD9335_TX_COM_BIAS_ATEST, 0xc0 }, + { WCD9335_TX_COM_ADC_INT1_IB, 0x6f }, + { WCD9335_TX_COM_ADC_INT2_IB, 0x4f }, + { WCD9335_TX_COM_TXFE_DIV_CTL, 0x2e }, + { WCD9335_TX_COM_TXFE_DIV_START, 0x00 }, + { WCD9335_TX_COM_TXFE_DIV_STOP_9P6M, 0xc7 }, + { WCD9335_TX_COM_TXFE_DIV_STOP_12P288M, 0xff }, + { WCD9335_TX_1_2_TEST_EN, 0xcc }, + { WCD9335_TX_1_2_ADC_IB, 0x09 }, + { WCD9335_TX_1_2_TEST_CTL, 0x38 }, + { WCD9335_TX_1_2_TEST_BLK_EN, 0xff }, + { WCD9335_TX_1_2_TXFE_CLKDIV, 0x00 }, + { WCD9335_TX_1_2_SAR1_ERR, 0x00 }, + { WCD9335_TX_1_2_SAR2_ERR, 0x00 }, + { WCD9335_TX_3_4_TEST_EN, 0xcc }, + { WCD9335_TX_3_4_ADC_IB, 0x09 }, + { WCD9335_TX_3_4_TEST_CTL, 0x38 }, + { WCD9335_TX_3_4_TEST_BLK_EN, 0xff }, + { WCD9335_TX_3_4_TXFE_CLKDIV, 0x00 }, + { WCD9335_TX_3_4_SAR1_ERR, 0x00 }, + { WCD9335_TX_3_4_SAR2_ERR, 0x00 }, + { WCD9335_TX_5_6_TEST_EN, 0xcc }, + { WCD9335_TX_5_6_ADC_IB, 0x09 }, + { WCD9335_TX_5_6_TEST_CTL, 0x38 }, + { WCD9335_TX_5_6_TEST_BLK_EN, 0xff }, + { WCD9335_TX_5_6_TXFE_CLKDIV, 0x00 }, + { WCD9335_TX_5_6_SAR1_ERR, 0x00 }, + { WCD9335_TX_5_6_SAR2_ERR, 0x00 }, + { WCD9335_CLASSH_MODE_1, 0x40 }, + { WCD9335_CLASSH_MODE_2, 0x3a }, + { WCD9335_CLASSH_MODE_3, 0x00 }, + { WCD9335_CLASSH_CTRL_VCL_1, 0x70 }, + { WCD9335_CLASSH_CTRL_VCL_2, 0xa2 }, + { WCD9335_CLASSH_CTRL_CCL_1, 0x51 }, + { WCD9335_CLASSH_CTRL_CCL_2, 0x80 }, + { WCD9335_CLASSH_CTRL_CCL_3, 0x80 }, + { WCD9335_CLASSH_CTRL_CCL_4, 0x51 }, + { WCD9335_CLASSH_CTRL_CCL_5, 0x00 }, + { WCD9335_CLASSH_BUCK_TMUX_A_D, 0x00 }, + { WCD9335_CLASSH_BUCK_SW_DRV_CNTL, 0x77 }, + { WCD9335_CLASSH_SPARE, 0x00 }, + { WCD9335_FLYBACK_EN, 0x4e }, + { WCD9335_FLYBACK_VNEG_CTRL_2, 0x45 }, + { WCD9335_FLYBACK_VNEG_CTRL_3, 0x74 }, + { WCD9335_FLYBACK_VNEG_CTRL_5, 0x83 }, + { WCD9335_FLYBACK_VNEG_CTRL_6, 0x98 }, + { WCD9335_FLYBACK_VNEG_CTRL_7, 0xa9 }, + { WCD9335_FLYBACK_VNEG_CTRL_8, 0x68 }, + { WCD9335_FLYBACK_VNEG_DAC_CTRL_2, 0x50 }, + { WCD9335_FLYBACK_VNEG_DAC_CTRL_3, 0xa6 }, + { WCD9335_FLYBACK_TEST_CTL, 0x00 }, + { WCD9335_RX_AUX_SW_CTL, 0x00 }, + { WCD9335_RX_PA_AUX_IN_CONN, 0x00 }, + { WCD9335_RX_TIMER_DIV, 0x74 }, + { WCD9335_RX_OCP_CTL, 0x1f }, + { WCD9335_RX_OCP_COUNT, 0x77 }, + { WCD9335_RX_BIAS_EAR_DAC, 0xa0 }, + { WCD9335_RX_BIAS_EAR_AMP, 0xaa }, + { WCD9335_RX_BIAS_HPH_LDO, 0xa9 }, + { WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8a }, + { WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x88 }, + { WCD9335_RX_BIAS_HPH_CNP1, 0x86 }, + { WCD9335_RX_BIAS_DIFFLO_PA, 0x80 }, + { WCD9335_RX_BIAS_DIFFLO_REF, 0x88 }, + { WCD9335_RX_BIAS_DIFFLO_LDO, 0x88 }, + { WCD9335_RX_BIAS_SELO_DAC_PA, 0xa8 }, + { WCD9335_RX_BIAS_BUCK_RST, 0x08 }, + { WCD9335_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 }, + { WCD9335_RX_BIAS_FLYB_ERRAMP, 0x40 }, + { WCD9335_RX_BIAS_FLYB_BUFF, 0xaa }, + { WCD9335_RX_BIAS_FLYB_MID_RST, 0x44 }, + { WCD9335_HPH_L_STATUS, 0x04 }, + { WCD9335_HPH_R_STATUS, 0x04 }, + { WCD9335_HPH_CNP_EN, 0x80 }, + { WCD9335_HPH_CNP_WG_CTL, 0xda }, + { WCD9335_HPH_CNP_WG_TIME, 0x15 }, + { WCD9335_HPH_OCP_CTL, 0x28 }, + { WCD9335_HPH_AUTO_CHOP, 0x12 }, + { WCD9335_HPH_CHOP_CTL, 0x83 }, + { WCD9335_HPH_PA_CTL1, 0x46 }, + { WCD9335_HPH_L_TEST, 0x00 }, + { WCD9335_HPH_L_ATEST, 0x50 }, + { WCD9335_HPH_R_TEST, 0x00 }, + { WCD9335_HPH_RDAC_CLK_CTL1, 0x99 }, + { WCD9335_HPH_RDAC_CLK_CTL2, 0x9b }, + { WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 }, + { WCD9335_HPH_REFBUFF_UHQA_CTL, 0xa8 }, + { WCD9335_HPH_REFBUFF_LP_CTL, 0x00 }, + { WCD9335_HPH_L_DAC_CTL, 0x00 }, + { WCD9335_HPH_R_DAC_CTL, 0x00 }, + { WCD9335_EAR_EN_REG, 0x60 }, + { WCD9335_EAR_CMBUFF, 0x0d }, + { WCD9335_EAR_ICTL, 0x40 }, + { WCD9335_EAR_EN_DBG_CTL, 0x00 }, + { WCD9335_EAR_CNP, 0xe0 }, + { WCD9335_EAR_DAC_CTL_ATEST, 0x00 }, + { WCD9335_EAR_STATUS_REG, 0x04 }, + { WCD9335_EAR_OUT_SHORT, 0x00 }, + { WCD9335_DIFF_LO_MISC, 0x03 }, + { WCD9335_DIFF_LO_LO2_COMPANDER, 0x00 }, + { WCD9335_DIFF_LO_LO1_COMPANDER, 0x00 }, + { WCD9335_DIFF_LO_COMMON, 0x40 }, + { WCD9335_DIFF_LO_BYPASS_EN, 0x00 }, + { WCD9335_DIFF_LO_CNP, 0x20 }, + { WCD9335_DIFF_LO_CORE_OUT_PROG, 0x00 }, + { WCD9335_DIFF_LO_LDO_OUT_PROG, 0x00 }, + { WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x9b }, + { WCD9335_DIFF_LO_COM_PA_FREQ, 0xb0 }, + { WCD9335_DIFF_LO_RESERVED_REG, 0x60 }, + { WCD9335_DIFF_LO_LO1_STATUS_1, 0x00 }, + { WCD9335_DIFF_LO_LO1_STATUS_2, 0x00 }, + { WCD9335_SE_LO_COM1, 0x80 }, + { WCD9335_SE_LO_COM2, 0x04 }, + { WCD9335_SE_LO_LO3_GAIN, 0x20 }, + { WCD9335_SE_LO_LO3_CTRL, 0x04 }, + { WCD9335_SE_LO_LO4_GAIN, 0x20 }, + { WCD9335_SE_LO_LO4_CTRL, 0x04 }, + { WCD9335_SE_LO_LO3_STATUS, 0x00 }, + { WCD9335_SE_LO_LO4_STATUS, 0x00 }, + /* Page #10 registers */ + { WCD9335_PAGE10_PAGE_REGISTER, 0x00 }, + { WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x00 }, + { WCD9335_CDC_ANC0_MODE_1_CTL, 0x00 }, + { WCD9335_CDC_ANC0_MODE_2_CTL, 0x00 }, + { WCD9335_CDC_ANC0_FF_SHIFT, 0x00 }, + { WCD9335_CDC_ANC0_FB_SHIFT, 0x00 }, + { WCD9335_CDC_ANC0_LPF_FF_A_CTL, 0x00 }, + { WCD9335_CDC_ANC0_LPF_FF_B_CTL, 0x00 }, + { WCD9335_CDC_ANC0_LPF_FB_CTL, 0x00 }, + { WCD9335_CDC_ANC0_SMLPF_CTL, 0x00 }, + { WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL, 0x00 }, + { WCD9335_CDC_ANC0_IIR_ADAPT_CTL, 0x00 }, + { WCD9335_CDC_ANC0_IIR_COEFF_1_CTL, 0x00 }, + { WCD9335_CDC_ANC0_IIR_COEFF_2_CTL, 0x00 }, + { WCD9335_CDC_ANC0_FF_A_GAIN_CTL, 0x00 }, + { WCD9335_CDC_ANC0_FF_B_GAIN_CTL, 0x00 }, + { WCD9335_CDC_ANC0_FB_GAIN_CTL, 0x00 }, + { WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x00 }, + { WCD9335_CDC_ANC1_MODE_1_CTL, 0x00 }, + { WCD9335_CDC_ANC1_MODE_2_CTL, 0x00 }, + { WCD9335_CDC_ANC1_FF_SHIFT, 0x00 }, + { WCD9335_CDC_ANC1_FB_SHIFT, 0x00 }, + { WCD9335_CDC_ANC1_LPF_FF_A_CTL, 0x00 }, + { WCD9335_CDC_ANC1_LPF_FF_B_CTL, 0x00 }, + { WCD9335_CDC_ANC1_LPF_FB_CTL, 0x00 }, + { WCD9335_CDC_ANC1_SMLPF_CTL, 0x00 }, + { WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL, 0x00 }, + { WCD9335_CDC_ANC1_IIR_ADAPT_CTL, 0x00 }, + { WCD9335_CDC_ANC1_IIR_COEFF_1_CTL, 0x00 }, + { WCD9335_CDC_ANC1_IIR_COEFF_2_CTL, 0x00 }, + { WCD9335_CDC_ANC1_FF_A_GAIN_CTL, 0x00 }, + { WCD9335_CDC_ANC1_FF_B_GAIN_CTL, 0x00 }, + { WCD9335_CDC_ANC1_FB_GAIN_CTL, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX0_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX0_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX0_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX1_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX1_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX1_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX2_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX2_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX2_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX3_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX3_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX3_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX4_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX4_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX4_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX5_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX5_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX5_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX6_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX6_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX6_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX7_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX7_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX7_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_CTL, 0x04 }, + { WCD9335_CDC_TX8_TX_VOL_CTL, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_192_CTL, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_192_CFG, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC0, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC1, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC4, 0x20 }, + { WCD9335_CDC_TX8_TX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_TX8_TX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x00 }, + /* Page #11 registers */ + { WCD9335_PAGE11_PAGE_REGISTER, 0x00 }, + { WCD9335_CDC_COMPANDER1_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER1_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER1_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER1_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER1_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER1_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER1_CTL6, 0x01 }, + { WCD9335_CDC_COMPANDER2_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER2_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER2_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER2_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER2_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER2_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER2_CTL6, 0x01 }, + { WCD9335_CDC_COMPANDER3_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER3_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER3_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER3_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER3_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER3_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER3_CTL6, 0x01 }, + { WCD9335_CDC_COMPANDER4_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER4_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER4_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER4_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER4_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER4_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER4_CTL6, 0x01 }, + { WCD9335_CDC_COMPANDER5_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER5_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER5_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER5_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER5_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER5_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER5_CTL6, 0x01 }, + { WCD9335_CDC_COMPANDER6_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER6_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER6_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER6_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER6_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER6_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER6_CTL6, 0x01 }, + { WCD9335_CDC_COMPANDER7_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER7_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER7_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER7_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER7_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER7_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER7_CTL6, 0x01 }, + { WCD9335_CDC_COMPANDER8_CTL0, 0x60 }, + { WCD9335_CDC_COMPANDER8_CTL1, 0xdb }, + { WCD9335_CDC_COMPANDER8_CTL2, 0xff }, + { WCD9335_CDC_COMPANDER8_CTL3, 0x35 }, + { WCD9335_CDC_COMPANDER8_CTL4, 0xff }, + { WCD9335_CDC_COMPANDER8_CTL5, 0x00 }, + { WCD9335_CDC_COMPANDER8_CTL6, 0x01 }, + { WCD9335_CDC_RX0_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX0_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX0_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX0_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX0_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX1_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX1_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX1_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC4, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX1_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX2_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX2_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX2_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC4, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX2_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX3_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX3_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX3_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX3_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX4_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX4_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX4_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX4_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX5_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX5_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX5_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX5_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX6_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX6_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX6_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX6_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX7_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX7_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX7_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX7_RX_PATH_MIX_SEC1, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_CTL, 0x04 }, + { WCD9335_CDC_RX8_RX_PATH_CFG0, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_CFG2, 0x8f }, + { WCD9335_CDC_RX8_RX_VOL_CTL, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_MIX_CTL, 0x04 }, + { WCD9335_CDC_RX8_RX_VOL_MIX_CTL, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC2, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC3, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC5, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC6, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_SEC7, 0x00 }, + { WCD9335_CDC_RX8_RX_PATH_MIX_SEC1, 0x00 }, + /* Page #12 registers */ + { WCD9335_PAGE12_PAGE_REGISTER, 0x00 }, + { WCD9335_CDC_CLSH_CRC, 0x00 }, + { WCD9335_CDC_CLSH_DLY_CTRL, 0x03 }, + { WCD9335_CDC_CLSH_DECAY_CTRL, 0x02 }, + { WCD9335_CDC_CLSH_HPH_V_PA, 0x1c }, + { WCD9335_CDC_CLSH_EAR_V_PA, 0x39 }, + { WCD9335_CDC_CLSH_HPH_V_HD, 0x0c }, + { WCD9335_CDC_CLSH_EAR_V_HD, 0x0c }, + { WCD9335_CDC_CLSH_K1_MSB, 0x01 }, + { WCD9335_CDC_CLSH_K1_LSB, 0x00 }, + { WCD9335_CDC_CLSH_K2_MSB, 0x00 }, + { WCD9335_CDC_CLSH_K2_LSB, 0x80 }, + { WCD9335_CDC_CLSH_IDLE_CTRL, 0x00 }, + { WCD9335_CDC_CLSH_IDLE_HPH, 0x00 }, + { WCD9335_CDC_CLSH_IDLE_EAR, 0x00 }, + { WCD9335_CDC_CLSH_TEST0, 0x07 }, + { WCD9335_CDC_CLSH_TEST1, 0x00 }, + { WCD9335_CDC_CLSH_OVR_VREF, 0x00 }, + { WCD9335_CDC_BOOST0_BOOST_PATH_CTL, 0x00 }, + { WCD9335_CDC_BOOST0_BOOST_CTL, 0xb2 }, + { WCD9335_CDC_BOOST0_BOOST_CFG1, 0x00 }, + { WCD9335_CDC_BOOST0_BOOST_CFG2, 0x00 }, + { WCD9335_CDC_BOOST1_BOOST_PATH_CTL, 0x00 }, + { WCD9335_CDC_BOOST1_BOOST_CTL, 0xb2 }, + { WCD9335_CDC_BOOST1_BOOST_CFG1, 0x00 }, + { WCD9335_CDC_BOOST1_BOOST_CFG2, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_DATA_0, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_DATA_1, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_DATA_2, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_DATA_3, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_DATA_0, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_DATA_1, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_DATA_2, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_RD_DATA_3, 0x00 }, + { WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG, 0x0f }, + { WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS, 0x03 }, + { WCD9335_CDC_VBAT_VBAT_PATH_CTL, 0x00 }, + { WCD9335_CDC_VBAT_VBAT_CFG, 0x0a }, + { WCD9335_CDC_VBAT_VBAT_ADC_CAL1, 0x00 }, + { WCD9335_CDC_VBAT_VBAT_ADC_CAL2, 0x00 }, + { WCD9335_CDC_VBAT_VBAT_ADC_CAL3, 0x04 }, + { WCD9335_CDC_VBAT_VBAT_PK_EST1, 0xe0 }, + { WCD9335_CDC_VBAT_VBAT_PK_EST2, 0x01 }, + { WCD9335_CDC_VBAT_VBAT_PK_EST3, 0x40 }, + { WCD9335_CDC_VBAT_VBAT_RF_PROC1, 0x2a }, + { WCD9335_CDC_VBAT_VBAT_RF_PROC2, 0x86 }, + { WCD9335_CDC_VBAT_VBAT_TAC1, 0x70 }, + { WCD9335_CDC_VBAT_VBAT_TAC2, 0x18 }, + { WCD9335_CDC_VBAT_VBAT_TAC3, 0x18 }, + { WCD9335_CDC_VBAT_VBAT_TAC4, 0x03 }, + { WCD9335_CDC_VBAT_VBAT_GAIN_UPD1, 0x01 }, + { WCD9335_CDC_VBAT_VBAT_GAIN_UPD2, 0x00 }, + { WCD9335_CDC_VBAT_VBAT_GAIN_UPD3, 0x64 }, + { WCD9335_CDC_VBAT_VBAT_GAIN_UPD4, 0x01 }, + { WCD9335_CDC_VBAT_VBAT_DEBUG1, 0x00 }, + { WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON, 0x00 }, + { WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL, 0x00 }, + { WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04 }, + { WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00 }, + { WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL, 0x04 }, + { WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1, 0x00 }, + /* Page #13 registers */ + { WCD9335_PAGE13_PAGE_REGISTER, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_ANC_CFG0, 0x00 }, + { WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0x00 }, + { WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00 }, + { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0x00 }, + { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 0x00 }, + { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 0x00 }, + { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3, 0x00 }, + { WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, 0x00 }, + { WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_CTL, 0x08 }, + { WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1, 0x4b }, + { WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_STATUS, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD, 0x00 }, + { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_CTL, 0x40 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_CTL, 0x40 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL, 0x00 }, + { WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL, 0x00 }, + { WCD9335_CDC_TOP_TOP_CFG0, 0x00 }, + { WCD9335_CDC_TOP_TOP_CFG1, 0x00 }, + { WCD9335_CDC_TOP_TOP_CFG2, 0x00 }, + { WCD9335_CDC_TOP_TOP_CFG3, 0x18 }, + { WCD9335_CDC_TOP_TOP_CFG4, 0x00 }, + { WCD9335_CDC_TOP_TOP_CFG5, 0x00 }, + { WCD9335_CDC_TOP_TOP_CFG6, 0x00 }, + { WCD9335_CDC_TOP_TOP_CFG7, 0x00 }, + { WCD9335_CDC_TOP_HPHL_COMP_WR_LSB, 0x00 }, + { WCD9335_CDC_TOP_HPHL_COMP_WR_MSB, 0x00 }, + { WCD9335_CDC_TOP_HPHL_COMP_LUT, 0x00 }, + { WCD9335_CDC_TOP_HPHL_COMP_RD_LSB, 0x00 }, + { WCD9335_CDC_TOP_HPHL_COMP_RD_MSB, 0x00 }, + { WCD9335_CDC_TOP_HPHR_COMP_WR_LSB, 0x00 }, + { WCD9335_CDC_TOP_HPHR_COMP_WR_MSB, 0x00 }, + { WCD9335_CDC_TOP_HPHR_COMP_LUT, 0x00 }, + { WCD9335_CDC_TOP_HPHR_COMP_RD_LSB, 0x00 }, + { WCD9335_CDC_TOP_HPHR_COMP_RD_MSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFL_COMP_LUT, 0x00 }, + { WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFR_COMP_LUT, 0x00 }, + { WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB, 0x00 }, + { WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB, 0x00 }, + /* Page #0x80 registers */ + { WCD9335_PAGE80_PAGE_REGISTER, 0x00 }, + { WCD9335_TLMM_BIST_MODE_PINCFG, 0x00 }, + { WCD9335_TLMM_RF_PA_ON_PINCFG, 0x00 }, + { WCD9335_TLMM_INTR1_PINCFG, 0x00 }, + { WCD9335_TLMM_INTR2_PINCFG, 0x00 }, + { WCD9335_TLMM_SWR_DATA_PINCFG, 0x00 }, + { WCD9335_TLMM_SWR_CLK_PINCFG, 0x00 }, + { WCD9335_TLMM_SLIMBUS_DATA2_PINCFG, 0x00 }, + { WCD9335_TLMM_I2C_CLK_PINCFG, 0x00 }, + { WCD9335_TLMM_I2C_DATA_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_RX_SD0_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_RX_SD1_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_RX_SCK_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_RX_WS_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_TX_SD0_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_TX_SD1_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_TX_SCK_PINCFG, 0x00 }, + { WCD9335_TLMM_I2S_TX_WS_PINCFG, 0x00 }, + { WCD9335_TLMM_DMIC1_CLK_PINCFG, 0x00 }, + { WCD9335_TLMM_DMIC1_DATA_PINCFG, 0x00 }, + { WCD9335_TLMM_DMIC2_CLK_PINCFG, 0x00 }, + { WCD9335_TLMM_DMIC2_DATA_PINCFG, 0x00 }, + { WCD9335_TLMM_DMIC3_CLK_PINCFG, 0x00 }, + { WCD9335_TLMM_DMIC3_DATA_PINCFG, 0x00 }, + { WCD9335_TLMM_JTDI_PINCFG, 0x00 }, + { WCD9335_TLMM_JTDO_PINCFG, 0x00 }, + { WCD9335_TLMM_JTMS_PINCFG, 0x00 }, + { WCD9335_TLMM_JTCK_PINCFG, 0x00 }, + { WCD9335_TLMM_JTRST_PINCFG, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_OE_0, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_OE_1, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_OE_2, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_OE_3, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_DATA_0, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_DATA_1, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_DATA_2, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_CTL_DATA_3, 0x00 }, + { WCD9335_TEST_DEBUG_PAD_DRVCTL, 0x00 }, + { WCD9335_TEST_DEBUG_PIN_STATUS, 0x00 }, + { WCD9335_TEST_DEBUG_MEM_CTRL, 0x00 }, + { WCD9335_TEST_DEBUG_DEBUG_BUS_SEL, 0x00 }, + { WCD9335_TEST_DEBUG_DEBUG_JTAG, 0x00 }, + { WCD9335_TEST_DEBUG_DEBUG_EN_1, 0x00 }, + { WCD9335_TEST_DEBUG_DEBUG_EN_2, 0x00 }, + { WCD9335_TEST_DEBUG_DEBUG_EN_3, 0x00 }, +}; + +/* + * wcd9335_regmap_register_patch: Update register defaults based on version + * @regmap: handle to wcd9xxx regmap + * @version: wcd9335 version + * + * Returns error code in case of failure or 0 for success + */ +int wcd9335_regmap_register_patch(struct regmap *regmap, int version) +{ + int rc; + + if (!regmap) { + pr_err("%s: regmap struct is NULL\n", __func__); + return -EINVAL; + } + + switch (version) { + case TASHA_VERSION_1_0: + case TASHA_VERSION_1_1: + regcache_cache_only(regmap, true); + rc = regmap_multi_reg_write(regmap, wcd9335_1_x_defaults, + ARRAY_SIZE(wcd9335_1_x_defaults)); + regcache_cache_only(regmap, false); + break; + case TASHA_VERSION_2_0: + regcache_cache_only(regmap, true); + rc = regmap_multi_reg_write(regmap, wcd9335_2_0_defaults, + ARRAY_SIZE(wcd9335_2_0_defaults)); + regcache_cache_only(regmap, false); + break; + default: + pr_err("%s: unknown version: %d\n", __func__, version); + rc = -EINVAL; + break; + } + + return rc; +} +EXPORT_SYMBOL(wcd9335_regmap_register_patch); + +static bool wcd9335_is_readable_register(struct device *dev, unsigned int reg) +{ + u8 pg_num, reg_offset; + const u8 *reg_tbl = NULL; + + /* + * Get the page number from MSB of codec register. If its 0x80, assign + * the corresponding page index PAGE_0x80. + */ + pg_num = reg >> 0x8; + if (pg_num == 0x80) + pg_num = PAGE_0X80; + else if (pg_num >= 0xE) + return false; + + reg_tbl = wcd9335_reg[pg_num]; + reg_offset = reg & 0xFF; + + if (reg_tbl) + return reg_tbl[reg_offset]; + else + return false; +} + +static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg) +{ + /* + * registers from 0x000 to 0x0FF are volatile because + * this space contains registers related to interrupt + * status, mask etc + */ + if (reg < 0x100) + return true; + + /* IIR Coeff registers are not cacheable */ + if ((reg >= WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL) && + (reg <= WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)) + return true; + + if ((reg >= WCD9335_CDC_ANC0_IIR_COEFF_1_CTL) && + (reg <= WCD9335_CDC_ANC0_FB_GAIN_CTL)) + return true; + + if ((reg >= WCD9335_CDC_ANC1_IIR_COEFF_1_CTL) && + (reg <= WCD9335_CDC_ANC1_FB_GAIN_CTL)) + return true; + /* + * CPE inbox and outbox registers are volatile + * since they can be updated in the codec hardware + * to indicate CPE status + */ + if (reg >= WCD9335_CPE_SS_MEM_PTR_0 && + reg <= WCD9335_CPE_SS_OUTBOX2_ACK) + return true; + + if (reg >= WCD9335_RCO_CAL_OUT_1 && + reg <= WCD9335_RCO_CAL_OUT_5) + return true; + + switch (reg) { + case WCD9335_CPE_SS_INBOX1_TRG: + case WCD9335_CPE_SS_INBOX2_TRG: + case WCD9335_SWR_AHB_BRIDGE_WR_DATA_0: + case WCD9335_SWR_AHB_BRIDGE_WR_DATA_1: + case WCD9335_SWR_AHB_BRIDGE_WR_DATA_2: + case WCD9335_SWR_AHB_BRIDGE_WR_DATA_3: + case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0: + case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1: + case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2: + case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3: + case WCD9335_SWR_AHB_BRIDGE_RD_DATA_0: + case WCD9335_SWR_AHB_BRIDGE_RD_DATA_1: + case WCD9335_SWR_AHB_BRIDGE_RD_DATA_2: + case WCD9335_SWR_AHB_BRIDGE_RD_DATA_3: + case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0: + case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1: + case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2: + case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3: + case WCD9335_ANA_BIAS: + case WCD9335_ANA_CLK_TOP: + case WCD9335_ANA_RCO: + case WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL: + case WCD9335_ANA_MBHC_RESULT_3: + case WCD9335_ANA_MBHC_RESULT_2: + case WCD9335_ANA_MBHC_RESULT_1: + case WCD9335_ANA_MBHC_MECH: + case WCD9335_ANA_MBHC_ELECT: + case WCD9335_ANA_MBHC_ZDET: + case WCD9335_ANA_MICB2: + case WCD9335_CPE_SS_SS_ERROR_INT_STATUS: + case WCD9335_CPE_SS_SS_ERROR_INT_MASK: + case WCD9335_CPE_SS_SS_ERROR_INT_CLEAR: + case WCD9335_CPE_SS_STATUS: + case WCD9335_CPE_SS_BACKUP_INT: + case WCD9335_CPE_SS_CFG: + case WCD9335_SOC_MAD_MAIN_CTL_1: + case WCD9335_SOC_MAD_AUDIO_CTL_3: + case WCD9335_SOC_MAD_AUDIO_CTL_4: + case WCD9335_FLYBACK_EN: + case WCD9335_ANA_RX_SUPPLIES: + case WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL: + case WCD9335_SIDO_SIDO_CCL_2: + case WCD9335_SIDO_SIDO_CCL_4: + case WCD9335_DATA_HUB_NATIVE_FIFO_STATUS: + case WCD9335_MBHC_FSM_STATUS: + case WCD9335_SPLINE_SRC0_STATUS: + case WCD9335_SPLINE_SRC1_STATUS: + case WCD9335_SPLINE_SRC2_STATUS: + case WCD9335_SPLINE_SRC3_STATUS: + case WCD9335_SIDO_SIDO_TEST_2: + case WCD9335_SIDO_SIDO_CCL_8: + case WCD9335_BIAS_VBG_FINE_ADJ: + case WCD9335_VBADC_ADC_DOUTMSB: + case WCD9335_VBADC_ADC_DOUTLSB: + case WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL: + case WCD9335_ANA_BUCK_CTL: + return true; + default: + return false; + } +} + +struct regmap_config wcd9335_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd9335_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd9335_defaults), + .max_register = WCD9335_MAX_REGISTER, + .volatile_reg = wcd9335_is_volatile_register, + .readable_reg = wcd9335_is_readable_register, + .can_multi_write = true, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9335-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335-tables.c new file mode 100644 index 0000000000..991b2bc0dc --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335-tables.c @@ -0,0 +1,1317 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved. + */ + +#include +#include "wcd9335_registers.h" + +#define WCD9335_REG(reg) ((reg) & 0xFF) + +const u8 wcd9335_page0_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE0_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_CLK_BYPASS)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_CLK_GATE)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_CLK_MCLK_CFG)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_RST_CTL)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_INT_MASK)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_INT_STATUS)] = 1, + [WCD9335_REG(WCD9335_CODEC_RPM_INT_CLEAR)] = 0, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_CTL)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB)] = 1, + [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_I2S_CLK)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_NATIVE_FIFO_SYNC)] = 1, + [WCD9335_REG(WCD9335_DATA_HUB_NATIVE_FIFO_STATUS)] = 1, + [WCD9335_REG(WCD9335_INTR_CFG)] = 1, + [WCD9335_REG(WCD9335_INTR_CLR_COMMIT)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN1_MASK0)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_MASK1)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_MASK2)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_MASK3)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_STATUS0)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_STATUS1)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_STATUS2)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_STATUS3)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR0)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR1)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR2)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR3)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN2_MASK0)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_MASK1)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_MASK2)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_MASK3)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_STATUS0)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_STATUS1)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_STATUS2)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_STATUS3)] = 1, + [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR0)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR1)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR2)] = 0, + [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR3)] = 0, + [WCD9335_REG(WCD9335_INTR_LEVEL0)] = 1, + [WCD9335_REG(WCD9335_INTR_LEVEL1)] = 1, + [WCD9335_REG(WCD9335_INTR_LEVEL2)] = 1, + [WCD9335_REG(WCD9335_INTR_LEVEL3)] = 1, + [WCD9335_REG(WCD9335_INTR_BYPASS0)] = 1, + [WCD9335_REG(WCD9335_INTR_BYPASS1)] = 1, + [WCD9335_REG(WCD9335_INTR_BYPASS2)] = 1, + [WCD9335_REG(WCD9335_INTR_BYPASS3)] = 1, + [WCD9335_REG(WCD9335_INTR_SET0)] = 1, + [WCD9335_REG(WCD9335_INTR_SET1)] = 1, + [WCD9335_REG(WCD9335_INTR_SET2)] = 1, + [WCD9335_REG(WCD9335_INTR_SET3)] = 1, +}; + +const u8 wcd9335_page1_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE1_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_2)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_3)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_4)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_5)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_6)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_7)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_8)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_9)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_L_VAL_CTL_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_L_VAL_CTL_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_DSM_FRAC_CTL_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_DSM_FRAC_CTL_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_2)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_3)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_4)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_2)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_3)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_4)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_5)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_6)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_7)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_2)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_3)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_2)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_3)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_FLL_MODE)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_STATUS_0)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_STATUS_1)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_STATUS_2)] = 1, + [WCD9335_REG(WCD9335_CPE_FLL_STATUS_3)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_2)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_3)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_4)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_5)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_6)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_7)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_8)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_9)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_L_VAL_CTL_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_L_VAL_CTL_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_DSM_FRAC_CTL_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_DSM_FRAC_CTL_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_2)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_3)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_4)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_2)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_3)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_4)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_5)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_6)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_7)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_2)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_3)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_2)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_3)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_FLL_MODE)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_STATUS_0)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_STATUS_1)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_STATUS_2)] = 1, + [WCD9335_REG(WCD9335_I2S_FLL_STATUS_3)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_4)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_5)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_6)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_7)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_8)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_9)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_L_VAL_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_L_VAL_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_DSM_FRAC_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_DSM_FRAC_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_4)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_4)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_5)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_6)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_7)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_FLL_MODE)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_STATUS_0)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_STATUS_1)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_STATUS_2)] = 1, + [WCD9335_REG(WCD9335_SB_FLL_STATUS_3)] = 1, +}; + +const u8 wcd9335_page2_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE2_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_0)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_1)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_2)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_CTRL)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_0)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_1)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_2)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_3)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_4)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_5)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_6)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_7)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_8)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_9)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_10)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_11)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_12)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_13)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_14)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_15)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_TRG)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_TRG)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_0)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_1)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_2)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_3)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_4)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_5)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_6)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_7)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_8)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_9)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_10)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_11)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_12)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_13)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_14)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX1_15)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_0)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_1)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_2)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_3)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_4)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_5)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_6)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_7)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_8)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_9)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_10)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_11)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_12)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_13)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_14)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_15)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_0)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_1)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_2)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_3)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_4)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_5)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_6)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_7)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_8)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_9)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_10)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_11)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_12)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_13)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_14)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_INBOX2_15)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_0)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_1)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_2)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_3)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_4)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_5)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_6)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_7)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_8)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_9)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_10)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_11)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_12)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_13)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_14)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_15)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_ACK)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_ACK)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_EC_BUF_INT_PERIOD)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_US_BUF_INT_PERIOD)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_US_EC_MUX_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_MAD_CTL)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_CPAR_CTL)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_TX_PP_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_DMIC0_CTL)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_DMIC1_CTL)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_DMIC2_CTL)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_DMIC_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_SVA_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_CPAR_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_WDOG_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_BACKUP_INT)] = 0, + [WCD9335_REG(WCD9335_CPE_SS_STATUS)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_CPE_OCD_CFG)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_MASK)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_STATUS)] = 1, + [WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_CLEAR)] = 0, + [WCD9335_REG(WCD9335_SOC_MAD_MAIN_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_MAIN_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_4)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_5)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_6)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_7)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_8)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_4)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_5)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_6)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_7)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_1)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_2)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_3)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_4)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_5)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_6)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_7)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_8)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL)] = 1, + [WCD9335_REG(WCD9335_SOC_MAD_INP_SEL)] = 1, +}; + +const u8 wcd9335_page6_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE6_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_ANA_BIAS)] = 1, + [WCD9335_REG(WCD9335_ANA_CLK_TOP)] = 1, + [WCD9335_REG(WCD9335_ANA_RCO)] = 1, + [WCD9335_REG(WCD9335_ANA_BUCK_VOUT_A)] = 1, + [WCD9335_REG(WCD9335_ANA_BUCK_VOUT_D)] = 1, + [WCD9335_REG(WCD9335_ANA_BUCK_CTL)] = 1, + [WCD9335_REG(WCD9335_ANA_BUCK_STATUS)] = 1, + [WCD9335_REG(WCD9335_ANA_RX_SUPPLIES)] = 1, + [WCD9335_REG(WCD9335_ANA_HPH)] = 1, + [WCD9335_REG(WCD9335_ANA_EAR)] = 1, + [WCD9335_REG(WCD9335_ANA_LO_1_2)] = 1, + [WCD9335_REG(WCD9335_ANA_LO_3_4)] = 1, + [WCD9335_REG(WCD9335_ANA_MAD_SETUP)] = 1, + [WCD9335_REG(WCD9335_ANA_AMIC1)] = 1, + [WCD9335_REG(WCD9335_ANA_AMIC2)] = 1, + [WCD9335_REG(WCD9335_ANA_AMIC3)] = 1, + [WCD9335_REG(WCD9335_ANA_AMIC4)] = 1, + [WCD9335_REG(WCD9335_ANA_AMIC5)] = 1, + [WCD9335_REG(WCD9335_ANA_AMIC6)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_MECH)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_ELECT)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_ZDET)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_RESULT_1)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_RESULT_2)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_RESULT_3)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN0)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN1)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN2)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN3)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN4)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN5)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN6)] = 1, + [WCD9335_REG(WCD9335_ANA_MBHC_BTN7)] = 1, + [WCD9335_REG(WCD9335_ANA_MICB1)] = 1, + [WCD9335_REG(WCD9335_ANA_MICB2)] = 1, + [WCD9335_REG(WCD9335_ANA_MICB2_RAMP)] = 1, + [WCD9335_REG(WCD9335_ANA_MICB3)] = 1, + [WCD9335_REG(WCD9335_ANA_MICB4)] = 1, + [WCD9335_REG(WCD9335_ANA_VBADC)] = 1, + [WCD9335_REG(WCD9335_BIAS_CTL)] = 1, + [WCD9335_REG(WCD9335_BIAS_VBG_FINE_ADJ)] = 1, + [WCD9335_REG(WCD9335_CLOCK_TEST_CTL)] = 1, + [WCD9335_REG(WCD9335_RCO_CTRL_1)] = 1, + [WCD9335_REG(WCD9335_RCO_CTRL_2)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL_1)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL_2)] = 1, + [WCD9335_REG(WCD9335_RCO_TEST_CTRL)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL_OUT_1)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL_OUT_2)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL_OUT_3)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL_OUT_4)] = 1, + [WCD9335_REG(WCD9335_RCO_CAL_OUT_5)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_2)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_3)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_4)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_VCL_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_VCL_2)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_VCL_3)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_2)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_3)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_4)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_5)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_6)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_7)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_8)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_9)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_10)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_FILTER_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_FILTER_2)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_2)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_3)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_EXT_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_EXT_2)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_OUT_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_OUT_2)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_TEST_1)] = 1, + [WCD9335_REG(WCD9335_SIDO_SIDO_TEST_2)] = 1, + [WCD9335_REG(WCD9335_MBHC_CTL_1)] = 1, + [WCD9335_REG(WCD9335_MBHC_CTL_2)] = 1, + [WCD9335_REG(WCD9335_MBHC_PLUG_DETECT_CTL)] = 1, + [WCD9335_REG(WCD9335_MBHC_ZDET_ANA_CTL)] = 1, + [WCD9335_REG(WCD9335_MBHC_ZDET_RAMP_CTL)] = 1, + [WCD9335_REG(WCD9335_MBHC_FSM_DEBUG)] = 1, + [WCD9335_REG(WCD9335_MBHC_TEST_CTL)] = 1, + [WCD9335_REG(WCD9335_VBADC_SUBBLOCK_EN)] = 1, + [WCD9335_REG(WCD9335_VBADC_IBIAS_FE)] = 1, + [WCD9335_REG(WCD9335_VBADC_BIAS_ADC)] = 1, + [WCD9335_REG(WCD9335_VBADC_FE_CTRL)] = 1, + [WCD9335_REG(WCD9335_VBADC_ADC_REF)] = 1, + [WCD9335_REG(WCD9335_VBADC_ADC_IO)] = 1, + [WCD9335_REG(WCD9335_VBADC_ADC_SAR)] = 1, + [WCD9335_REG(WCD9335_VBADC_DEBUG)] = 1, + [WCD9335_REG(WCD9335_VBADC_ADC_DOUTMSB)] = 1, + [WCD9335_REG(WCD9335_VBADC_ADC_DOUTLSB)] = 1, + [WCD9335_REG(WCD9335_LDOH_MODE)] = 1, + [WCD9335_REG(WCD9335_LDOH_BIAS)] = 1, + [WCD9335_REG(WCD9335_LDOH_STB_LOADS)] = 1, + [WCD9335_REG(WCD9335_LDOH_SLOWRAMP)] = 1, + [WCD9335_REG(WCD9335_MICB1_TEST_CTL_1)] = 1, + [WCD9335_REG(WCD9335_MICB1_TEST_CTL_2)] = 1, + [WCD9335_REG(WCD9335_MICB1_TEST_CTL_3)] = 1, + [WCD9335_REG(WCD9335_MICB2_TEST_CTL_1)] = 1, + [WCD9335_REG(WCD9335_MICB2_TEST_CTL_2)] = 1, + [WCD9335_REG(WCD9335_MICB2_TEST_CTL_3)] = 1, + [WCD9335_REG(WCD9335_MICB3_TEST_CTL_1)] = 1, + [WCD9335_REG(WCD9335_MICB3_TEST_CTL_2)] = 1, + [WCD9335_REG(WCD9335_MICB3_TEST_CTL_3)] = 1, + [WCD9335_REG(WCD9335_MICB4_TEST_CTL_1)] = 1, + [WCD9335_REG(WCD9335_MICB4_TEST_CTL_2)] = 1, + [WCD9335_REG(WCD9335_MICB4_TEST_CTL_3)] = 1, + [WCD9335_REG(WCD9335_TX_COM_ADC_VCM)] = 1, + [WCD9335_REG(WCD9335_TX_COM_BIAS_ATEST)] = 1, + [WCD9335_REG(WCD9335_TX_COM_ADC_INT1_IB)] = 1, + [WCD9335_REG(WCD9335_TX_COM_ADC_INT2_IB)] = 1, + [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_CTL)] = 1, + [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_START)] = 1, + [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_STOP_9P6M)] = 1, + [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_STOP_12P288M)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_TEST_EN)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_ADC_IB)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_ATEST_REFCTL)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_TEST_CTL)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_TEST_BLK_EN)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_TXFE_CLKDIV)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_SAR1_ERR)] = 1, + [WCD9335_REG(WCD9335_TX_1_2_SAR2_ERR)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_TEST_EN)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_ADC_IB)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_ATEST_REFCTL)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_TEST_CTL)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_TEST_BLK_EN)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_TXFE_CLKDIV)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_SAR1_ERR)] = 1, + [WCD9335_REG(WCD9335_TX_3_4_SAR2_ERR)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_TEST_EN)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_ADC_IB)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_ATEST_REFCTL)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_TEST_CTL)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_TEST_BLK_EN)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_TXFE_CLKDIV)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_SAR1_ERR)] = 1, + [WCD9335_REG(WCD9335_TX_5_6_SAR2_ERR)] = 1, + [WCD9335_REG(WCD9335_CLASSH_MODE_1)] = 1, + [WCD9335_REG(WCD9335_CLASSH_MODE_2)] = 1, + [WCD9335_REG(WCD9335_CLASSH_MODE_3)] = 1, + [WCD9335_REG(WCD9335_CLASSH_CTRL_VCL_1)] = 1, + [WCD9335_REG(WCD9335_CLASSH_CTRL_VCL_2)] = 1, + [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_1)] = 1, + [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_2)] = 1, + [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_3)] = 1, + [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_4)] = 1, + [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_5)] = 1, + [WCD9335_REG(WCD9335_CLASSH_BUCK_TMUX_A_D)] = 1, + [WCD9335_REG(WCD9335_CLASSH_BUCK_SW_DRV_CNTL)] = 1, + [WCD9335_REG(WCD9335_CLASSH_SPARE)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_EN)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_1)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_2)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_3)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_4)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_5)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_6)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_7)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_8)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_9)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_1)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_2)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_3)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_4)] = 1, + [WCD9335_REG(WCD9335_FLYBACK_TEST_CTL)] = 1, + [WCD9335_REG(WCD9335_RX_AUX_SW_CTL)] = 1, + [WCD9335_REG(WCD9335_RX_PA_AUX_IN_CONN)] = 1, + [WCD9335_REG(WCD9335_RX_TIMER_DIV)] = 1, + [WCD9335_REG(WCD9335_RX_OCP_CTL)] = 1, + [WCD9335_REG(WCD9335_RX_OCP_COUNT)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_EAR_DAC)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_EAR_AMP)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_HPH_LDO)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_HPH_PA)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_HPH_RDAC_LDO)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_HPH_CNP1)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_HPH_LOWPOWER)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_PA)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_REF)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_LDO)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_SELO_DAC_PA)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_BUCK_RST)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_BUCK_VREF_ERRAMP)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_FLYB_ERRAMP)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_FLYB_BUFF)] = 1, + [WCD9335_REG(WCD9335_RX_BIAS_FLYB_MID_RST)] = 1, + [WCD9335_REG(WCD9335_HPH_L_STATUS)] = 1, + [WCD9335_REG(WCD9335_HPH_R_STATUS)] = 1, + [WCD9335_REG(WCD9335_HPH_CNP_EN)] = 1, + [WCD9335_REG(WCD9335_HPH_CNP_WG_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_CNP_WG_TIME)] = 1, + [WCD9335_REG(WCD9335_HPH_OCP_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_AUTO_CHOP)] = 1, + [WCD9335_REG(WCD9335_HPH_CHOP_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_PA_CTL1)] = 1, + [WCD9335_REG(WCD9335_HPH_PA_CTL2)] = 1, + [WCD9335_REG(WCD9335_HPH_L_EN)] = 1, + [WCD9335_REG(WCD9335_HPH_L_TEST)] = 1, + [WCD9335_REG(WCD9335_HPH_L_ATEST)] = 1, + [WCD9335_REG(WCD9335_HPH_R_EN)] = 1, + [WCD9335_REG(WCD9335_HPH_R_TEST)] = 1, + [WCD9335_REG(WCD9335_HPH_R_ATEST)] = 1, + [WCD9335_REG(WCD9335_HPH_RDAC_CLK_CTL1)] = 1, + [WCD9335_REG(WCD9335_HPH_RDAC_CLK_CTL2)] = 1, + [WCD9335_REG(WCD9335_HPH_RDAC_LDO_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_REFBUFF_UHQA_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_REFBUFF_LP_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_L_DAC_CTL)] = 1, + [WCD9335_REG(WCD9335_HPH_R_DAC_CTL)] = 1, + [WCD9335_REG(WCD9335_EAR_EN_REG)] = 1, + [WCD9335_REG(WCD9335_EAR_CMBUFF)] = 1, + [WCD9335_REG(WCD9335_EAR_ICTL)] = 1, + [WCD9335_REG(WCD9335_EAR_EN_DBG_CTL)] = 1, + [WCD9335_REG(WCD9335_EAR_CNP)] = 1, + [WCD9335_REG(WCD9335_EAR_DAC_CTL_ATEST)] = 1, + [WCD9335_REG(WCD9335_EAR_STATUS_REG)] = 1, + [WCD9335_REG(WCD9335_EAR_OUT_SHORT)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_MISC)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_LO2_COMPANDER)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_LO1_COMPANDER)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_COMMON)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_BYPASS_EN)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_CNP)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_CORE_OUT_PROG)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_LDO_OUT_PROG)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_COM_PA_FREQ)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_RESERVED_REG)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_LO1_STATUS_1)] = 1, + [WCD9335_REG(WCD9335_DIFF_LO_LO1_STATUS_2)] = 1, + [WCD9335_REG(WCD9335_SE_LO_COM1)] = 1, + [WCD9335_REG(WCD9335_SE_LO_COM2)] = 1, + [WCD9335_REG(WCD9335_SE_LO_LO3_GAIN)] = 1, + [WCD9335_REG(WCD9335_SE_LO_LO3_CTRL)] = 1, + [WCD9335_REG(WCD9335_SE_LO_LO4_GAIN)] = 1, + [WCD9335_REG(WCD9335_SE_LO_LO4_CTRL)] = 1, + [WCD9335_REG(WCD9335_SE_LO_LO3_STATUS)] = 1, + [WCD9335_REG(WCD9335_SE_LO_LO4_STATUS)] = 1, +}; + +const u8 wcd9335_page10_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE10_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_CLK_RESET_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_MODE_1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_MODE_2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_FF_SHIFT)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_FB_SHIFT)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_LPF_FF_A_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_LPF_FF_B_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_LPF_FB_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_SMLPF_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_IIR_ADAPT_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_IIR_COEFF_1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_IIR_COEFF_2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_FF_A_GAIN_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_FF_B_GAIN_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC0_FB_GAIN_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_CLK_RESET_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_MODE_1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_MODE_2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_FF_SHIFT)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_FB_SHIFT)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_LPF_FF_A_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_LPF_FF_B_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_LPF_FB_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_SMLPF_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_IIR_ADAPT_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_IIR_COEFF_1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_IIR_COEFF_2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_FF_A_GAIN_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_FF_B_GAIN_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_ANC1_FB_GAIN_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_192_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_192_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0)] = 1, +}; + +const u8 wcd9335_page11_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE11_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL0)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL1)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL2)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL3)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL4)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL5)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL6)] = 1, + [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC4)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_VOL_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_VOL_MIX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC5)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC6)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC7)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_SEC0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_SEC1)] = 1, +}; + +const u8 wcd9335_page12_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE12_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_CRC)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_DLY_CTRL)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_DECAY_CTRL)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_HPH_V_PA)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_EAR_V_PA)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_HPH_V_HD)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_EAR_V_HD)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_K1_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_K1_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_K2_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_K2_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_IDLE_CTRL)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_IDLE_HPH)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_IDLE_EAR)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_TEST0)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_TEST1)] = 1, + [WCD9335_REG(WCD9335_CDC_CLSH_OVR_VREF)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CFG2)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_0)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_1)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_2)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_3)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_0)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_1)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_2)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_3)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG)] = 1, + [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_CFG)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL1)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL2)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL3)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST1)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST2)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST3)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_RF_PROC1)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_RF_PROC2)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC1)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC2)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC3)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC4)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD1)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD2)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD3)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD4)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_DEBUG1)] = 1, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON)] = 0, + [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC0_CLK_RST_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC0_STATUS)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC1_CLK_RST_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC1_STATUS)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC2_CLK_RST_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC2_STATUS)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC3_CLK_RST_CTL_0)] = 1, + [WCD9335_REG(WCD9335_SPLINE_SRC3_STATUS)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] = 1, +}; + +const u8 wcd9335_page13_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE13_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_ANC_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3)] = 1, + [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3)] = 1, + [WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL)] = 1, + [WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL)] = 1, + [WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_STATUS)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD)] = 1, + [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG0)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG1)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG2)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG3)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG4)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG5)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG6)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG7)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_WR_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_WR_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_LUT)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_RD_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_RD_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_WR_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_WR_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_LUT)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_RD_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_RD_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_LUT)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_LUT)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB)] = 1, + [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB)] = 1, +}; + +const u8 wcd9335_page_0x80_reg_readable[WCD9335_PAGE_SIZE] = { + [WCD9335_REG(WCD9335_PAGE80_PAGE_REGISTER)] = 1, + [WCD9335_REG(WCD9335_TLMM_BIST_MODE_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_RF_PA_ON_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_INTR1_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_INTR2_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_SWR_DATA_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_SWR_CLK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_SLIMBUS_DATA2_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2C_CLK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2C_DATA_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_RX_SD0_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_RX_SD1_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_RX_SCK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_RX_WS_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_TX_SD0_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_TX_SD1_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_TX_SCK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_I2S_TX_WS_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_DMIC1_CLK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_DMIC1_DATA_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_DMIC2_CLK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_DMIC2_DATA_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_DMIC3_CLK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_DMIC3_DATA_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_JTDI_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_JTDO_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_JTMS_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_JTCK_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TLMM_JTRST_PINCFG)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_0)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_1)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_2)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_3)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_0)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_1)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_2)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_3)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PAD_DRVCTL)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_STATUS)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_NPL_DLY_TEST_1)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_NPL_DLY_TEST_2)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_MEM_CTRL)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_BUS_SEL)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_JTAG)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_1)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_2)] = 1, + [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_3)] = 1, +}; + +const u8 *wcd9335_reg[WCD9335_NUM_PAGES] = { + [PAGE_0] = wcd9335_page0_reg_readable, + [PAGE_1] = wcd9335_page1_reg_readable, + [PAGE_2] = wcd9335_page2_reg_readable, + [PAGE_6] = wcd9335_page6_reg_readable, + [PAGE_10] = wcd9335_page10_reg_readable, + [PAGE_11] = wcd9335_page11_reg_readable, + [PAGE_12] = wcd9335_page12_reg_readable, + [PAGE_13] = wcd9335_page13_reg_readable, + [PAGE_0X80] = wcd9335_page_0x80_reg_readable, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9335.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335.c new file mode 100644 index 0000000000..d8e61a56b1 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335.c @@ -0,0 +1,14810 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd9335.h" +#include +#include +#include +#include +#include "wcd9335_registers.h" +#include "wcd9335_irq.h" +#include "wcd_cpe_core.h" +#include +#include +#include + +#define DRV_NAME "tasha_codec" + +#define TASHA_RX_PORT_START_NUMBER 16 + +#define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +/* Fractional Rates */ +#define WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100) + +#define WCD9335_MIX_RATES_MASK (SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) + +#define TASHA_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define TASHA_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define TASHA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +/* + * Timeout in milli seconds and it is the wait time for + * slim channel removal interrupt to receive. + */ +#define TASHA_SLIM_CLOSE_TIMEOUT 1000 +#define TASHA_SLIM_IRQ_OVERFLOW (1 << 0) +#define TASHA_SLIM_IRQ_UNDERFLOW (1 << 1) +#define TASHA_SLIM_IRQ_PORT_CLOSED (1 << 2) +#define TASHA_MCLK_CLK_12P288MHZ 12288000 +#define TASHA_MCLK_CLK_9P6MHZ 9600000 + +#define TASHA_SLIM_PGD_PORT_INT_TX_EN0 (TASHA_SLIM_PGD_PORT_INT_EN0 + 2) + +#define TASHA_NUM_INTERPOLATORS 9 +#define TASHA_NUM_DECIMATORS 9 + +#define WCD9335_CHILD_DEVICES_MAX 6 + +#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE)) +#define TASHA_MAD_AUDIO_FIRMWARE_PATH "wcd9335/wcd9335_mad_audio.bin" +#define TASHA_CPE_SS_ERR_STATUS_MEM_ACCESS (1 << 0) +#define TASHA_CPE_SS_ERR_STATUS_WDOG_BITE (1 << 1) + +#define TASHA_CPE_FATAL_IRQS \ + (TASHA_CPE_SS_ERR_STATUS_WDOG_BITE | \ + TASHA_CPE_SS_ERR_STATUS_MEM_ACCESS) + +#define SLIM_BW_CLK_GEAR_9 6200000 +#define SLIM_BW_UNVOTE 0 + +#define CPE_FLL_CLK_75MHZ 75000000 +#define CPE_FLL_CLK_150MHZ 150000000 +#define WCD9335_REG_BITS 8 + +#define WCD9335_MAX_VALID_ADC_MUX 13 +#define WCD9335_INVALID_ADC_MUX 9 + +#define TASHA_DIG_CORE_REG_MIN WCD9335_CDC_ANC0_CLK_RESET_CTL +#define TASHA_DIG_CORE_REG_MAX 0xDFF + +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) + +#define TASHA_ZDET_NUM_MEASUREMENTS 900 +#define TASHA_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define TASHA_MBHC_GET_X1(x) (x & 0x3FFF) +/* z value compared in milliOhm */ +#define TASHA_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define TASHA_MBHC_ZDET_CONST (86 * 16384) +#define TASHA_MBHC_MOISTURE_VREF V_45_MV +#define TASHA_MBHC_MOISTURE_IREF I_3P0_UA + +#define TASHA_VERSION_ENTRY_SIZE 17 + +#define WCD9335_AMIC_PWR_LEVEL_LP 0 +#define WCD9335_AMIC_PWR_LEVEL_DEFAULT 1 +#define WCD9335_AMIC_PWR_LEVEL_HP 2 +#define WCD9335_AMIC_PWR_LVL_MASK 0x60 +#define WCD9335_AMIC_PWR_LVL_SHIFT 0x5 + +#define WCD9335_DEC_PWR_LVL_MASK 0x06 +#define WCD9335_DEC_PWR_LVL_LP 0x02 +#define WCD9335_DEC_PWR_LVL_HP 0x04 +#define WCD9335_DEC_PWR_LVL_DF 0x00 +#define WCD9335_STRING_LEN 100 + +#define CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) + +static int cpe_debug_mode; + +#define TASHA_MAX_MICBIAS 4 +#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone" +#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone" +#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone" +#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone" + +#define DAPM_LDO_H_STANDALONE "LDO_H" +module_param(cpe_debug_mode, int, 0664); +MODULE_PARM_DESC(cpe_debug_mode, "boot cpe in debug mode"); + +#define TASHA_DIG_CORE_COLLAPSE_TIMER_MS (5 * 1000) + +#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64 + +static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = { + "cdc-vdd-mic-bias", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h" +}; + +enum { + POWER_COLLAPSE, + POWER_RESUME, +}; + +enum tasha_sido_voltage { + SIDO_VOLTAGE_SVS_MV = 950, + SIDO_VOLTAGE_NOMINAL_MV = 1100, +}; + +static enum codec_variant codec_ver; + +static int dig_core_collapse_enable = 1; +module_param(dig_core_collapse_enable, int, 0664); +MODULE_PARM_DESC(dig_core_collapse_enable, "enable/disable power gating"); + +/* dig_core_collapse timer in seconds */ +static int dig_core_collapse_timer = (TASHA_DIG_CORE_COLLAPSE_TIMER_MS/1000); +module_param(dig_core_collapse_timer, int, 0664); +MODULE_PARM_DESC(dig_core_collapse_timer, "timer for power gating"); + +/* SVS Scaling enable/disable */ +static int svs_scaling_enabled = 1; +module_param(svs_scaling_enabled, int, 0664); +MODULE_PARM_DESC(svs_scaling_enabled, "enable/disable svs scaling"); + +/* SVS buck setting */ +static int sido_buck_svs_voltage = SIDO_VOLTAGE_SVS_MV; +module_param(sido_buck_svs_voltage, int, 0664); +MODULE_PARM_DESC(sido_buck_svs_voltage, + "setting for SVS voltage for SIDO BUCK"); + +#define TASHA_TX_UNMUTE_DELAY_MS 40 + +static int tx_unmute_delay = TASHA_TX_UNMUTE_DELAY_MS; +module_param(tx_unmute_delay, int, 0664); +MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path"); + +static struct afe_param_slimbus_slave_port_cfg tasha_slimbus_slave_port_cfg = { + .minor_version = 1, + .slimbus_dev_id = AFE_SLIMBUS_DEVICE_1, + .slave_dev_pgd_la = 0, + .slave_dev_intfdev_la = 0, + .bit_width = 16, + .data_format = 0, + .num_channels = 1 +}; + +struct tasha_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static struct afe_param_cdc_reg_page_cfg tasha_cdc_reg_page_cfg = { + .minor_version = AFE_API_VERSION_CDC_REG_PAGE_CFG, + .enable = 1, + .proc_id = AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_1, +}; + +static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = { + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_MAIN_CTL_1), + HW_MAD_AUDIO_ENABLE, 0x1, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_AUDIO_CTL_3), + HW_MAD_AUDIO_SLEEP_TIME, 0xF, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_AUDIO_CTL_4), + HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG), + MAD_AUDIO_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3), + MAD_AUDIO_INT_MASK_REG, 0x1, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3), + MAD_AUDIO_INT_STATUS_REG, 0x1, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3), + MAD_AUDIO_INT_CLEAR_REG, 0x1, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG), + VBAT_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3), + VBAT_INT_MASK_REG, 0x08, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3), + VBAT_INT_STATUS_REG, 0x08, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3), + VBAT_INT_CLEAR_REG, 0x08, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG), + VBAT_RELEASE_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3), + VBAT_RELEASE_INT_MASK_REG, 0x10, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3), + VBAT_RELEASE_INT_STATUS_REG, 0x10, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3), + VBAT_RELEASE_INT_CLEAR_REG, 0x10, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_TX_BASE), + SB_PGD_PORT_TX_WATERMARK_N, 0x1E, WCD9335_REG_BITS, 0x1 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_TX_BASE), + SB_PGD_PORT_TX_ENABLE_N, 0x1, WCD9335_REG_BITS, 0x1 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_RX_BASE), + SB_PGD_PORT_RX_WATERMARK_N, 0x1E, WCD9335_REG_BITS, 0x1 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_RX_BASE), + SB_PGD_PORT_RX_ENABLE_N, 0x1, WCD9335_REG_BITS, 0x1 + }, + { 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_IIR_ADAPT_CTL), + AANC_FF_GAIN_ADAPTIVE, 0x4, WCD9335_REG_BITS, 0 + }, + { 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_IIR_ADAPT_CTL), + AANC_FFGAIN_ADAPTIVE_EN, 0x8, WCD9335_REG_BITS, 0 + }, + { + 1, + (TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_FF_A_GAIN_CTL), + AANC_GAIN_CONTROL, 0xFF, WCD9335_REG_BITS, 0 + }, +}; + +static struct afe_param_cdc_reg_cfg_data tasha_audio_reg_cfg = { + .num_registers = ARRAY_SIZE(audio_reg_cfg), + .reg_data = audio_reg_cfg, +}; + +static struct afe_param_id_cdc_aanc_version tasha_cdc_aanc_version = { + .cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION, + .aanc_hw_version = AANC_HW_BLOCK_VERSION_2, +}; + +enum { + VI_SENSE_1, + VI_SENSE_2, + AIF4_SWITCH_VALUE, + AUDIO_NOMINAL, + CPE_NOMINAL, + HPH_PA_DELAY, + ANC_MIC_AMIC1, + ANC_MIC_AMIC2, + ANC_MIC_AMIC3, + ANC_MIC_AMIC4, + ANC_MIC_AMIC5, + ANC_MIC_AMIC6, + CLASSH_CONFIG, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + AIF2_PB, + AIF2_CAP, + AIF3_PB, + AIF3_CAP, + AIF4_PB, + AIF_MIX1_PB, + AIF4_MAD_TX, + AIF4_VIFEED, + AIF5_CPE_TX, + NUM_CODEC_DAIS, +}; + +enum { + INTn_1_MIX_INP_SEL_ZERO = 0, + INTn_1_MIX_INP_SEL_DEC0, + INTn_1_MIX_INP_SEL_DEC1, + INTn_1_MIX_INP_SEL_IIR0, + INTn_1_MIX_INP_SEL_IIR1, + INTn_1_MIX_INP_SEL_RX0, + INTn_1_MIX_INP_SEL_RX1, + INTn_1_MIX_INP_SEL_RX2, + INTn_1_MIX_INP_SEL_RX3, + INTn_1_MIX_INP_SEL_RX4, + INTn_1_MIX_INP_SEL_RX5, + INTn_1_MIX_INP_SEL_RX6, + INTn_1_MIX_INP_SEL_RX7, + +}; + +#define IS_VALID_NATIVE_FIFO_PORT(inp) \ + ((inp >= INTn_1_MIX_INP_SEL_RX0) && \ + (inp <= INTn_1_MIX_INP_SEL_RX3)) + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_PROXIMITY, +}; + +enum { + INTERP_EAR = 0, + INTERP_HPHL, + INTERP_HPHR, + INTERP_LO1, + INTERP_LO2, + INTERP_LO3, + INTERP_LO4, + INTERP_SPKR1, + INTERP_SPKR2, +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +static struct interp_sample_rate int_prim_sample_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +static struct interp_sample_rate int_mix_sample_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +static const struct wcd9xxx_ch tasha_rx_chs[TASHA_RX_MAX] = { + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER, 0), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 1, 1), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 2, 2), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 3, 3), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 4, 4), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 5, 5), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 6, 6), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 7, 7), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 8, 8), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 9, 9), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 10, 10), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 11, 11), + WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 12, 12), +}; + +static const struct wcd9xxx_ch tasha_tx_chs[TASHA_TX_MAX] = { + WCD9XXX_CH(0, 0), + WCD9XXX_CH(1, 1), + WCD9XXX_CH(2, 2), + WCD9XXX_CH(3, 3), + WCD9XXX_CH(4, 4), + WCD9XXX_CH(5, 5), + WCD9XXX_CH(6, 6), + WCD9XXX_CH(7, 7), + WCD9XXX_CH(8, 8), + WCD9XXX_CH(9, 9), + WCD9XXX_CH(10, 10), + WCD9XXX_CH(11, 11), + WCD9XXX_CH(12, 12), + WCD9XXX_CH(13, 13), + WCD9XXX_CH(14, 14), + WCD9XXX_CH(15, 15), +}; + +static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = { + /* Needs to define in the same order of DAI enum definitions */ + 0, + BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX), + 0, + BIT(AIF1_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX), + 0, + BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX), + 0, + 0, + BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF5_CPE_TX), + 0, + BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX), +}; + +static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = { + 0, /* AIF1_PB */ + BIT(AIF2_CAP), /* AIF1_CAP */ + 0, /* AIF2_PB */ + BIT(AIF1_CAP), /* AIF2_CAP */ +}; + +/* Codec supports 2 IIR filters */ +enum { + IIR0 = 0, + IIR1, + IIR_MAX, +}; + +/* Each IIR has 5 Filter Stages */ +enum { + BAND1 = 0, + BAND2, + BAND3, + BAND4, + BAND5, + BAND_MAX, +}; + +enum { + COMPANDER_1, /* HPH_L */ + COMPANDER_2, /* HPH_R */ + COMPANDER_3, /* LO1_DIFF */ + COMPANDER_4, /* LO2_DIFF */ + COMPANDER_5, /* LO3_SE */ + COMPANDER_6, /* LO4_SE */ + COMPANDER_7, /* SWR SPK CH1 */ + COMPANDER_8, /* SWR SPK CH2 */ + COMPANDER_MAX, +}; + +enum { + SRC_IN_HPHL, + SRC_IN_LO1, + SRC_IN_HPHR, + SRC_IN_LO2, + SRC_IN_SPKRL, + SRC_IN_LO3, + SRC_IN_SPKRR, + SRC_IN_LO4, +}; + +enum { + SPLINE_SRC0, + SPLINE_SRC1, + SPLINE_SRC2, + SPLINE_SRC3, + SPLINE_SRC_MAX, +}; + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +static struct snd_soc_dai_driver tasha_dai[]; +static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv); + +static int tasha_config_compander(struct snd_soc_component *, int, int); +static void tasha_codec_set_tx_hold(struct snd_soc_component *, u16, bool); +static int tasha_codec_internal_rco_ctrl(struct snd_soc_component *component, + bool enable); + +/* Hold instance to soundwire platform device */ +struct tasha_swr_ctrl_data { + struct platform_device *swr_pdev; + struct ida swr_ida; +}; + +struct wcd_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action); +}; + +static struct wcd_mbhc_register + wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN", + WCD9335_ANA_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + WCD9335_ANA_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + WCD9335_ANA_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + WCD9335_MBHC_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + WCD9335_ANA_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + WCD9335_MBHC_PLUG_DETECT_CTL, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + WCD9335_ANA_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + WCD9335_ANA_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + WCD9335_ANA_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + WCD9335_ANA_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + WCD9335_ANA_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + WCD9335_ANA_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + WCD9335_MBHC_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + WCD9335_MBHC_CTL_1, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + WCD9335_MBHC_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + WCD9335_ANA_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE", + WCD9335_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + WCD9335_ANA_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + WCD9335_ANA_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + WCD9335_ANA_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + WCD9335_HPH_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + WCD9335_ANA_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + WCD9335_ANA_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + WCD9335_ANA_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + WCD9335_ANA_MICB2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + WCD9335_HPH_CNP_WG_TIME, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + WCD9335_ANA_HPH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + WCD9335_ANA_HPH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + WCD9335_ANA_HPH, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + WCD9335_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL", + 0, 0, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", + WCD9335_ANA_MBHC_ZDET, 0x01, 0, 0), + /* + * MBHC FSM status register is only available in Tasha 2.0. + * So, init with 0 later once the version is known, then values + * will be updated. + */ + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + 0, 0, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + WCD9335_MBHC_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD9335_MBHC_FSM_STATUS, 0X20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD9335_HPH_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD9335_HPH_PA_CTL2, 0x10, 4, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = WCD9335_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = WCD9335_IRQ_HPH_PA_OCPL_FAULT, + .hph_right_ocp = WCD9335_IRQ_HPH_PA_OCPR_FAULT, +}; + +struct wcd_vbat { + bool is_enabled; + bool adc_config; + /* Variables to cache Vbat ADC output values */ + u16 dcp1; + u16 dcp2; +}; + +struct hpf_work { + struct tasha_priv *tasha; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +#define WCD9335_SPK_ANC_EN_DELAY_MS 350 +static int spk_anc_en_delay = WCD9335_SPK_ANC_EN_DELAY_MS; +module_param(spk_anc_en_delay, int, 0664); +MODULE_PARM_DESC(spk_anc_en_delay, "delay to enable anc in speaker path"); + +struct spk_anc_work { + struct tasha_priv *tasha; + struct delayed_work dwork; +}; + +struct tx_mute_work { + struct tasha_priv *tasha; + u8 decimator; + struct delayed_work dwork; +}; + +struct tasha_priv { + struct device *dev; + struct wcd9xxx *wcd9xxx; + + struct snd_soc_component *component; + u32 adc_count; + u32 rx_bias_count; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + s32 ldo_h_users; + s32 micb_ref[TASHA_MAX_MICBIAS]; + s32 pullup_ref[TASHA_MAX_MICBIAS]; + + u32 anc_slot; + bool anc_func; + bool is_wsa_attach; + + /* Vbat module */ + struct wcd_vbat vbat; + + /* cal info for codec */ + struct fw_info *fw_data; + + /*track tasha interface type*/ + u8 intf_type; + + /* num of slim ports required */ + struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS]; + + /* SoundWire data structure */ + struct tasha_swr_ctrl_data *swr_ctrl_data; + int nr; + + /*compander*/ + int comp_enabled[COMPANDER_MAX]; + + /* Maintain the status of AUX PGA */ + int aux_pga_cnt; + u8 aux_l_gain; + u8 aux_r_gain; + + bool spkr_pa_widget_on; + struct regulator *spkdrv_reg; + struct regulator *spkdrv2_reg; + + bool mbhc_started; + /* class h specific data */ + struct wcd_clsh_cdc_data clsh_d; + + struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg; + + /* + * list used to save/restore registers at start and + * end of impedance measurement + */ + struct list_head reg_save_restore; + + /* handle to cpe core */ + struct wcd_cpe_core *cpe_core; + u32 current_cpe_clk_freq; + enum tasha_sido_voltage sido_voltage; + int sido_ccl_cnt; + + u32 ana_rx_supplies; + /* Multiplication factor used for impedance detection */ + int zdet_gain_mul_fact; + + /* to track the status */ + unsigned long status_mask; + + struct work_struct tasha_add_child_devices_work; + struct wcd_swr_ctrl_platform_data swr_plat_data; + + /* Port values for Rx and Tx codec_dai */ + unsigned int rx_port_value[TASHA_RX_MAX]; + unsigned int tx_port_value; + + unsigned int vi_feed_value; + /* Tasha Interpolator Mode Select for EAR, HPH_L and HPH_R */ + u32 hph_mode; + + u16 prim_int_users[TASHA_NUM_INTERPOLATORS]; + int spl_src_users[SPLINE_SRC_MAX]; + + struct wcd9xxx_resmgr_v2 *resmgr; + struct delayed_work power_gate_work; + struct mutex power_lock; + struct mutex sido_lock; + + /* mbhc module */ + struct wcd_mbhc mbhc; + struct blocking_notifier_head notifier; + struct mutex micb_lock; + + struct clk *wcd_ext_clk; + struct clk *wcd_native_clk; + struct mutex swr_read_lock; + struct mutex swr_write_lock; + struct mutex swr_clk_lock; + int swr_clk_users; + int native_clk_users; + int (*zdet_gpio_cb)(struct snd_soc_component *component, bool high); + + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + int power_active_ref; + + struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX]; + + int (*machine_codec_event_cb)(struct snd_soc_component *component, + enum wcd9335_codec_event); + int spkr_gain_offset; + int spkr_mode; + int ear_spkr_gain; + struct hpf_work tx_hpf_work[TASHA_NUM_DECIMATORS]; + struct tx_mute_work tx_mute_dwork[TASHA_NUM_DECIMATORS]; + struct spk_anc_work spk_anc_dwork; + struct mutex codec_mutex; + int hph_l_gain; + int hph_r_gain; + int rx_7_count; + int rx_8_count; + bool clk_mode; + bool clk_internal; + /* Lock to prevent multiple functions voting at same time */ + struct mutex sb_clk_gear_lock; + /* Count for functions voting or un-voting */ + u32 ref_count; + /* Lock to protect mclk enablement */ + struct mutex mclk_lock; + + struct platform_device *pdev_child_devices + [WCD9335_CHILD_DEVICES_MAX]; + int child_count; +}; + +static int tasha_codec_vote_max_bw(struct snd_soc_component *component, + bool vote); + +static const struct tasha_reg_mask_val tasha_spkr_default[] = { + {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x58}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x58}, +}; + +static const struct tasha_reg_mask_val tasha_spkr_mode1[] = { + {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x00}, + {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x00}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x00}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x00}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x44}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44}, +}; + +/** + * tasha_set_spkr_gain_offset - offset the speaker path + * gain with the given offset value. + * + * @component: codec component instance + * @offset: Indicates speaker path gain offset value. + * + * Returns 0 on success or -EINVAL on error. + */ +int tasha_set_spkr_gain_offset(struct snd_soc_component *component, int offset) +{ + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + + if (!priv) + return -EINVAL; + + priv->spkr_gain_offset = offset; + return 0; +} +EXPORT_SYMBOL(tasha_set_spkr_gain_offset); + +/** + * tasha_set_spkr_mode - Configures speaker compander and smartboost + * settings based on speaker mode. + * + * @component: codec component instance + * @mode: Indicates speaker configuration mode. + * + * Returns 0 on success or -EINVAL on error. + */ +int tasha_set_spkr_mode(struct snd_soc_component *component, int mode) +{ + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + int i; + const struct tasha_reg_mask_val *regs; + int size; + + if (!priv) + return -EINVAL; + + switch (mode) { + case SPKR_MODE_1: + regs = tasha_spkr_mode1; + size = ARRAY_SIZE(tasha_spkr_mode1); + break; + default: + regs = tasha_spkr_default; + size = ARRAY_SIZE(tasha_spkr_default); + break; + } + + priv->spkr_mode = mode; + for (i = 0; i < size; i++) + snd_soc_component_update_bits(component, regs[i].reg, + regs[i].mask, regs[i].val); + return 0; +} +EXPORT_SYMBOL(tasha_set_spkr_mode); + +static void tasha_enable_sido_buck(struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + snd_soc_component_update_bits(component, WCD9335_ANA_RCO, 0x80, 0x80); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + 0x02, 0x02); + /* 100us sleep needed after IREF settings */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + 0x04, 0x04); + /* 100us sleep needed after VREF settings */ + usleep_range(100, 110); + tasha->resmgr->sido_input_src = SIDO_SOURCE_RCO_BG; +} + +static void tasha_cdc_sido_ccl_enable(struct tasha_priv *tasha, bool ccl_flag) +{ + struct snd_soc_component *component = tasha->component; + + if (!component) + return; + + if (!TASHA_IS_2_0(tasha->wcd9xxx)) { + dev_dbg(component->dev, "%s: tasha version < 2p0, return\n", + __func__); + return; + } + dev_dbg(component->dev, "%s: sido_ccl_cnt=%d, ccl_flag:%d\n", + __func__, tasha->sido_ccl_cnt, ccl_flag); + if (ccl_flag) { + if (++tasha->sido_ccl_cnt == 1) + snd_soc_component_update_bits(component, + WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x6E); + } else { + if (tasha->sido_ccl_cnt == 0) { + dev_dbg(component->dev, "%s: sido_ccl already disabled\n", + __func__); + return; + } + if (--tasha->sido_ccl_cnt == 0) + snd_soc_component_update_bits(component, + WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x02); + } +} + +static bool tasha_cdc_is_svs_enabled(struct tasha_priv *tasha) +{ + if (TASHA_IS_2_0(tasha->wcd9xxx) && + svs_scaling_enabled) + return true; + + return false; +} + +static int tasha_cdc_req_mclk_enable(struct tasha_priv *tasha, + bool enable) +{ + int ret = 0; + + mutex_lock(&tasha->mclk_lock); + if (enable) { + tasha_cdc_sido_ccl_enable(tasha, true); + ret = clk_prepare_enable(tasha->wcd_ext_clk); + if (ret) { + dev_err(tasha->dev, "%s: ext clk enable failed\n", + __func__); + goto unlock_mutex; + } + /* get BG */ + wcd_resmgr_enable_master_bias(tasha->resmgr); + /* get MCLK */ + wcd_resmgr_enable_clk_block(tasha->resmgr, WCD_CLK_MCLK); + } else { + /* put MCLK */ + wcd_resmgr_disable_clk_block(tasha->resmgr, WCD_CLK_MCLK); + /* put BG */ + wcd_resmgr_disable_master_bias(tasha->resmgr); + clk_disable_unprepare(tasha->wcd_ext_clk); + tasha_cdc_sido_ccl_enable(tasha, false); + } +unlock_mutex: + mutex_unlock(&tasha->mclk_lock); + return ret; +} + +static int tasha_cdc_check_sido_value(enum tasha_sido_voltage req_mv) +{ + if ((req_mv != SIDO_VOLTAGE_SVS_MV) && + (req_mv != SIDO_VOLTAGE_NOMINAL_MV)) + return -EINVAL; + + return 0; +} + +static void tasha_codec_apply_sido_voltage( + struct tasha_priv *tasha, + enum tasha_sido_voltage req_mv) +{ + u32 vout_d_val; + struct snd_soc_component *component = tasha->component; + int ret; + + if (!component) + return; + + if (!tasha_cdc_is_svs_enabled(tasha)) + return; + + if ((sido_buck_svs_voltage != SIDO_VOLTAGE_SVS_MV) && + (sido_buck_svs_voltage != SIDO_VOLTAGE_NOMINAL_MV)) + sido_buck_svs_voltage = SIDO_VOLTAGE_SVS_MV; + + ret = tasha_cdc_check_sido_value(req_mv); + if (ret < 0) { + dev_dbg(component->dev, "%s: requested mv=%d not in range\n", + __func__, req_mv); + return; + } + if (req_mv == tasha->sido_voltage) { + dev_dbg(component->dev, "%s: Already at requested mv=%d\n", + __func__, req_mv); + return; + } + if (req_mv == sido_buck_svs_voltage) { + if (test_bit(AUDIO_NOMINAL, &tasha->status_mask) || + test_bit(CPE_NOMINAL, &tasha->status_mask)) { + dev_dbg(component->dev, + "%s: nominal client running, status_mask=%lu\n", + __func__, tasha->status_mask); + return; + } + } + /* compute the vout_d step value */ + vout_d_val = CALCULATE_VOUT_D(req_mv); + snd_soc_component_write(component, WCD9335_ANA_BUCK_VOUT_D, + vout_d_val & 0xFF); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + 0x80, 0x80); + + /* 1 msec sleep required after SIDO Vout_D voltage change */ + usleep_range(1000, 1100); + tasha->sido_voltage = req_mv; + dev_dbg(component->dev, + "%s: updated SIDO buck Vout_D to %d, vout_d step = %u\n", + __func__, tasha->sido_voltage, vout_d_val); + + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + 0x80, 0x00); +} + +static int tasha_codec_update_sido_voltage( + struct tasha_priv *tasha, + enum tasha_sido_voltage req_mv) +{ + int ret = 0; + + if (!tasha_cdc_is_svs_enabled(tasha)) + return ret; + + mutex_lock(&tasha->sido_lock); + /* enable mclk before setting SIDO voltage */ + ret = tasha_cdc_req_mclk_enable(tasha, true); + if (ret) { + dev_err(tasha->dev, "%s: ext clk enable failed\n", + __func__); + goto err; + } + tasha_codec_apply_sido_voltage(tasha, req_mv); + tasha_cdc_req_mclk_enable(tasha, false); + +err: + mutex_unlock(&tasha->sido_lock); + return ret; +} + +int tasha_enable_efuse_sensing(struct snd_soc_component *component) +{ + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + + tasha_cdc_mclk_enable(component, true, false); + + if (!TASHA_IS_2_0(priv->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, + 0x1E, 0x02); + snd_soc_component_update_bits(component, + WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, + 0x01, 0x01); + /* + * 5ms sleep required after enabling efuse control + * before checking the status. + */ + usleep_range(5000, 5500); + if (!(snd_soc_component_read32( + component, WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & 0x01)) + WARN(1, "%s: Efuse sense is not complete\n", __func__); + + if (TASHA_IS_2_0(priv->wcd9xxx)) { + if (!(snd_soc_component_read32(component, + WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0) & 0x40)) + snd_soc_component_update_bits(component, + WCD9335_HPH_R_ATEST, + 0x04, 0x00); + tasha_enable_sido_buck(component); + } + + tasha_cdc_mclk_enable(component, false, false); + + return 0; +} +EXPORT_SYMBOL(tasha_enable_efuse_sensing); + +void *tasha_get_afe_config(struct snd_soc_component *component, + enum afe_config_type config_type) +{ + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + + switch (config_type) { + case AFE_SLIMBUS_SLAVE_CONFIG: + return &priv->slimbus_slave_cfg; + case AFE_CDC_REGISTERS_CONFIG: + return &tasha_audio_reg_cfg; + case AFE_SLIMBUS_SLAVE_PORT_CONFIG: + return &tasha_slimbus_slave_port_cfg; + case AFE_AANC_VERSION: + return &tasha_cdc_aanc_version; + case AFE_CLIP_BANK_SEL: + return NULL; + case AFE_CDC_CLIP_REGISTERS_CONFIG: + return NULL; + case AFE_CDC_REGISTER_PAGE_CONFIG: + return &tasha_cdc_reg_page_cfg; + default: + dev_err(component->dev, "%s: Unknown config_type 0x%x\n", + __func__, config_type); + return NULL; + } +} +EXPORT_SYMBOL(tasha_get_afe_config); + +/* + * tasha_event_register: Registers a machine driver callback + * function with codec private data for post ADSP sub-system + * restart (SSR). This callback function will be called from + * codec driver once codec comes out of reset after ADSP SSR. + * + * @machine_event_cb: callback function from machine driver + * @component: Codec component instance + * + * Return: none + */ +void tasha_event_register( + int (*machine_event_cb)(struct snd_soc_component *component, + enum wcd9335_codec_event), + struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (tasha) + tasha->machine_codec_event_cb = machine_event_cb; + else + dev_dbg(component->dev, "%s: Invalid tasha_priv data\n", + __func__); +} +EXPORT_SYMBOL(tasha_event_register); + +static int tasha_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + return wcd9xxx_request_irq(core_res, irq, handler, name, data); +} + +static void tasha_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + if (enable) + wcd9xxx_enable_irq(core_res, irq); + else + wcd9xxx_disable_irq(core_res, irq); +} + +static int tasha_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + wcd9xxx_free_irq(core_res, irq, data); + return 0; +} + +static void tasha_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD9335_MBHC_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, WCD9335_MBHC_CTL_1, + 0x80, 0x00); +} + +static int tasha_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read32( + component, WCD9335_ANA_MBHC_RESULT_3) & 0x7; +} + +static void tasha_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_ELECT, + 0x01, 0x00); +} + +static void tasha_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; + } + /* + * Tasha just needs one set of thresholds for button detection + * due to micbias voltage ramp to pullup upon button press. So + * btn_low and is_micbias are ignored and always program button + * thresholds using btn_high. + */ + for (i = 0; i < num_btn; i++) { + vth = ((btn_high[i] * 2) / 25) & 0x3F; + snd_soc_component_update_bits( + component, WCD9335_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 tasha_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + struct snd_soc_component *component = mbhc->component; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + if (lock) + return wcd9xxx_lock_sleep(core_res); + else { + wcd9xxx_unlock_sleep(core_res); + return 0; + } +} + +static int tasha_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct snd_soc_component *component = mbhc->component; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (enable) + return blocking_notifier_chain_register(&tasha->notifier, + nblock); + else + return blocking_notifier_chain_unregister(&tasha->notifier, + nblock); +} + +static bool tasha_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + u8 val; + + if (micb_num == MIC_BIAS_2) { + val = (snd_soc_component_read32( + mbhc->component, WCD9335_ANA_MICB2) >> 6); + if (val == 0x01) + return true; + } + return false; +} + +static bool tasha_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + return (snd_soc_component_read32(component, WCD9335_ANA_HPH) & 0xC0) ? + true : false; +} + +static void tasha_mbhc_hph_l_pull_up_control( + struct snd_soc_component *component, + enum mbhc_hs_pullup_iref pull_up_cur) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (!tasha) + return; + + /* Default pull up current to 2uA */ + if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA || + pull_up_cur == I_DEFAULT) + pull_up_cur = I_2P0_UA; + + dev_dbg(component->dev, "%s: HS pull up current:%d\n", + __func__, pull_up_cur); + + if (TASHA_IS_2_0(tasha->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD9335_MBHC_PLUG_DETECT_CTL, + 0xC0, pull_up_cur << 6); + else + snd_soc_component_update_bits(component, + WCD9335_MBHC_PLUG_DETECT_CTL, + 0xC0, 0x40); +} + +static int tasha_enable_ext_mb_source(struct wcd_mbhc *mbhc, + bool turn_on) +{ + struct snd_soc_component *component = mbhc->component; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int ret = 0; + struct on_demand_supply *supply; + + if (!tasha) + return -EINVAL; + + supply = &tasha->on_demand_list[ON_DEMAND_MICBIAS]; + if (!supply->supply) { + dev_dbg(component->dev, "%s: warning supply not present ond for %s\n", + __func__, "onDemand Micbias"); + return ret; + } + + dev_dbg(component->dev, "%s turn_on: %d count: %d\n", __func__, turn_on, + supply->ondemand_supply_count); + + if (turn_on) { + if (!(supply->ondemand_supply_count)) { + ret = snd_soc_dapm_force_enable_pin( + snd_soc_component_get_dapm(component), + "MICBIAS_REGULATOR"); + snd_soc_dapm_sync( + snd_soc_component_get_dapm(component)); + } + supply->ondemand_supply_count++; + } else { + if (supply->ondemand_supply_count > 0) + supply->ondemand_supply_count--; + if (!(supply->ondemand_supply_count)) { + ret = snd_soc_dapm_disable_pin( + snd_soc_component_get_dapm(component), + "MICBIAS_REGULATOR"); + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + } + } + + if (ret) + dev_err(component->dev, "%s: Failed to %s external micbias source\n", + __func__, turn_on ? "enable" : "disabled"); + else + dev_dbg(component->dev, "%s: %s external micbias source\n", + __func__, turn_on ? "Enabled" : "Disabled"); + + return ret; +} + +static int tasha_micbias_control(struct snd_soc_component *component, + int micb_num, + int req, bool is_dapm) +{ + struct tasha_priv *tasha = 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 > TASHA_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 = WCD9335_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD9335_ANA_MICB2; + pre_off_event = WCD_EVENT_PRE_MICBIAS_2_OFF; + post_off_event = WCD_EVENT_POST_MICBIAS_2_OFF; + post_on_event = WCD_EVENT_POST_MICBIAS_2_ON; + post_dapm_on = WCD_EVENT_POST_DAPM_MICBIAS_2_ON; + post_dapm_off = WCD_EVENT_POST_DAPM_MICBIAS_2_OFF; + break; + case MIC_BIAS_3: + micb_reg = WCD9335_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD9335_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + mutex_lock(&tasha->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + tasha->pullup_ref[micb_index]++; + if ((tasha->pullup_ref[micb_index] == 1) && + (tasha->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + if (tasha->pullup_ref[micb_index] > 0) + tasha->pullup_ref[micb_index]--; + if ((tasha->pullup_ref[micb_index] == 0) && + (tasha->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + tasha->micb_ref[micb_index]++; + if (tasha->micb_ref[micb_index] == 1) { + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x40); + if (post_on_event) + blocking_notifier_call_chain(&tasha->notifier, + post_on_event, &tasha->mbhc); + } + if (is_dapm && post_dapm_on) + blocking_notifier_call_chain(&tasha->notifier, + post_dapm_on, &tasha->mbhc); + break; + case MICB_DISABLE: + if (tasha->micb_ref[micb_index] > 0) + tasha->micb_ref[micb_index]--; + if ((tasha->micb_ref[micb_index] == 0) && + (tasha->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((tasha->micb_ref[micb_index] == 0) && + (tasha->pullup_ref[micb_index] == 0)) { + if (pre_off_event) + blocking_notifier_call_chain(&tasha->notifier, + pre_off_event, &tasha->mbhc); + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + if (post_off_event) + blocking_notifier_call_chain(&tasha->notifier, + post_off_event, &tasha->mbhc); + } + if (is_dapm && post_dapm_off) + blocking_notifier_call_chain(&tasha->notifier, + post_dapm_off, &tasha->mbhc); + break; + }; + + dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, tasha->micb_ref[micb_index], + tasha->pullup_ref[micb_index]); + + mutex_unlock(&tasha->micb_lock); + + return 0; +} + +static int tasha_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + int ret; + + /* + * If micbias is requested, make sure that there + * is vote to enable mclk + */ + if (req == MICB_ENABLE) + tasha_cdc_mclk_enable(component, true, false); + + ret = tasha_micbias_control(component, micb_num, req, false); + + /* + * Release vote for mclk while requesting for + * micbias disable + */ + if (req == MICB_DISABLE) + tasha_cdc_mclk_enable(component, false, false); + + return ret; +} + +static void tasha_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD9335_ANA_MICB2_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, WCD9335_ANA_MICB2_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, WCD9335_ANA_MICB2_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD9335_ANA_MICB2_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *tasha_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct tasha_priv *tasha; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + if (!component) { + pr_err("%s: NULL component pointer\n", __func__); + return NULL; + } + tasha = snd_soc_component_get_drvdata(component); + hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, type); + if (!hwdep_cal) + dev_err(component->dev, "%s: cal not sent by %d\n", + __func__, type); + + return hwdep_cal; +} + +static int tasha_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, + int micb_num) +{ + int cur_vout_ctl, req_vout_ctl; + int micb_reg, micb_val, micb_en; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD9335_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD9335_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD9335_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD9335_ANA_MICB4; + break; + default: + return -EINVAL; + } + + /* + * If requested micbias voltage is same as current micbias + * voltage, then just return. Otherwise, adjust voltage as + * per requested value. If micbias is already enabled, then + * to avoid slow micbias ramp-up or down enable pull-up + * momentarily, change the micbias value and then re-enable + * micbias. + */ + micb_val = snd_soc_component_read32(component, micb_reg); + micb_en = (micb_val & 0xC0) >> 6; + cur_vout_ctl = micb_val & 0x3F; + + req_vout_ctl = wcd9335_get_micb_vout_ctl_val(req_volt); + if (req_vout_ctl < 0) + return -EINVAL; + if (cur_vout_ctl == req_vout_ctl) + return 0; + + dev_dbg(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); + } + + return 0; +} + +static int tasha_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); + int rc, micb_mv; + + if (micb_num != MIC_BIAS_2) + return -EINVAL; + + /* + * If device tree micbias level is already above the minimum + * voltage needed to detect threshold microphone, then do + * not change the micbias, just return. + */ + if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) + return 0; + + micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv; + + mutex_lock(&tasha->micb_lock); + rc = tasha_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + mutex_unlock(&tasha->micb_lock); + + return rc; +} + +static inline void tasha_mbhc_get_result_params(struct wcd9xxx *wcd9xxx, + s16 *d1_a, u16 noff, + int32_t *zdet) +{ + int i; + int val, val1; + s16 c1; + s32 x1, d1; + int32_t denom; + int minCode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 + }; + + regmap_update_bits(wcd9xxx->regmap, WCD9335_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < TASHA_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd9xxx->regmap, WCD9335_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd9xxx->regmap, WCD9335_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(wcd9xxx->regmap, WCD9335_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = TASHA_MBHC_GET_X1(val); + c1 = TASHA_MBHC_GET_C1(val); + /* If ramp is not complete, give additional 5ms */ + if ((c1 < 2) && x1) + usleep_range(5000, 5050); + + if (!c1 || !x1) { + dev_dbg(wcd9xxx->dev, + "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", + __func__, c1, x1); + goto ramp_down; + } + d1 = d1_a[c1]; + denom = (x1 * d1) - (1 << (14 - noff)); + if (denom > 0) + *zdet = (TASHA_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = TASHA_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(wcd9xxx->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + while (x1) { + regmap_bulk_read(wcd9xxx->regmap, + WCD9335_ANA_MBHC_RESULT_1, (u8 *)&val, 2); + x1 = TASHA_MBHC_GET_X1(val); + i++; + if (i == TASHA_ZDET_NUM_MEASUREMENTS) + break; + } +} + +/* + * tasha_mbhc_zdet_gpio_ctrl: Register callback function for + * controlling the switch on hifi amps. Default switch state + * will put a 51ohm load in parallel to the hph load. So, + * impedance detection function will pull the gpio high + * to make the switch open. + * + * @zdet_gpio_cb: callback function from machine driver + * @component: Codec instance + * + * Return: none + */ +void tasha_mbhc_zdet_gpio_ctrl( + int (*zdet_gpio_cb)( + struct snd_soc_component *component, bool high), + struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + tasha->zdet_gpio_cb = zdet_gpio_cb; +} +EXPORT_SYMBOL(tasha_mbhc_zdet_gpio_ctrl); + +static void tasha_mbhc_zdet_ramp(struct snd_soc_component *component, + struct tasha_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + int32_t zdet = 0; + + snd_soc_component_update_bits(component, WCD9335_MBHC_ZDET_ANA_CTL, + 0x70, zdet_param->ldo_ctl << 4); + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_BTN5, 0xFC, + zdet_param->btn5); + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_BTN6, 0xFC, + zdet_param->btn6); + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_BTN7, 0xFC, + zdet_param->btn7); + snd_soc_component_update_bits(component, WCD9335_MBHC_ZDET_ANA_CTL, + 0x0F, zdet_param->noff); + snd_soc_component_update_bits(component, WCD9335_MBHC_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_ZDET, 0x80, 0x80); + dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + tasha_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_ZDET, 0x40, 0x40); + dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + tasha_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void tasha_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) +{ + s16 q1; + int q1_cal; + + if (*z_val < (TASHA_ZDET_VAL_400/1000)) + q1 = snd_soc_component_read32(component, + WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read32(component, + WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 + (2 * flag_l_r)); + if (q1 & 0x80) + q1_cal = (10000 - ((q1 & 0x7F) * 25)); + else + q1_cal = (10000 + (q1 * 25)); + if (q1_cal > 0) + *z_val = ((*z_val) * 10000) / q1_cal; +} + +static void tasha_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + s16 reg0, reg1, reg2, reg3, reg4; + int32_t z1L, z1R, z1Ls; + int zMono, z_diff1, z_diff2; + bool is_fsm_disable = false; + bool is_change = false; + struct tasha_mbhc_zdet_param zdet_param[] = { + {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */ + {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ + {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */ + {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */ + }; + struct tasha_mbhc_zdet_param *zdet_param_ptr = NULL; + s16 d1_a[][4] = { + {0, 30, 90, 30}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + }; + s16 *d1 = NULL; + + if (!TASHA_IS_2_0(wcd9xxx)) { + dev_dbg(component->dev, "%s: Z-det is not supported for this codec version\n", + __func__); + *zl = 0; + *zr = 0; + return; + } + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + if (tasha->zdet_gpio_cb) + is_change = tasha->zdet_gpio_cb(component, true); + + reg0 = snd_soc_component_read32(component, WCD9335_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read32(component, WCD9335_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read32(component, WCD9335_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read32(component, WCD9335_MBHC_CTL_1); + reg4 = snd_soc_component_read32(component, WCD9335_MBHC_ZDET_ANA_CTL); + + if (snd_soc_component_read32( + component, WCD9335_ANA_MBHC_ELECT) & 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_MECH, 0x80, 0x00); + + /* Enable AZ */ + snd_soc_component_update_bits(component, WCD9335_MBHC_CTL_1, + 0x0C, 0x04); + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_MECH, 0x01, 0x00); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + tasha_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + + if (!TASHA_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) + goto left_ch_impedance; + + /* second ramp for left ch */ + if (z1L < TASHA_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1L > TASHA_ZDET_VAL_400) && (z1L <= TASHA_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1L > TASHA_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + tasha_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + +left_ch_impedance: + if ((z1L == TASHA_ZDET_FLOATING_IMPEDANCE) || + (z1L > TASHA_ZDET_VAL_100K)) { + *zl = TASHA_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1L/1000; + tasha_wcd_mbhc_qfuse_cal(component, zl, 0); + } + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", + __func__, *zl); + + /* start of right impedance ramp and calculation */ + tasha_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if (TASHA_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { + if (((z1R > TASHA_ZDET_VAL_1200) && + (zdet_param_ptr->noff == 0x6)) || + ((*zl) != TASHA_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* second ramp for right ch */ + if (z1R < TASHA_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1R > TASHA_ZDET_VAL_400) && + (z1R <= TASHA_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1R > TASHA_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + tasha_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + } +right_ch_impedance: + if ((z1R == TASHA_ZDET_FLOATING_IMPEDANCE) || + (z1R > TASHA_ZDET_VAL_100K)) { + *zr = TASHA_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R/1000; + tasha_wcd_mbhc_qfuse_cal(component, zr, 1); + } + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", + __func__, *zr); + + /* mono/stereo detection */ + if ((*zl == TASHA_ZDET_FLOATING_IMPEDANCE) && + (*zr == TASHA_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == TASHA_ZDET_FLOATING_IMPEDANCE) || + (*zr == TASHA_ZDET_FLOATING_IMPEDANCE) || + ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) || + ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) { + dev_dbg(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, WCD9335_HPH_R_ATEST, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, + 0x40, 0x01); + if (*zl < (TASHA_ZDET_VAL_32/1000)) + tasha_mbhc_zdet_ramp(component, &zdet_param[0], + &z1Ls, NULL, d1); + else + tasha_mbhc_zdet_ramp(component, &zdet_param[1], + &z1Ls, NULL, d1); + snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD9335_HPH_R_ATEST, + 0x02, 0x00); + z1Ls /= 1000; + tasha_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, WCD9335_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD9335_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD9335_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD9335_MBHC_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD9335_MBHC_CTL_1, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd9xxx->regmap, + WCD9335_ANA_MBHC_ELECT, 0x80, 0x80); + if (tasha->zdet_gpio_cb && is_change) + tasha->zdet_gpio_cb(component, false); +} + +static void tasha_mbhc_gnd_det_ctrl( + struct snd_soc_component *component, bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_MECH, + 0x02, 0x00); + } +} + +static void tasha_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (enable) { + snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, + 0x40, 0x40); + if (TASHA_IS_2_0(tasha->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, + 0x10, 0x10); + } else { + snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, + 0x40, 0x00); + if (TASHA_IS_2_0(tasha->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, + 0x10, 0x00); + } +} + +static void tasha_mbhc_moisture_config(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + + if (mbhc->moist_vref == V_OFF) + return; + + /* Donot enable moisture detection if jack type is NC */ + if (!mbhc->hphl_swh) { + dev_dbg(component->dev, "%s: disable moisture detection for NC\n", + __func__); + return; + } + + snd_soc_component_update_bits(component, WCD9335_MBHC_CTL_2, + 0x0C, mbhc->moist_vref << 2); + tasha_mbhc_hph_l_pull_up_control(component, mbhc->moist_iref); +} + +static void tasha_update_anc_state(struct snd_soc_component *component, + bool enable, int anc_num) +{ + if (enable) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_CFG0 + (20 * anc_num), + 0x10, 0x10); + else + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_CFG0 + (20 * anc_num), + 0x10, 0x00); +} + +static bool tasha_is_anc_on(struct wcd_mbhc *mbhc) +{ + bool anc_on = false; + u16 ancl, ancr; + + ancl = + (snd_soc_component_read32( + mbhc->component, WCD9335_CDC_RX1_RX_PATH_CFG0)) & 0x10; + ancr = + (snd_soc_component_read32( + mbhc->component, WCD9335_CDC_RX2_RX_PATH_CFG0)) & 0x10; + + anc_on = !!(ancl | ancr); + + return anc_on; +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = tasha_mbhc_request_irq, + .irq_control = tasha_mbhc_irq_control, + .free_irq = tasha_mbhc_free_irq, + .clk_setup = tasha_mbhc_clk_setup, + .map_btn_code_to_num = tasha_mbhc_btn_to_num, + .enable_mb_source = tasha_enable_ext_mb_source, + .mbhc_bias = tasha_mbhc_mbhc_bias_control, + .set_btn_thr = tasha_mbhc_program_btn_thr, + .lock_sleep = tasha_mbhc_lock_sleep, + .register_notifier = tasha_mbhc_register_notifier, + .micbias_enable_status = tasha_mbhc_micb_en_status, + .hph_pa_on_status = tasha_mbhc_hph_pa_on_status, + .hph_pull_up_control = tasha_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = tasha_mbhc_request_micbias, + .mbhc_micb_ramp_control = tasha_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = tasha_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = tasha_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = tasha_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = tasha_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = tasha_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = tasha_mbhc_moisture_config, + .update_anc_state = tasha_update_anc_state, + .is_anc_on = tasha_is_anc_on, +}; + +static int tasha_get_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tasha->anc_slot; + return 0; +} + +static int tasha_put_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + tasha->anc_slot = ucontrol->value.integer.value[0]; + return 0; +} + +static int tasha_get_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (tasha->anc_func == true ? 1 : 0); + return 0; +} + +static int tasha_put_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + + mutex_lock(&tasha->codec_mutex); + tasha->anc_func = (!ucontrol->value.integer.value[0] ? false : true); + + dev_dbg(component->dev, "%s: anc_func %x", __func__, tasha->anc_func); + + if (tasha->anc_func == true) { + snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT2 PA"); + snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT2"); + snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT1 PA"); + snd_soc_dapm_enable_pin(dapm, "ANC LINEOUT1"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_enable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_enable_pin(dapm, "ANC EAR"); + snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA"); + snd_soc_dapm_disable_pin(dapm, "LINEOUT2"); + snd_soc_dapm_disable_pin(dapm, "LINEOUT2 PA"); + snd_soc_dapm_disable_pin(dapm, "LINEOUT1"); + snd_soc_dapm_disable_pin(dapm, "LINEOUT1 PA"); + snd_soc_dapm_disable_pin(dapm, "HPHR"); + snd_soc_dapm_disable_pin(dapm, "HPHL"); + snd_soc_dapm_disable_pin(dapm, "HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "EAR PA"); + snd_soc_dapm_disable_pin(dapm, "EAR"); + } else { + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2 PA"); + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2"); + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1 PA"); + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR"); + snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA"); + snd_soc_dapm_enable_pin(dapm, "LINEOUT2"); + snd_soc_dapm_enable_pin(dapm, "LINEOUT2 PA"); + snd_soc_dapm_enable_pin(dapm, "LINEOUT1"); + snd_soc_dapm_enable_pin(dapm, "LINEOUT1 PA"); + snd_soc_dapm_enable_pin(dapm, "HPHR"); + snd_soc_dapm_enable_pin(dapm, "HPHL"); + snd_soc_dapm_enable_pin(dapm, "HPHR PA"); + snd_soc_dapm_enable_pin(dapm, "HPHL PA"); + snd_soc_dapm_enable_pin(dapm, "EAR PA"); + snd_soc_dapm_enable_pin(dapm, "EAR"); + } + mutex_unlock(&tasha->codec_mutex); + snd_soc_dapm_sync(dapm); + return 0; +} + +static int tasha_get_clkmode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = tasha->clk_mode; + dev_dbg(component->dev, "%s: clk_mode: %d\n", __func__, + tasha->clk_mode); + + return 0; +} + +static int tasha_put_clkmode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + tasha->clk_mode = ucontrol->value.enumerated.item[0]; + dev_dbg(component->dev, "%s: clk_mode: %d\n", __func__, + tasha->clk_mode); + + return 0; +} + +static int tasha_get_iir_enable_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + /* IIR filter band registers are at integer multiples of 16 */ + u16 iir_reg = WCD9335_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx; + + ucontrol->value.integer.value[0] = ( + snd_soc_component_read32(component, iir_reg) & + (1 << band_idx)) != 0; + + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0]); + return 0; +} + +static int tasha_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t zl, zr; + bool hphr; + struct soc_multi_mixer_control *mc; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + + mc = (struct soc_multi_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + wcd_mbhc_get_impedance(&priv->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 impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + tasha_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + tasha_hph_impedance_get, NULL), +}; + +static int tasha_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + struct wcd_mbhc *mbhc; + + if (!priv) { + dev_dbg(component->dev, "%s: wcd9335 private data is NULL\n", + __func__); + return 0; + } + + mbhc = &priv->mbhc; + if (!mbhc) { + dev_dbg(component->dev, "%s: mbhc not initialized\n", __func__); + return 0; + } + + 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 const struct snd_kcontrol_new hph_type_detect_controls[] = { + SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, + tasha_get_hph_type, NULL), +}; + +static int tasha_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tasha_p->vi_feed_value; + + return 0; +} + +static int tasha_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx *core = tasha_p->wcd9xxx; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 port_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n", + __func__, enable, port_id, dai_id); + + tasha_p->vi_feed_value = ucontrol->value.integer.value[0]; + + mutex_lock(&tasha_p->codec_mutex); + if (enable) { + if (port_id == TASHA_TX14 && !test_bit(VI_SENSE_1, + &tasha_p->status_mask)) { + list_add_tail(&core->tx_chs[TASHA_TX14].list, + &tasha_p->dai[dai_id].wcd9xxx_ch_list); + set_bit(VI_SENSE_1, &tasha_p->status_mask); + } + if (port_id == TASHA_TX15 && !test_bit(VI_SENSE_2, + &tasha_p->status_mask)) { + list_add_tail(&core->tx_chs[TASHA_TX15].list, + &tasha_p->dai[dai_id].wcd9xxx_ch_list); + set_bit(VI_SENSE_2, &tasha_p->status_mask); + } + } else { + if (port_id == TASHA_TX14 && test_bit(VI_SENSE_1, + &tasha_p->status_mask)) { + list_del_init(&core->tx_chs[TASHA_TX14].list); + clear_bit(VI_SENSE_1, &tasha_p->status_mask); + } + if (port_id == TASHA_TX15 && test_bit(VI_SENSE_2, + &tasha_p->status_mask)) { + list_del_init(&core->tx_chs[TASHA_TX15].list); + clear_bit(VI_SENSE_2, &tasha_p->status_mask); + } + } + mutex_unlock(&tasha_p->codec_mutex); + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +/* virtual port entries */ +static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tasha_p->tx_port_value; + return 0; +} + +static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx *core = dev_get_drvdata(component->dev->parent); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 port_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + u32 vtable; + + + dev_dbg(component->dev, "%s: wname %s cname %s value %u shift %d item %ld\n", + __func__, + widget->name, ucontrol->id.name, tasha_p->tx_port_value, + widget->shift, ucontrol->value.integer.value[0]); + + mutex_lock(&tasha_p->codec_mutex); + + if (tasha_p->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + if (dai_id != AIF1_CAP) { + dev_err(component->dev, "%s: invalid AIF for I2C mode\n", + __func__); + mutex_unlock(&tasha_p->codec_mutex); + return -EINVAL; + } + vtable = vport_slim_check_table[dai_id]; + } else { + if (dai_id >= ARRAY_SIZE(vport_i2s_check_table)) { + dev_err(component->dev, "%s: dai_id: %d, out of bounds\n", + __func__, dai_id); + return -EINVAL; + } + vtable = vport_i2s_check_table[dai_id]; + } + switch (dai_id) { + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + /* only add to the list if value not set */ + if (enable && !(tasha_p->tx_port_value & 1 << port_id)) { + + if (wcd9xxx_tx_vport_validation(vtable, port_id, + tasha_p->dai, NUM_CODEC_DAIS)) { + dev_dbg(component->dev, "%s: TX%u is used by other virtual port\n", + __func__, port_id); + mutex_unlock(&tasha_p->codec_mutex); + return 0; + } + tasha_p->tx_port_value |= 1 << port_id; + list_add_tail(&core->tx_chs[port_id].list, + &tasha_p->dai[dai_id].wcd9xxx_ch_list + ); + } else if (!enable && (tasha_p->tx_port_value & + 1 << port_id)) { + tasha_p->tx_port_value &= ~(1 << port_id); + list_del_init(&core->tx_chs[port_id].list); + } else { + if (enable) + dev_dbg(component->dev, "%s: TX%u port is used by\n" + "this virtual port\n", + __func__, port_id); + else + dev_dbg(component->dev, "%s: TX%u port is not used by\n" + "this virtual port\n", + __func__, port_id); + /* avoid update power function */ + mutex_unlock(&tasha_p->codec_mutex); + return 0; + } + break; + case AIF4_MAD_TX: + case AIF5_CPE_TX: + break; + default: + pr_err("Unknown AIF %d\n", dai_id); + mutex_unlock(&tasha_p->codec_mutex); + return -EINVAL; + } + pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__, + widget->name, widget->sname, tasha_p->tx_port_value, + widget->shift); + + mutex_unlock(&tasha_p->codec_mutex); + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static int slim_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = + tasha_p->rx_port_value[widget->shift]; + return 0; +} + +static const char *const slim_rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", "AIF_MIX1_PB" +}; + +static int slim_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx *core = dev_get_drvdata(component->dev->parent); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + unsigned int rx_port_value; + u32 port_id = widget->shift; + + tasha_p->rx_port_value[port_id] = ucontrol->value.enumerated.item[0]; + rx_port_value = tasha_p->rx_port_value[port_id]; + + pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__, + widget->name, ucontrol->id.name, rx_port_value, + widget->shift, ucontrol->value.integer.value[0]); + + mutex_lock(&tasha_p->codec_mutex); + + if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + if (rx_port_value > 2) { + dev_err(component->dev, "%s: invalid AIF for I2C mode\n", + __func__); + goto err; + } + } + /* value need to match the Virtual port and AIF number */ + switch (rx_port_value) { + case 0: + list_del_init(&core->rx_chs[port_id].list); + break; + case 1: + if (wcd9xxx_rx_vport_validation(port_id + + TASHA_RX_PORT_START_NUMBER, + &tasha_p->dai[AIF1_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tasha_p->dai[AIF1_PB].wcd9xxx_ch_list); + break; + case 2: + if (wcd9xxx_rx_vport_validation(port_id + + TASHA_RX_PORT_START_NUMBER, + &tasha_p->dai[AIF2_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tasha_p->dai[AIF2_PB].wcd9xxx_ch_list); + break; + case 3: + if (wcd9xxx_rx_vport_validation(port_id + + TASHA_RX_PORT_START_NUMBER, + &tasha_p->dai[AIF3_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tasha_p->dai[AIF3_PB].wcd9xxx_ch_list); + break; + case 4: + if (wcd9xxx_rx_vport_validation(port_id + + TASHA_RX_PORT_START_NUMBER, + &tasha_p->dai[AIF4_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tasha_p->dai[AIF4_PB].wcd9xxx_ch_list); + break; + case 5: + if (wcd9xxx_rx_vport_validation(port_id + + TASHA_RX_PORT_START_NUMBER, + &tasha_p->dai[AIF_MIX1_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tasha_p->dai[AIF_MIX1_PB].wcd9xxx_ch_list); + break; + default: + pr_err("Unknown AIF %d\n", rx_port_value); + goto err; + } +rtn: + mutex_unlock(&tasha_p->codec_mutex); + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + + return 0; +err: + mutex_unlock(&tasha_p->codec_mutex); + return -EINVAL; +} + +static const struct soc_enum slim_rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text); + +static const struct snd_kcontrol_new slim_rx_mux[TASHA_RX_MAX] = { + SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), +}; + +static const struct snd_kcontrol_new aif4_vi_mixer[] = { + SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, TASHA_TX14, 1, 0, + tasha_vi_feed_mixer_get, tasha_vi_feed_mixer_put), + SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, TASHA_TX15, 1, 0, + tasha_vi_feed_mixer_get, tasha_vi_feed_mixer_put), +}; + +static const struct snd_kcontrol_new aif1_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, TASHA_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TASHA_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TASHA_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TASHA_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TASHA_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TASHA_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TASHA_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TASHA_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TASHA_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TASHA_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TASHA_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, TASHA_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif2_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, TASHA_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TASHA_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TASHA_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TASHA_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TASHA_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TASHA_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TASHA_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TASHA_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TASHA_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TASHA_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TASHA_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, TASHA_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif3_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, TASHA_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TASHA_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TASHA_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TASHA_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TASHA_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TASHA_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TASHA_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TASHA_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TASHA_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TASHA_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TASHA_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, TASHA_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif4_mad_mixer[] = { + SOC_SINGLE_EXT("SLIM TX12", SND_SOC_NOPM, TASHA_TX12, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, TASHA_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, 0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + +}; + +static const struct snd_kcontrol_new rx_int1_spline_mix_switch[] = { + SOC_DAPM_SINGLE("HPHL Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int2_spline_mix_switch[] = { + SOC_DAPM_SINGLE("HPHR Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int3_spline_mix_switch[] = { + SOC_DAPM_SINGLE("LO1 Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int4_spline_mix_switch[] = { + SOC_DAPM_SINGLE("LO2 Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int5_spline_mix_switch[] = { + SOC_DAPM_SINGLE("LO3 Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int6_spline_mix_switch[] = { + SOC_DAPM_SINGLE("LO4 Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int7_spline_mix_switch[] = { + SOC_DAPM_SINGLE("SPKRL Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int8_spline_mix_switch[] = { + SOC_DAPM_SINGLE("SPKRR Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int5_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("LO3 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int6_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("LO4 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int7_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("SPKRL VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_int8_vbat_mix_switch[] = { + SOC_DAPM_SINGLE("SPKRR VBAT Enable", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new cpe_in_mix_switch[] = { + SOC_DAPM_SINGLE("MAD_BYPASS", SND_SOC_NOPM, 0, 1, 0) +}; + + + +static int tasha_put_iir_enable_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + bool iir_band_en_status; + int value = ucontrol->value.integer.value[0]; + u16 iir_reg = WCD9335_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx; + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_component_update_bits(component, iir_reg, (1 << band_idx), + (value << band_idx)); + + iir_band_en_status = ((snd_soc_component_read32(component, iir_reg) & + (1 << band_idx)) != 0); + pr_debug("%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, iir_band_en_status); + return 0; +} + +static uint32_t get_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + int coeff_idx) +{ + uint32_t value = 0; + + /* Address does not automatically update if reading */ + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_component_read32(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx)); + + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_component_read32(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) << 8); + + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_component_read32(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) << 16); + + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_component_read32(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) & 0x3F) << 24); + + return value; +} + +static int tasha_get_iir_band_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = + get_iir_band_coeff(component, iir_idx, band_idx, 0); + ucontrol->value.integer.value[1] = + get_iir_band_coeff(component, iir_idx, band_idx, 1); + ucontrol->value.integer.value[2] = + get_iir_band_coeff(component, iir_idx, band_idx, 2); + ucontrol->value.integer.value[3] = + get_iir_band_coeff(component, iir_idx, band_idx, 3); + ucontrol->value.integer.value[4] = + get_iir_band_coeff(component, iir_idx, band_idx, 4); + + pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[1], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[2], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[3], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[4]); + return 0; +} + +static void set_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + uint32_t value) +{ + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value & 0xFF)); + + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 8) & 0xFF); + + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 24) & 0x3F); +} + +static void tasha_codec_enable_int_port(struct wcd9xxx_codec_dai_data *dai, + struct snd_soc_component *component) +{ + struct wcd9xxx_ch *ch; + int port_num = 0; + unsigned short reg = 0; + u8 val = 0; + struct tasha_priv *tasha_p; + + if (!dai || !component) { + pr_err("%s: Invalid params\n", __func__); + return; + } + + tasha_p = snd_soc_component_get_drvdata(component); + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + if (ch->port >= TASHA_RX_PORT_START_NUMBER) { + port_num = ch->port - TASHA_RX_PORT_START_NUMBER; + reg = TASHA_SLIM_PGD_PORT_INT_EN0 + (port_num / 8); + val = wcd9xxx_interface_reg_read(tasha_p->wcd9xxx, + reg); + if (!(val & BYTE_BIT_MASK(port_num))) { + val |= BYTE_BIT_MASK(port_num); + wcd9xxx_interface_reg_write( + tasha_p->wcd9xxx, reg, val); + val = wcd9xxx_interface_reg_read( + tasha_p->wcd9xxx, reg); + } + } else { + port_num = ch->port; + reg = TASHA_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8); + val = wcd9xxx_interface_reg_read(tasha_p->wcd9xxx, + reg); + if (!(val & BYTE_BIT_MASK(port_num))) { + val |= BYTE_BIT_MASK(port_num); + wcd9xxx_interface_reg_write(tasha_p->wcd9xxx, + reg, val); + val = wcd9xxx_interface_reg_read( + tasha_p->wcd9xxx, reg); + } + } + } +} + +static int tasha_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai, + bool up) +{ + int ret = 0; + struct wcd9xxx_ch *ch; + + if (up) { + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + ret = wcd9xxx_get_slave_port(ch->ch_num); + if (ret < 0) { + pr_err("%s: Invalid slave port ID: %d\n", + __func__, ret); + ret = -EINVAL; + } else { + set_bit(ret, &dai->ch_mask); + } + } + } else { + ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0), + msecs_to_jiffies( + TASHA_SLIM_CLOSE_TIMEOUT)); + if (!ret) { + pr_err("%s: Slim close tx/rx wait timeout, ch_mask:0x%lx\n", + __func__, dai->ch_mask); + ret = -ETIMEDOUT; + } else { + ret = 0; + } + } + return ret; +} + +static int tasha_codec_enable_slimrx(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct wcd9xxx *core; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + int ret = 0; + struct wcd9xxx_codec_dai_data *dai; + + core = dev_get_drvdata(component->dev->parent); + + dev_dbg(component->dev, "%s: event called! component name %s num_dai %d\n" + "stream name %s event %d\n", + __func__, component->name, + component->num_dai, w->sname, event); + + /* Execute the callback only if interface type is slimbus */ + if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) + return 0; + + dai = &tasha_p->dai[w->shift]; + dev_dbg(component->dev, "%s: w->name %s w->shift %d event %d\n", + __func__, w->name, w->shift, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dai->bus_down_in_recovery = false; + tasha_codec_enable_int_port(dai, component); + (void) tasha_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_PRE_PMD: + tasha_codec_vote_max_bw(component, true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_disconnect_port(core, &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(component->dev, "%s: Disconnect RX port, ret = %d\n", + __func__, ret); + + if (!dai->bus_down_in_recovery) + ret = tasha_codec_enable_slim_chmask(dai, false); + else + dev_dbg(component->dev, + "%s: bus in recovery skip enable slim_chmask", + __func__); + ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list, + dai->grph); + break; + } + return ret; +} + +static int tasha_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct wcd9xxx *core = NULL; + struct snd_soc_component *component = NULL; + struct tasha_priv *tasha_p = NULL; + int ret = 0; + struct wcd9xxx_codec_dai_data *dai = NULL; + + if (!w) { + pr_err("%s invalid params\n", __func__); + return -EINVAL; + } + component = snd_soc_dapm_to_component(w->dapm); + tasha_p = snd_soc_component_get_drvdata(component); + core = tasha_p->wcd9xxx; + + dev_dbg(component->dev, "%s: num_dai %d stream name %s\n", + __func__, component->num_dai, w->sname); + + /* Execute the callback only if interface type is slimbus */ + if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + dev_err(component->dev, "%s Interface is not correct", + __func__); + return 0; + } + + dev_dbg(component->dev, "%s(): w->name %s event %d w->shift %d\n", + __func__, w->name, event, w->shift); + if (w->shift != AIF4_VIFEED) { + pr_err("%s Error in enabling the tx path\n", __func__); + ret = -EINVAL; + goto out_vi; + } + dai = &tasha_p->dai[w->shift]; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (test_bit(VI_SENSE_1, &tasha_p->status_mask)) { + dev_dbg(component->dev, "%s: spkr1 enabled\n", + __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + } + if (test_bit(VI_SENSE_2, &tasha_p->status_mask)) { + pr_debug("%s: spkr2 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + } + dai->bus_down_in_recovery = false; + tasha_codec_enable_int_port(dai, component); + (void) tasha_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->grph); + if (ret) + dev_err(component->dev, "%s error in close_slim_sch_tx %d\n", + __func__, ret); + if (!dai->bus_down_in_recovery) + ret = tasha_codec_enable_slim_chmask(dai, false); + if (ret < 0) { + ret = wcd9xxx_disconnect_port(core, + &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(component->dev, "%s: Disconnect TX port, ret = %d\n", + __func__, ret); + } + if (test_bit(VI_SENSE_1, &tasha_p->status_mask)) { + /* Disable V&I sensing */ + dev_dbg(component->dev, "%s: spkr1 disabled\n", + __func__); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + } + if (test_bit(VI_SENSE_2, &tasha_p->status_mask)) { + /* Disable V&I sensing */ + dev_dbg(component->dev, "%s: spkr2 disabled\n", + __func__); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + } + break; + } +out_vi: + return ret; +} + +/* + * __tasha_codec_enable_slimtx: Enable the slimbus slave port + * for TX path + * @component: Handle to the codec for which the slave port is to be + * enabled. + * @dai_data: The dai specific data for dai which is enabled. + */ +static int __tasha_codec_enable_slimtx(struct snd_soc_component *component, + int event, struct wcd9xxx_codec_dai_data *dai) +{ + struct wcd9xxx *core; + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + int ret = 0; + + /* Execute the callback only if interface type is slimbus */ + if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) + return 0; + + dev_dbg(component->dev, + "%s: event = %d\n", __func__, event); + core = dev_get_drvdata(component->dev->parent); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dai->bus_down_in_recovery = false; + tasha_codec_enable_int_port(dai, component); + (void) tasha_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->grph); + if (!dai->bus_down_in_recovery) + ret = tasha_codec_enable_slim_chmask(dai, false); + if (ret < 0) { + ret = wcd9xxx_disconnect_port(core, + &dai->wcd9xxx_ch_list, + dai->grph); + pr_debug("%s: Disconnect TX port, ret = %d\n", + __func__, ret); + } + + break; + } + + return ret; +} + +static int tasha_codec_enable_slimtx(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx_codec_dai_data *dai; + + dev_dbg(component->dev, + "%s: w->name %s, w->shift = %d, num_dai %d stream name %s\n", + __func__, w->name, w->shift, + component->num_dai, w->sname); + + dai = &tasha_p->dai[w->shift]; + return __tasha_codec_enable_slimtx(component, event, dai); +} + +static void tasha_codec_cpe_pp_set_cfg(struct snd_soc_component *component, + int event) +{ + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx_codec_dai_data *dai; + u8 bit_width, rate, buf_period; + + dai = &tasha_p->dai[AIF4_MAD_TX]; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (dai->bit_width) { + case 32: + bit_width = 0xF; + break; + case 24: + bit_width = 0xE; + break; + case 20: + bit_width = 0xD; + break; + case 16: + default: + bit_width = 0x0; + break; + } + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_TX_PP_CFG, 0x0F, bit_width); + + switch (dai->rate) { + case 384000: + rate = 0x30; + break; + case 192000: + rate = 0x20; + break; + case 48000: + rate = 0x10; + break; + case 16000: + default: + rate = 0x00; + break; + } + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_TX_PP_CFG, 0x70, rate); + + buf_period = (dai->rate * (dai->bit_width/8)) / (16*1000); + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD, + 0xFF, buf_period); + dev_dbg(component->dev, "%s: PP buffer period= 0x%x\n", + __func__, buf_period); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write(component, WCD9335_CPE_SS_TX_PP_CFG, + 0x3C); + snd_soc_component_write(component, + WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD, + 0x60); + break; + + default: + break; + } +} + +/* + * tasha_codec_get_mad_port_id: Callback function that will be invoked + * to get the port ID for MAD. + * @component: Handle to the codec + * @port_id: cpe port_id needs to enable + */ +static int tasha_codec_get_mad_port_id(struct snd_soc_component *component, + u16 *port_id) +{ + struct tasha_priv *tasha_p; + struct wcd9xxx_codec_dai_data *dai; + struct wcd9xxx_ch *ch; + + if (!port_id || !component) + return -EINVAL; + + tasha_p = snd_soc_component_get_drvdata(component); + if (!tasha_p) + return -EINVAL; + + dai = &tasha_p->dai[AIF4_MAD_TX]; + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + if (ch->port == TASHA_TX12) + *port_id = WCD_CPE_AFE_OUT_PORT_2; + else if (ch->port == TASHA_TX13) + *port_id = WCD_CPE_AFE_OUT_PORT_4; + else { + dev_err(component->dev, "%s: invalid mad_port = %d\n", + __func__, ch->port); + return -EINVAL; + } + } + dev_dbg(component->dev, "%s: port_id = %d\n", __func__, *port_id); + + return 0; +} + +/* + * tasha_codec_enable_slimtx_mad: Callback function that will be invoked + * to setup the slave port for MAD. + * @component: Handle to the codec + * @event: Indicates whether to enable or disable the slave port + */ +static int tasha_codec_enable_slimtx_mad(struct snd_soc_component *component, + u8 event) +{ + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx_codec_dai_data *dai; + struct wcd9xxx_ch *ch; + int dapm_event = SND_SOC_DAPM_POST_PMU; + u16 port = 0; + int ret = 0; + + dai = &tasha_p->dai[AIF4_MAD_TX]; + + if (event == 0) + dapm_event = SND_SOC_DAPM_POST_PMD; + + dev_dbg(component->dev, + "%s: mad_channel, event = 0x%x\n", + __func__, event); + + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + dev_dbg(component->dev, "%s: mad_port = %d, event = 0x%x\n", + __func__, ch->port, event); + if (ch->port == TASHA_TX13) { + tasha_codec_cpe_pp_set_cfg(component, dapm_event); + port = TASHA_TX13; + break; + } + } + + ret = __tasha_codec_enable_slimtx(component, dapm_event, dai); + + if (port == TASHA_TX13) { + switch (dapm_event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN, + 0x20, 0x00); + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG, + 0x03, 0x02); + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_CFG, + 0x80, 0x80); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN, + 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG, + 0x03, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_CFG, + 0x80, 0x00); + break; + } + } + + return ret; +} + +static int tasha_put_iir_band_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + /* + * Mask top bit it is reserved + * Updates addr automatically for each B2 write + */ + snd_soc_component_write(component, + (WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + set_iir_band_coeff(component, iir_idx, band_idx, + ucontrol->value.integer.value[0]); + set_iir_band_coeff(component, iir_idx, band_idx, + ucontrol->value.integer.value[1]); + set_iir_band_coeff(component, iir_idx, band_idx, + ucontrol->value.integer.value[2]); + set_iir_band_coeff(component, iir_idx, band_idx, + ucontrol->value.integer.value[3]); + set_iir_band_coeff(component, iir_idx, band_idx, + ucontrol->value.integer.value[4]); + + pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 0), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 1), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 2), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 3), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 4)); + return 0; +} + +static int tasha_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tasha->comp_enabled[comp]; + return 0; +} + +static int tasha_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + + pr_debug("%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, tasha->comp_enabled[comp], value); + tasha->comp_enabled[comp] = value; + + /* Any specific register configuration for compander */ + switch (comp) { + case COMPANDER_1: + /* Set Gain Source Select based on compander enable/disable */ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, 0x20, + (value ? 0x00:0x20)); + break; + case COMPANDER_2: + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, 0x20, + (value ? 0x00:0x20)); + break; + case COMPANDER_3: + break; + case COMPANDER_4: + break; + case COMPANDER_5: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO3_GAIN, + 0x20, (value ? 0x00:0x20)); + break; + case COMPANDER_6: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO4_GAIN, + 0x20, (value ? 0x00:0x20)); + break; + case COMPANDER_7: + break; + case COMPANDER_8: + break; + default: + /* + * if compander is not enabled for any interpolator, + * it does not cause any audio failure, so do not + * return error in this case, but just print a log + */ + dev_warn(component->dev, "%s: unknown compander: %d\n", + __func__, comp); + }; + return 0; +} + +static void tasha_codec_init_flyback(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, 0xC0, 0x00); + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, 0xC0, 0x00); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + 0x0F, 0x00); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + 0xF0, 0x00); +} + +static int tasha_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tasha->rx_bias_count++; + if (tasha->rx_bias_count == 1) { + if (TASHA_IS_2_0(tasha->wcd9xxx)) + tasha_codec_init_flyback(component); + snd_soc_component_update_bits(component, + WCD9335_ANA_RX_SUPPLIES, + 0x01, 0x01); + } + break; + case SND_SOC_DAPM_POST_PMD: + tasha->rx_bias_count--; + if (!tasha->rx_bias_count) + snd_soc_component_update_bits(component, + WCD9335_ANA_RX_SUPPLIES, + 0x01, 0x00); + break; + }; + dev_dbg(component->dev, "%s: Current RX BIAS user count: %d\n", + __func__, tasha->rx_bias_count); + + return 0; +} + +static void tasha_realign_anc_coeff(struct snd_soc_component *component, + u16 reg1, u16 reg2) +{ + u8 val1, val2, tmpval1, tmpval2; + + snd_soc_component_write(component, reg1, 0x00); + tmpval1 = snd_soc_component_read32(component, reg2); + tmpval2 = snd_soc_component_read32(component, reg2); + snd_soc_component_write(component, reg1, 0x00); + snd_soc_component_write(component, reg2, 0xFF); + snd_soc_component_write(component, reg1, 0x01); + snd_soc_component_write(component, reg2, 0xFF); + + snd_soc_component_write(component, reg1, 0x00); + val1 = snd_soc_component_read32(component, reg2); + val2 = snd_soc_component_read32(component, reg2); + + if (val1 == 0x0F && val2 == 0xFF) { + dev_dbg(component->dev, "%s: ANC0 co-eff index re-aligned\n", + __func__); + snd_soc_component_read32(component, reg2); + snd_soc_component_write(component, reg1, 0x00); + snd_soc_component_write(component, reg2, tmpval2); + snd_soc_component_write(component, reg1, 0x01); + snd_soc_component_write(component, reg2, tmpval1); + } else if (val1 == 0xFF && val2 == 0x0F) { + dev_dbg(component->dev, "%s: ANC1 co-eff index already aligned\n", + __func__); + snd_soc_component_write(component, reg1, 0x00); + snd_soc_component_write(component, reg2, tmpval1); + snd_soc_component_write(component, reg1, 0x01); + snd_soc_component_write(component, reg2, tmpval2); + } else { + dev_err(component->dev, "%s: ANC0 co-eff index not aligned\n", + __func__); + } +} + +static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + const char *filename; + const struct firmware *fw; + int i; + int ret = 0; + int num_anc_slots; + struct wcd9xxx_anc_header *anc_head; + struct firmware_cal *hwdep_cal = NULL; + u32 anc_writes_size = 0; + u32 anc_cal_size = 0; + int anc_size_remaining; + u32 *anc_ptr; + u16 reg; + u8 mask, val; + size_t cal_size; + const void *data; + + if (!tasha->anc_func) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, WCD9XXX_ANC_CAL); + if (hwdep_cal) { + data = hwdep_cal->data; + cal_size = hwdep_cal->size; + dev_dbg(component->dev, "%s: using hwdep calibration\n", + __func__); + } else { + filename = "wcd9335/wcd9335_anc.bin"; + ret = request_firmware(&fw, filename, component->dev); + if (ret != 0) { + dev_err(component->dev, + "Failed to acquire ANC data: %d\n", ret); + return -ENODEV; + } + if (!fw) { + dev_err(component->dev, "failed to get anc fw"); + return -ENODEV; + } + data = fw->data; + cal_size = fw->size; + dev_dbg(component->dev, + "%s: using request_firmware calibration\n", __func__); + } + if (cal_size < sizeof(struct wcd9xxx_anc_header)) { + dev_err(component->dev, "Not enough data\n"); + ret = -ENOMEM; + goto err; + } + /* First number is the number of register writes */ + anc_head = (struct wcd9xxx_anc_header *)(data); + anc_ptr = (u32 *)(data + + sizeof(struct wcd9xxx_anc_header)); + anc_size_remaining = cal_size - + sizeof(struct wcd9xxx_anc_header); + num_anc_slots = anc_head->num_anc_slots; + + if (tasha->anc_slot >= num_anc_slots) { + dev_err(component->dev, "Invalid ANC slot selected\n"); + ret = -EINVAL; + goto err; + } + for (i = 0; i < num_anc_slots; i++) { + if (anc_size_remaining < TASHA_PACKED_REG_SIZE) { + dev_err(component->dev, + "Invalid register format\n"); + ret = -EINVAL; + goto err; + } + anc_writes_size = (u32)(*anc_ptr); + anc_size_remaining -= sizeof(u32); + anc_ptr += 1; + + if (anc_writes_size * TASHA_PACKED_REG_SIZE + > anc_size_remaining) { + dev_err(component->dev, + "Invalid register format\n"); + ret = -EINVAL; + goto err; + } + + if (tasha->anc_slot == i) + break; + + anc_size_remaining -= (anc_writes_size * + TASHA_PACKED_REG_SIZE); + anc_ptr += anc_writes_size; + } + if (i == num_anc_slots) { + dev_err(component->dev, "Selected ANC slot not present\n"); + ret = -EINVAL; + goto err; + } + + i = 0; + anc_cal_size = anc_writes_size; + + if (!strcmp(w->name, "RX INT0 DAC") || + !strcmp(w->name, "ANC SPK1 PA")) + tasha_realign_anc_coeff(component, + WCD9335_CDC_ANC0_IIR_COEFF_1_CTL, + WCD9335_CDC_ANC0_IIR_COEFF_2_CTL); + + if (!strcmp(w->name, "RX INT1 DAC") || + !strcmp(w->name, "RX INT3 DAC")) { + tasha_realign_anc_coeff(component, + WCD9335_CDC_ANC0_IIR_COEFF_1_CTL, + WCD9335_CDC_ANC0_IIR_COEFF_2_CTL); + anc_writes_size = anc_cal_size / 2; + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x39, 0x39); + } else if (!strcmp(w->name, "RX INT2 DAC") || + !strcmp(w->name, "RX INT4 DAC")) { + tasha_realign_anc_coeff(component, + WCD9335_CDC_ANC1_IIR_COEFF_1_CTL, + WCD9335_CDC_ANC1_IIR_COEFF_2_CTL); + i = anc_cal_size / 2; + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x39, 0x39); + } + + for (; i < anc_writes_size; i++) { + TASHA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg, mask, val); + snd_soc_component_write(component, reg, (val & mask)); + } + if (!strcmp(w->name, "RX INT1 DAC") || + !strcmp(w->name, "RX INT3 DAC")) { + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08); + } else if (!strcmp(w->name, "RX INT2 DAC") || + !strcmp(w->name, "RX INT4 DAC")) { + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08); + } + + if (!hwdep_cal) + release_firmware(fw); + break; + case SND_SOC_DAPM_POST_PMU: + /* Remove ANC Rx from reset */ + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_CLK_RESET_CTL, + 0x08, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_CLK_RESET_CTL, + 0x08, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + if (!strcmp(w->name, "ANC HPHL PA") || + !strcmp(w->name, "ANC EAR PA") || + !strcmp(w->name, "ANC SPK1 PA") || + !strcmp(w->name, "ANC LINEOUT1 PA")) { + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_MODE_1_CTL, 0x30, 0x00); + msleep(50); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_MODE_1_CTL, 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x38); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x07, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x00); + } else if (!strcmp(w->name, "ANC HPHR PA") || + !strcmp(w->name, "ANC LINEOUT2 PA")) { + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_MODE_1_CTL, 0x30, 0x00); + msleep(50); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_MODE_1_CTL, 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x38); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x07, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x00); + } + break; + } + + return 0; +err: + if (!hwdep_cal) + release_firmware(fw); + return ret; +} + +static void tasha_codec_clear_anc_tx_hold(struct tasha_priv *tasha) +{ + if (test_and_clear_bit(ANC_MIC_AMIC1, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->component, + WCD9335_ANA_AMIC1, false); + if (test_and_clear_bit(ANC_MIC_AMIC2, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->component, + WCD9335_ANA_AMIC2, false); + if (test_and_clear_bit(ANC_MIC_AMIC3, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->component, + WCD9335_ANA_AMIC3, false); + if (test_and_clear_bit(ANC_MIC_AMIC4, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->component, + WCD9335_ANA_AMIC4, false); + if (test_and_clear_bit(ANC_MIC_AMIC5, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->component, + WCD9335_ANA_AMIC5, false); + if (test_and_clear_bit(ANC_MIC_AMIC6, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->component, + WCD9335_ANA_AMIC6, false); +} + +static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha, + int mode, int event) +{ + u8 scale_val = 0; + + if (!TASHA_IS_2_0(tasha->wcd9xxx)) + return; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (mode) { + case CLS_H_HIFI: + scale_val = 0x3; + break; + case CLS_H_LOHIFI: + scale_val = 0x1; + break; + } + if (tasha->anc_func) { + /* Clear Tx FE HOLD if both PAs are enabled */ + if ((snd_soc_component_read32( + tasha->component, WCD9335_ANA_HPH) & + 0xC0) == 0xC0) { + tasha_codec_clear_anc_tx_hold(tasha); + } + } + break; + case SND_SOC_DAPM_PRE_PMD: + scale_val = 0x6; + break; + } + + if (scale_val) + snd_soc_component_update_bits(tasha->component, + WCD9335_HPH_PA_CTL1, 0x0E, + scale_val << 1); + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (tasha->comp_enabled[COMPANDER_1] || + tasha->comp_enabled[COMPANDER_2]) { + snd_soc_component_update_bits(tasha->component, + WCD9335_HPH_L_EN, + 0x20, 0x00); + snd_soc_component_update_bits(tasha->component, + WCD9335_HPH_R_EN, + 0x20, 0x00); + snd_soc_component_update_bits(tasha->component, + WCD9335_HPH_AUTO_CHOP, + 0x20, 0x20); + } + snd_soc_component_update_bits(tasha->component, + WCD9335_HPH_L_EN, 0x1F, + tasha->hph_l_gain); + snd_soc_component_update_bits(tasha->component, + WCD9335_HPH_R_EN, 0x1F, + tasha->hph_r_gain); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(tasha->component, + WCD9335_HPH_AUTO_CHOP, 0x20, + 0x00); + } +} + +static void tasha_codec_override(struct snd_soc_component *component, + int mode, + int event) +{ + if (mode == CLS_AB) { + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (!(snd_soc_component_read32(component, + WCD9335_CDC_RX2_RX_PATH_CTL) & 0x10) && + (!(snd_soc_component_read32(component, + WCD9335_CDC_RX1_RX_PATH_CTL) & 0x10))) + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x00); + break; + } + } +} + +static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int hph_mode = tasha->hph_mode; + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if ((!(strcmp(w->name, "ANC HPHR PA"))) && + (test_bit(HPH_PA_DELAY, &tasha->status_mask))) { + snd_soc_component_update_bits( + component, WCD9335_ANA_HPH, 0xC0, 0xC0); + } + set_bit(HPH_PA_DELAY, &tasha->status_mask); + if (!(strcmp(w->name, "HPHR PA"))) + snd_soc_component_update_bits( + component, WCD9335_ANA_HPH, 0x40, 0x40); + break; + case SND_SOC_DAPM_POST_PMU: + if (!(strcmp(w->name, "ANC HPHR PA"))) { + if ((snd_soc_component_read32( + component, WCD9335_ANA_HPH) & 0xC0) != 0xC0) + /* + * If PA_EN is not set (potentially in ANC case) + * then do nothing for POST_PMU and let left + * channel handle everything. + */ + break; + } + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) { + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tasha->status_mask); + } + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32( + component, WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) & 0x10) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + + if (!(strcmp(w->name, "ANC HPHR PA"))) { + /* Do everything needed for left channel */ + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + /* Remove ANC Rx from reset */ + ret = tasha_codec_enable_anc(w, kcontrol, event); + } + tasha_codec_override(component, hph_mode, event); + break; + + case SND_SOC_DAPM_PRE_PMD: + blocking_notifier_call_chain(&tasha->notifier, + WCD_EVENT_PRE_HPHR_PA_OFF, + &tasha->mbhc); + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); + if (!(strcmp(w->name, "ANC HPHR PA")) || + !(strcmp(w->name, "HPHR PA"))) + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0x40, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + tasha_codec_override(component, hph_mode, event); + blocking_notifier_call_chain(&tasha->notifier, + WCD_EVENT_POST_HPHR_PA_OFF, + &tasha->mbhc); + + if (!(strcmp(w->name, "ANC HPHR PA"))) { + ret = tasha_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX2_RX_PATH_CFG0, 0x10, 0x00); + } + break; + }; + + return ret; +} + +static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int hph_mode = tasha->hph_mode; + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if ((!(strcmp(w->name, "ANC HPHL PA"))) && + (test_bit(HPH_PA_DELAY, &tasha->status_mask))) { + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0xC0, 0xC0); + } + if (!(strcmp(w->name, "HPHL PA"))) + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0x80, 0x80); + set_bit(HPH_PA_DELAY, &tasha->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if (!(strcmp(w->name, "ANC HPHL PA"))) { + if ((snd_soc_component_read32( + component, WCD9335_ANA_HPH) & 0xC0) != 0xC0) + /* + * If PA_EN is not set (potentially in ANC case) + * then do nothing for POST_PMU and let right + * channel handle everything. + */ + break; + } + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + if (test_bit(HPH_PA_DELAY, &tasha->status_mask)) { + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tasha->status_mask); + } + + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32( + component, WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) & 0x10) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + + if (!(strcmp(w->name, "ANC HPHL PA"))) { + /* Do everything needed for right channel */ + snd_soc_component_update_bits(component, + WCD9335_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + + /* Remove ANC Rx from reset */ + ret = tasha_codec_enable_anc(w, kcontrol, event); + } + tasha_codec_override(component, hph_mode, event); + break; + case SND_SOC_DAPM_PRE_PMD: + blocking_notifier_call_chain(&tasha->notifier, + WCD_EVENT_PRE_HPHL_PA_OFF, + &tasha->mbhc); + tasha_codec_hph_post_pa_config(tasha, hph_mode, event); + if (!(strcmp(w->name, "ANC HPHL PA")) || + !(strcmp(w->name, "HPHL PA"))) + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0x80, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + tasha_codec_override(component, hph_mode, event); + blocking_notifier_call_chain(&tasha->notifier, + WCD_EVENT_POST_HPHL_PA_OFF, + &tasha->mbhc); + + if (!(strcmp(w->name, "ANC HPHL PA"))) { + ret = tasha_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_CFG0, 0x10, 0x00); + } + break; + }; + + return ret; +} + +static int tasha_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0; + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + if (w->reg == WCD9335_ANA_LO_1_2) { + if (w->shift == 7) { + lineout_vol_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + lineout_mix_vol_reg = WCD9335_CDC_RX3_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + lineout_vol_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + lineout_mix_vol_reg = WCD9335_CDC_RX4_RX_PATH_MIX_CTL; + } + } else if (w->reg == WCD9335_ANA_LO_3_4) { + if (w->shift == 7) { + lineout_vol_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + lineout_mix_vol_reg = WCD9335_CDC_RX5_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + lineout_vol_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + lineout_mix_vol_reg = WCD9335_CDC_RX6_RX_PATH_MIX_CTL; + } + } else { + dev_err(component->dev, "%s: Error enabling lineout PA\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, lineout_vol_reg, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32( + component, lineout_mix_vol_reg)) & 0x10) + snd_soc_component_update_bits(component, + lineout_mix_vol_reg, + 0x10, 0x00); + if (!(strcmp(w->name, "ANC LINEOUT1 PA")) || + !(strcmp(w->name, "ANC LINEOUT2 PA"))) + ret = tasha_codec_enable_anc(w, kcontrol, event); + tasha_codec_override(component, CLS_AB, event); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + tasha_codec_override(component, CLS_AB, event); + if (!(strcmp(w->name, "ANC LINEOUT1 PA")) || + !(strcmp(w->name, "ANC LINEOUT2 PA"))) { + ret = tasha_codec_enable_anc(w, kcontrol, event); + if (!(strcmp(w->name, "ANC LINEOUT1 PA"))) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX3_RX_PATH_CFG0, 0x10, 0x10); + else + snd_soc_component_update_bits(component, + WCD9335_CDC_RX4_RX_PATH_CFG0, 0x10, 0x10); + } + break; + }; + + return ret; +} + +static void tasha_spk_anc_update_callback(struct work_struct *work) +{ + struct spk_anc_work *spk_anc_dwork; + struct tasha_priv *tasha; + struct delayed_work *delayed_work; + struct snd_soc_component *component; + + delayed_work = to_delayed_work(work); + spk_anc_dwork = container_of(delayed_work, struct spk_anc_work, dwork); + tasha = spk_anc_dwork->tasha; + component = tasha->component; + + snd_soc_component_update_bits(component, WCD9335_CDC_RX7_RX_PATH_CFG0, + 0x10, 0x10); +} + +static int tasha_codec_enable_spk_anc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %s %d %d\n", __func__, w->name, event, + tasha->anc_func); + + if (!tasha->anc_func) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = tasha_codec_enable_anc(w, kcontrol, event); + schedule_delayed_work(&tasha->spk_anc_dwork.dwork, + msecs_to_jiffies(spk_anc_en_delay)); + break; + case SND_SOC_DAPM_POST_PMD: + cancel_delayed_work_sync(&tasha->spk_anc_dwork.dwork); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_CFG0, + 0x10, 0x00); + ret = tasha_codec_enable_anc(w, kcontrol, event); + break; + } + return ret; +} + +static int tasha_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX0_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32( + component, WCD9335_CDC_RX0_RX_PATH_MIX_CTL)) & 0x10) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + + if (!(strcmp(w->name, "ANC EAR PA"))) { + ret = tasha_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX0_RX_PATH_CFG0, 0x10, 0x00); + } + break; + }; + + return ret; +} + +static void tasha_codec_hph_mode_gain_opt(struct snd_soc_component *component, + u8 gain) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u8 hph_l_en, hph_r_en; + u8 l_val, r_val; + u8 hph_pa_status; + bool is_hphl_pa, is_hphr_pa; + + hph_pa_status = snd_soc_component_read32(component, WCD9335_ANA_HPH); + is_hphl_pa = hph_pa_status >> 7; + is_hphr_pa = (hph_pa_status & 0x40) >> 6; + + hph_l_en = snd_soc_component_read32(component, WCD9335_HPH_L_EN); + hph_r_en = snd_soc_component_read32(component, WCD9335_HPH_R_EN); + + l_val = (hph_l_en & 0xC0) | 0x20 | gain; + r_val = (hph_r_en & 0xC0) | 0x20 | gain; + + /* + * Set HPH_L & HPH_R gain source selection to REGISTER + * for better click and pop only if corresponding PAs are + * not enabled. Also cache the values of the HPHL/R + * PA gains to be applied after PAs are enabled + */ + if ((l_val != hph_l_en) && !is_hphl_pa) { + snd_soc_component_write(component, WCD9335_HPH_L_EN, l_val); + tasha->hph_l_gain = hph_l_en & 0x1F; + } + + if ((r_val != hph_r_en) && !is_hphr_pa) { + snd_soc_component_write(component, WCD9335_HPH_R_EN, r_val); + tasha->hph_r_gain = hph_r_en & 0x1F; + } +} + +static void tasha_codec_hph_lohifi_config(struct snd_soc_component *component, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, + WCD9335_RX_BIAS_HPH_PA, + 0x0F, 0x06); + snd_soc_component_update_bits(component, + WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0xF0, 0x40); + snd_soc_component_update_bits(component, + WCD9335_HPH_CNP_WG_CTL, + 0x07, 0x03); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, + 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL1, + 0x0E, 0x0C); + tasha_codec_hph_mode_gain_opt(component, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, + 0x08, 0x00); + snd_soc_component_update_bits(component, + WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02); + snd_soc_component_write(component, + WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A); + snd_soc_component_update_bits(component, + WCD9335_RX_BIAS_HPH_PA, + 0x0F, 0x0A); + } +} + +static void tasha_codec_hph_lp_config(struct snd_soc_component *component, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL1, 0x0E, 0x0C); + tasha_codec_hph_mode_gain_opt(component, 0x10); + snd_soc_component_update_bits(component, + WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9335_HPH_RDAC_LDO_CTL, 0x07, 0x01); + snd_soc_component_update_bits(component, + WCD9335_HPH_RDAC_LDO_CTL, 0x70, 0x10); + snd_soc_component_update_bits(component, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x0F, 0x01); + snd_soc_component_update_bits(component, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0xF0, 0x10); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_write(component, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x88); + snd_soc_component_write(component, + WCD9335_HPH_RDAC_LDO_CTL, 0x33); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x20, 0x00); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x04, 0x00); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x08, 0x00); + snd_soc_component_update_bits(component, + WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02); + snd_soc_component_update_bits(component, + WCD9335_HPH_R_EN, 0xC0, 0x80); + snd_soc_component_update_bits(component, + WCD9335_HPH_L_EN, 0xC0, 0x80); + } +} + +static void tasha_codec_hph_hifi_config(struct snd_soc_component *component, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, + WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL1, 0x0E, 0x0C); + tasha_codec_hph_mode_gain_opt(component, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + WCD9335_HPH_PA_CTL2, 0x08, 0x00); + snd_soc_component_update_bits(component, + WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02); + } +} + +static void tasha_codec_hph_mode_config(struct snd_soc_component *component, + int event, int mode) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (!TASHA_IS_2_0(tasha->wcd9xxx)) + return; + + switch (mode) { + case CLS_H_LP: + tasha_codec_hph_lp_config(component, event); + break; + case CLS_H_LOHIFI: + tasha_codec_hph_lohifi_config(component, event); + break; + case CLS_H_HIFI: + tasha_codec_hph_hifi_config(component, event); + break; + } +} + +static int tasha_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 tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + int hph_mode = tasha->hph_mode; + u8 dem_inp; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d hph_mode: %d\n", + __func__, w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tasha->anc_func) { + ret = tasha_codec_enable_anc(w, kcontrol, event); + /* 40 msec delay is needed to avoid click and pop */ + msleep(40); + } + + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32( + component, WCD9335_CDC_RX2_RX_PATH_SEC0) & + 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + if (!(strcmp(w->name, "RX INT2 DAC"))) + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0x10, 0x10); + + tasha_codec_hph_mode_config(component, event, hph_mode); + + if (tasha->anc_func) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX2_RX_PATH_CFG0, 0x10, 0x10); + + break; + case SND_SOC_DAPM_POST_PMU: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + if ((hph_mode == CLS_H_LP) && + (TASHA_IS_1_1(wcd9xxx))) { + snd_soc_component_update_bits(component, + WCD9335_HPH_L_DAC_CTL, 0x03, 0x03); + } + break; + case SND_SOC_DAPM_PRE_PMD: + if ((hph_mode == CLS_H_LP) && + (TASHA_IS_1_1(wcd9xxx))) { + snd_soc_component_update_bits(component, + WCD9335_HPH_L_DAC_CTL, + 0x03, 0x00); + } + if (!(strcmp(w->name, "RX INT2 DAC"))) + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_get_clsh_state(&tasha->clsh_d) & + WCD_CLSH_STATE_HPHL)) + tasha_codec_hph_mode_config(component, event, hph_mode); + + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + }; + + return ret; +} + +static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + int hph_mode = tasha->hph_mode; + u8 dem_inp; + int ret = 0; + uint32_t impedl = 0, impedr = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d hph_mode: %d\n", + __func__, w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tasha->anc_func) { + ret = tasha_codec_enable_anc(w, kcontrol, event); + /* 40 msec delay is needed to avoid click and pop */ + msleep(40); + } + + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32( + component, WCD9335_CDC_RX1_RX_PATH_SEC0) & + 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + if (!(strcmp(w->name, "RX INT1 DAC"))) + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0x20, 0x20); + + tasha_codec_hph_mode_config(component, event, hph_mode); + + if (tasha->anc_func) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX1_RX_PATH_CFG0, 0x10, 0x10); + + ret = wcd_mbhc_get_impedance(&tasha->mbhc, + &impedl, &impedr); + if (!ret) { + wcd_clsh_imped_config(component, impedl, false); + set_bit(CLASSH_CONFIG, &tasha->status_mask); + } else { + dev_dbg(component->dev, "%s: Failed to get mbhc impedance %d\n", + __func__, ret); + ret = 0; + } + + + break; + case SND_SOC_DAPM_POST_PMU: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + if ((hph_mode == CLS_H_LP) && + (TASHA_IS_1_1(wcd9xxx))) { + snd_soc_component_update_bits(component, + WCD9335_HPH_L_DAC_CTL, + 0x03, 0x03); + } + break; + case SND_SOC_DAPM_PRE_PMD: + if (!(strcmp(w->name, "RX INT1 DAC"))) + snd_soc_component_update_bits(component, + WCD9335_ANA_HPH, 0x20, 0x00); + if ((hph_mode == CLS_H_LP) && + (TASHA_IS_1_1(wcd9xxx))) { + snd_soc_component_update_bits(component, + WCD9335_HPH_L_DAC_CTL, + 0x03, 0x00); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_get_clsh_state(&tasha->clsh_d) & + WCD_CLSH_STATE_HPHR)) + tasha_codec_hph_mode_config(component, event, hph_mode); + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + if (test_bit(CLASSH_CONFIG, &tasha->status_mask)) { + wcd_clsh_imped_config(component, impedl, true); + clear_bit(CLASSH_CONFIG, &tasha->status_mask); + } else + dev_dbg(component->dev, "%s: Failed to get mbhc impedance %d\n", + __func__, ret); + + + break; + }; + + return ret; +} + +static int tasha_codec_lineout_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tasha->anc_func && + (!strcmp(w->name, "RX INT3 DAC") || + !strcmp(w->name, "RX INT4 DAC"))) + ret = tasha_codec_enable_anc(w, kcontrol, event); + + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_LO, + CLS_AB); + + if (tasha->anc_func) { + if (!strcmp(w->name, "RX INT3 DAC")) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX3_RX_PATH_CFG0, 0x10, 0x10); + else if (!strcmp(w->name, "RX INT4 DAC")) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX4_RX_PATH_CFG0, 0x10, 0x10); + } + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_LO, + CLS_AB); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget tasha_dapm_i2s_widgets[] = { + SND_SOC_DAPM_SUPPLY("RX_I2S_CTL", WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TX_I2S_CTL", WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0, 0, NULL, 0), +}; + +static int tasha_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tasha->anc_func) + ret = tasha_codec_enable_anc(w, kcontrol, event); + + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + CLS_H_NORMAL); + if (tasha->anc_func) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX0_RX_PATH_CFG0, 0x10, 0x10); + + break; + case SND_SOC_DAPM_POST_PMU: + break; + case SND_SOC_DAPM_PRE_PMD: + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_fsm(component, &tasha->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + CLS_H_NORMAL); + break; + }; + + return ret; +} + +static int tasha_codec_spk_boost_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 boost_path_ctl, boost_path_cfg1; + u16 reg, reg_mix; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + if (!strcmp(w->name, "RX INT7 CHAIN")) { + boost_path_ctl = WCD9335_CDC_BOOST0_BOOST_PATH_CTL; + boost_path_cfg1 = WCD9335_CDC_RX7_RX_PATH_CFG1; + reg = WCD9335_CDC_RX7_RX_PATH_CTL; + reg_mix = WCD9335_CDC_RX7_RX_PATH_MIX_CTL; + } else if (!strcmp(w->name, "RX INT8 CHAIN")) { + boost_path_ctl = WCD9335_CDC_BOOST1_BOOST_PATH_CTL; + boost_path_cfg1 = WCD9335_CDC_RX8_RX_PATH_CFG1; + reg = WCD9335_CDC_RX8_RX_PATH_CTL; + reg_mix = WCD9335_CDC_RX8_RX_PATH_MIX_CTL; + } else { + dev_err(component->dev, "%s: unknown widget: %s\n", + __func__, w->name); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x10); + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x01); + snd_soc_component_update_bits(component, reg, 0x10, 0x00); + if ((snd_soc_component_read32(component, reg_mix)) & 0x10) + snd_soc_component_update_bits(component, reg_mix, + 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x00); + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x00); + break; + }; + + return 0; +} + +static u16 tasha_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = 0; + + switch (reg) { + case WCD9335_CDC_RX0_RX_PATH_CTL: + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL; + *ind = 0; + break; + case WCD9335_CDC_RX1_RX_PATH_CTL: + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX1_RX_PATH_CTL; + *ind = 1; + break; + case WCD9335_CDC_RX2_RX_PATH_CTL: + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX2_RX_PATH_CTL; + *ind = 2; + break; + case WCD9335_CDC_RX3_RX_PATH_CTL: + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + *ind = 3; + break; + case WCD9335_CDC_RX4_RX_PATH_CTL: + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + *ind = 4; + break; + case WCD9335_CDC_RX5_RX_PATH_CTL: + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + *ind = 5; + break; + case WCD9335_CDC_RX6_RX_PATH_CTL: + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + *ind = 6; + break; + case WCD9335_CDC_RX7_RX_PATH_CTL: + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX7_RX_PATH_CTL; + *ind = 7; + break; + case WCD9335_CDC_RX8_RX_PATH_CTL: + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL; + *ind = 8; + break; + }; + + return prim_int_reg; +} + +static void tasha_codec_hd2_control(struct snd_soc_component *component, + u16 prim_int_reg, int event) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (!TASHA_IS_2_0(tasha->wcd9xxx)) + return; + + if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + } + if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x10); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x01); + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x03, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x00); + } +} + +static int tasha_codec_enable_prim_interpolator( + struct snd_soc_component *component, + u16 reg, int event) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u16 prim_int_reg; + u16 ind = 0; + + prim_int_reg = tasha_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tasha->prim_int_users[ind]++; + if (tasha->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(component, prim_int_reg, + 0x10, 0x10); + tasha_codec_hd2_control(component, prim_int_reg, event); + snd_soc_component_update_bits(component, prim_int_reg, + 1 << 0x5, 1 << 0x5); + } + if ((reg != prim_int_reg) && + ((snd_soc_component_read32( + component, prim_int_reg)) & 0x10)) + snd_soc_component_update_bits(component, reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + tasha->prim_int_users[ind]--; + if (tasha->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(component, prim_int_reg, + 1 << 0x5, 0 << 0x5); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, prim_int_reg, + 0x40, 0x00); + tasha_codec_hd2_control(component, prim_int_reg, event); + } + break; + }; + + dev_dbg(component->dev, "%s: primary interpolator: INT%d, users: %d\n", + __func__, ind, tasha->prim_int_users[ind]); + return 0; +} + +static int tasha_codec_enable_spline_src(struct snd_soc_component *component, + int src_num, + int event) +{ + u16 src_paired_reg = 0; + struct tasha_priv *tasha; + u16 rx_path_cfg_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + u16 rx_path_ctl_reg = WCD9335_CDC_RX1_RX_PATH_CTL; + int *src_users, count, spl_src = SPLINE_SRC0; + u16 src_clk_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0; + + tasha = snd_soc_component_get_drvdata(component); + + switch (src_num) { + case SRC_IN_HPHL: + rx_path_cfg_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX1_RX_PATH_CTL; + spl_src = SPLINE_SRC0; + break; + case SRC_IN_LO1: + rx_path_cfg_reg = WCD9335_CDC_RX3_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + spl_src = SPLINE_SRC0; + break; + case SRC_IN_HPHR: + rx_path_cfg_reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX2_RX_PATH_CTL; + spl_src = SPLINE_SRC1; + break; + case SRC_IN_LO2: + rx_path_cfg_reg = WCD9335_CDC_RX4_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC1_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC0_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + spl_src = SPLINE_SRC1; + break; + case SRC_IN_SPKRL: + rx_path_cfg_reg = WCD9335_CDC_RX7_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX7_RX_PATH_CTL; + spl_src = SPLINE_SRC2; + break; + case SRC_IN_LO3: + rx_path_cfg_reg = WCD9335_CDC_RX5_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + spl_src = SPLINE_SRC2; + break; + case SRC_IN_SPKRR: + rx_path_cfg_reg = WCD9335_CDC_RX8_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX8_RX_PATH_CTL; + spl_src = SPLINE_SRC3; + break; + case SRC_IN_LO4: + rx_path_cfg_reg = WCD9335_CDC_RX6_RX_PATH_CFG0; + src_clk_reg = WCD9335_SPLINE_SRC3_CLK_RST_CTL_0; + src_paired_reg = WCD9335_SPLINE_SRC2_CLK_RST_CTL_0; + rx_path_ctl_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + spl_src = SPLINE_SRC3; + break; + }; + + src_users = &tasha->spl_src_users[spl_src]; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + count = *src_users; + count++; + if (count == 1) { + if ((snd_soc_component_read32( + component, src_clk_reg) & 0x02) || + (snd_soc_component_read32( + component, src_paired_reg) & 0x02)) { + snd_soc_component_update_bits(component, + src_clk_reg, 0x02, 0x00); + snd_soc_component_update_bits(component, + src_paired_reg, 0x02, 0x00); + } + snd_soc_component_update_bits(component, src_clk_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, + rx_path_cfg_reg, 0x80, 0x80); + } + *src_users = count; + break; + case SND_SOC_DAPM_POST_PMD: + count = *src_users; + count--; + if (count == 0) { + snd_soc_component_update_bits(component, + rx_path_cfg_reg, 0x80, 0x00); + snd_soc_component_update_bits(component, + src_clk_reg, 0x03, 0x02); + /* default sample rate */ + snd_soc_component_update_bits(component, + rx_path_ctl_reg, 0x0f, 0x04); + } + *src_users = count; + break; + }; + + dev_dbg(component->dev, "%s: Spline SRC%d, users: %d\n", + __func__, spl_src, *src_users); + return 0; +} + +static int tasha_codec_enable_spline_resampler(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + u8 src_in; + + src_in = snd_soc_component_read32( + component, WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0); + if (!(src_in & 0xFF)) { + dev_err(component->dev, "%s: Spline SRC%u input not selected\n", + __func__, w->shift); + return -EINVAL; + } + + switch (w->shift) { + case SPLINE_SRC0: + ret = tasha_codec_enable_spline_src(component, + ((src_in & 0x03) == 1) ? SRC_IN_HPHL : SRC_IN_LO1, + event); + break; + case SPLINE_SRC1: + ret = tasha_codec_enable_spline_src(component, + ((src_in & 0x0C) == 4) ? SRC_IN_HPHR : SRC_IN_LO2, + event); + break; + case SPLINE_SRC2: + ret = tasha_codec_enable_spline_src(component, + ((src_in & 0x30) == 0x10) ? SRC_IN_LO3 : SRC_IN_SPKRL, + event); + break; + case SPLINE_SRC3: + ret = tasha_codec_enable_spline_src(component, + ((src_in & 0xC0) == 0x40) ? SRC_IN_LO4 : SRC_IN_SPKRR, + event); + break; + default: + dev_err(component->dev, "%s: Invalid spline src:%u\n", __func__, + w->shift); + ret = -EINVAL; + }; + + return ret; +} + +static int tasha_codec_enable_swr(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha; + int i, ch_cnt; + + tasha = snd_soc_component_get_drvdata(component); + + if (!tasha->nr) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) && + !tasha->rx_7_count) + tasha->rx_7_count++; + if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && + !tasha->rx_8_count) + tasha->rx_8_count++; + ch_cnt = tasha->rx_7_count + tasha->rx_8_count; + + for (i = 0; i < tasha->nr; i++) { + swrm_wcd_notify(tasha->swr_ctrl_data[i].swr_pdev, + SWR_DEVICE_UP, NULL); + swrm_wcd_notify(tasha->swr_ctrl_data[i].swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + } + break; + case SND_SOC_DAPM_POST_PMD: + if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) && + tasha->rx_7_count) + tasha->rx_7_count--; + if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && + tasha->rx_8_count) + tasha->rx_8_count--; + ch_cnt = tasha->rx_7_count + tasha->rx_8_count; + + for (i = 0; i < tasha->nr; i++) + swrm_wcd_notify(tasha->swr_ctrl_data[i].swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + + break; + } + dev_dbg(tasha->dev, "%s: current swr ch cnt: %d\n", + __func__, tasha->rx_7_count + tasha->rx_8_count); + + return 0; +} + +static int tasha_codec_config_ear_spkr_gain(struct snd_soc_component *component, + int event, int gain_reg) +{ + int comp_gain_offset, val; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + switch (tasha->spkr_mode) { + /* Compander gain in SPKR_MODE1 case is 12 dB */ + case SPKR_MODE_1: + comp_gain_offset = -12; + break; + /* Default case compander gain is 15 dB */ + default: + comp_gain_offset = -15; + break; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Apply ear spkr gain only if compander is enabled */ + if (tasha->comp_enabled[COMPANDER_7] && + (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL) && + (tasha->ear_spkr_gain != 0)) { + /* For example, val is -8(-12+5-1) for 4dB of gain */ + val = comp_gain_offset + tasha->ear_spkr_gain - 1; + snd_soc_component_write(component, gain_reg, val); + + dev_dbg(component->dev, "%s: RX7 Volume %d dB\n", + __func__, val); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* + * Reset RX7 volume to 0 dB if compander is enabled and + * ear_spkr_gain is non-zero. + */ + if (tasha->comp_enabled[COMPANDER_7] && + (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL) && + (tasha->ear_spkr_gain != 0)) { + snd_soc_component_write(component, gain_reg, 0x0); + + dev_dbg(component->dev, "%s: Reset RX7 Volume to 0 dB\n", + __func__); + } + break; + } + + return 0; +} + +static int tasha_codec_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u16 gain_reg; + int offset_val = 0; + int val = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + switch (w->reg) { + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX0_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX1_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX2_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX3_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX4_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX5_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX6_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX7_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX8_RX_VOL_MIX_CTL; + break; + default: + dev_err(component->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + }; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + (tasha->comp_enabled[COMPANDER_7] || + tasha->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL || + gain_reg == WCD9335_CDC_RX8_RX_VOL_MIX_CTL)) { + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x01); + offset_val = -2; + } + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + tasha_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + case SND_SOC_DAPM_POST_PMD: + if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + (tasha->comp_enabled[COMPANDER_7] || + tasha->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL || + gain_reg == WCD9335_CDC_RX8_RX_VOL_MIX_CTL)) { + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x00); + offset_val = 2; + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + } + tasha_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + }; + + return 0; +} + +static int __tasha_cdc_native_clk_enable(struct tasha_priv *tasha, + bool enable) +{ + int ret = 0; + struct snd_soc_component *component = tasha->component; + + if (!tasha->wcd_native_clk) { + dev_err(tasha->dev, "%s: wcd native clock is NULL\n", + __func__); + return -EINVAL; + } + + dev_dbg(tasha->dev, "%s: native_clk_enable = %u\n", + __func__, enable); + + if (enable) { + ret = clk_prepare_enable(tasha->wcd_native_clk); + if (ret) { + dev_err(tasha->dev, "%s: native clk enable failed\n", + __func__); + goto err; + } + if (++tasha->native_clk_users == 1) { + snd_soc_component_update_bits(component, + WCD9335_CLOCK_TEST_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD9335_CLOCK_TEST_CTL, + 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_CLK_GATE, + 0x04, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x02); + } + } else { + if (tasha->native_clk_users && + (--tasha->native_clk_users == 0)) { + snd_soc_component_update_bits(component, + WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_CLK_GATE, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD9335_CLOCK_TEST_CTL, + 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CLOCK_TEST_CTL, + 0x10, 0x00); + } + clk_disable_unprepare(tasha->wcd_native_clk); + } + + dev_dbg(component->dev, "%s: native_clk_users: %d\n", __func__, + tasha->native_clk_users); +err: + return ret; +} + +static int tasha_codec_get_native_fifo_sync_mask( + struct snd_soc_component *component, + int interp_n) +{ + int mask = 0; + u16 reg; + u8 val1, val2, inp0 = 0; + u8 inp1 = 0, inp2 = 0; + + reg = WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 + (2 * interp_n) - 2; + + val1 = snd_soc_component_read32(component, reg); + val2 = snd_soc_component_read32(component, reg + 1); + + inp0 = val1 & 0x0F; + inp1 = (val1 >> 4) & 0x0F; + inp2 = (val2 >> 4) & 0x0F; + + if (IS_VALID_NATIVE_FIFO_PORT(inp0)) + mask |= (1 << (inp0 - 5)); + if (IS_VALID_NATIVE_FIFO_PORT(inp1)) + mask |= (1 << (inp1 - 5)); + if (IS_VALID_NATIVE_FIFO_PORT(inp2)) + mask |= (1 << (inp2 - 5)); + + dev_dbg(component->dev, "%s: native fifo mask: 0x%x\n", __func__, mask); + if (!mask) + dev_err(component->dev, "native fifo err,int:%d,inp0:%d,inp1:%d,inp2:%d\n", + interp_n, inp0, inp1, inp2); + return mask; +} + +static int tasha_enable_native_supply(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int mask; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u16 interp_reg; + + dev_dbg(component->dev, "%s: event: %d, shift:%d\n", __func__, event, + w->shift); + + if (w->shift < INTERP_HPHL || w->shift > INTERP_LO2) + return -EINVAL; + + interp_reg = WCD9335_CDC_RX1_RX_PATH_CTL + 20 * (w->shift - 1); + + mask = tasha_codec_get_native_fifo_sync_mask(component, w->shift); + if (!mask) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Adjust interpolator rate to 44P1_NATIVE */ + snd_soc_component_update_bits(component, interp_reg, + 0x0F, 0x09); + __tasha_cdc_native_clk_enable(tasha, true); + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_NATIVE_FIFO_SYNC, + mask, mask); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_NATIVE_FIFO_SYNC, + mask, 0x0); + __tasha_cdc_native_clk_enable(tasha, false); + /* Adjust interpolator rate to default */ + snd_soc_component_update_bits(component, interp_reg, + 0x0F, 0x04); + break; + } + + return 0; +} + +static int tasha_codec_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "RX INT0 INTERP"))) { + reg = WCD9335_CDC_RX0_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT1 INTERP"))) { + reg = WCD9335_CDC_RX1_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT2 INTERP"))) { + reg = WCD9335_CDC_RX2_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT3 INTERP"))) { + reg = WCD9335_CDC_RX3_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT4 INTERP"))) { + reg = WCD9335_CDC_RX4_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT5 INTERP"))) { + reg = WCD9335_CDC_RX5_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT6 INTERP"))) { + reg = WCD9335_CDC_RX6_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT7 INTERP"))) { + reg = WCD9335_CDC_RX7_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT8 INTERP"))) { + reg = WCD9335_CDC_RX8_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL; + } else { + dev_err(component->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tasha_codec_vote_max_bw(component, true); + /* Reset if needed */ + tasha_codec_enable_prim_interpolator(component, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + tasha_config_compander(component, w->shift, event); + /* apply gain after int clk is enabled */ + if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + (tasha->comp_enabled[COMPANDER_7] || + tasha->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD9335_CDC_RX8_RX_VOL_CTL)) { + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x01); + offset_val = -2; + } + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + tasha_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + case SND_SOC_DAPM_POST_PMD: + tasha_config_compander(component, w->shift, event); + tasha_codec_enable_prim_interpolator(component, reg, event); + if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + (tasha->comp_enabled[COMPANDER_7] || + tasha->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD9335_CDC_RX8_RX_VOL_CTL)) { + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x00); + offset_val = 2; + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + } + tasha_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + }; + + return 0; +} + +static int tasha_codec_set_iir_gain(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: /* fall through */ + case SND_SOC_DAPM_PRE_PMD: + if (strnstr(w->name, "IIR0", sizeof("IIR0"))) { + snd_soc_component_write(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, + snd_soc_component_read32(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, + snd_soc_component_read32(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, + snd_soc_component_read32(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)); + snd_soc_component_write(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, + snd_soc_component_read32(component, + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)); + } else { + snd_soc_component_write(component, + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, + snd_soc_component_read32(component, + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, + snd_soc_component_read32(component, + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, + snd_soc_component_read32(component, + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)); + } + break; + } + return 0; +} + +static int tasha_codec_enable_on_demand_supply( + struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct on_demand_supply *supply; + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); + const char *supply_name; + + if (w->shift >= ON_DEMAND_SUPPLIES_MAX) { + dev_err(component->dev, "%s: error index > MAX Demand supplies", + __func__); + ret = -EINVAL; + goto out; + } + + dev_dbg(component->dev, "%s: supply: %s event: %d\n", + __func__, on_demand_supply_name[w->shift], event); + + supply = &tasha->on_demand_list[w->shift]; + supply_name = on_demand_supply_name[w->shift]; + WARN_ONCE(!supply->supply, "%s isn't defined\n", + on_demand_supply_name[w->shift]); + if (!supply->supply) { + dev_err(component->dev, "%s: err supply not present ond for %d", + __func__, w->shift); + goto out; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (pdata->vote_regulator_on_demand) { + ret = wcd9xxx_vote_ondemand_regulator(wcd9xxx, pdata, + supply_name, + true); + if (ret) + dev_err(component->dev, "%s: Failed to vote %s\n", + __func__, + on_demand_supply_name[w->shift]); + } + ret = regulator_enable(supply->supply); + if (ret) + dev_err(component->dev, "%s: Failed to enable %s\n", + __func__, + on_demand_supply_name[w->shift]); + break; + case SND_SOC_DAPM_POST_PMD: + ret = regulator_disable(supply->supply); + if (ret) + dev_err(component->dev, "%s: Failed to disable %s\n", + __func__, + on_demand_supply_name[w->shift]); + if (pdata->vote_regulator_on_demand) { + ret = wcd9xxx_vote_ondemand_regulator(wcd9xxx, pdata, + supply_name, + false); + if (ret) + dev_err(component->dev, "%s: Failed to unvote %s\n", + __func__, + on_demand_supply_name[w->shift]); + } + break; + default: + break; + }; + +out: + return ret; +} + +static int tasha_codec_find_amic_input(struct snd_soc_component *component, + int adc_mux_n) +{ + u16 mask, shift, adc_mux_in_reg; + u16 amic_mux_sel_reg; + bool is_amic; + + if (adc_mux_n < 0 || adc_mux_n > WCD9335_MAX_VALID_ADC_MUX || + adc_mux_n == WCD9335_INVALID_ADC_MUX) + return 0; + + /* Check whether adc mux input is AMIC or DMIC */ + if (adc_mux_n < 4) { + adc_mux_in_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + 2 * adc_mux_n; + amic_mux_sel_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + 2 * adc_mux_n; + mask = 0x03; + shift = 0; + } else { + adc_mux_in_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + amic_mux_sel_reg = adc_mux_in_reg; + mask = 0xC0; + shift = 6; + } + is_amic = (((snd_soc_component_read32( + component, adc_mux_in_reg) & mask) >> shift) == 1); + if (!is_amic) + return 0; + + return snd_soc_component_read32(component, amic_mux_sel_reg) & 0x07; +} + +static void tasha_codec_set_tx_hold(struct snd_soc_component *component, + u16 amic_reg, bool set) +{ + u8 mask = 0x20; + u8 val; + + if (amic_reg == WCD9335_ANA_AMIC1 || + amic_reg == WCD9335_ANA_AMIC3 || + amic_reg == WCD9335_ANA_AMIC5) + mask = 0x40; + + val = set ? mask : 0x00; + + switch (amic_reg) { + case WCD9335_ANA_AMIC1: + case WCD9335_ANA_AMIC2: + snd_soc_component_update_bits(component, WCD9335_ANA_AMIC2, + mask, val); + break; + case WCD9335_ANA_AMIC3: + case WCD9335_ANA_AMIC4: + snd_soc_component_update_bits(component, WCD9335_ANA_AMIC4, + mask, val); + break; + case WCD9335_ANA_AMIC5: + case WCD9335_ANA_AMIC6: + snd_soc_component_update_bits(component, WCD9335_ANA_AMIC6, + mask, val); + break; + default: + dev_dbg(component->dev, "%s: invalid amic: %d\n", + __func__, amic_reg); + break; + } +} + +static int tasha_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int adc_mux_n = w->shift; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int amic_n; + + dev_dbg(component->dev, "%s: event: %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + amic_n = tasha_codec_find_amic_input(component, adc_mux_n); + if (amic_n) { + /* + * Prevent ANC Rx pop by leaving Tx FE in HOLD + * state until PA is up. Track AMIC being used + * so we can release the HOLD later. + */ + set_bit(ANC_MIC_AMIC1 + amic_n - 1, + &tasha->status_mask); + } + break; + default: + break; + } + + return 0; +} + +static u16 tasha_codec_get_amic_pwlvl_reg( + struct snd_soc_component *component, int amic) +{ + u16 pwr_level_reg = 0; + + switch (amic) { + case 1: + case 2: + pwr_level_reg = WCD9335_ANA_AMIC1; + break; + + case 3: + case 4: + pwr_level_reg = WCD9335_ANA_AMIC3; + break; + + case 5: + case 6: + pwr_level_reg = WCD9335_ANA_AMIC5; + break; + default: + dev_dbg(component->dev, "%s: invalid amic: %d\n", + __func__, amic); + break; + } + + return pwr_level_reg; +} + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +static void tasha_tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct tasha_priv *tasha; + struct snd_soc_component *component; + u16 dec_cfg_reg, amic_reg; + u8 hpf_cut_off_freq; + int amic_n; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + tasha = hpf_work->tasha; + component = tasha->component; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * hpf_work->decimator; + + dev_dbg(component->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + amic_n = tasha_codec_find_amic_input(component, hpf_work->decimator); + if (amic_n) { + amic_reg = WCD9335_ANA_AMIC1 + amic_n - 1; + tasha_codec_set_tx_hold(component, amic_reg, false); + } + tasha_codec_vote_max_bw(component, true); + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + tasha_codec_vote_max_bw(component, false); +} + +static void tasha_tx_mute_update_callback(struct work_struct *work) +{ + struct tx_mute_work *tx_mute_dwork; + struct tasha_priv *tasha; + struct delayed_work *delayed_work; + struct snd_soc_component *component; + u16 tx_vol_ctl_reg, hpf_gate_reg; + + delayed_work = to_delayed_work(work); + tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork); + tasha = tx_mute_dwork->tasha; + component = tasha->component; + + tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + + 16 * tx_mute_dwork->decimator; + hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 + + 16 * tx_mute_dwork->decimator; + snd_soc_component_update_bits(component, hpf_gate_reg, 0x01, 0x01); + snd_soc_component_update_bits(component, tx_vol_ctl_reg, 0x10, 0x00); +} + +static int tasha_codec_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + unsigned int decimator; + char *dec_adc_mux_name = NULL; + char *widget_name = NULL; + char *wname; + int ret = 0, amic_n; + u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + char *dec; + u8 hpf_cut_off_freq; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %d\n", __func__, event); + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + + wname = widget_name; + dec_adc_mux_name = strsep(&widget_name, " "); + if (!dec_adc_mux_name) { + dev_err(component->dev, "%s: Invalid decimator = %s\n", + __func__, w->name); + ret = -EINVAL; + goto out; + } + dec_adc_mux_name = widget_name; + + dec = strpbrk(dec_adc_mux_name, "012345678"); + if (!dec) { + dev_err(component->dev, "%s: decimator index not found\n", + __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec, 10, &decimator); + if (ret < 0) { + dev_err(component->dev, "%s: Invalid decimator = %s\n", + __func__, wname); + ret = -EINVAL; + goto out; + } + + dev_dbg(component->dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator; + hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 + 16 * decimator; + dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * decimator; + tx_gain_ctl_reg = WCD9335_CDC_TX0_TX_VOL_CTL + 16 * decimator; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + amic_n = tasha_codec_find_amic_input(component, decimator); + if (amic_n) + pwr_level_reg = tasha_codec_get_amic_pwlvl_reg( + component, amic_n); + + if (pwr_level_reg) { + switch ( + (snd_soc_component_read32(component, pwr_level_reg) & + WCD9335_AMIC_PWR_LVL_MASK) >> + WCD9335_AMIC_PWR_LVL_SHIFT) { + case WCD9335_AMIC_PWR_LEVEL_LP: + snd_soc_component_update_bits( + component, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_LP); + break; + + case WCD9335_AMIC_PWR_LEVEL_HP: + snd_soc_component_update_bits( + component, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_HP); + break; + case WCD9335_AMIC_PWR_LEVEL_DEFAULT: + default: + snd_soc_component_update_bits( + component, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_DF); + break; + } + } + hpf_cut_off_freq = ( + snd_soc_component_read32(component, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + tasha->tx_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x01, 0x00); + + if (decimator == 0) { + snd_soc_component_write(component, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(component, + WCD9335_MBHC_ZDET_RAMP_CTL, 0xA3); + snd_soc_component_write(component, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(component, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x03); + } + /* schedule work queue to Remove Mute */ + schedule_delayed_work(&tasha->tx_mute_dwork[decimator].dwork, + msecs_to_jiffies(tx_unmute_delay)); + if (tasha->tx_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) + schedule_delayed_work( + &tasha->tx_hpf_work[decimator].dwork, + msecs_to_jiffies(300)); + /* apply gain after decimator is enabled */ + snd_soc_component_write(component, tx_gain_ctl_reg, + snd_soc_component_read32( + component, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + tasha->tx_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + if (cancel_delayed_work_sync( + &tasha->tx_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + tasha_codec_vote_max_bw(component, true); + snd_soc_component_update_bits(component, + dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + tasha_codec_vote_max_bw(component, false); + } + } + cancel_delayed_work_sync( + &tasha->tx_mute_dwork[decimator].dwork); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x00); + break; + }; +out: + kfree(wname); + return ret; +} + +static u32 tasha_get_dmic_sample_rate(struct snd_soc_component *component, + unsigned int dmic, struct wcd9xxx_pdata *pdata) +{ + u8 tx_stream_fs; + u8 adc_mux_index = 0, adc_mux_sel = 0; + bool dec_found = false; + u16 adc_mux_ctl_reg, tx_fs_reg; + u32 dmic_fs; + + while (dec_found == 0 && adc_mux_index < WCD9335_MAX_VALID_ADC_MUX) { + if (adc_mux_index < 4) { + adc_mux_ctl_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + (adc_mux_index * 2); + adc_mux_sel = ((snd_soc_component_read32(component, + adc_mux_ctl_reg) & 0x78) >> 3) - 1; + } else if (adc_mux_index < 9) { + adc_mux_ctl_reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + ((adc_mux_index - 4) * 1); + adc_mux_sel = ((snd_soc_component_read32( + component, adc_mux_ctl_reg) & 0x38) >> 3) - 1; + } else if (adc_mux_index == 9) { + ++adc_mux_index; + continue; + } + if (adc_mux_sel == dmic) + dec_found = true; + else + ++adc_mux_index; + } + + if (dec_found == true && adc_mux_index <= 8) { + tx_fs_reg = WCD9335_CDC_TX0_TX_PATH_CTL + (16 * adc_mux_index); + tx_stream_fs = + snd_soc_component_read32(component, tx_fs_reg) & 0x0F; + dmic_fs = tx_stream_fs <= 4 ? WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ : + WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ; + + /* + * Check for ECPP path selection and DEC1 not connected to + * any other audio path to apply ECPP DMIC sample rate + */ + if ((adc_mux_index == 1) && + ((snd_soc_component_read32( + component, WCD9335_CPE_SS_US_EC_MUX_CFG) + & 0x0F) == 0x0A) && + ((snd_soc_component_read32( + component, WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0) + & 0x0C) == 0x00)) { + dmic_fs = pdata->ecpp_dmic_sample_rate; + } + } else { + dmic_fs = pdata->dmic_sample_rate; + } + + return dmic_fs; +} + +static u8 tasha_get_dmic_clk_val(struct snd_soc_component *component, + u32 mclk_rate, u32 dmic_clk_rate) +{ + u32 div_factor; + u8 dmic_ctl_val; + + dev_dbg(component->dev, + "%s: mclk_rate = %d, dmic_sample_rate = %d\n", + __func__, mclk_rate, dmic_clk_rate); + + /* Default value to return in case of error */ + if (mclk_rate == TASHA_MCLK_CLK_9P6MHZ) + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + else + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + + if (dmic_clk_rate == 0) { + dev_err(component->dev, + "%s: dmic_sample_rate cannot be 0\n", + __func__); + goto done; + } + + div_factor = mclk_rate / dmic_clk_rate; + switch (div_factor) { + case 2: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + break; + case 3: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + break; + case 4: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4; + break; + case 6: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6; + break; + case 8: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8; + break; + case 16: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16; + break; + default: + dev_err(component->dev, + "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n", + __func__, div_factor, mclk_rate, dmic_clk_rate); + break; + } + +done: + return dmic_ctl_val; +} + +static int tasha_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s: event:%d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tasha_codec_set_tx_hold(component, w->reg, true); + break; + default: + break; + } + + return 0; +} + +static int tasha_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + u8 dmic_rate_val, dmic_rate_shift = 1; + unsigned int dmic; + u32 dmic_sample_rate; + int ret; + char *wname; + + wname = strpbrk(w->name, "012345"); + if (!wname) { + dev_err(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; + } + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(tasha->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC0_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(tasha->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC1_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(tasha->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC2_CTL; + break; + default: + dev_err(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: + dmic_sample_rate = tasha_get_dmic_sample_rate(component, dmic, + pdata); + dmic_rate_val = + tasha_get_dmic_clk_val(component, + pdata->mclk_rate, + dmic_sample_rate); + + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + + break; + case SND_SOC_DAPM_POST_PMD: + dmic_rate_val = + tasha_get_dmic_clk_val(component, + pdata->mclk_rate, + pdata->mad_dmic_sample_rate); + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, 0); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + } + break; + }; + + return 0; +} + +static int __tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_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: + /* + * MIC BIAS can also be requested by MBHC, + * so use ref count to handle micbias pullup + * and enable requests + */ + tasha_micbias_control(component, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* wait for cnp time */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + tasha_micbias_control(component, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int tasha_codec_ldo_h_control(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + tasha->ldo_h_users++; + + if (tasha->ldo_h_users == 1) + snd_soc_component_update_bits(component, + WCD9335_LDOH_MODE, + 0x80, 0x80); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + tasha->ldo_h_users--; + + if (tasha->ldo_h_users < 0) + tasha->ldo_h_users = 0; + + if (tasha->ldo_h_users == 0) + snd_soc_component_update_bits(component, + WCD9335_LDOH_MODE, + 0x80, 0x00); + } + + return 0; +} + +static int tasha_codec_force_enable_ldo_h(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_resmgr_enable_master_bias(tasha->resmgr); + tasha_codec_ldo_h_control(w, event); + break; + case SND_SOC_DAPM_POST_PMD: + tasha_codec_ldo_h_control(w, event); + wcd_resmgr_disable_master_bias(tasha->resmgr); + break; + } + + return 0; +} + +static int tasha_codec_force_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_resmgr_enable_master_bias(tasha->resmgr); + tasha_cdc_mclk_enable(component, true, true); + ret = __tasha_codec_enable_micbias(w, SND_SOC_DAPM_PRE_PMU); + /* Wait for 1ms for better cnp */ + usleep_range(1000, 1100); + tasha_cdc_mclk_enable(component, false, true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = __tasha_codec_enable_micbias(w, SND_SOC_DAPM_POST_PMD); + wcd_resmgr_disable_master_bias(tasha->resmgr); + break; + } + + return ret; +} + +static int tasha_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return __tasha_codec_enable_micbias(w, event); +} + +static int tasha_codec_enable_standalone_ldo_h( + struct snd_soc_component *component, + bool enable) +{ + int rc; + + if (enable) + rc = snd_soc_dapm_force_enable_pin( + snd_soc_component_get_dapm(component), + DAPM_LDO_H_STANDALONE); + else + rc = snd_soc_dapm_disable_pin( + snd_soc_component_get_dapm(component), + DAPM_LDO_H_STANDALONE); + + if (!rc) + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + else + dev_err(component->dev, "%s: ldo_h force %s pin failed\n", + __func__, (enable ? "enable" : "disable")); + + return rc; +} + +/* + * tasha_codec_enable_standalone_micbias - enable micbias standalone + * @component: pointer to codec instance + * @micb_num: number of micbias to be enabled + * @enable: true to enable micbias or false to disable + * + * This function is used to enable micbias (1, 2, 3 or 4) during + * standalone independent of whether TX use-case is running or not + * + * Return: error code in case of failure or 0 for success + */ +int tasha_codec_enable_standalone_micbias(struct snd_soc_component *component, + int micb_num, + bool enable) +{ + const char * const micb_names[] = { + DAPM_MICBIAS1_STANDALONE, DAPM_MICBIAS2_STANDALONE, + DAPM_MICBIAS3_STANDALONE, DAPM_MICBIAS4_STANDALONE + }; + int micb_index = micb_num - 1; + int rc; + + if (!component) { + pr_err("%s: Component memory is NULL\n", __func__); + return -EINVAL; + } + + if ((micb_index < 0) || (micb_index > TASHA_MAX_MICBIAS - 1)) { + dev_err(component->dev, "%s: Invalid micbias index, micb_ind:%d\n", + __func__, micb_index); + return -EINVAL; + } + + if (enable) + rc = snd_soc_dapm_force_enable_pin( + snd_soc_component_get_dapm(component), + micb_names[micb_index]); + else + rc = snd_soc_dapm_disable_pin( + snd_soc_component_get_dapm(component), + micb_names[micb_index]); + + if (!rc) + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + else + dev_err(component->dev, "%s: micbias%d force %s pin failed\n", + __func__, micb_num, (enable ? "enable" : "disable")); + + return rc; +} +EXPORT_SYMBOL(tasha_codec_enable_standalone_micbias); + +static const char *const tasha_anc_func_text[] = {"OFF", "ON"}; +static const struct soc_enum tasha_anc_func_enum = + SOC_ENUM_SINGLE_EXT(2, tasha_anc_func_text); + +static const char *const tasha_clkmode_text[] = {"EXTERNAL", "INTERNAL"}; +static SOC_ENUM_SINGLE_EXT_DECL(tasha_clkmode_enum, tasha_clkmode_text); + +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static const char * const rx_cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ", + "CF_NEG_3DB_0P48HZ" +}; + +static const struct soc_enum cf_dec0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX0_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX1_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX2_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX3_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX4_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX5_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX6_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX7_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX8_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_int0_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int1_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int2_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int3_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int4_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int5_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int5_2_enum, WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int6_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int6_2_enum, WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int7_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int8_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct snd_soc_dapm_route audio_i2s_map[] = { + {"SLIM RX0 MUX", NULL, "RX_I2S_CTL"}, + {"SLIM RX1 MUX", NULL, "RX_I2S_CTL"}, + {"SLIM RX2 MUX", NULL, "RX_I2S_CTL"}, + {"SLIM RX3 MUX", NULL, "RX_I2S_CTL"}, + + {"SLIM TX6 MUX", NULL, "TX_I2S_CTL"}, + {"SLIM TX7 MUX", NULL, "TX_I2S_CTL"}, + {"SLIM TX8 MUX", NULL, "TX_I2S_CTL"}, + {"SLIM TX11 MUX", NULL, "TX_I2S_CTL"}, +}; + +static const struct snd_soc_dapm_route audio_map[] = { + + /* MAD */ + {"MAD_SEL MUX", "SPE", "MAD_CPE_INPUT"}, + {"MAD_SEL MUX", "MSM", "MADINPUT"}, + {"MADONOFF", "Switch", "MAD_SEL MUX"}, + {"MAD_BROADCAST", "Switch", "MAD_SEL MUX"}, + {"TX13 INP MUX", "CPE_TX_PP", "MADONOFF"}, + + /* CPE HW MAD bypass */ + {"CPE IN Mixer", "MAD_BYPASS", "SLIM TX1 MUX"}, + + {"AIF4_MAD Mixer", "SLIM TX1", "CPE IN Mixer"}, + {"AIF4_MAD Mixer", "SLIM TX12", "MADONOFF"}, + {"AIF4_MAD Mixer", "SLIM TX13", "TX13 INP MUX"}, + {"AIF4 MAD", NULL, "AIF4_MAD Mixer"}, + {"AIF4 MAD", NULL, "AIF4"}, + + {"EC BUF MUX INP", "DEC1", "ADC MUX1"}, + {"AIF5 CPE", NULL, "EC BUF MUX INP"}, + + /* SLIMBUS Connections */ + {"AIF1 CAP", NULL, "AIF1_CAP Mixer"}, + {"AIF2 CAP", NULL, "AIF2_CAP Mixer"}, + {"AIF3 CAP", NULL, "AIF3_CAP Mixer"}, + + /* VI Feedback */ + {"AIF4_VI Mixer", "SPKR_VI_1", "VIINPUT"}, + {"AIF4_VI Mixer", "SPKR_VI_2", "VIINPUT"}, + {"AIF4 VI", NULL, "AIF4_VI Mixer"}, + + /* SLIM_MIXER("AIF1_CAP Mixer"),*/ + {"AIF1_CAP Mixer", "SLIM TX0", "SLIM TX0 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX11", "SLIM TX11 MUX"}, + {"AIF1_CAP Mixer", "SLIM TX13", "TX13 INP MUX"}, + /* SLIM_MIXER("AIF2_CAP Mixer"),*/ + {"AIF2_CAP Mixer", "SLIM TX0", "SLIM TX0 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX11", "SLIM TX11 MUX"}, + {"AIF2_CAP Mixer", "SLIM TX13", "TX13 INP MUX"}, + /* SLIM_MIXER("AIF3_CAP Mixer"),*/ + {"AIF3_CAP Mixer", "SLIM TX0", "SLIM TX0 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX11", "SLIM TX11 MUX"}, + {"AIF3_CAP Mixer", "SLIM TX13", "TX13 INP MUX"}, + + {"SLIM TX0 MUX", "DEC0", "ADC MUX0"}, + {"SLIM TX0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"}, + {"SLIM TX0 MUX", "DEC0_192", "ADC US MUX0"}, + + {"SLIM TX1 MUX", "DEC1", "ADC MUX1"}, + {"SLIM TX1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"}, + {"SLIM TX1 MUX", "DEC1_192", "ADC US MUX1"}, + + {"SLIM TX2 MUX", "DEC2", "ADC MUX2"}, + {"SLIM TX2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"}, + {"SLIM TX2 MUX", "DEC2_192", "ADC US MUX2"}, + + {"SLIM TX3 MUX", "DEC3", "ADC MUX3"}, + {"SLIM TX3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"}, + {"SLIM TX3 MUX", "DEC3_192", "ADC US MUX3"}, + + {"SLIM TX4 MUX", "DEC4", "ADC MUX4"}, + {"SLIM TX4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"}, + {"SLIM TX4 MUX", "DEC4_192", "ADC US MUX4"}, + + {"SLIM TX5 MUX", "DEC5", "ADC MUX5"}, + {"SLIM TX5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"}, + {"SLIM TX5 MUX", "DEC5_192", "ADC US MUX5"}, + + {"SLIM TX6 MUX", "DEC6", "ADC MUX6"}, + {"SLIM TX6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"}, + {"SLIM TX6 MUX", "DEC6_192", "ADC US MUX6"}, + + {"SLIM TX7 MUX", "DEC7", "ADC MUX7"}, + {"SLIM TX7 MUX", "RX_MIX_TX7", "RX MIX TX7 MUX"}, + {"SLIM TX7 MUX", "DEC7_192", "ADC US MUX7"}, + + {"SLIM TX8 MUX", "DEC8", "ADC MUX8"}, + {"SLIM TX8 MUX", "RX_MIX_TX8", "RX MIX TX8 MUX"}, + {"SLIM TX8 MUX", "DEC8_192", "ADC US MUX8"}, + + {"SLIM TX9 MUX", "DEC7", "ADC MUX7"}, + {"SLIM TX9 MUX", "DEC7_192", "ADC US MUX7"}, + {"SLIM TX10 MUX", "DEC6", "ADC MUX6"}, + {"SLIM TX10 MUX", "DEC6_192", "ADC US MUX6"}, + + {"SLIM TX11 MUX", "DEC_0_5", "SLIM TX11 INP1 MUX"}, + {"SLIM TX11 MUX", "DEC_9_12", "SLIM TX11 INP1 MUX"}, + {"SLIM TX11 INP1 MUX", "DEC0", "ADC MUX0"}, + {"SLIM TX11 INP1 MUX", "DEC1", "ADC MUX1"}, + {"SLIM TX11 INP1 MUX", "DEC2", "ADC MUX2"}, + {"SLIM TX11 INP1 MUX", "DEC3", "ADC MUX3"}, + {"SLIM TX11 INP1 MUX", "DEC4", "ADC MUX4"}, + {"SLIM TX11 INP1 MUX", "DEC5", "ADC MUX5"}, + {"SLIM TX11 INP1 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"}, + + {"TX13 INP MUX", "MAD_BRDCST", "MAD_BROADCAST"}, + {"TX13 INP MUX", "CDC_DEC_5", "SLIM TX13 MUX"}, + {"SLIM TX13 MUX", "DEC5", "ADC MUX5"}, + + {"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX0 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX0 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX0 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX1 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX1 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX1 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX2 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX2 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX2 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX3 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX3 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX3 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX3 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX4 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX4 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX4 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX4 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX5 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX5 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX5 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX5 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX6 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX6 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX6 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX6 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX7 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX7 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX7 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX7 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"RX MIX TX8 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX5", "RX INT5 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX6", "RX INT6 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX_VBAT5", "RX INT5 VBAT"}, + {"RX MIX TX8 MUX", "RX_MIX_VBAT6", "RX INT6 VBAT"}, + {"RX MIX TX8 MUX", "RX_MIX_VBAT7", "RX INT7 VBAT"}, + {"RX MIX TX8 MUX", "RX_MIX_VBAT8", "RX INT8 VBAT"}, + + {"ADC US MUX0", "US_Switch", "ADC MUX0"}, + {"ADC US MUX1", "US_Switch", "ADC MUX1"}, + {"ADC US MUX2", "US_Switch", "ADC MUX2"}, + {"ADC US MUX3", "US_Switch", "ADC MUX3"}, + {"ADC US MUX4", "US_Switch", "ADC MUX4"}, + {"ADC US MUX5", "US_Switch", "ADC MUX5"}, + {"ADC US MUX6", "US_Switch", "ADC MUX6"}, + {"ADC US MUX7", "US_Switch", "ADC MUX7"}, + {"ADC US MUX8", "US_Switch", "ADC MUX8"}, + {"ADC MUX0", "DMIC", "DMIC MUX0"}, + {"ADC MUX0", "AMIC", "AMIC MUX0"}, + {"ADC MUX1", "DMIC", "DMIC MUX1"}, + {"ADC MUX1", "AMIC", "AMIC MUX1"}, + {"ADC MUX2", "DMIC", "DMIC MUX2"}, + {"ADC MUX2", "AMIC", "AMIC MUX2"}, + {"ADC MUX3", "DMIC", "DMIC MUX3"}, + {"ADC MUX3", "AMIC", "AMIC MUX3"}, + {"ADC MUX4", "DMIC", "DMIC MUX4"}, + {"ADC MUX4", "AMIC", "AMIC MUX4"}, + {"ADC MUX5", "DMIC", "DMIC MUX5"}, + {"ADC MUX5", "AMIC", "AMIC MUX5"}, + {"ADC MUX6", "DMIC", "DMIC MUX6"}, + {"ADC MUX6", "AMIC", "AMIC MUX6"}, + {"ADC MUX7", "DMIC", "DMIC MUX7"}, + {"ADC MUX7", "AMIC", "AMIC MUX7"}, + {"ADC MUX8", "DMIC", "DMIC MUX8"}, + {"ADC MUX8", "AMIC", "AMIC MUX8"}, + {"ADC MUX10", "DMIC", "DMIC MUX10"}, + {"ADC MUX10", "AMIC", "AMIC MUX10"}, + {"ADC MUX11", "DMIC", "DMIC MUX11"}, + {"ADC MUX11", "AMIC", "AMIC MUX11"}, + {"ADC MUX12", "DMIC", "DMIC MUX12"}, + {"ADC MUX12", "AMIC", "AMIC MUX12"}, + {"ADC MUX13", "DMIC", "DMIC MUX13"}, + {"ADC MUX13", "AMIC", "AMIC MUX13"}, + + {"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX13"}, + + {"DMIC MUX0", "DMIC0", "DMIC0"}, + {"DMIC MUX0", "DMIC1", "DMIC1"}, + {"DMIC MUX0", "DMIC2", "DMIC2"}, + {"DMIC MUX0", "DMIC3", "DMIC3"}, + {"DMIC MUX0", "DMIC4", "DMIC4"}, + {"DMIC MUX0", "DMIC5", "DMIC5"}, + {"AMIC MUX0", "ADC1", "ADC1"}, + {"AMIC MUX0", "ADC2", "ADC2"}, + {"AMIC MUX0", "ADC3", "ADC3"}, + {"AMIC MUX0", "ADC4", "ADC4"}, + {"AMIC MUX0", "ADC5", "ADC5"}, + {"AMIC MUX0", "ADC6", "ADC6"}, + + {"DMIC MUX1", "DMIC0", "DMIC0"}, + {"DMIC MUX1", "DMIC1", "DMIC1"}, + {"DMIC MUX1", "DMIC2", "DMIC2"}, + {"DMIC MUX1", "DMIC3", "DMIC3"}, + {"DMIC MUX1", "DMIC4", "DMIC4"}, + {"DMIC MUX1", "DMIC5", "DMIC5"}, + {"AMIC MUX1", "ADC1", "ADC1"}, + {"AMIC MUX1", "ADC2", "ADC2"}, + {"AMIC MUX1", "ADC3", "ADC3"}, + {"AMIC MUX1", "ADC4", "ADC4"}, + {"AMIC MUX1", "ADC5", "ADC5"}, + {"AMIC MUX1", "ADC6", "ADC6"}, + + {"DMIC MUX2", "DMIC0", "DMIC0"}, + {"DMIC MUX2", "DMIC1", "DMIC1"}, + {"DMIC MUX2", "DMIC2", "DMIC2"}, + {"DMIC MUX2", "DMIC3", "DMIC3"}, + {"DMIC MUX2", "DMIC4", "DMIC4"}, + {"DMIC MUX2", "DMIC5", "DMIC5"}, + {"AMIC MUX2", "ADC1", "ADC1"}, + {"AMIC MUX2", "ADC2", "ADC2"}, + {"AMIC MUX2", "ADC3", "ADC3"}, + {"AMIC MUX2", "ADC4", "ADC4"}, + {"AMIC MUX2", "ADC5", "ADC5"}, + {"AMIC MUX2", "ADC6", "ADC6"}, + + {"DMIC MUX3", "DMIC0", "DMIC0"}, + {"DMIC MUX3", "DMIC1", "DMIC1"}, + {"DMIC MUX3", "DMIC2", "DMIC2"}, + {"DMIC MUX3", "DMIC3", "DMIC3"}, + {"DMIC MUX3", "DMIC4", "DMIC4"}, + {"DMIC MUX3", "DMIC5", "DMIC5"}, + {"AMIC MUX3", "ADC1", "ADC1"}, + {"AMIC MUX3", "ADC2", "ADC2"}, + {"AMIC MUX3", "ADC3", "ADC3"}, + {"AMIC MUX3", "ADC4", "ADC4"}, + {"AMIC MUX3", "ADC5", "ADC5"}, + {"AMIC MUX3", "ADC6", "ADC6"}, + + {"DMIC MUX4", "DMIC0", "DMIC0"}, + {"DMIC MUX4", "DMIC1", "DMIC1"}, + {"DMIC MUX4", "DMIC2", "DMIC2"}, + {"DMIC MUX4", "DMIC3", "DMIC3"}, + {"DMIC MUX4", "DMIC4", "DMIC4"}, + {"DMIC MUX4", "DMIC5", "DMIC5"}, + {"AMIC MUX4", "ADC1", "ADC1"}, + {"AMIC MUX4", "ADC2", "ADC2"}, + {"AMIC MUX4", "ADC3", "ADC3"}, + {"AMIC MUX4", "ADC4", "ADC4"}, + {"AMIC MUX4", "ADC5", "ADC5"}, + {"AMIC MUX4", "ADC6", "ADC6"}, + + {"DMIC MUX5", "DMIC0", "DMIC0"}, + {"DMIC MUX5", "DMIC1", "DMIC1"}, + {"DMIC MUX5", "DMIC2", "DMIC2"}, + {"DMIC MUX5", "DMIC3", "DMIC3"}, + {"DMIC MUX5", "DMIC4", "DMIC4"}, + {"DMIC MUX5", "DMIC5", "DMIC5"}, + {"AMIC MUX5", "ADC1", "ADC1"}, + {"AMIC MUX5", "ADC2", "ADC2"}, + {"AMIC MUX5", "ADC3", "ADC3"}, + {"AMIC MUX5", "ADC4", "ADC4"}, + {"AMIC MUX5", "ADC5", "ADC5"}, + {"AMIC MUX5", "ADC6", "ADC6"}, + + {"DMIC MUX6", "DMIC0", "DMIC0"}, + {"DMIC MUX6", "DMIC1", "DMIC1"}, + {"DMIC MUX6", "DMIC2", "DMIC2"}, + {"DMIC MUX6", "DMIC3", "DMIC3"}, + {"DMIC MUX6", "DMIC4", "DMIC4"}, + {"DMIC MUX6", "DMIC5", "DMIC5"}, + {"AMIC MUX6", "ADC1", "ADC1"}, + {"AMIC MUX6", "ADC2", "ADC2"}, + {"AMIC MUX6", "ADC3", "ADC3"}, + {"AMIC MUX6", "ADC4", "ADC4"}, + {"AMIC MUX6", "ADC5", "ADC5"}, + {"AMIC MUX6", "ADC6", "ADC6"}, + + {"DMIC MUX7", "DMIC0", "DMIC0"}, + {"DMIC MUX7", "DMIC1", "DMIC1"}, + {"DMIC MUX7", "DMIC2", "DMIC2"}, + {"DMIC MUX7", "DMIC3", "DMIC3"}, + {"DMIC MUX7", "DMIC4", "DMIC4"}, + {"DMIC MUX7", "DMIC5", "DMIC5"}, + {"AMIC MUX7", "ADC1", "ADC1"}, + {"AMIC MUX7", "ADC2", "ADC2"}, + {"AMIC MUX7", "ADC3", "ADC3"}, + {"AMIC MUX7", "ADC4", "ADC4"}, + {"AMIC MUX7", "ADC5", "ADC5"}, + {"AMIC MUX7", "ADC6", "ADC6"}, + + {"DMIC MUX8", "DMIC0", "DMIC0"}, + {"DMIC MUX8", "DMIC1", "DMIC1"}, + {"DMIC MUX8", "DMIC2", "DMIC2"}, + {"DMIC MUX8", "DMIC3", "DMIC3"}, + {"DMIC MUX8", "DMIC4", "DMIC4"}, + {"DMIC MUX8", "DMIC5", "DMIC5"}, + {"AMIC MUX8", "ADC1", "ADC1"}, + {"AMIC MUX8", "ADC2", "ADC2"}, + {"AMIC MUX8", "ADC3", "ADC3"}, + {"AMIC MUX8", "ADC4", "ADC4"}, + {"AMIC MUX8", "ADC5", "ADC5"}, + {"AMIC MUX8", "ADC6", "ADC6"}, + + {"DMIC MUX10", "DMIC0", "DMIC0"}, + {"DMIC MUX10", "DMIC1", "DMIC1"}, + {"DMIC MUX10", "DMIC2", "DMIC2"}, + {"DMIC MUX10", "DMIC3", "DMIC3"}, + {"DMIC MUX10", "DMIC4", "DMIC4"}, + {"DMIC MUX10", "DMIC5", "DMIC5"}, + {"AMIC MUX10", "ADC1", "ADC1"}, + {"AMIC MUX10", "ADC2", "ADC2"}, + {"AMIC MUX10", "ADC3", "ADC3"}, + {"AMIC MUX10", "ADC4", "ADC4"}, + {"AMIC MUX10", "ADC5", "ADC5"}, + {"AMIC MUX10", "ADC6", "ADC6"}, + + {"DMIC MUX11", "DMIC0", "DMIC0"}, + {"DMIC MUX11", "DMIC1", "DMIC1"}, + {"DMIC MUX11", "DMIC2", "DMIC2"}, + {"DMIC MUX11", "DMIC3", "DMIC3"}, + {"DMIC MUX11", "DMIC4", "DMIC4"}, + {"DMIC MUX11", "DMIC5", "DMIC5"}, + {"AMIC MUX11", "ADC1", "ADC1"}, + {"AMIC MUX11", "ADC2", "ADC2"}, + {"AMIC MUX11", "ADC3", "ADC3"}, + {"AMIC MUX11", "ADC4", "ADC4"}, + {"AMIC MUX11", "ADC5", "ADC5"}, + {"AMIC MUX11", "ADC6", "ADC6"}, + + {"DMIC MUX12", "DMIC0", "DMIC0"}, + {"DMIC MUX12", "DMIC1", "DMIC1"}, + {"DMIC MUX12", "DMIC2", "DMIC2"}, + {"DMIC MUX12", "DMIC3", "DMIC3"}, + {"DMIC MUX12", "DMIC4", "DMIC4"}, + {"DMIC MUX12", "DMIC5", "DMIC5"}, + {"AMIC MUX12", "ADC1", "ADC1"}, + {"AMIC MUX12", "ADC2", "ADC2"}, + {"AMIC MUX12", "ADC3", "ADC3"}, + {"AMIC MUX12", "ADC4", "ADC4"}, + {"AMIC MUX12", "ADC5", "ADC5"}, + {"AMIC MUX12", "ADC6", "ADC6"}, + + {"DMIC MUX13", "DMIC0", "DMIC0"}, + {"DMIC MUX13", "DMIC1", "DMIC1"}, + {"DMIC MUX13", "DMIC2", "DMIC2"}, + {"DMIC MUX13", "DMIC3", "DMIC3"}, + {"DMIC MUX13", "DMIC4", "DMIC4"}, + {"DMIC MUX13", "DMIC5", "DMIC5"}, + {"AMIC MUX13", "ADC1", "ADC1"}, + {"AMIC MUX13", "ADC2", "ADC2"}, + {"AMIC MUX13", "ADC3", "ADC3"}, + {"AMIC MUX13", "ADC4", "ADC4"}, + {"AMIC MUX13", "ADC5", "ADC5"}, + {"AMIC MUX13", "ADC6", "ADC6"}, + /* ADC Connections */ + {"ADC1", NULL, "AMIC1"}, + {"ADC2", NULL, "AMIC2"}, + {"ADC3", NULL, "AMIC3"}, + {"ADC4", NULL, "AMIC4"}, + {"ADC5", NULL, "AMIC5"}, + {"ADC6", NULL, "AMIC6"}, + + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP0"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP1"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP2"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP0"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP1"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP2"}, + {"RX INT5_1 MIX1", NULL, "RX INT5_1 MIX1 INP0"}, + {"RX INT5_1 MIX1", NULL, "RX INT5_1 MIX1 INP1"}, + {"RX INT5_1 MIX1", NULL, "RX INT5_1 MIX1 INP2"}, + {"RX INT6_1 MIX1", NULL, "RX INT6_1 MIX1 INP0"}, + {"RX INT6_1 MIX1", NULL, "RX INT6_1 MIX1 INP1"}, + {"RX INT6_1 MIX1", NULL, "RX INT6_1 MIX1 INP2"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP0"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP1"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP2"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP0"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP1"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP2"}, + + {"RX INT0 SEC MIX", NULL, "RX INT0_1 MIX1"}, + {"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"}, + {"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"}, + {"RX INT0 INTERP", NULL, "RX INT0 MIX2"}, + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 INTERP"}, + {"RX INT0 DAC", NULL, "RX INT0 DEM MUX"}, + {"RX INT0 DAC", NULL, "RX_BIAS"}, + {"EAR PA", NULL, "RX INT0 DAC"}, + {"EAR", NULL, "EAR PA"}, + + {"SPL SRC0 MUX", "SRC_IN_HPHL", "RX INT1_1 MIX1"}, + {"RX INT1 SPLINE MIX", NULL, "RX INT1_1 MIX1"}, + {"RX INT1 SPLINE MIX", "HPHL Switch", "SPL SRC0 MUX"}, + {"RX INT1_1 NATIVE MUX", "ON", "RX INT1_1 MIX1"}, + {"RX INT1 SPLINE MIX", NULL, "RX INT1_1 NATIVE MUX"}, + {"RX INT1_1 NATIVE MUX", NULL, "RX INT1 NATIVE SUPPLY"}, + {"RX INT1 SEC MIX", NULL, "RX INT1 SPLINE MIX"}, + {"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"}, + {"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"}, + {"RX INT1 INTERP", NULL, "RX INT1 MIX2"}, + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"}, + {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"}, + {"RX INT1 DAC", NULL, "RX_BIAS"}, + {"HPHL PA", NULL, "RX INT1 DAC"}, + {"HPHL", NULL, "HPHL PA"}, + + {"SPL SRC1 MUX", "SRC_IN_HPHR", "RX INT2_1 MIX1"}, + {"RX INT2 SPLINE MIX", NULL, "RX INT2_1 MIX1"}, + {"RX INT2 SPLINE MIX", "HPHR Switch", "SPL SRC1 MUX"}, + {"RX INT2_1 NATIVE MUX", "ON", "RX INT2_1 MIX1"}, + {"RX INT2 SPLINE MIX", NULL, "RX INT2_1 NATIVE MUX"}, + {"RX INT2_1 NATIVE MUX", NULL, "RX INT2 NATIVE SUPPLY"}, + {"RX INT2 SEC MIX", NULL, "RX INT2 SPLINE MIX"}, + {"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"}, + {"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"}, + {"RX INT2 INTERP", NULL, "RX INT2 MIX2"}, + {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"}, + {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"}, + {"RX INT2 DAC", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "RX INT2 DAC"}, + {"HPHR", NULL, "HPHR PA"}, + + {"SPL SRC0 MUX", "SRC_IN_LO1", "RX INT3_1 MIX1"}, + {"RX INT3 SPLINE MIX", NULL, "RX INT3_1 MIX1"}, + {"RX INT3 SPLINE MIX", "LO1 Switch", "SPL SRC0 MUX"}, + {"RX INT3_1 NATIVE MUX", "ON", "RX INT3_1 MIX1"}, + {"RX INT3 SPLINE MIX", NULL, "RX INT3_1 NATIVE MUX"}, + {"RX INT3_1 NATIVE MUX", NULL, "RX INT3 NATIVE SUPPLY"}, + {"RX INT3 SEC MIX", NULL, "RX INT3 SPLINE MIX"}, + {"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"}, + {"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"}, + {"RX INT3 INTERP", NULL, "RX INT3 MIX2"}, + {"RX INT3 DAC", NULL, "RX INT3 INTERP"}, + {"RX INT3 DAC", NULL, "RX_BIAS"}, + {"LINEOUT1 PA", NULL, "RX INT3 DAC"}, + {"LINEOUT1", NULL, "LINEOUT1 PA"}, + + {"SPL SRC1 MUX", "SRC_IN_LO2", "RX INT4_1 MIX1"}, + {"RX INT4 SPLINE MIX", NULL, "RX INT4_1 MIX1"}, + {"RX INT4 SPLINE MIX", "LO2 Switch", "SPL SRC1 MUX"}, + {"RX INT4_1 NATIVE MUX", "ON", "RX INT4_1 MIX1"}, + {"RX INT4 SPLINE MIX", NULL, "RX INT4_1 NATIVE MUX"}, + {"RX INT4_1 NATIVE MUX", NULL, "RX INT4 NATIVE SUPPLY"}, + {"RX INT4 SEC MIX", NULL, "RX INT4 SPLINE MIX"}, + {"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"}, + {"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"}, + {"RX INT4 INTERP", NULL, "RX INT4 MIX2"}, + {"RX INT4 DAC", NULL, "RX INT4 INTERP"}, + {"RX INT4 DAC", NULL, "RX_BIAS"}, + {"LINEOUT2 PA", NULL, "RX INT4 DAC"}, + {"LINEOUT2", NULL, "LINEOUT2 PA"}, + + {"SPL SRC2 MUX", "SRC_IN_LO3", "RX INT5_1 MIX1"}, + {"RX INT5 SPLINE MIX", NULL, "RX INT5_1 MIX1"}, + {"RX INT5 SPLINE MIX", "LO3 Switch", "SPL SRC2 MUX"}, + {"RX INT5 SEC MIX", NULL, "RX INT5 SPLINE MIX"}, + {"RX INT5 MIX2", NULL, "RX INT5 SEC MIX"}, + {"RX INT5 INTERP", NULL, "RX INT5 MIX2"}, + + {"RX INT5 VBAT", "LO3 VBAT Enable", "RX INT5 INTERP"}, + {"RX INT5 DAC", NULL, "RX INT5 VBAT"}, + + {"RX INT5 DAC", NULL, "RX INT5 INTERP"}, + {"RX INT5 DAC", NULL, "RX_BIAS"}, + {"LINEOUT3 PA", NULL, "RX INT5 DAC"}, + {"LINEOUT3", NULL, "LINEOUT3 PA"}, + + {"SPL SRC3 MUX", "SRC_IN_LO4", "RX INT6_1 MIX1"}, + {"RX INT6 SPLINE MIX", NULL, "RX INT6_1 MIX1"}, + {"RX INT6 SPLINE MIX", "LO4 Switch", "SPL SRC3 MUX"}, + {"RX INT6 SEC MIX", NULL, "RX INT6 SPLINE MIX"}, + {"RX INT6 MIX2", NULL, "RX INT6 SEC MIX"}, + {"RX INT6 INTERP", NULL, "RX INT6 MIX2"}, + + {"RX INT6 VBAT", "LO4 VBAT Enable", "RX INT6 INTERP"}, + {"RX INT6 DAC", NULL, "RX INT6 VBAT"}, + + {"RX INT6 DAC", NULL, "RX INT6 INTERP"}, + {"RX INT6 DAC", NULL, "RX_BIAS"}, + {"LINEOUT4 PA", NULL, "RX INT6 DAC"}, + {"LINEOUT4", NULL, "LINEOUT4 PA"}, + + {"SPL SRC2 MUX", "SRC_IN_SPKRL", "RX INT7_1 MIX1"}, + {"RX INT7 SPLINE MIX", NULL, "RX INT7_1 MIX1"}, + {"RX INT7 SPLINE MIX", "SPKRL Switch", "SPL SRC2 MUX"}, + {"RX INT7 SEC MIX", NULL, "RX INT7 SPLINE MIX"}, + {"RX INT7 MIX2", NULL, "RX INT7 SEC MIX"}, + {"RX INT7 MIX2", NULL, "RX INT7 MIX2 INP"}, + + {"RX INT7 INTERP", NULL, "RX INT7 MIX2"}, + + {"RX INT7 VBAT", "SPKRL VBAT Enable", "RX INT7 INTERP"}, + {"RX INT7 CHAIN", NULL, "RX INT7 VBAT"}, + + {"RX INT7 CHAIN", NULL, "RX INT7 INTERP"}, + {"RX INT7 CHAIN", NULL, "RX_BIAS"}, + {"SPK1 OUT", NULL, "RX INT7 CHAIN"}, + + {"ANC SPKR PA Enable", "Switch", "RX INT7 CHAIN"}, + {"ANC SPK1 PA", NULL, "ANC SPKR PA Enable"}, + {"SPK1 OUT", NULL, "ANC SPK1 PA"}, + + {"SPL SRC3 MUX", "SRC_IN_SPKRR", "RX INT8_1 MIX1"}, + {"RX INT8 SPLINE MIX", NULL, "RX INT8_1 MIX1"}, + {"RX INT8 SPLINE MIX", "SPKRR Switch", "SPL SRC3 MUX"}, + {"RX INT8 SEC MIX", NULL, "RX INT8 SPLINE MIX"}, + {"RX INT8 INTERP", NULL, "RX INT8 SEC MIX"}, + + {"RX INT8 VBAT", "SPKRR VBAT Enable", "RX INT8 INTERP"}, + {"RX INT8 CHAIN", NULL, "RX INT8 VBAT"}, + + {"RX INT8 CHAIN", NULL, "RX INT8 INTERP"}, + {"RX INT8 CHAIN", NULL, "RX_BIAS"}, + {"SPK2 OUT", NULL, "RX INT8 CHAIN"}, + + {"ANC0 FB MUX", "ANC_IN_EAR", "RX INT0 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_HPHL", "RX INT1 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_LO1", "RX INT3 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_EAR_SPKR", "RX INT7 MIX2"}, + {"ANC1 FB MUX", "ANC_IN_HPHR", "RX INT2 MIX2"}, + {"ANC1 FB MUX", "ANC_IN_LO2", "RX INT4 MIX2"}, + + {"ANC HPHL Enable", "Switch", "ADC MUX10"}, + {"ANC HPHL Enable", "Switch", "ADC MUX11"}, + {"RX INT1 MIX2", NULL, "ANC HPHL Enable"}, + + {"ANC HPHR Enable", "Switch", "ADC MUX12"}, + {"ANC HPHR Enable", "Switch", "ADC MUX13"}, + {"RX INT2 MIX2", NULL, "ANC HPHR Enable"}, + + {"ANC EAR Enable", "Switch", "ADC MUX10"}, + {"ANC EAR Enable", "Switch", "ADC MUX11"}, + {"RX INT0 MIX2", NULL, "ANC EAR Enable"}, + + {"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX10"}, + {"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX11"}, + {"RX INT7 MIX2", NULL, "ANC OUT EAR SPKR Enable"}, + + {"ANC LINEOUT1 Enable", "Switch", "ADC MUX10"}, + {"ANC LINEOUT1 Enable", "Switch", "ADC MUX11"}, + {"RX INT3 MIX2", NULL, "ANC LINEOUT1 Enable"}, + + {"ANC LINEOUT2 Enable", "Switch", "ADC MUX12"}, + {"ANC LINEOUT2 Enable", "Switch", "ADC MUX13"}, + {"RX INT4 MIX2", NULL, "ANC LINEOUT2 Enable"}, + + {"ANC EAR PA", NULL, "RX INT0 DAC"}, + {"ANC EAR", NULL, "ANC EAR PA"}, + {"ANC HPHL PA", NULL, "RX INT1 DAC"}, + {"ANC HPHL", NULL, "ANC HPHL PA"}, + {"ANC HPHR PA", NULL, "RX INT2 DAC"}, + {"ANC HPHR", NULL, "ANC HPHR PA"}, + {"ANC LINEOUT1 PA", NULL, "RX INT3 DAC"}, + {"ANC LINEOUT1", NULL, "ANC LINEOUT1 PA"}, + {"ANC LINEOUT2 PA", NULL, "RX INT4 DAC"}, + {"ANC LINEOUT2", NULL, "ANC LINEOUT2 PA"}, + + /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/ + {"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"}, + /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/ + {"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"}, + /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/ + {"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"}, + /* SLIM_MUX("AIF4_PB", "AIF4 PB"),*/ + {"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"}, + + /* SLIM_MUX("AIF_MIX1_PB", "AIF MIX1 PB"),*/ + {"SLIM RX0 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + {"SLIM RX1 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + {"SLIM RX2 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + {"SLIM RX3 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + {"SLIM RX4 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + {"SLIM RX5 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + {"SLIM RX6 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + {"SLIM RX7 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"}, + + {"SLIM RX0", NULL, "SLIM RX0 MUX"}, + {"SLIM RX1", NULL, "SLIM RX1 MUX"}, + {"SLIM RX2", NULL, "SLIM RX2 MUX"}, + {"SLIM RX3", NULL, "SLIM RX3 MUX"}, + {"SLIM RX4", NULL, "SLIM RX4 MUX"}, + {"SLIM RX5", NULL, "SLIM RX5 MUX"}, + {"SLIM RX6", NULL, "SLIM RX6 MUX"}, + {"SLIM RX7", NULL, "SLIM RX7 MUX"}, + + {"RX INT0_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT0_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT0_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT0_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT0_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT0_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT0_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT0_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT0_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT0_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT0_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT0_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT0_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT0_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT0_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT0_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT0_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT0_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT0_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT0_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT0_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT0_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"}, + + /* MIXing path INT0 */ + {"RX INT0_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT0_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT0_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT0_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT0_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT0_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT0_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT0_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_2 MUX"}, + + /* MIXing path INT1 */ + {"RX INT1_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT1_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT1_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT1_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT1_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT1_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT1_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT1_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_2 MUX"}, + + /* MIXing path INT2 */ + {"RX INT2_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT2_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT2_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT2_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT2_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT2_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT2_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT2_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_2 MUX"}, + + /* MIXing path INT3 */ + {"RX INT3_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT3_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT3_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT3_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT3_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT3_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT3_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT3_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT3 SEC MIX", NULL, "RX INT3_2 MUX"}, + + /* MIXing path INT4 */ + {"RX INT4_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT4_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT4_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT4_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT4_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT4_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT4_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT4_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT4 SEC MIX", NULL, "RX INT4_2 MUX"}, + + /* MIXing path INT5 */ + {"RX INT5_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT5_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT5_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT5_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT5_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT5_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT5_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT5_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT5 SEC MIX", NULL, "RX INT5_2 MUX"}, + + /* MIXing path INT6 */ + {"RX INT6_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT6_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT6_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT6_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT6_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT6_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT6_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT6_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT6 SEC MIX", NULL, "RX INT6_2 MUX"}, + + /* MIXing path INT7 */ + {"RX INT7_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT7_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT7_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT7_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT7_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT7_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT7_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT7_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT7 SEC MIX", NULL, "RX INT7_2 MUX"}, + + /* MIXing path INT8 */ + {"RX INT8_2 MUX", "RX0", "SLIM RX0"}, + {"RX INT8_2 MUX", "RX1", "SLIM RX1"}, + {"RX INT8_2 MUX", "RX2", "SLIM RX2"}, + {"RX INT8_2 MUX", "RX3", "SLIM RX3"}, + {"RX INT8_2 MUX", "RX4", "SLIM RX4"}, + {"RX INT8_2 MUX", "RX5", "SLIM RX5"}, + {"RX INT8_2 MUX", "RX6", "SLIM RX6"}, + {"RX INT8_2 MUX", "RX7", "SLIM RX7"}, + {"RX INT8 SEC MIX", NULL, "RX INT8_2 MUX"}, + + {"RX INT1_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT1_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT1_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT1_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT1_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT1_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT1_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT1_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT1_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT1_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT1_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT1_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT1_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT1_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT1_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT1_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT1_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT1_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT1_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT1_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT1_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT1_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT2_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT2_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT2_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT2_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT2_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT2_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT2_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT2_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT2_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT2_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT2_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT2_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT2_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT2_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT2_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT2_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT2_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT2_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT2_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT2_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT2_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT3_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT3_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT3_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT3_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT3_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT3_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT3_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT3_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT3_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT3_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT3_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT3_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT3_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT3_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT3_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT3_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT3_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT3_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT3_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT3_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT3_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT3_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT3_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT3_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT3_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT3_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT3_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT4_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT4_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT4_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT4_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT4_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT4_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT4_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT4_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT4_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT4_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT4_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT4_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT4_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT4_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT4_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT4_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT4_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT4_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT4_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT4_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT4_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT4_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT4_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT4_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT4_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT4_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT4_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT5_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT5_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT5_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT5_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT5_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT5_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT5_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT5_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT5_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT5_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT5_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT5_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT5_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT5_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT5_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT5_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT5_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT5_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT5_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT5_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT5_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT5_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT5_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT5_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT5_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT5_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT5_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT5_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT5_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT5_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT6_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT6_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT6_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT6_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT6_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT6_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT6_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT6_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT6_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT6_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT6_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT6_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT6_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT6_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT6_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT6_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT6_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT6_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT6_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT6_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT6_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT6_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT6_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT6_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT6_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT6_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT6_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT6_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT6_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT6_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT7_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT7_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT7_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT7_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT7_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT7_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT7_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT7_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT7_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT7_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT7_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT7_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT7_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT7_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT7_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT7_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT7_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT7_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT7_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT7_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT7_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT7_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT7_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT7_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT7_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT7_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT7_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT8_1 MIX1 INP0", "RX0", "SLIM RX0"}, + {"RX INT8_1 MIX1 INP0", "RX1", "SLIM RX1"}, + {"RX INT8_1 MIX1 INP0", "RX2", "SLIM RX2"}, + {"RX INT8_1 MIX1 INP0", "RX3", "SLIM RX3"}, + {"RX INT8_1 MIX1 INP0", "RX4", "SLIM RX4"}, + {"RX INT8_1 MIX1 INP0", "RX5", "SLIM RX5"}, + {"RX INT8_1 MIX1 INP0", "RX6", "SLIM RX6"}, + {"RX INT8_1 MIX1 INP0", "RX7", "SLIM RX7"}, + {"RX INT8_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT8_1 MIX1 INP1", "RX0", "SLIM RX0"}, + {"RX INT8_1 MIX1 INP1", "RX1", "SLIM RX1"}, + {"RX INT8_1 MIX1 INP1", "RX2", "SLIM RX2"}, + {"RX INT8_1 MIX1 INP1", "RX3", "SLIM RX3"}, + {"RX INT8_1 MIX1 INP1", "RX4", "SLIM RX4"}, + {"RX INT8_1 MIX1 INP1", "RX5", "SLIM RX5"}, + {"RX INT8_1 MIX1 INP1", "RX6", "SLIM RX6"}, + {"RX INT8_1 MIX1 INP1", "RX7", "SLIM RX7"}, + {"RX INT8_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT8_1 MIX1 INP2", "RX0", "SLIM RX0"}, + {"RX INT8_1 MIX1 INP2", "RX1", "SLIM RX1"}, + {"RX INT8_1 MIX1 INP2", "RX2", "SLIM RX2"}, + {"RX INT8_1 MIX1 INP2", "RX3", "SLIM RX3"}, + {"RX INT8_1 MIX1 INP2", "RX4", "SLIM RX4"}, + {"RX INT8_1 MIX1 INP2", "RX5", "SLIM RX5"}, + {"RX INT8_1 MIX1 INP2", "RX6", "SLIM RX6"}, + {"RX INT8_1 MIX1 INP2", "RX7", "SLIM RX7"}, + {"RX INT8_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP2", "IIR1", "IIR1"}, + + /* SRC0, SRC1 inputs to Sidetone RX Mixer + * on RX0, RX1, RX2, RX3, RX4 and RX7 chains + */ + {"IIR0", NULL, "IIR0 INP0 MUX"}, + {"IIR0 INP0 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP0 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP0 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP0 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP0 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP0 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP0 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP0 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP0 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP0 MUX", "RX0", "SLIM RX0"}, + {"IIR0 INP0 MUX", "RX1", "SLIM RX1"}, + {"IIR0 INP0 MUX", "RX2", "SLIM RX2"}, + {"IIR0 INP0 MUX", "RX3", "SLIM RX3"}, + {"IIR0 INP0 MUX", "RX4", "SLIM RX4"}, + {"IIR0 INP0 MUX", "RX5", "SLIM RX5"}, + {"IIR0 INP0 MUX", "RX6", "SLIM RX6"}, + {"IIR0 INP0 MUX", "RX7", "SLIM RX7"}, + {"IIR0", NULL, "IIR0 INP1 MUX"}, + {"IIR0 INP1 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP1 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP1 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP1 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP1 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP1 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP1 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP1 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP1 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP1 MUX", "RX0", "SLIM RX0"}, + {"IIR0 INP1 MUX", "RX1", "SLIM RX1"}, + {"IIR0 INP1 MUX", "RX2", "SLIM RX2"}, + {"IIR0 INP1 MUX", "RX3", "SLIM RX3"}, + {"IIR0 INP1 MUX", "RX4", "SLIM RX4"}, + {"IIR0 INP1 MUX", "RX5", "SLIM RX5"}, + {"IIR0 INP1 MUX", "RX6", "SLIM RX6"}, + {"IIR0 INP1 MUX", "RX7", "SLIM RX7"}, + {"IIR0", NULL, "IIR0 INP2 MUX"}, + {"IIR0 INP2 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP2 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP2 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP2 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP2 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP2 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP2 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP2 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP2 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP2 MUX", "RX0", "SLIM RX0"}, + {"IIR0 INP2 MUX", "RX1", "SLIM RX1"}, + {"IIR0 INP2 MUX", "RX2", "SLIM RX2"}, + {"IIR0 INP2 MUX", "RX3", "SLIM RX3"}, + {"IIR0 INP2 MUX", "RX4", "SLIM RX4"}, + {"IIR0 INP2 MUX", "RX5", "SLIM RX5"}, + {"IIR0 INP2 MUX", "RX6", "SLIM RX6"}, + {"IIR0 INP2 MUX", "RX7", "SLIM RX7"}, + {"IIR0", NULL, "IIR0 INP3 MUX"}, + {"IIR0 INP3 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP3 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP3 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP3 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP3 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP3 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP3 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP3 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP3 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP3 MUX", "RX0", "SLIM RX0"}, + {"IIR0 INP3 MUX", "RX1", "SLIM RX1"}, + {"IIR0 INP3 MUX", "RX2", "SLIM RX2"}, + {"IIR0 INP3 MUX", "RX3", "SLIM RX3"}, + {"IIR0 INP3 MUX", "RX4", "SLIM RX4"}, + {"IIR0 INP3 MUX", "RX5", "SLIM RX5"}, + {"IIR0 INP3 MUX", "RX6", "SLIM RX6"}, + {"IIR0 INP3 MUX", "RX7", "SLIM RX7"}, + + {"IIR1", NULL, "IIR1 INP0 MUX"}, + {"IIR1 INP0 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP0 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP0 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP0 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP0 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP0 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP0 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP0 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP0 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP0 MUX", "RX0", "SLIM RX0"}, + {"IIR1 INP0 MUX", "RX1", "SLIM RX1"}, + {"IIR1 INP0 MUX", "RX2", "SLIM RX2"}, + {"IIR1 INP0 MUX", "RX3", "SLIM RX3"}, + {"IIR1 INP0 MUX", "RX4", "SLIM RX4"}, + {"IIR1 INP0 MUX", "RX5", "SLIM RX5"}, + {"IIR1 INP0 MUX", "RX6", "SLIM RX6"}, + {"IIR1 INP0 MUX", "RX7", "SLIM RX7"}, + {"IIR1", NULL, "IIR1 INP1 MUX"}, + {"IIR1 INP1 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP1 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP1 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP1 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP1 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP1 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP1 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP1 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP1 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP1 MUX", "RX0", "SLIM RX0"}, + {"IIR1 INP1 MUX", "RX1", "SLIM RX1"}, + {"IIR1 INP1 MUX", "RX2", "SLIM RX2"}, + {"IIR1 INP1 MUX", "RX3", "SLIM RX3"}, + {"IIR1 INP1 MUX", "RX4", "SLIM RX4"}, + {"IIR1 INP1 MUX", "RX5", "SLIM RX5"}, + {"IIR1 INP1 MUX", "RX6", "SLIM RX6"}, + {"IIR1 INP1 MUX", "RX7", "SLIM RX7"}, + {"IIR1", NULL, "IIR1 INP2 MUX"}, + {"IIR1 INP2 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP2 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP2 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP2 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP2 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP2 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP2 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP2 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP2 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP2 MUX", "RX0", "SLIM RX0"}, + {"IIR1 INP2 MUX", "RX1", "SLIM RX1"}, + {"IIR1 INP2 MUX", "RX2", "SLIM RX2"}, + {"IIR1 INP2 MUX", "RX3", "SLIM RX3"}, + {"IIR1 INP2 MUX", "RX4", "SLIM RX4"}, + {"IIR1 INP2 MUX", "RX5", "SLIM RX5"}, + {"IIR1 INP2 MUX", "RX6", "SLIM RX6"}, + {"IIR1 INP2 MUX", "RX7", "SLIM RX7"}, + {"IIR1", NULL, "IIR1 INP3 MUX"}, + {"IIR1 INP3 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP3 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP3 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP3 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP3 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP3 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP3 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP3 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP3 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP3 MUX", "RX0", "SLIM RX0"}, + {"IIR1 INP3 MUX", "RX1", "SLIM RX1"}, + {"IIR1 INP3 MUX", "RX2", "SLIM RX2"}, + {"IIR1 INP3 MUX", "RX3", "SLIM RX3"}, + {"IIR1 INP3 MUX", "RX4", "SLIM RX4"}, + {"IIR1 INP3 MUX", "RX5", "SLIM RX5"}, + {"IIR1 INP3 MUX", "RX6", "SLIM RX6"}, + {"IIR1 INP3 MUX", "RX7", "SLIM RX7"}, + + {"SRC0", NULL, "IIR0"}, + {"SRC1", NULL, "IIR1"}, + {"RX INT0 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT0 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT1 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT1 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT2 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT2 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT3 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT3 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT4 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT4 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT7 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT7 MIX2 INP", "SRC1", "SRC1"}, +}; + +static int tasha_amic_pwr_lvl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u16 amic_reg; + + if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE")) + amic_reg = WCD9335_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE")) + amic_reg = WCD9335_ANA_AMIC3; + if (!strcmp(kcontrol->id.name, "AMIC_5_6 PWR MODE")) + amic_reg = WCD9335_ANA_AMIC5; + + ucontrol->value.integer.value[0] = + (snd_soc_component_read32(component, amic_reg) & + WCD9335_AMIC_PWR_LVL_MASK) >> + WCD9335_AMIC_PWR_LVL_SHIFT; + + return 0; +} + +static int tasha_amic_pwr_lvl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 mode_val; + u16 amic_reg; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: mode: %d\n", + __func__, mode_val); + + if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE")) + amic_reg = WCD9335_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE")) + amic_reg = WCD9335_ANA_AMIC3; + if (!strcmp(kcontrol->id.name, "AMIC_5_6 PWR MODE")) + amic_reg = WCD9335_ANA_AMIC5; + + snd_soc_component_update_bits(component, amic_reg, + WCD9335_AMIC_PWR_LVL_MASK, + mode_val << WCD9335_AMIC_PWR_LVL_SHIFT); + + return 0; +} + +static int tasha_rx_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tasha->hph_mode; + return 0; +} + +static int tasha_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = 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_warn(component->dev, "%s:Invalid HPH Mode, default to Cls-H HiFi\n", + __func__); + mode_val = CLS_H_HIFI; + } + tasha->hph_mode = mode_val; + return 0; +} + +static const char *const tasha_conn_mad_text[] = { + "NOTUSED1", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", + "NOTUSED2", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", + "DMIC5", "NOTUSED3", "NOTUSED4" +}; + +static const struct soc_enum tasha_conn_mad_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_conn_mad_text), + tasha_conn_mad_text); + +static int tasha_enable_ldo_h_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u8 val = 0; + + if (component) + val = snd_soc_component_read32(component, WCD9335_LDOH_MODE) & + 0x80; + + ucontrol->value.integer.value[0] = !!val; + + return 0; +} + +static int tasha_enable_ldo_h_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int value = ucontrol->value.integer.value[0]; + bool enable; + + enable = !!value; + if (component) + tasha_codec_enable_standalone_ldo_h(component, enable); + + return 0; +} + +static int tasha_mad_input_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 tasha_mad_input; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + tasha_mad_input = snd_soc_component_read32(component, + WCD9335_SOC_MAD_INP_SEL) & 0x0F; + ucontrol->value.integer.value[0] = tasha_mad_input; + + dev_dbg(component->dev, + "%s: tasha_mad_input = %s\n", __func__, + tasha_conn_mad_text[tasha_mad_input]); + return 0; +} + +static int tasha_mad_input_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 tasha_mad_input; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct snd_soc_card *card = component->card; + char mad_amic_input_widget[6]; + const char *mad_input_widget; + const char *source_widget = NULL; + u32 adc, i, mic_bias_found = 0; + int ret = 0; + char *mad_input; + + tasha_mad_input = ucontrol->value.integer.value[0]; + + if (tasha_mad_input >= ARRAY_SIZE(tasha_conn_mad_text)) { + dev_err(component->dev, + "%s: tasha_mad_input = %d out of bounds\n", + __func__, tasha_mad_input); + return -EINVAL; + } + + if (!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED1") || + !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED2") || + !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED3") || + !strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED4")) { + dev_err(component->dev, + "%s: Unsupported tasha_mad_input = %s\n", + __func__, tasha_conn_mad_text[tasha_mad_input]); + return -EINVAL; + } + + if (strnstr(tasha_conn_mad_text[tasha_mad_input], + "ADC", sizeof("ADC"))) { + mad_input = strpbrk(tasha_conn_mad_text[tasha_mad_input], + "123456"); + if (!mad_input) { + dev_err(component->dev, "%s: Invalid MAD input %s\n", + __func__, + tasha_conn_mad_text[tasha_mad_input]); + return -EINVAL; + } + ret = kstrtouint(mad_input, 10, &adc); + if ((ret < 0) || (adc > 6)) { + dev_err(component->dev, + "%s: Invalid ADC = %s\n", __func__, + tasha_conn_mad_text[tasha_mad_input]); + ret = -EINVAL; + } + + snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc); + + mad_input_widget = mad_amic_input_widget; + } else { + /* DMIC type input widget*/ + mad_input_widget = tasha_conn_mad_text[tasha_mad_input]; + } + + dev_dbg(component->dev, + "%s: tasha input widget = %s\n", __func__, + mad_input_widget); + + for (i = 0; i < card->num_of_dapm_routes; i++) { + if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) { + source_widget = card->of_dapm_routes[i].source; + if (!source_widget) { + dev_err(component->dev, + "%s: invalid source widget\n", + __func__); + return -EINVAL; + } + + if (strnstr(source_widget, + "MIC BIAS1", sizeof("MIC BIAS1"))) { + mic_bias_found = 1; + break; + } else if (strnstr(source_widget, + "MIC BIAS2", sizeof("MIC BIAS2"))) { + mic_bias_found = 2; + break; + } else if (strnstr(source_widget, + "MIC BIAS3", sizeof("MIC BIAS3"))) { + mic_bias_found = 3; + break; + } else if (strnstr(source_widget, + "MIC BIAS4", sizeof("MIC BIAS4"))) { + mic_bias_found = 4; + break; + } + } + } + + if (!mic_bias_found) { + dev_err(component->dev, + "%s: mic bias source not found for input = %s\n", + __func__, mad_input_widget); + return -EINVAL; + } + + dev_dbg(component->dev, + "%s: mic_bias found = %d\n", __func__, + mic_bias_found); + + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_INP_SEL, + 0x0F, tasha_mad_input); + snd_soc_component_update_bits(component, WCD9335_ANA_MAD_SETUP, + 0x07, mic_bias_found); + + return 0; +} + +static int tasha_pinctl_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u16 ctl_reg; + u8 reg_val, pinctl_position; + + pinctl_position = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + switch (pinctl_position >> 3) { + case 0: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_0; + break; + case 1: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_1; + break; + case 2: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_2; + break; + case 3: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_3; + break; + default: + dev_err(component->dev, "%s: Invalid pinctl position = %d\n", + __func__, pinctl_position); + return -EINVAL; + } + + reg_val = snd_soc_component_read32(component, ctl_reg); + reg_val = (reg_val >> (pinctl_position & 0x07)) & 0x1; + ucontrol->value.integer.value[0] = reg_val; + + return 0; +} + +static int tasha_pinctl_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u16 ctl_reg, cfg_reg; + u8 ctl_val, cfg_val, pinctl_position, pinctl_mode, mask; + + /* 1- high or low; 0- high Z */ + pinctl_mode = ucontrol->value.integer.value[0]; + pinctl_position = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + switch (pinctl_position >> 3) { + case 0: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_0; + break; + case 1: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_1; + break; + case 2: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_2; + break; + case 3: + ctl_reg = WCD9335_TEST_DEBUG_PIN_CTL_OE_3; + break; + default: + dev_err(component->dev, "%s: Invalid pinctl position = %d\n", + __func__, pinctl_position); + return -EINVAL; + } + + ctl_val = pinctl_mode << (pinctl_position & 0x07); + mask = 1 << (pinctl_position & 0x07); + snd_soc_component_update_bits(component, ctl_reg, mask, ctl_val); + + cfg_reg = WCD9335_TLMM_BIST_MODE_PINCFG + pinctl_position; + if (!pinctl_mode) { + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + cfg_val = 0x4; + else + cfg_val = 0xC; + } else { + cfg_val = 0; + } + snd_soc_component_update_bits(component, cfg_reg, 0x07, cfg_val); + + dev_dbg(component->dev, "%s: reg=0x%x mask=0x%x val=%d reg=0x%x val=%d\n", + __func__, ctl_reg, mask, ctl_val, cfg_reg, cfg_val); + + return 0; +} + +static void wcd_vbat_adc_out_config_2_0(struct wcd_vbat *vbat, + struct snd_soc_component *component) +{ + u8 val1, val2; + + /* + * Measure dcp1 by using "ALT" branch of band gap + * voltage(Vbg) and use it in FAST mode + */ + snd_soc_component_update_bits(component, WCD9335_BIAS_CTL, + 0x82, 0x82); + snd_soc_component_update_bits(component, WCD9335_CDC_VBAT_VBAT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, WCD9335_CDC_VBAT_VBAT_DEBUG1, + 0x01, 0x01); + snd_soc_component_update_bits(component, WCD9335_ANA_VBADC, + 0x80, 0x80); + snd_soc_component_update_bits(component, WCD9335_VBADC_SUBBLOCK_EN, + 0x20, 0x00); + snd_soc_component_update_bits(component, WCD9335_VBADC_FE_CTRL, + 0x20, 0x20); + /* Wait 100 usec after calibration select as Vbg */ + usleep_range(100, 110); + + snd_soc_component_update_bits(component, WCD9335_VBADC_ADC_IO, + 0x40, 0x40); + val1 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTMSB); + val2 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTLSB); + snd_soc_component_update_bits(component, WCD9335_VBADC_ADC_IO, + 0x40, 0x00); + + vbat->dcp1 = (((val1 & 0xFF) << 3) | (val2 & 0x07)); + + snd_soc_component_update_bits(component, WCD9335_BIAS_CTL, 0x40, 0x40); + /* Wait 100 usec after selecting Vbg as 1.05V */ + usleep_range(100, 110); + + snd_soc_component_update_bits(component, WCD9335_VBADC_ADC_IO, + 0x40, 0x40); + val1 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTMSB); + val2 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTLSB); + snd_soc_component_update_bits(component, WCD9335_VBADC_ADC_IO, + 0x40, 0x00); + + vbat->dcp2 = (((val1 & 0xFF) << 3) | (val2 & 0x07)); + + dev_dbg(component->dev, "%s: dcp1:0x%x, dcp2:0x%x\n", + __func__, vbat->dcp1, vbat->dcp2); + + snd_soc_component_write(component, WCD9335_BIAS_CTL, 0x28); + /* Wait 100 usec after selecting Vbg as 0.85V */ + usleep_range(100, 110); + + snd_soc_component_update_bits(component, WCD9335_VBADC_FE_CTRL, + 0x20, 0x00); + snd_soc_component_update_bits(component, WCD9335_VBADC_SUBBLOCK_EN, + 0x20, 0x20); + snd_soc_component_update_bits(component, WCD9335_ANA_VBADC, + 0x80, 0x00); + + snd_soc_component_update_bits(component, WCD9335_CDC_VBAT_VBAT_PATH_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, WCD9335_CDC_VBAT_VBAT_DEBUG1, + 0x01, 0x00); +} + +static void wcd_vbat_adc_out_config_1_x(struct wcd_vbat *vbat, + struct snd_soc_component *component) +{ + u8 val1, val2; + + /* + * Measure dcp1 by applying band gap voltage(Vbg) + * of 0.85V + */ + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0x20); + snd_soc_component_write(component, WCD9335_BIAS_CTL, 0x28); + snd_soc_component_write(component, WCD9335_BIAS_VBG_FINE_ADJ, 0x05); + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0xA0); + /* Wait 2 sec after enabling band gap bias */ + usleep_range(2000000, 2000100); + + snd_soc_component_write(component, WCD9335_ANA_CLK_TOP, 0x82); + snd_soc_component_write(component, WCD9335_ANA_CLK_TOP, 0x87); + snd_soc_component_update_bits(component, WCD9335_CDC_VBAT_VBAT_PATH_CTL, + 0x10, 0x10); + snd_soc_component_write(component, WCD9335_CDC_VBAT_VBAT_CFG, 0x0D); + snd_soc_component_write(component, WCD9335_CDC_VBAT_VBAT_DEBUG1, 0x01); + + snd_soc_component_write(component, WCD9335_ANA_VBADC, 0x80); + snd_soc_component_write(component, WCD9335_VBADC_SUBBLOCK_EN, 0xDE); + snd_soc_component_write(component, WCD9335_VBADC_FE_CTRL, 0x3C); + /* Wait 1 msec after calibration select as Vbg */ + usleep_range(1000, 1100); + + snd_soc_component_write(component, WCD9335_VBADC_ADC_IO, 0xC0); + val1 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTMSB); + val2 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTLSB); + snd_soc_component_write(component, WCD9335_VBADC_ADC_IO, 0x80); + + vbat->dcp1 = (((val1 & 0xFF) << 3) | (val2 & 0x07)); + + /* + * Measure dcp2 by applying band gap voltage(Vbg) + * of 1.05V + */ + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0x80); + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0xC0); + snd_soc_component_write(component, WCD9335_BIAS_CTL, 0x68); + /* Wait 2 msec after selecting Vbg as 1.05V */ + usleep_range(2000, 2100); + + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0x80); + /* Wait 1 sec after enabling band gap bias */ + usleep_range(1000000, 1000100); + + snd_soc_component_write(component, WCD9335_VBADC_ADC_IO, 0xC0); + val1 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTMSB); + val2 = snd_soc_component_read32(component, WCD9335_VBADC_ADC_DOUTLSB); + snd_soc_component_write(component, WCD9335_VBADC_ADC_IO, 0x80); + + vbat->dcp2 = (((val1 & 0xFF) << 3) | (val2 & 0x07)); + + dev_dbg(component->dev, "%s: dcp1:0x%x, dcp2:0x%x\n", + __func__, vbat->dcp1, vbat->dcp2); + + /* Reset the Vbat ADC configuration */ + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0x80); + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0xC0); + + snd_soc_component_write(component, WCD9335_BIAS_CTL, 0x28); + /* Wait 2 msec after selecting Vbg as 0.85V */ + usleep_range(2000, 2100); + + snd_soc_component_write(component, WCD9335_ANA_BIAS, 0xA0); + /* Wait 1 sec after enabling band gap bias */ + usleep_range(1000000, 1000100); + + snd_soc_component_write(component, WCD9335_VBADC_FE_CTRL, 0x1C); + snd_soc_component_write(component, WCD9335_VBADC_SUBBLOCK_EN, 0xFE); + snd_soc_component_write(component, WCD9335_VBADC_ADC_IO, 0x80); + snd_soc_component_write(component, WCD9335_ANA_VBADC, 0x00); + + snd_soc_component_write(component, WCD9335_CDC_VBAT_VBAT_DEBUG1, 0x00); + snd_soc_component_write(component, WCD9335_CDC_VBAT_VBAT_PATH_CTL, + 0x00); + snd_soc_component_write(component, WCD9335_CDC_VBAT_VBAT_CFG, 0x0A); +} + +static void wcd_vbat_adc_out_config(struct wcd_vbat *vbat, + struct snd_soc_component *component) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (!vbat->adc_config) { + tasha_cdc_mclk_enable(component, true, false); + + if (TASHA_IS_2_0(wcd9xxx)) + wcd_vbat_adc_out_config_2_0(vbat, component); + else + wcd_vbat_adc_out_config_1_x(vbat, component); + + tasha_cdc_mclk_enable(component, false, false); + vbat->adc_config = true; + } +} + +static int tasha_update_vbat_reg_config(struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct firmware_cal *hwdep_cal = NULL; + struct vbat_monitor_reg *vbat_reg_ptr = NULL; + const void *data; + size_t cal_size, vbat_size_remaining; + int ret = 0, i; + u32 vbat_writes_size = 0; + u16 reg; + u8 mask, val, old_val; + + hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, WCD9XXX_VBAT_CAL); + if (hwdep_cal) { + data = hwdep_cal->data; + cal_size = hwdep_cal->size; + dev_dbg(component->dev, "%s: using hwdep calibration\n", + __func__); + } else { + dev_err(component->dev, "%s: Vbat cal not received\n", + __func__); + ret = -EINVAL; + goto done; + } + + if (cal_size < sizeof(*vbat_reg_ptr)) { + dev_err(component->dev, + "%s: Incorrect size %zd for Vbat Cal, expected %zd\n", + __func__, cal_size, sizeof(*vbat_reg_ptr)); + ret = -EINVAL; + goto done; + } + + vbat_reg_ptr = (struct vbat_monitor_reg *) (data); + + if (!vbat_reg_ptr) { + dev_err(component->dev, + "%s: Invalid calibration data for Vbat\n", + __func__); + ret = -EINVAL; + goto done; + } + + vbat_writes_size = vbat_reg_ptr->size; + vbat_size_remaining = cal_size - sizeof(u32); + dev_dbg(component->dev, "%s: vbat_writes_sz: %d, vbat_sz_remaining: %zd\n", + __func__, vbat_writes_size, vbat_size_remaining); + + if ((vbat_writes_size * TASHA_PACKED_REG_SIZE) + > vbat_size_remaining) { + pr_err("%s: Incorrect Vbat calibration data\n", __func__); + ret = -EINVAL; + goto done; + } + + for (i = 0 ; i < vbat_writes_size; i++) { + TASHA_CODEC_UNPACK_ENTRY(vbat_reg_ptr->writes[i], + reg, mask, val); + old_val = snd_soc_component_read32(component, reg); + snd_soc_component_write(component, reg, (old_val & ~mask) | + (val & mask)); + } + +done: + return ret; +} + +static int tasha_vbat_adc_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + wcd_vbat_adc_out_config(&tasha->vbat, component); + + ucontrol->value.integer.value[0] = tasha->vbat.dcp1; + ucontrol->value.integer.value[1] = tasha->vbat.dcp2; + + dev_dbg(component->dev, + "%s: Vbat ADC output values, Dcp1 : %lu, Dcp2: %lu\n", + __func__, ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1]); + + return 0; +} + +static const char * const tasha_vbat_gsm_mode_text[] = { + "OFF", "ON"}; + +static const struct soc_enum tasha_vbat_gsm_mode_enum = + SOC_ENUM_SINGLE_EXT(2, tasha_vbat_gsm_mode_text); + +static int tasha_vbat_gsm_mode_func_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ucontrol->value.integer.value[0] = + ((snd_soc_component_read32( + component, WCD9335_CDC_VBAT_VBAT_CFG) & 0x04) ? 1 : 0); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int tasha_vbat_gsm_mode_func_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: value: %lu\n", __func__, + ucontrol->value.integer.value[0]); + + /* Set Vbat register configuration for GSM mode bit based on value */ + if (ucontrol->value.integer.value[0]) + snd_soc_component_update_bits(component, + WCD9335_CDC_VBAT_VBAT_CFG, + 0x04, 0x04); + else + snd_soc_component_update_bits(component, + WCD9335_CDC_VBAT_VBAT_CFG, + 0x04, 0x00); + + return 0; +} + +static int tasha_codec_vbat_enable_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u16 vbat_path_ctl, vbat_cfg, vbat_path_cfg; + + vbat_path_ctl = WCD9335_CDC_VBAT_VBAT_PATH_CTL; + vbat_cfg = WCD9335_CDC_VBAT_VBAT_CFG; + vbat_path_cfg = WCD9335_CDC_RX8_RX_PATH_CFG1; + + if (!strcmp(w->name, "RX INT8 VBAT")) + vbat_path_cfg = WCD9335_CDC_RX8_RX_PATH_CFG1; + else if (!strcmp(w->name, "RX INT7 VBAT")) + vbat_path_cfg = WCD9335_CDC_RX7_RX_PATH_CFG1; + else if (!strcmp(w->name, "RX INT6 VBAT")) + vbat_path_cfg = WCD9335_CDC_RX6_RX_PATH_CFG1; + else if (!strcmp(w->name, "RX INT5 VBAT")) + vbat_path_cfg = WCD9335_CDC_RX5_RX_PATH_CFG1; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = tasha_update_vbat_reg_config(component); + if (ret) { + dev_dbg(component->dev, + "%s : VBAT isn't calibrated, So not enabling it\n", + __func__); + return 0; + } + snd_soc_component_write(component, WCD9335_ANA_VBADC, 0x80); + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x02); + snd_soc_component_update_bits(component, vbat_path_ctl, + 0x10, 0x10); + snd_soc_component_update_bits(component, vbat_cfg, 0x01, 0x01); + tasha->vbat.is_enabled = true; + break; + case SND_SOC_DAPM_POST_PMD: + if (tasha->vbat.is_enabled) { + snd_soc_component_update_bits(component, vbat_cfg, + 0x01, 0x00); + snd_soc_component_update_bits(component, vbat_path_ctl, + 0x10, 0x00); + snd_soc_component_update_bits(component, vbat_path_cfg, + 0x02, 0x00); + snd_soc_component_write(component, WCD9335_ANA_VBADC, + 0x00); + tasha->vbat.is_enabled = false; + } + break; + }; + + return ret; +} + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI" +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static const char * const amic_pwr_lvl_text[] = { + "LOW_PWR", "DEFAULT", "HIGH_PERF" +}; + +static const struct soc_enum amic_pwr_lvl_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(amic_pwr_lvl_text), + amic_pwr_lvl_text); + +static const struct snd_kcontrol_new tasha_snd_controls[] = { + SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + -84, 40, digital_gain), + + SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", + WCD9335_CDC_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", + WCD9335_CDC_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", + WCD9335_CDC_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", + WCD9335_CDC_RX3_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", + WCD9335_CDC_RX4_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume", + WCD9335_CDC_RX5_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume", + WCD9335_CDC_RX6_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", + WCD9335_CDC_RX7_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", + WCD9335_CDC_RX8_RX_VOL_MIX_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + + SOC_SINGLE_S8_TLV("DEC0 Volume", WCD9335_CDC_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC1 Volume", WCD9335_CDC_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC2 Volume", WCD9335_CDC_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC3 Volume", WCD9335_CDC_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC4 Volume", WCD9335_CDC_TX4_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC5 Volume", WCD9335_CDC_TX5_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC6 Volume", WCD9335_CDC_TX6_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC7 Volume", WCD9335_CDC_TX7_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC8 Volume", WCD9335_CDC_TX8_TX_VOL_CTL, + -84, 40, digital_gain), + + SOC_SINGLE_S8_TLV("IIR0 INP0 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, + 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP1 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, + 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP2 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, + 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP3 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, + 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP0 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, + 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, + 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, + 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, + 40, digital_gain), + + SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tasha_get_anc_slot, + tasha_put_anc_slot), + SOC_ENUM_EXT("ANC Function", tasha_anc_func_enum, tasha_get_anc_func, + tasha_put_anc_func), + + SOC_ENUM_EXT("CLK MODE", tasha_clkmode_enum, tasha_get_clkmode, + tasha_put_clkmode), + + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), + + SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), + SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), + SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), + SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum), + SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum), + SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum), + SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum), + SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum), + SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum), + SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum), + SOC_ENUM("RX INT5_1 HPF cut off", cf_int5_1_enum), + SOC_ENUM("RX INT5_2 HPF cut off", cf_int5_2_enum), + SOC_ENUM("RX INT6_1 HPF cut off", cf_int6_1_enum), + SOC_ENUM("RX INT6_2 HPF cut off", cf_int6_2_enum), + SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum), + SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum), + SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum), + SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum), + + SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR0 Enable Band2", IIR0, BAND2, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR0 Enable Band3", IIR0, BAND3, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR0 Enable Band4", IIR0, BAND4, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR0 Enable Band5", IIR0, BAND5, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0, + tasha_get_iir_enable_audio_mixer, tasha_put_iir_enable_audio_mixer), + + SOC_SINGLE_MULTI_EXT("IIR0 Band1", IIR0, BAND1, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR0 Band2", IIR0, BAND2, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR0 Band3", IIR0, BAND3, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR0 Band4", IIR0, BAND4, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR0 Band5", IIR0, BAND5, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5, + tasha_get_iir_band_audio_mixer, tasha_put_iir_band_audio_mixer), + + SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0, + tasha_get_compander, tasha_set_compander), + SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0, + tasha_get_compander, tasha_set_compander), + SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0, + tasha_get_compander, tasha_set_compander), + SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0, + tasha_get_compander, tasha_set_compander), + SOC_SINGLE_EXT("COMP5 Switch", SND_SOC_NOPM, COMPANDER_5, 1, 0, + tasha_get_compander, tasha_set_compander), + SOC_SINGLE_EXT("COMP6 Switch", SND_SOC_NOPM, COMPANDER_6, 1, 0, + tasha_get_compander, tasha_set_compander), + SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0, + tasha_get_compander, tasha_set_compander), + SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0, + tasha_get_compander, tasha_set_compander), + + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + tasha_rx_hph_mode_get, tasha_rx_hph_mode_put), + + SOC_ENUM_EXT("MAD Input", tasha_conn_mad_enum, + tasha_mad_input_get, tasha_mad_input_put), + SOC_SINGLE_EXT("LDO_H Enable", SND_SOC_NOPM, 0, 1, 0, + tasha_enable_ldo_h_get, tasha_enable_ldo_h_put), + + SOC_SINGLE_EXT("DMIC1_CLK_PIN_MODE", SND_SOC_NOPM, 17, 1, 0, + tasha_pinctl_mode_get, tasha_pinctl_mode_put), + + SOC_SINGLE_EXT("DMIC1_DATA_PIN_MODE", SND_SOC_NOPM, 18, 1, 0, + tasha_pinctl_mode_get, tasha_pinctl_mode_put), + + SOC_SINGLE_EXT("DMIC2_CLK_PIN_MODE", SND_SOC_NOPM, 19, 1, 0, + tasha_pinctl_mode_get, tasha_pinctl_mode_put), + + SOC_SINGLE_EXT("DMIC2_DATA_PIN_MODE", SND_SOC_NOPM, 20, 1, 0, + tasha_pinctl_mode_get, tasha_pinctl_mode_put), + + SOC_SINGLE_EXT("DMIC3_CLK_PIN_MODE", SND_SOC_NOPM, 21, 1, 0, + tasha_pinctl_mode_get, tasha_pinctl_mode_put), + + SOC_SINGLE_EXT("DMIC3_DATA_PIN_MODE", SND_SOC_NOPM, 22, 1, 0, + tasha_pinctl_mode_get, tasha_pinctl_mode_put), + SOC_ENUM_EXT("AMIC_1_2 PWR MODE", amic_pwr_lvl_enum, + tasha_amic_pwr_lvl_get, tasha_amic_pwr_lvl_put), + SOC_ENUM_EXT("AMIC_3_4 PWR MODE", amic_pwr_lvl_enum, + tasha_amic_pwr_lvl_get, tasha_amic_pwr_lvl_put), + SOC_ENUM_EXT("AMIC_5_6 PWR MODE", amic_pwr_lvl_enum, + tasha_amic_pwr_lvl_get, tasha_amic_pwr_lvl_put), + + SOC_SINGLE_MULTI_EXT("Vbat ADC data", SND_SOC_NOPM, 0, 0xFFFF, 0, 2, + tasha_vbat_adc_data_get, NULL), + + SOC_ENUM_EXT("GSM mode Enable", tasha_vbat_gsm_mode_enum, + tasha_vbat_gsm_mode_func_get, + tasha_vbat_gsm_mode_func_put), +}; + +static int tasha_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + u16 mic_sel_reg; + u8 mic_sel; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1: + mic_sel_reg = WCD9335_CDC_TX0_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1: + mic_sel_reg = WCD9335_CDC_TX1_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1: + mic_sel_reg = WCD9335_CDC_TX2_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1: + mic_sel_reg = WCD9335_CDC_TX3_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0: + mic_sel_reg = WCD9335_CDC_TX4_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0: + mic_sel_reg = WCD9335_CDC_TX5_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0: + mic_sel_reg = WCD9335_CDC_TX6_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0: + mic_sel_reg = WCD9335_CDC_TX7_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0: + mic_sel_reg = WCD9335_CDC_TX8_TX_PATH_CFG0; + break; + default: + dev_err(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + + /* ADC: 0, DMIC: 1 */ + mic_sel = val ? 0x0 : 0x1; + snd_soc_component_update_bits(component, mic_sel_reg, + 1 << 7, mic_sel << 7); + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int tasha_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + unsigned short look_ahead_dly_reg = WCD9335_CDC_RX0_RX_PATH_CFG0; + + val = ucontrol->value.enumerated.item[0]; + if (val >= e->items) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0) + look_ahead_dly_reg = WCD9335_CDC_RX0_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX1_RX_PATH_SEC0) + look_ahead_dly_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX2_RX_PATH_SEC0) + look_ahead_dly_reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, look_ahead_dly_reg, + 0x08, (val ? 0x08 : 0x00)); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int tasha_ear_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ear_pa_gain = snd_soc_component_read32(component, WCD9335_ANA_EAR); + + ear_pa_gain = (ear_pa_gain & 0x70) >> 4; + + ucontrol->value.integer.value[0] = ear_pa_gain; + + dev_dbg(component->dev, "%s: ear_pa_gain = 0x%x\n", __func__, + ear_pa_gain); + + return 0; +} + +static int tasha_ear_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + ear_pa_gain = ucontrol->value.integer.value[0] << 4; + + snd_soc_component_update_bits(component, WCD9335_ANA_EAR, + 0x70, ear_pa_gain); + return 0; +} + +static int tasha_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tasha->ear_spkr_gain; + + dev_dbg(component->dev, "%s: ear_spkr_gain = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int tasha_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + tasha->ear_spkr_gain = ucontrol->value.integer.value[0]; + + return 0; +} + +static int tasha_spkr_left_boost_stage_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + bst_state_max = snd_soc_component_read32( + component, WCD9335_CDC_BOOST0_BOOST_CTL); + bst_state_max = (bst_state_max & 0x0c) >> 2; + ucontrol->value.integer.value[0] = bst_state_max; + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int tasha_spkr_left_boost_stage_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + bst_state_max = ucontrol->value.integer.value[0] << 2; + snd_soc_component_update_bits(component, WCD9335_CDC_BOOST0_BOOST_CTL, + 0x0c, bst_state_max); + + return 0; +} + +static int tasha_spkr_right_boost_stage_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + bst_state_max = snd_soc_component_read32( + component, WCD9335_CDC_BOOST1_BOOST_CTL); + bst_state_max = (bst_state_max & 0x0c) >> 2; + ucontrol->value.integer.value[0] = bst_state_max; + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int tasha_spkr_right_boost_stage_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + bst_state_max = ucontrol->value.integer.value[0] << 2; + snd_soc_component_update_bits(component, WCD9335_CDC_BOOST1_BOOST_CTL, + 0x0c, bst_state_max); + + return 0; +} + +static int tasha_config_compander(struct snd_soc_component *component, + int interp_n, int event) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int comp; + u16 comp_ctl0_reg, rx_path_cfg0_reg; + + /* EAR does not have compander */ + if (!interp_n) + return 0; + + comp = interp_n - 1; + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, tasha->comp_enabled[comp]); + + if (!tasha->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = WCD9335_CDC_COMPANDER1_CTL0 + (comp * 8); + rx_path_cfg0_reg = WCD9335_CDC_RX1_RX_PATH_CFG0 + (comp * 20); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x04); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x00); + } + + return 0; +} + +static int tasha_codec_config_mad(struct snd_soc_component *component) +{ + int ret = 0; + int idx; + const struct firmware *fw; + struct firmware_cal *hwdep_cal = NULL; + struct wcd_mad_audio_cal *mad_cal = NULL; + const void *data; + const char *filename = TASHA_MAD_AUDIO_FIRMWARE_PATH; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + size_t cal_size; + + hwdep_cal = wcdcal_get_fw_cal(tasha->fw_data, WCD9XXX_MAD_CAL); + if (hwdep_cal) { + data = hwdep_cal->data; + cal_size = hwdep_cal->size; + dev_dbg(component->dev, "%s: using hwdep calibration\n", + __func__); + } else { + ret = request_firmware(&fw, filename, component->dev); + if (ret || !fw) { + dev_err(component->dev, + "%s: MAD firmware acquire failed, err = %d\n", + __func__, ret); + return -ENODEV; + } + data = fw->data; + cal_size = fw->size; + dev_dbg(component->dev, "%s: using request_firmware calibration\n", + __func__); + } + + if (cal_size < sizeof(*mad_cal)) { + dev_err(component->dev, + "%s: Incorrect size %zd for MAD Cal, expected %zd\n", + __func__, cal_size, sizeof(*mad_cal)); + ret = -ENOMEM; + goto done; + } + + mad_cal = (struct wcd_mad_audio_cal *) (data); + if (!mad_cal) { + dev_err(component->dev, + "%s: Invalid calibration data\n", + __func__); + ret = -EINVAL; + goto done; + } + + snd_soc_component_write(component, WCD9335_SOC_MAD_MAIN_CTL_2, + mad_cal->microphone_info.cycle_time); + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_MAIN_CTL_1, + 0xFF << 3, + ((uint16_t)mad_cal->microphone_info.settle_time) << 3); + + /* Audio */ + snd_soc_component_write(component, WCD9335_SOC_MAD_AUDIO_CTL_8, + mad_cal->audio_info.rms_omit_samples); + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_AUDIO_CTL_1, + 0x07 << 4, mad_cal->audio_info.rms_comp_time << 4); + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_AUDIO_CTL_2, + 0x03 << 2, + mad_cal->audio_info.detection_mechanism << 2); + snd_soc_component_write(component, WCD9335_SOC_MAD_AUDIO_CTL_7, + mad_cal->audio_info.rms_diff_threshold & 0x3F); + snd_soc_component_write(component, WCD9335_SOC_MAD_AUDIO_CTL_5, + mad_cal->audio_info.rms_threshold_lsb); + snd_soc_component_write(component, WCD9335_SOC_MAD_AUDIO_CTL_6, + mad_cal->audio_info.rms_threshold_msb); + + for (idx = 0; idx < ARRAY_SIZE(mad_cal->audio_info.iir_coefficients); + idx++) { + snd_soc_component_update_bits(component, + WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR, 0x3F, idx); + snd_soc_component_write(component, + WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL, + mad_cal->audio_info.iir_coefficients[idx]); + dev_dbg(component->dev, "%s:MAD Audio IIR Coef[%d] = 0X%x", + __func__, idx, + mad_cal->audio_info.iir_coefficients[idx]); + } + + /* Beacon */ + snd_soc_component_write(component, WCD9335_SOC_MAD_BEACON_CTL_8, + mad_cal->beacon_info.rms_omit_samples); + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_BEACON_CTL_1, + 0x07 << 4, mad_cal->beacon_info.rms_comp_time << 4); + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_BEACON_CTL_2, + 0x03 << 2, + mad_cal->beacon_info.detection_mechanism << 2); + snd_soc_component_write(component, WCD9335_SOC_MAD_BEACON_CTL_7, + mad_cal->beacon_info.rms_diff_threshold & 0x1F); + snd_soc_component_write(component, WCD9335_SOC_MAD_BEACON_CTL_5, + mad_cal->beacon_info.rms_threshold_lsb); + snd_soc_component_write(component, WCD9335_SOC_MAD_BEACON_CTL_6, + mad_cal->beacon_info.rms_threshold_msb); + + for (idx = 0; idx < ARRAY_SIZE(mad_cal->beacon_info.iir_coefficients); + idx++) { + snd_soc_component_update_bits(component, + WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR, + 0x3F, idx); + snd_soc_component_write(component, + WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL, + mad_cal->beacon_info.iir_coefficients[idx]); + dev_dbg(component->dev, "%s:MAD Beacon IIR Coef[%d] = 0X%x", + __func__, idx, + mad_cal->beacon_info.iir_coefficients[idx]); + } + + /* Ultrasound */ + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_ULTR_CTL_1, + 0x07 << 4, + mad_cal->ultrasound_info.rms_comp_time << 4); + snd_soc_component_update_bits(component, WCD9335_SOC_MAD_ULTR_CTL_2, + 0x03 << 2, + mad_cal->ultrasound_info.detection_mechanism << 2); + snd_soc_component_write(component, WCD9335_SOC_MAD_ULTR_CTL_7, + mad_cal->ultrasound_info.rms_diff_threshold & 0x1F); + snd_soc_component_write(component, WCD9335_SOC_MAD_ULTR_CTL_5, + mad_cal->ultrasound_info.rms_threshold_lsb); + snd_soc_component_write(component, WCD9335_SOC_MAD_ULTR_CTL_6, + mad_cal->ultrasound_info.rms_threshold_msb); + +done: + if (!hwdep_cal) + release_firmware(fw); + + return ret; +} + +static int tasha_codec_enable_mad(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + + dev_dbg(component->dev, + "%s: event = %d\n", __func__, event); + + /* Return if CPE INPUT is DEC1 */ + if (snd_soc_component_read32(component, WCD9335_CPE_SS_SVA_CFG) & 0x01) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + + /* Turn on MAD clk */ + snd_soc_component_update_bits(component, WCD9335_CPE_SS_MAD_CTL, + 0x01, 0x01); + + /* Undo reset for MAD */ + snd_soc_component_update_bits(component, WCD9335_CPE_SS_MAD_CTL, + 0x02, 0x00); + ret = tasha_codec_config_mad(component); + if (ret) + dev_err(component->dev, + "%s: Failed to config MAD, err = %d\n", + __func__, ret); + break; + case SND_SOC_DAPM_POST_PMD: + /* Reset the MAD block */ + snd_soc_component_update_bits(component, WCD9335_CPE_SS_MAD_CTL, + 0x02, 0x02); + /* Turn off MAD clk */ + snd_soc_component_update_bits(component, WCD9335_CPE_SS_MAD_CTL, + 0x01, 0x00); + break; + } + + return ret; +} + +static int tasha_codec_configure_cpe_input(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, + "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Configure CPE input as DEC1 */ + snd_soc_component_update_bits(component, WCD9335_CPE_SS_SVA_CFG, + 0x01, 0x01); + + /* Configure DEC1 Tx out with sample rate as 16K */ + snd_soc_component_update_bits(component, + WCD9335_CDC_TX1_TX_PATH_CTL, + 0x0F, 0x01); + + break; + case SND_SOC_DAPM_POST_PMD: + /* Reset DEC1 Tx out sample rate */ + snd_soc_component_update_bits(component, + WCD9335_CDC_TX1_TX_PATH_CTL, + 0x0F, 0x04); + snd_soc_component_update_bits(component, WCD9335_CPE_SS_SVA_CFG, + 0x01, 0x00); + + break; + } + + return 0; +} + + +static int tasha_codec_aif4_mixer_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + + if (test_bit(AIF4_SWITCH_VALUE, &tasha_p->status_mask)) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + dev_dbg(component->dev, "%s: AIF4 switch value = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int tasha_codec_aif4_mixer_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_dapm_update *update = NULL; + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tasha_priv *tasha_p = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s: AIF4 switch value = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + if (ucontrol->value.integer.value[0]) { + snd_soc_dapm_mixer_update_power(widget->dapm, + kcontrol, 1, update); + set_bit(AIF4_SWITCH_VALUE, &tasha_p->status_mask); + } else { + snd_soc_dapm_mixer_update_power(widget->dapm, + kcontrol, 0, update); + clear_bit(AIF4_SWITCH_VALUE, &tasha_p->status_mask); + } + + return 1; +} + +static const char * const tasha_ear_pa_gain_text[] = { + "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", + "G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB" +}; + +static const char * const tasha_ear_spkr_pa_gain_text[] = { + "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB", "G_4_DB", + "G_5_DB", "G_6_DB" +}; + +static const char * const tasha_speaker_boost_stage_text[] = { + "NO_MAX_STATE", "MAX_STATE_1", "MAX_STATE_2" +}; + +static const struct soc_enum tasha_ear_pa_gain_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_ear_pa_gain_text), + tasha_ear_pa_gain_text); + +static const struct soc_enum tasha_ear_spkr_pa_gain_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_ear_spkr_pa_gain_text), + tasha_ear_spkr_pa_gain_text); + +static const struct soc_enum tasha_spkr_boost_stage_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tasha_speaker_boost_stage_text), + tasha_speaker_boost_stage_text); + +static const struct snd_kcontrol_new tasha_analog_gain_controls[] = { + SOC_ENUM_EXT("EAR PA Gain", tasha_ear_pa_gain_enum, + tasha_ear_pa_gain_get, tasha_ear_pa_gain_put), + + SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT1 Volume", WCD9335_DIFF_LO_LO1_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT2 Volume", WCD9335_DIFF_LO_LO2_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT3 Volume", WCD9335_SE_LO_LO3_GAIN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT4 Volume", WCD9335_SE_LO_LO4_GAIN, 0, 20, 1, + line_gain), + + SOC_SINGLE_TLV("ADC1 Volume", WCD9335_ANA_AMIC1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD9335_ANA_AMIC2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD9335_ANA_AMIC3, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD9335_ANA_AMIC4, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC5 Volume", WCD9335_ANA_AMIC5, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC6 Volume", WCD9335_ANA_AMIC6, 0, 20, 0, + analog_gain), +}; + +static const struct snd_kcontrol_new tasha_spkr_wsa_controls[] = { + SOC_ENUM_EXT("EAR SPKR PA Gain", tasha_ear_spkr_pa_gain_enum, + tasha_ear_spkr_pa_gain_get, tasha_ear_spkr_pa_gain_put), + + SOC_ENUM_EXT("SPKR Left Boost Max State", tasha_spkr_boost_stage_enum, + tasha_spkr_left_boost_stage_get, + tasha_spkr_left_boost_stage_put), + + SOC_ENUM_EXT("SPKR Right Boost Max State", tasha_spkr_boost_stage_enum, + tasha_spkr_right_boost_stage_get, + tasha_spkr_right_boost_stage_put), +}; + +static const char * const spl_src0_mux_text[] = { + "ZERO", "SRC_IN_HPHL", "SRC_IN_LO1", +}; + +static const char * const spl_src1_mux_text[] = { + "ZERO", "SRC_IN_HPHR", "SRC_IN_LO2", +}; + +static const char * const spl_src2_mux_text[] = { + "ZERO", "SRC_IN_LO3", "SRC_IN_SPKRL", +}; + +static const char * const spl_src3_mux_text[] = { + "ZERO", "SRC_IN_LO4", "SRC_IN_SPKRR", +}; + +static const char * const rx_int0_7_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7", "PROXIMITY" +}; + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_sidetone_mix_text[] = { + "ZERO", "SRC0", "SRC1", "SRC_SUM" +}; + +static const char * const sb_tx0_mux_text[] = { + "ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192" +}; + +static const char * const sb_tx1_mux_text[] = { + "ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192" +}; + +static const char * const sb_tx2_mux_text[] = { + "ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192" +}; + +static const char * const sb_tx3_mux_text[] = { + "ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192" +}; + +static const char * const sb_tx4_mux_text[] = { + "ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192" +}; + +static const char * const sb_tx5_mux_text[] = { + "ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192" +}; + +static const char * const sb_tx6_mux_text[] = { + "ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192" +}; + +static const char * const sb_tx7_mux_text[] = { + "ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192" +}; + +static const char * const sb_tx8_mux_text[] = { + "ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192" +}; + +static const char * const sb_tx9_mux_text[] = { + "ZERO", "DEC7", "DEC7_192" +}; + +static const char * const sb_tx10_mux_text[] = { + "ZERO", "DEC6", "DEC6_192" +}; + +static const char * const sb_tx11_mux_text[] = { + "DEC_0_5", "DEC_9_12", "MAD_AUDIO", "MAD_BRDCST" +}; + +static const char * const sb_tx11_inp1_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", + "DEC5", "RX_MIX_TX5", "DEC9_10", "DEC11_12" +}; + +static const char * const sb_tx13_mux_text[] = { + "ZERO", "DEC5", "DEC5_192" +}; + +static const char * const tx13_inp_mux_text[] = { + "CDC_DEC_5", "MAD_BRDCST", "CPE_TX_PP" +}; + +static const char * const iir_inp_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", + "DEC7", "DEC8", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_interp_mux_text[] = { + "ZERO", "RX INT0 MIX2", +}; + +static const char * const rx_int1_interp_mux_text[] = { + "ZERO", "RX INT1 MIX2", +}; + +static const char * const rx_int2_interp_mux_text[] = { + "ZERO", "RX INT2 MIX2", +}; + +static const char * const rx_int3_interp_mux_text[] = { + "ZERO", "RX INT3 MIX2", +}; + +static const char * const rx_int4_interp_mux_text[] = { + "ZERO", "RX INT4 MIX2", +}; + +static const char * const rx_int5_interp_mux_text[] = { + "ZERO", "RX INT5 MIX2", +}; + +static const char * const rx_int6_interp_mux_text[] = { + "ZERO", "RX INT6 MIX2", +}; + +static const char * const rx_int7_interp_mux_text[] = { + "ZERO", "RX INT7 MIX2", +}; + +static const char * const rx_int8_interp_mux_text[] = { + "ZERO", "RX INT8 SEC MIX" +}; + +static const char * const mad_sel_text[] = { + "SPE", "MSM" +}; + +static const char * const adc_mux_text[] = { + "DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2" +}; + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", + "SMIC0", "SMIC1", "SMIC2", "SMIC3" +}; + +static const char * const dmic_mux_alt_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", +}; + +static const char * const amic_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6" +}; + +static const char * const rx_echo_mux_text[] = { + "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2", "RX_MIX3", "RX_MIX4", + "RX_MIX5", "RX_MIX6", "RX_MIX7", "RX_MIX8", "RX_MIX_VBAT5", + "RX_MIX_VBAT6", "RX_MIX_VBAT7", "RX_MIX_VBAT8" +}; + +static const char * const anc0_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHL", "ANC_IN_EAR", "ANC_IN_EAR_SPKR", + "ANC_IN_LO1" +}; + +static const char * const anc1_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHR", "ANC_IN_LO2" +}; + +static const char * const native_mux_text[] = { + "OFF", "ON", +}; + +static const struct soc_enum spl_src0_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 0, 3, + spl_src0_mux_text); + +static const struct soc_enum spl_src1_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 2, 3, + spl_src1_mux_text); + +static const struct soc_enum spl_src2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 4, 3, + spl_src2_mux_text); + +static const struct soc_enum spl_src3_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 6, 3, + spl_src3_mux_text); + +static const struct soc_enum rx_int0_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int1_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int2_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int3_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int4_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int5_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int6_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int7_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int8_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum int1_1_native_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text), + native_mux_text); + +static const struct soc_enum int2_1_native_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text), + native_mux_text); + +static const struct soc_enum int3_1_native_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text), + native_mux_text); + +static const struct soc_enum int4_1_native_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(native_mux_text), + native_mux_text); + +static const struct soc_enum rx_int0_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_sidetone_mix_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0, 4, + rx_sidetone_mix_text); + +static const struct soc_enum rx_int1_sidetone_mix_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, 4, + rx_sidetone_mix_text); + +static const struct soc_enum rx_int2_sidetone_mix_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, 4, + rx_sidetone_mix_text); + +static const struct soc_enum rx_int3_sidetone_mix_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6, 4, + rx_sidetone_mix_text); + +static const struct soc_enum rx_int4_sidetone_mix_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0, 4, + rx_sidetone_mix_text); + +static const struct soc_enum rx_int7_sidetone_mix_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 2, 4, + rx_sidetone_mix_text); + +static const struct soc_enum tx_adc_mux0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux3_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux4_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux5_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux6_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux7_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux8_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux10_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux11_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux12_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux13_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_dmic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux10_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux11_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux12_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux13_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_amic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux10_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux11_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux12_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux13_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum sb_tx0_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0, 4, + sb_tx0_mux_text); + +static const struct soc_enum sb_tx1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 2, 4, + sb_tx1_mux_text); + +static const struct soc_enum sb_tx2_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 4, 4, + sb_tx2_mux_text); + +static const struct soc_enum sb_tx3_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 6, 4, + sb_tx3_mux_text); + +static const struct soc_enum sb_tx4_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 0, 4, + sb_tx4_mux_text); + +static const struct soc_enum sb_tx5_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 2, 4, + sb_tx5_mux_text); + +static const struct soc_enum sb_tx6_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 4, 4, + sb_tx6_mux_text); + +static const struct soc_enum sb_tx7_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 6, 4, + sb_tx7_mux_text); + +static const struct soc_enum sb_tx8_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 0, 4, + sb_tx8_mux_text); + +static const struct soc_enum sb_tx9_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 2, 3, + sb_tx9_mux_text); + +static const struct soc_enum sb_tx10_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 4, 3, + sb_tx10_mux_text); + +static const struct soc_enum sb_tx11_mux_enum = + SOC_ENUM_SINGLE(WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG, 0, 4, + sb_tx11_mux_text); + +static const struct soc_enum sb_tx11_inp1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3, 0, 10, + sb_tx11_inp1_mux_text); + +static const struct soc_enum sb_tx13_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3, 4, 3, + sb_tx13_mux_text); + +static const struct soc_enum tx13_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG, 0, 3, + tx13_inp_mux_text); + +static const struct soc_enum rx_mix_tx0_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0, 0, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0, 4, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx2_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1, 0, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx3_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1, 4, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx4_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2, 0, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx5_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2, 4, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx6_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3, 0, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx7_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3, 4, 14, + rx_echo_mux_text); + +static const struct soc_enum rx_mix_tx8_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4, 0, 14, + rx_echo_mux_text); + +static const struct soc_enum iir0_inp0_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum iir0_inp1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum iir0_inp2_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum iir0_inp3_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum iir1_inp0_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum iir1_inp1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum iir1_inp2_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum iir1_inp3_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0, 18, + iir_inp_mux_text); + +static const struct soc_enum rx_int0_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int1_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int2_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int0_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CTL, 5, 2, + rx_int0_interp_mux_text); + +static const struct soc_enum rx_int1_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CTL, 5, 2, + rx_int1_interp_mux_text); + +static const struct soc_enum rx_int2_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CTL, 5, 2, + rx_int2_interp_mux_text); + +static const struct soc_enum rx_int3_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CTL, 5, 2, + rx_int3_interp_mux_text); + +static const struct soc_enum rx_int4_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CTL, 5, 2, + rx_int4_interp_mux_text); + +static const struct soc_enum rx_int5_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CTL, 5, 2, + rx_int5_interp_mux_text); + +static const struct soc_enum rx_int6_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CTL, 5, 2, + rx_int6_interp_mux_text); + +static const struct soc_enum rx_int7_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CTL, 5, 2, + rx_int7_interp_mux_text); + +static const struct soc_enum rx_int8_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2, + rx_int8_interp_mux_text); + +static const struct soc_enum mad_sel_enum = + SOC_ENUM_SINGLE(WCD9335_CPE_SS_CFG, 0, 2, mad_sel_text); + +static const struct soc_enum anc0_fb_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_ANC_CFG0, 0, 5, + anc0_fb_mux_text); + +static const struct soc_enum anc1_fb_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_ANC_CFG0, 3, 3, + anc1_fb_mux_text); + +static const struct snd_kcontrol_new rx_int0_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + tasha_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int1_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + tasha_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int2_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + tasha_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new spl_src0_mux = + SOC_DAPM_ENUM("SPL SRC0 MUX Mux", spl_src0_mux_chain_enum); + +static const struct snd_kcontrol_new spl_src1_mux = + SOC_DAPM_ENUM("SPL SRC1 MUX Mux", spl_src1_mux_chain_enum); + +static const struct snd_kcontrol_new spl_src2_mux = + SOC_DAPM_ENUM("SPL SRC2 MUX Mux", spl_src2_mux_chain_enum); + +static const struct snd_kcontrol_new spl_src3_mux = + SOC_DAPM_ENUM("SPL SRC3 MUX Mux", spl_src3_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int0_2_mux = + SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int1_2_mux = + SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int2_2_mux = + SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int3_2_mux = + SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int4_2_mux = + SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int5_2_mux = + SOC_DAPM_ENUM("RX INT5_2 MUX Mux", rx_int5_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int6_2_mux = + SOC_DAPM_ENUM("RX INT6_2 MUX Mux", rx_int6_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int7_2_mux = + SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int8_2_mux = + SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum); + +static const struct snd_kcontrol_new int1_1_native_mux = + SOC_DAPM_ENUM("RX INT1_1 NATIVE MUX Mux", int1_1_native_enum); + +static const struct snd_kcontrol_new int2_1_native_mux = + SOC_DAPM_ENUM("RX INT2_1 NATIVE MUX Mux", int2_1_native_enum); + +static const struct snd_kcontrol_new int3_1_native_mux = + SOC_DAPM_ENUM("RX INT3_1 NATIVE MUX Mux", int3_1_native_enum); + +static const struct snd_kcontrol_new int4_1_native_mux = + SOC_DAPM_ENUM("RX INT4_1 NATIVE MUX Mux", int4_1_native_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP0 Mux", rx_int5_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP1 Mux", rx_int5_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP2 Mux", rx_int5_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP0 Mux", rx_int6_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP1 Mux", rx_int6_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP2 Mux", rx_int6_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int0_mix2_inp_mux = + SOC_DAPM_ENUM("RX INT0 MIX2 INP Mux", rx_int0_sidetone_mix_chain_enum); + +static const struct snd_kcontrol_new rx_int1_mix2_inp_mux = + SOC_DAPM_ENUM("RX INT1 MIX2 INP Mux", rx_int1_sidetone_mix_chain_enum); + +static const struct snd_kcontrol_new rx_int2_mix2_inp_mux = + SOC_DAPM_ENUM("RX INT2 MIX2 INP Mux", rx_int2_sidetone_mix_chain_enum); + +static const struct snd_kcontrol_new rx_int3_mix2_inp_mux = + SOC_DAPM_ENUM("RX INT3 MIX2 INP Mux", rx_int3_sidetone_mix_chain_enum); + +static const struct snd_kcontrol_new rx_int4_mix2_inp_mux = + SOC_DAPM_ENUM("RX INT4 MIX2 INP Mux", rx_int4_sidetone_mix_chain_enum); + +static const struct snd_kcontrol_new rx_int7_mix2_inp_mux = + SOC_DAPM_ENUM("RX INT7 MIX2 INP Mux", rx_int7_sidetone_mix_chain_enum); + +static const struct snd_kcontrol_new tx_adc_mux0 = + SOC_DAPM_ENUM_EXT("ADC MUX0 Mux", tx_adc_mux0_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux1 = + SOC_DAPM_ENUM_EXT("ADC MUX1 Mux", tx_adc_mux1_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux2 = + SOC_DAPM_ENUM_EXT("ADC MUX2 Mux", tx_adc_mux2_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux3 = + SOC_DAPM_ENUM_EXT("ADC MUX3 Mux", tx_adc_mux3_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux4 = + SOC_DAPM_ENUM_EXT("ADC MUX4 Mux", tx_adc_mux4_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux5 = + SOC_DAPM_ENUM_EXT("ADC MUX5 Mux", tx_adc_mux5_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux6 = + SOC_DAPM_ENUM_EXT("ADC MUX6 Mux", tx_adc_mux6_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux7 = + SOC_DAPM_ENUM_EXT("ADC MUX7 Mux", tx_adc_mux7_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux8 = + SOC_DAPM_ENUM_EXT("ADC MUX8 Mux", tx_adc_mux8_chain_enum, + snd_soc_dapm_get_enum_double, + tasha_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux10 = + SOC_DAPM_ENUM("ADC MUX10 Mux", tx_adc_mux10_chain_enum); + +static const struct snd_kcontrol_new tx_adc_mux11 = + SOC_DAPM_ENUM("ADC MUX11 Mux", tx_adc_mux11_chain_enum); + +static const struct snd_kcontrol_new tx_adc_mux12 = + SOC_DAPM_ENUM("ADC MUX12 Mux", tx_adc_mux12_chain_enum); + +static const struct snd_kcontrol_new tx_adc_mux13 = + SOC_DAPM_ENUM("ADC MUX13 Mux", tx_adc_mux13_chain_enum); + +static const struct snd_kcontrol_new tx_dmic_mux0 = + SOC_DAPM_ENUM("DMIC MUX0 Mux", tx_dmic_mux0_enum); + +static const struct snd_kcontrol_new tx_dmic_mux1 = + SOC_DAPM_ENUM("DMIC MUX1 Mux", tx_dmic_mux1_enum); + +static const struct snd_kcontrol_new tx_dmic_mux2 = + SOC_DAPM_ENUM("DMIC MUX2 Mux", tx_dmic_mux2_enum); + +static const struct snd_kcontrol_new tx_dmic_mux3 = + SOC_DAPM_ENUM("DMIC MUX3 Mux", tx_dmic_mux3_enum); + +static const struct snd_kcontrol_new tx_dmic_mux4 = + SOC_DAPM_ENUM("DMIC MUX4 Mux", tx_dmic_mux4_enum); + +static const struct snd_kcontrol_new tx_dmic_mux5 = + SOC_DAPM_ENUM("DMIC MUX5 Mux", tx_dmic_mux5_enum); + +static const struct snd_kcontrol_new tx_dmic_mux6 = + SOC_DAPM_ENUM("DMIC MUX6 Mux", tx_dmic_mux6_enum); + +static const struct snd_kcontrol_new tx_dmic_mux7 = + SOC_DAPM_ENUM("DMIC MUX7 Mux", tx_dmic_mux7_enum); + +static const struct snd_kcontrol_new tx_dmic_mux8 = + SOC_DAPM_ENUM("DMIC MUX8 Mux", tx_dmic_mux8_enum); + +static const struct snd_kcontrol_new tx_dmic_mux10 = + SOC_DAPM_ENUM("DMIC MUX10 Mux", tx_dmic_mux10_enum); + +static const struct snd_kcontrol_new tx_dmic_mux11 = + SOC_DAPM_ENUM("DMIC MUX11 Mux", tx_dmic_mux11_enum); + +static const struct snd_kcontrol_new tx_dmic_mux12 = + SOC_DAPM_ENUM("DMIC MUX12 Mux", tx_dmic_mux12_enum); + +static const struct snd_kcontrol_new tx_dmic_mux13 = + SOC_DAPM_ENUM("DMIC MUX13 Mux", tx_dmic_mux13_enum); + +static const struct snd_kcontrol_new tx_amic_mux0 = + SOC_DAPM_ENUM("AMIC MUX0 Mux", tx_amic_mux0_enum); + +static const struct snd_kcontrol_new tx_amic_mux1 = + SOC_DAPM_ENUM("AMIC MUX1 Mux", tx_amic_mux1_enum); + +static const struct snd_kcontrol_new tx_amic_mux2 = + SOC_DAPM_ENUM("AMIC MUX2 Mux", tx_amic_mux2_enum); + +static const struct snd_kcontrol_new tx_amic_mux3 = + SOC_DAPM_ENUM("AMIC MUX3 Mux", tx_amic_mux3_enum); + +static const struct snd_kcontrol_new tx_amic_mux4 = + SOC_DAPM_ENUM("AMIC MUX4 Mux", tx_amic_mux4_enum); + +static const struct snd_kcontrol_new tx_amic_mux5 = + SOC_DAPM_ENUM("AMIC MUX5 Mux", tx_amic_mux5_enum); + +static const struct snd_kcontrol_new tx_amic_mux6 = + SOC_DAPM_ENUM("AMIC MUX6 Mux", tx_amic_mux6_enum); + +static const struct snd_kcontrol_new tx_amic_mux7 = + SOC_DAPM_ENUM("AMIC MUX7 Mux", tx_amic_mux7_enum); + +static const struct snd_kcontrol_new tx_amic_mux8 = + SOC_DAPM_ENUM("AMIC MUX8 Mux", tx_amic_mux8_enum); + +static const struct snd_kcontrol_new tx_amic_mux10 = + SOC_DAPM_ENUM("AMIC MUX10 Mux", tx_amic_mux10_enum); + +static const struct snd_kcontrol_new tx_amic_mux11 = + SOC_DAPM_ENUM("AMIC MUX11 Mux", tx_amic_mux11_enum); + +static const struct snd_kcontrol_new tx_amic_mux12 = + SOC_DAPM_ENUM("AMIC MUX12 Mux", tx_amic_mux12_enum); + +static const struct snd_kcontrol_new tx_amic_mux13 = + SOC_DAPM_ENUM("AMIC MUX13 Mux", tx_amic_mux13_enum); + +static const struct snd_kcontrol_new sb_tx0_mux = + SOC_DAPM_ENUM("SLIM TX0 MUX Mux", sb_tx0_mux_enum); + +static const struct snd_kcontrol_new sb_tx1_mux = + SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum); + +static const struct snd_kcontrol_new sb_tx2_mux = + SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum); + +static const struct snd_kcontrol_new sb_tx3_mux = + SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum); + +static const struct snd_kcontrol_new sb_tx4_mux = + SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum); + +static const struct snd_kcontrol_new sb_tx5_mux = + SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum); + +static const struct snd_kcontrol_new sb_tx6_mux = + SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum); + +static const struct snd_kcontrol_new sb_tx7_mux = + SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum); + +static const struct snd_kcontrol_new sb_tx8_mux = + SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum); + +static const struct snd_kcontrol_new sb_tx9_mux = + SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum); + +static const struct snd_kcontrol_new sb_tx10_mux = + SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum); + +static const struct snd_kcontrol_new sb_tx11_mux = + SOC_DAPM_ENUM("SLIM TX11 MUX Mux", sb_tx11_mux_enum); + +static const struct snd_kcontrol_new sb_tx11_inp1_mux = + SOC_DAPM_ENUM("SLIM TX11 INP1 MUX Mux", sb_tx11_inp1_mux_enum); + +static const struct snd_kcontrol_new sb_tx13_mux = + SOC_DAPM_ENUM("SLIM TX13 MUX Mux", sb_tx13_mux_enum); + +static const struct snd_kcontrol_new tx13_inp_mux = + SOC_DAPM_ENUM("TX13 INP MUX Mux", tx13_inp_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx0_mux = + SOC_DAPM_ENUM("RX MIX TX0 MUX Mux", rx_mix_tx0_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx1_mux = + SOC_DAPM_ENUM("RX MIX TX1 MUX Mux", rx_mix_tx1_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx2_mux = + SOC_DAPM_ENUM("RX MIX TX2 MUX Mux", rx_mix_tx2_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx3_mux = + SOC_DAPM_ENUM("RX MIX TX3 MUX Mux", rx_mix_tx3_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx4_mux = + SOC_DAPM_ENUM("RX MIX TX4 MUX Mux", rx_mix_tx4_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx5_mux = + SOC_DAPM_ENUM("RX MIX TX5 MUX Mux", rx_mix_tx5_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx6_mux = + SOC_DAPM_ENUM("RX MIX TX6 MUX Mux", rx_mix_tx6_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx7_mux = + SOC_DAPM_ENUM("RX MIX TX7 MUX Mux", rx_mix_tx7_mux_enum); + +static const struct snd_kcontrol_new rx_mix_tx8_mux = + SOC_DAPM_ENUM("RX MIX TX8 MUX Mux", rx_mix_tx8_mux_enum); + +static const struct snd_kcontrol_new iir0_inp0_mux = + SOC_DAPM_ENUM("IIR0 INP0 Mux", iir0_inp0_mux_enum); + +static const struct snd_kcontrol_new iir0_inp1_mux = + SOC_DAPM_ENUM("IIR0 INP1 Mux", iir0_inp1_mux_enum); + +static const struct snd_kcontrol_new iir0_inp2_mux = + SOC_DAPM_ENUM("IIR0 INP2 Mux", iir0_inp2_mux_enum); + +static const struct snd_kcontrol_new iir0_inp3_mux = + SOC_DAPM_ENUM("IIR0 INP3 Mux", iir0_inp3_mux_enum); + +static const struct snd_kcontrol_new iir1_inp0_mux = + SOC_DAPM_ENUM("IIR1 INP0 Mux", iir1_inp0_mux_enum); + +static const struct snd_kcontrol_new iir1_inp1_mux = + SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum); + +static const struct snd_kcontrol_new iir1_inp2_mux = + SOC_DAPM_ENUM("IIR1 INP2 Mux", iir1_inp2_mux_enum); + +static const struct snd_kcontrol_new iir1_inp3_mux = + SOC_DAPM_ENUM("IIR1 INP3 Mux", iir1_inp3_mux_enum); + +static const struct snd_kcontrol_new rx_int0_interp_mux = + SOC_DAPM_ENUM("RX INT0 INTERP Mux", rx_int0_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int1_interp_mux = + SOC_DAPM_ENUM("RX INT1 INTERP Mux", rx_int1_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int2_interp_mux = + SOC_DAPM_ENUM("RX INT2 INTERP Mux", rx_int2_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int3_interp_mux = + SOC_DAPM_ENUM("RX INT3 INTERP Mux", rx_int3_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int4_interp_mux = + SOC_DAPM_ENUM("RX INT4 INTERP Mux", rx_int4_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int5_interp_mux = + SOC_DAPM_ENUM("RX INT5 INTERP Mux", rx_int5_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int6_interp_mux = + SOC_DAPM_ENUM("RX INT6 INTERP Mux", rx_int6_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int7_interp_mux = + SOC_DAPM_ENUM("RX INT7 INTERP Mux", rx_int7_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int8_interp_mux = + SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum); + +static const struct snd_kcontrol_new mad_sel_mux = + SOC_DAPM_ENUM("MAD_SEL MUX Mux", mad_sel_enum); + +static const struct snd_kcontrol_new aif4_mad_switch = + SOC_DAPM_SINGLE("Switch", WCD9335_CPE_SS_CFG, 5, 1, 0); + +static const struct snd_kcontrol_new mad_brdcst_switch = + SOC_DAPM_SINGLE("Switch", WCD9335_CPE_SS_CFG, 6, 1, 0); + +static const struct snd_kcontrol_new aif4_switch_mixer_controls = + SOC_SINGLE_EXT("Switch", SND_SOC_NOPM, + 0, 1, 0, tasha_codec_aif4_mixer_switch_get, + tasha_codec_aif4_mixer_switch_put); + +static const struct snd_kcontrol_new anc_hphl_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_hphr_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_ear_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_ear_spkr_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_lineout1_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_lineout2_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_spkr_pa_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux0_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux1_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux2_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux3_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux4_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux5_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux6_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux7_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux8_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc0_fb_mux = + SOC_DAPM_ENUM("ANC0 FB MUX Mux", anc0_fb_mux_enum); + +static const struct snd_kcontrol_new anc1_fb_mux = + SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum); + +static int tasha_codec_ec_buf_mux_enable(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s: event = %d name = %s\n", + __func__, event, w->name); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write(component, + WCD9335_CPE_SS_EC_BUF_INT_PERIOD, 0x3B); + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_CFG, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0x08, 0x08); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, + 0x08, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_CFG, 0x08, 0x00); + snd_soc_component_write(component, + WCD9335_CPE_SS_EC_BUF_INT_PERIOD, 0x00); + break; + } + + return 0; +}; + +static const char * const ec_buf_mux_text[] = { + "ZERO", "RXMIXEC", "SB_RX0", "SB_RX1", "SB_RX2", "SB_RX3", + "I2S_RX_SD0_L", "I2S_RX_SD0_R", "I2S_RX_SD1_L", "I2S_RX_SD1_R", + "DEC1" +}; + +static SOC_ENUM_SINGLE_DECL(ec_buf_mux_enum, WCD9335_CPE_SS_US_EC_MUX_CFG, + 0, ec_buf_mux_text); + +static const struct snd_kcontrol_new ec_buf_mux = + SOC_DAPM_ENUM("EC BUF Mux", ec_buf_mux_enum); + +static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("ANC EAR"), + SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM, + AIF1_PB, 0, tasha_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM, + AIF2_PB, 0, tasha_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM, + AIF3_PB, 0, tasha_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM, + AIF4_PB, 0, tasha_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF MIX1 PB", "AIF Mix Playback", 0, + SND_SOC_NOPM, AIF_MIX1_PB, 0, + tasha_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, TASHA_RX0, 0, + &slim_rx_mux[TASHA_RX0]), + SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TASHA_RX1, 0, + &slim_rx_mux[TASHA_RX1]), + SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TASHA_RX2, 0, + &slim_rx_mux[TASHA_RX2]), + SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TASHA_RX3, 0, + &slim_rx_mux[TASHA_RX3]), + SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TASHA_RX4, 0, + &slim_rx_mux[TASHA_RX4]), + SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TASHA_RX5, 0, + &slim_rx_mux[TASHA_RX5]), + SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, TASHA_RX6, 0, + &slim_rx_mux[TASHA_RX6]), + SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, TASHA_RX7, 0, + &slim_rx_mux[TASHA_RX7]), + + SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("SPL SRC0 MUX", SND_SOC_NOPM, SPLINE_SRC0, 0, + &spl_src0_mux, tasha_codec_enable_spline_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("SPL SRC1 MUX", SND_SOC_NOPM, SPLINE_SRC1, 0, + &spl_src1_mux, tasha_codec_enable_spline_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("SPL SRC2 MUX", SND_SOC_NOPM, SPLINE_SRC2, 0, + &spl_src2_mux, tasha_codec_enable_spline_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("SPL SRC3 MUX", SND_SOC_NOPM, SPLINE_SRC3, 0, + &spl_src3_mux, tasha_codec_enable_spline_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + 5, 0, &rx_int0_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + 5, 0, &rx_int1_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + 5, 0, &rx_int2_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD9335_CDC_RX3_RX_PATH_MIX_CTL, + 5, 0, &rx_int3_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD9335_CDC_RX4_RX_PATH_MIX_CTL, + 5, 0, &rx_int4_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT5_2 MUX", WCD9335_CDC_RX5_RX_PATH_MIX_CTL, + 5, 0, &rx_int5_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT6_2 MUX", WCD9335_CDC_RX6_RX_PATH_MIX_CTL, + 5, 0, &rx_int6_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD9335_CDC_RX7_RX_PATH_MIX_CTL, + 5, 0, &rx_int7_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD9335_CDC_RX8_RX_PATH_MIX_CTL, + 5, 0, &rx_int8_2_mux, tasha_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp2_mux), + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp0_mux, tasha_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp1_mux, tasha_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp2_mux, tasha_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp0_mux, tasha_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp1_mux, tasha_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp2_mux, tasha_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int1_spline_mix_switch, + ARRAY_SIZE(rx_int1_spline_mix_switch)), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int2_spline_mix_switch, + ARRAY_SIZE(rx_int2_spline_mix_switch)), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int3_spline_mix_switch, + ARRAY_SIZE(rx_int3_spline_mix_switch)), + SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int4_spline_mix_switch, + ARRAY_SIZE(rx_int4_spline_mix_switch)), + SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int5_spline_mix_switch, + ARRAY_SIZE(rx_int5_spline_mix_switch)), + SND_SOC_DAPM_MIXER("RX INT5 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX INT6_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int6_spline_mix_switch, + ARRAY_SIZE(rx_int6_spline_mix_switch)), + SND_SOC_DAPM_MIXER("RX INT6 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int7_spline_mix_switch, + ARRAY_SIZE(rx_int7_spline_mix_switch)), + + SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 SPLINE MIX", SND_SOC_NOPM, 0, 0, + rx_int8_spline_mix_switch, + ARRAY_SIZE(rx_int8_spline_mix_switch)), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, tasha_codec_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX INT8 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, tasha_codec_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("RX INT5 VBAT", SND_SOC_NOPM, 0, 0, + rx_int5_vbat_mix_switch, + ARRAY_SIZE(rx_int5_vbat_mix_switch), + tasha_codec_vbat_enable_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX INT6 VBAT", SND_SOC_NOPM, 0, 0, + rx_int6_vbat_mix_switch, + ARRAY_SIZE(rx_int6_vbat_mix_switch), + tasha_codec_vbat_enable_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX INT7 VBAT", SND_SOC_NOPM, 0, 0, + rx_int7_vbat_mix_switch, + ARRAY_SIZE(rx_int7_vbat_mix_switch), + tasha_codec_vbat_enable_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX INT8 VBAT", SND_SOC_NOPM, 0, 0, + rx_int8_vbat_mix_switch, + ARRAY_SIZE(rx_int8_vbat_mix_switch), + tasha_codec_vbat_enable_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RX INT0 MIX2 INP", WCD9335_CDC_RX0_RX_PATH_CFG1, 4, + 0, &rx_int0_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT1 MIX2 INP", WCD9335_CDC_RX1_RX_PATH_CFG1, 4, + 0, &rx_int1_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT2 MIX2 INP", WCD9335_CDC_RX2_RX_PATH_CFG1, 4, + 0, &rx_int2_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT3 MIX2 INP", WCD9335_CDC_RX3_RX_PATH_CFG1, 4, + 0, &rx_int3_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT4 MIX2 INP", WCD9335_CDC_RX4_RX_PATH_CFG1, 4, + 0, &rx_int4_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT7 MIX2 INP", WCD9335_CDC_RX7_RX_PATH_CFG1, 4, + 0, &rx_int7_mix2_inp_mux), + + SND_SOC_DAPM_MUX("SLIM TX0 MUX", SND_SOC_NOPM, TASHA_TX0, 0, + &sb_tx0_mux), + SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TASHA_TX1, 0, + &sb_tx1_mux), + SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TASHA_TX2, 0, + &sb_tx2_mux), + SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TASHA_TX3, 0, + &sb_tx3_mux), + SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TASHA_TX4, 0, + &sb_tx4_mux), + SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TASHA_TX5, 0, + &sb_tx5_mux), + SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, TASHA_TX6, 0, + &sb_tx6_mux), + SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, TASHA_TX7, 0, + &sb_tx7_mux), + SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, TASHA_TX8, 0, + &sb_tx8_mux), + SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, TASHA_TX9, 0, + &sb_tx9_mux), + SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, TASHA_TX10, 0, + &sb_tx10_mux), + SND_SOC_DAPM_MUX("SLIM TX11 MUX", SND_SOC_NOPM, TASHA_TX11, 0, + &sb_tx11_mux), + SND_SOC_DAPM_MUX("SLIM TX11 INP1 MUX", SND_SOC_NOPM, TASHA_TX11, 0, + &sb_tx11_inp1_mux), + SND_SOC_DAPM_MUX("SLIM TX13 MUX", SND_SOC_NOPM, TASHA_TX13, 0, + &sb_tx13_mux), + SND_SOC_DAPM_MUX("TX13 INP MUX", SND_SOC_NOPM, 0, 0, + &tx13_inp_mux), + + SND_SOC_DAPM_MUX_E("ADC MUX0", WCD9335_CDC_TX0_TX_PATH_CTL, 5, 0, + &tx_adc_mux0, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX1", WCD9335_CDC_TX1_TX_PATH_CTL, 5, 0, + &tx_adc_mux1, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX2", WCD9335_CDC_TX2_TX_PATH_CTL, 5, 0, + &tx_adc_mux2, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX3", WCD9335_CDC_TX3_TX_PATH_CTL, 5, 0, + &tx_adc_mux3, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX4", WCD9335_CDC_TX4_TX_PATH_CTL, 5, 0, + &tx_adc_mux4, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX5", WCD9335_CDC_TX5_TX_PATH_CTL, 5, 0, + &tx_adc_mux5, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX6", WCD9335_CDC_TX6_TX_PATH_CTL, 5, 0, + &tx_adc_mux6, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX7", WCD9335_CDC_TX7_TX_PATH_CTL, 5, 0, + &tx_adc_mux7, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX8", WCD9335_CDC_TX8_TX_PATH_CTL, 5, 0, + &tx_adc_mux8, tasha_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX10", SND_SOC_NOPM, 10, 0, + &tx_adc_mux10, tasha_codec_tx_adc_cfg, + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX11", SND_SOC_NOPM, 11, 0, + &tx_adc_mux11, tasha_codec_tx_adc_cfg, + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX12", SND_SOC_NOPM, 12, 0, + &tx_adc_mux12, tasha_codec_tx_adc_cfg, + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX13", SND_SOC_NOPM, 13, 0, + &tx_adc_mux13, tasha_codec_tx_adc_cfg, + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX("DMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux0), + SND_SOC_DAPM_MUX("DMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux1), + SND_SOC_DAPM_MUX("DMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux2), + SND_SOC_DAPM_MUX("DMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux3), + SND_SOC_DAPM_MUX("DMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux4), + SND_SOC_DAPM_MUX("DMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux5), + SND_SOC_DAPM_MUX("DMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux6), + SND_SOC_DAPM_MUX("DMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux7), + SND_SOC_DAPM_MUX("DMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux8), + SND_SOC_DAPM_MUX("DMIC MUX10", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux10), + SND_SOC_DAPM_MUX("DMIC MUX11", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux11), + SND_SOC_DAPM_MUX("DMIC MUX12", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux12), + SND_SOC_DAPM_MUX("DMIC MUX13", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux13), + + SND_SOC_DAPM_MUX("AMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_amic_mux0), + SND_SOC_DAPM_MUX("AMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_amic_mux1), + SND_SOC_DAPM_MUX("AMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_amic_mux2), + SND_SOC_DAPM_MUX("AMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_amic_mux3), + SND_SOC_DAPM_MUX("AMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_amic_mux4), + SND_SOC_DAPM_MUX("AMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_amic_mux5), + SND_SOC_DAPM_MUX("AMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_amic_mux6), + SND_SOC_DAPM_MUX("AMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_amic_mux7), + SND_SOC_DAPM_MUX("AMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_amic_mux8), + SND_SOC_DAPM_MUX("AMIC MUX10", SND_SOC_NOPM, 0, 0, + &tx_amic_mux10), + SND_SOC_DAPM_MUX("AMIC MUX11", SND_SOC_NOPM, 0, 0, + &tx_amic_mux11), + SND_SOC_DAPM_MUX("AMIC MUX12", SND_SOC_NOPM, 0, 0, + &tx_amic_mux12), + SND_SOC_DAPM_MUX("AMIC MUX13", SND_SOC_NOPM, 0, 0, + &tx_amic_mux13), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD9335_ANA_AMIC1, 7, 0, + tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD9335_ANA_AMIC2, 7, 0, + tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD9335_ANA_AMIC3, 7, 0, + tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD9335_ANA_AMIC4, 7, 0, + tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC5", NULL, WCD9335_ANA_AMIC5, 7, 0, + tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC6", NULL, WCD9335_ANA_AMIC6, 7, 0, + tasha_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY("RX INT1 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_HPHL, 0, tasha_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY("RX INT2 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_HPHR, 0, tasha_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY("RX INT3 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_LO1, 0, tasha_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY("RX INT4 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_LO2, 0, tasha_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0, + tasha_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS2", SND_SOC_NOPM, 0, 0, + tasha_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS3", SND_SOC_NOPM, 0, 0, + tasha_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS4", SND_SOC_NOPM, 0, 0, + tasha_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0, + tasha_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_STANDALONE, SND_SOC_NOPM, 0, 0, + tasha_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS3_STANDALONE, SND_SOC_NOPM, 0, 0, + tasha_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0, + tasha_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_LDO_H_STANDALONE, SND_SOC_NOPM, 0, 0, + tasha_codec_force_enable_ldo_h, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("tx regulator", SND_SOC_NOPM, + ON_DEMAND_TX_SUPPLY, 0, + tasha_codec_enable_on_demand_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("rx regulator", SND_SOC_NOPM, + ON_DEMAND_RX_SUPPLY, 0, + tasha_codec_enable_on_demand_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("ANC0 FB MUX", SND_SOC_NOPM, 0, 0, &anc0_fb_mux), + SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux), + + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + SND_SOC_DAPM_INPUT("AMIC6"), + + SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM, + AIF1_CAP, 0, tasha_codec_enable_slimtx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM, + AIF2_CAP, 0, tasha_codec_enable_slimtx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM, + AIF3_CAP, 0, tasha_codec_enable_slimtx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM, + AIF4_VIFEED, 0, tasha_codec_enable_slimvi_feedback, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("AIF4_VI Mixer", SND_SOC_NOPM, AIF4_VIFEED, 0, + aif4_vi_mixer, ARRAY_SIZE(aif4_vi_mixer)), + + SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0, + aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, + aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF4_MAD Mixer", SND_SOC_NOPM, AIF4_MAD_TX, 0, + aif4_mad_mixer, ARRAY_SIZE(aif4_mad_mixer)), + + SND_SOC_DAPM_INPUT("VIINPUT"), + + SND_SOC_DAPM_AIF_OUT("AIF5 CPE", "AIF5 CPE TX", 0, SND_SOC_NOPM, + AIF5_CPE_TX, 0), + + SND_SOC_DAPM_MUX_E("EC BUF MUX INP", SND_SOC_NOPM, 0, 0, &ec_buf_mux, + tasha_codec_ec_buf_mux_enable, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0, + tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0, + tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0, + tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0, + tasha_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("IIR0 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp0_mux), + SND_SOC_DAPM_MUX("IIR0 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp1_mux), + SND_SOC_DAPM_MUX("IIR0 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp2_mux), + SND_SOC_DAPM_MUX("IIR0 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir0_inp3_mux), + SND_SOC_DAPM_MUX("IIR1 INP0 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp0_mux), + SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux), + SND_SOC_DAPM_MUX("IIR1 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp2_mux), + SND_SOC_DAPM_MUX("IIR1 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp3_mux), + + SND_SOC_DAPM_MIXER_E("IIR0", WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL, + 4, 0, NULL, 0, tasha_codec_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER_E("IIR1", WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL, + 4, 0, NULL, 0, tasha_codec_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER("SRC0", WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SRC1", WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("CPE IN Mixer", SND_SOC_NOPM, 0, 0, + cpe_in_mix_switch, + ARRAY_SIZE(cpe_in_mix_switch), + tasha_codec_configure_cpe_input, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RX INT1_1 NATIVE MUX", SND_SOC_NOPM, 0, 0, + &int1_1_native_mux), + SND_SOC_DAPM_MUX("RX INT2_1 NATIVE MUX", SND_SOC_NOPM, 0, 0, + &int2_1_native_mux), + SND_SOC_DAPM_MUX("RX INT3_1 NATIVE MUX", SND_SOC_NOPM, 0, 0, + &int3_1_native_mux), + SND_SOC_DAPM_MUX("RX INT4_1 NATIVE MUX", SND_SOC_NOPM, 0, 0, + &int4_1_native_mux), + SND_SOC_DAPM_MUX("RX MIX TX0 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx0_mux), + SND_SOC_DAPM_MUX("RX MIX TX1 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx1_mux), + SND_SOC_DAPM_MUX("RX MIX TX2 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx2_mux), + SND_SOC_DAPM_MUX("RX MIX TX3 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx3_mux), + SND_SOC_DAPM_MUX("RX MIX TX4 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx4_mux), + SND_SOC_DAPM_MUX("RX MIX TX5 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx5_mux), + SND_SOC_DAPM_MUX("RX MIX TX6 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx6_mux), + SND_SOC_DAPM_MUX("RX MIX TX7 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx7_mux), + SND_SOC_DAPM_MUX("RX MIX TX8 MUX", SND_SOC_NOPM, 0, 0, + &rx_mix_tx8_mux), + + SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int0_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int1_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int2_dem_inp_mux), + + SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM, + INTERP_EAR, 0, &rx_int0_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM, + INTERP_HPHL, 0, &rx_int1_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM, + INTERP_HPHR, 0, &rx_int2_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM, + INTERP_LO1, 0, &rx_int3_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM, + INTERP_LO2, 0, &rx_int4_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT5 INTERP", SND_SOC_NOPM, + INTERP_LO3, 0, &rx_int5_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT6 INTERP", SND_SOC_NOPM, + INTERP_LO4, 0, &rx_int6_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM, + INTERP_SPKR1, 0, &rx_int7_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM, + INTERP_SPKR2, 0, &rx_int8_interp_mux, + tasha_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM, + 0, 0, tasha_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, SND_SOC_NOPM, + 0, 0, tasha_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, SND_SOC_NOPM, + 0, 0, tasha_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM, + 0, 0, tasha_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM, + 0, 0, tasha_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT5 DAC", NULL, SND_SOC_NOPM, + 0, 0, tasha_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT6 DAC", NULL, SND_SOC_NOPM, + 0, 0, tasha_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tasha_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tasha_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0, + tasha_codec_enable_ear_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0, + tasha_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD9335_ANA_LO_1_2, 6, 0, NULL, 0, + tasha_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT3 PA", WCD9335_ANA_LO_3_4, 7, 0, NULL, 0, + tasha_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT4 PA", WCD9335_ANA_LO_3_4, 6, 0, NULL, 0, + tasha_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0, + tasha_codec_enable_ear_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tasha_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tasha_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC LINEOUT1 PA", WCD9335_ANA_LO_1_2, + 7, 0, NULL, 0, + tasha_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC LINEOUT2 PA", WCD9335_ANA_LO_1_2, + 6, 0, NULL, 0, + tasha_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC SPK1 PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tasha_codec_enable_spk_anc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + SND_SOC_DAPM_OUTPUT("ANC HPHL"), + SND_SOC_DAPM_OUTPUT("ANC HPHR"), + SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0, + tasha_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("SPK1 OUT"), + SND_SOC_DAPM_OUTPUT("SPK2 OUT"), + SND_SOC_DAPM_OUTPUT("LINEOUT1"), + SND_SOC_DAPM_OUTPUT("LINEOUT2"), + SND_SOC_DAPM_OUTPUT("LINEOUT3"), + SND_SOC_DAPM_OUTPUT("LINEOUT4"), + SND_SOC_DAPM_OUTPUT("ANC LINEOUT1"), + SND_SOC_DAPM_OUTPUT("ANC LINEOUT2"), + SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM, + ON_DEMAND_MICBIAS, 0, + tasha_codec_enable_on_demand_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SWITCH("ADC US MUX0", WCD9335_CDC_TX0_TX_PATH_192_CTL, 0, + 0, &adc_us_mux0_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX1", WCD9335_CDC_TX1_TX_PATH_192_CTL, 0, + 0, &adc_us_mux1_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX2", WCD9335_CDC_TX2_TX_PATH_192_CTL, 0, + 0, &adc_us_mux2_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX3", WCD9335_CDC_TX3_TX_PATH_192_CTL, 0, + 0, &adc_us_mux3_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX4", WCD9335_CDC_TX4_TX_PATH_192_CTL, 0, + 0, &adc_us_mux4_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX5", WCD9335_CDC_TX5_TX_PATH_192_CTL, 0, + 0, &adc_us_mux5_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX6", WCD9335_CDC_TX6_TX_PATH_192_CTL, 0, + 0, &adc_us_mux6_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX7", WCD9335_CDC_TX7_TX_PATH_192_CTL, 0, + 0, &adc_us_mux7_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX8", WCD9335_CDC_TX8_TX_PATH_192_CTL, 0, + 0, &adc_us_mux8_switch), + /* MAD related widgets */ + SND_SOC_DAPM_AIF_OUT_E("AIF4 MAD", "AIF4 MAD TX", 0, + SND_SOC_NOPM, 0, 0, + tasha_codec_enable_mad, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("MAD_SEL MUX", SND_SOC_NOPM, 0, 0, + &mad_sel_mux), + SND_SOC_DAPM_INPUT("MAD_CPE_INPUT"), + SND_SOC_DAPM_INPUT("MADINPUT"), + SND_SOC_DAPM_SWITCH("MADONOFF", SND_SOC_NOPM, 0, 0, + &aif4_mad_switch), + SND_SOC_DAPM_SWITCH("MAD_BROADCAST", SND_SOC_NOPM, 0, 0, + &mad_brdcst_switch), + SND_SOC_DAPM_SWITCH("AIF4", SND_SOC_NOPM, 0, 0, + &aif4_switch_mixer_controls), + SND_SOC_DAPM_SWITCH("ANC HPHL Enable", SND_SOC_NOPM, 0, 0, + &anc_hphl_switch), + SND_SOC_DAPM_SWITCH("ANC HPHR Enable", SND_SOC_NOPM, 0, 0, + &anc_hphr_switch), + SND_SOC_DAPM_SWITCH("ANC EAR Enable", SND_SOC_NOPM, 0, 0, + &anc_ear_switch), + SND_SOC_DAPM_SWITCH("ANC OUT EAR SPKR Enable", SND_SOC_NOPM, 0, 0, + &anc_ear_spkr_switch), + SND_SOC_DAPM_SWITCH("ANC LINEOUT1 Enable", SND_SOC_NOPM, 0, 0, + &anc_lineout1_switch), + SND_SOC_DAPM_SWITCH("ANC LINEOUT2 Enable", SND_SOC_NOPM, 0, 0, + &anc_lineout2_switch), + SND_SOC_DAPM_SWITCH("ANC SPKR PA Enable", SND_SOC_NOPM, 0, 0, + &anc_spkr_pa_switch), +}; + +static int tasha_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct tasha_priv *tasha_p = + snd_soc_component_get_drvdata(dai->component); + u32 i = 0; + struct wcd9xxx_ch *ch; + + switch (dai->id) { + case AIF1_PB: + case AIF2_PB: + case AIF3_PB: + case AIF4_PB: + case AIF_MIX1_PB: + if (!rx_slot || !rx_num) { + pr_err("%s: Invalid rx_slot %pK or rx_num %pK\n", + __func__, rx_slot, rx_num); + return -EINVAL; + } + list_for_each_entry(ch, &tasha_p->dai[dai->id].wcd9xxx_ch_list, + list) { + pr_debug("%s: slot_num %u ch->ch_num %d\n", + __func__, i, ch->ch_num); + rx_slot[i++] = ch->ch_num; + } + pr_debug("%s: rx_num %d\n", __func__, i); + *rx_num = i; + break; + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + case AIF4_MAD_TX: + case AIF4_VIFEED: + if (!tx_slot || !tx_num) { + pr_err("%s: Invalid tx_slot %pK or tx_num %pK\n", + __func__, tx_slot, tx_num); + return -EINVAL; + } + list_for_each_entry(ch, &tasha_p->dai[dai->id].wcd9xxx_ch_list, + list) { + pr_debug("%s: slot_num %u ch->ch_num %d\n", + __func__, i, ch->ch_num); + tx_slot[i++] = ch->ch_num; + } + pr_debug("%s: tx_num %d\n", __func__, i); + *tx_num = i; + break; + + default: + pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id); + break; + } + + return 0; +} + +static int tasha_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct tasha_priv *tasha; + struct wcd9xxx *core; + struct wcd9xxx_codec_dai_data *dai_data = NULL; + + if (!dai) { + pr_err("%s: dai is empty\n", __func__); + return -EINVAL; + } + tasha = snd_soc_component_get_drvdata(dai->component); + core = dev_get_drvdata(dai->component->dev->parent); + + if (!tx_slot || !rx_slot) { + pr_err("%s: Invalid tx_slot=%pK, rx_slot=%pK\n", + __func__, tx_slot, rx_slot); + return -EINVAL; + } + pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n" + "tasha->intf_type %d\n", + __func__, dai->name, dai->id, tx_num, rx_num, + tasha->intf_type); + + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + wcd9xxx_init_slimslave(core, core->slim->laddr, + tx_num, tx_slot, rx_num, rx_slot); + /* Reserve TX12/TX13 for MAD data channel */ + dai_data = &tasha->dai[AIF4_MAD_TX]; + if (dai_data) { + if (TASHA_IS_2_0(tasha->wcd9xxx)) + list_add_tail(&core->tx_chs[TASHA_TX13].list, + &dai_data->wcd9xxx_ch_list); + else + list_add_tail(&core->tx_chs[TASHA_TX12].list, + &dai_data->wcd9xxx_ch_list); + } + } + return 0; +} + +static int tasha_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + return 0; +} + +static void tasha_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tasha_priv *tasha = + snd_soc_component_get_drvdata(dai->component); + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) + return; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tasha_codec_vote_max_bw(dai->component, false); +} + +static int tasha_set_decimator_rate(struct snd_soc_dai *dai, + u8 tx_fs_rate_reg_val, u32 sample_rate) +{ + struct snd_soc_component *component = dai->component; + struct wcd9xxx_ch *ch; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u32 tx_port = 0; + u8 shift = 0, shift_val = 0, tx_mux_sel = 0; + int decimator = -1; + u16 tx_port_reg = 0, tx_fs_reg = 0; + + list_for_each_entry(ch, &tasha->dai[dai->id].wcd9xxx_ch_list, list) { + tx_port = ch->port; + dev_dbg(component->dev, "%s: dai->id = %d, tx_port = %d", + __func__, dai->id, tx_port); + + if ((tx_port < 0) || (tx_port == 12) || (tx_port >= 14)) { + dev_err(component->dev, "%s: Invalid SLIM TX%u port. DAI ID: %d\n", + __func__, tx_port, dai->id); + return -EINVAL; + } + /* Find the SB TX MUX input - which decimator is connected */ + if (tx_port < 4) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0; + shift = (tx_port << 1); + shift_val = 0x03; + } else if ((tx_port >= 4) && (tx_port < 8)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1; + shift = ((tx_port - 4) << 1); + shift_val = 0x03; + } else if ((tx_port >= 8) && (tx_port < 11)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2; + shift = ((tx_port - 8) << 1); + shift_val = 0x03; + } else if (tx_port == 11) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 0; + shift_val = 0x0F; + } else if (tx_port == 13) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 4; + shift_val = 0x03; + } + tx_mux_sel = snd_soc_component_read32(component, tx_port_reg) & + (shift_val << shift); + tx_mux_sel = tx_mux_sel >> shift; + + if (tx_port <= 8) { + if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3)) + decimator = tx_port; + } else if (tx_port <= 10) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = ((tx_port == 9) ? 7 : 6); + } else if (tx_port == 11) { + if ((tx_mux_sel >= 1) && (tx_mux_sel < 7)) + decimator = tx_mux_sel - 1; + } else if (tx_port == 13) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = 5; + } + + if (decimator >= 0) { + tx_fs_reg = WCD9335_CDC_TX0_TX_PATH_CTL + + 16 * decimator; + dev_dbg(component->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n", + __func__, decimator, tx_port, sample_rate); + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, tx_fs_rate_reg_val); + } else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) { + /* Check if the TX Mux input is RX MIX TXn */ + dev_dbg(component->dev, "%s: RX_MIX_TX%u going to SLIM TX%u\n", + __func__, tx_port, tx_port); + } else { + dev_err(component->dev, "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int tasha_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 int_mix_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp; + u32 j; + u16 int_mux_cfg1, int_fs_reg; + u8 int_mux_cfg1_val; + struct snd_soc_component *component = dai->component; + struct wcd9xxx_ch *ch; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + list_for_each_entry(ch, &tasha->dai[dai->id].wcd9xxx_ch_list, list) { + int_2_inp = ch->port + INTn_2_INP_SEL_RX0 - + TASHA_RX_PORT_START_NUMBER; + if ((int_2_inp < INTn_2_INP_SEL_RX0) || + (int_2_inp > INTn_2_INP_SEL_RX7)) { + pr_err("%s: Invalid RX%u port, Dai ID is %d\n", + __func__, + (ch->port - TASHA_RX_PORT_START_NUMBER), + dai->id); + return -EINVAL; + } + + int_mux_cfg1 = WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < TASHA_NUM_INTERPOLATORS; j++) { + int_mux_cfg1_val = snd_soc_component_read32( + component, int_mux_cfg1) & + 0x0F; + if (int_mux_cfg1_val == int_2_inp) { + int_fs_reg = WCD9335_CDC_RX0_RX_PATH_MIX_CTL + + 20 * j; + pr_debug("%s: AIF_MIX_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + pr_debug("%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits(component, + int_fs_reg, + 0x0F, int_mix_fs_rate_reg_val); + } + int_mux_cfg1 += 2; + } + } + return 0; +} + +static int tasha_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 int_prim_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp; + u32 j; + u16 int_mux_cfg0, int_mux_cfg1; + u16 int_fs_reg; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 inp0_sel, inp1_sel, inp2_sel; + struct snd_soc_component *component = dai->component; + struct wcd9xxx_ch *ch; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + list_for_each_entry(ch, &tasha->dai[dai->id].wcd9xxx_ch_list, list) { + int_1_mix1_inp = ch->port + INTn_1_MIX_INP_SEL_RX0 - + TASHA_RX_PORT_START_NUMBER; + if ((int_1_mix1_inp < INTn_1_MIX_INP_SEL_RX0) || + (int_1_mix1_inp > INTn_1_MIX_INP_SEL_RX7)) { + pr_err("%s: Invalid RX%u port, Dai ID is %d\n", + __func__, + (ch->port - TASHA_RX_PORT_START_NUMBER), + dai->id); + return -EINVAL; + } + + int_mux_cfg0 = WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the slim rx port + * is connected + */ + for (j = 0; j < TASHA_NUM_INTERPOLATORS; j++) { + int_mux_cfg1 = int_mux_cfg0 + 1; + + int_mux_cfg0_val = snd_soc_component_read32(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read32(component, + int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & 0x0F; + inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F; + inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F; + if ((inp0_sel == int_1_mix1_inp) || + (inp1_sel == int_1_mix1_inp) || + (inp2_sel == int_1_mix1_inp)) { + int_fs_reg = WCD9335_CDC_RX0_RX_PATH_CTL + + 20 * j; + pr_debug("%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + pr_debug("%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + /* sample_rate is in Hz */ + if ((j == 0) && (sample_rate == 44100)) { + pr_info("%s: Cannot set 44.1KHz on INT0\n", + __func__); + } else + snd_soc_component_update_bits( + component, int_fs_reg, + 0x0F, int_prim_fs_rate_reg_val); + } + int_mux_cfg0 += 2; + } + } + + return 0; +} + + +static int tasha_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + int rate_val = 0; + int i, ret; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) { + if (sample_rate == + int_mix_sample_rate_val[i].sample_rate) { + rate_val = + int_mix_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) || + (rate_val < 0)) + goto prim_rate; + ret = tasha_set_mix_interpolator_rate(dai, + (u8) rate_val, sample_rate); +prim_rate: + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) { + if (sample_rate == + int_prim_sample_rate_val[i].sample_rate) { + rate_val = + int_prim_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) || + (rate_val < 0)) + return -EINVAL; + ret = tasha_set_prim_interpolator_rate(dai, + (u8) rate_val, sample_rate); + return ret; +} + +static int tasha_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tasha_codec_vote_max_bw(dai->component, false); + return 0; +} + +static int tasha_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tasha_priv *tasha = + snd_soc_component_get_drvdata(dai->component); + int ret; + int tx_fs_rate = -EINVAL; + int rx_fs_rate = -EINVAL; + int i2s_bit_mode; + struct snd_soc_component *component = dai->component; + + pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, + dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = tasha_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + pr_err("%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16: + tasha->dai[dai->id].bit_width = 16; + i2s_bit_mode = 0x01; + break; + case 24: + tasha->dai[dai->id].bit_width = 24; + i2s_bit_mode = 0x00; + break; + default: + return -EINVAL; + } + tasha->dai[dai->id].rate = params_rate(params); + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + switch (params_rate(params)) { + case 8000: + rx_fs_rate = 0; + break; + case 16000: + rx_fs_rate = 1; + break; + case 32000: + rx_fs_rate = 2; + break; + case 48000: + rx_fs_rate = 3; + break; + case 96000: + rx_fs_rate = 4; + break; + case 192000: + rx_fs_rate = 5; + break; + default: + dev_err(tasha->dev, + "%s: Invalid RX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + }; + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x20, i2s_bit_mode << 5); + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x1c, (rx_fs_rate << 2)); + } + break; + case SNDRV_PCM_STREAM_CAPTURE: + switch (params_rate(params)) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err(tasha->dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + + }; + if (dai->id != AIF4_VIFEED && + dai->id != AIF4_MAD_TX) { + ret = tasha_set_decimator_rate(dai, tx_fs_rate, + params_rate(params)); + if (ret < 0) { + dev_err(tasha->dev, "%s: cannot set TX Decimator rate: %d\n", + __func__, tx_fs_rate); + return ret; + } + } + tasha->dai[dai->id].rate = params_rate(params); + switch (params_width(params)) { + case 16: + tasha->dai[dai->id].bit_width = 16; + i2s_bit_mode = 0x01; + break; + case 24: + tasha->dai[dai->id].bit_width = 24; + i2s_bit_mode = 0x00; + break; + case 32: + tasha->dai[dai->id].bit_width = 32; + i2s_bit_mode = 0x00; + break; + default: + dev_err(tasha->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + }; + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x20, i2s_bit_mode << 5); + if (tx_fs_rate > 1) + tx_fs_rate--; + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x1c, tx_fs_rate << 2); + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG, + 0x05, 0x05); + + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG, + 0x05, 0x05); + + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG, + 0x05, 0x05); + + snd_soc_component_update_bits(component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG, + 0x05, 0x05); + } + break; + default: + pr_err("%s: Invalid stream type %d\n", __func__, + substream->stream); + return -EINVAL; + }; + if (dai->id == AIF4_VIFEED) + tasha->dai[dai->id].bit_width = 32; + + return 0; +} + +static int tasha_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct tasha_priv *tasha = + snd_soc_component_get_drvdata(dai->component); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* CPU is master */ + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + if (dai->id == AIF1_CAP) + snd_soc_component_update_bits(dai->component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x2, 0); + else if (dai->id == AIF1_PB) + snd_soc_component_update_bits(dai->component, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x2, 0); + } + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* CPU is slave */ + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + if (dai->id == AIF1_CAP) + snd_soc_component_update_bits(dai->component, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x2, 0x2); + else if (dai->id == AIF1_PB) + snd_soc_component_update_bits(dai->component, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x2, 0x2); + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int tasha_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static struct snd_soc_dai_ops tasha_dai_ops = { + .startup = tasha_startup, + .shutdown = tasha_shutdown, + .hw_params = tasha_hw_params, + .prepare = tasha_prepare, + .set_sysclk = tasha_set_dai_sysclk, + .set_fmt = tasha_set_dai_fmt, + .set_channel_map = tasha_set_channel_map, + .get_channel_map = tasha_get_channel_map, +}; + +static struct snd_soc_dai_driver tasha_dai[] = { + { + .name = "tasha_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_rx3", + .id = AIF3_PB, + .playback = { + .stream_name = "AIF3 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_tx3", + .id = AIF3_CAP, + .capture = { + .stream_name = "AIF3 Capture", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_rx4", + .id = AIF4_PB, + .playback = { + .stream_name = "AIF4 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_mix_rx1", + .id = AIF_MIX1_PB, + .playback = { + .stream_name = "AIF Mix Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_mad1", + .id = AIF4_MAD_TX, + .capture = { + .stream_name = "AIF4 MAD TX", + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000, + .formats = TASHA_FORMATS_S16_S24_S32_LE, + .rate_min = 16000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_vifeedback", + .id = AIF4_VIFEED, + .capture = { + .stream_name = "VIfeed", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000, + .formats = TASHA_FORMATS_S16_S24_S32_LE, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_cpe", + .id = AIF5_CPE_TX, + .capture = { + .stream_name = "AIF5 CPE TX", + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000, + .formats = TASHA_FORMATS_S16_S24_S32_LE, + .rate_min = 16000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 1, + }, + }, +}; + +static struct snd_soc_dai_driver tasha_i2s_dai[] = { + { + .name = "tasha_i2s_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_i2s_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_i2s_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_i2s_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_mad1", + .id = AIF4_MAD_TX, + .capture = { + .stream_name = "AIF4 MAD TX", + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000, + .formats = TASHA_FORMATS_S16_S24_S32_LE, + .rate_min = 16000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &tasha_dai_ops, + }, +}; + +static void tasha_codec_power_gate_digital_core(struct tasha_priv *tasha) +{ + struct snd_soc_component *component = tasha->component; + + if (!component) + return; + + mutex_lock(&tasha->power_lock); + dev_dbg(component->dev, "%s: Entering power gating function, %d\n", + __func__, tasha->power_active_ref); + + if (tasha->power_active_ref > 0) + goto exit; + + wcd9xxx_set_power_state(tasha->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_BEGIN, + WCD9XXX_DIG_CORE_REGION_1); + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x02, 0x00); + clear_bit(AUDIO_NOMINAL, &tasha->status_mask); + tasha_codec_update_sido_voltage(tasha, sido_buck_svs_voltage); + wcd9xxx_set_power_state(tasha->wcd9xxx, WCD_REGION_POWER_DOWN, + WCD9XXX_DIG_CORE_REGION_1); +exit: + dev_dbg(component->dev, "%s: Exiting power gating function, %d\n", + __func__, tasha->power_active_ref); + mutex_unlock(&tasha->power_lock); +} + +static void tasha_codec_power_gate_work(struct work_struct *work) +{ + struct tasha_priv *tasha; + struct delayed_work *dwork; + struct snd_soc_component *component; + + dwork = to_delayed_work(work); + tasha = container_of(dwork, struct tasha_priv, power_gate_work); + component = tasha->component; + + if (!component) + return; + + tasha_codec_power_gate_digital_core(tasha); +} + +/* called under power_lock acquisition */ +static int tasha_dig_core_remove_power_collapse( + struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + tasha_codec_vote_max_bw(component, true); + snd_soc_component_write(component, + WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5); + snd_soc_component_write(component, + WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7); + snd_soc_component_write(component, + WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); + snd_soc_component_update_bits(component, WCD9335_CODEC_RPM_RST_CTL, + 0x02, 0x00); + snd_soc_component_update_bits(component, WCD9335_CODEC_RPM_RST_CTL, + 0x02, 0x02); + + wcd9xxx_set_power_state(tasha->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_REMOVE, + WCD9XXX_DIG_CORE_REGION_1); + regcache_mark_dirty(component->regmap); + regcache_sync_region(component->regmap, + TASHA_DIG_CORE_REG_MIN, TASHA_DIG_CORE_REG_MAX); + tasha_codec_vote_max_bw(component, false); + + return 0; +} + +static int tasha_dig_core_power_collapse(struct tasha_priv *tasha, + int req_state) +{ + struct snd_soc_component *component; + int cur_state; + + /* Exit if feature is disabled */ + if (!dig_core_collapse_enable) + return 0; + + mutex_lock(&tasha->power_lock); + if (req_state == POWER_COLLAPSE) + tasha->power_active_ref--; + else if (req_state == POWER_RESUME) + tasha->power_active_ref++; + else + goto unlock_mutex; + + if (tasha->power_active_ref < 0) { + dev_dbg(tasha->dev, "%s: power_active_ref is negative\n", + __func__); + goto unlock_mutex; + } + + component = tasha->component; + if (!component) + goto unlock_mutex; + + if (req_state == POWER_COLLAPSE) { + if (tasha->power_active_ref == 0) { + schedule_delayed_work(&tasha->power_gate_work, + msecs_to_jiffies(dig_core_collapse_timer * 1000)); + } + } else if (req_state == POWER_RESUME) { + if (tasha->power_active_ref == 1) { + /* + * At this point, there can be two cases: + * 1. Core already in power collapse state + * 2. Timer kicked in and still did not expire or + * waiting for the power_lock + */ + cur_state = wcd9xxx_get_current_power_state( + tasha->wcd9xxx, + WCD9XXX_DIG_CORE_REGION_1); + if (cur_state == WCD_REGION_POWER_DOWN) + tasha_dig_core_remove_power_collapse(component); + else { + mutex_unlock(&tasha->power_lock); + cancel_delayed_work_sync( + &tasha->power_gate_work); + mutex_lock(&tasha->power_lock); + } + } + } + +unlock_mutex: + mutex_unlock(&tasha->power_lock); + + return 0; +} + +static int __tasha_cdc_mclk_enable_locked(struct tasha_priv *tasha, + bool enable) +{ + int ret = 0; + + if (!tasha->wcd_ext_clk) { + dev_err(tasha->dev, "%s: wcd ext clock is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(tasha->dev, "%s: mclk_enable = %u\n", __func__, enable); + + if (enable) { + tasha_dig_core_power_collapse(tasha, POWER_RESUME); + ret = tasha_cdc_req_mclk_enable(tasha, true); + if (ret) + goto err; + + set_bit(AUDIO_NOMINAL, &tasha->status_mask); + tasha_codec_apply_sido_voltage(tasha, + SIDO_VOLTAGE_NOMINAL_MV); + } else { + if (!dig_core_collapse_enable) { + clear_bit(AUDIO_NOMINAL, &tasha->status_mask); + tasha_codec_update_sido_voltage(tasha, + sido_buck_svs_voltage); + } + tasha_cdc_req_mclk_enable(tasha, false); + tasha_dig_core_power_collapse(tasha, POWER_COLLAPSE); + } + +err: + return ret; +} + +static int __tasha_cdc_mclk_enable(struct tasha_priv *tasha, + bool enable) +{ + int ret; + + WCD9XXX_V2_BG_CLK_LOCK(tasha->resmgr); + ret = __tasha_cdc_mclk_enable_locked(tasha, enable); + WCD9XXX_V2_BG_CLK_UNLOCK(tasha->resmgr); + + return ret; +} + +int tasha_cdc_mclk_enable(struct snd_soc_component *component, + int enable, bool dapm) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + return __tasha_cdc_mclk_enable(tasha, enable); +} +EXPORT_SYMBOL(tasha_cdc_mclk_enable); + +int tasha_cdc_mclk_tx_enable(struct snd_soc_component *component, + int enable, bool dapm) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(tasha->dev, "%s: clk_mode: %d, enable: %d, clk_internal: %d\n", + __func__, tasha->clk_mode, enable, tasha->clk_internal); + if (tasha->clk_mode || tasha->clk_internal) { + if (enable) { + tasha_cdc_sido_ccl_enable(tasha, true); + wcd_resmgr_enable_master_bias(tasha->resmgr); + tasha_dig_core_power_collapse(tasha, POWER_RESUME); + snd_soc_component_update_bits(component, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + set_bit(CPE_NOMINAL, &tasha->status_mask); + tasha_codec_update_sido_voltage(tasha, + SIDO_VOLTAGE_NOMINAL_MV); + tasha->clk_internal = true; + } else { + tasha->clk_internal = false; + clear_bit(CPE_NOMINAL, &tasha->status_mask); + tasha_codec_update_sido_voltage(tasha, + sido_buck_svs_voltage); + tasha_dig_core_power_collapse(tasha, POWER_COLLAPSE); + wcd_resmgr_disable_master_bias(tasha->resmgr); + tasha_cdc_sido_ccl_enable(tasha, false); + } + } else { + ret = __tasha_cdc_mclk_enable(tasha, enable); + } + return ret; +} +EXPORT_SYMBOL(tasha_cdc_mclk_tx_enable); + +static ssize_t tasha_codec_version_read(struct snd_info_entry *entry, + void *file_private_data, struct file *file, + char __user *buf, size_t count, loff_t pos) +{ + struct tasha_priv *tasha; + struct wcd9xxx *wcd9xxx; + char buffer[TASHA_VERSION_ENTRY_SIZE]; + int len = 0; + + tasha = (struct tasha_priv *) entry->private_data; + if (!tasha) { + pr_err("%s: tasha priv is null\n", __func__); + return -EINVAL; + } + + wcd9xxx = tasha->wcd9xxx; + + if (wcd9xxx->codec_type->id_major == TASHA_MAJOR) { + if (TASHA_IS_1_0(wcd9xxx)) + len = snprintf(buffer, sizeof(buffer), "WCD9335_1_0\n"); + else if (TASHA_IS_1_1(wcd9xxx)) + len = snprintf(buffer, sizeof(buffer), "WCD9335_1_1\n"); + else + snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + } else if (wcd9xxx->codec_type->id_major == TASHA2P0_MAJOR) { + len = snprintf(buffer, sizeof(buffer), "WCD9335_2_0\n"); + } else + len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static struct snd_info_entry_ops tasha_codec_info_ops = { + .read = tasha_codec_version_read, +}; + +/* + * tasha_codec_info_create_codec_entry - creates wcd9335 module + * @codec_root: The parent directory + * @component: Codec instance + * + * Creates wcd9335 module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int tasha_codec_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct tasha_priv *tasha; + struct snd_soc_card *card; + + if (!codec_root || !component) + return -EINVAL; + + tasha = snd_soc_component_get_drvdata(component); + card = component->card; + tasha->entry = snd_info_create_subdir(codec_root->module, + "tasha", codec_root); + if (!tasha->entry) { + dev_dbg(component->dev, "%s: failed to create wcd9335 entry\n", + __func__); + return -ENOMEM; + } + + version_entry = snd_info_create_card_entry(card->snd_card, + "version", + tasha->entry); + if (!version_entry) { + dev_dbg(component->dev, "%s: failed to create wcd9335 version entry\n", + __func__); + return -ENOMEM; + } + + version_entry->private_data = tasha; + version_entry->size = TASHA_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &tasha_codec_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + return -ENOMEM; + } + tasha->version_entry = version_entry; + + return 0; +} +EXPORT_SYMBOL(tasha_codec_info_create_codec_entry); + +static int __tasha_codec_internal_rco_ctrl( + struct snd_soc_component *component, bool enable) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int ret = 0; + + if (enable) { + tasha_cdc_sido_ccl_enable(tasha, true); + if (wcd_resmgr_get_clk_type(tasha->resmgr) == + WCD_CLK_RCO) { + ret = wcd_resmgr_enable_clk_block(tasha->resmgr, + WCD_CLK_RCO); + } else { + ret = tasha_cdc_req_mclk_enable(tasha, true); + ret |= wcd_resmgr_enable_clk_block(tasha->resmgr, + WCD_CLK_RCO); + ret |= tasha_cdc_req_mclk_enable(tasha, false); + } + + } else { + ret = wcd_resmgr_disable_clk_block(tasha->resmgr, + WCD_CLK_RCO); + tasha_cdc_sido_ccl_enable(tasha, false); + } + + if (ret) { + dev_err(component->dev, "%s: Error in %s RCO\n", + __func__, (enable ? "enabling" : "disabling")); + ret = -EINVAL; + } + + return ret; +} + +/* + * tasha_codec_internal_rco_ctrl() + * Make sure that the caller does not acquire + * BG_CLK_LOCK. + */ +static int tasha_codec_internal_rco_ctrl(struct snd_soc_component *component, + bool enable) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + int ret = 0; + + WCD9XXX_V2_BG_CLK_LOCK(tasha->resmgr); + ret = __tasha_codec_internal_rco_ctrl(component, enable); + WCD9XXX_V2_BG_CLK_UNLOCK(tasha->resmgr); + return ret; +} + +/* + * tasha_mbhc_hs_detect: starts mbhc insertion/removal functionality + * @component: 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 tasha_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + return wcd_mbhc_start(&tasha->mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(tasha_mbhc_hs_detect); + +/* + * tasha_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void tasha_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + wcd_mbhc_stop(&tasha->mbhc); +} +EXPORT_SYMBOL(tasha_mbhc_hs_detect_exit); + +static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < 1000 || micb_mv > 2850) { + pr_err("%s: unsupported micbias voltage\n", __func__); + return -EINVAL; + } + + return (micb_mv - 1000) / 50; +} + +static const struct tasha_reg_mask_val tasha_reg_update_reset_val_1_1[] = { + {WCD9335_RCO_CTRL_2, 0xFF, 0x47}, + {WCD9335_FLYBACK_VNEG_DAC_CTRL_4, 0xFF, 0x60}, +}; + +static const struct tasha_reg_mask_val tasha_codec_reg_init_val_1_1[] = { + {WCD9335_FLYBACK_VNEG_DAC_CTRL_1, 0xFF, 0x65}, + {WCD9335_FLYBACK_VNEG_DAC_CTRL_2, 0xFF, 0x52}, + {WCD9335_FLYBACK_VNEG_DAC_CTRL_3, 0xFF, 0xAF}, + {WCD9335_FLYBACK_VNEG_DAC_CTRL_4, 0xFF, 0x60}, + {WCD9335_FLYBACK_VNEG_CTRL_3, 0xFF, 0xF4}, + {WCD9335_FLYBACK_VNEG_CTRL_9, 0xFF, 0x40}, + {WCD9335_FLYBACK_VNEG_CTRL_2, 0xFF, 0x4F}, + {WCD9335_FLYBACK_EN, 0xFF, 0x6E}, + {WCD9335_CDC_RX2_RX_PATH_SEC0, 0xF8, 0xF8}, + {WCD9335_CDC_RX1_RX_PATH_SEC0, 0xF8, 0xF8}, +}; + +static const struct tasha_reg_mask_val tasha_codec_reg_init_val_1_0[] = { + {WCD9335_FLYBACK_VNEG_CTRL_3, 0xFF, 0x54}, + {WCD9335_CDC_RX2_RX_PATH_SEC0, 0xFC, 0xFC}, + {WCD9335_CDC_RX1_RX_PATH_SEC0, 0xFC, 0xFC}, +}; + +static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = { + {WCD9335_RCO_CTRL_2, 0x0F, 0x08}, + {WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10}, + {WCD9335_FLYBACK_CTRL_1, 0x20, 0x20}, + {WCD9335_HPH_OCP_CTL, 0xFF, 0x7A}, + {WCD9335_HPH_L_TEST, 0x01, 0x01}, + {WCD9335_HPH_R_TEST, 0x01, 0x01}, + {WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45}, + {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, + {WCD9335_DIFF_LO_CORE_OUT_PROG, 0xFC, 0xA0}, + {WCD9335_SE_LO_COM1, 0xFF, 0xC0}, + {WCD9335_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_CDC_RX5_RX_PATH_SEC0, 0xFC, 0xF8}, + {WCD9335_CDC_RX6_RX_PATH_SEC0, 0xFC, 0xF8}, +}; + +static const struct tasha_reg_mask_val tasha_codec_reg_defaults[] = { + {WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x00}, + {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x01}, + {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x04, 0x04}, +}; + +static const struct tasha_reg_mask_val tasha_codec_reg_i2c_defaults[] = { + {WCD9335_ANA_CLK_TOP, 0x20, 0x20}, + {WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x01}, + {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x00}, + {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG, 0x05, 0x05}, +}; + +static const struct tasha_reg_mask_val tasha_codec_reg_init_common_val[] = { + /* Rbuckfly/R_EAR(32) */ + {WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00}, + {WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60}, + {WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x58}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x58}, + {WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_ANA_LO_1_2, 0x3C, 0X3C}, + {WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00}, + {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01}, + {WCD9335_EAR_CMBUFF, 0x08, 0x00}, + {WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08}, +}; + +static const struct tasha_reg_mask_val tasha_codec_reg_init_1_x_val[] = { + /* Enable TX HPF Filter & Linear Phase */ + {WCD9335_CDC_TX0_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX1_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX2_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX3_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX4_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX5_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX6_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX7_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_TX8_TX_PATH_CFG0, 0x11, 0x11}, + {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xF8, 0xF8}, + {WCD9335_CDC_RX0_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX1_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX2_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX3_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX4_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX5_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX6_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX7_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX8_RX_PATH_SEC1, 0x08, 0x08}, + {WCD9335_CDC_RX0_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX1_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX2_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX3_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX4_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX5_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX6_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x08, 0x08}, + {WCD9335_CDC_TX0_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX1_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX2_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX3_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX4_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX5_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX6_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX7_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_TX8_TX_PATH_SEC2, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_SEC0, 0xF8, 0xF0}, + {WCD9335_CDC_RX4_RX_PATH_SEC0, 0xF8, 0xF0}, + {WCD9335_CDC_RX5_RX_PATH_SEC0, 0xF8, 0xF8}, + {WCD9335_CDC_RX6_RX_PATH_SEC0, 0xF8, 0xF8}, + {WCD9335_RX_OCP_COUNT, 0xFF, 0xFF}, + {WCD9335_HPH_OCP_CTL, 0xF0, 0x70}, + {WCD9335_CPE_SS_CPAR_CFG, 0xFF, 0x00}, + {WCD9335_FLYBACK_VNEG_CTRL_1, 0xFF, 0x63}, + {WCD9335_FLYBACK_VNEG_CTRL_4, 0xFF, 0x7F}, + {WCD9335_CLASSH_CTRL_VCL_1, 0xFF, 0x60}, + {WCD9335_CLASSH_CTRL_CCL_5, 0xFF, 0x40}, + {WCD9335_RX_TIMER_DIV, 0xFF, 0x32}, + {WCD9335_SE_LO_COM2, 0xFF, 0x01}, + {WCD9335_MBHC_ZDET_ANA_CTL, 0x0F, 0x07}, + {WCD9335_RX_BIAS_HPH_PA, 0xF0, 0x60}, + {WCD9335_HPH_RDAC_LDO_CTL, 0x88, 0x88}, + {WCD9335_HPH_L_EN, 0x20, 0x20}, + {WCD9335_HPH_R_EN, 0x20, 0x20}, + {WCD9335_DIFF_LO_CORE_OUT_PROG, 0xFC, 0xD8}, + {WCD9335_CDC_RX5_RX_PATH_SEC3, 0xBD, 0xBD}, + {WCD9335_CDC_RX6_RX_PATH_SEC3, 0xBD, 0xBD}, + {WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40}, +}; + +static void tasha_update_reg_reset_values(struct snd_soc_component *component) +{ + u32 i; + struct wcd9xxx *tasha_core = dev_get_drvdata(component->dev->parent); + + if (TASHA_IS_1_1(tasha_core)) { + for (i = 0; i < ARRAY_SIZE(tasha_reg_update_reset_val_1_1); + i++) + snd_soc_component_write(component, + tasha_reg_update_reset_val_1_1[i].reg, + tasha_reg_update_reset_val_1_1[i].val); + } +} + +static void tasha_codec_init_reg(struct snd_soc_component *component) +{ + u32 i; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_common_val); i++) + snd_soc_component_update_bits(component, + tasha_codec_reg_init_common_val[i].reg, + tasha_codec_reg_init_common_val[i].mask, + tasha_codec_reg_init_common_val[i].val); + + if (TASHA_IS_1_1(wcd9xxx) || + TASHA_IS_1_0(wcd9xxx)) + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_1_x_val); i++) + snd_soc_component_update_bits(component, + tasha_codec_reg_init_1_x_val[i].reg, + tasha_codec_reg_init_1_x_val[i].mask, + tasha_codec_reg_init_1_x_val[i].val); + + if (TASHA_IS_1_1(wcd9xxx)) { + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_1_1); i++) + snd_soc_component_update_bits(component, + tasha_codec_reg_init_val_1_1[i].reg, + tasha_codec_reg_init_val_1_1[i].mask, + tasha_codec_reg_init_val_1_1[i].val); + } else if (TASHA_IS_1_0(wcd9xxx)) { + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_1_0); i++) + snd_soc_component_update_bits(component, + tasha_codec_reg_init_val_1_0[i].reg, + tasha_codec_reg_init_val_1_0[i].mask, + tasha_codec_reg_init_val_1_0[i].val); + } else if (TASHA_IS_2_0(wcd9xxx)) { + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_2_0); i++) + snd_soc_component_update_bits(component, + tasha_codec_reg_init_val_2_0[i].reg, + tasha_codec_reg_init_val_2_0[i].mask, + tasha_codec_reg_init_val_2_0[i].val); + } +} + +static void tasha_update_reg_defaults(struct tasha_priv *tasha) +{ + u32 i; + struct wcd9xxx *wcd9xxx; + + wcd9xxx = tasha->wcd9xxx; + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_defaults); i++) + regmap_update_bits(wcd9xxx->regmap, + tasha_codec_reg_defaults[i].reg, + tasha_codec_reg_defaults[i].mask, + tasha_codec_reg_defaults[i].val); + + tasha->intf_type = wcd9xxx_get_intf_type(); + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_i2c_defaults); i++) + regmap_update_bits(wcd9xxx->regmap, + tasha_codec_reg_i2c_defaults[i].reg, + tasha_codec_reg_i2c_defaults[i].mask, + tasha_codec_reg_i2c_defaults[i].val); + +} + +static void tasha_slim_interface_init_reg(struct snd_soc_component *component) +{ + int i; + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + + for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) + wcd9xxx_interface_reg_write(priv->wcd9xxx, + TASHA_SLIM_PGD_PORT_INT_EN0 + i, + 0xFF); +} + +static irqreturn_t tasha_slimbus_irq(int irq, void *data) +{ + struct tasha_priv *priv = data; + unsigned long status = 0; + int i, j, port_id, k; + u32 bit; + u8 val, int_val = 0; + bool tx, cleared; + unsigned short reg = 0; + + for (i = TASHA_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0; + i <= TASHA_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) { + val = wcd9xxx_interface_reg_read(priv->wcd9xxx, i); + status |= ((u32)val << (8 * j)); + } + + for_each_set_bit(j, &status, 32) { + tx = (j >= 16 ? true : false); + port_id = (tx ? j - 16 : j); + val = wcd9xxx_interface_reg_read(priv->wcd9xxx, + TASHA_SLIM_PGD_PORT_INT_RX_SOURCE0 + j); + if (val) { + if (!tx) + reg = TASHA_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = TASHA_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + int_val = wcd9xxx_interface_reg_read( + priv->wcd9xxx, reg); + /* + * Ignore interrupts for ports for which the + * interrupts are not specifically enabled. + */ + if (!(int_val & (1 << (port_id % 8)))) + continue; + } + if (val & TASHA_SLIM_IRQ_OVERFLOW) + pr_err_ratelimited( + "%s: overflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if (val & TASHA_SLIM_IRQ_UNDERFLOW) + pr_err_ratelimited( + "%s: underflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if ((val & TASHA_SLIM_IRQ_OVERFLOW) || + (val & TASHA_SLIM_IRQ_UNDERFLOW)) { + if (!tx) + reg = TASHA_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = TASHA_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + int_val = wcd9xxx_interface_reg_read( + priv->wcd9xxx, reg); + if (int_val & (1 << (port_id % 8))) { + int_val = int_val ^ (1 << (port_id % 8)); + wcd9xxx_interface_reg_write(priv->wcd9xxx, + reg, int_val); + } + } + if (val & TASHA_SLIM_IRQ_PORT_CLOSED) { + /* + * INT SOURCE register starts from RX to TX + * but port number in the ch_mask is in opposite way + */ + bit = (tx ? j - 16 : j + 16); + pr_debug("%s: %s port %d closed value %x, bit %u\n", + __func__, (tx ? "TX" : "RX"), port_id, val, + bit); + for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) { + pr_debug("%s: priv->dai[%d].ch_mask = 0x%lx\n", + __func__, k, priv->dai[k].ch_mask); + if (test_and_clear_bit(bit, + &priv->dai[k].ch_mask)) { + cleared = true; + if (!priv->dai[k].ch_mask) + wake_up(&priv->dai[k].dai_wait); + /* + * There are cases when multiple DAIs + * might be using the same slimbus + * channel. Hence don't break here. + */ + } + } + WARN(!cleared, + "Couldn't find slimbus %s port %d for closing\n", + (tx ? "TX" : "RX"), port_id); + } + wcd9xxx_interface_reg_write(priv->wcd9xxx, + TASHA_SLIM_PGD_PORT_INT_CLR_RX_0 + + (j / 8), + 1 << (j % 8)); + } + + return IRQ_HANDLED; +} + +static int tasha_setup_irqs(struct tasha_priv *tasha) +{ + int ret = 0; + struct snd_soc_component *component = tasha->component; + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS, + tasha_slimbus_irq, "SLIMBUS Slave", tasha); + if (ret) + pr_err("%s: Failed to request irq %d\n", __func__, + WCD9XXX_IRQ_SLIMBUS); + else + tasha_slim_interface_init_reg(component); + + return ret; +} + +static void tasha_init_slim_slave_cfg(struct snd_soc_component *component) +{ + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + struct afe_param_cdc_slimbus_slave_cfg *cfg; + struct wcd9xxx *wcd9xxx = priv->wcd9xxx; + uint64_t eaddr = 0; + + cfg = &priv->slimbus_slave_cfg; + cfg->minor_version = 1; + cfg->tx_slave_port_offset = 0; + cfg->rx_slave_port_offset = 16; + + memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr)); + WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6); + cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF; + cfg->device_enum_addr_msw = eaddr >> 32; + + dev_dbg(component->dev, "%s: slimbus logical address 0x%llx\n", + __func__, eaddr); +} + +static void tasha_cleanup_irqs(struct tasha_priv *tasha) +{ + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tasha); +} + +static int tasha_handle_pdata(struct tasha_priv *tasha, + struct wcd9xxx_pdata *pdata) +{ + struct snd_soc_component *component = tasha->component; + u8 dmic_ctl_val, mad_dmic_ctl_val; + u8 anc_ctl_value; + u32 def_dmic_rate, dmic_clk_drv; + int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; + int rc = 0; + + if (!pdata) { + dev_err(component->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl_1 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + vout_ctl_2 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb2_mv); + vout_ctl_3 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb3_mv); + vout_ctl_4 = wcd9335_get_micb_vout_ctl_val(pdata->micbias.micb4_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || + vout_ctl_3 < 0 || vout_ctl_4 < 0) { + rc = -EINVAL; + goto done; + } + snd_soc_component_update_bits(component, WCD9335_ANA_MICB1, + 0x3F, vout_ctl_1); + snd_soc_component_update_bits(component, WCD9335_ANA_MICB2, + 0x3F, vout_ctl_2); + snd_soc_component_update_bits(component, WCD9335_ANA_MICB3, + 0x3F, vout_ctl_3); + snd_soc_component_update_bits(component, WCD9335_ANA_MICB4, + 0x3F, vout_ctl_4); + + /* Set the DMIC sample rate */ + switch (pdata->mclk_rate) { + case TASHA_MCLK_CLK_9P6MHZ: + def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ; + break; + case TASHA_MCLK_CLK_12P288MHZ: + def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ; + break; + default: + /* should never happen */ + dev_err(component->dev, "%s: Invalid mclk_rate %d\n", + __func__, pdata->mclk_rate); + rc = -EINVAL; + goto done; + }; + + if (pdata->dmic_sample_rate == + WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) { + dev_info(component->dev, "%s: dmic_rate invalid default = %d\n", + __func__, def_dmic_rate); + pdata->dmic_sample_rate = def_dmic_rate; + } + if (pdata->mad_dmic_sample_rate == + WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) { + dev_info(component->dev, "%s: mad_dmic_rate invalid default = %d\n", + __func__, def_dmic_rate); + /* + * use dmic_sample_rate as the default for MAD + * if mad dmic sample rate is undefined + */ + pdata->mad_dmic_sample_rate = pdata->dmic_sample_rate; + } + if (pdata->ecpp_dmic_sample_rate == + WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) { + dev_info(component->dev, + "%s: ecpp_dmic_rate invalid default = %d\n", + __func__, def_dmic_rate); + /* + * use dmic_sample_rate as the default for ECPP DMIC + * if ecpp dmic sample rate is undefined + */ + pdata->ecpp_dmic_sample_rate = pdata->dmic_sample_rate; + } + + if (pdata->dmic_clk_drv == + WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED) { + pdata->dmic_clk_drv = WCD9335_DMIC_CLK_DRIVE_DEFAULT; + dev_info(component->dev, + "%s: dmic_clk_strength invalid, default = %d\n", + __func__, pdata->dmic_clk_drv); + } + + switch (pdata->dmic_clk_drv) { + case 2: + dmic_clk_drv = 0; + break; + case 4: + dmic_clk_drv = 1; + break; + case 8: + dmic_clk_drv = 2; + break; + case 16: + dmic_clk_drv = 3; + break; + default: + dev_err(component->dev, + "%s: invalid dmic_clk_drv %d, using default\n", + __func__, pdata->dmic_clk_drv); + dmic_clk_drv = 0; + break; + } + + snd_soc_component_update_bits(component, WCD9335_TEST_DEBUG_PAD_DRVCTL, + 0x0C, dmic_clk_drv << 2); + + /* + * Default the DMIC clk rates to mad_dmic_sample_rate, + * whereas, the anc/txfe dmic rates to dmic_sample_rate + * since the anc/txfe are independent of mad block. + */ + mad_dmic_ctl_val = tasha_get_dmic_clk_val(tasha->component, + pdata->mclk_rate, + pdata->mad_dmic_sample_rate); + snd_soc_component_update_bits(component, WCD9335_CPE_SS_DMIC0_CTL, + 0x0E, mad_dmic_ctl_val << 1); + snd_soc_component_update_bits(component, WCD9335_CPE_SS_DMIC1_CTL, + 0x0E, mad_dmic_ctl_val << 1); + snd_soc_component_update_bits(component, WCD9335_CPE_SS_DMIC2_CTL, + 0x0E, mad_dmic_ctl_val << 1); + + dmic_ctl_val = tasha_get_dmic_clk_val(tasha->component, + pdata->mclk_rate, + pdata->dmic_sample_rate); + + if (dmic_ctl_val == WCD9335_DMIC_CLK_DIV_2) + anc_ctl_value = WCD9335_ANC_DMIC_X2_FULL_RATE; + else + anc_ctl_value = WCD9335_ANC_DMIC_X2_HALF_RATE; + + snd_soc_component_update_bits(component, WCD9335_CDC_ANC0_MODE_2_CTL, + 0x40, anc_ctl_value << 6); + snd_soc_component_update_bits(component, WCD9335_CDC_ANC0_MODE_2_CTL, + 0x20, anc_ctl_value << 5); + snd_soc_component_update_bits(component, WCD9335_CDC_ANC1_MODE_2_CTL, + 0x40, anc_ctl_value << 6); + snd_soc_component_update_bits(component, WCD9335_CDC_ANC1_MODE_2_CTL, + 0x20, anc_ctl_value << 5); +done: + return rc; +} + +static struct wcd_cpe_core *tasha_codec_get_cpe_core( + struct snd_soc_component *component) +{ + struct tasha_priv *priv = snd_soc_component_get_drvdata(component); + + return priv->cpe_core; +} + +static int tasha_codec_cpe_fll_update_divider( + struct snd_soc_component *component, u32 cpe_fll_rate) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + u32 div_val = 0, l_val = 0; + u32 computed_cpe_fll; + + if (cpe_fll_rate != CPE_FLL_CLK_75MHZ && + cpe_fll_rate != CPE_FLL_CLK_150MHZ) { + dev_err(component->dev, + "%s: Invalid CPE fll rate request %u\n", + __func__, cpe_fll_rate); + return -EINVAL; + } + + if (wcd9xxx->mclk_rate == TASHA_MCLK_CLK_12P288MHZ) { + /* update divider to 10 and enable 5x divider */ + snd_soc_component_write(component, WCD9335_CPE_FLL_USER_CTL_1, + 0x55); + div_val = 10; + } else if (wcd9xxx->mclk_rate == TASHA_MCLK_CLK_9P6MHZ) { + /* update divider to 8 and enable 2x divider */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_USER_CTL_0, + 0x7C, 0x70); + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_USER_CTL_1, + 0xE0, 0x20); + div_val = 8; + } else { + dev_err(component->dev, + "%s: Invalid MCLK rate %u\n", + __func__, wcd9xxx->mclk_rate); + return -EINVAL; + } + + l_val = ((cpe_fll_rate / 1000) * div_val) / + (wcd9xxx->mclk_rate / 1000); + + /* If l_val was integer truncated, increment l_val once */ + computed_cpe_fll = (wcd9xxx->mclk_rate / div_val) * l_val; + if (computed_cpe_fll < cpe_fll_rate) + l_val++; + + + /* update L value LSB and MSB */ + snd_soc_component_write(component, WCD9335_CPE_FLL_L_VAL_CTL_0, + (l_val & 0xFF)); + snd_soc_component_write(component, WCD9335_CPE_FLL_L_VAL_CTL_1, + ((l_val >> 8) & 0xFF)); + + tasha->current_cpe_clk_freq = cpe_fll_rate; + dev_dbg(component->dev, + "%s: updated l_val to %u for cpe_clk %u and mclk %u\n", + __func__, l_val, cpe_fll_rate, wcd9xxx->mclk_rate); + + return 0; +} + +static int __tasha_cdc_change_cpe_clk(struct snd_soc_component *component, + u32 clk_freq) +{ + int ret = 0; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (!tasha_cdc_is_svs_enabled(tasha)) { + dev_dbg(component->dev, + "%s: SVS not enabled or tasha is not 2p0, return\n", + __func__); + return 0; + } + dev_dbg(component->dev, "%s: clk_freq = %u\n", __func__, clk_freq); + + if (clk_freq == CPE_FLL_CLK_75MHZ) { + /* Change to SVS */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_FLL_MODE, + 0x08, 0x08); + if (tasha_codec_cpe_fll_update_divider(component, clk_freq)) { + ret = -EINVAL; + goto done; + } + + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_FLL_MODE, + 0x10, 0x10); + + clear_bit(CPE_NOMINAL, &tasha->status_mask); + tasha_codec_update_sido_voltage(tasha, sido_buck_svs_voltage); + + } else if (clk_freq == CPE_FLL_CLK_150MHZ) { + /* change to nominal */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_FLL_MODE, + 0x08, 0x08); + + set_bit(CPE_NOMINAL, &tasha->status_mask); + tasha_codec_update_sido_voltage(tasha, SIDO_VOLTAGE_NOMINAL_MV); + + if (tasha_codec_cpe_fll_update_divider(component, clk_freq)) { + ret = -EINVAL; + goto done; + } + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_FLL_MODE, + 0x10, 0x10); + } else { + dev_err(component->dev, + "%s: Invalid clk_freq request %d for CPE FLL\n", + __func__, clk_freq); + ret = -EINVAL; + } + +done: + snd_soc_component_update_bits(component, WCD9335_CPE_FLL_FLL_MODE, + 0x10, 0x00); + snd_soc_component_update_bits(component, WCD9335_CPE_FLL_FLL_MODE, + 0x08, 0x00); + return ret; +} + + +static int tasha_codec_cpe_fll_enable(struct snd_soc_component *component, + bool enable) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u8 clk_sel_reg_val = 0x00; + + dev_dbg(component->dev, "%s: enable = %s\n", + __func__, enable ? "true" : "false"); + + if (enable) { + if (tasha_cdc_is_svs_enabled(tasha)) { + /* FLL enable is always at SVS */ + if (__tasha_cdc_change_cpe_clk(component, + CPE_FLL_CLK_75MHZ)) { + dev_err(component->dev, + "%s: clk change to %d failed\n", + __func__, CPE_FLL_CLK_75MHZ); + return -EINVAL; + } + } else { + if (tasha_codec_cpe_fll_update_divider(component, + CPE_FLL_CLK_75MHZ)) { + dev_err(component->dev, + "%s: clk change to %d failed\n", + __func__, CPE_FLL_CLK_75MHZ); + return -EINVAL; + } + } + + if (TASHA_IS_1_0(wcd9xxx)) { + tasha_cdc_mclk_enable(component, true, false); + clk_sel_reg_val = 0x02; + } + + /* Setup CPE reference clk */ + snd_soc_component_update_bits(component, WCD9335_ANA_CLK_TOP, + 0x02, clk_sel_reg_val); + + /* enable CPE FLL reference clk */ + snd_soc_component_update_bits(component, WCD9335_ANA_CLK_TOP, + 0x01, 0x01); + + /* program the PLL */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_USER_CTL_0, + 0x01, 0x01); + + /* TEST clk setting */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_TEST_CTL_0, + 0x80, 0x80); + /* set FLL mode to HW controlled */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_FLL_MODE, + 0x60, 0x00); + snd_soc_component_write(component, WCD9335_CPE_FLL_FLL_MODE, + 0x80); + } else { + /* disable CPE FLL reference clk */ + snd_soc_component_update_bits(component, WCD9335_ANA_CLK_TOP, + 0x01, 0x00); + /* undo TEST clk setting */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_TEST_CTL_0, + 0x80, 0x00); + /* undo FLL mode to HW control */ + snd_soc_component_write(component, + WCD9335_CPE_FLL_FLL_MODE, 0x00); + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_FLL_MODE, + 0x60, 0x20); + /* undo the PLL */ + snd_soc_component_update_bits(component, + WCD9335_CPE_FLL_USER_CTL_0, + 0x01, 0x00); + + if (TASHA_IS_1_0(wcd9xxx)) + tasha_cdc_mclk_enable(component, false, false); + + /* + * FLL could get disabled while at nominal, + * scale it back to SVS + */ + if (tasha_cdc_is_svs_enabled(tasha)) + __tasha_cdc_change_cpe_clk(component, + CPE_FLL_CLK_75MHZ); + } + + return 0; + +} + +static void tasha_cdc_query_cpe_clk_plan(void *data, + struct cpe_svc_cfg_clk_plan *clk_freq) +{ + struct snd_soc_component *component = data; + struct tasha_priv *tasha; + u32 cpe_clk_khz; + + if (!component) { + pr_err("%s: Invalid component handle\n", + __func__); + return; + } + + tasha = snd_soc_component_get_drvdata(component); + cpe_clk_khz = tasha->current_cpe_clk_freq / 1000; + + dev_dbg(component->dev, + "%s: current_clk_freq = %u\n", + __func__, tasha->current_cpe_clk_freq); + + clk_freq->current_clk_feq = cpe_clk_khz; + clk_freq->num_clk_freqs = 2; + + if (tasha_cdc_is_svs_enabled(tasha)) { + clk_freq->clk_freqs[0] = CPE_FLL_CLK_75MHZ / 1000; + clk_freq->clk_freqs[1] = CPE_FLL_CLK_150MHZ / 1000; + } else { + clk_freq->clk_freqs[0] = CPE_FLL_CLK_75MHZ; + clk_freq->clk_freqs[1] = CPE_FLL_CLK_150MHZ; + } +} + +static void tasha_cdc_change_cpe_clk(void *data, + u32 clk_freq) +{ + struct snd_soc_component *component = data; + struct tasha_priv *tasha; + u32 cpe_clk_khz, req_freq = 0; + + if (!component) { + pr_err("%s: Invalid codec handle\n", + __func__); + return; + } + + tasha = snd_soc_component_get_drvdata(component); + cpe_clk_khz = tasha->current_cpe_clk_freq / 1000; + + if (tasha_cdc_is_svs_enabled(tasha)) { + if ((clk_freq * 1000) <= CPE_FLL_CLK_75MHZ) + req_freq = CPE_FLL_CLK_75MHZ; + else + req_freq = CPE_FLL_CLK_150MHZ; + } + + dev_dbg(component->dev, + "%s: requested clk_freq = %u, current clk_freq = %u\n", + __func__, clk_freq * 1000, + tasha->current_cpe_clk_freq); + + if (tasha_cdc_is_svs_enabled(tasha)) { + if (__tasha_cdc_change_cpe_clk(component, req_freq)) + dev_err(component->dev, + "%s: clock/voltage scaling failed\n", + __func__); + } +} + +static int tasha_codec_slim_reserve_bw(struct snd_soc_component *component, + u32 bw_ops, bool commit) +{ + struct wcd9xxx *wcd9xxx; + + if (!component) { + pr_err("%s: Invalid handle to codec\n", + __func__); + return -EINVAL; + } + + wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (!wcd9xxx) { + dev_err(component->dev, "%s: Invalid parent drv_data\n", + __func__); + return -EINVAL; + } + + return wcd9xxx_slim_reserve_bw(wcd9xxx, bw_ops, commit); +} + +static int tasha_codec_vote_max_bw(struct snd_soc_component *component, + bool vote) +{ + u32 bw_ops; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) + return 0; + + mutex_lock(&tasha->sb_clk_gear_lock); + if (vote) { + tasha->ref_count++; + if (tasha->ref_count == 1) { + bw_ops = SLIM_BW_CLK_GEAR_9; + tasha_codec_slim_reserve_bw(component, + bw_ops, true); + } + } else if (!vote && tasha->ref_count > 0) { + tasha->ref_count--; + if (tasha->ref_count == 0) { + bw_ops = SLIM_BW_UNVOTE; + tasha_codec_slim_reserve_bw(component, + bw_ops, true); + } + }; + + dev_dbg(component->dev, "%s Value of counter after vote or un-vote is %d\n", + __func__, tasha->ref_count); + + mutex_unlock(&tasha->sb_clk_gear_lock); + + return 0; +} + +static int tasha_cpe_err_irq_control(struct snd_soc_component *component, + enum cpe_err_irq_cntl_type cntl_type, u8 *status) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + u8 irq_bits; + + if (TASHA_IS_2_0(tasha->wcd9xxx)) + irq_bits = 0xFF; + else + irq_bits = 0x3F; + + if (status) + irq_bits = (*status) & irq_bits; + + switch (cntl_type) { + case CPE_ERR_IRQ_MASK: + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_SS_ERROR_INT_MASK, + irq_bits, irq_bits); + break; + case CPE_ERR_IRQ_UNMASK: + snd_soc_component_update_bits(component, + WCD9335_CPE_SS_SS_ERROR_INT_MASK, + irq_bits, 0x00); + break; + case CPE_ERR_IRQ_CLEAR: + snd_soc_component_write(component, + WCD9335_CPE_SS_SS_ERROR_INT_CLEAR, + irq_bits); + break; + case CPE_ERR_IRQ_STATUS: + if (!status) + return -EINVAL; + *status = snd_soc_component_read32(component, + WCD9335_CPE_SS_SS_ERROR_INT_STATUS); + break; + } + + return 0; +} + +static const struct wcd_cpe_cdc_cb cpe_cb = { + .cdc_clk_en = tasha_codec_internal_rco_ctrl, + .cpe_clk_en = tasha_codec_cpe_fll_enable, + .get_afe_out_port_id = tasha_codec_get_mad_port_id, + .lab_cdc_ch_ctl = tasha_codec_enable_slimtx_mad, + .cdc_ext_clk = tasha_cdc_mclk_enable, + .bus_vote_bw = tasha_codec_vote_max_bw, + .cpe_err_irq_control = tasha_cpe_err_irq_control, +}; + +static struct cpe_svc_init_param cpe_svc_params = { + .version = CPE_SVC_INIT_PARAM_V1, + .query_freq_plans_cb = tasha_cdc_query_cpe_clk_plan, + .change_freq_plan_cb = tasha_cdc_change_cpe_clk, +}; + +static int tasha_cpe_initialize(struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd_cpe_params cpe_params; + + memset(&cpe_params, 0, + sizeof(struct wcd_cpe_params)); + cpe_params.component = component; + cpe_params.get_cpe_core = tasha_codec_get_cpe_core; + cpe_params.cdc_cb = &cpe_cb; + cpe_params.dbg_mode = cpe_debug_mode; + cpe_params.cdc_major_ver = CPE_SVC_CODEC_WCD9335; + cpe_params.cdc_minor_ver = CPE_SVC_CODEC_V1P0; + cpe_params.cdc_id = CPE_SVC_CODEC_WCD9335; + + cpe_params.cdc_irq_info.cpe_engine_irq = + WCD9335_IRQ_SVA_OUTBOX1; + cpe_params.cdc_irq_info.cpe_err_irq = + WCD9335_IRQ_SVA_ERROR; + cpe_params.cdc_irq_info.cpe_fatal_irqs = + TASHA_CPE_FATAL_IRQS; + + cpe_svc_params.context = component; + cpe_params.cpe_svc_params = &cpe_svc_params; + + tasha->cpe_core = wcd_cpe_init("cpe_9335", component, + &cpe_params); + if (IS_ERR_OR_NULL(tasha->cpe_core)) { + dev_err(component->dev, + "%s: Failed to enable CPE\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static const struct wcd_resmgr_cb tasha_resmgr_cb = { + .cdc_rco_ctrl = __tasha_codec_internal_rco_ctrl, +}; + +static int tasha_device_down(struct wcd9xxx *wcd9xxx) +{ + struct snd_soc_component *component; + struct tasha_priv *priv; + int count; + int i = 0; + + component = (struct snd_soc_component *)(wcd9xxx->ssr_priv); + priv = snd_soc_component_get_drvdata(component); + snd_event_notify(priv->dev->parent, SND_EVENT_DOWN); + wcd_cpe_ssr_event(priv->cpe_core, WCD_CPE_BUS_DOWN_EVENT); + + if (!priv->swr_ctrl_data) + return -EINVAL; + + for (i = 0; i < priv->nr; i++) { + if (is_snd_event_fwk_enabled()) + swrm_wcd_notify( + priv->swr_ctrl_data[i].swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + swrm_wcd_notify(priv->swr_ctrl_data[i].swr_pdev, + SWR_DEVICE_DOWN, NULL); + } + +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + if (!is_snd_event_fwk_enabled()) + snd_soc_card_change_online_state(component->card, 0); +#endif /* CONFIG_AUDIO_QGKI */ + for (count = 0; count < NUM_CODEC_DAIS; count++) + priv->dai[count].bus_down_in_recovery = true; + + priv->resmgr->sido_input_src = SIDO_SOURCE_INTERNAL; + + return 0; +} + +static int tasha_post_reset_cb(struct wcd9xxx *wcd9xxx) +{ + int i, ret = 0; + struct wcd9xxx *control; + struct snd_soc_component *component; + struct tasha_priv *tasha; + struct wcd9xxx_pdata *pdata; + + component = (struct snd_soc_component *)(wcd9xxx->ssr_priv); + tasha = snd_soc_component_get_drvdata(component); + control = dev_get_drvdata(component->dev->parent); + + wcd9xxx_set_power_state(tasha->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_REMOVE, + WCD9XXX_DIG_CORE_REGION_1); + + mutex_lock(&tasha->codec_mutex); + + tasha_slimbus_slave_port_cfg.slave_dev_intfdev_la = + control->slim_slave->laddr; + tasha_slimbus_slave_port_cfg.slave_dev_pgd_la = + control->slim->laddr; + tasha_init_slim_slave_cfg(component); + if (tasha->machine_codec_event_cb) + tasha->machine_codec_event_cb(component, + WCD9335_CODEC_EVENT_CODEC_UP); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + if (!is_snd_event_fwk_enabled()) + snd_soc_card_change_online_state(component->card, 1); +#endif /* CONFIG_AUDIO_QGKI */ + + /* Class-H Init*/ + wcd_clsh_init(&tasha->clsh_d); + + for (i = 0; i < TASHA_MAX_MICBIAS; i++) + tasha->micb_ref[i] = 0; + + tasha_update_reg_defaults(tasha); + + tasha->component = component; + + dev_dbg(component->dev, "%s: MCLK Rate = %x\n", + __func__, control->mclk_rate); + + if (control->mclk_rate == TASHA_MCLK_CLK_12P288MHZ) + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x00); + else if (control->mclk_rate == TASHA_MCLK_CLK_9P6MHZ) + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x01); + tasha_codec_init_reg(component); + + wcd_resmgr_post_ssr_v2(tasha->resmgr); + + tasha_enable_efuse_sensing(component); + + regcache_mark_dirty(component->regmap); + regcache_sync(component->regmap); + + pdata = dev_get_platdata(component->dev->parent); + ret = tasha_handle_pdata(tasha, pdata); + if (ret < 0) + dev_err(component->dev, "%s: invalid pdata\n", __func__); + + /* Reset reference counter for voting for max bw */ + tasha->ref_count = 0; + /* MBHC Init */ + wcd_mbhc_deinit(&tasha->mbhc); + tasha->mbhc_started = false; + + /* Initialize MBHC module */ + ret = wcd_mbhc_init(&tasha->mbhc, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, TASHA_ZDET_SUPPORTED); + if (ret) + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + else + tasha_mbhc_hs_detect(component, tasha->mbhc.mbhc_cfg); + + tasha_cleanup_irqs(tasha); + ret = tasha_setup_irqs(tasha); + if (ret) { + dev_err(component->dev, "%s: tasha irq setup failed %d\n", + __func__, ret); + goto err; + } + + if (!tasha->swr_ctrl_data) { + ret = -EINVAL; + goto err; + } + + if (is_snd_event_fwk_enabled()) { + for (i = 0; i < tasha->nr; i++) + swrm_wcd_notify( + tasha->swr_ctrl_data[i].swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + } + + tasha_set_spkr_mode(component, tasha->spkr_mode); + wcd_cpe_ssr_event(tasha->cpe_core, WCD_CPE_BUS_UP_EVENT); + snd_event_notify(tasha->dev->parent, SND_EVENT_UP); +err: + mutex_unlock(&tasha->codec_mutex); + return ret; +} + +static struct regulator *tasha_codec_find_ondemand_regulator( + struct snd_soc_component *component, const char *name) +{ + int i; + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = tasha->wcd9xxx; + struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); + + for (i = 0; i < wcd9xxx->num_of_supplies; ++i) { + if (pdata->regulator[i].ondemand && + wcd9xxx->supplies[i].supply && + !strcmp(wcd9xxx->supplies[i].supply, name)) + return wcd9xxx->supplies[i].consumer; + } + + dev_dbg(tasha->dev, "Warning: regulator not found:%s\n", + name); + return NULL; +} + +static void tasha_ssr_disable(struct device *dev, void *data) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev); + struct tasha_priv *tasha; + struct snd_soc_component *component; + int count = 0; + + if (!wcd9xxx) { + dev_dbg(dev, "%s: wcd9xxx pointer NULL.\n", __func__); + return; + } + component = (struct snd_soc_component *)(wcd9xxx->ssr_priv); + tasha = snd_soc_component_get_drvdata(component); + + for (count = 0; count < NUM_CODEC_DAIS; count++) + tasha->dai[count].bus_down_in_recovery = true; +} + +static const struct snd_event_ops tasha_ssr_ops = { + .disable = tasha_ssr_disable, +}; + +static int tasha_codec_probe(struct snd_soc_component *component) +{ + struct wcd9xxx *control; + struct tasha_priv *tasha; + struct wcd9xxx_pdata *pdata; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int i, ret; + void *ptr = NULL; + struct regulator *supply; + + control = dev_get_drvdata(component->dev->parent); + + snd_soc_component_init_regmap(component, control->regmap); + + dev_info(component->dev, "%s()\n", __func__); + tasha = snd_soc_component_get_drvdata(component); + tasha->intf_type = wcd9xxx_get_intf_type(); + + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + control->dev_down = tasha_device_down; + control->post_reset = tasha_post_reset_cb; + control->ssr_priv = (void *)component; + } + + /* Resource Manager post Init */ + ret = wcd_resmgr_post_init(tasha->resmgr, &tasha_resmgr_cb, component); + if (ret) { + dev_err(component->dev, "%s: wcd resmgr post init failed\n", + __func__); + goto err; + } + /* Class-H Init*/ + wcd_clsh_init(&tasha->clsh_d); + /* Default HPH Mode to Class-H HiFi */ + tasha->hph_mode = CLS_H_HIFI; + + tasha->component = component; + for (i = 0; i < COMPANDER_MAX; i++) + tasha->comp_enabled[i] = 0; + + tasha->spkr_gain_offset = RX_GAIN_OFFSET_0_DB; + tasha->intf_type = wcd9xxx_get_intf_type(); + tasha_update_reg_reset_values(component); + pr_debug("%s: MCLK Rate = %x\n", __func__, control->mclk_rate); + if (control->mclk_rate == TASHA_MCLK_CLK_12P288MHZ) + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x00); + else if (control->mclk_rate == TASHA_MCLK_CLK_9P6MHZ) + snd_soc_component_update_bits(component, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x01); + tasha_codec_init_reg(component); + + tasha_enable_efuse_sensing(component); + + pdata = dev_get_platdata(component->dev->parent); + ret = tasha_handle_pdata(tasha, pdata); + if (ret < 0) { + pr_err("%s: bad pdata\n", __func__); + goto err; + } + + for (i = ON_DEMAND_MICBIAS; i < ON_DEMAND_SUPPLIES_MAX; i++) { + supply = tasha_codec_find_ondemand_regulator(component, + on_demand_supply_name[i]); + if (supply) { + tasha->on_demand_list[i].supply = supply; + tasha->on_demand_list[i].ondemand_supply_count = + 0; + } + } + + tasha->fw_data = devm_kzalloc(component->dev, + sizeof(*(tasha->fw_data)), GFP_KERNEL); + if (!tasha->fw_data) + goto err; + set_bit(WCD9XXX_ANC_CAL, tasha->fw_data->cal_bit); + set_bit(WCD9XXX_MBHC_CAL, tasha->fw_data->cal_bit); + set_bit(WCD9XXX_MAD_CAL, tasha->fw_data->cal_bit); + set_bit(WCD9XXX_VBAT_CAL, tasha->fw_data->cal_bit); + + ret = wcd_cal_create_hwdep(tasha->fw_data, + WCD9XXX_CODEC_HWDEP_NODE, component); + if (ret < 0) { + dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret); + goto err_hwdep; + } + + /* Initialize MBHC module */ + if (TASHA_IS_2_0(tasha->wcd9xxx)) { + wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].reg = + WCD9335_MBHC_FSM_STATUS; + wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].mask = 0x01; + } + ret = wcd_mbhc_init(&tasha->mbhc, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, TASHA_ZDET_SUPPORTED); + if (ret) { + pr_err("%s: mbhc initialization failed\n", __func__); + goto err_hwdep; + } + + ptr = devm_kzalloc(component->dev, (sizeof(tasha_rx_chs) + + sizeof(tasha_tx_chs)), GFP_KERNEL); + if (!ptr) { + ret = -ENOMEM; + goto err_hwdep; + } + + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + snd_soc_dapm_new_controls(dapm, tasha_dapm_i2s_widgets, + ARRAY_SIZE(tasha_dapm_i2s_widgets)); + snd_soc_dapm_add_routes(dapm, audio_i2s_map, + ARRAY_SIZE(audio_i2s_map)); + for (i = 0; i < ARRAY_SIZE(tasha_i2s_dai); i++) { + INIT_LIST_HEAD(&tasha->dai[i].wcd9xxx_ch_list); + init_waitqueue_head(&tasha->dai[i].dai_wait); + } + } else if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + for (i = 0; i < NUM_CODEC_DAIS; i++) { + INIT_LIST_HEAD(&tasha->dai[i].wcd9xxx_ch_list); + init_waitqueue_head(&tasha->dai[i].dai_wait); + } + tasha_slimbus_slave_port_cfg.slave_dev_intfdev_la = + control->slim_slave->laddr; + tasha_slimbus_slave_port_cfg.slave_dev_pgd_la = + control->slim->laddr; + tasha_slimbus_slave_port_cfg.slave_port_mapping[0] = + TASHA_TX13; + tasha_init_slim_slave_cfg(component); + } + + 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)); + + snd_soc_add_component_controls(component, + tasha_analog_gain_controls, + ARRAY_SIZE(tasha_analog_gain_controls)); + if (tasha->is_wsa_attach) + snd_soc_add_component_controls(component, + tasha_spkr_wsa_controls, + ARRAY_SIZE(tasha_spkr_wsa_controls)); + control->num_rx_port = TASHA_RX_MAX; + control->rx_chs = ptr; + memcpy(control->rx_chs, tasha_rx_chs, sizeof(tasha_rx_chs)); + control->num_tx_port = TASHA_TX_MAX; + control->tx_chs = ptr + sizeof(tasha_rx_chs); + memcpy(control->tx_chs, tasha_tx_chs, sizeof(tasha_tx_chs)); + + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "AIF2 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF2 Capture"); + + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + snd_soc_dapm_ignore_suspend(dapm, "AIF3 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF3 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "AIF4 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF Mix Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX"); + snd_soc_dapm_ignore_suspend(dapm, "VIfeed"); + snd_soc_dapm_ignore_suspend(dapm, "AIF5 CPE TX"); + } + + snd_soc_dapm_sync(dapm); + + ret = tasha_setup_irqs(tasha); + if (ret) { + pr_err("%s: tasha irq setup failed %d\n", __func__, ret); + goto err_pdata; + } + + ret = tasha_cpe_initialize(component); + if (ret) { + dev_err(component->dev, + "%s: cpe initialization failed, err = %d\n", + __func__, ret); + /* Do not fail probe if CPE failed */ + ret = 0; + } + + for (i = 0; i < TASHA_NUM_DECIMATORS; i++) { + tasha->tx_hpf_work[i].tasha = tasha; + tasha->tx_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&tasha->tx_hpf_work[i].dwork, + tasha_tx_hpf_corner_freq_callback); + } + + for (i = 0; i < TASHA_NUM_DECIMATORS; i++) { + tasha->tx_mute_dwork[i].tasha = tasha; + tasha->tx_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&tasha->tx_mute_dwork[i].dwork, + tasha_tx_mute_update_callback); + } + + tasha->spk_anc_dwork.tasha = tasha; + INIT_DELAYED_WORK(&tasha->spk_anc_dwork.dwork, + tasha_spk_anc_update_callback); + + mutex_lock(&tasha->codec_mutex); + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1"); + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2"); + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1 PA"); + snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2 PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR"); + snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA"); + mutex_unlock(&tasha->codec_mutex); + snd_soc_dapm_sync(dapm); + + return ret; + +err_pdata: + devm_kfree(component->dev, ptr); + control->rx_chs = NULL; + control->tx_chs = NULL; +err_hwdep: + devm_kfree(component->dev, tasha->fw_data); + tasha->fw_data = NULL; +err: + return ret; +} + +static void tasha_codec_remove(struct snd_soc_component *component) +{ + struct tasha_priv *tasha = snd_soc_component_get_drvdata(component); + struct wcd9xxx *control; + + control = dev_get_drvdata(component->dev->parent); + control->num_rx_port = 0; + control->num_tx_port = 0; + control->rx_chs = NULL; + control->tx_chs = NULL; + + tasha_cleanup_irqs(tasha); + /* Cleanup MBHC */ + wcd_mbhc_deinit(&tasha->mbhc); + /* Cleanup resmgr */ + + return; +} + +static const struct snd_soc_component_driver soc_codec_dev_tasha = { + .name = DRV_NAME, + .probe = tasha_codec_probe, + .remove = tasha_codec_remove, + .controls = tasha_snd_controls, + .num_controls = ARRAY_SIZE(tasha_snd_controls), + .dapm_widgets = tasha_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tasha_dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), +}; + +#ifdef CONFIG_PM +static int tasha_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tasha_priv *tasha = platform_get_drvdata(pdev); + + dev_dbg(dev, "%s: system suspend\n", __func__); + if (cancel_delayed_work_sync(&tasha->power_gate_work)) + tasha_codec_power_gate_digital_core(tasha); + + return 0; +} + +static int tasha_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tasha_priv *tasha = platform_get_drvdata(pdev); + + if (!tasha) { + dev_err(dev, "%s: tasha private data is NULL\n", __func__); + return -EINVAL; + } + dev_dbg(dev, "%s: system resume\n", __func__); + return 0; +} + +static const struct dev_pm_ops tasha_pm_ops = { + .suspend = tasha_suspend, + .resume = tasha_resume, +}; +#endif + +static int tasha_swrm_read(void *handle, int reg) +{ + struct tasha_priv *tasha; + struct wcd9xxx *wcd9xxx; + unsigned short swr_rd_addr_base; + unsigned short swr_rd_data_base; + int val, ret; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tasha = (struct tasha_priv *)handle; + wcd9xxx = tasha->wcd9xxx; + + dev_dbg(tasha->dev, "%s: Reading soundwire register, 0x%x\n", + __func__, reg); + swr_rd_addr_base = WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0; + swr_rd_data_base = WCD9335_SWR_AHB_BRIDGE_RD_DATA_0; + /* read_lock */ + mutex_lock(&tasha->swr_read_lock); + ret = regmap_bulk_write(wcd9xxx->regmap, swr_rd_addr_base, + (u8 *)®, 4); + if (ret < 0) { + pr_err("%s: RD Addr Failure\n", __func__); + goto err; + } + /* Check for RD status */ + ret = regmap_bulk_read(wcd9xxx->regmap, swr_rd_data_base, + (u8 *)&val, 4); + if (ret < 0) { + pr_err("%s: RD Data Failure\n", __func__); + goto err; + } + ret = val; +err: + /* read_unlock */ + mutex_unlock(&tasha->swr_read_lock); + return ret; +} + +static int tasha_swrm_i2s_bulk_write(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_reg_val *bulk_reg, + size_t len) +{ + int i, ret = 0; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + + swr_wr_addr_base = WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD9335_SWR_AHB_BRIDGE_WR_DATA_0; + + for (i = 0; i < (len * 2); i += 2) { + /* First Write the Data to register */ + ret = regmap_bulk_write(wcd9xxx->regmap, + swr_wr_data_base, bulk_reg[i].buf, 4); + if (ret < 0) { + dev_err(wcd9xxx->dev, "%s: WR Data Failure\n", + __func__); + break; + } + /* Next Write Address */ + ret = regmap_bulk_write(wcd9xxx->regmap, + swr_wr_addr_base, bulk_reg[i+1].buf, 4); + if (ret < 0) { + dev_err(wcd9xxx->dev, "%s: WR Addr Failure\n", + __func__); + break; + } + } + return ret; +} + +static int tasha_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len) +{ + struct tasha_priv *tasha; + struct wcd9xxx *wcd9xxx; + struct wcd9xxx_reg_val *bulk_reg; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + int i, j, ret; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + if (len <= 0) { + pr_err("%s: Invalid size: %zu\n", __func__, len); + return -EINVAL; + } + tasha = (struct tasha_priv *)handle; + wcd9xxx = tasha->wcd9xxx; + + swr_wr_addr_base = WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD9335_SWR_AHB_BRIDGE_WR_DATA_0; + + bulk_reg = kzalloc((2 * len * sizeof(struct wcd9xxx_reg_val)), + GFP_KERNEL); + if (!bulk_reg) + return -ENOMEM; + + for (i = 0, j = 0; i < (len * 2); i += 2, j++) { + bulk_reg[i].reg = swr_wr_data_base; + bulk_reg[i].buf = (u8 *)(&val[j]); + bulk_reg[i].bytes = 4; + bulk_reg[i+1].reg = swr_wr_addr_base; + bulk_reg[i+1].buf = (u8 *)(®[j]); + bulk_reg[i+1].bytes = 4; + } + mutex_lock(&tasha->swr_write_lock); + + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) { + ret = tasha_swrm_i2s_bulk_write(wcd9xxx, bulk_reg, len); + if (ret) { + dev_err(tasha->dev, "%s: i2s bulk write failed, ret: %d\n", + __func__, ret); + } + } else { + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, + (len * 2), false); + if (ret) { + dev_err(tasha->dev, "%s: swrm bulk write failed, ret: %d\n", + __func__, ret); + } + } + + mutex_unlock(&tasha->swr_write_lock); + kfree(bulk_reg); + + return ret; +} + +static int tasha_swrm_write(void *handle, int reg, int val) +{ + struct tasha_priv *tasha; + struct wcd9xxx *wcd9xxx; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + struct wcd9xxx_reg_val bulk_reg[2]; + int ret; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tasha = (struct tasha_priv *)handle; + wcd9xxx = tasha->wcd9xxx; + + swr_wr_addr_base = WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD9335_SWR_AHB_BRIDGE_WR_DATA_0; + + /* First Write the Data to register */ + bulk_reg[0].reg = swr_wr_data_base; + bulk_reg[0].buf = (u8 *)(&val); + bulk_reg[0].bytes = 4; + bulk_reg[1].reg = swr_wr_addr_base; + bulk_reg[1].buf = (u8 *)(®); + bulk_reg[1].bytes = 4; + + mutex_lock(&tasha->swr_write_lock); + + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) { + ret = tasha_swrm_i2s_bulk_write(wcd9xxx, bulk_reg, 1); + if (ret) { + dev_err(tasha->dev, "%s: i2s swrm write failed, ret: %d\n", + __func__, ret); + } + } else { + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2, false); + if (ret < 0) + pr_err("%s: WR Data Failure\n", __func__); + } + + mutex_unlock(&tasha->swr_write_lock); + return ret; +} + +static int tasha_swrm_clock(void *handle, bool enable) +{ + struct tasha_priv *tasha = (struct tasha_priv *) handle; + + mutex_lock(&tasha->swr_clk_lock); + + dev_dbg(tasha->dev, "%s: swrm clock %s\n", + __func__, (enable?"enable" : "disable")); + if (enable) { + tasha->swr_clk_users++; + if (tasha->swr_clk_users == 1) { + if (TASHA_IS_2_0(tasha->wcd9xxx)) + regmap_update_bits( + tasha->wcd9xxx->regmap, + WCD9335_TEST_DEBUG_NPL_DLY_TEST_1, + 0x10, 0x00); + __tasha_cdc_mclk_enable(tasha, true); + regmap_update_bits(tasha->wcd9xxx->regmap, + WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + } + } else { + tasha->swr_clk_users--; + if (tasha->swr_clk_users == 0) { + regmap_update_bits(tasha->wcd9xxx->regmap, + WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + __tasha_cdc_mclk_enable(tasha, false); + if (TASHA_IS_2_0(tasha->wcd9xxx)) + regmap_update_bits( + tasha->wcd9xxx->regmap, + WCD9335_TEST_DEBUG_NPL_DLY_TEST_1, + 0x10, 0x10); + } + } + dev_dbg(tasha->dev, "%s: swrm clock users %d\n", + __func__, tasha->swr_clk_users); + mutex_unlock(&tasha->swr_clk_lock); + return 0; +} + +static int tasha_swrm_handle_irq(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action) +{ + struct tasha_priv *tasha; + int ret = 0; + struct wcd9xxx *wcd9xxx; + + if (!handle) { + pr_err("%s: null handle received\n", __func__); + return -EINVAL; + } + tasha = (struct tasha_priv *) handle; + wcd9xxx = tasha->wcd9xxx; + + if (action) { + ret = wcd9xxx_request_irq(&wcd9xxx->core_res, + WCD9335_IRQ_SOUNDWIRE, + swrm_irq_handler, + "Tasha SWR Master", swrm_handle); + if (ret) + dev_err(tasha->dev, "%s: Failed to request irq %d\n", + __func__, WCD9335_IRQ_SOUNDWIRE); + } else + wcd9xxx_free_irq(&wcd9xxx->core_res, WCD9335_IRQ_SOUNDWIRE, + swrm_handle); + + return ret; +} + +static void tasha_add_child_devices(struct work_struct *work) +{ + struct tasha_priv *tasha; + struct platform_device *pdev; + struct device_node *node; + struct wcd9xxx *wcd9xxx; + struct tasha_swr_ctrl_data *swr_ctrl_data = NULL, *temp; + int ret, ctrl_num = 0; + struct wcd_swr_ctrl_platform_data *platdata; + char plat_dev_name[WCD9335_STRING_LEN]; + + tasha = container_of(work, struct tasha_priv, + tasha_add_child_devices_work); + if (!tasha) { + pr_err("%s: Memory for WCD9335 does not exist\n", + __func__); + return; + } + wcd9xxx = tasha->wcd9xxx; + if (!wcd9xxx) { + pr_err("%s: Memory for WCD9XXX does not exist\n", + __func__); + return; + } + if (!wcd9xxx->dev->of_node) { + pr_err("%s: DT node for wcd9xxx does not exist\n", + __func__); + return; + } + + platdata = &tasha->swr_plat_data; + tasha->child_count = 0; + + for_each_child_of_node(wcd9xxx->dev->of_node, node) { + if (!strcmp(node->name, "swr_master")) + strlcpy(plat_dev_name, "tasha_swr_ctrl", + (WCD9335_STRING_LEN - 1)); + else if (strnstr(node->name, "msm_cdc_pinctrl", + strlen("msm_cdc_pinctrl")) != NULL) + strlcpy(plat_dev_name, node->name, + (WCD9335_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err; + } + pdev->dev.parent = tasha->dev; + pdev->dev.of_node = node; + + if (!strcmp(node->name, "swr_master")) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } + tasha->is_wsa_attach = true; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto fail_pdev_add; + } + + if (!strcmp(node->name, "swr_master")) { + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct tasha_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(wcd9xxx->dev, "out of memory\n"); + ret = -ENOMEM; + goto err; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Added soundwire ctrl device(s)\n", + __func__); + tasha->nr = ctrl_num; + tasha->swr_ctrl_data = swr_ctrl_data; + } + + if (tasha->child_count < WCD9335_CHILD_DEVICES_MAX) + tasha->pdev_child_devices[tasha->child_count++] = pdev; + else + goto err; + } + + return; +fail_pdev_add: + platform_device_put(pdev); +err: + return; +} + +/* + * tasha_codec_ver: to get tasha codec version + * @codec: handle to snd_soc_component * + * return enum codec_variant - version + */ +enum codec_variant tasha_codec_ver(void) +{ + return codec_ver; +} +EXPORT_SYMBOL(tasha_codec_ver); + +static int __tasha_enable_efuse_sensing(struct tasha_priv *tasha) +{ + int val, rc; + + __tasha_cdc_mclk_enable(tasha, true); + + regmap_update_bits(tasha->wcd9xxx->regmap, + WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x20); + regmap_update_bits(tasha->wcd9xxx->regmap, + WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01); + + /* + * 5ms sleep required after enabling efuse control + * before checking the status. + */ + usleep_range(5000, 5500); + rc = regmap_read(tasha->wcd9xxx->regmap, + WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS, &val); + + if (rc || (!(val & 0x01))) + WARN(1, "%s: Efuse sense is not complete\n", __func__); + + __tasha_cdc_mclk_enable(tasha, false); + + return rc; +} + +void tasha_get_codec_ver(struct tasha_priv *tasha) +{ + int i; + int val; + struct tasha_reg_mask_val codec_reg[] = { + {WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10, 0xFF, 0xFF}, + {WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11, 0xFF, 0x83}, + {WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12, 0xFF, 0x0A}, + }; + + __tasha_enable_efuse_sensing(tasha); + for (i = 0; i < ARRAY_SIZE(codec_reg); i++) { + regmap_read(tasha->wcd9xxx->regmap, codec_reg[i].reg, &val); + if (!(val && codec_reg[i].val)) { + codec_ver = WCD9335; + goto ret; + } + } + codec_ver = WCD9326; +ret: + pr_debug("%s: codec is %d\n", __func__, codec_ver); +} +EXPORT_SYMBOL(tasha_get_codec_ver); + +static int tasha_probe(struct platform_device *pdev) +{ + int ret = 0; + struct tasha_priv *tasha; + struct clk *wcd_ext_clk, *wcd_native_clk; + struct wcd9xxx_resmgr_v2 *resmgr; + struct wcd9xxx_power_region *cdc_pwr; + + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) { + if (apr_get_subsys_state() == APR_SUBSYS_DOWN) { + dev_err(&pdev->dev, "%s: dsp down\n", __func__); + return -EPROBE_DEFER; + } + } + + tasha = devm_kzalloc(&pdev->dev, sizeof(struct tasha_priv), + GFP_KERNEL); + if (!tasha) + return -ENOMEM; + platform_set_drvdata(pdev, tasha); + + tasha->wcd9xxx = dev_get_drvdata(pdev->dev.parent); + tasha->dev = &pdev->dev; + INIT_DELAYED_WORK(&tasha->power_gate_work, tasha_codec_power_gate_work); + mutex_init(&tasha->power_lock); + mutex_init(&tasha->sido_lock); + INIT_WORK(&tasha->tasha_add_child_devices_work, + tasha_add_child_devices); + BLOCKING_INIT_NOTIFIER_HEAD(&tasha->notifier); + mutex_init(&tasha->micb_lock); + mutex_init(&tasha->swr_read_lock); + mutex_init(&tasha->swr_write_lock); + mutex_init(&tasha->swr_clk_lock); + mutex_init(&tasha->sb_clk_gear_lock); + mutex_init(&tasha->mclk_lock); + + cdc_pwr = devm_kzalloc(&pdev->dev, sizeof(struct wcd9xxx_power_region), + GFP_KERNEL); + if (!cdc_pwr) { + ret = -ENOMEM; + goto err_cdc_pwr; + } + tasha->wcd9xxx->wcd9xxx_pwr[WCD9XXX_DIG_CORE_REGION_1] = cdc_pwr; + cdc_pwr->pwr_collapse_reg_min = TASHA_DIG_CORE_REG_MIN; + cdc_pwr->pwr_collapse_reg_max = TASHA_DIG_CORE_REG_MAX; + wcd9xxx_set_power_state(tasha->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_REMOVE, + WCD9XXX_DIG_CORE_REGION_1); + + mutex_init(&tasha->codec_mutex); + /* + * Init resource manager so that if child nodes such as SoundWire + * requests for clock, resource manager can honor the request + */ + resmgr = wcd_resmgr_init(&tasha->wcd9xxx->core_res, NULL); + if (IS_ERR(resmgr)) { + ret = PTR_ERR(resmgr); + dev_err(&pdev->dev, "%s: Failed to initialize wcd resmgr\n", + __func__); + goto err_resmgr; + } + tasha->resmgr = resmgr; + tasha->swr_plat_data.handle = (void *) tasha; + tasha->swr_plat_data.read = tasha_swrm_read; + tasha->swr_plat_data.write = tasha_swrm_write; + tasha->swr_plat_data.bulk_write = tasha_swrm_bulk_write; + tasha->swr_plat_data.clk = tasha_swrm_clock; + tasha->swr_plat_data.handle_irq = tasha_swrm_handle_irq; + + /* Register for Clock */ + wcd_ext_clk = clk_get(tasha->wcd9xxx->dev, "wcd_clk"); + if (IS_ERR(wcd_ext_clk)) { + dev_err(tasha->wcd9xxx->dev, "%s: clk get %s failed\n", + __func__, "wcd_ext_clk"); + goto err_clk; + } + tasha->wcd_ext_clk = wcd_ext_clk; + tasha->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; + set_bit(AUDIO_NOMINAL, &tasha->status_mask); + tasha->sido_ccl_cnt = 0; + + /* Register native clk for 44.1 playback */ + wcd_native_clk = clk_get(tasha->wcd9xxx->dev, "wcd_native_clk"); + if (IS_ERR(wcd_native_clk)) + dev_dbg(tasha->wcd9xxx->dev, "%s: clk get %s failed\n", + __func__, "wcd_native_clk"); + else + tasha->wcd_native_clk = wcd_native_clk; + + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + ret = snd_soc_register_component(&pdev->dev, + &soc_codec_dev_tasha, + tasha_dai, ARRAY_SIZE(tasha_dai)); + else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) + ret = snd_soc_register_component(&pdev->dev, + &soc_codec_dev_tasha, + tasha_i2s_dai, + ARRAY_SIZE(tasha_i2s_dai)); + else + ret = -EINVAL; + if (ret) { + dev_err(&pdev->dev, "%s: Codec registration failed, ret = %d\n", + __func__, ret); + goto err_cdc_reg; + } + /* Update codec register default values */ + tasha_update_reg_defaults(tasha); + schedule_work(&tasha->tasha_add_child_devices_work); + tasha_get_codec_ver(tasha); + ret = snd_event_client_register(pdev->dev.parent, &tasha_ssr_ops, NULL); + if (!ret) { + snd_event_notify(pdev->dev.parent, SND_EVENT_UP); + } else { + pr_err("%s: Registration with SND event fwk failed ret = %d\n", + __func__, ret); + ret = 0; + } + + dev_info(&pdev->dev, "%s: Tasha driver probe done\n", __func__); + return ret; + +err_cdc_reg: + clk_put(tasha->wcd_ext_clk); + if (tasha->wcd_native_clk) + clk_put(tasha->wcd_native_clk); +err_clk: + wcd_resmgr_remove(tasha->resmgr); +err_resmgr: + devm_kfree(&pdev->dev, cdc_pwr); +err_cdc_pwr: + mutex_destroy(&tasha->mclk_lock); + devm_kfree(&pdev->dev, tasha); + return ret; +} + +static int tasha_remove(struct platform_device *pdev) +{ + struct tasha_priv *tasha; + int count = 0; + + tasha = platform_get_drvdata(pdev); + + if (!tasha) + return -EINVAL; + + snd_event_client_deregister(pdev->dev.parent); + for (count = 0; count < tasha->child_count && + count < WCD9335_CHILD_DEVICES_MAX; count++) + platform_device_unregister(tasha->pdev_child_devices[count]); + + mutex_destroy(&tasha->codec_mutex); + clk_put(tasha->wcd_ext_clk); + if (tasha->wcd_native_clk) + clk_put(tasha->wcd_native_clk); + mutex_destroy(&tasha->mclk_lock); + mutex_destroy(&tasha->sb_clk_gear_lock); + snd_soc_unregister_component(&pdev->dev); + devm_kfree(&pdev->dev, tasha); + return 0; +} + +static struct platform_driver tasha_codec_driver = { + .probe = tasha_probe, + .remove = tasha_remove, + .driver = { + .name = "tasha_codec", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &tasha_pm_ops, +#endif + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(tasha_codec_driver); + +MODULE_DESCRIPTION("Tasha Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9335.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335.h new file mode 100644 index 0000000000..707f2e9627 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335.h @@ -0,0 +1,239 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ +#ifndef WCD9335_H +#define WCD9335_H + +#include +#include +#include +#include +#include + +#define TASHA_REG_VAL(reg, val) {reg, 0, val} + +#define TASHA_REGISTER_START_OFFSET 0x800 +#define TASHA_SB_PGD_PORT_RX_BASE 0x40 +#define TASHA_SB_PGD_PORT_TX_BASE 0x50 + +#define TASHA_ZDET_SUPPORTED true +/* z value defined in milliohm */ +#define TASHA_ZDET_VAL_32 32000 +#define TASHA_ZDET_VAL_400 400000 +#define TASHA_ZDET_VAL_1200 1200000 +#define TASHA_ZDET_VAL_100K 100000000 +/* z floating defined in ohms */ +#define TASHA_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define WCD9335_DMIC_CLK_DIV_2 0x0 +#define WCD9335_DMIC_CLK_DIV_3 0x1 +#define WCD9335_DMIC_CLK_DIV_4 0x2 +#define WCD9335_DMIC_CLK_DIV_6 0x3 +#define WCD9335_DMIC_CLK_DIV_8 0x4 +#define WCD9335_DMIC_CLK_DIV_16 0x5 +#define WCD9335_DMIC_CLK_DRIVE_DEFAULT 0x02 + +#define WCD9335_ANC_DMIC_X2_FULL_RATE 1 +#define WCD9335_ANC_DMIC_X2_HALF_RATE 0 + +/* Number of input and output Slimbus port */ +enum { + TASHA_RX0 = 0, + TASHA_RX1, + TASHA_RX2, + TASHA_RX3, + TASHA_RX4, + TASHA_RX5, + TASHA_RX6, + TASHA_RX7, + TASHA_RX8, + TASHA_RX9, + TASHA_RX10, + TASHA_RX11, + TASHA_RX12, + TASHA_RX_MAX, +}; + +enum { + TASHA_TX0 = 0, + TASHA_TX1, + TASHA_TX2, + TASHA_TX3, + TASHA_TX4, + TASHA_TX5, + TASHA_TX6, + TASHA_TX7, + TASHA_TX8, + TASHA_TX9, + TASHA_TX10, + TASHA_TX11, + TASHA_TX12, + TASHA_TX13, + TASHA_TX14, + TASHA_TX15, + TASHA_TX_MAX, +}; + +enum wcd9335_codec_event { + WCD9335_CODEC_EVENT_CODEC_UP = 0, +}; + +enum tasha_on_demand_supply { + ON_DEMAND_MICBIAS = 0, + ON_DEMAND_TX_SUPPLY, + ON_DEMAND_RX_SUPPLY, + ON_DEMAND_SUPPLIES_MAX, +}; + +/* structure used to put the defined + * ondemand supply for codec + * and count being used. + */ +struct on_demand_supply { + struct regulator *supply; + int ondemand_supply_count; +}; + +/* Dai data structure holds the + * dai specific info like rate, + * channel number etc. + */ +struct tasha_codec_dai_data { + u32 rate; + u32 *ch_num; + u32 ch_act; + u32 ch_tot; +}; + +/* Structure used to update codec + * register defaults after reset + */ +struct tasha_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +/* Selects compander and smart boost settings + * for a given speaker mode + */ +enum { + SPKR_MODE_DEFAULT, + SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */ +}; + +/* + * Rx path gain offsets + */ +enum { + RX_GAIN_OFFSET_M1P5_DB, + RX_GAIN_OFFSET_0_DB, +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD9335) +extern void *tasha_get_afe_config(struct snd_soc_component *component, + enum afe_config_type config_type); +extern int tasha_cdc_mclk_enable(struct snd_soc_component *component, + int enable, bool dapm); +extern int tasha_cdc_mclk_tx_enable(struct snd_soc_component *component, + int enable, bool dapm); +extern int tasha_enable_efuse_sensing(struct snd_soc_component *component); +extern int tasha_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void tasha_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern void tasha_mbhc_zdet_gpio_ctrl( + int (*zdet_gpio_cb)(struct snd_soc_component *component, + bool high), struct snd_soc_component *component); +extern int tasha_codec_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component); +extern void tasha_event_register( + int (*machine_event_cb)(struct snd_soc_component *component, + enum wcd9335_codec_event), + struct snd_soc_component *component); +extern int tasha_codec_enable_standalone_micbias( + struct snd_soc_component *component, + int micb_num, + bool enable); +extern int tasha_set_spkr_mode(struct snd_soc_component *component, int mode); +extern int tasha_set_spkr_gain_offset(struct snd_soc_component *component, + int offset); +extern enum codec_variant tasha_codec_ver(void); +#else /* CONFIG_SND_SOC_WCD9335 */ +static inline void *tasha_get_afe_config(struct snd_soc_component *component, + enum afe_config_type config_type) +{ + return NULL; +} +static inline int tasha_cdc_mclk_enable(struct snd_soc_component *component, + int enable, + bool dapm) +{ + return 0; +} +static inline int tasha_cdc_mclk_tx_enable(struct snd_soc_component *component, + int enable, + bool dapm) +{ + return 0; +} +static inline int tasha_enable_efuse_sensing( + struct snd_soc_component *component) +{ + return 0; +} +static inline int tasha_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void tasha_mbhc_hs_detect_exit( + struct snd_soc_component *component) +{ + +} +static inline void tasha_mbhc_zdet_gpio_ctrl( + int (*zdet_gpio_cb)(struct snd_soc_component *component, + bool high), + struct snd_soc_component *component) +{ + +} +static inline int tasha_codec_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} +static inline void tasha_event_register( + int (*machine_event_cb)(struct snd_soc_component *component, + enum wcd9335_codec_event), + struct snd_soc_component *component) +{ + +} +static inline int tasha_codec_enable_standalone_micbias( + struct snd_soc_component *component, + int micb_num, + bool enable) +{ + return 0; +} +static inline int tasha_set_spkr_mode(struct snd_soc_component *component, + int mode) +{ + return 0; +} +static inline int tasha_set_spkr_gain_offset( + struct snd_soc_component *component, + int offset) +{ + return 0; +} +static inline enum codec_variant tasha_codec_ver(void) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD9335 */ +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9335_irq.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335_irq.h new file mode 100644 index 0000000000..39a223d026 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335_irq.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD9335_IRQ_H_ +#define __WCD9335_IRQ_H_ + +enum { + /* INTR_REG 0 */ + WCD9335_IRQ_FLL_LOCK_LOSS = 1, + WCD9335_IRQ_HPH_PA_OCPL_FAULT, + WCD9335_IRQ_HPH_PA_OCPR_FAULT, + WCD9335_IRQ_EAR_PA_OCP_FAULT, + WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, + WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, + WCD9335_IRQ_EAR_PA_CNP_COMPLETE, + /* INTR_REG 1 */ + WCD9335_IRQ_MBHC_SW_DET, + WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, + WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, + WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD9335_IRQ_RESERVED_0, + WCD9335_IRQ_RESERVED_1, + WCD9335_IRQ_RESERVED_2, + /* INTR_REG 2 */ + WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, + WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, + WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, + WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, + WCD9335_IRQ_SOUNDWIRE, + WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, + WCD9335_IRQ_RCO_ERROR, + WCD9335_IRQ_SVA_ERROR, + /* INTR_REG 3 */ + WCD9335_IRQ_MAD_AUDIO, + WCD9335_IRQ_MAD_BEACON, + WCD9335_IRQ_MAD_ULTRASOUND, + WCD9335_IRQ_VBAT_ATTACK, + WCD9335_IRQ_VBAT_RESTORE, + WCD9335_IRQ_SVA_OUTBOX1, + WCD9335_IRQ_SVA_OUTBOX2, + WCD9335_NUM_IRQS, +}; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9335_registers.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335_registers.h new file mode 100644 index 0000000000..19a942c2a6 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9335_registers.h @@ -0,0 +1,1340 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + */ + +#ifndef _WCD9335_REGISTERS_H +#define _WCD9335_REGISTERS_H + +#define WCD9335_PAGE_SIZE 256 +#define WCD9335_NUM_PAGES 256 + +extern const u8 *wcd9335_reg[WCD9335_NUM_PAGES]; + +enum { + PAGE_0 = 0, + PAGE_1, + PAGE_2, + PAGE_6 = 6, + PAGE_10 = 0xA, + PAGE_11, + PAGE_12, + PAGE_13, + PAGE_0X80, +}; + +/* Page-0 Registers */ +#define WCD9335_PAGE0_PAGE_REGISTER 0x0000 +#define WCD9335_CODEC_RPM_CLK_BYPASS 0x0001 +#define WCD9335_CODEC_RPM_CLK_GATE 0x0002 +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG 0x0003 +#define WCD9335_CODEC_RPM_RST_CTL 0x0009 +#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL 0x0011 +#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1 0x0012 +#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2 0x0013 +#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3 0x0014 +#define WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN 0x0015 +#define WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN 0x0016 +#define WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1 0x0017 +#define WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2 0x0018 +#define WCD9335_CODEC_RPM_INT_MASK 0x001d +#define WCD9335_CODEC_RPM_INT_STATUS 0x001e +#define WCD9335_CODEC_RPM_INT_CLEAR 0x001f +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0 0x0021 +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1 0x0022 +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2 0x0023 +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3 0x0024 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL 0x0025 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0 0x0026 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1 0x0027 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0 0x0029 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 0x002a +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 0x002b +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3 0x002c +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4 0x002d +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5 0x002e +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6 0x002f +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7 0x0030 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8 0x0031 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9 0x0032 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10 0x0033 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11 0x0034 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12 0x0035 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13 0x0036 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14 0x0037 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15 0x0038 +#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS 0x0039 +#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO 0x003a +#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1 0x003b +#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2 0x003c +#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3 0x003d +#define WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL 0x003e +#define WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE 0x003f +#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL 0x0041 +#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS 0x0042 +#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB 0x0043 +#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB 0x0044 +#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL 0x0045 +#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS 0x0046 +#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB 0x0047 +#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB 0x0048 +#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL 0x0049 +#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS 0x004a +#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB 0x004b +#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB 0x004c +#define WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL 0x0051 +#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL 0x0052 +#define WCD9335_DATA_HUB_DATA_HUB_I2S_CLK 0x0053 +#define WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG 0x0054 +#define WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG 0x0055 +#define WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG 0x0056 +#define WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG 0x0057 +#define WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG 0x0058 +#define WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG 0x0059 +#define WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG 0x005a +#define WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG 0x005b +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG 0x0061 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG 0x0062 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG 0x0063 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG 0x0064 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG 0x0065 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG 0x0066 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG 0x0067 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG 0x0068 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG 0x0069 +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG 0x006a +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG 0x006b +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG 0x006c +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG 0x006e +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG 0x006f +#define WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG 0x0070 +#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG 0x0071 +#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG 0x0072 +#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG 0x0073 +#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG 0x0074 +#define WCD9335_DATA_HUB_NATIVE_FIFO_SYNC 0x0075 +#define WCD9335_DATA_HUB_NATIVE_FIFO_STATUS 0x007D +#define WCD9335_INTR_CFG 0x0081 +#define WCD9335_INTR_CLR_COMMIT 0x0082 +#define WCD9335_INTR_PIN1_MASK0 0x0089 +#define WCD9335_INTR_PIN1_MASK1 0x008a +#define WCD9335_INTR_PIN1_MASK2 0x008b +#define WCD9335_INTR_PIN1_MASK3 0x008c +#define WCD9335_INTR_PIN1_STATUS0 0x0091 +#define WCD9335_INTR_PIN1_STATUS1 0x0092 +#define WCD9335_INTR_PIN1_STATUS2 0x0093 +#define WCD9335_INTR_PIN1_STATUS3 0x0094 +#define WCD9335_INTR_PIN1_CLEAR0 0x0099 +#define WCD9335_INTR_PIN1_CLEAR1 0x009a +#define WCD9335_INTR_PIN1_CLEAR2 0x009b +#define WCD9335_INTR_PIN1_CLEAR3 0x009c +#define WCD9335_INTR_PIN2_MASK0 0x00a1 +#define WCD9335_INTR_PIN2_MASK1 0x00a2 +#define WCD9335_INTR_PIN2_MASK2 0x00a3 +#define WCD9335_INTR_PIN2_MASK3 0x00a4 +#define WCD9335_INTR_PIN2_STATUS0 0x00a9 +#define WCD9335_INTR_PIN2_STATUS1 0x00aa +#define WCD9335_INTR_PIN2_STATUS2 0x00ab +#define WCD9335_INTR_PIN2_STATUS3 0x00ac +#define WCD9335_INTR_PIN2_CLEAR0 0x00b1 +#define WCD9335_INTR_PIN2_CLEAR1 0x00b2 +#define WCD9335_INTR_PIN2_CLEAR2 0x00b3 +#define WCD9335_INTR_PIN2_CLEAR3 0x00b4 +#define WCD9335_INTR_LEVEL0 0x00e1 +#define WCD9335_INTR_LEVEL1 0x00e2 +#define WCD9335_INTR_LEVEL2 0x00e3 +#define WCD9335_INTR_LEVEL3 0x00e4 +#define WCD9335_INTR_BYPASS0 0x00e9 +#define WCD9335_INTR_BYPASS1 0x00ea +#define WCD9335_INTR_BYPASS2 0x00eb +#define WCD9335_INTR_BYPASS3 0x00ec +#define WCD9335_INTR_SET0 0x00f1 +#define WCD9335_INTR_SET1 0x00f2 +#define WCD9335_INTR_SET2 0x00f3 +#define WCD9335_INTR_SET3 0x00f4 + +/* Page-1 Registers */ +#define WCD9335_PAGE1_PAGE_REGISTER 0x0100 +#define WCD9335_CPE_FLL_USER_CTL_0 0x0101 +#define WCD9335_CPE_FLL_USER_CTL_1 0x0102 +#define WCD9335_CPE_FLL_USER_CTL_2 0x0103 +#define WCD9335_CPE_FLL_USER_CTL_3 0x0104 +#define WCD9335_CPE_FLL_USER_CTL_4 0x0105 +#define WCD9335_CPE_FLL_USER_CTL_5 0x0106 +#define WCD9335_CPE_FLL_USER_CTL_6 0x0107 +#define WCD9335_CPE_FLL_USER_CTL_7 0x0108 +#define WCD9335_CPE_FLL_USER_CTL_8 0x0109 +#define WCD9335_CPE_FLL_USER_CTL_9 0x010a +#define WCD9335_CPE_FLL_L_VAL_CTL_0 0x010b +#define WCD9335_CPE_FLL_L_VAL_CTL_1 0x010c +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0 0x010d +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1 0x010e +#define WCD9335_CPE_FLL_CONFIG_CTL_0 0x010f +#define WCD9335_CPE_FLL_CONFIG_CTL_1 0x0110 +#define WCD9335_CPE_FLL_CONFIG_CTL_2 0x0111 +#define WCD9335_CPE_FLL_CONFIG_CTL_3 0x0112 +#define WCD9335_CPE_FLL_CONFIG_CTL_4 0x0113 +#define WCD9335_CPE_FLL_TEST_CTL_0 0x0114 +#define WCD9335_CPE_FLL_TEST_CTL_1 0x0115 +#define WCD9335_CPE_FLL_TEST_CTL_2 0x0116 +#define WCD9335_CPE_FLL_TEST_CTL_3 0x0117 +#define WCD9335_CPE_FLL_TEST_CTL_4 0x0118 +#define WCD9335_CPE_FLL_TEST_CTL_5 0x0119 +#define WCD9335_CPE_FLL_TEST_CTL_6 0x011a +#define WCD9335_CPE_FLL_TEST_CTL_7 0x011b +#define WCD9335_CPE_FLL_FREQ_CTL_0 0x011c +#define WCD9335_CPE_FLL_FREQ_CTL_1 0x011d +#define WCD9335_CPE_FLL_FREQ_CTL_2 0x011e +#define WCD9335_CPE_FLL_FREQ_CTL_3 0x011f +#define WCD9335_CPE_FLL_SSC_CTL_0 0x0120 +#define WCD9335_CPE_FLL_SSC_CTL_1 0x0121 +#define WCD9335_CPE_FLL_SSC_CTL_2 0x0122 +#define WCD9335_CPE_FLL_SSC_CTL_3 0x0123 +#define WCD9335_CPE_FLL_FLL_MODE 0x0124 +#define WCD9335_CPE_FLL_STATUS_0 0x0125 +#define WCD9335_CPE_FLL_STATUS_1 0x0126 +#define WCD9335_CPE_FLL_STATUS_2 0x0127 +#define WCD9335_CPE_FLL_STATUS_3 0x0128 +#define WCD9335_I2S_FLL_USER_CTL_0 0x0141 +#define WCD9335_I2S_FLL_USER_CTL_1 0x0142 +#define WCD9335_I2S_FLL_USER_CTL_2 0x0143 +#define WCD9335_I2S_FLL_USER_CTL_3 0x0144 +#define WCD9335_I2S_FLL_USER_CTL_4 0x0145 +#define WCD9335_I2S_FLL_USER_CTL_5 0x0146 +#define WCD9335_I2S_FLL_USER_CTL_6 0x0147 +#define WCD9335_I2S_FLL_USER_CTL_7 0x0148 +#define WCD9335_I2S_FLL_USER_CTL_8 0x0149 +#define WCD9335_I2S_FLL_USER_CTL_9 0x014a +#define WCD9335_I2S_FLL_L_VAL_CTL_0 0x014b +#define WCD9335_I2S_FLL_L_VAL_CTL_1 0x014c +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0 0x014d +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1 0x014e +#define WCD9335_I2S_FLL_CONFIG_CTL_0 0x014f +#define WCD9335_I2S_FLL_CONFIG_CTL_1 0x0150 +#define WCD9335_I2S_FLL_CONFIG_CTL_2 0x0151 +#define WCD9335_I2S_FLL_CONFIG_CTL_3 0x0152 +#define WCD9335_I2S_FLL_CONFIG_CTL_4 0x0153 +#define WCD9335_I2S_FLL_TEST_CTL_0 0x0154 +#define WCD9335_I2S_FLL_TEST_CTL_1 0x0155 +#define WCD9335_I2S_FLL_TEST_CTL_2 0x0156 +#define WCD9335_I2S_FLL_TEST_CTL_3 0x0157 +#define WCD9335_I2S_FLL_TEST_CTL_4 0x0158 +#define WCD9335_I2S_FLL_TEST_CTL_5 0x0159 +#define WCD9335_I2S_FLL_TEST_CTL_6 0x015a +#define WCD9335_I2S_FLL_TEST_CTL_7 0x015b +#define WCD9335_I2S_FLL_FREQ_CTL_0 0x015c +#define WCD9335_I2S_FLL_FREQ_CTL_1 0x015d +#define WCD9335_I2S_FLL_FREQ_CTL_2 0x015e +#define WCD9335_I2S_FLL_FREQ_CTL_3 0x015f +#define WCD9335_I2S_FLL_SSC_CTL_0 0x0160 +#define WCD9335_I2S_FLL_SSC_CTL_1 0x0161 +#define WCD9335_I2S_FLL_SSC_CTL_2 0x0162 +#define WCD9335_I2S_FLL_SSC_CTL_3 0x0163 +#define WCD9335_I2S_FLL_FLL_MODE 0x0164 +#define WCD9335_I2S_FLL_STATUS_0 0x0165 +#define WCD9335_I2S_FLL_STATUS_1 0x0166 +#define WCD9335_I2S_FLL_STATUS_2 0x0167 +#define WCD9335_I2S_FLL_STATUS_3 0x0168 +#define WCD9335_SB_FLL_USER_CTL_0 0x0181 +#define WCD9335_SB_FLL_USER_CTL_1 0x0182 +#define WCD9335_SB_FLL_USER_CTL_2 0x0183 +#define WCD9335_SB_FLL_USER_CTL_3 0x0184 +#define WCD9335_SB_FLL_USER_CTL_4 0x0185 +#define WCD9335_SB_FLL_USER_CTL_5 0x0186 +#define WCD9335_SB_FLL_USER_CTL_6 0x0187 +#define WCD9335_SB_FLL_USER_CTL_7 0x0188 +#define WCD9335_SB_FLL_USER_CTL_8 0x0189 +#define WCD9335_SB_FLL_USER_CTL_9 0x018a +#define WCD9335_SB_FLL_L_VAL_CTL_0 0x018b +#define WCD9335_SB_FLL_L_VAL_CTL_1 0x018c +#define WCD9335_SB_FLL_DSM_FRAC_CTL_0 0x018d +#define WCD9335_SB_FLL_DSM_FRAC_CTL_1 0x018e +#define WCD9335_SB_FLL_CONFIG_CTL_0 0x018f +#define WCD9335_SB_FLL_CONFIG_CTL_1 0x0190 +#define WCD9335_SB_FLL_CONFIG_CTL_2 0x0191 +#define WCD9335_SB_FLL_CONFIG_CTL_3 0x0192 +#define WCD9335_SB_FLL_CONFIG_CTL_4 0x0193 +#define WCD9335_SB_FLL_TEST_CTL_0 0x0194 +#define WCD9335_SB_FLL_TEST_CTL_1 0x0195 +#define WCD9335_SB_FLL_TEST_CTL_2 0x0196 +#define WCD9335_SB_FLL_TEST_CTL_3 0x0197 +#define WCD9335_SB_FLL_TEST_CTL_4 0x0198 +#define WCD9335_SB_FLL_TEST_CTL_5 0x0199 +#define WCD9335_SB_FLL_TEST_CTL_6 0x019a +#define WCD9335_SB_FLL_TEST_CTL_7 0x019b +#define WCD9335_SB_FLL_FREQ_CTL_0 0x019c +#define WCD9335_SB_FLL_FREQ_CTL_1 0x019d +#define WCD9335_SB_FLL_FREQ_CTL_2 0x019e +#define WCD9335_SB_FLL_FREQ_CTL_3 0x019f +#define WCD9335_SB_FLL_SSC_CTL_0 0x01a0 +#define WCD9335_SB_FLL_SSC_CTL_1 0x01a1 +#define WCD9335_SB_FLL_SSC_CTL_2 0x01a2 +#define WCD9335_SB_FLL_SSC_CTL_3 0x01a3 +#define WCD9335_SB_FLL_FLL_MODE 0x01a4 +#define WCD9335_SB_FLL_STATUS_0 0x01a5 +#define WCD9335_SB_FLL_STATUS_1 0x01a6 +#define WCD9335_SB_FLL_STATUS_2 0x01a7 +#define WCD9335_SB_FLL_STATUS_3 0x01a8 + +/* Page-2 Registers */ +#define WCD9335_PAGE2_PAGE_REGISTER 0x0200 +#define WCD9335_CPE_SS_MEM_PTR_0 0x0201 +#define WCD9335_CPE_SS_MEM_PTR_1 0x0202 +#define WCD9335_CPE_SS_MEM_PTR_2 0x0203 +#define WCD9335_CPE_SS_MEM_CTRL 0x0205 +#define WCD9335_CPE_SS_MEM_BANK_0 0x0206 +#define WCD9335_CPE_SS_MEM_BANK_1 0x0207 +#define WCD9335_CPE_SS_MEM_BANK_2 0x0208 +#define WCD9335_CPE_SS_MEM_BANK_3 0x0209 +#define WCD9335_CPE_SS_MEM_BANK_4 0x020a +#define WCD9335_CPE_SS_MEM_BANK_5 0x020b +#define WCD9335_CPE_SS_MEM_BANK_6 0x020c +#define WCD9335_CPE_SS_MEM_BANK_7 0x020d +#define WCD9335_CPE_SS_MEM_BANK_8 0x020e +#define WCD9335_CPE_SS_MEM_BANK_9 0x020f +#define WCD9335_CPE_SS_MEM_BANK_10 0x0210 +#define WCD9335_CPE_SS_MEM_BANK_11 0x0211 +#define WCD9335_CPE_SS_MEM_BANK_12 0x0212 +#define WCD9335_CPE_SS_MEM_BANK_13 0x0213 +#define WCD9335_CPE_SS_MEM_BANK_14 0x0214 +#define WCD9335_CPE_SS_MEM_BANK_15 0x0215 +#define WCD9335_CPE_SS_INBOX1_TRG 0x0216 +#define WCD9335_CPE_SS_INBOX2_TRG 0x0217 +#define WCD9335_CPE_SS_INBOX1_0 0x0218 +#define WCD9335_CPE_SS_INBOX1_1 0x0219 +#define WCD9335_CPE_SS_INBOX1_2 0x021a +#define WCD9335_CPE_SS_INBOX1_3 0x021b +#define WCD9335_CPE_SS_INBOX1_4 0x021c +#define WCD9335_CPE_SS_INBOX1_5 0x021d +#define WCD9335_CPE_SS_INBOX1_6 0x021e +#define WCD9335_CPE_SS_INBOX1_7 0x021f +#define WCD9335_CPE_SS_INBOX1_8 0x0220 +#define WCD9335_CPE_SS_INBOX1_9 0x0221 +#define WCD9335_CPE_SS_INBOX1_10 0x0222 +#define WCD9335_CPE_SS_INBOX1_11 0x0223 +#define WCD9335_CPE_SS_INBOX1_12 0x0224 +#define WCD9335_CPE_SS_INBOX1_13 0x0225 +#define WCD9335_CPE_SS_INBOX1_14 0x0226 +#define WCD9335_CPE_SS_INBOX1_15 0x0227 +#define WCD9335_CPE_SS_OUTBOX1_0 0x0228 +#define WCD9335_CPE_SS_OUTBOX1_1 0x0229 +#define WCD9335_CPE_SS_OUTBOX1_2 0x022a +#define WCD9335_CPE_SS_OUTBOX1_3 0x022b +#define WCD9335_CPE_SS_OUTBOX1_4 0x022c +#define WCD9335_CPE_SS_OUTBOX1_5 0x022d +#define WCD9335_CPE_SS_OUTBOX1_6 0x022e +#define WCD9335_CPE_SS_OUTBOX1_7 0x022f +#define WCD9335_CPE_SS_OUTBOX1_8 0x0230 +#define WCD9335_CPE_SS_OUTBOX1_9 0x0231 +#define WCD9335_CPE_SS_OUTBOX1_10 0x0232 +#define WCD9335_CPE_SS_OUTBOX1_11 0x0233 +#define WCD9335_CPE_SS_OUTBOX1_12 0x0234 +#define WCD9335_CPE_SS_OUTBOX1_13 0x0235 +#define WCD9335_CPE_SS_OUTBOX1_14 0x0236 +#define WCD9335_CPE_SS_OUTBOX1_15 0x0237 +#define WCD9335_CPE_SS_INBOX2_0 0x0238 +#define WCD9335_CPE_SS_INBOX2_1 0x0239 +#define WCD9335_CPE_SS_INBOX2_2 0x023a +#define WCD9335_CPE_SS_INBOX2_3 0x023b +#define WCD9335_CPE_SS_INBOX2_4 0x023c +#define WCD9335_CPE_SS_INBOX2_5 0x023d +#define WCD9335_CPE_SS_INBOX2_6 0x023e +#define WCD9335_CPE_SS_INBOX2_7 0x023f +#define WCD9335_CPE_SS_INBOX2_8 0x0240 +#define WCD9335_CPE_SS_INBOX2_9 0x0241 +#define WCD9335_CPE_SS_INBOX2_10 0x0242 +#define WCD9335_CPE_SS_INBOX2_11 0x0243 +#define WCD9335_CPE_SS_INBOX2_12 0x0244 +#define WCD9335_CPE_SS_INBOX2_13 0x0245 +#define WCD9335_CPE_SS_INBOX2_14 0x0246 +#define WCD9335_CPE_SS_INBOX2_15 0x0247 +#define WCD9335_CPE_SS_OUTBOX2_0 0x0248 +#define WCD9335_CPE_SS_OUTBOX2_1 0x0249 +#define WCD9335_CPE_SS_OUTBOX2_2 0x024a +#define WCD9335_CPE_SS_OUTBOX2_3 0x024b +#define WCD9335_CPE_SS_OUTBOX2_4 0x024c +#define WCD9335_CPE_SS_OUTBOX2_5 0x024d +#define WCD9335_CPE_SS_OUTBOX2_6 0x024e +#define WCD9335_CPE_SS_OUTBOX2_7 0x024f +#define WCD9335_CPE_SS_OUTBOX2_8 0x0250 +#define WCD9335_CPE_SS_OUTBOX2_9 0x0251 +#define WCD9335_CPE_SS_OUTBOX2_10 0x0252 +#define WCD9335_CPE_SS_OUTBOX2_11 0x0253 +#define WCD9335_CPE_SS_OUTBOX2_12 0x0254 +#define WCD9335_CPE_SS_OUTBOX2_13 0x0255 +#define WCD9335_CPE_SS_OUTBOX2_14 0x0256 +#define WCD9335_CPE_SS_OUTBOX2_15 0x0257 +#define WCD9335_CPE_SS_OUTBOX1_ACK 0x0258 +#define WCD9335_CPE_SS_OUTBOX2_ACK 0x0259 +#define WCD9335_CPE_SS_EC_BUF_INT_PERIOD 0x025a +#define WCD9335_CPE_SS_US_BUF_INT_PERIOD 0x025b +#define WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD 0x025c +#define WCD9335_CPE_SS_CFG 0x025d +#define WCD9335_CPE_SS_US_EC_MUX_CFG 0x025e +#define WCD9335_CPE_SS_MAD_CTL 0x025f +#define WCD9335_CPE_SS_CPAR_CTL 0x0260 +#define WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD 0x0261 +#define WCD9335_CPE_SS_TX_PP_CFG 0x0262 +#define WCD9335_CPE_SS_DMIC0_CTL 0x0263 +#define WCD9335_CPE_SS_DMIC1_CTL 0x0264 +#define WCD9335_CPE_SS_DMIC2_CTL 0x0265 +#define WCD9335_CPE_SS_DMIC_CFG 0x0266 +#define WCD9335_CPE_SS_SVA_CFG 0x0267 +#define WCD9335_CPE_SS_CPAR_CFG 0x0271 +#define WCD9335_CPE_SS_WDOG_CFG 0x0272 +#define WCD9335_CPE_SS_BACKUP_INT 0x0273 +#define WCD9335_CPE_SS_STATUS 0x0274 +#define WCD9335_CPE_SS_CPE_OCD_CFG 0x0275 +#define WCD9335_CPE_SS_SS_ERROR_INT_MASK 0x0276 +#define WCD9335_CPE_SS_SS_ERROR_INT_STATUS 0x0277 +#define WCD9335_CPE_SS_SS_ERROR_INT_CLEAR 0x0278 +#define WCD9335_SOC_MAD_MAIN_CTL_1 0x0281 +#define WCD9335_SOC_MAD_MAIN_CTL_2 0x0282 +#define WCD9335_SOC_MAD_AUDIO_CTL_1 0x0283 +#define WCD9335_SOC_MAD_AUDIO_CTL_2 0x0284 +#define WCD9335_SOC_MAD_AUDIO_CTL_3 0x0285 +#define WCD9335_SOC_MAD_AUDIO_CTL_4 0x0286 +#define WCD9335_SOC_MAD_AUDIO_CTL_5 0x0287 +#define WCD9335_SOC_MAD_AUDIO_CTL_6 0x0288 +#define WCD9335_SOC_MAD_AUDIO_CTL_7 0x0289 +#define WCD9335_SOC_MAD_AUDIO_CTL_8 0x028a +#define WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR 0x028b +#define WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL 0x028c +#define WCD9335_SOC_MAD_ULTR_CTL_1 0x028d +#define WCD9335_SOC_MAD_ULTR_CTL_2 0x028e +#define WCD9335_SOC_MAD_ULTR_CTL_3 0x028f +#define WCD9335_SOC_MAD_ULTR_CTL_4 0x0290 +#define WCD9335_SOC_MAD_ULTR_CTL_5 0x0291 +#define WCD9335_SOC_MAD_ULTR_CTL_6 0x0292 +#define WCD9335_SOC_MAD_ULTR_CTL_7 0x0293 +#define WCD9335_SOC_MAD_BEACON_CTL_1 0x0294 +#define WCD9335_SOC_MAD_BEACON_CTL_2 0x0295 +#define WCD9335_SOC_MAD_BEACON_CTL_3 0x0296 +#define WCD9335_SOC_MAD_BEACON_CTL_4 0x0297 +#define WCD9335_SOC_MAD_BEACON_CTL_5 0x0298 +#define WCD9335_SOC_MAD_BEACON_CTL_6 0x0299 +#define WCD9335_SOC_MAD_BEACON_CTL_7 0x029a +#define WCD9335_SOC_MAD_BEACON_CTL_8 0x029b +#define WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR 0x029c +#define WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL 0x029d +#define WCD9335_SOC_MAD_INP_SEL 0x029e + +/* Page-6 Registers */ +#define WCD9335_PAGE6_PAGE_REGISTER 0x0600 +#define WCD9335_ANA_BIAS 0x0601 +#define WCD9335_ANA_CLK_TOP 0x0602 +#define WCD9335_ANA_RCO 0x0603 +#define WCD9335_ANA_BUCK_VOUT_A 0x0604 +#define WCD9335_ANA_BUCK_VOUT_D 0x0605 +#define WCD9335_ANA_BUCK_CTL 0x0606 +#define WCD9335_ANA_BUCK_STATUS 0x0607 +#define WCD9335_ANA_RX_SUPPLIES 0x0608 +#define WCD9335_ANA_HPH 0x0609 +#define WCD9335_ANA_EAR 0x060a +#define WCD9335_ANA_LO_1_2 0x060b +#define WCD9335_ANA_LO_3_4 0x060c +#define WCD9335_ANA_MAD_SETUP 0x060d +#define WCD9335_ANA_AMIC1 0x060e +#define WCD9335_ANA_AMIC2 0x060f +#define WCD9335_ANA_AMIC3 0x0610 +#define WCD9335_ANA_AMIC4 0x0611 +#define WCD9335_ANA_AMIC5 0x0612 +#define WCD9335_ANA_AMIC6 0x0613 +#define WCD9335_ANA_MBHC_MECH 0x0614 +#define WCD9335_ANA_MBHC_ELECT 0x0615 +#define WCD9335_ANA_MBHC_ZDET 0x0616 +#define WCD9335_ANA_MBHC_RESULT_1 0x0617 +#define WCD9335_ANA_MBHC_RESULT_2 0x0618 +#define WCD9335_ANA_MBHC_RESULT_3 0x0619 +#define WCD9335_ANA_MBHC_BTN0 0x061a +#define WCD9335_ANA_MBHC_BTN1 0x061b +#define WCD9335_ANA_MBHC_BTN2 0x061c +#define WCD9335_ANA_MBHC_BTN3 0x061d +#define WCD9335_ANA_MBHC_BTN4 0x061e +#define WCD9335_ANA_MBHC_BTN5 0x061f +#define WCD9335_ANA_MBHC_BTN6 0x0620 +#define WCD9335_ANA_MBHC_BTN7 0x0621 +#define WCD9335_ANA_MICB1 0x0622 +#define WCD9335_ANA_MICB2 0x0623 +#define WCD9335_ANA_MICB2_RAMP 0x0624 +#define WCD9335_ANA_MICB3 0x0625 +#define WCD9335_ANA_MICB4 0x0626 +#define WCD9335_ANA_VBADC 0x0627 +#define WCD9335_BIAS_CTL 0x0628 +#define WCD9335_BIAS_VBG_FINE_ADJ 0x0629 +#define WCD9335_CLOCK_TEST_CTL 0x062d +#define WCD9335_RCO_CTRL_1 0x062e +#define WCD9335_RCO_CTRL_2 0x062f +#define WCD9335_RCO_CAL 0x0630 +#define WCD9335_RCO_CAL_1 0x0631 +#define WCD9335_RCO_CAL_2 0x0632 +#define WCD9335_RCO_TEST_CTRL 0x0633 +#define WCD9335_RCO_CAL_OUT_1 0x0634 +#define WCD9335_RCO_CAL_OUT_2 0x0635 +#define WCD9335_RCO_CAL_OUT_3 0x0636 +#define WCD9335_RCO_CAL_OUT_4 0x0637 +#define WCD9335_RCO_CAL_OUT_5 0x0638 +#define WCD9335_SIDO_SIDO_MODE_1 0x063a +#define WCD9335_SIDO_SIDO_MODE_2 0x063b +#define WCD9335_SIDO_SIDO_MODE_3 0x063c +#define WCD9335_SIDO_SIDO_MODE_4 0x063d +#define WCD9335_SIDO_SIDO_VCL_1 0x063e +#define WCD9335_SIDO_SIDO_VCL_2 0x063f +#define WCD9335_SIDO_SIDO_VCL_3 0x0640 +#define WCD9335_SIDO_SIDO_CCL_1 0x0641 +#define WCD9335_SIDO_SIDO_CCL_2 0x0642 +#define WCD9335_SIDO_SIDO_CCL_3 0x0643 +#define WCD9335_SIDO_SIDO_CCL_4 0x0644 +#define WCD9335_SIDO_SIDO_CCL_5 0x0645 +#define WCD9335_SIDO_SIDO_CCL_6 0x0646 +#define WCD9335_SIDO_SIDO_CCL_7 0x0647 +#define WCD9335_SIDO_SIDO_CCL_8 0x0648 +#define WCD9335_SIDO_SIDO_CCL_9 0x0649 +#define WCD9335_SIDO_SIDO_CCL_10 0x064a +#define WCD9335_SIDO_SIDO_FILTER_1 0x064b +#define WCD9335_SIDO_SIDO_FILTER_2 0x064c +#define WCD9335_SIDO_SIDO_DRIVER_1 0x064d +#define WCD9335_SIDO_SIDO_DRIVER_2 0x064e +#define WCD9335_SIDO_SIDO_DRIVER_3 0x064f +#define WCD9335_SIDO_SIDO_CAL_CODE_EXT_1 0x0650 +#define WCD9335_SIDO_SIDO_CAL_CODE_EXT_2 0x0651 +#define WCD9335_SIDO_SIDO_CAL_CODE_OUT_1 0x0652 +#define WCD9335_SIDO_SIDO_CAL_CODE_OUT_2 0x0653 +#define WCD9335_SIDO_SIDO_TEST_1 0x0654 +#define WCD9335_SIDO_SIDO_TEST_2 0x0655 +#define WCD9335_MBHC_CTL_1 0x0656 +#define WCD9335_MBHC_CTL_2 0x0657 +#define WCD9335_MBHC_PLUG_DETECT_CTL 0x0658 +#define WCD9335_MBHC_ZDET_ANA_CTL 0x0659 +#define WCD9335_MBHC_ZDET_RAMP_CTL 0x065a +#define WCD9335_MBHC_FSM_DEBUG 0x065b /* v1.x */ +#define WCD9335_MBHC_FSM_STATUS 0x065b /* v2.0 */ +#define WCD9335_MBHC_TEST_CTL 0x065c +#define WCD9335_VBADC_SUBBLOCK_EN 0x065d +#define WCD9335_VBADC_IBIAS_FE 0x065e +#define WCD9335_VBADC_BIAS_ADC 0x065f +#define WCD9335_VBADC_FE_CTRL 0x0660 +#define WCD9335_VBADC_ADC_REF 0x0661 +#define WCD9335_VBADC_ADC_IO 0x0662 +#define WCD9335_VBADC_ADC_SAR 0x0663 +#define WCD9335_VBADC_DEBUG 0x0664 +#define WCD9335_VBADC_ADC_DOUTMSB 0x0665 +#define WCD9335_VBADC_ADC_DOUTLSB 0x0666 +#define WCD9335_LDOH_MODE 0x0667 +#define WCD9335_LDOH_BIAS 0x0668 +#define WCD9335_LDOH_STB_LOADS 0x0669 +#define WCD9335_LDOH_SLOWRAMP 0x066a +#define WCD9335_MICB1_TEST_CTL_1 0x066b +#define WCD9335_MICB1_TEST_CTL_2 0x066c +#define WCD9335_MICB1_TEST_CTL_3 0x066d +#define WCD9335_MICB2_TEST_CTL_1 0x066e +#define WCD9335_MICB2_TEST_CTL_2 0x066f +#define WCD9335_MICB2_TEST_CTL_3 0x0670 +#define WCD9335_MICB3_TEST_CTL_1 0x0671 +#define WCD9335_MICB3_TEST_CTL_2 0x0672 +#define WCD9335_MICB3_TEST_CTL_3 0x0673 +#define WCD9335_MICB4_TEST_CTL_1 0x0674 +#define WCD9335_MICB4_TEST_CTL_2 0x0675 +#define WCD9335_MICB4_TEST_CTL_3 0x0676 +#define WCD9335_TX_COM_ADC_VCM 0x0677 +#define WCD9335_TX_COM_BIAS_ATEST 0x0678 +#define WCD9335_TX_COM_ADC_INT1_IB 0x0679 +#define WCD9335_TX_COM_ADC_INT2_IB 0x067a +#define WCD9335_TX_COM_TXFE_DIV_CTL 0x067b +#define WCD9335_TX_COM_TXFE_DIV_START 0x067c +#define WCD9335_TX_COM_TXFE_DIV_STOP_9P6M 0x067d +#define WCD9335_TX_COM_TXFE_DIV_STOP_12P288M 0x067e +#define WCD9335_TX_1_2_TEST_EN 0x067f +#define WCD9335_TX_1_2_ADC_IB 0x0680 +#define WCD9335_TX_1_2_ATEST_REFCTL 0x0681 +#define WCD9335_TX_1_2_TEST_CTL 0x0682 +#define WCD9335_TX_1_2_TEST_BLK_EN 0x0683 +#define WCD9335_TX_1_2_TXFE_CLKDIV 0x0684 +#define WCD9335_TX_1_2_SAR1_ERR 0x0685 +#define WCD9335_TX_1_2_SAR2_ERR 0x0686 +#define WCD9335_TX_3_4_TEST_EN 0x0687 +#define WCD9335_TX_3_4_ADC_IB 0x0688 +#define WCD9335_TX_3_4_ATEST_REFCTL 0x0689 +#define WCD9335_TX_3_4_TEST_CTL 0x068a +#define WCD9335_TX_3_4_TEST_BLK_EN 0x068b +#define WCD9335_TX_3_4_TXFE_CLKDIV 0x068c +#define WCD9335_TX_3_4_SAR1_ERR 0x068d +#define WCD9335_TX_3_4_SAR2_ERR 0x068e +#define WCD9335_TX_5_6_TEST_EN 0x068f +#define WCD9335_TX_5_6_ADC_IB 0x0690 +#define WCD9335_TX_5_6_ATEST_REFCTL 0x0691 +#define WCD9335_TX_5_6_TEST_CTL 0x0692 +#define WCD9335_TX_5_6_TEST_BLK_EN 0x0693 +#define WCD9335_TX_5_6_TXFE_CLKDIV 0x0694 +#define WCD9335_TX_5_6_SAR1_ERR 0x0695 +#define WCD9335_TX_5_6_SAR2_ERR 0x0696 +#define WCD9335_CLASSH_MODE_1 0x0697 +#define WCD9335_CLASSH_MODE_2 0x0698 +#define WCD9335_CLASSH_MODE_3 0x0699 +#define WCD9335_CLASSH_CTRL_VCL_1 0x069a +#define WCD9335_CLASSH_CTRL_VCL_2 0x069b +#define WCD9335_CLASSH_CTRL_CCL_1 0x069c +#define WCD9335_CLASSH_CTRL_CCL_2 0x069d +#define WCD9335_CLASSH_CTRL_CCL_3 0x069e +#define WCD9335_CLASSH_CTRL_CCL_4 0x069f +#define WCD9335_CLASSH_CTRL_CCL_5 0x06a0 +#define WCD9335_CLASSH_BUCK_TMUX_A_D 0x06a1 +#define WCD9335_CLASSH_BUCK_SW_DRV_CNTL 0x06a2 +#define WCD9335_CLASSH_SPARE 0x06a3 +#define WCD9335_FLYBACK_EN 0x06a4 +#define WCD9335_FLYBACK_VNEG_CTRL_1 0x06a5 +#define WCD9335_FLYBACK_VNEG_CTRL_2 0x06a6 +#define WCD9335_FLYBACK_VNEG_CTRL_3 0x06a7 +#define WCD9335_FLYBACK_VNEG_CTRL_4 0x06a8 +#define WCD9335_FLYBACK_VNEG_CTRL_5 0x06a9 +#define WCD9335_FLYBACK_VNEG_CTRL_6 0x06aa +#define WCD9335_FLYBACK_VNEG_CTRL_7 0x06ab +#define WCD9335_FLYBACK_VNEG_CTRL_8 0x06ac +#define WCD9335_FLYBACK_VNEG_CTRL_9 0x06ad +#define WCD9335_FLYBACK_VNEG_DAC_CTRL_1 0x06ae +#define WCD9335_FLYBACK_VNEG_DAC_CTRL_2 0x06af +#define WCD9335_FLYBACK_VNEG_DAC_CTRL_3 0x06b0 +#define WCD9335_FLYBACK_VNEG_DAC_CTRL_4 0x06b1 /* v1.x */ +#define WCD9335_FLYBACK_CTRL_1 0x06b1 /* v2.0 */ +#define WCD9335_FLYBACK_TEST_CTL 0x06b2 +#define WCD9335_RX_AUX_SW_CTL 0x06b3 +#define WCD9335_RX_PA_AUX_IN_CONN 0x06b4 +#define WCD9335_RX_TIMER_DIV 0x06b5 +#define WCD9335_RX_OCP_CTL 0x06b6 +#define WCD9335_RX_OCP_COUNT 0x06b7 +#define WCD9335_RX_BIAS_EAR_DAC 0x06b8 +#define WCD9335_RX_BIAS_EAR_AMP 0x06b9 +#define WCD9335_RX_BIAS_HPH_LDO 0x06ba +#define WCD9335_RX_BIAS_HPH_PA 0x06bb +#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2 0x06bc +#define WCD9335_RX_BIAS_HPH_RDAC_LDO 0x06bd +#define WCD9335_RX_BIAS_HPH_CNP1 0x06be +#define WCD9335_RX_BIAS_HPH_LOWPOWER 0x06bf +#define WCD9335_RX_BIAS_DIFFLO_PA 0x06c0 +#define WCD9335_RX_BIAS_DIFFLO_REF 0x06c1 +#define WCD9335_RX_BIAS_DIFFLO_LDO 0x06c2 +#define WCD9335_RX_BIAS_SELO_DAC_PA 0x06c3 +#define WCD9335_RX_BIAS_BUCK_RST 0x06c4 +#define WCD9335_RX_BIAS_BUCK_VREF_ERRAMP 0x06c5 +#define WCD9335_RX_BIAS_FLYB_ERRAMP 0x06c6 +#define WCD9335_RX_BIAS_FLYB_BUFF 0x06c7 +#define WCD9335_RX_BIAS_FLYB_MID_RST 0x06c8 +#define WCD9335_HPH_L_STATUS 0x06c9 +#define WCD9335_HPH_R_STATUS 0x06ca +#define WCD9335_HPH_CNP_EN 0x06cb +#define WCD9335_HPH_CNP_WG_CTL 0x06cc +#define WCD9335_HPH_CNP_WG_TIME 0x06cd +#define WCD9335_HPH_OCP_CTL 0x06ce +#define WCD9335_HPH_AUTO_CHOP 0x06cf +#define WCD9335_HPH_CHOP_CTL 0x06d0 +#define WCD9335_HPH_PA_CTL1 0x06d1 +#define WCD9335_HPH_PA_CTL2 0x06d2 +#define WCD9335_HPH_L_EN 0x06d3 +#define WCD9335_HPH_L_TEST 0x06d4 +#define WCD9335_HPH_L_ATEST 0x06d5 +#define WCD9335_HPH_R_EN 0x06d6 +#define WCD9335_HPH_R_TEST 0x06d7 +#define WCD9335_HPH_R_ATEST 0x06d8 +#define WCD9335_HPH_RDAC_CLK_CTL1 0x06d9 +#define WCD9335_HPH_RDAC_CLK_CTL2 0x06da +#define WCD9335_HPH_RDAC_LDO_CTL 0x06db +#define WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL 0x06dc +#define WCD9335_HPH_REFBUFF_UHQA_CTL 0x06dd +#define WCD9335_HPH_REFBUFF_LP_CTL 0x06de +#define WCD9335_HPH_L_DAC_CTL 0x06df +#define WCD9335_HPH_R_DAC_CTL 0x06e0 +#define WCD9335_EAR_EN_REG 0x06e1 +#define WCD9335_EAR_CMBUFF 0x06e2 +#define WCD9335_EAR_ICTL 0x06e3 +#define WCD9335_EAR_EN_DBG_CTL 0x06e4 +#define WCD9335_EAR_CNP 0x06e5 +#define WCD9335_EAR_DAC_CTL_ATEST 0x06e6 +#define WCD9335_EAR_STATUS_REG 0x06e7 +#define WCD9335_EAR_OUT_SHORT 0x06e8 +#define WCD9335_DIFF_LO_MISC 0x06e9 +#define WCD9335_DIFF_LO_LO2_COMPANDER 0x06ea +#define WCD9335_DIFF_LO_LO1_COMPANDER 0x06eb +#define WCD9335_DIFF_LO_COMMON 0x06ec +#define WCD9335_DIFF_LO_BYPASS_EN 0x06ed +#define WCD9335_DIFF_LO_CNP 0x06ee +#define WCD9335_DIFF_LO_CORE_OUT_PROG 0x06ef +#define WCD9335_DIFF_LO_LDO_OUT_PROG 0x06f0 +#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ 0x06f1 +#define WCD9335_DIFF_LO_COM_PA_FREQ 0x06f2 +#define WCD9335_DIFF_LO_RESERVED_REG 0x06f3 +#define WCD9335_DIFF_LO_LO1_STATUS_1 0x06f4 +#define WCD9335_DIFF_LO_LO1_STATUS_2 0x06f5 +#define WCD9335_SE_LO_COM1 0x06f6 +#define WCD9335_SE_LO_COM2 0x06f7 +#define WCD9335_SE_LO_LO3_GAIN 0x06f8 +#define WCD9335_SE_LO_LO3_CTRL 0x06f9 +#define WCD9335_SE_LO_LO4_GAIN 0x06fa +#define WCD9335_SE_LO_LO4_CTRL 0x06fb +#define WCD9335_SE_LO_LO3_STATUS 0x06fe +#define WCD9335_SE_LO_LO4_STATUS 0x06ff + +/* Page-10 Registers */ +#define WCD9335_PAGE10_PAGE_REGISTER 0x0a00 +#define WCD9335_CDC_ANC0_CLK_RESET_CTL 0x0a01 +#define WCD9335_CDC_ANC0_MODE_1_CTL 0x0a02 +#define WCD9335_CDC_ANC0_MODE_2_CTL 0x0a03 +#define WCD9335_CDC_ANC0_FF_SHIFT 0x0a04 +#define WCD9335_CDC_ANC0_FB_SHIFT 0x0a05 +#define WCD9335_CDC_ANC0_LPF_FF_A_CTL 0x0a06 +#define WCD9335_CDC_ANC0_LPF_FF_B_CTL 0x0a07 +#define WCD9335_CDC_ANC0_LPF_FB_CTL 0x0a08 +#define WCD9335_CDC_ANC0_SMLPF_CTL 0x0a09 +#define WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL 0x0a0a +#define WCD9335_CDC_ANC0_IIR_ADAPT_CTL 0x0a0b +#define WCD9335_CDC_ANC0_IIR_COEFF_1_CTL 0x0a0c +#define WCD9335_CDC_ANC0_IIR_COEFF_2_CTL 0x0a0d +#define WCD9335_CDC_ANC0_FF_A_GAIN_CTL 0x0a0e +#define WCD9335_CDC_ANC0_FF_B_GAIN_CTL 0x0a0f +#define WCD9335_CDC_ANC0_FB_GAIN_CTL 0x0a10 +#define WCD9335_CDC_ANC1_CLK_RESET_CTL 0x0a19 +#define WCD9335_CDC_ANC1_MODE_1_CTL 0x0a1a +#define WCD9335_CDC_ANC1_MODE_2_CTL 0x0a1b +#define WCD9335_CDC_ANC1_FF_SHIFT 0x0a1c +#define WCD9335_CDC_ANC1_FB_SHIFT 0x0a1d +#define WCD9335_CDC_ANC1_LPF_FF_A_CTL 0x0a1e +#define WCD9335_CDC_ANC1_LPF_FF_B_CTL 0x0a1f +#define WCD9335_CDC_ANC1_LPF_FB_CTL 0x0a20 +#define WCD9335_CDC_ANC1_SMLPF_CTL 0x0a21 +#define WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL 0x0a22 +#define WCD9335_CDC_ANC1_IIR_ADAPT_CTL 0x0a23 +#define WCD9335_CDC_ANC1_IIR_COEFF_1_CTL 0x0a24 +#define WCD9335_CDC_ANC1_IIR_COEFF_2_CTL 0x0a25 +#define WCD9335_CDC_ANC1_FF_A_GAIN_CTL 0x0a26 +#define WCD9335_CDC_ANC1_FF_B_GAIN_CTL 0x0a27 +#define WCD9335_CDC_ANC1_FB_GAIN_CTL 0x0a28 +#define WCD9335_CDC_TX0_TX_PATH_CTL 0x0a31 +#define WCD9335_CDC_TX0_TX_PATH_CFG0 0x0a32 +#define WCD9335_CDC_TX0_TX_PATH_CFG1 0x0a33 +#define WCD9335_CDC_TX0_TX_VOL_CTL 0x0a34 +#define WCD9335_CDC_TX0_TX_PATH_192_CTL 0x0a35 +#define WCD9335_CDC_TX0_TX_PATH_192_CFG 0x0a36 +#define WCD9335_CDC_TX0_TX_PATH_SEC0 0x0a37 +#define WCD9335_CDC_TX0_TX_PATH_SEC1 0x0a38 +#define WCD9335_CDC_TX0_TX_PATH_SEC2 0x0a39 +#define WCD9335_CDC_TX0_TX_PATH_SEC3 0x0a3a +#define WCD9335_CDC_TX0_TX_PATH_SEC4 0x0a3b +#define WCD9335_CDC_TX0_TX_PATH_SEC5 0x0a3c +#define WCD9335_CDC_TX0_TX_PATH_SEC6 0x0a3d +#define WCD9335_CDC_TX0_TX_PATH_SEC7 0x0a3e +#define WCD9335_CDC_TX1_TX_PATH_CTL 0x0a41 +#define WCD9335_CDC_TX1_TX_PATH_CFG0 0x0a42 +#define WCD9335_CDC_TX1_TX_PATH_CFG1 0x0a43 +#define WCD9335_CDC_TX1_TX_VOL_CTL 0x0a44 +#define WCD9335_CDC_TX1_TX_PATH_192_CTL 0x0a45 +#define WCD9335_CDC_TX1_TX_PATH_192_CFG 0x0a46 +#define WCD9335_CDC_TX1_TX_PATH_SEC0 0x0a47 +#define WCD9335_CDC_TX1_TX_PATH_SEC1 0x0a48 +#define WCD9335_CDC_TX1_TX_PATH_SEC2 0x0a49 +#define WCD9335_CDC_TX1_TX_PATH_SEC3 0x0a4a +#define WCD9335_CDC_TX1_TX_PATH_SEC4 0x0a4b +#define WCD9335_CDC_TX1_TX_PATH_SEC5 0x0a4c +#define WCD9335_CDC_TX1_TX_PATH_SEC6 0x0a4d +#define WCD9335_CDC_TX2_TX_PATH_CTL 0x0a51 +#define WCD9335_CDC_TX2_TX_PATH_CFG0 0x0a52 +#define WCD9335_CDC_TX2_TX_PATH_CFG1 0x0a53 +#define WCD9335_CDC_TX2_TX_VOL_CTL 0x0a54 +#define WCD9335_CDC_TX2_TX_PATH_192_CTL 0x0a55 +#define WCD9335_CDC_TX2_TX_PATH_192_CFG 0x0a56 +#define WCD9335_CDC_TX2_TX_PATH_SEC0 0x0a57 +#define WCD9335_CDC_TX2_TX_PATH_SEC1 0x0a58 +#define WCD9335_CDC_TX2_TX_PATH_SEC2 0x0a59 +#define WCD9335_CDC_TX2_TX_PATH_SEC3 0x0a5a +#define WCD9335_CDC_TX2_TX_PATH_SEC4 0x0a5b +#define WCD9335_CDC_TX2_TX_PATH_SEC5 0x0a5c +#define WCD9335_CDC_TX2_TX_PATH_SEC6 0x0a5d +#define WCD9335_CDC_TX3_TX_PATH_CTL 0x0a61 +#define WCD9335_CDC_TX3_TX_PATH_CFG0 0x0a62 +#define WCD9335_CDC_TX3_TX_PATH_CFG1 0x0a63 +#define WCD9335_CDC_TX3_TX_VOL_CTL 0x0a64 +#define WCD9335_CDC_TX3_TX_PATH_192_CTL 0x0a65 +#define WCD9335_CDC_TX3_TX_PATH_192_CFG 0x0a66 +#define WCD9335_CDC_TX3_TX_PATH_SEC0 0x0a67 +#define WCD9335_CDC_TX3_TX_PATH_SEC1 0x0a68 +#define WCD9335_CDC_TX3_TX_PATH_SEC2 0x0a69 +#define WCD9335_CDC_TX3_TX_PATH_SEC3 0x0a6a +#define WCD9335_CDC_TX3_TX_PATH_SEC4 0x0a6b +#define WCD9335_CDC_TX3_TX_PATH_SEC5 0x0a6c +#define WCD9335_CDC_TX3_TX_PATH_SEC6 0x0a6d +#define WCD9335_CDC_TX4_TX_PATH_CTL 0x0a71 +#define WCD9335_CDC_TX4_TX_PATH_CFG0 0x0a72 +#define WCD9335_CDC_TX4_TX_PATH_CFG1 0x0a73 +#define WCD9335_CDC_TX4_TX_VOL_CTL 0x0a74 +#define WCD9335_CDC_TX4_TX_PATH_192_CTL 0x0a75 +#define WCD9335_CDC_TX4_TX_PATH_192_CFG 0x0a76 +#define WCD9335_CDC_TX4_TX_PATH_SEC0 0x0a77 +#define WCD9335_CDC_TX4_TX_PATH_SEC1 0x0a78 +#define WCD9335_CDC_TX4_TX_PATH_SEC2 0x0a79 +#define WCD9335_CDC_TX4_TX_PATH_SEC3 0x0a7a +#define WCD9335_CDC_TX4_TX_PATH_SEC4 0x0a7b +#define WCD9335_CDC_TX4_TX_PATH_SEC5 0x0a7c +#define WCD9335_CDC_TX4_TX_PATH_SEC6 0x0a7d +#define WCD9335_CDC_TX5_TX_PATH_CTL 0x0a81 +#define WCD9335_CDC_TX5_TX_PATH_CFG0 0x0a82 +#define WCD9335_CDC_TX5_TX_PATH_CFG1 0x0a83 +#define WCD9335_CDC_TX5_TX_VOL_CTL 0x0a84 +#define WCD9335_CDC_TX5_TX_PATH_192_CTL 0x0a85 +#define WCD9335_CDC_TX5_TX_PATH_192_CFG 0x0a86 +#define WCD9335_CDC_TX5_TX_PATH_SEC0 0x0a87 +#define WCD9335_CDC_TX5_TX_PATH_SEC1 0x0a88 +#define WCD9335_CDC_TX5_TX_PATH_SEC2 0x0a89 +#define WCD9335_CDC_TX5_TX_PATH_SEC3 0x0a8a +#define WCD9335_CDC_TX5_TX_PATH_SEC4 0x0a8b +#define WCD9335_CDC_TX5_TX_PATH_SEC5 0x0a8c +#define WCD9335_CDC_TX5_TX_PATH_SEC6 0x0a8d +#define WCD9335_CDC_TX6_TX_PATH_CTL 0x0a91 +#define WCD9335_CDC_TX6_TX_PATH_CFG0 0x0a92 +#define WCD9335_CDC_TX6_TX_PATH_CFG1 0x0a93 +#define WCD9335_CDC_TX6_TX_VOL_CTL 0x0a94 +#define WCD9335_CDC_TX6_TX_PATH_192_CTL 0x0a95 +#define WCD9335_CDC_TX6_TX_PATH_192_CFG 0x0a96 +#define WCD9335_CDC_TX6_TX_PATH_SEC0 0x0a97 +#define WCD9335_CDC_TX6_TX_PATH_SEC1 0x0a98 +#define WCD9335_CDC_TX6_TX_PATH_SEC2 0x0a99 +#define WCD9335_CDC_TX6_TX_PATH_SEC3 0x0a9a +#define WCD9335_CDC_TX6_TX_PATH_SEC4 0x0a9b +#define WCD9335_CDC_TX6_TX_PATH_SEC5 0x0a9c +#define WCD9335_CDC_TX6_TX_PATH_SEC6 0x0a9d +#define WCD9335_CDC_TX7_TX_PATH_CTL 0x0aa1 +#define WCD9335_CDC_TX7_TX_PATH_CFG0 0x0aa2 +#define WCD9335_CDC_TX7_TX_PATH_CFG1 0x0aa3 +#define WCD9335_CDC_TX7_TX_VOL_CTL 0x0aa4 +#define WCD9335_CDC_TX7_TX_PATH_192_CTL 0x0aa5 +#define WCD9335_CDC_TX7_TX_PATH_192_CFG 0x0aa6 +#define WCD9335_CDC_TX7_TX_PATH_SEC0 0x0aa7 +#define WCD9335_CDC_TX7_TX_PATH_SEC1 0x0aa8 +#define WCD9335_CDC_TX7_TX_PATH_SEC2 0x0aa9 +#define WCD9335_CDC_TX7_TX_PATH_SEC3 0x0aaa +#define WCD9335_CDC_TX7_TX_PATH_SEC4 0x0aab +#define WCD9335_CDC_TX7_TX_PATH_SEC5 0x0aac +#define WCD9335_CDC_TX7_TX_PATH_SEC6 0x0aad +#define WCD9335_CDC_TX8_TX_PATH_CTL 0x0ab1 +#define WCD9335_CDC_TX8_TX_PATH_CFG0 0x0ab2 +#define WCD9335_CDC_TX8_TX_PATH_CFG1 0x0ab3 +#define WCD9335_CDC_TX8_TX_VOL_CTL 0x0ab4 +#define WCD9335_CDC_TX8_TX_PATH_192_CTL 0x0ab5 +#define WCD9335_CDC_TX8_TX_PATH_192_CFG 0x0ab6 +#define WCD9335_CDC_TX8_TX_PATH_SEC0 0x0ab7 +#define WCD9335_CDC_TX8_TX_PATH_SEC1 0x0ab8 +#define WCD9335_CDC_TX8_TX_PATH_SEC2 0x0ab9 +#define WCD9335_CDC_TX8_TX_PATH_SEC3 0x0aba +#define WCD9335_CDC_TX8_TX_PATH_SEC4 0x0abb +#define WCD9335_CDC_TX8_TX_PATH_SEC5 0x0abc +#define WCD9335_CDC_TX8_TX_PATH_SEC6 0x0abd +#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL 0x0ac2 +#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0 0x0ac3 +#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL 0x0ac6 +#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0 0x0ac7 +#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL 0x0aca +#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0 0x0acb +#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL 0x0ace +#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0 0x0acf + +/* Page-11 Registers */ +#define WCD9335_PAGE11_PAGE_REGISTER 0x0b00 +#define WCD9335_CDC_COMPANDER1_CTL0 0x0b01 +#define WCD9335_CDC_COMPANDER1_CTL1 0x0b02 +#define WCD9335_CDC_COMPANDER1_CTL2 0x0b03 +#define WCD9335_CDC_COMPANDER1_CTL3 0x0b04 +#define WCD9335_CDC_COMPANDER1_CTL4 0x0b05 +#define WCD9335_CDC_COMPANDER1_CTL5 0x0b06 +#define WCD9335_CDC_COMPANDER1_CTL6 0x0b07 +#define WCD9335_CDC_COMPANDER1_CTL7 0x0b08 +#define WCD9335_CDC_COMPANDER2_CTL0 0x0b09 +#define WCD9335_CDC_COMPANDER2_CTL1 0x0b0a +#define WCD9335_CDC_COMPANDER2_CTL2 0x0b0b +#define WCD9335_CDC_COMPANDER2_CTL3 0x0b0c +#define WCD9335_CDC_COMPANDER2_CTL4 0x0b0d +#define WCD9335_CDC_COMPANDER2_CTL5 0x0b0e +#define WCD9335_CDC_COMPANDER2_CTL6 0x0b0f +#define WCD9335_CDC_COMPANDER2_CTL7 0x0b10 +#define WCD9335_CDC_COMPANDER3_CTL0 0x0b11 +#define WCD9335_CDC_COMPANDER3_CTL1 0x0b12 +#define WCD9335_CDC_COMPANDER3_CTL2 0x0b13 +#define WCD9335_CDC_COMPANDER3_CTL3 0x0b14 +#define WCD9335_CDC_COMPANDER3_CTL4 0x0b15 +#define WCD9335_CDC_COMPANDER3_CTL5 0x0b16 +#define WCD9335_CDC_COMPANDER3_CTL6 0x0b17 +#define WCD9335_CDC_COMPANDER3_CTL7 0x0b18 +#define WCD9335_CDC_COMPANDER4_CTL0 0x0b19 +#define WCD9335_CDC_COMPANDER4_CTL1 0x0b1a +#define WCD9335_CDC_COMPANDER4_CTL2 0x0b1b +#define WCD9335_CDC_COMPANDER4_CTL3 0x0b1c +#define WCD9335_CDC_COMPANDER4_CTL4 0x0b1d +#define WCD9335_CDC_COMPANDER4_CTL5 0x0b1e +#define WCD9335_CDC_COMPANDER4_CTL6 0x0b1f +#define WCD9335_CDC_COMPANDER4_CTL7 0x0b20 +#define WCD9335_CDC_COMPANDER5_CTL0 0x0b21 +#define WCD9335_CDC_COMPANDER5_CTL1 0x0b22 +#define WCD9335_CDC_COMPANDER5_CTL2 0x0b23 +#define WCD9335_CDC_COMPANDER5_CTL3 0x0b24 +#define WCD9335_CDC_COMPANDER5_CTL4 0x0b25 +#define WCD9335_CDC_COMPANDER5_CTL5 0x0b26 +#define WCD9335_CDC_COMPANDER5_CTL6 0x0b27 +#define WCD9335_CDC_COMPANDER5_CTL7 0x0b28 +#define WCD9335_CDC_COMPANDER6_CTL0 0x0b29 +#define WCD9335_CDC_COMPANDER6_CTL1 0x0b2a +#define WCD9335_CDC_COMPANDER6_CTL2 0x0b2b +#define WCD9335_CDC_COMPANDER6_CTL3 0x0b2c +#define WCD9335_CDC_COMPANDER6_CTL4 0x0b2d +#define WCD9335_CDC_COMPANDER6_CTL5 0x0b2e +#define WCD9335_CDC_COMPANDER6_CTL6 0x0b2f +#define WCD9335_CDC_COMPANDER6_CTL7 0x0b30 +#define WCD9335_CDC_COMPANDER7_CTL0 0x0b31 +#define WCD9335_CDC_COMPANDER7_CTL1 0x0b32 +#define WCD9335_CDC_COMPANDER7_CTL2 0x0b33 +#define WCD9335_CDC_COMPANDER7_CTL3 0x0b34 +#define WCD9335_CDC_COMPANDER7_CTL4 0x0b35 +#define WCD9335_CDC_COMPANDER7_CTL5 0x0b36 +#define WCD9335_CDC_COMPANDER7_CTL6 0x0b37 +#define WCD9335_CDC_COMPANDER7_CTL7 0x0b38 +#define WCD9335_CDC_COMPANDER8_CTL0 0x0b39 +#define WCD9335_CDC_COMPANDER8_CTL1 0x0b3a +#define WCD9335_CDC_COMPANDER8_CTL2 0x0b3b +#define WCD9335_CDC_COMPANDER8_CTL3 0x0b3c +#define WCD9335_CDC_COMPANDER8_CTL4 0x0b3d +#define WCD9335_CDC_COMPANDER8_CTL5 0x0b3e +#define WCD9335_CDC_COMPANDER8_CTL6 0x0b3f +#define WCD9335_CDC_COMPANDER8_CTL7 0x0b40 +#define WCD9335_CDC_RX0_RX_PATH_CTL 0x0b41 +#define WCD9335_CDC_RX0_RX_PATH_CFG0 0x0b42 +#define WCD9335_CDC_RX0_RX_PATH_CFG1 0x0b43 +#define WCD9335_CDC_RX0_RX_PATH_CFG2 0x0b44 +#define WCD9335_CDC_RX0_RX_VOL_CTL 0x0b45 +#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL 0x0b46 +#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG 0x0b47 +#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL 0x0b48 +#define WCD9335_CDC_RX0_RX_PATH_SEC0 0x0b49 +#define WCD9335_CDC_RX0_RX_PATH_SEC1 0x0b4a +#define WCD9335_CDC_RX0_RX_PATH_SEC2 0x0b4b +#define WCD9335_CDC_RX0_RX_PATH_SEC3 0x0b4c +#define WCD9335_CDC_RX0_RX_PATH_SEC5 0x0b4e +#define WCD9335_CDC_RX0_RX_PATH_SEC6 0x0b4f +#define WCD9335_CDC_RX0_RX_PATH_SEC7 0x0b50 +#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0 0x0b51 +#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC1 0x0b52 +#define WCD9335_CDC_RX1_RX_PATH_CTL 0x0b55 +#define WCD9335_CDC_RX1_RX_PATH_CFG0 0x0b56 +#define WCD9335_CDC_RX1_RX_PATH_CFG1 0x0b57 +#define WCD9335_CDC_RX1_RX_PATH_CFG2 0x0b58 +#define WCD9335_CDC_RX1_RX_VOL_CTL 0x0b59 +#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL 0x0b5a +#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG 0x0b5b +#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL 0x0b5c +#define WCD9335_CDC_RX1_RX_PATH_SEC0 0x0b5d +#define WCD9335_CDC_RX1_RX_PATH_SEC1 0x0b5e +#define WCD9335_CDC_RX1_RX_PATH_SEC2 0x0b5f +#define WCD9335_CDC_RX1_RX_PATH_SEC3 0x0b60 +#define WCD9335_CDC_RX1_RX_PATH_SEC4 0x0b61 +#define WCD9335_CDC_RX1_RX_PATH_SEC5 0x0b62 +#define WCD9335_CDC_RX1_RX_PATH_SEC6 0x0b63 +#define WCD9335_CDC_RX1_RX_PATH_SEC7 0x0b64 +#define WCD9335_CDC_RX1_RX_PATH_MIX_SEC0 0x0b65 +#define WCD9335_CDC_RX1_RX_PATH_MIX_SEC1 0x0b66 +#define WCD9335_CDC_RX2_RX_PATH_CTL 0x0b69 +#define WCD9335_CDC_RX2_RX_PATH_CFG0 0x0b6a +#define WCD9335_CDC_RX2_RX_PATH_CFG1 0x0b6b +#define WCD9335_CDC_RX2_RX_PATH_CFG2 0x0b6c +#define WCD9335_CDC_RX2_RX_VOL_CTL 0x0b6d +#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL 0x0b6e +#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG 0x0b6f +#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL 0x0b70 +#define WCD9335_CDC_RX2_RX_PATH_SEC0 0x0b71 +#define WCD9335_CDC_RX2_RX_PATH_SEC1 0x0b72 +#define WCD9335_CDC_RX2_RX_PATH_SEC2 0x0b73 +#define WCD9335_CDC_RX2_RX_PATH_SEC3 0x0b74 +#define WCD9335_CDC_RX2_RX_PATH_SEC4 0x0b75 +#define WCD9335_CDC_RX2_RX_PATH_SEC5 0x0b76 +#define WCD9335_CDC_RX2_RX_PATH_SEC6 0x0b77 +#define WCD9335_CDC_RX2_RX_PATH_SEC7 0x0b78 +#define WCD9335_CDC_RX2_RX_PATH_MIX_SEC0 0x0b79 +#define WCD9335_CDC_RX2_RX_PATH_MIX_SEC1 0x0b7a +#define WCD9335_CDC_RX3_RX_PATH_CTL 0x0b7d +#define WCD9335_CDC_RX3_RX_PATH_CFG0 0x0b7e +#define WCD9335_CDC_RX3_RX_PATH_CFG1 0x0b7f +#define WCD9335_CDC_RX3_RX_PATH_CFG2 0x0b80 +#define WCD9335_CDC_RX3_RX_VOL_CTL 0x0b81 +#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL 0x0b82 +#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG 0x0b83 +#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL 0x0b84 +#define WCD9335_CDC_RX3_RX_PATH_SEC0 0x0b85 +#define WCD9335_CDC_RX3_RX_PATH_SEC1 0x0b86 +#define WCD9335_CDC_RX3_RX_PATH_SEC2 0x0b87 +#define WCD9335_CDC_RX3_RX_PATH_SEC3 0x0b88 +#define WCD9335_CDC_RX3_RX_PATH_SEC5 0x0b8a +#define WCD9335_CDC_RX3_RX_PATH_SEC6 0x0b8b +#define WCD9335_CDC_RX3_RX_PATH_SEC7 0x0b8c +#define WCD9335_CDC_RX3_RX_PATH_MIX_SEC0 0x0b8d +#define WCD9335_CDC_RX3_RX_PATH_MIX_SEC1 0x0b8e +#define WCD9335_CDC_RX4_RX_PATH_CTL 0x0b91 +#define WCD9335_CDC_RX4_RX_PATH_CFG0 0x0b92 +#define WCD9335_CDC_RX4_RX_PATH_CFG1 0x0b93 +#define WCD9335_CDC_RX4_RX_PATH_CFG2 0x0b94 +#define WCD9335_CDC_RX4_RX_VOL_CTL 0x0b95 +#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL 0x0b96 +#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG 0x0b97 +#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL 0x0b98 +#define WCD9335_CDC_RX4_RX_PATH_SEC0 0x0b99 +#define WCD9335_CDC_RX4_RX_PATH_SEC1 0x0b9a +#define WCD9335_CDC_RX4_RX_PATH_SEC2 0x0b9b +#define WCD9335_CDC_RX4_RX_PATH_SEC3 0x0b9c +#define WCD9335_CDC_RX4_RX_PATH_SEC5 0x0b9e +#define WCD9335_CDC_RX4_RX_PATH_SEC6 0x0b9f +#define WCD9335_CDC_RX4_RX_PATH_SEC7 0x0ba0 +#define WCD9335_CDC_RX4_RX_PATH_MIX_SEC0 0x0ba1 +#define WCD9335_CDC_RX4_RX_PATH_MIX_SEC1 0x0ba2 +#define WCD9335_CDC_RX5_RX_PATH_CTL 0x0ba5 +#define WCD9335_CDC_RX5_RX_PATH_CFG0 0x0ba6 +#define WCD9335_CDC_RX5_RX_PATH_CFG1 0x0ba7 +#define WCD9335_CDC_RX5_RX_PATH_CFG2 0x0ba8 +#define WCD9335_CDC_RX5_RX_VOL_CTL 0x0ba9 +#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL 0x0baa +#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG 0x0bab +#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL 0x0bac +#define WCD9335_CDC_RX5_RX_PATH_SEC0 0x0bad +#define WCD9335_CDC_RX5_RX_PATH_SEC1 0x0bae +#define WCD9335_CDC_RX5_RX_PATH_SEC2 0x0baf +#define WCD9335_CDC_RX5_RX_PATH_SEC3 0x0bb0 +#define WCD9335_CDC_RX5_RX_PATH_SEC5 0x0bb2 +#define WCD9335_CDC_RX5_RX_PATH_SEC6 0x0bb3 +#define WCD9335_CDC_RX5_RX_PATH_SEC7 0x0bb4 +#define WCD9335_CDC_RX5_RX_PATH_MIX_SEC0 0x0bb5 +#define WCD9335_CDC_RX5_RX_PATH_MIX_SEC1 0x0bb6 +#define WCD9335_CDC_RX6_RX_PATH_CTL 0x0bb9 +#define WCD9335_CDC_RX6_RX_PATH_CFG0 0x0bba +#define WCD9335_CDC_RX6_RX_PATH_CFG1 0x0bbb +#define WCD9335_CDC_RX6_RX_PATH_CFG2 0x0bbc +#define WCD9335_CDC_RX6_RX_VOL_CTL 0x0bbd +#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL 0x0bbe +#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG 0x0bbf +#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL 0x0bc0 +#define WCD9335_CDC_RX6_RX_PATH_SEC0 0x0bc1 +#define WCD9335_CDC_RX6_RX_PATH_SEC1 0x0bc2 +#define WCD9335_CDC_RX6_RX_PATH_SEC2 0x0bc3 +#define WCD9335_CDC_RX6_RX_PATH_SEC3 0x0bc4 +#define WCD9335_CDC_RX6_RX_PATH_SEC5 0x0bc6 +#define WCD9335_CDC_RX6_RX_PATH_SEC6 0x0bc7 +#define WCD9335_CDC_RX6_RX_PATH_SEC7 0x0bc8 +#define WCD9335_CDC_RX6_RX_PATH_MIX_SEC0 0x0bc9 +#define WCD9335_CDC_RX6_RX_PATH_MIX_SEC1 0x0bca +#define WCD9335_CDC_RX7_RX_PATH_CTL 0x0bcd +#define WCD9335_CDC_RX7_RX_PATH_CFG0 0x0bce +#define WCD9335_CDC_RX7_RX_PATH_CFG1 0x0bcf +#define WCD9335_CDC_RX7_RX_PATH_CFG2 0x0bd0 +#define WCD9335_CDC_RX7_RX_VOL_CTL 0x0bd1 +#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL 0x0bd2 +#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG 0x0bd3 +#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL 0x0bd4 +#define WCD9335_CDC_RX7_RX_PATH_SEC0 0x0bd5 +#define WCD9335_CDC_RX7_RX_PATH_SEC1 0x0bd6 +#define WCD9335_CDC_RX7_RX_PATH_SEC2 0x0bd7 +#define WCD9335_CDC_RX7_RX_PATH_SEC3 0x0bd8 +#define WCD9335_CDC_RX7_RX_PATH_SEC5 0x0bda +#define WCD9335_CDC_RX7_RX_PATH_SEC6 0x0bdb +#define WCD9335_CDC_RX7_RX_PATH_SEC7 0x0bdc +#define WCD9335_CDC_RX7_RX_PATH_MIX_SEC0 0x0bdd +#define WCD9335_CDC_RX7_RX_PATH_MIX_SEC1 0x0bde +#define WCD9335_CDC_RX8_RX_PATH_CTL 0x0be1 +#define WCD9335_CDC_RX8_RX_PATH_CFG0 0x0be2 +#define WCD9335_CDC_RX8_RX_PATH_CFG1 0x0be3 +#define WCD9335_CDC_RX8_RX_PATH_CFG2 0x0be4 +#define WCD9335_CDC_RX8_RX_VOL_CTL 0x0be5 +#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL 0x0be6 +#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG 0x0be7 +#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL 0x0be8 +#define WCD9335_CDC_RX8_RX_PATH_SEC0 0x0be9 +#define WCD9335_CDC_RX8_RX_PATH_SEC1 0x0bea +#define WCD9335_CDC_RX8_RX_PATH_SEC2 0x0beb +#define WCD9335_CDC_RX8_RX_PATH_SEC3 0x0bec +#define WCD9335_CDC_RX8_RX_PATH_SEC5 0x0bee +#define WCD9335_CDC_RX8_RX_PATH_SEC6 0x0bef +#define WCD9335_CDC_RX8_RX_PATH_SEC7 0x0bf0 +#define WCD9335_CDC_RX8_RX_PATH_MIX_SEC0 0x0bf1 +#define WCD9335_CDC_RX8_RX_PATH_MIX_SEC1 0x0bf2 + +/* Page-12 Registers */ +#define WCD9335_PAGE12_PAGE_REGISTER 0x0c00 +#define WCD9335_CDC_CLSH_CRC 0x0c01 +#define WCD9335_CDC_CLSH_DLY_CTRL 0x0c02 +#define WCD9335_CDC_CLSH_DECAY_CTRL 0x0c03 +#define WCD9335_CDC_CLSH_HPH_V_PA 0x0c04 +#define WCD9335_CDC_CLSH_EAR_V_PA 0x0c05 +#define WCD9335_CDC_CLSH_HPH_V_HD 0x0c06 +#define WCD9335_CDC_CLSH_EAR_V_HD 0x0c07 +#define WCD9335_CDC_CLSH_K1_MSB 0x0c08 +#define WCD9335_CDC_CLSH_K1_LSB 0x0c09 +#define WCD9335_CDC_CLSH_K2_MSB 0x0c0a +#define WCD9335_CDC_CLSH_K2_LSB 0x0c0b +#define WCD9335_CDC_CLSH_IDLE_CTRL 0x0c0c +#define WCD9335_CDC_CLSH_IDLE_HPH 0x0c0d +#define WCD9335_CDC_CLSH_IDLE_EAR 0x0c0e +#define WCD9335_CDC_CLSH_TEST0 0x0c0f +#define WCD9335_CDC_CLSH_TEST1 0x0c10 +#define WCD9335_CDC_CLSH_OVR_VREF 0x0c11 +#define WCD9335_CDC_BOOST0_BOOST_PATH_CTL 0x0c19 +#define WCD9335_CDC_BOOST0_BOOST_CTL 0x0c1a +#define WCD9335_CDC_BOOST0_BOOST_CFG1 0x0c1b +#define WCD9335_CDC_BOOST0_BOOST_CFG2 0x0c1c +#define WCD9335_CDC_BOOST1_BOOST_PATH_CTL 0x0c21 +#define WCD9335_CDC_BOOST1_BOOST_CTL 0x0c22 +#define WCD9335_CDC_BOOST1_BOOST_CFG1 0x0c23 +#define WCD9335_CDC_BOOST1_BOOST_CFG2 0x0c24 +#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_0 0x0c29 +#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_1 0x0c2a +#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_2 0x0c2b +#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_3 0x0c2c +#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0 0x0c2d +#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1 0x0c2e +#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2 0x0c2f +#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3 0x0c30 +#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0 0x0c31 +#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1 0x0c32 +#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2 0x0c33 +#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3 0x0c34 +#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_0 0x0c35 +#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_1 0x0c36 +#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_2 0x0c37 +#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_3 0x0c38 +#define WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG 0x0c39 +#define WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS 0x0c3a +#define WCD9335_CDC_VBAT_VBAT_PATH_CTL 0x0c3d +#define WCD9335_CDC_VBAT_VBAT_CFG 0x0c3e +#define WCD9335_CDC_VBAT_VBAT_ADC_CAL1 0x0c3f +#define WCD9335_CDC_VBAT_VBAT_ADC_CAL2 0x0c40 +#define WCD9335_CDC_VBAT_VBAT_ADC_CAL3 0x0c41 +#define WCD9335_CDC_VBAT_VBAT_PK_EST1 0x0c42 +#define WCD9335_CDC_VBAT_VBAT_PK_EST2 0x0c43 +#define WCD9335_CDC_VBAT_VBAT_PK_EST3 0x0c44 +#define WCD9335_CDC_VBAT_VBAT_RF_PROC1 0x0c45 +#define WCD9335_CDC_VBAT_VBAT_RF_PROC2 0x0c46 +#define WCD9335_CDC_VBAT_VBAT_TAC1 0x0c47 +#define WCD9335_CDC_VBAT_VBAT_TAC2 0x0c48 +#define WCD9335_CDC_VBAT_VBAT_TAC3 0x0c49 +#define WCD9335_CDC_VBAT_VBAT_TAC4 0x0c4a +#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD1 0x0c4b +#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD2 0x0c4c +#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD3 0x0c4d +#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD4 0x0c4e +#define WCD9335_CDC_VBAT_VBAT_DEBUG1 0x0c4f +#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON 0x0c50 +#define WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL 0x0c51 +#define WCD9335_SPLINE_SRC0_CLK_RST_CTL_0 0x0c55 +#define WCD9335_SPLINE_SRC0_STATUS 0x0c56 +#define WCD9335_SPLINE_SRC1_CLK_RST_CTL_0 0x0c6d +#define WCD9335_SPLINE_SRC1_STATUS 0x0c6e +#define WCD9335_SPLINE_SRC2_CLK_RST_CTL_0 0x0c85 +#define WCD9335_SPLINE_SRC2_STATUS 0x0c86 +#define WCD9335_SPLINE_SRC3_CLK_RST_CTL_0 0x0c9d +#define WCD9335_SPLINE_SRC3_STATUS 0x0c9e +#define WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL 0x0cb5 +#define WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1 0x0cb6 +#define WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL 0x0cb9 +#define WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1 0x0cba + +/* Page-13 Registers */ +#define WCD9335_PAGE13_PAGE_REGISTER 0x0d00 +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0 0x0d01 +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1 0x0d02 +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 0x0d03 +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1 0x0d04 +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0 0x0d05 +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1 0x0d06 +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0 0x0d07 +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1 0x0d08 +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0 0x0d09 +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1 0x0d0a +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0 0x0d0b +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1 0x0d0c +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0 0x0d0d +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1 0x0d0e +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0 0x0d0f +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1 0x0d10 +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0 0x0d11 +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1 0x0d12 +#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0 0x0d13 +#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1 0x0d14 +#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2 0x0d15 +#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3 0x0d16 +#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4 0x0d17 +#define WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0 0x0d18 +#define WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1 0x0d19 +#define WCD9335_CDC_RX_INP_MUX_ANC_CFG0 0x0d1a +#define WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0 0x0d1b +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 0x0d1d +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 0x0d1e +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0 0x0d1f +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1 0x0d20 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0 0x0d21 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1 0x0d22 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0 0x0d23 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1 0x0d24 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 0x0d25 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0 0x0d26 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0 0x0d27 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0 0x0d28 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0 0x0d29 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0 0x0d2b +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0 0x0d2c +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0 0x0d2d +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0 0x0d2e +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0 0x0d31 +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1 0x0d32 +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2 0x0d33 +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3 0x0d34 +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0 0x0d35 +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1 0x0d36 +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2 0x0d37 +#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3 0x0d38 +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0 0x0d3a +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1 0x0d3b +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2 0x0d3c +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3 0x0d3d +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41 +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42 +#define WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL 0x0d43 +#define WCD9335_CDC_PROX_DETECT_PROX_CTL 0x0d49 +#define WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0 0x0d4a +#define WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1 0x0d4b +#define WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB 0x0d4c +#define WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB 0x0d4d +#define WCD9335_CDC_PROX_DETECT_PROX_STATUS 0x0d4e +#define WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL 0x0d4f +#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB 0x0d50 +#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB 0x0d51 +#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD 0x0d52 +#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD 0x0d53 +#define WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT 0x0d54 +#define WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL 0x0d55 +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL 0x0d56 +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL 0x0d57 +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL 0x0d58 +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL 0x0d59 +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL 0x0d5a +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL 0x0d5b +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL 0x0d5c +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL 0x0d5d +#define WCD9335_CDC_SIDETONE_IIR0_IIR_CTL 0x0d5e +#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL 0x0d5f +#define WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL 0x0d60 +#define WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL 0x0d61 +#define WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL 0x0d65 +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL 0x0d66 +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL 0x0d67 +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL 0x0d68 +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL 0x0d69 +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL 0x0d6a +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL 0x0d6b +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL 0x0d6c +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL 0x0d6d +#define WCD9335_CDC_SIDETONE_IIR1_IIR_CTL 0x0d6e +#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL 0x0d6f +#define WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL 0x0d70 +#define WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL 0x0d71 +#define WCD9335_CDC_TOP_TOP_CFG0 0x0d81 +#define WCD9335_CDC_TOP_TOP_CFG1 0x0d82 +#define WCD9335_CDC_TOP_TOP_CFG2 0x0d83 +#define WCD9335_CDC_TOP_TOP_CFG3 0x0d84 +#define WCD9335_CDC_TOP_TOP_CFG4 0x0d85 +#define WCD9335_CDC_TOP_TOP_CFG5 0x0d86 +#define WCD9335_CDC_TOP_TOP_CFG6 0x0d87 +#define WCD9335_CDC_TOP_TOP_CFG7 0x0d88 +#define WCD9335_CDC_TOP_HPHL_COMP_WR_LSB 0x0d89 +#define WCD9335_CDC_TOP_HPHL_COMP_WR_MSB 0x0d8a +#define WCD9335_CDC_TOP_HPHL_COMP_LUT 0x0d8b +#define WCD9335_CDC_TOP_HPHL_COMP_RD_LSB 0x0d8c +#define WCD9335_CDC_TOP_HPHL_COMP_RD_MSB 0x0d8d +#define WCD9335_CDC_TOP_HPHR_COMP_WR_LSB 0x0d8e +#define WCD9335_CDC_TOP_HPHR_COMP_WR_MSB 0x0d8f +#define WCD9335_CDC_TOP_HPHR_COMP_LUT 0x0d90 +#define WCD9335_CDC_TOP_HPHR_COMP_RD_LSB 0x0d91 +#define WCD9335_CDC_TOP_HPHR_COMP_RD_MSB 0x0d92 +#define WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB 0x0d93 +#define WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB 0x0d94 +#define WCD9335_CDC_TOP_DIFFL_COMP_LUT 0x0d95 +#define WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB 0x0d96 +#define WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB 0x0d97 +#define WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB 0x0d98 +#define WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB 0x0d99 +#define WCD9335_CDC_TOP_DIFFR_COMP_LUT 0x0d9a +#define WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB 0x0d9b +#define WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB 0x0d9c + +/* Page-0x80 Registers */ +#define WCD9335_PAGE80_PAGE_REGISTER 0x8000 +#define WCD9335_TLMM_BIST_MODE_PINCFG 0x8001 +#define WCD9335_TLMM_RF_PA_ON_PINCFG 0x8002 +#define WCD9335_TLMM_INTR1_PINCFG 0x8003 +#define WCD9335_TLMM_INTR2_PINCFG 0x8004 +#define WCD9335_TLMM_SWR_DATA_PINCFG 0x8005 +#define WCD9335_TLMM_SWR_CLK_PINCFG 0x8006 +#define WCD9335_TLMM_SLIMBUS_DATA2_PINCFG 0x8007 +#define WCD9335_TLMM_I2C_CLK_PINCFG 0x8008 +#define WCD9335_TLMM_I2C_DATA_PINCFG 0x8009 +#define WCD9335_TLMM_I2S_RX_SD0_PINCFG 0x800a +#define WCD9335_TLMM_I2S_RX_SD1_PINCFG 0x800b +#define WCD9335_TLMM_I2S_RX_SCK_PINCFG 0x800c +#define WCD9335_TLMM_I2S_RX_WS_PINCFG 0x800d +#define WCD9335_TLMM_I2S_TX_SD0_PINCFG 0x800e +#define WCD9335_TLMM_I2S_TX_SD1_PINCFG 0x800f +#define WCD9335_TLMM_I2S_TX_SCK_PINCFG 0x8010 +#define WCD9335_TLMM_I2S_TX_WS_PINCFG 0x8011 +#define WCD9335_TLMM_DMIC1_CLK_PINCFG 0x8012 +#define WCD9335_TLMM_DMIC1_DATA_PINCFG 0x8013 +#define WCD9335_TLMM_DMIC2_CLK_PINCFG 0x8014 +#define WCD9335_TLMM_DMIC2_DATA_PINCFG 0x8015 +#define WCD9335_TLMM_DMIC3_CLK_PINCFG 0x8016 +#define WCD9335_TLMM_DMIC3_DATA_PINCFG 0x8017 +#define WCD9335_TLMM_JTDI_PINCFG 0x8018 +#define WCD9335_TLMM_JTDO_PINCFG 0x8019 +#define WCD9335_TLMM_JTMS_PINCFG 0x801a +#define WCD9335_TLMM_JTCK_PINCFG 0x801b +#define WCD9335_TLMM_JTRST_PINCFG 0x801c +#define WCD9335_TEST_DEBUG_PIN_CTL_OE_0 0x8031 +#define WCD9335_TEST_DEBUG_PIN_CTL_OE_1 0x8032 +#define WCD9335_TEST_DEBUG_PIN_CTL_OE_2 0x8033 +#define WCD9335_TEST_DEBUG_PIN_CTL_OE_3 0x8034 +#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_0 0x8035 +#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_1 0x8036 +#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_2 0x8037 +#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_3 0x8038 +#define WCD9335_TEST_DEBUG_PAD_DRVCTL 0x8039 +#define WCD9335_TEST_DEBUG_PIN_STATUS 0x803a +#define WCD9335_TEST_DEBUG_NPL_DLY_TEST_1 0x803b +#define WCD9335_TEST_DEBUG_NPL_DLY_TEST_2 0x803c +#define WCD9335_TEST_DEBUG_MEM_CTRL 0x803d +#define WCD9335_TEST_DEBUG_DEBUG_BUS_SEL 0x8041 +#define WCD9335_TEST_DEBUG_DEBUG_JTAG 0x8042 +#define WCD9335_TEST_DEBUG_DEBUG_EN_1 0x8043 +#define WCD9335_TEST_DEBUG_DEBUG_EN_2 0x8044 +#define WCD9335_TEST_DEBUG_DEBUG_EN_3 0x8045 +#define WCD9335_MAX_REGISTER 0x80FF + +/* SLIMBUS Slave Registers */ +#define TASHA_SLIM_PGD_PORT_INT_EN0 (0x30) +#define TASHA_SLIM_PGD_PORT_INT_STATUS_RX_0 (0x34) +#define TASHA_SLIM_PGD_PORT_INT_STATUS_RX_1 (0x35) +#define TASHA_SLIM_PGD_PORT_INT_STATUS_TX_0 (0x36) +#define TASHA_SLIM_PGD_PORT_INT_STATUS_TX_1 (0x37) +#define TASHA_SLIM_PGD_PORT_INT_CLR_RX_0 (0x38) +#define TASHA_SLIM_PGD_PORT_INT_CLR_RX_1 (0x39) +#define TASHA_SLIM_PGD_PORT_INT_CLR_TX_0 (0x3A) +#define TASHA_SLIM_PGD_PORT_INT_CLR_TX_1 (0x3B) +#define TASHA_SLIM_PGD_PORT_INT_RX_SOURCE0 (0x60) +#define TASHA_SLIM_PGD_PORT_INT_TX_SOURCE0 (0x70) + +/* Macros for Packing Register Writes into a U32 */ +#define TASHA_PACKED_REG_SIZE sizeof(u32) + +#define TASHA_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\ + ((mask & 0xff) << 8)|((reg & 0xffff) << 16)) +#define TASHA_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \ + do { \ + ((reg) = ((packed >> 16) & (0xffff))); \ + ((mask) = ((packed >> 8) & (0xff))); \ + ((val) = ((packed) & (0xff))); \ + } while (0) +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/Kbuild new file mode 100644 index 0000000000..4c7965197b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/Kbuild @@ -0,0 +1,127 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_TRINKET), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_SM8150), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDMSHRIKE), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDXLEMUR), y) + include $(AUDIO_ROOT)/config/sdxlemurauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdxlemurautoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ WCD934X ############ + +# for WCD934X Codec +ifdef CONFIG_SND_SOC_WCD934X + WCD934X_OBJS += wcd934x.o + WCD934X_OBJS += wcd934x-dsp-cntl.o + WCD934X_OBJS += wcd934x-mbhc.o + WCD934X_OBJS += wcd934x-dsd.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_WCD934X) += wcd934x_dlkm.o +wcd934x_dlkm-y := $(WCD934X_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsd.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsd.c new file mode 100644 index 0000000000..98f126481a --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsd.c @@ -0,0 +1,829 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "wcd934x-dsd.h" + +#define DSD_VOLUME_MAX_0dB 0 +#define DSD_VOLUME_MIN_M110dB -110 + +#define DSD_VOLUME_RANGE_CHECK(x) ((x >= DSD_VOLUME_MIN_M110dB) &&\ + (x <= DSD_VOLUME_MAX_0dB)) +#define DSD_VOLUME_STEPS 3 +#define DSD_VOLUME_UPDATE_DELAY_MS 30 +#define DSD_VOLUME_USLEEP_MARGIN_US 100 +#define DSD_VOLUME_STEP_DELAY_US ((1000 * DSD_VOLUME_UPDATE_DELAY_MS) / \ + (2 * DSD_VOLUME_STEPS)) + +#define TAVIL_VERSION_1_0 0 +#define TAVIL_VERSION_1_1 1 + +static const DECLARE_TLV_DB_MINMAX(tavil_dsd_db_scale, DSD_VOLUME_MIN_M110dB, + DSD_VOLUME_MAX_0dB); + +static const char *const dsd_if_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7", + "DSD_DATA_PAD" +}; + +static const char * const dsd_filt0_mux_text[] = { + "ZERO", "DSD_L IF MUX", +}; + +static const char * const dsd_filt1_mux_text[] = { + "ZERO", "DSD_R IF MUX", +}; + +static const struct soc_enum dsd_filt0_mux_enum = + SOC_ENUM_SINGLE(WCD934X_CDC_DSD0_PATH_CTL, 0, + ARRAY_SIZE(dsd_filt0_mux_text), dsd_filt0_mux_text); + +static const struct soc_enum dsd_filt1_mux_enum = + SOC_ENUM_SINGLE(WCD934X_CDC_DSD1_PATH_CTL, 0, + ARRAY_SIZE(dsd_filt1_mux_text), dsd_filt1_mux_text); + +static SOC_ENUM_SINGLE_DECL(dsd_l_if_enum, WCD934X_CDC_DSD0_CFG0, + 2, dsd_if_text); +static SOC_ENUM_SINGLE_DECL(dsd_r_if_enum, WCD934X_CDC_DSD1_CFG0, + 2, dsd_if_text); + +static const struct snd_kcontrol_new dsd_filt0_mux = + SOC_DAPM_ENUM("DSD Filt0 Mux", dsd_filt0_mux_enum); + +static const struct snd_kcontrol_new dsd_filt1_mux = + SOC_DAPM_ENUM("DSD Filt1 Mux", dsd_filt1_mux_enum); + +static const struct snd_kcontrol_new dsd_l_if_mux = + SOC_DAPM_ENUM("DSD Left If Mux", dsd_l_if_enum); +static const struct snd_kcontrol_new dsd_r_if_mux = + SOC_DAPM_ENUM("DSD Right If Mux", dsd_r_if_enum); + +static const struct snd_soc_dapm_route tavil_dsd_audio_map[] = { + {"DSD_L IF MUX", "RX0", "CDC_IF RX0 MUX"}, + {"DSD_L IF MUX", "RX1", "CDC_IF RX1 MUX"}, + {"DSD_L IF MUX", "RX2", "CDC_IF RX2 MUX"}, + {"DSD_L IF MUX", "RX3", "CDC_IF RX3 MUX"}, + {"DSD_L IF MUX", "RX4", "CDC_IF RX4 MUX"}, + {"DSD_L IF MUX", "RX5", "CDC_IF RX5 MUX"}, + {"DSD_L IF MUX", "RX6", "CDC_IF RX6 MUX"}, + {"DSD_L IF MUX", "RX7", "CDC_IF RX7 MUX"}, + + {"DSD_FILTER_0", NULL, "DSD_L IF MUX"}, + {"DSD_FILTER_0", NULL, "RX INT1 NATIVE SUPPLY"}, + {"RX INT1 MIX3", "DSD HPHL Switch", "DSD_FILTER_0"}, + + {"DSD_R IF MUX", "RX0", "CDC_IF RX0 MUX"}, + {"DSD_R IF MUX", "RX1", "CDC_IF RX1 MUX"}, + {"DSD_R IF MUX", "RX2", "CDC_IF RX2 MUX"}, + {"DSD_R IF MUX", "RX3", "CDC_IF RX3 MUX"}, + {"DSD_R IF MUX", "RX4", "CDC_IF RX4 MUX"}, + {"DSD_R IF MUX", "RX5", "CDC_IF RX5 MUX"}, + {"DSD_R IF MUX", "RX6", "CDC_IF RX6 MUX"}, + {"DSD_R IF MUX", "RX7", "CDC_IF RX7 MUX"}, + + {"DSD_FILTER_1", NULL, "DSD_R IF MUX"}, + {"DSD_FILTER_1", NULL, "RX INT2 NATIVE SUPPLY"}, + {"RX INT2 MIX3", "DSD HPHR Switch", "DSD_FILTER_1"}, + + {"DSD_FILTER_0", NULL, "RX INT3 NATIVE SUPPLY"}, + {"RX INT3 MIX3", "DSD LO1 Switch", "DSD_FILTER_0"}, + {"DSD_FILTER_1", NULL, "RX INT4 NATIVE SUPPLY"}, + {"RX INT4 MIX3", "DSD LO2 Switch", "DSD_FILTER_1"}, +}; + +static bool is_valid_dsd_interpolator(int interp_num) +{ + if ((interp_num == INTERP_HPHL) || (interp_num == INTERP_HPHR) || + (interp_num == INTERP_LO1) || (interp_num == INTERP_LO2)) + return true; + + return false; +} + +/** + * tavil_dsd_set_mixer_value - Set DSD HPH/LO mixer value + * + * @dsd_conf: pointer to dsd config + * @interp_num: Interpolator number (HPHL/R, LO1/2) + * @sw_value: Mixer switch value + * + * Returns 0 on success or -EINVAL on failure + */ +int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf, + int interp_num, int sw_value) +{ + if (!dsd_conf) + return -EINVAL; + + if (!is_valid_dsd_interpolator(interp_num)) + return -EINVAL; + + dsd_conf->dsd_interp_mixer[interp_num] = !!sw_value; + + return 0; +} +EXPORT_SYMBOL(tavil_dsd_set_mixer_value); + +/** + * tavil_dsd_get_current_mixer_value - Get DSD HPH/LO mixer value + * + * @dsd_conf: pointer to dsd config + * @interp_num: Interpolator number (HPHL/R, LO1/2) + * + * Returns current mixer val for success or -EINVAL for failure + */ +int tavil_dsd_get_current_mixer_value(struct tavil_dsd_config *dsd_conf, + int interp_num) +{ + if (!dsd_conf) + return -EINVAL; + + if (!is_valid_dsd_interpolator(interp_num)) + return -EINVAL; + + return dsd_conf->dsd_interp_mixer[interp_num]; +} +EXPORT_SYMBOL(tavil_dsd_get_current_mixer_value); + +/** + * tavil_dsd_set_out_select - DSD0/1 out select to HPH or LO + * + * @dsd_conf: pointer to dsd config + * @interp_num: Interpolator number (HPHL/R, LO1/2) + * + * Returns 0 for success or -EINVAL for failure + */ +int tavil_dsd_set_out_select(struct tavil_dsd_config *dsd_conf, + int interp_num) +{ + unsigned int reg, val; + struct snd_soc_component *component; + + if (!dsd_conf || !dsd_conf->component) + return -EINVAL; + + component = dsd_conf->component; + + if (!is_valid_dsd_interpolator(interp_num)) { + dev_err(component->dev, "%s: Invalid Interpolator: %d for DSD\n", + __func__, interp_num); + return -EINVAL; + } + + switch (interp_num) { + case INTERP_HPHL: + reg = WCD934X_CDC_DSD0_CFG0; + val = 0x00; + break; + case INTERP_HPHR: + reg = WCD934X_CDC_DSD1_CFG0; + val = 0x00; + break; + case INTERP_LO1: + reg = WCD934X_CDC_DSD0_CFG0; + val = 0x02; + break; + case INTERP_LO2: + reg = WCD934X_CDC_DSD1_CFG0; + val = 0x02; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, reg, 0x02, val); + + return 0; +} +EXPORT_SYMBOL(tavil_dsd_set_out_select); + +/** + * tavil_dsd_reset - Reset DSD block + * + * @dsd_conf: pointer to dsd config + * + */ +void tavil_dsd_reset(struct tavil_dsd_config *dsd_conf) +{ + if (!dsd_conf || !dsd_conf->component) + return; + + snd_soc_component_update_bits(dsd_conf->component, + WCD934X_CDC_DSD0_PATH_CTL, + 0x02, 0x02); + snd_soc_component_update_bits(dsd_conf->component, + WCD934X_CDC_DSD0_PATH_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(dsd_conf->component, + WCD934X_CDC_DSD1_PATH_CTL, + 0x02, 0x02); + snd_soc_component_update_bits(dsd_conf->component, + WCD934X_CDC_DSD1_PATH_CTL, + 0x01, 0x00); +} +EXPORT_SYMBOL(tavil_dsd_reset); + +/** + * tavil_dsd_set_interp_rate - Set interpolator rate for DSD + * + * @dsd_conf: pointer to dsd config + * @rx_port: RX port number + * @sample_rate: Sample rate of the RX interpolator + * @sample_rate_val: Interpolator rate value + */ +void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port, + u32 sample_rate, u8 sample_rate_val) +{ + u8 dsd_inp_sel; + u8 dsd0_inp, dsd1_inp; + u8 val0, val1; + u8 dsd0_out_sel, dsd1_out_sel; + u16 int_fs_reg, interp_num = 0; + struct snd_soc_component *component; + + if (!dsd_conf || !dsd_conf->component) + return; + + component = dsd_conf->component; + + dsd_inp_sel = DSD_INP_SEL_RX0 + rx_port - WCD934X_RX_PORT_START_NUMBER; + + val0 = snd_soc_component_read32(component, WCD934X_CDC_DSD0_CFG0); + val1 = snd_soc_component_read32(component, WCD934X_CDC_DSD1_CFG0); + dsd0_inp = (val0 & 0x3C) >> 2; + dsd1_inp = (val1 & 0x3C) >> 2; + dsd0_out_sel = (val0 & 0x02) >> 1; + dsd1_out_sel = (val1 & 0x02) >> 1; + + /* Set HPHL or LO1 interp rate based on out select */ + if (dsd_inp_sel == dsd0_inp) { + interp_num = dsd0_out_sel ? INTERP_LO1 : INTERP_HPHL; + dsd_conf->base_sample_rate[DSD0] = sample_rate; + } + + /* Set HPHR or LO2 interp rate based on out select */ + if (dsd_inp_sel == dsd1_inp) { + interp_num = dsd1_out_sel ? INTERP_LO2 : INTERP_HPHR; + dsd_conf->base_sample_rate[DSD1] = sample_rate; + } + + if (interp_num) { + int_fs_reg = WCD934X_CDC_RX0_RX_PATH_CTL + 20 * interp_num; + if ((snd_soc_component_read32(component, int_fs_reg) & 0x0f) < + 0x09) { + dev_dbg(component->dev, "%s: Set Interp %d to sample_rate val 0x%x\n", + __func__, interp_num, sample_rate_val); + snd_soc_component_update_bits(component, int_fs_reg, + 0x0F, sample_rate_val); + } + } +} +EXPORT_SYMBOL(tavil_dsd_set_interp_rate); + +static int tavil_set_dsd_mode(struct snd_soc_component *component, int dsd_num, + u8 *pcm_rate_val) +{ + unsigned int dsd_out_sel_reg; + u8 dsd_mode; + u32 sample_rate; + struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(component); + + if (!dsd_conf) + return -EINVAL; + + if ((dsd_num < 0) || (dsd_num > 1)) + return -EINVAL; + + sample_rate = dsd_conf->base_sample_rate[dsd_num]; + dsd_out_sel_reg = WCD934X_CDC_DSD0_CFG0 + dsd_num * 16; + + switch (sample_rate) { + case 176400: + dsd_mode = 0; /* DSD_64 */ + *pcm_rate_val = 0xb; + break; + case 352800: + dsd_mode = 1; /* DSD_128 */ + *pcm_rate_val = 0xc; + break; + default: + dev_err(component->dev, "%s: Invalid DSD rate: %d\n", + __func__, sample_rate); + return -EINVAL; + } + + snd_soc_component_update_bits(component, dsd_out_sel_reg, + 0x01, dsd_mode); + + return 0; +} + +static void tavil_dsd_data_pull(struct snd_soc_component *component, + int dsd_num, + u8 pcm_rate_val, bool enable) +{ + u8 clk_en, mute_en; + u8 dsd_inp_sel; + + if (enable) { + clk_en = 0x20; + mute_en = 0x10; + } else { + clk_en = 0x00; + mute_en = 0x00; + } + + if (dsd_num & 0x01) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_MIX_CTL, + 0x20, clk_en); + dsd_inp_sel = (snd_soc_component_read32( + component, WCD934X_CDC_DSD0_CFG0) & + 0x3C) >> 2; + dsd_inp_sel = (enable) ? dsd_inp_sel : 0; + if (dsd_inp_sel < 9) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, + 0x0F, dsd_inp_sel); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_MIX_CTL, + 0x0F, pcm_rate_val); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_MIX_CTL, + 0x10, mute_en); + } + } + if (dsd_num & 0x02) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_MIX_CTL, + 0x20, clk_en); + dsd_inp_sel = (snd_soc_component_read32( + component, WCD934X_CDC_DSD1_CFG0) & + 0x3C) >> 2; + dsd_inp_sel = (enable) ? dsd_inp_sel : 0; + if (dsd_inp_sel < 9) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, + 0x0F, dsd_inp_sel); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_MIX_CTL, + 0x0F, pcm_rate_val); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_MIX_CTL, + 0x10, mute_en); + } + } +} + +static void tavil_dsd_update_volume(struct tavil_dsd_config *dsd_conf) +{ + snd_soc_component_update_bits(dsd_conf->component, + WCD934X_CDC_TOP_TOP_CFG0, + 0x01, 0x01); + snd_soc_component_update_bits(dsd_conf->component, + WCD934X_CDC_TOP_TOP_CFG0, + 0x01, 0x00); +} + +static int tavil_enable_dsd(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(component); + int rc, clk_users; + int interp_idx; + u8 pcm_rate_val; + + if (!dsd_conf) { + dev_err(component->dev, "%s: null dsd_config pointer\n", + __func__); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: DSD%d, event: %d\n", __func__, + w->shift, event); + + if (w->shift == DSD0) { + /* Read out select */ + if (snd_soc_component_read32( + component, WCD934X_CDC_DSD0_CFG0) & 0x02) + interp_idx = INTERP_LO1; + else + interp_idx = INTERP_HPHL; + } else if (w->shift == DSD1) { + /* Read out select */ + if (snd_soc_component_read32( + component, WCD934X_CDC_DSD1_CFG0) & 0x02) + interp_idx = INTERP_LO2; + else + interp_idx = INTERP_HPHR; + } else { + dev_err(component->dev, "%s: Unsupported DSD:%d\n", + __func__, w->shift); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + clk_users = tavil_codec_enable_interp_clk(component, event, + interp_idx); + + rc = tavil_set_dsd_mode(component, w->shift, &pcm_rate_val); + if (rc) + return rc; + + tavil_dsd_data_pull(component, (1 << w->shift), pcm_rate_val, + true); + + snd_soc_component_update_bits(component, + WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL, 0x01, + 0x01); + if (w->shift == DSD0) { + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_PATH_CTL, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_PATH_CTL, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_PATH_CTL, + 0x01, 0x01); + /* Apply Gain */ + snd_soc_component_write(component, + WCD934X_CDC_DSD0_CFG1, + dsd_conf->volume[DSD0]); + if (dsd_conf->version == TAVIL_VERSION_1_1) + tavil_dsd_update_volume(dsd_conf); + + } else if (w->shift == DSD1) { + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_PATH_CTL, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_PATH_CTL, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_PATH_CTL, + 0x01, 0x01); + /* Apply Gain */ + snd_soc_component_write(component, + WCD934X_CDC_DSD1_CFG1, + dsd_conf->volume[DSD1]); + if (dsd_conf->version == TAVIL_VERSION_1_1) + tavil_dsd_update_volume(dsd_conf); + } + /* 10msec sleep required after DSD clock is set */ + usleep_range(10000, 10100); + + if (clk_users > 1) { + snd_soc_component_update_bits(component, + WCD934X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (w->shift == DSD0) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x04, 0x00); + if (w->shift == DSD1) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, + 0x04, 0x00); + + } + break; + case SND_SOC_DAPM_POST_PMD: + if (w->shift == DSD0) { + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_PATH_CTL, + 0x01, 0x00); + } else if (w->shift == DSD1) { + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_PATH_CTL, + 0x01, 0x00); + } + + tavil_codec_enable_interp_clk(component, event, interp_idx); + + if (!(snd_soc_component_read32( + component, WCD934X_CDC_DSD0_PATH_CTL) & 0x01) && + !(snd_soc_component_read32( + component, WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) { + snd_soc_component_update_bits(component, + WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL, + 0x01, 0x00); + tavil_dsd_data_pull(component, 0x03, 0x04, false); + tavil_dsd_reset(dsd_conf); + } + break; + } + + return 0; +} + +static int tavil_dsd_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = DSD_VOLUME_MIN_M110dB; + uinfo->value.integer.max = DSD_VOLUME_MAX_0dB; + + return 0; +} + +static int tavil_dsd_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(component); + int nv[DSD_MAX], cv[DSD_MAX]; + int step_size, nv1; + int i, dsd_idx; + + if (!dsd_conf) + return 0; + + mutex_lock(&dsd_conf->vol_mutex); + + for (dsd_idx = DSD0; dsd_idx < DSD_MAX; dsd_idx++) { + cv[dsd_idx] = dsd_conf->volume[dsd_idx]; + nv[dsd_idx] = ucontrol->value.integer.value[dsd_idx]; + } + + if ((!DSD_VOLUME_RANGE_CHECK(nv[DSD0])) || + (!DSD_VOLUME_RANGE_CHECK(nv[DSD1]))) + goto done; + + for (dsd_idx = DSD0; dsd_idx < DSD_MAX; dsd_idx++) { + if (cv[dsd_idx] == nv[dsd_idx]) + continue; + + dev_dbg(component->dev, "%s: DSD%d cur.vol: %d, new vol: %d\n", + __func__, dsd_idx, cv[dsd_idx], nv[dsd_idx]); + + step_size = (nv[dsd_idx] - cv[dsd_idx]) / + DSD_VOLUME_STEPS; + + nv1 = cv[dsd_idx]; + + for (i = 0; i < DSD_VOLUME_STEPS; i++) { + nv1 += step_size; + snd_soc_component_write(component, + WCD934X_CDC_DSD0_CFG1 + 16 * dsd_idx, + nv1); + if (dsd_conf->version == TAVIL_VERSION_1_1) + tavil_dsd_update_volume(dsd_conf); + + /* sleep required after each volume step */ + usleep_range(DSD_VOLUME_STEP_DELAY_US, + (DSD_VOLUME_STEP_DELAY_US + + DSD_VOLUME_USLEEP_MARGIN_US)); + } + if (nv1 != nv[dsd_idx]) { + snd_soc_component_write(component, + WCD934X_CDC_DSD0_CFG1 + 16 * dsd_idx, + nv[dsd_idx]); + + if (dsd_conf->version == TAVIL_VERSION_1_1) + tavil_dsd_update_volume(dsd_conf); + } + + dsd_conf->volume[dsd_idx] = nv[dsd_idx]; + } + +done: + mutex_unlock(&dsd_conf->vol_mutex); + + return 0; +} + +static int tavil_dsd_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_dsd_config *dsd_conf = tavil_get_dsd_config(component); + + if (dsd_conf) { + ucontrol->value.integer.value[0] = dsd_conf->volume[DSD0]; + ucontrol->value.integer.value[1] = dsd_conf->volume[DSD1]; + } + + return 0; +} + +static const struct snd_kcontrol_new tavil_dsd_vol_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "DSD Volume", + .info = tavil_dsd_vol_info, + .get = tavil_dsd_vol_get, + .put = tavil_dsd_vol_put, + .tlv = { .p = tavil_dsd_db_scale }, + }, +}; + +static const struct snd_soc_dapm_widget tavil_dsd_widgets[] = { + SND_SOC_DAPM_MUX("DSD_L IF MUX", SND_SOC_NOPM, 0, 0, &dsd_l_if_mux), + SND_SOC_DAPM_MUX_E("DSD_FILTER_0", SND_SOC_NOPM, 0, 0, &dsd_filt0_mux, + tavil_enable_dsd, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("DSD_R IF MUX", SND_SOC_NOPM, 0, 0, &dsd_r_if_mux), + SND_SOC_DAPM_MUX_E("DSD_FILTER_1", SND_SOC_NOPM, 1, 0, &dsd_filt1_mux, + tavil_enable_dsd, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +/** + * tavil_dsd_post_ssr_init - DSD intialization after subsystem restart + * + * @component: pointer to snd_soc_component + * + * Returns 0 on success or error on failure + */ +int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_conf) +{ + struct snd_soc_component *component; + + if (!dsd_conf || !dsd_conf->component) + return -EINVAL; + + component = dsd_conf->component; + /* Disable DSD Interrupts */ + snd_soc_component_update_bits(component, + WCD934X_INTR_CODEC_MISC_MASK, + 0x08, 0x08); + + /* DSD registers init */ + if (dsd_conf->version == TAVIL_VERSION_1_0) { + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, + 0x02, 0x00); + } + /* DSD0: Mute EN */ + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x04, 0x04); + /* DSD1: Mute EN */ + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, + 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, + 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, + 0x0E, 0x0A); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, + 0x0E, 0x0A); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, + 0x07, 0x04); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, + 0x07, 0x04); + + /* Enable DSD Interrupts */ + snd_soc_component_update_bits(component, + WCD934X_INTR_CODEC_MISC_MASK, + 0x08, 0x00); + + return 0; +} +EXPORT_SYMBOL(tavil_dsd_post_ssr_init); + +/** + * tavil_dsd_init - DSD intialization + * + * @component: pointer to snd_soc_component + * + * Returns pointer to tavil_dsd_config for success or NULL for failure + */ +struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm; + struct tavil_dsd_config *dsd_conf; + u8 val; + + if (!component) + return NULL; + + dapm = snd_soc_component_get_dapm(component); + + /* Read efuse register to check if DSD is supported */ + val = snd_soc_component_read32(component, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14); + if (val & 0x80) { + dev_info(component->dev, "%s: DSD unsupported for this codec version\n", + __func__); + return NULL; + } + + dsd_conf = devm_kzalloc(component->dev, sizeof(struct tavil_dsd_config), + GFP_KERNEL); + if (!dsd_conf) + return NULL; + + dsd_conf->component = component; + + /* Read version */ + dsd_conf->version = snd_soc_component_read32(component, + WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0); + /* DSD registers init */ + if (dsd_conf->version == TAVIL_VERSION_1_0) { + snd_soc_component_update_bits(component, WCD934X_CDC_DSD0_CFG2, + 0x02, 0x00); + snd_soc_component_update_bits(component, WCD934X_CDC_DSD1_CFG2, + 0x02, 0x00); + } + /* DSD0: Mute EN */ + snd_soc_component_update_bits(component, WCD934X_CDC_DSD0_CFG2, + 0x04, 0x04); + /* DSD1: Mute EN */ + snd_soc_component_update_bits(component, WCD934X_CDC_DSD1_CFG2, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, + 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, + 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, + 0x0E, 0x0A); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, + 0x0E, 0x0A); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, + 0x07, 0x04); + snd_soc_component_update_bits(component, + WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, + 0x07, 0x04); + + snd_soc_dapm_new_controls(dapm, tavil_dsd_widgets, + ARRAY_SIZE(tavil_dsd_widgets)); + + snd_soc_dapm_add_routes(dapm, tavil_dsd_audio_map, + ARRAY_SIZE(tavil_dsd_audio_map)); + + mutex_init(&dsd_conf->vol_mutex); + dsd_conf->volume[DSD0] = DSD_VOLUME_MAX_0dB; + dsd_conf->volume[DSD1] = DSD_VOLUME_MAX_0dB; + + snd_soc_add_component_controls(component, tavil_dsd_vol_controls, + ARRAY_SIZE(tavil_dsd_vol_controls)); + + /* Enable DSD Interrupts */ + snd_soc_component_update_bits(component, + WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x00); + + return dsd_conf; +} +EXPORT_SYMBOL(tavil_dsd_init); + +/** + * tavil_dsd_deinit - DSD de-intialization + * + * @dsd_conf: pointer to tavil_dsd_config + */ +void tavil_dsd_deinit(struct tavil_dsd_config *dsd_conf) +{ + struct snd_soc_component *component; + + if (!dsd_conf) + return; + + component = dsd_conf->component; + + mutex_destroy(&dsd_conf->vol_mutex); + + /* Disable DSD Interrupts */ + snd_soc_component_update_bits(component, + WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x08); + + devm_kfree(component->dev, dsd_conf); +} +EXPORT_SYMBOL(tavil_dsd_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsd.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsd.h new file mode 100644 index 0000000000..0dc4516b2c --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsd.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD934X_DSD_H__ +#define __WCD934X_DSD_H__ + +#include +#include "wcd934x.h" + +enum { + DSD0, + DSD1, + DSD_MAX, +}; + +enum { + DSD_INP_SEL_ZERO = 0, + DSD_INP_SEL_RX0, + DSD_INP_SEL_RX1, + DSD_INP_SEL_RX2, + DSD_INP_SEL_RX3, + DSD_INP_SEL_RX4, + DSD_INP_SEL_RX5, + DSD_INP_SEL_RX6, + DSD_INP_SEL_RX7, +}; + +struct tavil_dsd_config { + struct snd_soc_component *component; + unsigned int dsd_interp_mixer[INTERP_MAX]; + u32 base_sample_rate[DSD_MAX]; + int volume[DSD_MAX]; + struct mutex vol_mutex; + int version; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD934X_DSD) +int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf, + int interp_num, int sw_value); +int tavil_dsd_get_current_mixer_value(struct tavil_dsd_config *dsd_conf, + int interp_num); +int tavil_dsd_set_out_select(struct tavil_dsd_config *dsd_conf, + int interp_num); +void tavil_dsd_reset(struct tavil_dsd_config *dsd_conf); +void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port, + u32 sample_rate, u8 sample_rate_val); +struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_component *component); +void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config); +int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config); +#else +int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf, + int interp_num, int sw_value) +{ + return 0; +} + +int tavil_dsd_get_current_mixer_value(struct tavil_dsd_config *dsd_conf, + int interp_num) +{ + return 0; +} + +int tavil_dsd_set_out_select(struct tavil_dsd_config *dsd_conf, + int interp_num) +{ + return 0; +} + +void tavil_dsd_reset(struct tavil_dsd_config *dsd_conf) +{ } + +void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port, + u32 sample_rate, u8 sample_rate_val) +{ } + +struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_component *component) +{ + return NULL; +} + +void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config) +{ } +int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config) +{ + return 0; +} +#endif +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c new file mode 100644 index 0000000000..a7c9ea6e98 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsp-cntl.c @@ -0,0 +1,1526 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wcd934x.h" +#include "wcd934x-dsp-cntl.h" +#include +#include + +#define WCD_CNTL_DIR_NAME_LEN_MAX 32 +#define WCD_CPE_FLL_MAX_RETRIES 5 +#define WCD_MEM_ENABLE_MAX_RETRIES 20 +#define WCD_DSP_BOOT_TIMEOUT_MS 3000 +#define WCD_SYSFS_ENTRY_MAX_LEN 8 +#define WCD_PROCFS_ENTRY_MAX_LEN 16 +#define WCD_934X_RAMDUMP_START_ADDR 0x20100000 +#define WCD_934X_RAMDUMP_SIZE ((1024 * 1024) - 128) +#define WCD_MISCDEV_CMD_MAX_LEN 11 + +#define WCD_CNTL_MUTEX_LOCK(component, lock) \ +{ \ + dev_dbg(component->dev, "%s: mutex_lock(%s)\n", \ + __func__, __stringify_1(lock)); \ + mutex_lock(&lock); \ +} + +#define WCD_CNTL_MUTEX_UNLOCK(component, lock) \ +{ \ + dev_dbg(component->dev, "%s: mutex_unlock(%s)\n", \ + __func__, __stringify_1(lock)); \ + mutex_unlock(&lock); \ +} + +enum wcd_mem_type { + WCD_MEM_TYPE_ALWAYS_ON, + WCD_MEM_TYPE_SWITCHABLE, +}; + +struct wcd_cntl_attribute { + struct attribute attr; + ssize_t (*show)(struct wcd_dsp_cntl *cntl, char *buf); + ssize_t (*store)(struct wcd_dsp_cntl *cntl, const char *buf, + ssize_t count); +}; + +#define WCD_CNTL_ATTR(_name, _mode, _show, _store) \ +static struct wcd_cntl_attribute cntl_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode}, \ + .show = _show, \ + .store = _store, \ +} + +#define to_wcd_cntl_attr(a) \ + container_of((a), struct wcd_cntl_attribute, attr) + +#define to_wcd_cntl(kobj) \ + container_of((kobj), struct wcd_dsp_cntl, wcd_kobj) + +static u8 mem_enable_values[] = { + 0xFE, 0xFC, 0xF8, 0xF0, + 0xE0, 0xC0, 0x80, 0x00, +}; + +#ifdef CONFIG_DEBUG_FS +#define WCD_CNTL_SET_ERR_IRQ_FLAG(cntl)\ + atomic_cmpxchg(&cntl->err_irq_flag, 0, 1) +#define WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl)\ + atomic_set(&cntl->err_irq_flag, 0) + +static u16 wdsp_reg_for_debug_dump[] = { + WCD934X_CPE_SS_CPE_CTL, + WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0, + WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1, + WCD934X_CPE_SS_PWR_CPEFLL_CTL, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5, + WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN, + WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL, + WCD934X_CPE_SS_MAD_CTL, + WCD934X_CPE_SS_CPAR_CTL, + WCD934X_CPE_SS_CPAR_CFG, + WCD934X_CPE_SS_WDOG_CFG, + WCD934X_CPE_SS_STATUS, + WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, + WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, + WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A, + WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B, + WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A, + WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B, + WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A, + WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B, +}; + +static void wcd_cntl_collect_debug_dumps(struct wcd_dsp_cntl *cntl, + bool internal) +{ + struct snd_soc_component *component = cntl->component; + struct wdsp_err_signal_arg arg; + enum wdsp_signal signal; + int i; + u8 val; + + /* If WDSP SSR happens, skip collecting debug dumps */ + if (WCD_CNTL_SET_ERR_IRQ_FLAG(cntl) != 0) + return; + + /* Mask all error interrupts */ + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, + 0xFF); + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, + 0xFF); + + /* Collect important WDSP registers dump for debug use */ + pr_err("%s: Dump the WDSP registers for debug use\n", __func__); + for (i = 0; i < sizeof(wdsp_reg_for_debug_dump)/sizeof(u16); i++) { + val = snd_soc_component_read32(component, + wdsp_reg_for_debug_dump[i]); + pr_err("%s: reg = 0x%x, val = 0x%x\n", __func__, + wdsp_reg_for_debug_dump[i], val); + } + + /* Trigger NMI in WDSP to sync and update the memory */ + snd_soc_component_write(component, WCD934X_CPE_SS_BACKUP_INT, 0x02); + + /* Collect WDSP ramdump for debug use */ + if (cntl->m_dev && cntl->m_ops && cntl->m_ops->signal_handler) { + arg.mem_dumps_enabled = cntl->ramdump_enable; + arg.remote_start_addr = WCD_934X_RAMDUMP_START_ADDR; + arg.dump_size = WCD_934X_RAMDUMP_SIZE; + signal = internal ? WDSP_DEBUG_DUMP_INTERNAL : WDSP_DEBUG_DUMP; + cntl->m_ops->signal_handler(cntl->m_dev, signal, &arg); + } + + /* Unmask the fatal irqs */ + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, + ~(cntl->irqs.fatal_irqs & 0xFF)); + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, + ~((cntl->irqs.fatal_irqs >> 8) & 0xFF)); + + WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl); +} +#else +#define WCD_CNTL_SET_ERR_IRQ_FLAG(cntl) 0 +#define WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl) do {} while (0) +static void wcd_cntl_collect_debug_dumps(struct wcd_dsp_cntl *cntl, + bool internal) +{ +} +#endif + +static ssize_t wdsp_boot_show(struct wcd_dsp_cntl *cntl, char *buf) +{ + return snprintf(buf, WCD_SYSFS_ENTRY_MAX_LEN, + "%u", cntl->boot_reqs); +} + +static ssize_t wdsp_boot_store(struct wcd_dsp_cntl *cntl, + const char *buf, ssize_t count) +{ + u32 val; + bool vote; + int ret; + + ret = kstrtou32(buf, 10, &val); + if (ret) { + dev_err(cntl->component->dev, + "%s: Invalid entry, ret = %d\n", __func__, ret); + return -EINVAL; + } + + if (val > 0) { + cntl->boot_reqs++; + vote = true; + } else { + cntl->boot_reqs--; + vote = false; + } + + if (cntl->m_dev && cntl->m_ops && + cntl->m_ops->vote_for_dsp) + ret = cntl->m_ops->vote_for_dsp(cntl->m_dev, vote); + else + ret = -EINVAL; + + if (ret < 0) + dev_err(cntl->component->dev, + "%s: failed to %s dsp\n", __func__, + vote ? "enable" : "disable"); + return count; +} + +WCD_CNTL_ATTR(boot, 0660, wdsp_boot_show, wdsp_boot_store); + +static ssize_t wcd_cntl_sysfs_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct wcd_cntl_attribute *wcd_attr = to_wcd_cntl_attr(attr); + struct wcd_dsp_cntl *cntl = to_wcd_cntl(kobj); + ssize_t ret = -EINVAL; + + if (cntl && wcd_attr->show) + ret = wcd_attr->show(cntl, buf); + + return ret; +} + +static ssize_t wcd_cntl_sysfs_store(struct kobject *kobj, + struct attribute *attr, const char *buf, + size_t count) +{ + struct wcd_cntl_attribute *wcd_attr = to_wcd_cntl_attr(attr); + struct wcd_dsp_cntl *cntl = to_wcd_cntl(kobj); + ssize_t ret = -EINVAL; + + if (cntl && wcd_attr->store) + ret = wcd_attr->store(cntl, buf, count); + + return ret; +} + +static const struct sysfs_ops wcd_cntl_sysfs_ops = { + .show = wcd_cntl_sysfs_show, + .store = wcd_cntl_sysfs_store, +}; + +static struct kobj_type wcd_cntl_ktype = { + .sysfs_ops = &wcd_cntl_sysfs_ops, +}; + +static void wcd_cntl_change_online_state(struct wcd_dsp_cntl *cntl, + u8 online) +{ + struct wdsp_ssr_entry *ssr_entry = &cntl->ssr_entry; + unsigned long ret; + + WCD_CNTL_MUTEX_LOCK(cntl->component, cntl->ssr_mutex); + ssr_entry->offline = !online; + /* Make sure the write is complete */ + wmb(); + ret = xchg(&ssr_entry->offline_change, 1); + wake_up_interruptible(&ssr_entry->offline_poll_wait); + dev_dbg(cntl->component->dev, + "%s: requested %u, offline %u offline_change %u, ret = %ldn", + __func__, online, ssr_entry->offline, + ssr_entry->offline_change, ret); + WCD_CNTL_MUTEX_UNLOCK(cntl->component, cntl->ssr_mutex); +} + +static ssize_t wdsp_ssr_entry_read(struct snd_info_entry *entry, + void *file_priv_data, struct file *file, + char __user *buf, size_t count, loff_t pos) +{ + int len = 0; + char buffer[WCD_PROCFS_ENTRY_MAX_LEN]; + struct wcd_dsp_cntl *cntl; + struct wdsp_ssr_entry *ssr_entry; + ssize_t ret; + u8 offline; + + cntl = (struct wcd_dsp_cntl *) entry->private_data; + if (!cntl) { + pr_err("%s: Invalid private data for SSR procfs entry\n", + __func__); + return -EINVAL; + } + + ssr_entry = &cntl->ssr_entry; + + WCD_CNTL_MUTEX_LOCK(cntl->component, cntl->ssr_mutex); + offline = ssr_entry->offline; + /* Make sure the read is complete */ + rmb(); + dev_dbg(cntl->component->dev, "%s: offline = %s\n", __func__, + offline ? "true" : "false"); + len = snprintf(buffer, sizeof(buffer), "%s\n", + offline ? "OFFLINE" : "ONLINE"); + ret = simple_read_from_buffer(buf, count, &pos, buffer, len); + WCD_CNTL_MUTEX_UNLOCK(cntl->component, cntl->ssr_mutex); + + return ret; +} + +static unsigned int wdsp_ssr_entry_poll(struct snd_info_entry *entry, + void *private_data, struct file *file, + poll_table *wait) +{ + struct wcd_dsp_cntl *cntl; + struct wdsp_ssr_entry *ssr_entry; + unsigned int ret = 0; + + if (!entry || !entry->private_data) { + pr_err("%s: %s is NULL\n", __func__, + (!entry) ? "entry" : "private_data"); + return -EINVAL; + } + + cntl = (struct wcd_dsp_cntl *) entry->private_data; + ssr_entry = &cntl->ssr_entry; + + dev_dbg(cntl->component->dev, "%s: Poll wait, offline = %u\n", + __func__, ssr_entry->offline); + poll_wait(file, &ssr_entry->offline_poll_wait, wait); + dev_dbg(cntl->component->dev, "%s: Woken up Poll wait, offline = %u\n", + __func__, ssr_entry->offline); + + WCD_CNTL_MUTEX_LOCK(cntl->component, cntl->ssr_mutex); + if (xchg(&ssr_entry->offline_change, 0)) + ret = POLLIN | POLLPRI | POLLRDNORM; + dev_dbg(cntl->component->dev, "%s: ret (%d) from poll_wait\n", + __func__, ret); + WCD_CNTL_MUTEX_UNLOCK(cntl->component, cntl->ssr_mutex); + + return ret; +} + +static struct snd_info_entry_ops wdsp_ssr_entry_ops = { + .read = wdsp_ssr_entry_read, + .poll = wdsp_ssr_entry_poll, +}; + +static int wcd_cntl_cpe_fll_calibrate(struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + int ret = 0, retry = 0; + u8 cal_lsb, cal_msb; + u8 lock_det; + + /* Make sure clocks are gated */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPE_CTL, + 0x05, 0x00); + + /* Enable CPE FLL reference clock */ + snd_soc_component_update_bits(component, WCD934X_CLK_SYS_MCLK2_PRG1, + 0x80, 0x80); + + snd_soc_component_update_bits(component, WCD934X_CPE_FLL_USER_CTL_5, + 0xF3, 0x13); + snd_soc_component_write(component, WCD934X_CPE_FLL_L_VAL_CTL_0, 0x50); + + /* Disable CPAR reset and Enable CPAR clk */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CTL, + 0x02, 0x02); + + /* Write calibration l-value based on cdc clk rate */ + if (cntl->clk_rate == 9600000) { + cal_lsb = 0x6d; + cal_msb = 0x00; + } else { + cal_lsb = 0x56; + cal_msb = 0x00; + } + snd_soc_component_write(component, WCD934X_CPE_FLL_USER_CTL_6, cal_lsb); + snd_soc_component_write(component, WCD934X_CPE_FLL_USER_CTL_7, cal_msb); + + /* FLL mode to follow power up sequence */ + snd_soc_component_update_bits(component, WCD934X_CPE_FLL_FLL_MODE, + 0x60, 0x00); + + /* HW controlled CPE FLL */ + snd_soc_component_update_bits(component, WCD934X_CPE_FLL_FLL_MODE, + 0x80, 0x80); + + /* Force on CPE FLL */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CFG, + 0x04, 0x04); + + do { + /* Time for FLL calibration to complete */ + usleep_range(1000, 1100); + lock_det = snd_soc_component_read32( + component, WCD934X_CPE_FLL_STATUS_3); + retry++; + } while (!(lock_det & 0x01) && + retry <= WCD_CPE_FLL_MAX_RETRIES); + + if (!(lock_det & 0x01)) { + dev_err(component->dev, "%s: lock detect not set, 0x%02x\n", + __func__, lock_det); + ret = -EIO; + goto err_lock_det; + } + + snd_soc_component_update_bits(component, WCD934X_CPE_FLL_FLL_MODE, + 0x60, 0x20); + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CFG, + 0x04, 0x00); + return ret; + +err_lock_det: + /* Undo the register settings */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CFG, + 0x04, 0x00); + snd_soc_component_update_bits(component, WCD934X_CPE_FLL_FLL_MODE, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CTL, + 0x02, 0x00); + return ret; +} + +static void wcd_cntl_config_cpar(struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + u8 nom_lo, nom_hi, svs2_lo, svs2_hi; + + /* Configure CPAR */ + nom_hi = svs2_hi = 0; + if (cntl->clk_rate == 9600000) { + nom_lo = 0x90; + svs2_lo = 0x50; + } else { + nom_lo = 0x70; + svs2_lo = 0x3e; + } + + snd_soc_component_write(component, WCD934X_TEST_DEBUG_LVAL_NOM_LOW, + nom_lo); + snd_soc_component_write(component, WCD934X_TEST_DEBUG_LVAL_NOM_HIGH, + nom_hi); + snd_soc_component_write(component, WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW, + svs2_lo); + snd_soc_component_write(component, + WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH, + svs2_hi); + + snd_soc_component_update_bits(component, WCD934X_CPE_SS_PWR_CPEFLL_CTL, + 0x03, 0x03); +} + +static int wcd_cntl_cpe_fll_ctrl(struct wcd_dsp_cntl *cntl, + bool enable) +{ + struct snd_soc_component *component = cntl->component; + int ret = 0; + + if (enable) { + ret = wcd_cntl_cpe_fll_calibrate(cntl); + if (ret < 0) { + dev_err(component->dev, + "%s: cpe_fll_cal failed, err = %d\n", + __func__, ret); + goto done; + } + + wcd_cntl_config_cpar(cntl); + + /* Enable AHB CLK and CPE CLK*/ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPE_CTL, + 0x05, 0x05); + } else { + /* Disable AHB CLK and CPE CLK */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPE_CTL, + 0x05, 0x00); + /* Reset the CPAR mode for CPE FLL */ + snd_soc_component_write(component, WCD934X_CPE_FLL_FLL_MODE, + 0x20); + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_CPAR_CFG, + 0x04, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_CPAR_CTL, + 0x02, 0x00); + } +done: + return ret; +} + +static int wcd_cntl_clocks_enable(struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + int ret; + + WCD_CNTL_MUTEX_LOCK(component, cntl->clk_mutex); + /* Enable codec clock */ + if (cntl->cdc_cb && cntl->cdc_cb->cdc_clk_en) + ret = cntl->cdc_cb->cdc_clk_en(component, true); + else + ret = -EINVAL; + + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to enable cdc clk, err = %d\n", + __func__, ret); + goto done; + } + /* Pull CPAR out of reset */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CTL, + 0x04, 0x00); + + /* Configure and Enable CPE FLL clock */ + ret = wcd_cntl_cpe_fll_ctrl(cntl, true); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to enable cpe clk, err = %d\n", + __func__, ret); + goto err_cpe_clk; + } + cntl->is_clk_enabled = true; + + /* Ungate the CPR clock */ + snd_soc_component_update_bits(component, WCD934X_CODEC_RPM_CLK_GATE, + 0x10, 0x00); +done: + WCD_CNTL_MUTEX_UNLOCK(component, cntl->clk_mutex); + return ret; + +err_cpe_clk: + if (cntl->cdc_cb && cntl->cdc_cb->cdc_clk_en) + cntl->cdc_cb->cdc_clk_en(component, false); + + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CTL, + 0x04, 0x04); + WCD_CNTL_MUTEX_UNLOCK(component, cntl->clk_mutex); + return ret; +} + +static int wcd_cntl_clocks_disable(struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + int ret = 0; + + WCD_CNTL_MUTEX_LOCK(component, cntl->clk_mutex); + if (!cntl->is_clk_enabled) { + dev_info(component->dev, "%s: clocks already disabled\n", + __func__); + goto done; + } + + /* Gate the CPR clock */ + snd_soc_component_update_bits(component, WCD934X_CODEC_RPM_CLK_GATE, + 0x10, 0x10); + + /* Disable CPE FLL clock */ + ret = wcd_cntl_cpe_fll_ctrl(cntl, false); + if (ret < 0) + dev_err(component->dev, + "%s: Failed to disable cpe clk, err = %d\n", + __func__, ret); + + /* + * Even if CPE FLL disable failed, go ahead and disable + * the codec clock + */ + if (cntl->cdc_cb && cntl->cdc_cb->cdc_clk_en) + ret = cntl->cdc_cb->cdc_clk_en(component, false); + else + ret = -EINVAL; + + cntl->is_clk_enabled = false; + + /* Put CPAR in reset */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPAR_CTL, + 0x04, 0x04); +done: + WCD_CNTL_MUTEX_UNLOCK(component, cntl->clk_mutex); + return ret; +} + +static void wcd_cntl_cpar_ctrl(struct wcd_dsp_cntl *cntl, + bool enable) +{ + struct snd_soc_component *component = cntl->component; + + if (enable) + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_CPAR_CTL, 0x03, 0x03); + else + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_CPAR_CTL, 0x03, 0x00); +} + +static int wcd_cntl_enable_memory(struct wcd_dsp_cntl *cntl, + enum wcd_mem_type mem_type) +{ + struct snd_soc_component *component = cntl->component; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + int loop_cnt = 0; + u8 status; + int ret = 0; + + + switch (mem_type) { + + case WCD_MEM_TYPE_ALWAYS_ON: + + /* 512KB of always on region */ + wcd9xxx_slim_write_repeat(wcd9xxx, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0, + ARRAY_SIZE(mem_enable_values), + mem_enable_values); + wcd9xxx_slim_write_repeat(wcd9xxx, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1, + ARRAY_SIZE(mem_enable_values), + mem_enable_values); + break; + + case WCD_MEM_TYPE_SWITCHABLE: + + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL, + 0x04, 0x00); + snd_soc_component_update_bits(component, + WCD934X_TEST_DEBUG_MEM_CTRL, + 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL, + 0x01, 0x01); + do { + loop_cnt++; + /* Time to enable the power domain for memory */ + usleep_range(100, 150); + status = snd_soc_component_read32(component, + WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL); + } while ((status & 0x02) != 0x02 && + loop_cnt != WCD_MEM_ENABLE_MAX_RETRIES); + + if ((status & 0x02) != 0x02) { + dev_err(cntl->component->dev, + "%s: power domain not enabled, status = 0x%02x\n", + __func__, status); + ret = -EIO; + goto done; + } + + /* Rest of the memory */ + wcd9xxx_slim_write_repeat(wcd9xxx, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2, + ARRAY_SIZE(mem_enable_values), + mem_enable_values); + wcd9xxx_slim_write_repeat(wcd9xxx, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3, + ARRAY_SIZE(mem_enable_values), + mem_enable_values); + + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN, + 0x05); + break; + + default: + dev_err(cntl->component->dev, "%s: Invalid mem_type %d\n", + __func__, mem_type); + ret = -EINVAL; + break; + } +done: + /* Make sure Deep sleep of memories is enabled for all banks */ + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xFF); + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0F); + + return ret; +} + +static void wcd_cntl_disable_memory(struct wcd_dsp_cntl *cntl, + enum wcd_mem_type mem_type) +{ + struct snd_soc_component *component = cntl->component; + u8 val; + + switch (mem_type) { + case WCD_MEM_TYPE_ALWAYS_ON: + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1, + 0xFF); + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0, + 0xFF); + break; + case WCD_MEM_TYPE_SWITCHABLE: + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3, + 0xFF); + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2, + 0xFF); + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN, + 0x07); + + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL, + 0x01, 0x00); + val = snd_soc_component_read32(component, + WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL); + if (val & 0x02) + dev_err(component->dev, + "%s: Disable switchable failed, val = 0x%02x", + __func__, val); + + snd_soc_component_update_bits(component, + WCD934X_TEST_DEBUG_MEM_CTRL, + 0x80, 0x00); + break; + default: + dev_err(cntl->component->dev, "%s: Invalid mem_type %d\n", + __func__, mem_type); + break; + } + + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xFF); + snd_soc_component_write(component, + WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0F); +} + +static void wcd_cntl_do_shutdown(struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + + /* Disable WDOG */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_WDOG_CFG, + 0x3F, 0x01); + + /* Put WDSP in reset state */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPE_CTL, + 0x02, 0x00); + + /* If DSP transitions from boot to shutdown, then vote for SVS */ + if (cntl->is_wdsp_booted) + cntl->cdc_cb->cdc_vote_svs(component, true); + cntl->is_wdsp_booted = false; +} + +static int wcd_cntl_do_boot(struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + int ret = 0; + + /* + * Debug mode is set from debugfs file node. If debug_mode + * is set, then do not configure the watchdog timer. This + * will be required for debugging the DSP firmware. + */ + if (cntl->debug_mode) { + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_WDOG_CFG, + 0x3F, 0x01); + } else { + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_WDOG_CFG, + 0x3F, 0x21); + } + + /* Make sure all the error interrupts are cleared */ + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A, + 0xFF); + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B, + 0xFF); + + reinit_completion(&cntl->boot_complete); + + /* Remove WDSP out of reset */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_CPE_CTL, + 0x02, 0x02); + + /* + * In debug mode, DSP may not boot up normally, + * wait indefinitely for DSP to boot. + */ + if (cntl->debug_mode) { + wait_for_completion(&cntl->boot_complete); + dev_dbg(component->dev, "%s: WDSP booted in dbg mode\n", + __func__); + cntl->is_wdsp_booted = true; + goto done; + } + + /* Boot in normal mode */ + ret = wait_for_completion_timeout(&cntl->boot_complete, + msecs_to_jiffies(WCD_DSP_BOOT_TIMEOUT_MS)); + if (!ret) { + dev_err(component->dev, "%s: WDSP boot timed out\n", + __func__); + if (cntl->dbg_dmp_enable) + wcd_cntl_collect_debug_dumps(cntl, true); + ret = -ETIMEDOUT; + goto err_boot; + } else { + /* + * Re-initialize the return code to 0, as in success case, + * it will hold the remaining time for completion timeout + */ + ret = 0; + } + + dev_dbg(component->dev, "%s: WDSP booted in normal mode\n", __func__); + cntl->is_wdsp_booted = true; + + /* Enable WDOG */ + snd_soc_component_update_bits(component, WCD934X_CPE_SS_WDOG_CFG, + 0x10, 0x10); +done: + /* If dsp booted up, then remove vote on SVS */ + if (cntl->is_wdsp_booted) + cntl->cdc_cb->cdc_vote_svs(component, false); + + return ret; +err_boot: + /* call shutdown to perform cleanup */ + wcd_cntl_do_shutdown(cntl); + return ret; +} + +static irqreturn_t wcd_cntl_ipc_irq(int irq, void *data) +{ + struct wcd_dsp_cntl *cntl = data; + int ret; + + complete(&cntl->boot_complete); + + if (cntl->m_dev && cntl->m_ops && + cntl->m_ops->signal_handler) + ret = cntl->m_ops->signal_handler(cntl->m_dev, WDSP_IPC1_INTR, + NULL); + else + ret = -EINVAL; + + if (ret < 0) + dev_err(cntl->component->dev, + "%s: Failed to handle irq %d\n", __func__, irq); + + return IRQ_HANDLED; +} + +static irqreturn_t wcd_cntl_err_irq(int irq, void *data) +{ + struct wcd_dsp_cntl *cntl = data; + struct snd_soc_component *component = cntl->component; + struct wdsp_err_signal_arg arg; + u16 status = 0; + u8 reg_val; + int rc, ret = 0; + + reg_val = snd_soc_component_read32(component, + WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A); + status = status | reg_val; + + reg_val = snd_soc_component_read32(component, + WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B); + status = status | (reg_val << 8); + + dev_info(component->dev, "%s: error interrupt status = 0x%x\n", + __func__, status); + + if ((status & cntl->irqs.fatal_irqs) && + (cntl->m_dev && cntl->m_ops && cntl->m_ops->signal_handler)) { + /* + * If WDSP SSR happens, skip collecting debug dumps. + * If debug dumps collecting happens first, WDSP_ERR_INTR + * will be blocked in signal_handler and get processed later. + */ + rc = WCD_CNTL_SET_ERR_IRQ_FLAG(cntl); + arg.mem_dumps_enabled = cntl->ramdump_enable; + arg.remote_start_addr = WCD_934X_RAMDUMP_START_ADDR; + arg.dump_size = WCD_934X_RAMDUMP_SIZE; + ret = cntl->m_ops->signal_handler(cntl->m_dev, WDSP_ERR_INTR, + &arg); + if (ret < 0) + dev_err(cntl->component->dev, + "%s: Failed to handle fatal irq 0x%x\n", + __func__, status & cntl->irqs.fatal_irqs); + wcd_cntl_change_online_state(cntl, 0); + if (rc == 0) + WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl); + } else { + dev_err(cntl->component->dev, "%s: Invalid signal_handler\n", + __func__); + } + + return IRQ_HANDLED; +} + +static int wcd_control_handler(struct device *dev, void *priv_data, + enum wdsp_event_type event, void *data) +{ + struct wcd_dsp_cntl *cntl = priv_data; + struct snd_soc_component *component = cntl->component; + int ret = 0; + + switch (event) { + case WDSP_EVENT_POST_INIT: + case WDSP_EVENT_POST_DLOAD_CODE: + case WDSP_EVENT_DLOAD_FAILED: + case WDSP_EVENT_POST_SHUTDOWN: + + /* Disable CPAR */ + wcd_cntl_cpar_ctrl(cntl, false); + /* Disable all the clocks */ + ret = wcd_cntl_clocks_disable(cntl); + if (ret < 0) + dev_err(component->dev, + "%s: Failed to disable clocks, err = %d\n", + __func__, ret); + + if (event == WDSP_EVENT_POST_DLOAD_CODE) + /* Mark DSP online since code download is complete */ + wcd_cntl_change_online_state(cntl, 1); + break; + + case WDSP_EVENT_PRE_DLOAD_DATA: + case WDSP_EVENT_PRE_DLOAD_CODE: + + /* Enable all the clocks */ + ret = wcd_cntl_clocks_enable(cntl); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to enable clocks, err = %d\n", + __func__, ret); + goto done; + } + + /* Enable CPAR */ + wcd_cntl_cpar_ctrl(cntl, true); + + if (event == WDSP_EVENT_PRE_DLOAD_CODE) + wcd_cntl_enable_memory(cntl, WCD_MEM_TYPE_ALWAYS_ON); + else if (event == WDSP_EVENT_PRE_DLOAD_DATA) + wcd_cntl_enable_memory(cntl, WCD_MEM_TYPE_SWITCHABLE); + break; + + case WDSP_EVENT_DO_BOOT: + + ret = wcd_cntl_do_boot(cntl); + if (ret < 0) + dev_err(component->dev, + "%s: WDSP boot failed, err = %d\n", + __func__, ret); + break; + + case WDSP_EVENT_DO_SHUTDOWN: + + wcd_cntl_do_shutdown(cntl); + wcd_cntl_disable_memory(cntl, WCD_MEM_TYPE_SWITCHABLE); + break; + + default: + dev_dbg(component->dev, "%s: unhandled event %d\n", + __func__, event); + } + +done: + return ret; +} + +static int wcd_cntl_sysfs_init(char *dir, struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + int ret = 0; + + ret = kobject_init_and_add(&cntl->wcd_kobj, &wcd_cntl_ktype, + kernel_kobj, dir); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add kobject %s, err = %d\n", + __func__, dir, ret); + goto done; + } + + ret = sysfs_create_file(&cntl->wcd_kobj, &cntl_attr_boot.attr); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add wdsp_boot sysfs entry to %s\n", + __func__, dir); + goto fail_create_file; + } + + return ret; + +fail_create_file: + kobject_put(&cntl->wcd_kobj); +done: + return ret; +} + +static void wcd_cntl_sysfs_remove(struct wcd_dsp_cntl *cntl) +{ + sysfs_remove_file(&cntl->wcd_kobj, &cntl_attr_boot.attr); + kobject_put(&cntl->wcd_kobj); +} + +static void wcd_cntl_debugfs_init(char *dir, struct wcd_dsp_cntl *cntl) +{ + struct snd_soc_component *component = cntl->component; + + cntl->entry = debugfs_create_dir(dir, NULL); + if (IS_ERR_OR_NULL(dir)) { + dev_err(component->dev, "%s debugfs_create_dir failed for %s\n", + __func__, dir); + goto done; + } + + debugfs_create_u32("debug_mode", 0644, + cntl->entry, &cntl->debug_mode); + debugfs_create_bool("ramdump_enable", 0644, + cntl->entry, &cntl->ramdump_enable); + debugfs_create_bool("debug_dump_enable", 0644, + cntl->entry, &cntl->dbg_dmp_enable); +done: + return; +} + +static void wcd_cntl_debugfs_remove(struct wcd_dsp_cntl *cntl) +{ + if (cntl) + debugfs_remove(cntl->entry); +} + +static int wcd_miscdev_release(struct inode *inode, struct file *filep) +{ + struct wcd_dsp_cntl *cntl = container_of(filep->private_data, + struct wcd_dsp_cntl, miscdev); + if (!cntl->m_dev || !cntl->m_ops || + !cntl->m_ops->vote_for_dsp) { + dev_err(cntl->component->dev, + "%s: DSP not ready to boot\n", __func__); + return -EINVAL; + } + + /* Make sure the DSP users goes to zero upon closing dev node */ + while (cntl->boot_reqs > 0) { + cntl->m_ops->vote_for_dsp(cntl->m_dev, false); + cntl->boot_reqs--; + } + + return 0; +} + +static ssize_t wcd_miscdev_write(struct file *filep, const char __user *ubuf, + size_t count, loff_t *pos) +{ + struct wcd_dsp_cntl *cntl = container_of(filep->private_data, + struct wcd_dsp_cntl, miscdev); + char val[WCD_MISCDEV_CMD_MAX_LEN + 1]; + bool vote; + int ret = 0; + + memset(val, 0, WCD_MISCDEV_CMD_MAX_LEN + 1); + + if (count == 0 || count > WCD_MISCDEV_CMD_MAX_LEN) { + pr_err("%s: Invalid count = %zd\n", __func__, count); + ret = -EINVAL; + goto done; + } + + ret = copy_from_user(val, ubuf, count); + if (ret < 0) { + dev_err(cntl->component->dev, + "%s: copy_from_user failed, err = %d\n", + __func__, ret); + ret = -EFAULT; + goto done; + } + + if (val[0] == '1') { + cntl->boot_reqs++; + vote = true; + } else if (val[0] == '0') { + if (cntl->boot_reqs == 0) { + dev_err(cntl->component->dev, + "%s: WDSP already disabled\n", + __func__); + ret = -EINVAL; + goto done; + } + cntl->boot_reqs--; + vote = false; + } else if (!strcmp(val, "DEBUG_DUMP")) { + if (cntl->dbg_dmp_enable) { + dev_dbg(cntl->component->dev, + "%s: Collect dumps for debug use\n", __func__); + wcd_cntl_collect_debug_dumps(cntl, false); + } + /* + * simply ignore the request from userspace + * if dbg_dump_enable is not set from debugfs + */ + goto done; + } else { + dev_err(cntl->component->dev, "%s: Invalid value %s\n", + __func__, val); + ret = -EINVAL; + goto done; + } + + dev_dbg(cntl->component->dev, + "%s: booted = %s, ref_cnt = %d, vote = %s\n", + __func__, cntl->is_wdsp_booted ? "true" : "false", + cntl->boot_reqs, vote ? "true" : "false"); + + if (cntl->m_dev && cntl->m_ops && + cntl->m_ops->vote_for_dsp) + ret = cntl->m_ops->vote_for_dsp(cntl->m_dev, vote); + else + ret = -EINVAL; +done: + if (ret) + return ret; + else + return count; +} + +static const struct file_operations wcd_miscdev_fops = { + .write = wcd_miscdev_write, + .release = wcd_miscdev_release, +}; + +static int wcd_cntl_miscdev_create(struct wcd_dsp_cntl *cntl) +{ + snprintf(cntl->miscdev_name, ARRAY_SIZE(cntl->miscdev_name), + "wcd_dsp%u_control", cntl->dsp_instance); + cntl->miscdev.minor = MISC_DYNAMIC_MINOR; + cntl->miscdev.name = cntl->miscdev_name; + cntl->miscdev.fops = &wcd_miscdev_fops; + cntl->miscdev.parent = cntl->component->dev; + + return misc_register(&cntl->miscdev); +} + +static void wcd_cntl_miscdev_destroy(struct wcd_dsp_cntl *cntl) +{ + misc_deregister(&cntl->miscdev); +} + +static int wcd_control_init(struct device *dev, void *priv_data) +{ + struct wcd_dsp_cntl *cntl = priv_data; + struct snd_soc_component *component = cntl->component; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res; + int ret; + bool err_irq_requested = false; + + ret = wcd9xxx_request_irq(core_res, + cntl->irqs.cpe_ipc1_irq, + wcd_cntl_ipc_irq, "CPE IPC1", + cntl); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to request cpe ipc irq, err = %d\n", + __func__, ret); + goto done; + } + + /* Unmask the fatal irqs */ + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, + ~(cntl->irqs.fatal_irqs & 0xFF)); + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, + ~((cntl->irqs.fatal_irqs >> 8) & 0xFF)); + + /* + * CPE ERR irq is used only for error reporting from WCD DSP, + * even if this request fails, DSP can be function normally. + * Continuing with init even if the CPE ERR irq request fails. + */ + if (wcd9xxx_request_irq(core_res, cntl->irqs.cpe_err_irq, + wcd_cntl_err_irq, "CPE ERR", cntl)) + dev_info(component->dev, "%s: Failed request_irq(cpe_err_irq)", + __func__); + else + err_irq_requested = true; + + + /* Enable all the clocks */ + ret = wcd_cntl_clocks_enable(cntl); + if (ret < 0) { + dev_err(component->dev, "%s: Failed to enable clocks, err = %d\n", + __func__, ret); + goto err_clk_enable; + } + wcd_cntl_cpar_ctrl(cntl, true); + + return 0; + +err_clk_enable: + /* Mask all error interrupts */ + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, + 0xFF); + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, + 0xFF); + + /* Free the irq's requested */ + wcd9xxx_free_irq(core_res, cntl->irqs.cpe_ipc1_irq, cntl); + + if (err_irq_requested) + wcd9xxx_free_irq(core_res, cntl->irqs.cpe_err_irq, cntl); +done: + return ret; +} + +static int wcd_control_deinit(struct device *dev, void *priv_data) +{ + struct wcd_dsp_cntl *cntl = priv_data; + struct snd_soc_component *component = cntl->component; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res; + + wcd_cntl_clocks_disable(cntl); + wcd_cntl_cpar_ctrl(cntl, false); + + /* Mask all error interrupts */ + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, + 0xFF); + snd_soc_component_write(component, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, + 0xFF); + + /* Free the irq's requested */ + wcd9xxx_free_irq(core_res, cntl->irqs.cpe_err_irq, cntl); + wcd9xxx_free_irq(core_res, cntl->irqs.cpe_ipc1_irq, cntl); + + return 0; +} + +static struct wdsp_cmpnt_ops control_ops = { + .init = wcd_control_init, + .deinit = wcd_control_deinit, + .event_handler = wcd_control_handler, +}; + +static int wcd_ctrl_component_bind(struct device *dev, + struct device *master, + void *data) +{ + struct wcd_dsp_cntl *cntl; + struct snd_soc_component *component; + struct snd_card *card; + struct snd_info_entry *entry; + char proc_name[WCD_PROCFS_ENTRY_MAX_LEN]; + char wcd_cntl_dir_name[WCD_CNTL_DIR_NAME_LEN_MAX]; + int ret = 0; + + if (!dev || !master || !data) { + pr_err("%s: Invalid parameters\n", __func__); + return -EINVAL; + } + + cntl = tavil_get_wcd_dsp_cntl(dev); + if (!cntl) { + dev_err(dev, "%s: Failed to get cntl reference\n", + __func__); + return -EINVAL; + } + + cntl->m_dev = master; + cntl->m_ops = data; + + if (!cntl->m_ops->register_cmpnt_ops) { + dev_err(dev, "%s: invalid master callback register_cmpnt_ops\n", + __func__); + ret = -EINVAL; + goto done; + } + + ret = cntl->m_ops->register_cmpnt_ops(master, dev, cntl, &control_ops); + if (ret) { + dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n", + __func__, ret); + goto done; + } + + ret = wcd_cntl_miscdev_create(cntl); + if (ret < 0) { + dev_err(dev, "%s: misc dev register failed, err = %d\n", + __func__, ret); + goto done; + } + + snprintf(wcd_cntl_dir_name, WCD_CNTL_DIR_NAME_LEN_MAX, + "%s%d", "wdsp", cntl->dsp_instance); + ret = wcd_cntl_sysfs_init(wcd_cntl_dir_name, cntl); + if (ret < 0) { + dev_err(dev, "%s: sysfs_init failed, err = %d\n", + __func__, ret); + goto err_sysfs_init; + } + + wcd_cntl_debugfs_init(wcd_cntl_dir_name, cntl); + + component = cntl->component; + card = component->card->snd_card; + snprintf(proc_name, WCD_PROCFS_ENTRY_MAX_LEN, "%s%d%s", "cpe", + cntl->dsp_instance, "_state"); + entry = snd_info_create_card_entry(card, proc_name, card->proc_root); + if (!entry) { + /* Do not treat this as Fatal error */ + dev_err(dev, "%s: Failed to create procfs entry %s\n", + __func__, proc_name); + goto err_sysfs_init; + } + + cntl->ssr_entry.entry = entry; + cntl->ssr_entry.offline = 1; + entry->size = WCD_PROCFS_ENTRY_MAX_LEN; + entry->content = SNDRV_INFO_CONTENT_DATA; + entry->c.ops = &wdsp_ssr_entry_ops; + entry->private_data = cntl; + ret = snd_info_register(entry); + if (ret < 0) { + dev_err(dev, "%s: Failed to register entry %s, err = %d\n", + __func__, proc_name, ret); + snd_info_free_entry(entry); + /* Let bind still happen even if creating the entry failed */ + ret = 0; + } +done: + return ret; + +err_sysfs_init: + wcd_cntl_miscdev_destroy(cntl); + return ret; +} + +static void wcd_ctrl_component_unbind(struct device *dev, + struct device *master, + void *data) +{ + struct wcd_dsp_cntl *cntl; + + if (!dev) { + pr_err("%s: Invalid device\n", __func__); + return; + } + + cntl = tavil_get_wcd_dsp_cntl(dev); + if (!cntl) { + dev_err(dev, "%s: Failed to get cntl reference\n", + __func__); + return; + } + + cntl->m_dev = NULL; + cntl->m_ops = NULL; + + /* Remove the sysfs entries */ + wcd_cntl_sysfs_remove(cntl); + + /* Remove the debugfs entries */ + wcd_cntl_debugfs_remove(cntl); + + /* Remove the misc device */ + wcd_cntl_miscdev_destroy(cntl); +} + +static const struct component_ops wcd_ctrl_component_ops = { + .bind = wcd_ctrl_component_bind, + .unbind = wcd_ctrl_component_unbind, +}; + +/* + * wcd_dsp_ssr_event: handle the SSR event raised by caller. + * @cntl: Handle to the wcd_dsp_cntl structure + * @event: The SSR event to be handled + * + * Notifies the manager driver about the SSR event. + * Returns 0 on success and negative error code on error. + */ +int wcd_dsp_ssr_event(struct wcd_dsp_cntl *cntl, enum cdc_ssr_event event) +{ + int ret = 0; + + if (!cntl) { + pr_err("%s: Invalid handle to control\n", __func__); + return -EINVAL; + } + + if (!cntl->m_dev || !cntl->m_ops || !cntl->m_ops->signal_handler) { + dev_err(cntl->component->dev, + "%s: Invalid signal_handler callback\n", __func__); + return -EINVAL; + } + + switch (event) { + case WCD_CDC_DOWN_EVENT: + ret = cntl->m_ops->signal_handler(cntl->m_dev, + WDSP_CDC_DOWN_SIGNAL, + NULL); + if (ret < 0) + dev_err(cntl->component->dev, + "%s: WDSP_CDC_DOWN_SIGNAL failed, err = %d\n", + __func__, ret); + wcd_cntl_change_online_state(cntl, 0); + break; + case WCD_CDC_UP_EVENT: + ret = cntl->m_ops->signal_handler(cntl->m_dev, + WDSP_CDC_UP_SIGNAL, + NULL); + if (ret < 0) + dev_err(cntl->component->dev, + "%s: WDSP_CDC_UP_SIGNAL failed, err = %d\n", + __func__, ret); + break; + default: + dev_err(cntl->component->dev, "%s: Invalid event %d\n", + __func__, event); + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL(wcd_dsp_ssr_event); + +/* + * wcd_dsp_cntl_init: Initialize the wcd-dsp control + * @component: pointer to the codec component handle + * @params: Parameters required to initialize wcd-dsp control + * + * This API is expected to be invoked by the codec driver and + * provide information essential for the wcd dsp control to + * configure and initialize the dsp + */ +void wcd_dsp_cntl_init(struct snd_soc_component *component, + struct wcd_dsp_params *params, + struct wcd_dsp_cntl **cntl) +{ + struct wcd_dsp_cntl *control; + int ret; + + if (!component || !params) { + pr_err("%s: Invalid handle to %s\n", __func__, + (!component) ? "component" : "params"); + *cntl = NULL; + return; + } + + if (*cntl) { + pr_err("%s: cntl is non NULL, maybe already initialized ?\n", + __func__); + return; + } + + if (!params->cb || !params->cb->cdc_clk_en || + !params->cb->cdc_vote_svs) { + dev_err(component->dev, + "%s: clk_en and vote_svs callbacks must be provided\n", + __func__); + return; + } + + control = kzalloc(sizeof(*control), GFP_KERNEL); + if (!(control)) + return; + + control->component = component; + control->clk_rate = params->clk_rate; + control->cdc_cb = params->cb; + control->dsp_instance = params->dsp_instance; + memcpy(&control->irqs, ¶ms->irqs, sizeof(control->irqs)); + init_completion(&control->boot_complete); + mutex_init(&control->clk_mutex); + mutex_init(&control->ssr_mutex); + init_waitqueue_head(&control->ssr_entry.offline_poll_wait); + WCD_CNTL_CLR_ERR_IRQ_FLAG(control); + + /* + * The default state of WDSP is in SVS mode. + * Vote for SVS now, the vote will be removed only + * after DSP is booted up. + */ + control->cdc_cb->cdc_vote_svs(component, true); + + /* + * If this is the last component needed by master to be ready, + * then component_bind will be called within the component_add. + * Hence, the data pointer should be assigned before component_add, + * so that we can access it during this component's bind call. + */ + *cntl = control; + ret = component_add(component->dev, &wcd_ctrl_component_ops); + if (ret) { + dev_err(component->dev, "%s: component_add failed, err = %d\n", + __func__, ret); + kfree(*cntl); + *cntl = NULL; + } +} +EXPORT_SYMBOL(wcd_dsp_cntl_init); + +/* + * wcd_dsp_cntl_deinit: De-initialize the wcd-dsp control + * @cntl: The struct wcd_dsp_cntl to de-initialize + * + * This API is intended to be invoked by the codec driver + * to de-initialize the wcd dsp control + */ +void wcd_dsp_cntl_deinit(struct wcd_dsp_cntl **cntl) +{ + struct wcd_dsp_cntl *control = *cntl; + struct snd_soc_component *component; + + /* If control is NULL, there is nothing to de-initialize */ + if (!control) + return; + component = control->component; + + /* + * Calling shutdown will cleanup all register states, + * irrespective of DSP was booted up or not. + */ + wcd_cntl_do_shutdown(control); + wcd_cntl_disable_memory(control, WCD_MEM_TYPE_SWITCHABLE); + wcd_cntl_disable_memory(control, WCD_MEM_TYPE_ALWAYS_ON); + + component_del(component->dev, &wcd_ctrl_component_ops); + + mutex_destroy(&control->clk_mutex); + mutex_destroy(&control->ssr_mutex); + kfree(*cntl); + *cntl = NULL; +} +EXPORT_SYMBOL(wcd_dsp_cntl_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsp-cntl.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsp-cntl.h new file mode 100644 index 0000000000..2bb55f99bb --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-dsp-cntl.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD934X_DSP_CNTL_H__ +#define __WCD934X_DSP_CNTL_H__ + +#include +#include +#include + +enum cdc_ssr_event { + WCD_CDC_DOWN_EVENT, + WCD_CDC_UP_EVENT, +}; + +struct wcd_dsp_cdc_cb { + /* Callback to enable codec clock */ + int (*cdc_clk_en)(struct snd_soc_component *component, bool enable); + /* Callback to vote and unvote for SVS2 mode */ + void (*cdc_vote_svs)(struct snd_soc_component *component, bool enable); +}; + +struct wcd_dsp_irq_info { + /* IPC interrupt */ + int cpe_ipc1_irq; + + /* CPE error summary interrupt */ + int cpe_err_irq; + + /* + * Bit mask to indicate which of the + * error interrupts are to be considered + * as fatal. + */ + u16 fatal_irqs; +}; + +struct wcd_dsp_params { + struct wcd_dsp_cdc_cb *cb; + struct wcd_dsp_irq_info irqs; + + /* Rate at which the codec clock operates */ + u32 clk_rate; + + /* + * Represents the dsp instance, will be used + * to create sysfs and debugfs entries with + * directory wdsp + */ + u32 dsp_instance; +}; + +struct wdsp_ssr_entry { + u8 offline; + u8 offline_change; + wait_queue_head_t offline_poll_wait; + struct snd_info_entry *entry; +}; + +struct wcd_dsp_cntl { + /* Handle to codec */ + struct snd_soc_component *component; + + /* Clk rate of the codec clock */ + u32 clk_rate; + + /* Callbacks to codec driver */ + const struct wcd_dsp_cdc_cb *cdc_cb; + + /* Completion to indicate WDSP boot done */ + struct completion boot_complete; + + struct wcd_dsp_irq_info irqs; + u32 dsp_instance; + + /* Sysfs entries related */ + int boot_reqs; + struct kobject wcd_kobj; + + /* Debugfs related */ + struct dentry *entry; + u32 debug_mode; + bool ramdump_enable; + bool dbg_dmp_enable; + + /* WDSP manager drivers data */ + struct device *m_dev; + struct wdsp_mgr_ops *m_ops; + + /* clk related */ + struct mutex clk_mutex; + bool is_clk_enabled; + + /* Keep track of WDSP boot status */ + bool is_wdsp_booted; + + /* SSR related */ + struct wdsp_ssr_entry ssr_entry; + struct mutex ssr_mutex; + + /* Misc device related */ + char miscdev_name[256]; + struct miscdevice miscdev; +#ifdef CONFIG_DEBUG_FS + /* Debug dump related */ + atomic_t err_irq_flag; +#endif +}; + +void wcd_dsp_cntl_init(struct snd_soc_component *component, + struct wcd_dsp_params *params, + struct wcd_dsp_cntl **cntl); +void wcd_dsp_cntl_deinit(struct wcd_dsp_cntl **cntl); +int wcd_dsp_ssr_event(struct wcd_dsp_cntl *cntl, enum cdc_ssr_event event); +#endif /* end __WCD_DSP_CONTROL_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-mbhc.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-mbhc.c new file mode 100644 index 0000000000..49d8820b88 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-mbhc.c @@ -0,0 +1,1187 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd934x.h" +#include "wcd934x-mbhc.h" +#include +#include "wcd934x_irq.h" +#include +#include +#include +#include +#include +#include + +#define TAVIL_ZDET_SUPPORTED true +/* Z value defined in milliohm */ +#define TAVIL_ZDET_VAL_32 32000 +#define TAVIL_ZDET_VAL_400 400000 +#define TAVIL_ZDET_VAL_1200 1200000 +#define TAVIL_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define TAVIL_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define TAVIL_ZDET_NUM_MEASUREMENTS 900 +#define TAVIL_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define TAVIL_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define TAVIL_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define TAVIL_MBHC_ZDET_CONST (86 * 16384) +#define TAVIL_MBHC_MOISTURE_RREF R_24_KOHM + +static struct wcd_mbhc_register + wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN", + WCD934X_ANA_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + WCD934X_ANA_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + WCD934X_ANA_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + WCD934X_ANA_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + WCD934X_ANA_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + WCD934X_ANA_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + WCD934X_ANA_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + WCD934X_ANA_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + WCD934X_ANA_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + WCD934X_ANA_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + WCD934X_MBHC_NEW_CTL_1, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + WCD934X_MBHC_NEW_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + WCD934X_ANA_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE", + WCD934X_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + WCD934X_ANA_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + WCD934X_ANA_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + WCD934X_ANA_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + WCD934X_HPH_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + WCD934X_ANA_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + WCD934X_ANA_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + WCD934X_ANA_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + WCD934X_ANA_MICB2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + WCD934X_HPH_CNP_WG_TIME, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + WCD934X_ANA_HPH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + WCD934X_ANA_HPH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + WCD934X_ANA_HPH, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + WCD934X_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL", + 0, 0, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", + WCD934X_MBHC_CTL_BCS, 0x02, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + WCD934X_MBHC_STATUS_SPARE_1, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + WCD934X_MBHC_NEW_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD934X_MBHC_NEW_FSM_STATUS, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD934X_HPH_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD934X_HPH_PA_CTL2, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", + WCD934X_HPH_L_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN", + WCD934X_HPH_R_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS", + WCD934X_INTR_PIN1_STATUS0, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS", + WCD934X_INTR_PIN1_STATUS0, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN", + WCD934X_MBHC_NEW_CTL_1, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD934X_MBHC_NEW_FSM_STATUS, + 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD934X_MBHC_NEW_FSM_STATUS, + 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD934X_MBHC_NEW_ADC_RESULT, + 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD934X_ANA_MICB2, 0x3F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE", + WCD934X_MBHC_NEW_CTL_1, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE", + WCD934X_MBHC_NEW_CTL_1, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN", + WCD934X_ANA_MBHC_ZDET, 0x02, 1, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = WCD934X_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = WCD934X_IRQ_HPH_PA_OCPL_FAULT, + .hph_right_ocp = WCD934X_IRQ_HPH_PA_OCPR_FAULT, +}; + + +static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = { + "cdc-vdd-mic-bias", +}; + +struct tavil_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static int tavil_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + return wcd9xxx_request_irq(core_res, irq, handler, name, data); +} + +static void tavil_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + if (enable) + wcd9xxx_enable_irq(core_res, irq); + else + wcd9xxx_disable_irq(core_res, irq); +} + +static int tavil_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + wcd9xxx_free_irq(core_res, irq, data); + return 0; +} + +static void tavil_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_CTL_1, + 0x80, 0x00); +} + +static int tavil_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read32(component, WCD934X_ANA_MBHC_RESULT_3) & + 0x7; +} + +static int tavil_enable_ext_mb_source(struct wcd_mbhc *mbhc, + bool turn_on) +{ + struct wcd934x_mbhc *wcd934x_mbhc; + struct snd_soc_component *component = mbhc->component; + struct wcd934x_on_demand_supply *supply; + int ret = 0; + + wcd934x_mbhc = container_of(mbhc, struct wcd934x_mbhc, wcd_mbhc); + + supply = &wcd934x_mbhc->on_demand_list[WCD934X_ON_DEMAND_MICBIAS]; + if (!supply->supply) { + dev_dbg(component->dev, "%s: warning supply not present ond for %s\n", + __func__, "onDemand Micbias"); + return ret; + } + + dev_dbg(component->dev, "%s turn_on: %d count: %d\n", __func__, turn_on, + supply->ondemand_supply_count); + + if (turn_on) { + if (!(supply->ondemand_supply_count)) { + ret = snd_soc_dapm_force_enable_pin( + snd_soc_component_get_dapm(component), + "MICBIAS_REGULATOR"); + snd_soc_dapm_sync( + snd_soc_component_get_dapm(component)); + } + supply->ondemand_supply_count++; + } else { + if (supply->ondemand_supply_count > 0) + supply->ondemand_supply_count--; + if (!(supply->ondemand_supply_count)) { + ret = snd_soc_dapm_disable_pin( + snd_soc_component_get_dapm(component), + "MICBIAS_REGULATOR"); + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + } + } + + if (ret) + dev_err(component->dev, "%s: Failed to %s external micbias source\n", + __func__, turn_on ? "enable" : "disabled"); + else + dev_dbg(component->dev, "%s: %s external micbias source\n", + __func__, turn_on ? "Enabled" : "Disabled"); + + return ret; +} + +static void tavil_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_ELECT, + 0x01, 0x00); +} + +static void tavil_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; + } + /* + * Tavil just needs one set of thresholds for button detection + * due to micbias voltage ramp to pullup upon button press. So + * btn_low and is_micbias are ignored and always program button + * thresholds using btn_high. + */ + for (i = 0; i < num_btn; i++) { + vth = ((btn_high[i] * 2) / 25) & 0x3F; + snd_soc_component_update_bits(component, + WCD934X_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 tavil_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + bool ret = 0; + + if (lock) + ret = wcd9xxx_lock_sleep(core_res); + else + wcd9xxx_unlock_sleep(core_res); + + return ret; +} + +static int tavil_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct wcd934x_mbhc *wcd934x_mbhc; + + wcd934x_mbhc = container_of(mbhc, struct wcd934x_mbhc, wcd_mbhc); + + if (enable) + return blocking_notifier_chain_register(&wcd934x_mbhc->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd934x_mbhc->notifier, nblock); +} + +static bool tavil_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + u8 val; + + if (micb_num == MIC_BIAS_2) { + val = (snd_soc_component_read32( + mbhc->component, WCD934X_ANA_MICB2) >> 6); + if (val == 0x01) + return true; + } + return false; +} + +static bool tavil_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + return (snd_soc_component_read32(component, WCD934X_ANA_HPH) & 0xC0) ? + true : false; +} + +static void tavil_mbhc_hph_l_pull_up_control( + struct snd_soc_component *component, + enum mbhc_hs_pullup_iref pull_up_cur) +{ + /* Default pull up current to 2uA */ + if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA || + pull_up_cur == I_DEFAULT) + pull_up_cur = I_2P0_UA; + + dev_dbg(component->dev, "%s: HS pull up current:%d\n", + __func__, pull_up_cur); + + snd_soc_component_update_bits(component, + WCD934X_MBHC_NEW_PLUG_DETECT_CTL, + 0xC0, pull_up_cur << 6); +} + +static int tavil_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + int ret; + + /* + * If micbias is requested, make sure that there + * is vote to enable mclk + */ + if (req == MICB_ENABLE) + tavil_cdc_mclk_enable(component, true); + + ret = tavil_micbias_control(component, micb_num, req, false); + + /* + * Release vote for mclk while requesting for + * micbias disable + */ + if (req == MICB_DISABLE) + tavil_cdc_mclk_enable(component, false); + + return ret; +} + +static void tavil_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD934X_ANA_MICB2_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, WCD934X_ANA_MICB2_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, WCD934X_ANA_MICB2_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD934X_ANA_MICB2_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *tavil_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct wcd934x_mbhc *wcd934x_mbhc; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + wcd934x_mbhc = container_of(mbhc, struct wcd934x_mbhc, wcd_mbhc); + + if (!component) { + pr_err("%s: NULL component pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(wcd934x_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 tavil_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); + int rc, micb_mv; + + if (micb_num != MIC_BIAS_2) + return -EINVAL; + + /* + * If device tree micbias level is already above the minimum + * voltage needed to detect threshold microphone, then do + * not change the micbias, just return. + */ + if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) + return 0; + + micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv; + + rc = tavil_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + + return rc; +} + +static inline void tavil_mbhc_get_result_params(struct wcd9xxx *wcd9xxx, + s16 *d1_a, u16 noff, + int32_t *zdet) +{ + int i; + int val, val1; + s16 c1; + s32 x1, d1; + int32_t denom; + int minCode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 + }; + + regmap_update_bits(wcd9xxx->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < TAVIL_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd9xxx->regmap, WCD934X_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd9xxx->regmap, WCD934X_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(wcd9xxx->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = TAVIL_MBHC_GET_X1(val); + c1 = TAVIL_MBHC_GET_C1(val); + /* If ramp is not complete, give additional 5ms */ + if ((c1 < 2) && x1) + usleep_range(5000, 5050); + + if (!c1 || !x1) { + dev_dbg(wcd9xxx->dev, + "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", + __func__, c1, x1); + goto ramp_down; + } + d1 = d1_a[c1]; + denom = (x1 * d1) - (1 << (14 - noff)); + if (denom > 0) + *zdet = (TAVIL_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = TAVIL_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(wcd9xxx->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + while (x1) { + regmap_bulk_read(wcd9xxx->regmap, + WCD934X_ANA_MBHC_RESULT_1, (u8 *)&val, 2); + x1 = TAVIL_MBHC_GET_X1(val); + i++; + if (i == TAVIL_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void tavil_mbhc_zdet_ramp(struct snd_soc_component *component, + struct tavil_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + int32_t zdet = 0; + + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_ZDET_ANA_CTL, + 0x70, zdet_param->ldo_ctl << 4); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_BTN5, 0xFC, + zdet_param->btn5); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_BTN6, 0xFC, + zdet_param->btn6); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_BTN7, 0xFC, + zdet_param->btn7); + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_ZDET_ANA_CTL, + 0x0F, zdet_param->noff); + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_ZDET, 0x80, 0x80); + dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + tavil_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_ZDET, 0x40, 0x40); + dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + tavil_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void tavil_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) +{ + s16 q1; + int q1_cal; + + if (*z_val < (TAVIL_ZDET_VAL_400/1000)) + q1 = snd_soc_component_read32(component, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read32(component, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 + (2 * flag_l_r)); + if (q1 & 0x80) + q1_cal = (10000 - ((q1 & 0x7F) * 25)); + else + q1_cal = (10000 + (q1 * 25)); + if (q1_cal > 0) + *z_val = ((*z_val) * 10000) / q1_cal; +} + +static void tavil_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + s16 reg0, reg1, reg2, reg3, reg4; + int32_t z1L, z1R, z1Ls; + int zMono, z_diff1, z_diff2; + bool is_fsm_disable = false; + struct tavil_mbhc_zdet_param zdet_param[] = { + {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */ + {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ + {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */ + {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */ + }; + struct tavil_mbhc_zdet_param *zdet_param_ptr = NULL; + s16 d1_a[][4] = { + {0, 30, 90, 30}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + }; + s16 *d1 = NULL; + + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + reg0 = snd_soc_component_read32(component, WCD934X_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read32(component, WCD934X_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read32(component, WCD934X_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read32(component, WCD934X_MBHC_CTL_CLK); + reg4 = snd_soc_component_read32(component, + WCD934X_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read32(component, WCD934X_ANA_MBHC_ELECT) & + 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_MECH, 0x01, 0x00); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + tavil_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + + if (!TAVIL_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) + goto left_ch_impedance; + + /* Second ramp for left ch */ + if (z1L < TAVIL_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1L > TAVIL_ZDET_VAL_400) && (z1L <= TAVIL_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1L > TAVIL_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + tavil_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + +left_ch_impedance: + if ((z1L == TAVIL_ZDET_FLOATING_IMPEDANCE) || + (z1L > TAVIL_ZDET_VAL_100K)) { + *zl = TAVIL_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1L/1000; + tavil_wcd_mbhc_qfuse_cal(component, zl, 0); + } + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", + __func__, *zl); + + /* Start of right impedance ramp and calculation */ + tavil_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if (TAVIL_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { + if (((z1R > TAVIL_ZDET_VAL_1200) && + (zdet_param_ptr->noff == 0x6)) || + ((*zl) != TAVIL_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* Second ramp for right ch */ + if (z1R < TAVIL_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1R > TAVIL_ZDET_VAL_400) && + (z1R <= TAVIL_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1R > TAVIL_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + tavil_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + } +right_ch_impedance: + if ((z1R == TAVIL_ZDET_FLOATING_IMPEDANCE) || + (z1R > TAVIL_ZDET_VAL_100K)) { + *zr = TAVIL_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R/1000; + tavil_wcd_mbhc_qfuse_cal(component, zr, 1); + } + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", + __func__, *zr); + + /* Mono/stereo detection */ + if ((*zl == TAVIL_ZDET_FLOATING_IMPEDANCE) && + (*zr == TAVIL_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == TAVIL_ZDET_FLOATING_IMPEDANCE) || + (*zr == TAVIL_ZDET_FLOATING_IMPEDANCE) || + ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) || + ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) { + dev_dbg(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, WCD934X_HPH_R_ATEST, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD934X_HPH_PA_CTL2, + 0x40, 0x01); + if (*zl < (TAVIL_ZDET_VAL_32/1000)) + tavil_mbhc_zdet_ramp(component, &zdet_param[0], + &z1Ls, NULL, d1); + else + tavil_mbhc_zdet_ramp(component, &zdet_param[1], + &z1Ls, NULL, d1); + snd_soc_component_update_bits(component, WCD934X_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD934X_HPH_R_ATEST, + 0x02, 0x00); + z1Ls /= 1000; + tavil_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, WCD934X_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD934X_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD934X_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD934X_MBHC_NEW_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD934X_MBHC_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd9xxx->regmap, + WCD934X_ANA_MBHC_ELECT, 0x80, 0x80); +} + +static void tavil_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_MECH, + 0x02, 0x00); + } +} + +static void tavil_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD934X_HPH_PA_CTL2, + 0x40, 0x40); + snd_soc_component_update_bits(component, WCD934X_HPH_PA_CTL2, + 0x10, 0x10); + } else { + snd_soc_component_update_bits(component, WCD934X_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD934X_HPH_PA_CTL2, + 0x10, 0x00); + } +} +static void tavil_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, WCD934X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + /* Donot enable moisture detection if jack type is NC */ + if (!mbhc->hphl_swh) { + dev_dbg(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); +} + +static bool tavil_hph_register_recovery(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(component); + + if (!wcd934x_mbhc) + return false; + + wcd934x_mbhc->is_hph_recover = false; + snd_soc_dapm_force_enable_pin(snd_soc_component_get_dapm(component), + "RESET_HPH_REGISTERS"); + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + + snd_soc_dapm_disable_pin(snd_soc_component_get_dapm(component), + "RESET_HPH_REGISTERS"); + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + + return wcd934x_mbhc->is_hph_recover; +} + +static void tavil_update_anc_state(struct snd_soc_component *component, + bool enable, int anc_num) +{ + if (enable) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_CFG0 + (20 * anc_num), + 0x10, 0x10); + else + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_CFG0 + (20 * anc_num), + 0x10, 0x00); +} + +static bool tavil_is_anc_on(struct wcd_mbhc *mbhc) +{ + bool anc_on = false; + u16 ancl, ancr; + + ancl = + (snd_soc_component_read32( + mbhc->component, WCD934X_CDC_RX1_RX_PATH_CFG0)) & 0x10; + ancr = + (snd_soc_component_read32( + mbhc->component, WCD934X_CDC_RX2_RX_PATH_CFG0)) & 0x10; + + anc_on = !!(ancl | ancr); + + return anc_on; +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = tavil_mbhc_request_irq, + .irq_control = tavil_mbhc_irq_control, + .free_irq = tavil_mbhc_free_irq, + .clk_setup = tavil_mbhc_clk_setup, + .map_btn_code_to_num = tavil_mbhc_btn_to_num, + .enable_mb_source = tavil_enable_ext_mb_source, + .mbhc_bias = tavil_mbhc_mbhc_bias_control, + .set_btn_thr = tavil_mbhc_program_btn_thr, + .lock_sleep = tavil_mbhc_lock_sleep, + .register_notifier = tavil_mbhc_register_notifier, + .micbias_enable_status = tavil_mbhc_micb_en_status, + .hph_pa_on_status = tavil_mbhc_hph_pa_on_status, + .hph_pull_up_control = tavil_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = tavil_mbhc_request_micbias, + .mbhc_micb_ramp_control = tavil_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = tavil_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = tavil_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = tavil_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = tavil_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = tavil_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = tavil_mbhc_moisture_config, + .hph_register_recovery = tavil_hph_register_recovery, + .update_anc_state = tavil_update_anc_state, + .is_anc_on = tavil_is_anc_on, +}; + +static struct regulator *tavil_codec_find_ondemand_regulator( + struct snd_soc_component *component, const char *name) +{ + int i; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); + + for (i = 0; i < wcd9xxx->num_of_supplies; ++i) { + if (pdata->regulator[i].ondemand && + wcd9xxx->supplies[i].supply && + !strcmp(wcd9xxx->supplies[i].supply, name)) + return wcd9xxx->supplies[i].consumer; + } + + dev_dbg(component->dev, "Warning: regulator not found:%s\n", + name); + return NULL; +} + +static int tavil_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(component); + struct wcd_mbhc *mbhc; + + if (!wcd934x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + mbhc = &wcd934x_mbhc->wcd_mbhc; + + ucontrol->value.integer.value[0] = (u32) mbhc->hph_type; + dev_dbg(component->dev, "%s: hph_type = %u\n", __func__, + mbhc->hph_type); + + return 0; +} + +static int tavil_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t zl, zr; + bool hphr; + struct soc_multi_mixer_control *mc; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(component); + + if (!wcd934x_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(&wcd934x_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, + tavil_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + tavil_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + tavil_hph_impedance_get, NULL), +}; + +/* + * tavil_mbhc_get_impedance: get impedance of headphone left and right channels + * @wcd934x_mbhc: handle to struct wcd934x_mbhc * + * @zl: handle to left-ch impedance + * @zr: handle to right-ch impedance + * return 0 for success or error code in case of failure + */ +int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (!wcd934x_mbhc) { + pr_err("%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + if (!zl || !zr) { + pr_err("%s: zl or zr null!\n", __func__); + return -EINVAL; + } + + return wcd_mbhc_get_impedance(&wcd934x_mbhc->wcd_mbhc, zl, zr); +} +EXPORT_SYMBOL(tavil_mbhc_get_impedance); + +/* + * tavil_mbhc_hs_detect: starts mbhc insertion/removal functionality + * @component: 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 tavil_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(component); + + if (!wcd934x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + return wcd_mbhc_start(&wcd934x_mbhc->wcd_mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(tavil_mbhc_hs_detect); + +/* + * tavil_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void tavil_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(component); + + if (!wcd934x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return; + } + wcd_mbhc_stop(&wcd934x_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL(tavil_mbhc_hs_detect_exit); + +/* + * tavil_mbhc_post_ssr_init: initialize mbhc for tavil post subsystem restart + * @mbhc: poniter to wcd934x_mbhc structure + * @component: handle to snd_soc_component * + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc, + struct snd_soc_component *component) +{ + int ret; + struct wcd_mbhc *wcd_mbhc; + + 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; + } + + tavil_mbhc_hs_detect_exit(component); + wcd_mbhc_deinit(wcd_mbhc); + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, TAVIL_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto done; + } + if (wcd_mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY) { + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_CTL_1, + 0x04, 0x04); + snd_soc_component_update_bits(component, WCD934X_MBHC_CTL_BCS, + 0x01, 0x01); + } + +done: + return ret; +} +EXPORT_SYMBOL(tavil_mbhc_post_ssr_init); + +/* + * tavil_mbhc_init: initialize mbhc for tavil + * @mbhc: poniter to wcd934x_mbhc struct pointer to store the configs + * @component: 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 tavil_mbhc_init(struct wcd934x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + struct regulator *supply; + struct wcd934x_mbhc *wcd934x_mbhc; + struct wcd_mbhc *wcd_mbhc; + int ret; + struct wcd9xxx_pdata *pdata; + + wcd934x_mbhc = devm_kzalloc(component->dev, sizeof(struct wcd934x_mbhc), + GFP_KERNEL); + if (!wcd934x_mbhc) + return -ENOMEM; + + wcd934x_mbhc->wcd9xxx = dev_get_drvdata(component->dev->parent); + wcd934x_mbhc->fw_data = fw_data; + BLOCKING_INIT_NOTIFIER_HEAD(&wcd934x_mbhc->notifier); + wcd_mbhc = &wcd934x_mbhc->wcd_mbhc; + if (wcd_mbhc == NULL) { + pr_err("%s: wcd_mbhc is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + + /* Setting default mbhc detection logic to ADC for Tavil */ + wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC; + + pdata = dev_get_platdata(component->dev->parent); + if (!pdata) { + dev_err(component->dev, "%s: pdata pointer is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + wcd_mbhc->micb_mv = pdata->micbias.micb2_mv; + + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, + &intr_ids, wcd_mbhc_registers, + TAVIL_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto err; + } + + supply = tavil_codec_find_ondemand_regulator(component, + on_demand_supply_name[WCD934X_ON_DEMAND_MICBIAS]); + if (supply) { + wcd934x_mbhc->on_demand_list[ + WCD934X_ON_DEMAND_MICBIAS].supply = + supply; + wcd934x_mbhc->on_demand_list[ + WCD934X_ON_DEMAND_MICBIAS].ondemand_supply_count = + 0; + } + + (*mbhc) = wcd934x_mbhc; + snd_soc_add_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)); + + if (wcd_mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY) { + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_CTL_1, + 0x04, 0x04); + snd_soc_component_update_bits(component, WCD934X_MBHC_CTL_BCS, + 0x01, 0x01); + } + + return 0; +err: + devm_kfree(component->dev, wcd934x_mbhc); + return ret; +} +EXPORT_SYMBOL(tavil_mbhc_init); + +/* + * tavil_mbhc_deinit: deinitialize mbhc for tavil + * @component: handle to snd_soc_component * + */ +void tavil_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(component); + + if (wcd934x_mbhc) { + wcd_mbhc_deinit(&wcd934x_mbhc->wcd_mbhc); + devm_kfree(component->dev, wcd934x_mbhc); + } +} +EXPORT_SYMBOL(tavil_mbhc_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-mbhc.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-mbhc.h new file mode 100644 index 0000000000..d474f6338b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-mbhc.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ +#ifndef __WCD934X_MBHC_H__ +#define __WCD934X_MBHC_H__ +#include + +enum wcd934x_on_demand_supply_name { + WCD934X_ON_DEMAND_MICBIAS = 0, + WCD934X_ON_DEMAND_SUPPLIES_MAX, +}; + +struct wcd934x_on_demand_supply { + struct regulator *supply; + int ondemand_supply_count; +}; + +struct wcd934x_mbhc { + struct wcd_mbhc wcd_mbhc; + struct blocking_notifier_head notifier; + struct wcd934x_on_demand_supply on_demand_list[ + WCD934X_ON_DEMAND_SUPPLIES_MAX]; + struct wcd9xxx *wcd9xxx; + struct fw_info *fw_data; + bool mbhc_started; + bool is_hph_recover; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD934X_MBHC) +extern int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data); +extern void tavil_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern int tavil_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void tavil_mbhc_deinit(struct snd_soc_component *component); +extern int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc, + struct snd_soc_component *component); +extern int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, + uint32_t *zl, uint32_t *zr); +#else +static inline int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + return 0; +} +static inline void tavil_mbhc_hs_detect_exit( + struct snd_soc_component *component) +{ +} +static inline int tavil_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void tavil_mbhc_deinit(struct snd_soc_component *component) +{ +} +static inline int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc, + struct snd_soc_component *component) +{ + return 0; +} +static inline int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + +#endif /* __WCD934X_MBHC_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-regmap.c new file mode 100644 index 0000000000..a9642091a6 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-regmap.c @@ -0,0 +1,1947 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + + +static const struct reg_sequence wcd934x_1_1_defaults[] = { + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0, 0x01 }, + { WCD934X_BIAS_VBG_FINE_ADJ, 0x75 }, + { WCD934X_HPH_REFBUFF_LP_CTL, 0x0E }, + { WCD934X_EAR_DAC_CTL_ATEST, 0x08 }, + { WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x17 }, + { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 }, + { WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81 }, + { WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81 }, +}; + +static const struct reg_default wcd934x_defaults[] = { + { WCD934X_PAGE0_PAGE_REGISTER, 0x00 }, + { WCD934X_CODEC_RPM_CLK_BYPASS, 0x00 }, + { WCD934X_CODEC_RPM_CLK_GATE, 0x1f }, + { WCD934X_CODEC_RPM_CLK_MCLK_CFG, 0x00 }, + { WCD934X_CODEC_RPM_CLK_MCLK2_CFG, 0x02 }, + { WCD934X_CODEC_RPM_I2S_DSD_CLK_SEL, 0x00 }, + { WCD934X_CODEC_RPM_RST_CTL, 0x00 }, + { WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2, 0x08 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE3, 0x01 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x10 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_TEST0, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_TEST1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT3, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT4, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT5, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT6, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT7, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT8, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT10, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT11, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT12, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT13, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO, 0x0d }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_2, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_3, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL, 0xcc }, + { WCD934X_CHIP_TIER_CTRL_SLNQ_WAIT_STATE_CTL, 0xcc }, + { WCD934X_CHIP_TIER_CTRL_I2C_ACTIVE, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA, 0x00 }, + { WCD934X_DATA_HUB_RX0_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX1_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX2_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX3_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX4_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX5_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX6_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX7_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX0_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX1_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX2_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX3_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX4_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX5_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX6_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX7_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX8_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX9_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX10_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX14_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX15_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_TX0_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_TX1_0_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_TX1_1_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_0_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_1_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_2_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_3_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_CLKSRC_CTL, 0x00 }, + { WCD934X_DATA_HUB_I2S_COMMON_CTL, 0x00 }, + { WCD934X_DATA_HUB_I2S_0_TDM_CTL, 0x00 }, + { WCD934X_DATA_HUB_I2S_STATUS, 0x00 }, + { WCD934X_DMA_RDMA_CTL_0, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_0, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_0, 0xff }, + { WCD934X_DMA_RDMA_CTL_1, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_1, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_1, 0xff }, + { WCD934X_DMA_RDMA_CTL_2, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_2, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_2, 0xff }, + { WCD934X_DMA_RDMA_CTL_3, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_3, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_3, 0xff }, + { WCD934X_DMA_RDMA_CTL_4, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_4, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_4, 0xff }, + { WCD934X_DMA_RDMA4_PRT_CFG, 0x00 }, + { WCD934X_DMA_RDMA_SBTX0_7_CFG, 0x00 }, + { WCD934X_DMA_RDMA_SBTX8_11_CFG, 0x00 }, + { WCD934X_DMA_WDMA_CTL_0, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_0, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_0, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_0, 0x00 }, + { WCD934X_DMA_WDMA_CTL_1, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_1, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_1, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_1, 0x00 }, + { WCD934X_DMA_WDMA_CTL_2, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_2, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_2, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_2, 0x00 }, + { WCD934X_DMA_WDMA_CTL_3, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_3, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_3, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_3, 0x00 }, + { WCD934X_DMA_WDMA_CTL_4, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_4, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_4, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_4, 0x00 }, + { WCD934X_DMA_WDMA0_PRT_CFG, 0x00 }, + { WCD934X_DMA_WDMA3_PRT_CFG, 0x00 }, + { WCD934X_DMA_WDMA4_PRT0_3_CFG, 0x00 }, + { WCD934X_DMA_WDMA4_PRT4_7_CFG, 0x00 }, + { WCD934X_PAGE1_PAGE_REGISTER, 0x00 }, + { WCD934X_CPE_FLL_USER_CTL_0, 0x71 }, + { WCD934X_CPE_FLL_USER_CTL_1, 0x34 }, + { WCD934X_CPE_FLL_USER_CTL_2, 0x0b }, + { WCD934X_CPE_FLL_USER_CTL_3, 0x02 }, + { WCD934X_CPE_FLL_USER_CTL_4, 0x04 }, + { WCD934X_CPE_FLL_USER_CTL_5, 0x02 }, + { WCD934X_CPE_FLL_USER_CTL_6, 0x6e }, + { WCD934X_CPE_FLL_USER_CTL_7, 0x00 }, + { WCD934X_CPE_FLL_USER_CTL_8, 0x94 }, + { WCD934X_CPE_FLL_USER_CTL_9, 0x50 }, + { WCD934X_CPE_FLL_L_VAL_CTL_0, 0x53 }, + { WCD934X_CPE_FLL_L_VAL_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD934X_CPE_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD934X_CPE_FLL_CONFIG_CTL_0, 0x6b }, + { WCD934X_CPE_FLL_CONFIG_CTL_1, 0x05 }, + { WCD934X_CPE_FLL_CONFIG_CTL_2, 0x08 }, + { WCD934X_CPE_FLL_CONFIG_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_CONFIG_CTL_4, 0x10 }, + { WCD934X_CPE_FLL_TEST_CTL_0, 0x80 }, + { WCD934X_CPE_FLL_TEST_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_2, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_4, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_5, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_6, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_7, 0x33 }, + { WCD934X_CPE_FLL_FREQ_CTL_0, 0x00 }, + { WCD934X_CPE_FLL_FREQ_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_FREQ_CTL_2, 0x00 }, + { WCD934X_CPE_FLL_FREQ_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_0, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_2, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_FLL_MODE, 0x20 }, + { WCD934X_CPE_FLL_STATUS_0, 0x00 }, + { WCD934X_CPE_FLL_STATUS_1, 0x00 }, + { WCD934X_CPE_FLL_STATUS_2, 0x00 }, + { WCD934X_CPE_FLL_STATUS_3, 0x00 }, + { WCD934X_I2S_FLL_USER_CTL_0, 0x41 }, + { WCD934X_I2S_FLL_USER_CTL_1, 0x94 }, + { WCD934X_I2S_FLL_USER_CTL_2, 0x08 }, + { WCD934X_I2S_FLL_USER_CTL_3, 0x02 }, + { WCD934X_I2S_FLL_USER_CTL_4, 0x04 }, + { WCD934X_I2S_FLL_USER_CTL_5, 0x02 }, + { WCD934X_I2S_FLL_USER_CTL_6, 0x40 }, + { WCD934X_I2S_FLL_USER_CTL_7, 0x00 }, + { WCD934X_I2S_FLL_USER_CTL_8, 0x5f }, + { WCD934X_I2S_FLL_USER_CTL_9, 0x02 }, + { WCD934X_I2S_FLL_L_VAL_CTL_0, 0x40 }, + { WCD934X_I2S_FLL_L_VAL_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD934X_I2S_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD934X_I2S_FLL_CONFIG_CTL_0, 0x6b }, + { WCD934X_I2S_FLL_CONFIG_CTL_1, 0x05 }, + { WCD934X_I2S_FLL_CONFIG_CTL_2, 0x08 }, + { WCD934X_I2S_FLL_CONFIG_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_CONFIG_CTL_4, 0x30 }, + { WCD934X_I2S_FLL_TEST_CTL_0, 0x80 }, + { WCD934X_I2S_FLL_TEST_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_2, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_4, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_5, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_6, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_7, 0xff }, + { WCD934X_I2S_FLL_FREQ_CTL_0, 0x00 }, + { WCD934X_I2S_FLL_FREQ_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_FREQ_CTL_2, 0x00 }, + { WCD934X_I2S_FLL_FREQ_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_0, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_2, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_FLL_MODE, 0x00 }, + { WCD934X_I2S_FLL_STATUS_0, 0x00 }, + { WCD934X_I2S_FLL_STATUS_1, 0x00 }, + { WCD934X_I2S_FLL_STATUS_2, 0x00 }, + { WCD934X_I2S_FLL_STATUS_3, 0x00 }, + { WCD934X_SB_FLL_USER_CTL_0, 0x41 }, + { WCD934X_SB_FLL_USER_CTL_1, 0x94 }, + { WCD934X_SB_FLL_USER_CTL_2, 0x08 }, + { WCD934X_SB_FLL_USER_CTL_3, 0x02 }, + { WCD934X_SB_FLL_USER_CTL_4, 0x04 }, + { WCD934X_SB_FLL_USER_CTL_5, 0x02 }, + { WCD934X_SB_FLL_USER_CTL_6, 0x40 }, + { WCD934X_SB_FLL_USER_CTL_7, 0x00 }, + { WCD934X_SB_FLL_USER_CTL_8, 0x5e }, + { WCD934X_SB_FLL_USER_CTL_9, 0x01 }, + { WCD934X_SB_FLL_L_VAL_CTL_0, 0x40 }, + { WCD934X_SB_FLL_L_VAL_CTL_1, 0x00 }, + { WCD934X_SB_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD934X_SB_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD934X_SB_FLL_CONFIG_CTL_0, 0x6b }, + { WCD934X_SB_FLL_CONFIG_CTL_1, 0x05 }, + { WCD934X_SB_FLL_CONFIG_CTL_2, 0x08 }, + { WCD934X_SB_FLL_CONFIG_CTL_3, 0x00 }, + { WCD934X_SB_FLL_CONFIG_CTL_4, 0x10 }, + { WCD934X_SB_FLL_TEST_CTL_0, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_1, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_2, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_3, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_4, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_5, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_6, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_7, 0xff }, + { WCD934X_SB_FLL_FREQ_CTL_0, 0x00 }, + { WCD934X_SB_FLL_FREQ_CTL_1, 0x00 }, + { WCD934X_SB_FLL_FREQ_CTL_2, 0x00 }, + { WCD934X_SB_FLL_FREQ_CTL_3, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_0, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_1, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_2, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_3, 0x00 }, + { WCD934X_SB_FLL_FLL_MODE, 0x00 }, + { WCD934X_SB_FLL_STATUS_0, 0x00 }, + { WCD934X_SB_FLL_STATUS_1, 0x00 }, + { WCD934X_SB_FLL_STATUS_2, 0x00 }, + { WCD934X_SB_FLL_STATUS_3, 0x00 }, + { WCD934X_PAGE2_PAGE_REGISTER, 0x00 }, + { WCD934X_CPE_SS_CPE_CTL, 0x05 }, + { WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0, 0x01 }, + { WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1, 0x00 }, + { WCD934X_CPE_SS_PWR_CPEFLL_CTL, 0x02 }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0f }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE, 0x00 }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN, 0x07 }, + { WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL, 0x00 }, + { WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL, 0x20 }, + { WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL1, 0x00 }, + { WCD934X_CPE_SS_US_BUF_INT_PERIOD, 0x60 }, + { WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x13 }, + { WCD934X_CPE_SS_SVA_CFG, 0x41 }, + { WCD934X_CPE_SS_US_CFG, 0x00 }, + { WCD934X_CPE_SS_MAD_CTL, 0x00 }, + { WCD934X_CPE_SS_CPAR_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC0_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC1_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC2_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC_CFG, 0x80 }, + { WCD934X_CPE_SS_CPAR_CFG, 0x00 }, + { WCD934X_CPE_SS_WDOG_CFG, 0x01 }, + { WCD934X_CPE_SS_BACKUP_INT, 0x00 }, + { WCD934X_CPE_SS_STATUS, 0x00 }, + { WCD934X_CPE_SS_CPE_OCD_CFG, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, 0xff }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, 0x3f }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A, 0xff }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B, 0x3f }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1B, 0x00 }, + { WCD934X_SOC_MAD_MAIN_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_MAIN_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_3, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_4, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_5, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_6, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_7, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_8, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL, 0x40 }, + { WCD934X_SOC_MAD_ULTR_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_3, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_4, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_5, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_6, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_7, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_3, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_4, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_5, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_6, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_7, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_8, 0x00 }, + { WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR, 0x00 }, + { WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL, 0x00 }, + { WCD934X_SOC_MAD_INP_SEL, 0x00 }, + { WCD934X_PAGE4_PAGE_REGISTER, 0x00 }, + { WCD934X_INTR_CFG, 0x00 }, + { WCD934X_INTR_CLR_COMMIT, 0x00 }, + { WCD934X_INTR_PIN1_MASK0, 0xff }, + { WCD934X_INTR_PIN1_MASK1, 0xff }, + { WCD934X_INTR_PIN1_MASK2, 0xff }, + { WCD934X_INTR_PIN1_MASK3, 0xff }, + { WCD934X_INTR_PIN1_STATUS0, 0x00 }, + { WCD934X_INTR_PIN1_STATUS1, 0x00 }, + { WCD934X_INTR_PIN1_STATUS2, 0x00 }, + { WCD934X_INTR_PIN1_STATUS3, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR0, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR1, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR2, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR3, 0x00 }, + { WCD934X_INTR_PIN2_MASK3, 0xff }, + { WCD934X_INTR_PIN2_STATUS3, 0x00 }, + { WCD934X_INTR_PIN2_CLEAR3, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_MASK2, 0xff }, + { WCD934X_INTR_CPESS_SUMRY_MASK3, 0xff }, + { WCD934X_INTR_CPESS_SUMRY_STATUS2, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_STATUS3, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_CLEAR2, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_CLEAR3, 0x00 }, + { WCD934X_INTR_LEVEL0, 0x03 }, + { WCD934X_INTR_LEVEL1, 0xe0 }, + { WCD934X_INTR_LEVEL2, 0x94 }, + { WCD934X_INTR_LEVEL3, 0x80 }, + { WCD934X_INTR_BYPASS0, 0x00 }, + { WCD934X_INTR_BYPASS1, 0x00 }, + { WCD934X_INTR_BYPASS2, 0x00 }, + { WCD934X_INTR_BYPASS3, 0x00 }, + { WCD934X_INTR_SET0, 0x00 }, + { WCD934X_INTR_SET1, 0x00 }, + { WCD934X_INTR_SET2, 0x00 }, + { WCD934X_INTR_SET3, 0x00 }, + { WCD934X_INTR_CODEC_MISC_MASK, 0x7f }, + { WCD934X_INTR_CODEC_MISC_STATUS, 0x00 }, + { WCD934X_INTR_CODEC_MISC_CLEAR, 0x00 }, + { WCD934X_PAGE5_PAGE_REGISTER, 0x00 }, + { WCD934X_SLNQ_DIG_DEVICE, 0x49 }, + { WCD934X_SLNQ_DIG_REVISION, 0x01 }, + { WCD934X_SLNQ_DIG_H_COMMAND, 0x00 }, + { WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_MASTER_ADDRESS_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_MASTER_ADDRESS_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_SLAVE_ADDRESS_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_SLAVE_ADDRESS_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_MSB, 0x40 }, + { WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_MSB, 0x40 }, + { WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_MSB, 0x40 }, + { WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_COMM_CTL, 0x00 }, + { WCD934X_SLNQ_DIG_FRAME_CTRL, 0x01 }, + { WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH1_2, 0x77 }, + { WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH3_4, 0x77 }, + { WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH5, 0x70 }, + { WCD934X_SLNQ_DIG_SW_EVENT_RD, 0x00 }, + { WCD934X_SLNQ_DIG_SW_EVENT_CTRL, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_SELECT_1, 0x12 }, + { WCD934X_SLNQ_DIG_PDM_SELECT_2, 0x34 }, + { WCD934X_SLNQ_DIG_PDM_SELECT_3, 0x55 }, + { WCD934X_SLNQ_DIG_PDM_SAMPLING_FREQ, 0x01 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_CTL, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_SEL, 0x11 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_RAM_CNTRL, 0x01 }, + { WCD934X_SLNQ_DIG_SRAM_BANK, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_0, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_4, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_5, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_6, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_7, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_8, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_9, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_F, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_10, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_11, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_12, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_13, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_14, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_15, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_16, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_17, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_18, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_19, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1F, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_20, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_21, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_22, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_23, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_24, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_25, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_26, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_27, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_28, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_29, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2F, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_30, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_31, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_32, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_33, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_34, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_35, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_36, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_37, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_38, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_39, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3F, 0x00 }, + { WCD934X_SLNQ_DIG_TOP_CTRL1, 0x00 }, + { WCD934X_SLNQ_DIG_TOP_CTRL2, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_CTRL, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_MUTE_CTRL, 0x20 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_CTRL, 0x00 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_STATUS, 0x00 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_FS, 0x00 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_IN_SEL, 0x00 }, + { WCD934X_SLNQ_DIG_GPOUT_ENABLE, 0x00 }, + { WCD934X_SLNQ_DIG_GPOUT_VAL, 0x00 }, + { WCD934X_SLNQ_DIG_ANA_INTERRUPT_MASK, 0x00 }, + { WCD934X_SLNQ_DIG_ANA_INTERRUPT_STATUS, 0x00 }, + { WCD934X_SLNQ_DIG_ANA_INTERRUPT_CLR, 0x00 }, + { WCD934X_SLNQ_DIG_IP_TESTING, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNTRL, 0x0f }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNT, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNT_MSB, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNT_LSB, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK0, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK1, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK2, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK3, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK4, 0x1f }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS0, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS1, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS2, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS3, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS4, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR0, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR1, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR2, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR3, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR4, 0x00 }, + { WCD934X_ANA_PAGE_REGISTER, 0x00 }, + { WCD934X_ANA_BIAS, 0x00 }, + { WCD934X_ANA_RCO, 0x00 }, + { WCD934X_ANA_PAGE6_SPARE2, 0x00 }, + { WCD934X_ANA_PAGE6_SPARE3, 0x00 }, + { WCD934X_ANA_BUCK_CTL, 0x00 }, + { WCD934X_ANA_BUCK_STATUS, 0x00 }, + { WCD934X_ANA_RX_SUPPLIES, 0x00 }, + { WCD934X_ANA_HPH, 0x0c }, + { WCD934X_ANA_EAR, 0x00 }, + { WCD934X_ANA_LO_1_2, 0x3c }, + { WCD934X_ANA_MAD_SETUP, 0x01 }, + { WCD934X_ANA_AMIC1, 0x20 }, + { WCD934X_ANA_AMIC2, 0x00 }, + { WCD934X_ANA_AMIC3, 0x20 }, + { WCD934X_ANA_AMIC4, 0x00 }, + { WCD934X_ANA_MBHC_MECH, 0x39 }, + { WCD934X_ANA_MBHC_ELECT, 0x08 }, + { WCD934X_ANA_MBHC_ZDET, 0x00 }, + { WCD934X_ANA_MBHC_RESULT_1, 0x00 }, + { WCD934X_ANA_MBHC_RESULT_2, 0x00 }, + { WCD934X_ANA_MBHC_RESULT_3, 0x00 }, + { WCD934X_ANA_MBHC_BTN0, 0x00 }, + { WCD934X_ANA_MBHC_BTN1, 0x10 }, + { WCD934X_ANA_MBHC_BTN2, 0x20 }, + { WCD934X_ANA_MBHC_BTN3, 0x30 }, + { WCD934X_ANA_MBHC_BTN4, 0x40 }, + { WCD934X_ANA_MBHC_BTN5, 0x50 }, + { WCD934X_ANA_MBHC_BTN6, 0x60 }, + { WCD934X_ANA_MBHC_BTN7, 0x70 }, + { WCD934X_ANA_MICB1, 0x10 }, + { WCD934X_ANA_MICB2, 0x10 }, + { WCD934X_ANA_MICB2_RAMP, 0x00 }, + { WCD934X_ANA_MICB3, 0x10 }, + { WCD934X_ANA_MICB4, 0x10 }, + { WCD934X_ANA_VBADC, 0x00 }, + { WCD934X_BIAS_CTL, 0x28 }, + { WCD934X_BIAS_VBG_FINE_ADJ, 0x65 }, + { WCD934X_RCO_CTRL_1, 0x44 }, + { WCD934X_RCO_CTRL_2, 0x48 }, + { WCD934X_RCO_CAL, 0x00 }, + { WCD934X_RCO_CAL_1, 0x00 }, + { WCD934X_RCO_CAL_2, 0x00 }, + { WCD934X_RCO_TEST_CTRL, 0x00 }, + { WCD934X_RCO_CAL_OUT_1, 0x00 }, + { WCD934X_RCO_CAL_OUT_2, 0x00 }, + { WCD934X_RCO_CAL_OUT_3, 0x00 }, + { WCD934X_RCO_CAL_OUT_4, 0x00 }, + { WCD934X_RCO_CAL_OUT_5, 0x00 }, + { WCD934X_SIDO_MODE_1, 0x84 }, + { WCD934X_SIDO_MODE_2, 0xfe }, + { WCD934X_SIDO_MODE_3, 0xf6 }, + { WCD934X_SIDO_MODE_4, 0x56 }, + { WCD934X_SIDO_VCL_1, 0x00 }, + { WCD934X_SIDO_VCL_2, 0x6c }, + { WCD934X_SIDO_VCL_3, 0x44 }, + { WCD934X_SIDO_CCL_1, 0x57 }, + { WCD934X_SIDO_CCL_2, 0x92 }, + { WCD934X_SIDO_CCL_3, 0x35 }, + { WCD934X_SIDO_CCL_4, 0x61 }, + { WCD934X_SIDO_CCL_5, 0x6d }, + { WCD934X_SIDO_CCL_6, 0x60 }, + { WCD934X_SIDO_CCL_7, 0x6f }, + { WCD934X_SIDO_CCL_8, 0x6f }, + { WCD934X_SIDO_CCL_9, 0x6e }, + { WCD934X_SIDO_CCL_10, 0x26 }, + { WCD934X_SIDO_FILTER_1, 0x92 }, + { WCD934X_SIDO_FILTER_2, 0x54 }, + { WCD934X_SIDO_DRIVER_1, 0x77 }, + { WCD934X_SIDO_DRIVER_2, 0x55 }, + { WCD934X_SIDO_DRIVER_3, 0x55 }, + { WCD934X_SIDO_CAL_CODE_EXT_1, 0x9c }, + { WCD934X_SIDO_CAL_CODE_EXT_2, 0x82 }, + { WCD934X_SIDO_CAL_CODE_OUT_1, 0x00 }, + { WCD934X_SIDO_CAL_CODE_OUT_2, 0x00 }, + { WCD934X_SIDO_TEST_1, 0x00 }, + { WCD934X_SIDO_TEST_2, 0x00 }, + { WCD934X_MBHC_CTL_CLK, 0x30 }, + { WCD934X_MBHC_CTL_ANA, 0x00 }, + { WCD934X_MBHC_CTL_SPARE_1, 0x00 }, + { WCD934X_MBHC_CTL_SPARE_2, 0x00 }, + { WCD934X_MBHC_CTL_BCS, 0x00 }, + { WCD934X_MBHC_STATUS_SPARE_1, 0x00 }, + { WCD934X_MBHC_TEST_CTL, 0x00 }, + { WCD934X_VBADC_SUBBLOCK_EN, 0xde }, + { WCD934X_VBADC_IBIAS_FE, 0x58 }, + { WCD934X_VBADC_BIAS_ADC, 0x51 }, + { WCD934X_VBADC_FE_CTRL, 0x1c }, + { WCD934X_VBADC_ADC_REF, 0x20 }, + { WCD934X_VBADC_ADC_IO, 0x80 }, + { WCD934X_VBADC_ADC_SAR, 0xff }, + { WCD934X_VBADC_DEBUG, 0x00 }, + { WCD934X_LDOH_MODE, 0x2b }, + { WCD934X_LDOH_BIAS, 0x68 }, + { WCD934X_LDOH_STB_LOADS, 0x00 }, + { WCD934X_LDOH_SLOWRAMP, 0x50 }, + { WCD934X_MICB1_TEST_CTL_1, 0x1a }, + { WCD934X_MICB1_TEST_CTL_2, 0x18 }, + { WCD934X_MICB1_TEST_CTL_3, 0xa4 }, + { WCD934X_MICB2_TEST_CTL_1, 0x1a }, + { WCD934X_MICB2_TEST_CTL_2, 0x18 }, + { WCD934X_MICB2_TEST_CTL_3, 0xa4 }, + { WCD934X_MICB3_TEST_CTL_1, 0x1a }, + { WCD934X_MICB3_TEST_CTL_2, 0x18 }, + { WCD934X_MICB3_TEST_CTL_3, 0xa4 }, + { WCD934X_MICB4_TEST_CTL_1, 0x1a }, + { WCD934X_MICB4_TEST_CTL_2, 0x18 }, + { WCD934X_MICB4_TEST_CTL_3, 0xa4 }, + { WCD934X_TX_COM_ADC_VCM, 0x39 }, + { WCD934X_TX_COM_BIAS_ATEST, 0xc0 }, + { WCD934X_TX_COM_ADC_INT1_IB, 0x6f }, + { WCD934X_TX_COM_ADC_INT2_IB, 0x4f }, + { WCD934X_TX_COM_TXFE_DIV_CTL, 0x2e }, + { WCD934X_TX_COM_TXFE_DIV_START, 0x00 }, + { WCD934X_TX_COM_TXFE_DIV_STOP_9P6M, 0xc7 }, + { WCD934X_TX_COM_TXFE_DIV_STOP_12P288M, 0xff }, + { WCD934X_TX_1_2_TEST_EN, 0xcc }, + { WCD934X_TX_1_2_ADC_IB, 0x09 }, + { WCD934X_TX_1_2_ATEST_REFCTL, 0x0a }, + { WCD934X_TX_1_2_TEST_CTL, 0x38 }, + { WCD934X_TX_1_2_TEST_BLK_EN, 0xff }, + { WCD934X_TX_1_2_TXFE_CLKDIV, 0x00 }, + { WCD934X_TX_1_2_SAR1_ERR, 0x00 }, + { WCD934X_TX_1_2_SAR2_ERR, 0x00 }, + { WCD934X_TX_3_4_TEST_EN, 0xcc }, + { WCD934X_TX_3_4_ADC_IB, 0x09 }, + { WCD934X_TX_3_4_ATEST_REFCTL, 0x0a }, + { WCD934X_TX_3_4_TEST_CTL, 0x38 }, + { WCD934X_TX_3_4_TEST_BLK_EN, 0xff }, + { WCD934X_TX_3_4_TXFE_CLKDIV, 0x00 }, + { WCD934X_TX_3_4_SAR1_ERR, 0x00 }, + { WCD934X_TX_3_4_SAR2_ERR, 0x00 }, + { WCD934X_CLASSH_MODE_1, 0x40 }, + { WCD934X_CLASSH_MODE_2, 0x3a }, + { WCD934X_CLASSH_MODE_3, 0x00 }, + { WCD934X_CLASSH_CTRL_VCL_1, 0x70 }, + { WCD934X_CLASSH_CTRL_VCL_2, 0x82 }, + { WCD934X_CLASSH_CTRL_CCL_1, 0x31 }, + { WCD934X_CLASSH_CTRL_CCL_2, 0x80 }, + { WCD934X_CLASSH_CTRL_CCL_3, 0x80 }, + { WCD934X_CLASSH_CTRL_CCL_4, 0x51 }, + { WCD934X_CLASSH_CTRL_CCL_5, 0x00 }, + { WCD934X_CLASSH_BUCK_TMUX_A_D, 0x00 }, + { WCD934X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 }, + { WCD934X_CLASSH_SPARE, 0x00 }, + { WCD934X_FLYBACK_EN, 0x4e }, + { WCD934X_FLYBACK_VNEG_CTRL_1, 0x0b }, + { WCD934X_FLYBACK_VNEG_CTRL_2, 0x45 }, + { WCD934X_FLYBACK_VNEG_CTRL_3, 0x74 }, + { WCD934X_FLYBACK_VNEG_CTRL_4, 0x7f }, + { WCD934X_FLYBACK_VNEG_CTRL_5, 0x83 }, + { WCD934X_FLYBACK_VNEG_CTRL_6, 0x98 }, + { WCD934X_FLYBACK_VNEG_CTRL_7, 0xa9 }, + { WCD934X_FLYBACK_VNEG_CTRL_8, 0x68 }, + { WCD934X_FLYBACK_VNEG_CTRL_9, 0x64 }, + { WCD934X_FLYBACK_VNEGDAC_CTRL_1, 0xed }, + { WCD934X_FLYBACK_VNEGDAC_CTRL_2, 0xf0 }, + { WCD934X_FLYBACK_VNEGDAC_CTRL_3, 0xa6 }, + { WCD934X_FLYBACK_CTRL_1, 0x65 }, + { WCD934X_FLYBACK_TEST_CTL, 0x00 }, + { WCD934X_RX_AUX_SW_CTL, 0x00 }, + { WCD934X_RX_PA_AUX_IN_CONN, 0x00 }, + { WCD934X_RX_TIMER_DIV, 0x32 }, + { WCD934X_RX_OCP_CTL, 0x1f }, + { WCD934X_RX_OCP_COUNT, 0x77 }, + { WCD934X_RX_BIAS_EAR_DAC, 0xa0 }, + { WCD934X_RX_BIAS_EAR_AMP, 0xaa }, + { WCD934X_RX_BIAS_HPH_LDO, 0xa9 }, + { WCD934X_RX_BIAS_HPH_PA, 0xaa }, + { WCD934X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8a }, + { WCD934X_RX_BIAS_HPH_RDAC_LDO, 0x88 }, + { WCD934X_RX_BIAS_HPH_CNP1, 0x82 }, + { WCD934X_RX_BIAS_HPH_LOWPOWER, 0x82 }, + { WCD934X_RX_BIAS_DIFFLO_PA, 0x80 }, + { WCD934X_RX_BIAS_DIFFLO_REF, 0x88 }, + { WCD934X_RX_BIAS_DIFFLO_LDO, 0x88 }, + { WCD934X_RX_BIAS_SELO_DAC_PA, 0xa8 }, + { WCD934X_RX_BIAS_BUCK_RST, 0x08 }, + { WCD934X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 }, + { WCD934X_RX_BIAS_FLYB_ERRAMP, 0x40 }, + { WCD934X_RX_BIAS_FLYB_BUFF, 0xaa }, + { WCD934X_RX_BIAS_FLYB_MID_RST, 0x14 }, + { WCD934X_HPH_L_STATUS, 0x04 }, + { WCD934X_HPH_R_STATUS, 0x04 }, + { WCD934X_HPH_CNP_EN, 0x80 }, + { WCD934X_HPH_CNP_WG_CTL, 0x9a }, + { WCD934X_HPH_CNP_WG_TIME, 0x14 }, + { WCD934X_HPH_OCP_CTL, 0x28 }, + { WCD934X_HPH_AUTO_CHOP, 0x16 }, + { WCD934X_HPH_CHOP_CTL, 0x83 }, + { WCD934X_HPH_PA_CTL1, 0x46 }, + { WCD934X_HPH_PA_CTL2, 0x50 }, + { WCD934X_HPH_L_EN, 0x80 }, + { WCD934X_HPH_L_TEST, 0xe0 }, + { WCD934X_HPH_L_ATEST, 0x50 }, + { WCD934X_HPH_R_EN, 0x80 }, + { WCD934X_HPH_R_TEST, 0xe0 }, + { WCD934X_HPH_R_ATEST, 0x54 }, + { WCD934X_HPH_RDAC_CLK_CTL1, 0x99 }, + { WCD934X_HPH_RDAC_CLK_CTL2, 0x9b }, + { WCD934X_HPH_RDAC_LDO_CTL, 0x33 }, + { WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 }, + { WCD934X_HPH_REFBUFF_UHQA_CTL, 0xa8 }, + { WCD934X_HPH_REFBUFF_LP_CTL, 0x0a }, + { WCD934X_HPH_L_DAC_CTL, 0x00 }, + { WCD934X_HPH_R_DAC_CTL, 0x00 }, + { WCD934X_EAR_EN_REG, 0x60 }, + { WCD934X_EAR_CMBUFF, 0x05 }, + { WCD934X_EAR_ICTL, 0x40 }, + { WCD934X_EAR_EN_DBG_CTL, 0x00 }, + { WCD934X_EAR_CNP, 0xe0 }, + { WCD934X_EAR_DAC_CTL_ATEST, 0x00 }, + { WCD934X_EAR_STATUS_REG, 0x04 }, + { WCD934X_EAR_EAR_MISC, 0x28 }, + { WCD934X_DIFF_LO_MISC, 0x03 }, + { WCD934X_DIFF_LO_LO2_COMPANDER, 0x00 }, + { WCD934X_DIFF_LO_LO1_COMPANDER, 0x00 }, + { WCD934X_DIFF_LO_COMMON, 0x40 }, + { WCD934X_DIFF_LO_BYPASS_EN, 0x00 }, + { WCD934X_DIFF_LO_CNP, 0x20 }, + { WCD934X_DIFF_LO_CORE_OUT_PROG, 0xa0 }, + { WCD934X_DIFF_LO_LDO_OUT_PROG, 0x00 }, + { WCD934X_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x8b }, + { WCD934X_DIFF_LO_COM_PA_FREQ, 0xb0 }, + { WCD934X_DIFF_LO_RESERVED_REG, 0x60 }, + { WCD934X_DIFF_LO_LO1_STATUS_1, 0x00 }, + { WCD934X_DIFF_LO_LO1_STATUS_2, 0x00 }, + { WCD934X_ANA_NEW_PAGE_REGISTER, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH2, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH3, 0x00 }, + { WCD934X_SLNQ_ANA_EN, 0x02 }, + { WCD934X_SLNQ_ANA_STATUS, 0x00 }, + { WCD934X_SLNQ_ANA_LDO_CONFIG, 0xea }, + { WCD934X_SLNQ_ANA_LDO_OCP_CONFIG, 0x95 }, + { WCD934X_SLNQ_ANA_TX_LDO_CONFIG, 0xb6 }, + { WCD934X_SLNQ_ANA_TX_DRV_CONFIG, 0x26 }, + { WCD934X_SLNQ_ANA_RX_CONFIG_1, 0x64 }, + { WCD934X_SLNQ_ANA_RX_CONFIG_2, 0x40 }, + { WCD934X_SLNQ_ANA_PLL_ENABLES, 0x00 }, + { WCD934X_SLNQ_ANA_PLL_PRESET, 0x08 }, + { WCD934X_SLNQ_ANA_PLL_STATUS, 0x00 }, + { WCD934X_CLK_SYS_PLL_ENABLES, 0x00 }, + { WCD934X_CLK_SYS_PLL_PRESET, 0x00 }, + { WCD934X_CLK_SYS_PLL_STATUS, 0x00 }, + { WCD934X_CLK_SYS_MCLK_PRG, 0x00 }, + { WCD934X_CLK_SYS_MCLK2_PRG1, 0x00 }, + { WCD934X_CLK_SYS_MCLK2_PRG2, 0x00 }, + { WCD934X_CLK_SYS_XO_PRG, 0x00 }, + { WCD934X_CLK_SYS_XO_CAP_XTP, 0x00 }, + { WCD934X_CLK_SYS_XO_CAP_XTM, 0x00 }, + { WCD934X_BOOST_BST_EN_DLY, 0x40 }, + { WCD934X_BOOST_CTRL_ILIM, 0x9c }, + { WCD934X_BOOST_VOUT_SETTING, 0xca }, + { WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x05 }, + { WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x0d }, + { WCD934X_SIDO_NEW_VOUT_D_FREQ1, 0x07 }, + { WCD934X_SIDO_NEW_VOUT_D_FREQ2, 0x00 }, + { WCD934X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 }, + { WCD934X_MBHC_NEW_CTL_1, 0x02 }, + { WCD934X_MBHC_NEW_CTL_2, 0x05 }, + { WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0xe9 }, + { WCD934X_MBHC_NEW_ZDET_ANA_CTL, 0x0f }, + { WCD934X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 }, + { WCD934X_MBHC_NEW_FSM_STATUS, 0x00 }, + { WCD934X_MBHC_NEW_ADC_RESULT, 0x00 }, + { WCD934X_TX_NEW_AMIC_4_5_SEL, 0x00 }, + { WCD934X_VBADC_NEW_ADC_MODE, 0x10 }, + { WCD934X_VBADC_NEW_ADC_DOUTMSB, 0x00 }, + { WCD934X_VBADC_NEW_ADC_DOUTLSB, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0xa0 }, + { WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 }, + { WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 }, + { WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xfe }, + { WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x02 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e }, + { WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 }, + { WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62 }, + { WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 }, + { WCD934X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 }, + { WCD934X_SLNQ_INT_ANA_INT_LDO_TEST, 0x0d }, + { WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_1, 0x85 }, + { WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_2, 0xb4 }, + { WCD934X_SLNQ_INT_ANA_INT_TX_LDO_TEST, 0x16 }, + { WCD934X_SLNQ_INT_ANA_INT_TX_DRV_TEST, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_TEST, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_TEST_STATUS, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_1, 0x50 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_2, 0x04 }, + { WCD934X_SLNQ_INT_ANA_INT_CLK_CTRL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RESERVED_1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RESERVED_2, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_L_VAL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_M_VAL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_N_VAL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_PFD_CP_DSM_PROG, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_VCO_PROG, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_LDO_LOCK_CFG, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_DIG_LOCK_DET_CFG, 0x00 }, + { WCD934X_CLK_SYS_INT_POST_DIV_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_POST_DIV_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_REF_DIV_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_REF_DIV_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_FILTER_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_FILTER_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_PLL_L_VAL, 0x00 }, + { WCD934X_CLK_SYS_INT_PLL_M_VAL, 0x00 }, + { WCD934X_CLK_SYS_INT_PLL_N_VAL, 0x00 }, + { WCD934X_CLK_SYS_INT_TEST_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG, 0x00 }, + { WCD934X_CLK_SYS_INT_VCO_PROG, 0x00 }, + { WCD934X_CLK_SYS_INT_TEST_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_LDO_LOCK_CFG, 0x00 }, + { WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG, 0x00 }, + { WCD934X_CLK_SYS_INT_CLK_TEST1, 0x00 }, + { WCD934X_CLK_SYS_INT_CLK_TEST2, 0x00 }, + { WCD934X_CLK_SYS_INT_CLK_TEST3, 0x00 }, + { WCD934X_CLK_SYS_INT_XO_TEST1, 0x98 }, + { WCD934X_CLK_SYS_INT_XO_TEST2, 0x00 }, + { WCD934X_BOOST_INT_VCOMP_HYST, 0x02 }, + { WCD934X_BOOST_INT_VLOOP_FILTER, 0xef }, + { WCD934X_BOOST_INT_CTRL_IDELTA, 0xa8 }, + { WCD934X_BOOST_INT_CTRL_ILIM_STARTUP, 0x17 }, + { WCD934X_BOOST_INT_CTRL_MIN_ONTIME, 0x5f }, + { WCD934X_BOOST_INT_CTRL_MAX_ONTIME, 0x88 }, + { WCD934X_BOOST_INT_CTRL_TIMING, 0x0a }, + { WCD934X_BOOST_INT_TMUX_A_D, 0x00 }, + { WCD934X_BOOST_INT_SW_DRV_CNTL, 0xf8 }, + { WCD934X_BOOST_INT_SPARE1, 0x00 }, + { WCD934X_BOOST_INT_SPARE2, 0x00 }, + { WCD934X_SIDO_NEW_INT_RAMP_STATUS, 0x00 }, + { WCD934X_SIDO_NEW_INT_SPARE_1, 0x00 }, + { WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_A, 0x64 }, + { WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_D, 0x40 }, + { WCD934X_SIDO_NEW_INT_RAMP_INC_WAIT, 0x24 }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_CTL, 0x09 }, + { WCD934X_SIDO_NEW_INT_RAMP_IBLEED_CTL, 0x7d }, + { WCD934X_SIDO_NEW_INT_DEBUG_CPROVR_TEST, 0x00 }, + { WCD934X_SIDO_NEW_INT_RAMP_CTL_A, 0x14 }, + { WCD934X_SIDO_NEW_INT_RAMP_CTL_D, 0x14 }, + { WCD934X_SIDO_NEW_INT_RAMP_TIMEOUT_PERIOD, 0x33 }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING1, 0x3f }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING2, 0x74 }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING3, 0x33 }, + { WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL1, 0x1d }, + { WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL2, 0x0a }, + { WCD934X_MBHC_NEW_INT_SLNQ_HPF, 0x50 }, + { WCD934X_MBHC_NEW_INT_SLNQ_REF, 0x24 }, + { WCD934X_MBHC_NEW_INT_SLNQ_COMP, 0x50 }, + { WCD934X_MBHC_NEW_INT_SPARE_2, 0x00 }, + { WCD934X_PAGE10_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_ANC0_CLK_RESET_CTL, 0x00 }, + { WCD934X_CDC_ANC0_MODE_1_CTL, 0x00 }, + { WCD934X_CDC_ANC0_MODE_2_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FF_SHIFT, 0x00 }, + { WCD934X_CDC_ANC0_FB_SHIFT, 0x00 }, + { WCD934X_CDC_ANC0_LPF_FF_A_CTL, 0x00 }, + { WCD934X_CDC_ANC0_LPF_FF_B_CTL, 0x00 }, + { WCD934X_CDC_ANC0_LPF_FB_CTL, 0x00 }, + { WCD934X_CDC_ANC0_SMLPF_CTL, 0x00 }, + { WCD934X_CDC_ANC0_DCFLT_SHIFT_CTL, 0x00 }, + { WCD934X_CDC_ANC0_IIR_ADAPT_CTL, 0x00 }, + { WCD934X_CDC_ANC0_IIR_COEFF_1_CTL, 0x00 }, + { WCD934X_CDC_ANC0_IIR_COEFF_2_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FF_A_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FF_B_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FB_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC0_RC_COMMON_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FIFO_COMMON_CTL, 0x88 }, + { WCD934X_CDC_ANC0_RC0_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_RC1_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_RC0_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_RC1_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_STATUS_FIFO, 0x00 }, + { WCD934X_CDC_ANC1_CLK_RESET_CTL, 0x00 }, + { WCD934X_CDC_ANC1_MODE_1_CTL, 0x00 }, + { WCD934X_CDC_ANC1_MODE_2_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FF_SHIFT, 0x00 }, + { WCD934X_CDC_ANC1_FB_SHIFT, 0x00 }, + { WCD934X_CDC_ANC1_LPF_FF_A_CTL, 0x00 }, + { WCD934X_CDC_ANC1_LPF_FF_B_CTL, 0x00 }, + { WCD934X_CDC_ANC1_LPF_FB_CTL, 0x00 }, + { WCD934X_CDC_ANC1_SMLPF_CTL, 0x00 }, + { WCD934X_CDC_ANC1_DCFLT_SHIFT_CTL, 0x00 }, + { WCD934X_CDC_ANC1_IIR_ADAPT_CTL, 0x00 }, + { WCD934X_CDC_ANC1_IIR_COEFF_1_CTL, 0x00 }, + { WCD934X_CDC_ANC1_IIR_COEFF_2_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FF_A_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FF_B_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FB_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC1_RC_COMMON_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FIFO_COMMON_CTL, 0x88 }, + { WCD934X_CDC_ANC1_RC0_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_RC1_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_RC0_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_RC1_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_STATUS_FIFO, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX0_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX0_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX0_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX0_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX0_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX0_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC7, 0x25 }, + { WCD934X_CDC_TX1_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX1_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX1_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX1_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX1_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX1_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX1_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX2_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX2_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX2_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX2_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX2_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX2_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX3_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX3_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX3_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX3_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX3_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX3_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX4_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX4_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX4_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX4_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX4_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX4_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX5_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX5_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX5_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX5_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX5_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX5_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX6_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX6_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX6_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX6_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX6_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX6_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX7_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX7_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX7_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX7_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX7_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX7_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX8_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX8_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX8_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX8_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX8_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX8_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_PAGE11_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_COMPANDER1_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER1_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER1_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER1_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER1_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER1_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER1_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER1_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER2_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER2_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER2_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER2_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER2_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER2_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER2_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER2_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER3_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER3_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER3_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER3_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER3_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER3_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER3_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER3_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER4_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER4_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER4_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER4_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER4_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER4_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER4_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER4_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER7_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER7_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER7_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER7_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER7_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER7_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER7_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER7_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER8_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER8_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER8_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER8_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER8_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER8_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER8_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER8_CTL7, 0x08 }, + { WCD934X_CDC_RX0_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX0_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX0_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX0_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX0_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX0_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX0_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX1_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX1_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX1_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX1_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX1_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX1_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC4, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX2_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX2_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX2_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX2_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX2_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX2_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC4, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX3_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX3_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX3_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX3_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX3_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX3_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX4_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX4_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX4_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX4_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX4_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX4_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX7_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX7_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX7_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX7_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC0, 0x04 }, + { WCD934X_CDC_RX7_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX7_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX8_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX8_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX8_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX8_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC0, 0x04 }, + { WCD934X_CDC_RX8_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX8_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_PAGE12_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_CLSH_CRC, 0x00 }, + { WCD934X_CDC_CLSH_DLY_CTRL, 0x03 }, + { WCD934X_CDC_CLSH_DECAY_CTRL, 0x02 }, + { WCD934X_CDC_CLSH_HPH_V_PA, 0x1c }, + { WCD934X_CDC_CLSH_EAR_V_PA, 0x39 }, + { WCD934X_CDC_CLSH_HPH_V_HD, 0x0c }, + { WCD934X_CDC_CLSH_EAR_V_HD, 0x0c }, + { WCD934X_CDC_CLSH_K1_MSB, 0x01 }, + { WCD934X_CDC_CLSH_K1_LSB, 0x00 }, + { WCD934X_CDC_CLSH_K2_MSB, 0x00 }, + { WCD934X_CDC_CLSH_K2_LSB, 0x80 }, + { WCD934X_CDC_CLSH_IDLE_CTRL, 0x00 }, + { WCD934X_CDC_CLSH_IDLE_HPH, 0x00 }, + { WCD934X_CDC_CLSH_IDLE_EAR, 0x00 }, + { WCD934X_CDC_CLSH_TEST0, 0x07 }, + { WCD934X_CDC_CLSH_TEST1, 0x00 }, + { WCD934X_CDC_CLSH_OVR_VREF, 0x00 }, + { WCD934X_CDC_BOOST0_BOOST_PATH_CTL, 0x00 }, + { WCD934X_CDC_BOOST0_BOOST_CTL, 0xb2 }, + { WCD934X_CDC_BOOST0_BOOST_CFG1, 0x00 }, + { WCD934X_CDC_BOOST0_BOOST_CFG2, 0x00 }, + { WCD934X_CDC_BOOST1_BOOST_PATH_CTL, 0x00 }, + { WCD934X_CDC_BOOST1_BOOST_CTL, 0xb2 }, + { WCD934X_CDC_BOOST1_BOOST_CFG1, 0x00 }, + { WCD934X_CDC_BOOST1_BOOST_CFG2, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_PATH_CTL, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_CFG, 0x1a }, + { WCD934X_CDC_VBAT_VBAT_ADC_CAL1, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_ADC_CAL2, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_ADC_CAL3, 0x04 }, + { WCD934X_CDC_VBAT_VBAT_PK_EST1, 0xe0 }, + { WCD934X_CDC_VBAT_VBAT_PK_EST2, 0x01 }, + { WCD934X_CDC_VBAT_VBAT_PK_EST3, 0x40 }, + { WCD934X_CDC_VBAT_VBAT_RF_PROC1, 0x2a }, + { WCD934X_CDC_VBAT_VBAT_RF_PROC2, 0x86 }, + { WCD934X_CDC_VBAT_VBAT_TAC1, 0x70 }, + { WCD934X_CDC_VBAT_VBAT_TAC2, 0x18 }, + { WCD934X_CDC_VBAT_VBAT_TAC3, 0x18 }, + { WCD934X_CDC_VBAT_VBAT_TAC4, 0x03 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD1, 0x01 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD2, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD3, 0x64 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD4, 0x01 }, + { WCD934X_CDC_VBAT_VBAT_DEBUG1, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD_MON, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_MON_VAL, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_BAN, 0x0c }, + { WCD934X_MIXING_ASRC0_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC0_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC0_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC0_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FIFO, 0x00 }, + { WCD934X_MIXING_ASRC1_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC1_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC1_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC1_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FIFO, 0x00 }, + { WCD934X_MIXING_ASRC2_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC2_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC2_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC2_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FIFO, 0x00 }, + { WCD934X_MIXING_ASRC3_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC3_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC3_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC3_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FIFO, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_ACCESS_CFG, 0x0f }, + { WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS, 0x03 }, + { WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04 }, + { WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00 }, + { WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL, 0x04 }, + { WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1, 0x00 }, + { WCD934X_SIDETONE_ASRC0_CLK_RST_CTL, 0x00 }, + { WCD934X_SIDETONE_ASRC0_CTL0, 0x00 }, + { WCD934X_SIDETONE_ASRC0_CTL1, 0x00 }, + { WCD934X_SIDETONE_ASRC0_FIFO_CTL, 0xa8 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FIFO, 0x00 }, + { WCD934X_SIDETONE_ASRC1_CLK_RST_CTL, 0x00 }, + { WCD934X_SIDETONE_ASRC1_CTL0, 0x00 }, + { WCD934X_SIDETONE_ASRC1_CTL1, 0x00 }, + { WCD934X_SIDETONE_ASRC1_FIFO_CTL, 0xa8 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FIFO, 0x00 }, + { WCD934X_EC_REF_HQ0_EC_REF_HQ_PATH_CTL, 0x00 }, + { WCD934X_EC_REF_HQ0_EC_REF_HQ_CFG0, 0x01 }, + { WCD934X_EC_REF_HQ1_EC_REF_HQ_PATH_CTL, 0x00 }, + { WCD934X_EC_REF_HQ1_EC_REF_HQ_CFG0, 0x01 }, + { WCD934X_EC_ASRC0_CLK_RST_CTL, 0x00 }, + { WCD934X_EC_ASRC0_CTL0, 0x00 }, + { WCD934X_EC_ASRC0_CTL1, 0x00 }, + { WCD934X_EC_ASRC0_FIFO_CTL, 0xa8 }, + { WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FIFO, 0x00 }, + { WCD934X_EC_ASRC1_CLK_RST_CTL, 0x00 }, + { WCD934X_EC_ASRC1_CTL0, 0x00 }, + { WCD934X_EC_ASRC1_CTL1, 0x00 }, + { WCD934X_EC_ASRC1_FIFO_CTL, 0xa8 }, + { WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FIFO, 0x00 }, + { WCD934X_PAGE13_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_EC_REF_HQ_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x0c }, + { WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL, 0x0f }, + { WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_CTL, 0x08 }, + { WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD0, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD1, 0x4b }, + { WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_STATUS, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_CTRL, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_CTL, 0x40 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_CTL, 0x40 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL, 0x00 }, + { WCD934X_CDC_TOP_TOP_CFG0, 0x00 }, + { WCD934X_CDC_TOP_TOP_CFG1, 0x00 }, + { WCD934X_CDC_TOP_TOP_CFG7, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_DSD0_PATH_CTL, 0x00 }, + { WCD934X_CDC_DSD0_CFG0, 0x00 }, + { WCD934X_CDC_DSD0_CFG1, 0x00 }, + { WCD934X_CDC_DSD0_CFG2, 0x42 }, + { WCD934X_CDC_DSD0_CFG3, 0x00 }, + { WCD934X_CDC_DSD0_CFG4, 0x02 }, + { WCD934X_CDC_DSD0_CFG5, 0x00 }, + { WCD934X_CDC_DSD1_PATH_CTL, 0x00 }, + { WCD934X_CDC_DSD1_CFG0, 0x00 }, + { WCD934X_CDC_DSD1_CFG1, 0x00 }, + { WCD934X_CDC_DSD1_CFG2, 0x42 }, + { WCD934X_CDC_DSD1_CFG3, 0x00 }, + { WCD934X_CDC_DSD1_CFG4, 0x02 }, + { WCD934X_CDC_DSD1_CFG5, 0x00 }, + { WCD934X_CDC_RX_IDLE_DET_PATH_CTL, 0x00 }, + { WCD934X_CDC_RX_IDLE_DET_CFG0, 0x07 }, + { WCD934X_CDC_RX_IDLE_DET_CFG1, 0x3c }, + { WCD934X_CDC_RX_IDLE_DET_CFG2, 0x00 }, + { WCD934X_CDC_RX_IDLE_DET_CFG3, 0x00 }, + { WCD934X_PAGE14_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST0_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST0_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST0_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST0_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST0_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST1_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST1_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST1_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST1_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST1_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST2_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST2_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST2_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST2_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST2_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST3_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST3_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST3_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST3_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST3_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_PAGE15_PAGE_REGISTER, 0x00 }, + { WCD934X_SPLINE_SRC0_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC0_STATUS, 0x00 }, + { WCD934X_SPLINE_SRC1_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC1_STATUS, 0x00 }, + { WCD934X_SPLINE_SRC2_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC2_STATUS, 0x00 }, + { WCD934X_SPLINE_SRC3_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC3_STATUS, 0x00 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, 0x11 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, 0x20 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG2, 0x00 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, 0x08 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, 0x11 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, 0x20 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG2, 0x00 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, 0x08 }, + { WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG0, 0x00 }, + { WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG1, 0x00 }, + { WCD934X_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0, 0x00 }, + { WCD934X_CDC_DEBUG_ANC0_RC0_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC0_RC1_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC1_RC0_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC1_RC1_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC_RC_RST_DBG_CNTR, 0x00 }, + { WCD934X_PAGE80_PAGE_REGISTER, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_0, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_1, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_2, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_3, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_0, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_1, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_2, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_3, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_0, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_1, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_2, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_3, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_0, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_1, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_2, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_3, 0x00 }, + { WCD934X_CODEC_CPR_ACCESS_CFG, 0x0f }, + { WCD934X_CODEC_CPR_ACCESS_STATUS, 0x03 }, + { WCD934X_CODEC_CPR_NOM_CX_VDD, 0xb4 }, + { WCD934X_CODEC_CPR_SVS_CX_VDD, 0x5c }, + { WCD934X_CODEC_CPR_SVS2_CX_VDD, 0x40 }, + { WCD934X_CODEC_CPR_NOM_MX_VDD, 0xb4 }, + { WCD934X_CODEC_CPR_SVS_MX_VDD, 0xb4 }, + { WCD934X_CODEC_CPR_SVS2_MX_VDD, 0xa0 }, + { WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x28 }, + { WCD934X_CODEC_CPR_MAX_SVS2_STEP, 0x08 }, + { WCD934X_CODEC_CPR_CTL, 0x00 }, + { WCD934X_CODEC_CPR_SW_MODECHNG_STATUS, 0x00 }, + { WCD934X_CODEC_CPR_SW_MODECHNG_START, 0x00 }, + { WCD934X_CODEC_CPR_CPR_STATUS, 0x00 }, + { WCD934X_PAGE128_PAGE_REGISTER, 0x00 }, + { WCD934X_TLMM_BIST_MODE_PINCFG, 0x00 }, + { WCD934X_TLMM_RF_PA_ON_PINCFG, 0x00 }, + { WCD934X_TLMM_INTR1_PINCFG, 0x00 }, + { WCD934X_TLMM_INTR2_PINCFG, 0x00 }, + { WCD934X_TLMM_SWR_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_SWR_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_2_SCK_PINCFG, 0x00 }, + { WCD934X_TLMM_SLIMBUS_DATA1_PINCFG, 0x00 }, + { WCD934X_TLMM_SLIMBUS_DATA2_PINCFG, 0x00 }, + { WCD934X_TLMM_SLIMBUS_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2C_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2C_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_RX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_TX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_SCK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_WS_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_RX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_TX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_SCK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_WS_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC1_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC1_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC2_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC2_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC3_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC3_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_JTCK_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO1_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO2_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO3_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO4_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_CSN_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_DOUT_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_DIN_PINCFG, 0x00 }, + { WCD934X_TLMM_BA_N_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO0_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_2_RX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_2_WS_PINCFG, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_0, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_1, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_2, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_3, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_4, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_0, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_1, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_2, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_3, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_4, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_DRVCTL_0, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_DRVCTL_1, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_STATUS, 0x00 }, + { WCD934X_TEST_DEBUG_NPL_DLY_TEST_1, 0x10 }, + { WCD934X_TEST_DEBUG_NPL_DLY_TEST_2, 0x60 }, + { WCD934X_TEST_DEBUG_MEM_CTRL, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_BUS_SEL, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_JTAG, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_1, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_2, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_3, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_4, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_5, 0x00 }, + { WCD934X_TEST_DEBUG_ANA_DTEST_DIR, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_0, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_1, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_2, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_3, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_4, 0x00 }, + { WCD934X_TEST_DEBUG_SYSMEM_CTRL, 0x00 }, + { WCD934X_TEST_DEBUG_SOC_SW_PWR_SEQ_DELAY, 0x00 }, + { WCD934X_TEST_DEBUG_LVAL_NOM_LOW, 0x96 }, + { WCD934X_TEST_DEBUG_LVAL_NOM_HIGH, 0x00 }, + { WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW, 0x53 }, + { WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH, 0x00 }, + { WCD934X_TEST_DEBUG_SPI_SLAVE_CHAR, 0x00 }, + { WCD934X_TEST_DEBUG_CODEC_DIAGS, 0x00 }, +}; + +/* + * wcd934x_regmap_register_patch: Update register defaults based on version + * @regmap: handle to wcd9xxx regmap + * @version: wcd934x version + * + * Returns error code in case of failure or 0 for success + */ +int wcd934x_regmap_register_patch(struct regmap *regmap, int revision) +{ + int rc = 0; + + if (!regmap) { + pr_err("%s: regmap struct is NULL\n", __func__); + return -EINVAL; + } + + switch (revision) { + case TAVIL_VERSION_1_1: + case TAVIL_VERSION_WCD9340_1_1: + case TAVIL_VERSION_WCD9341_1_1: + regcache_cache_only(regmap, true); + rc = regmap_multi_reg_write(regmap, wcd934x_1_1_defaults, + ARRAY_SIZE(wcd934x_1_1_defaults)); + regcache_cache_only(regmap, false); + break; + } + + return rc; +} +EXPORT_SYMBOL(wcd934x_regmap_register_patch); + +static bool wcd934x_is_readable_register(struct device *dev, unsigned int reg) +{ + u8 pg_num, reg_offset; + const u8 *reg_tbl = NULL; + + /* + * Get the page number from MSB of codec register. If its 0x80, assign + * the corresponding page index PAGE_0x80. + */ + pg_num = reg >> 0x8; + if (pg_num == 0x80) + pg_num = WCD934X_PAGE_0X80; + else if (pg_num == 0x50) + pg_num = WCD934X_PAGE_0x50; + else if (pg_num > 0xF) + return false; + + reg_tbl = wcd934x_reg[pg_num]; + reg_offset = reg & 0xFF; + + if (reg_tbl && reg_tbl[reg_offset]) + return true; + else + return false; +} + +static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg) +{ + u8 pg_num, reg_offset; + const u8 *reg_tbl = NULL; + + pg_num = reg >> 0x8; + if (pg_num == 0x80) + pg_num = WCD934X_PAGE_0X80; + else if (pg_num == 0x50) + pg_num = WCD934X_PAGE_0x50; + else if (pg_num > 0xF) + return false; + + reg_tbl = wcd934x_reg[pg_num]; + reg_offset = reg & 0xFF; + + if (reg_tbl && reg_tbl[reg_offset] == WCD934X_READ) + return true; + + /* IIR Coeff registers are not cacheable */ + if ((reg >= WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL) && + (reg <= WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)) + return true; + + if ((reg >= WCD934X_CDC_ANC0_IIR_COEFF_1_CTL) && + (reg <= WCD934X_CDC_ANC0_FB_GAIN_CTL)) + return true; + + if ((reg >= WCD934X_CDC_ANC1_IIR_COEFF_1_CTL) && + (reg <= WCD934X_CDC_ANC1_FB_GAIN_CTL)) + return true; + + if ((reg >= WCD934X_CODEC_CPR_WR_DATA_0) && + (reg <= WCD934X_CODEC_CPR_RD_DATA_3)) + return true; + + /* + * Need to mark volatile for registers that are writable but + * only few bits are read-only + */ + switch (reg) { + case WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL: + case WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0: + case WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1: + case WCD934X_CPE_SS_CPAR_CTL: + case WCD934X_CPE_SS_STATUS: + case WCD934X_CODEC_RPM_RST_CTL: + case WCD934X_SIDO_NEW_VOUT_A_STARTUP: + case WCD934X_SIDO_NEW_VOUT_D_STARTUP: + case WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL: + case WCD934X_ANA_MBHC_MECH: + case WCD934X_ANA_MBHC_ELECT: + case WCD934X_ANA_MBHC_ZDET: + case WCD934X_ANA_MICB2: + case WCD934X_CODEC_RPM_CLK_MCLK_CFG: + case WCD934X_CLK_SYS_MCLK_PRG: + case WCD934X_CHIP_TIER_CTRL_EFUSE_CTL: + case WCD934X_ANA_BIAS: + case WCD934X_ANA_BUCK_CTL: + case WCD934X_ANA_RCO: + case WCD934X_CODEC_RPM_CLK_GATE: + case WCD934X_BIAS_VBG_FINE_ADJ: + case WCD934X_CODEC_CPR_SVS_CX_VDD: + case WCD934X_CODEC_CPR_SVS2_CX_VDD: + return true; + } + + return false; +} + +struct regmap_config wcd934x_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd934x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd934x_defaults), + .max_register = WCD934X_MAX_REGISTER, + .volatile_reg = wcd934x_is_volatile_register, + .readable_reg = wcd934x_is_readable_register, + .can_multi_write = true, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-routing.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-routing.h new file mode 100644 index 0000000000..771f91f1cb --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-routing.h @@ -0,0 +1,1298 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ +#ifndef WCD934X_ROUTING_H +#define WCD934X_ROUTING_H + +#include + +const struct snd_soc_dapm_route tavil_slim_audio_map[] = { + + {"AIF4 MAD", NULL, "AIF4_MAD Mixer"}, + + /* Virtual input widget Mixer SLIMBUS*/ + {"AIF1_CAP Mixer", "SLIM TX0", "SLIM TX0"}, + {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1"}, + {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2"}, + {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3"}, + {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4"}, + {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5"}, + {"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6"}, + {"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7"}, + {"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8"}, + {"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9"}, + {"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10"}, + {"AIF1_CAP Mixer", "SLIM TX11", "SLIM TX11"}, + {"AIF1_CAP Mixer", "SLIM TX13", "SLIM TX13"}, + + {"AIF2_CAP Mixer", "SLIM TX0", "SLIM TX0"}, + {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1"}, + {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2"}, + {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3"}, + {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4"}, + {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5"}, + {"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6"}, + {"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7"}, + {"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8"}, + {"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9"}, + {"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10"}, + {"AIF2_CAP Mixer", "SLIM TX11", "SLIM TX11"}, + {"AIF2_CAP Mixer", "SLIM TX13", "SLIM TX13"}, + + {"AIF3_CAP Mixer", "SLIM TX0", "SLIM TX0"}, + {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1"}, + {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2"}, + {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3"}, + {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4"}, + {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5"}, + {"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6"}, + {"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7"}, + {"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8"}, + {"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9"}, + {"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10"}, + {"AIF3_CAP Mixer", "SLIM TX11", "SLIM TX11"}, + {"AIF3_CAP Mixer", "SLIM TX13", "SLIM TX13"}, + + {"AIF4_MAD Mixer", "SLIM TX13", "SLIM TX13"}, + + /* CDC Tx interface with SLIMBUS */ + {"SLIM TX0", NULL, "CDC_IF TX0 MUX"}, + {"SLIM TX1", NULL, "CDC_IF TX1 MUX"}, + {"SLIM TX2", NULL, "CDC_IF TX2 MUX"}, + {"SLIM TX3", NULL, "CDC_IF TX3 MUX"}, + {"SLIM TX4", NULL, "CDC_IF TX4 MUX"}, + {"SLIM TX5", NULL, "CDC_IF TX5 MUX"}, + {"SLIM TX6", NULL, "CDC_IF TX6 MUX"}, + {"SLIM TX7", NULL, "CDC_IF TX7 MUX"}, + {"SLIM TX8", NULL, "CDC_IF TX8 MUX"}, + {"SLIM TX9", NULL, "CDC_IF TX9 MUX"}, + {"SLIM TX10", NULL, "CDC_IF TX10 MUX"}, + {"SLIM TX11", NULL, "CDC_IF TX11 MUX"}, + {"SLIM TX13", NULL, "CDC_IF TX13 MUX"}, + + {"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"}, + + {"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"}, + + {"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"}, + + {"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"}, + + {"SLIM RX0", NULL, "SLIM RX0 MUX"}, + {"SLIM RX1", NULL, "SLIM RX1 MUX"}, + {"SLIM RX2", NULL, "SLIM RX2 MUX"}, + {"SLIM RX3", NULL, "SLIM RX3 MUX"}, + {"SLIM RX4", NULL, "SLIM RX4 MUX"}, + {"SLIM RX5", NULL, "SLIM RX5 MUX"}, + {"SLIM RX6", NULL, "SLIM RX6 MUX"}, + {"SLIM RX7", NULL, "SLIM RX7 MUX"}, + + /* CDC Rx interface with SLIMBUS */ + {"CDC_IF RX0 MUX", "SLIM RX0", "SLIM RX0"}, + {"CDC_IF RX1 MUX", "SLIM RX1", "SLIM RX1"}, + {"CDC_IF RX2 MUX", "SLIM RX2", "SLIM RX2"}, + {"CDC_IF RX3 MUX", "SLIM RX3", "SLIM RX3"}, + {"CDC_IF RX4 MUX", "SLIM RX4", "SLIM RX4"}, + {"CDC_IF RX5 MUX", "SLIM RX5", "SLIM RX5"}, + {"CDC_IF RX6 MUX", "SLIM RX6", "SLIM RX6"}, + {"CDC_IF RX7 MUX", "SLIM RX7", "SLIM RX7"}, + + /* VI Feedback */ + {"AIF4_VI Mixer", "SPKR_VI_1", "VIINPUT"}, + {"AIF4_VI Mixer", "SPKR_VI_2", "VIINPUT"}, + {"AIF4 VI", NULL, "AIF4_VI Mixer"}, + +}; + +const struct snd_soc_dapm_route tavil_i2s_audio_map[] = { + + /* Virtual input widget Mixer I2S*/ + {"AIF1_CAP Mixer", "I2S TX1", "I2S TX1"}, + {"AIF1_CAP Mixer", "I2S TX2", "I2S TX2"}, + {"AIF1_CAP Mixer", "I2S TX3", "I2S TX3"}, + {"AIF1_CAP Mixer", "I2S TX4", "I2S TX4"}, + {"AIF1_CAP Mixer", "I2S TX5", "I2S TX5"}, + {"AIF1_CAP Mixer", "I2S TX6", "I2S TX6"}, + {"AIF1_CAP Mixer", "I2S TX7", "I2S TX7"}, + + {"AIF2_CAP Mixer", "I2S TX8", "I2S TX8"}, + {"AIF2_CAP Mixer", "I2S TX11", "I2S TX11"}, + + {"AIF3_CAP Mixer", "I2S TX0", "I2S TX0"}, + {"AIF3_CAP Mixer", "I2S TX1", "I2S TX1"}, + + /* CDC Tx interface with I2S */ + {"I2S TX0", NULL, "CDC_IF TX0 MUX"}, + {"I2S TX1", NULL, "CDC_IF TX1 MUX"}, + {"I2S TX2", NULL, "CDC_IF TX2 MUX"}, + {"I2S TX3", NULL, "CDC_IF TX3 MUX"}, + {"I2S TX4", NULL, "CDC_IF TX4 MUX"}, + {"I2S TX5", NULL, "CDC_IF TX5 MUX"}, + {"I2S TX6", NULL, "CDC_IF TX6 MUX"}, + {"I2S TX7", NULL, "CDC_IF TX7 MUX"}, + {"I2S TX8", NULL, "CDC_IF TX8 MUX"}, + {"I2S TX11", NULL, "CDC_IF TX11 MUX"}, + + {"I2S RX0 MUX", "AIF1_PB", "AIF1 PB"}, + {"I2S RX1 MUX", "AIF1_PB", "AIF1 PB"}, + {"I2S RX2 MUX", "AIF1_PB", "AIF1 PB"}, + {"I2S RX3 MUX", "AIF1_PB", "AIF1 PB"}, + {"I2S RX4 MUX", "AIF1_PB", "AIF1 PB"}, + {"I2S RX5 MUX", "AIF1_PB", "AIF1 PB"}, + {"I2S RX6 MUX", "AIF1_PB", "AIF1 PB"}, + {"I2S RX7 MUX", "AIF1_PB", "AIF1 PB"}, + + {"I2S RX2 MUX", "AIF2_PB", "AIF2 PB"}, + {"I2S RX3 MUX", "AIF2_PB", "AIF2 PB"}, + + {"I2S RX4 MUX", "AIF3_PB", "AIF3 PB"}, + {"I2S RX5 MUX", "AIF3_PB", "AIF3 PB"}, + + {"I2S RX0", NULL, "I2S RX0 MUX"}, + {"I2S RX1", NULL, "I2S RX1 MUX"}, + {"I2S RX2", NULL, "I2S RX2 MUX"}, + {"I2S RX3", NULL, "I2S RX3 MUX"}, + {"I2S RX4", NULL, "I2S RX4 MUX"}, + {"I2S RX5", NULL, "I2S RX5 MUX"}, + {"I2S RX6", NULL, "I2S RX6 MUX"}, + {"I2S RX7", NULL, "I2S RX7 MUX"}, + + /* CDC Rx interface with I2S */ + {"CDC_IF RX0 MUX", "I2S RX0", "I2S RX0"}, + {"CDC_IF RX1 MUX", "I2S RX1", "I2S RX1"}, + {"CDC_IF RX2 MUX", "I2S RX2", "I2S RX2"}, + {"CDC_IF RX3 MUX", "I2S RX3", "I2S RX3"}, + {"CDC_IF RX4 MUX", "I2S RX4", "I2S RX4"}, + {"CDC_IF RX5 MUX", "I2S RX5", "I2S RX5"}, + {"CDC_IF RX6 MUX", "I2S RX6", "I2S RX6"}, + {"CDC_IF RX7 MUX", "I2S RX7", "I2S RX7"}, + +}; + +const struct snd_soc_dapm_route tavil_audio_map[] = { + + /* + * AIF CAP to Mixer routes are common + * for both SLIM as well as I2S + */ + + /* Virtual input widgets */ + {"AIF1 CAP", NULL, "AIF1_CAP Mixer"}, + {"AIF2 CAP", NULL, "AIF2_CAP Mixer"}, + {"AIF3 CAP", NULL, "AIF3_CAP Mixer"}, + + /* WDMA3 */ + {"WDMA3 PORT0 MUX", "DEC0", "ADC MUX0"}, + {"WDMA3 PORT0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"}, + {"WDMA3 PORT1 MUX", "DEC1", "ADC MUX1"}, + {"WDMA3 PORT1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"}, + {"WDMA3 PORT2 MUX", "DEC2", "ADC MUX2"}, + {"WDMA3 PORT2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"}, + {"WDMA3 PORT3 MUX", "DEC3", "ADC MUX3"}, + {"WDMA3 PORT3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"}, + {"WDMA3 PORT4 MUX", "DEC4", "ADC MUX4"}, + {"WDMA3 PORT4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"}, + {"WDMA3 PORT5 MUX", "DEC5", "ADC MUX5"}, + {"WDMA3 PORT5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"}, + {"WDMA3 PORT6 MUX", "DEC6", "ADC MUX6"}, + {"WDMA3 PORT6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"}, + + {"WDMA3 CH0 MUX", "PORT_0", "WDMA3 PORT0 MUX"}, + {"WDMA3 CH0 MUX", "PORT_1", "WDMA3 PORT1 MUX"}, + {"WDMA3 CH0 MUX", "PORT_2", "WDMA3 PORT2 MUX"}, + {"WDMA3 CH0 MUX", "PORT_3", "WDMA3 PORT3 MUX"}, + {"WDMA3 CH0 MUX", "PORT_4", "WDMA3 PORT4 MUX"}, + {"WDMA3 CH0 MUX", "PORT_5", "WDMA3 PORT5 MUX"}, + {"WDMA3 CH0 MUX", "PORT_6", "WDMA3 PORT6 MUX"}, + {"WDMA3 CH0 MUX", "PORT_7", "ADC MUX7"}, + {"WDMA3 CH0 MUX", "PORT_8", "ADC MUX8"}, + + {"WDMA3 CH1 MUX", "PORT_0", "WDMA3 PORT0 MUX"}, + {"WDMA3 CH1 MUX", "PORT_1", "WDMA3 PORT1 MUX"}, + {"WDMA3 CH1 MUX", "PORT_2", "WDMA3 PORT2 MUX"}, + {"WDMA3 CH1 MUX", "PORT_3", "WDMA3 PORT3 MUX"}, + {"WDMA3 CH1 MUX", "PORT_4", "WDMA3 PORT4 MUX"}, + {"WDMA3 CH1 MUX", "PORT_5", "WDMA3 PORT5 MUX"}, + {"WDMA3 CH1 MUX", "PORT_6", "WDMA3 PORT6 MUX"}, + {"WDMA3 CH1 MUX", "PORT_7", "ADC MUX7"}, + {"WDMA3 CH1 MUX", "PORT_8", "ADC MUX8"}, + + {"WDMA3 CH2 MUX", "PORT_0", "WDMA3 PORT0 MUX"}, + {"WDMA3 CH2 MUX", "PORT_1", "WDMA3 PORT1 MUX"}, + {"WDMA3 CH2 MUX", "PORT_2", "WDMA3 PORT2 MUX"}, + {"WDMA3 CH2 MUX", "PORT_3", "WDMA3 PORT3 MUX"}, + {"WDMA3 CH2 MUX", "PORT_4", "WDMA3 PORT4 MUX"}, + {"WDMA3 CH2 MUX", "PORT_5", "WDMA3 PORT5 MUX"}, + {"WDMA3 CH2 MUX", "PORT_6", "WDMA3 PORT6 MUX"}, + {"WDMA3 CH2 MUX", "PORT_7", "ADC MUX7"}, + {"WDMA3 CH2 MUX", "PORT_8", "ADC MUX8"}, + + {"WDMA3 CH3 MUX", "PORT_0", "WDMA3 PORT0 MUX"}, + {"WDMA3 CH3 MUX", "PORT_1", "WDMA3 PORT1 MUX"}, + {"WDMA3 CH3 MUX", "PORT_2", "WDMA3 PORT2 MUX"}, + {"WDMA3 CH3 MUX", "PORT_3", "WDMA3 PORT3 MUX"}, + {"WDMA3 CH3 MUX", "PORT_4", "WDMA3 PORT4 MUX"}, + {"WDMA3 CH3 MUX", "PORT_5", "WDMA3 PORT5 MUX"}, + {"WDMA3 CH3 MUX", "PORT_6", "WDMA3 PORT6 MUX"}, + {"WDMA3 CH3 MUX", "PORT_7", "ADC MUX7"}, + {"WDMA3 CH3 MUX", "PORT_8", "ADC MUX8"}, + + {"WDMA3_CH_MIXER", NULL, "WDMA3 CH0 MUX"}, + {"WDMA3_CH_MIXER", NULL, "WDMA3 CH1 MUX"}, + {"WDMA3_CH_MIXER", NULL, "WDMA3 CH2 MUX"}, + {"WDMA3_CH_MIXER", NULL, "WDMA3 CH3 MUX"}, + + {"WDMA3_ON_OFF", "Switch", "WDMA3_CH_MIXER"}, + {"WDMA3_OUT", NULL, "WDMA3_ON_OFF"}, + + /* MAD */ + {"MAD_SEL MUX", "SPE", "MAD_CPE_INPUT"}, + {"MAD_SEL MUX", "MSM", "MADINPUT"}, + + {"MAD_INP MUX", "MAD", "MAD_SEL MUX"}, + {"MAD_INP MUX", "DEC1", "ADC MUX1"}, + + {"MAD_BROADCAST", "Switch", "MAD_INP MUX"}, + {"MAD_CPE1", "Switch", "MAD_INP MUX"}, + {"MAD_CPE2", "Switch", "MAD_INP MUX"}, + + {"MAD_CPE_OUT1", NULL, "MAD_CPE1"}, + {"MAD_CPE_OUT2", NULL, "MAD_CPE2"}, + + {"CDC_IF TX0 MUX", "DEC0", "ADC MUX0"}, + {"CDC_IF TX0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"}, + {"CDC_IF TX0 MUX", "DEC0_192", "ADC US MUX0"}, + + {"CDC_IF TX1 MUX", "DEC1", "ADC MUX1"}, + {"CDC_IF TX1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"}, + {"CDC_IF TX1 MUX", "DEC1_192", "ADC US MUX1"}, + + {"CDC_IF TX2 MUX", "DEC2", "ADC MUX2"}, + {"CDC_IF TX2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"}, + {"CDC_IF TX2 MUX", "DEC2_192", "ADC US MUX2"}, + + {"CDC_IF TX3 MUX", "DEC3", "ADC MUX3"}, + {"CDC_IF TX3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"}, + {"CDC_IF TX3 MUX", "DEC3_192", "ADC US MUX3"}, + + {"CDC_IF TX4 MUX", "DEC4", "ADC MUX4"}, + {"CDC_IF TX4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"}, + {"CDC_IF TX4 MUX", "DEC4_192", "ADC US MUX4"}, + + {"CDC_IF TX5 MUX", "DEC5", "ADC MUX5"}, + {"CDC_IF TX5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"}, + {"CDC_IF TX5 MUX", "DEC5_192", "ADC US MUX5"}, + + {"CDC_IF TX6 MUX", "DEC6", "ADC MUX6"}, + {"CDC_IF TX6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"}, + {"CDC_IF TX6 MUX", "DEC6_192", "ADC US MUX6"}, + + {"CDC_IF TX7 MUX", "DEC7", "ADC MUX7"}, + {"CDC_IF TX7 MUX", "RX_MIX_TX7", "RX MIX TX7 MUX"}, + {"CDC_IF TX7 MUX", "DEC7_192", "ADC US MUX7"}, + + {"CDC_IF TX8 MUX", "DEC8", "ADC MUX8"}, + {"CDC_IF TX8 MUX", "RX_MIX_TX8", "RX MIX TX8 MUX"}, + {"CDC_IF TX8 MUX", "DEC8_192", "ADC US MUX8"}, + + {"CDC_IF TX9 MUX", "DEC7", "ADC MUX7"}, + {"CDC_IF TX9 MUX", "DEC7_192", "ADC US MUX7"}, + {"CDC_IF TX10 MUX", "DEC6", "ADC MUX6"}, + {"CDC_IF TX10 MUX", "DEC6_192", "ADC US MUX6"}, + + {"CDC_IF TX11 MUX", "DEC_0_5", "CDC_IF TX11 INP1 MUX"}, + {"CDC_IF TX11 MUX", "DEC_9_12", "CDC_IF TX11 INP1 MUX"}, + {"CDC_IF TX11 INP1 MUX", "DEC0", "ADC MUX0"}, + {"CDC_IF TX11 INP1 MUX", "DEC1", "ADC MUX1"}, + {"CDC_IF TX11 INP1 MUX", "DEC2", "ADC MUX2"}, + {"CDC_IF TX11 INP1 MUX", "DEC3", "ADC MUX3"}, + {"CDC_IF TX11 INP1 MUX", "DEC4", "ADC MUX4"}, + {"CDC_IF TX11 INP1 MUX", "DEC5", "ADC MUX5"}, + {"CDC_IF TX11 INP1 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"}, + + {"CDC_IF TX13 MUX", "MAD_BRDCST", "MAD_BROADCAST"}, + {"CDC_IF TX13 MUX", "CDC_DEC_5", "CDC_IF TX13 INP1 MUX"}, + {"CDC_IF TX13 INP1 MUX", "DEC5", "ADC MUX5"}, + {"CDC_IF TX13 INP1 MUX", "DEC5_192", "ADC US MUX5"}, + + {"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX3 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX4 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX5 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX6 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX7 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX8 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"ADC US MUX0", "US_Switch", "ADC MUX0"}, + {"ADC US MUX1", "US_Switch", "ADC MUX1"}, + {"ADC US MUX2", "US_Switch", "ADC MUX2"}, + {"ADC US MUX3", "US_Switch", "ADC MUX3"}, + {"ADC US MUX4", "US_Switch", "ADC MUX4"}, + {"ADC US MUX5", "US_Switch", "ADC MUX5"}, + {"ADC US MUX6", "US_Switch", "ADC MUX6"}, + {"ADC US MUX7", "US_Switch", "ADC MUX7"}, + {"ADC US MUX8", "US_Switch", "ADC MUX8"}, + + {"ADC MUX0", "DMIC", "DMIC MUX0"}, + {"ADC MUX0", "AMIC", "AMIC MUX0"}, + {"ADC MUX1", "DMIC", "DMIC MUX1"}, + {"ADC MUX1", "AMIC", "AMIC MUX1"}, + {"ADC MUX2", "DMIC", "DMIC MUX2"}, + {"ADC MUX2", "AMIC", "AMIC MUX2"}, + {"ADC MUX3", "DMIC", "DMIC MUX3"}, + {"ADC MUX3", "AMIC", "AMIC MUX3"}, + {"ADC MUX4", "DMIC", "DMIC MUX4"}, + {"ADC MUX4", "AMIC", "AMIC MUX4"}, + {"ADC MUX5", "DMIC", "DMIC MUX5"}, + {"ADC MUX5", "AMIC", "AMIC MUX5"}, + {"ADC MUX6", "DMIC", "DMIC MUX6"}, + {"ADC MUX6", "AMIC", "AMIC MUX6"}, + {"ADC MUX7", "DMIC", "DMIC MUX7"}, + {"ADC MUX7", "AMIC", "AMIC MUX7"}, + {"ADC MUX8", "DMIC", "DMIC MUX8"}, + {"ADC MUX8", "AMIC", "AMIC MUX8"}, + {"ADC MUX10", "DMIC", "DMIC MUX10"}, + {"ADC MUX10", "AMIC", "AMIC MUX10"}, + {"ADC MUX11", "DMIC", "DMIC MUX11"}, + {"ADC MUX11", "AMIC", "AMIC MUX11"}, + {"ADC MUX12", "DMIC", "DMIC MUX12"}, + {"ADC MUX12", "AMIC", "AMIC MUX12"}, + {"ADC MUX13", "DMIC", "DMIC MUX13"}, + {"ADC MUX13", "AMIC", "AMIC MUX13"}, + + {"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX13"}, + + {"DMIC MUX0", "DMIC0", "DMIC0"}, + {"DMIC MUX0", "DMIC1", "DMIC1"}, + {"DMIC MUX0", "DMIC2", "DMIC2"}, + {"DMIC MUX0", "DMIC3", "DMIC3"}, + {"DMIC MUX0", "DMIC4", "DMIC4"}, + {"DMIC MUX0", "DMIC5", "DMIC5"}, + {"AMIC MUX0", "ADC1", "ADC1"}, + {"AMIC MUX0", "ADC2", "ADC2"}, + {"AMIC MUX0", "ADC3", "ADC3"}, + {"AMIC MUX0", "ADC4", "ADC4"}, + + {"DMIC MUX1", "DMIC0", "DMIC0"}, + {"DMIC MUX1", "DMIC1", "DMIC1"}, + {"DMIC MUX1", "DMIC2", "DMIC2"}, + {"DMIC MUX1", "DMIC3", "DMIC3"}, + {"DMIC MUX1", "DMIC4", "DMIC4"}, + {"DMIC MUX1", "DMIC5", "DMIC5"}, + {"AMIC MUX1", "ADC1", "ADC1"}, + {"AMIC MUX1", "ADC2", "ADC2"}, + {"AMIC MUX1", "ADC3", "ADC3"}, + {"AMIC MUX1", "ADC4", "ADC4"}, + + {"DMIC MUX2", "DMIC0", "DMIC0"}, + {"DMIC MUX2", "DMIC1", "DMIC1"}, + {"DMIC MUX2", "DMIC2", "DMIC2"}, + {"DMIC MUX2", "DMIC3", "DMIC3"}, + {"DMIC MUX2", "DMIC4", "DMIC4"}, + {"DMIC MUX2", "DMIC5", "DMIC5"}, + {"AMIC MUX2", "ADC1", "ADC1"}, + {"AMIC MUX2", "ADC2", "ADC2"}, + {"AMIC MUX2", "ADC3", "ADC3"}, + {"AMIC MUX2", "ADC4", "ADC4"}, + + {"DMIC MUX3", "DMIC0", "DMIC0"}, + {"DMIC MUX3", "DMIC1", "DMIC1"}, + {"DMIC MUX3", "DMIC2", "DMIC2"}, + {"DMIC MUX3", "DMIC3", "DMIC3"}, + {"DMIC MUX3", "DMIC4", "DMIC4"}, + {"DMIC MUX3", "DMIC5", "DMIC5"}, + {"AMIC MUX3", "ADC1", "ADC1"}, + {"AMIC MUX3", "ADC2", "ADC2"}, + {"AMIC MUX3", "ADC3", "ADC3"}, + {"AMIC MUX3", "ADC4", "ADC4"}, + + {"DMIC MUX4", "DMIC0", "DMIC0"}, + {"DMIC MUX4", "DMIC1", "DMIC1"}, + {"DMIC MUX4", "DMIC2", "DMIC2"}, + {"DMIC MUX4", "DMIC3", "DMIC3"}, + {"DMIC MUX4", "DMIC4", "DMIC4"}, + {"DMIC MUX4", "DMIC5", "DMIC5"}, + {"AMIC MUX4", "ADC1", "ADC1"}, + {"AMIC MUX4", "ADC2", "ADC2"}, + {"AMIC MUX4", "ADC3", "ADC3"}, + {"AMIC MUX4", "ADC4", "ADC4"}, + + {"DMIC MUX5", "DMIC0", "DMIC0"}, + {"DMIC MUX5", "DMIC1", "DMIC1"}, + {"DMIC MUX5", "DMIC2", "DMIC2"}, + {"DMIC MUX5", "DMIC3", "DMIC3"}, + {"DMIC MUX5", "DMIC4", "DMIC4"}, + {"DMIC MUX5", "DMIC5", "DMIC5"}, + {"AMIC MUX5", "ADC1", "ADC1"}, + {"AMIC MUX5", "ADC2", "ADC2"}, + {"AMIC MUX5", "ADC3", "ADC3"}, + {"AMIC MUX5", "ADC4", "ADC4"}, + + {"DMIC MUX6", "DMIC0", "DMIC0"}, + {"DMIC MUX6", "DMIC1", "DMIC1"}, + {"DMIC MUX6", "DMIC2", "DMIC2"}, + {"DMIC MUX6", "DMIC3", "DMIC3"}, + {"DMIC MUX6", "DMIC4", "DMIC4"}, + {"DMIC MUX6", "DMIC5", "DMIC5"}, + {"AMIC MUX6", "ADC1", "ADC1"}, + {"AMIC MUX6", "ADC2", "ADC2"}, + {"AMIC MUX6", "ADC3", "ADC3"}, + {"AMIC MUX6", "ADC4", "ADC4"}, + + {"DMIC MUX7", "DMIC0", "DMIC0"}, + {"DMIC MUX7", "DMIC1", "DMIC1"}, + {"DMIC MUX7", "DMIC2", "DMIC2"}, + {"DMIC MUX7", "DMIC3", "DMIC3"}, + {"DMIC MUX7", "DMIC4", "DMIC4"}, + {"DMIC MUX7", "DMIC5", "DMIC5"}, + {"AMIC MUX7", "ADC1", "ADC1"}, + {"AMIC MUX7", "ADC2", "ADC2"}, + {"AMIC MUX7", "ADC3", "ADC3"}, + {"AMIC MUX7", "ADC4", "ADC4"}, + + {"DMIC MUX8", "DMIC0", "DMIC0"}, + {"DMIC MUX8", "DMIC1", "DMIC1"}, + {"DMIC MUX8", "DMIC2", "DMIC2"}, + {"DMIC MUX8", "DMIC3", "DMIC3"}, + {"DMIC MUX8", "DMIC4", "DMIC4"}, + {"DMIC MUX8", "DMIC5", "DMIC5"}, + {"AMIC MUX8", "ADC1", "ADC1"}, + {"AMIC MUX8", "ADC2", "ADC2"}, + {"AMIC MUX8", "ADC3", "ADC3"}, + {"AMIC MUX8", "ADC4", "ADC4"}, + + {"DMIC MUX10", "DMIC0", "DMIC0"}, + {"DMIC MUX10", "DMIC1", "DMIC1"}, + {"DMIC MUX10", "DMIC2", "DMIC2"}, + {"DMIC MUX10", "DMIC3", "DMIC3"}, + {"DMIC MUX10", "DMIC4", "DMIC4"}, + {"DMIC MUX10", "DMIC5", "DMIC5"}, + {"AMIC MUX10", "ADC1", "ADC1"}, + {"AMIC MUX10", "ADC2", "ADC2"}, + {"AMIC MUX10", "ADC3", "ADC3"}, + {"AMIC MUX10", "ADC4", "ADC4"}, + + {"DMIC MUX11", "DMIC0", "DMIC0"}, + {"DMIC MUX11", "DMIC1", "DMIC1"}, + {"DMIC MUX11", "DMIC2", "DMIC2"}, + {"DMIC MUX11", "DMIC3", "DMIC3"}, + {"DMIC MUX11", "DMIC4", "DMIC4"}, + {"DMIC MUX11", "DMIC5", "DMIC5"}, + {"AMIC MUX11", "ADC1", "ADC1"}, + {"AMIC MUX11", "ADC2", "ADC2"}, + {"AMIC MUX11", "ADC3", "ADC3"}, + {"AMIC MUX11", "ADC4", "ADC4"}, + + {"DMIC MUX12", "DMIC0", "DMIC0"}, + {"DMIC MUX12", "DMIC1", "DMIC1"}, + {"DMIC MUX12", "DMIC2", "DMIC2"}, + {"DMIC MUX12", "DMIC3", "DMIC3"}, + {"DMIC MUX12", "DMIC4", "DMIC4"}, + {"DMIC MUX12", "DMIC5", "DMIC5"}, + {"AMIC MUX12", "ADC1", "ADC1"}, + {"AMIC MUX12", "ADC2", "ADC2"}, + {"AMIC MUX12", "ADC3", "ADC3"}, + {"AMIC MUX12", "ADC4", "ADC4"}, + + {"DMIC MUX13", "DMIC0", "DMIC0"}, + {"DMIC MUX13", "DMIC1", "DMIC1"}, + {"DMIC MUX13", "DMIC2", "DMIC2"}, + {"DMIC MUX13", "DMIC3", "DMIC3"}, + {"DMIC MUX13", "DMIC4", "DMIC4"}, + {"DMIC MUX13", "DMIC5", "DMIC5"}, + {"AMIC MUX13", "ADC1", "ADC1"}, + {"AMIC MUX13", "ADC2", "ADC2"}, + {"AMIC MUX13", "ADC3", "ADC3"}, + {"AMIC MUX13", "ADC4", "ADC4"}, + + {"AMIC4_5 SEL", "AMIC4", "AMIC4"}, + {"AMIC4_5 SEL", "AMIC5", "AMIC5"}, + + {"ADC1", NULL, "AMIC1"}, + {"ADC2", NULL, "AMIC2"}, + {"ADC3", NULL, "AMIC3"}, + {"ADC4", NULL, "AMIC4_5 SEL"}, + + {"RX INT0_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT1_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT3_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT3_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT3_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT4_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT4_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT4_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT7_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT7_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT7_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT8_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT8_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT8_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP0"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP1"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP2"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP0"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP1"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP2"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP0"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP1"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP2"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP0"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP1"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP2"}, + + /* Mixing path INT0 */ + {"RX INT0_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0_2 INTERP", NULL, "RX INT0_2 MUX"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_2 INTERP"}, + + /* Mixing path INT1 */ + {"RX INT1_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1_2 INTERP", NULL, "RX INT1_2 MUX"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_2 INTERP"}, + + /* Mixing path INT2 */ + {"RX INT2_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2_2 INTERP", NULL, "RX INT2_2 MUX"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_2 INTERP"}, + + /* Mixing path INT3 */ + {"RX INT3_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3_2 INTERP", NULL, "RX INT3_2 MUX"}, + {"RX INT3 SEC MIX", NULL, "RX INT3_2 INTERP"}, + + /* Mixing path INT4 */ + {"RX INT4_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4_2 INTERP", NULL, "RX INT4_2 MUX"}, + {"RX INT4 SEC MIX", NULL, "RX INT4_2 INTERP"}, + + /* Mixing path INT7 */ + {"RX INT7_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7_2 INTERP", NULL, "RX INT7_2 MUX"}, + {"RX INT7 SEC MIX", NULL, "RX INT7_2 INTERP"}, + + /* Mixing path INT8 */ + {"RX INT8_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8_2 INTERP", NULL, "RX INT8_2 MUX"}, + {"RX INT8 SEC MIX", NULL, "RX INT8_2 INTERP"}, + + {"RX INT0_1 INTERP", NULL, "RX INT0_1 MIX1"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_1 INTERP"}, + {"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"}, + {"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"}, + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 MIX2"}, + {"RX INT0 DAC", NULL, "RX INT0 DEM MUX"}, + {"RX INT0 DAC", NULL, "RX_BIAS"}, + {"EAR PA", NULL, "RX INT0 DAC"}, + {"EAR", NULL, "EAR PA"}, + + {"RX INT1_1 INTERP", NULL, "RX INT1_1 MIX1"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_1 INTERP"}, + {"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"}, + {"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"}, + {"RX INT1 MIX3", NULL, "RX INT1 MIX2"}, + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 MIX3"}, + {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"}, + {"RX INT1 DAC", NULL, "RX_BIAS"}, + {"HPHL PA", NULL, "RX INT1 DAC"}, + {"HPHL", NULL, "HPHL PA"}, + + {"RX INT2_1 INTERP", NULL, "RX INT2_1 MIX1"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_1 INTERP"}, + {"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"}, + {"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"}, + {"RX INT2 MIX3", NULL, "RX INT2 MIX2"}, + {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 MIX3"}, + {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"}, + {"RX INT2 DAC", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "RX INT2 DAC"}, + {"HPHR", NULL, "HPHR PA"}, + + {"RX INT3_1 INTERP", NULL, "RX INT3_1 MIX1"}, + {"RX INT3 SEC MIX", NULL, "RX INT3_1 INTERP"}, + {"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"}, + {"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"}, + {"RX INT3 MIX3", NULL, "RX INT3 MIX2"}, + {"RX INT3 DAC", NULL, "RX INT3 MIX3"}, + {"RX INT3 DAC", NULL, "RX_BIAS"}, + {"LINEOUT1 PA", NULL, "RX INT3 DAC"}, + {"LINEOUT1", NULL, "LINEOUT1 PA"}, + + {"RX INT4_1 INTERP", NULL, "RX INT4_1 MIX1"}, + {"RX INT4 SEC MIX", NULL, "RX INT4_1 INTERP"}, + {"RX INT4 SEC MIX", NULL, "RX INT4_1 MIX1"}, + {"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"}, + {"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"}, + {"RX INT4 MIX3", NULL, "RX INT4 MIX2"}, + {"RX INT4 DAC", NULL, "RX INT4 MIX3"}, + {"RX INT4 DAC", NULL, "RX_BIAS"}, + {"LINEOUT2 PA", NULL, "RX INT4 DAC"}, + {"LINEOUT2", NULL, "LINEOUT2 PA"}, + + {"RX INT7_1 INTERP", NULL, "RX INT7_1 MIX1"}, + {"RX INT7 SEC MIX", NULL, "RX INT7_1 INTERP"}, + {"RX INT7 MIX2", NULL, "RX INT7 SEC MIX"}, + {"RX INT7 MIX2", NULL, "RX INT7 MIX2 INP"}, + {"RX INT7 CHAIN", NULL, "RX INT7 MIX2"}, + {"RX INT7 CHAIN", NULL, "RX_BIAS"}, + {"SPK1 OUT", NULL, "RX INT7 CHAIN"}, + + {"RX INT8_1 INTERP", NULL, "RX INT8_1 MIX1"}, + {"RX INT8 SEC MIX", NULL, "RX INT8_1 INTERP"}, + {"RX INT8 SEC MIX", NULL, "RX INT8_1 MIX1"}, + {"RX INT8 CHAIN", NULL, "RX INT8 SEC MIX"}, + {"RX INT8 CHAIN", NULL, "RX_BIAS"}, + {"SPK2 OUT", NULL, "RX INT8 CHAIN"}, + + /* ANC Routing */ + {"ANC0 FB MUX", "ANC_IN_EAR", "RX INT0 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_HPHL", "RX INT1 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_LO1", "RX INT3 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_EAR_SPKR", "RX INT7 MIX2"}, + {"ANC1 FB MUX", "ANC_IN_HPHR", "RX INT2 MIX2"}, + {"ANC1 FB MUX", "ANC_IN_LO2", "RX INT4 MIX2"}, + + {"ANC OUT EAR Enable", "Switch", "ADC MUX10"}, + {"ANC OUT EAR Enable", "Switch", "ADC MUX11"}, + {"RX INT0 MIX2", NULL, "ANC OUT EAR Enable"}, + + {"ANC OUT HPHL Enable", "Switch", "ADC MUX10"}, + {"ANC OUT HPHL Enable", "Switch", "ADC MUX11"}, + {"RX INT1 MIX2", NULL, "ANC OUT HPHL Enable"}, + + {"ANC OUT HPHR Enable", "Switch", "ADC MUX12"}, + {"ANC OUT HPHR Enable", "Switch", "ADC MUX13"}, + {"RX INT2 MIX2", NULL, "ANC OUT HPHR Enable"}, + + {"ANC EAR PA", NULL, "RX INT0 DAC"}, + {"ANC EAR", NULL, "ANC EAR PA"}, + + {"ANC HPHL PA", NULL, "RX INT1 DAC"}, + {"ANC HPHL", NULL, "ANC HPHL PA"}, + + {"ANC HPHR PA", NULL, "RX INT2 DAC"}, + {"ANC HPHR", NULL, "ANC HPHR PA"}, + + {"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX10"}, + {"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX11"}, + {"RX INT7 MIX2", NULL, "ANC OUT EAR SPKR Enable"}, + + {"ANC SPKR PA Enable", "Switch", "RX INT7 CHAIN"}, + {"ANC SPK1 PA", NULL, "ANC SPKR PA Enable"}, + {"SPK1 OUT", NULL, "ANC SPK1 PA"}, + + /* + * SRC0, SRC1 inputs to Sidetone RX Mixer + * on RX0, RX1, RX2, RX3, RX4 and RX7 chains + */ + {"IIR0", NULL, "IIR0 INP0 MUX"}, + {"IIR0 INP0 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP0 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP0 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP0 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP0 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP0 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP0 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP0 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP0 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP0 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP0 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP0 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP0 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP0 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP0 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP0 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP0 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR0", NULL, "IIR0 INP1 MUX"}, + {"IIR0 INP1 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP1 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP1 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP1 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP1 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP1 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP1 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP1 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP1 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP1 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP1 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP1 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP1 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP1 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP1 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP1 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP1 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR0", NULL, "IIR0 INP2 MUX"}, + {"IIR0 INP2 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP2 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP2 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP2 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP2 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP2 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP2 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP2 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP2 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR0", NULL, "IIR0 INP3 MUX"}, + {"IIR0 INP3 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP3 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP3 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP3 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP3 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP3 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP3 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP3 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP3 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP3 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP3 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP3 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP3 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP3 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP3 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP3 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP3 MUX", "RX7", "CDC_IF RX7 MUX"}, + + {"IIR1", NULL, "IIR1 INP0 MUX"}, + {"IIR1 INP0 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP0 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP0 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP0 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP0 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP0 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP0 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP0 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP0 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP0 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP0 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP0 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP0 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP0 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP0 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP0 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP0 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR1", NULL, "IIR1 INP1 MUX"}, + {"IIR1 INP1 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP1 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP1 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP1 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP1 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP1 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP1 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP1 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP1 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP1 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP1 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP1 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP1 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP1 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP1 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP1 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP1 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR1", NULL, "IIR1 INP2 MUX"}, + {"IIR1 INP2 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP2 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP2 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP2 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP2 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP2 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP2 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP2 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP2 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR1", NULL, "IIR1 INP3 MUX"}, + {"IIR1 INP3 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP3 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP3 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP3 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP3 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP3 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP3 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP3 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP3 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP3 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP3 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP3 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP3 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP3 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP3 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP3 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP3 MUX", "RX7", "CDC_IF RX7 MUX"}, + + {"SRC0", NULL, "IIR0"}, + {"SRC1", NULL, "IIR1"}, + {"RX INT0 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT0 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT1 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT1 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT2 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT2 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT3 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT3 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT4 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT4 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT7 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT7 MIX2 INP", "SRC1", "SRC1"}, + + /* Native clk main path routing */ + {"RX INT1_1 NATIVE MUX", "ON", "RX INT1_1 MIX1"}, + {"RX INT1_1 INTERP", NULL, "RX INT1_1 NATIVE MUX"}, + {"RX INT1_1 NATIVE MUX", NULL, "RX INT1 NATIVE SUPPLY"}, + + {"RX INT2_1 NATIVE MUX", "ON", "RX INT2_1 MIX1"}, + {"RX INT2_1 INTERP", NULL, "RX INT2_1 NATIVE MUX"}, + {"RX INT2_1 NATIVE MUX", NULL, "RX INT2 NATIVE SUPPLY"}, + + {"RX INT3_1 NATIVE MUX", "ON", "RX INT3_1 MIX1"}, + {"RX INT3_1 INTERP", NULL, "RX INT3_1 NATIVE MUX"}, + {"RX INT3_1 NATIVE MUX", NULL, "RX INT3 NATIVE SUPPLY"}, + + {"RX INT4_1 NATIVE MUX", "ON", "RX INT4_1 MIX1"}, + {"RX INT4_1 INTERP", NULL, "RX INT4_1 NATIVE MUX"}, + {"RX INT4_1 NATIVE MUX", NULL, "RX INT4 NATIVE SUPPLY"}, + + /* Native clk mix path routing */ + {"RX INT1_2 NATIVE MUX", "ON", "RX INT1_2 MUX"}, + {"RX INT1_2 INTERP", NULL, "RX INT1_2 NATIVE MUX"}, + {"RX INT1_2 NATIVE MUX", NULL, "RX INT1 NATIVE SUPPLY"}, + + {"RX INT2_2 NATIVE MUX", "ON", "RX INT2_2 MUX"}, + {"RX INT2_2 INTERP", NULL, "RX INT2_2 NATIVE MUX"}, + {"RX INT2_2 NATIVE MUX", NULL, "RX INT2 NATIVE SUPPLY"}, + + {"RX INT3_2 NATIVE MUX", "ON", "RX INT3_2 MUX"}, + {"RX INT3_2 INTERP", NULL, "RX INT3_2 NATIVE MUX"}, + {"RX INT3_2 NATIVE MUX", NULL, "RX INT3 NATIVE SUPPLY"}, + + {"RX INT4_2 NATIVE MUX", "ON", "RX INT4_2 MUX"}, + {"RX INT4_2 INTERP", NULL, "RX INT4_2 NATIVE MUX"}, + {"RX INT4_2 NATIVE MUX", NULL, "RX INT4 NATIVE SUPPLY"}, + + {"RX INT7_2 NATIVE MUX", "ON", "RX INT7_2 MUX"}, + {"RX INT7_2 INTERP", NULL, "RX INT7_2 NATIVE MUX"}, + {"RX INT7_2 NATIVE MUX", NULL, "RX INT7 NATIVE SUPPLY"}, + + {"RX INT8_2 NATIVE MUX", "ON", "RX INT8_2 MUX"}, + {"RX INT8_2 INTERP", NULL, "RX INT8_2 NATIVE MUX"}, + {"RX INT8_2 NATIVE MUX", NULL, "RX INT8 NATIVE SUPPLY"}, + + /* ASRC Routing */ + {"ASRC0 MUX", "ASRC_IN_HPHL", "RX INT1_2 INTERP"}, + {"RX INT1 SEC MIX", "HPHL Switch", "ASRC0 MUX"}, + + {"ASRC1 MUX", "ASRC_IN_HPHR", "RX INT2_2 INTERP"}, + {"RX INT2 SEC MIX", "HPHR Switch", "ASRC1 MUX"}, + + {"ASRC0 MUX", "ASRC_IN_LO1", "RX INT3_2 INTERP"}, + {"RX INT3 SEC MIX", "LO1 Switch", "ASRC0 MUX"}, + + {"ASRC1 MUX", "ASRC_IN_LO2", "RX INT4_2 INTERP"}, + {"RX INT4 SEC MIX", "LO2 Switch", "ASRC1 MUX"}, + + {"ASRC2 MUX", "ASRC_IN_SPKR1", "RX INT7_2 INTERP"}, + {"RX INT7 SEC MIX", NULL, "ASRC2 MUX"}, + + {"ASRC3 MUX", "ASRC_IN_SPKR2", "RX INT8_2 INTERP"}, + {"RX INT8 SEC MIX", NULL, "ASRC3 MUX"}, +}; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-tables.c new file mode 100644 index 0000000000..a74004fc25 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x-tables.c @@ -0,0 +1,2147 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + */ + +#include +#include + +#define WCD934X_REG(reg) ((reg) & 0xFF) + +const u8 wcd934x_page0_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE0_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_BYPASS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_GATE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_MCLK_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_MCLK2_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_I2S_DSD_CLK_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_TEST0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT4)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT5)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT7)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT10)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT11)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT12)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT13)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_SLNQ_WAIT_STATE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_ACTIVE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX0_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX1_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX2_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX3_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX4_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX5_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX6_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX7_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX0_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX1_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX2_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX3_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX4_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX5_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX6_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX7_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX8_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX9_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX10_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX11_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX13_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX14_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX15_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_TX0_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_TX1_0_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_TX1_1_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_0_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_3_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_CLKSRC_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_0_TDM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA4_PRT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_SBTX0_7_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_SBTX8_11_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA0_PRT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA3_PRT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA4_PRT0_3_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA4_PRT4_7_CFG)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page1_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE1_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FLL_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FLL_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FLL_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_3)] = WCD934X_READ, +}; + +const u8 wcd934x_page2_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE2_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPEFLL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_US_BUF_INT_PERIOD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SVA_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_US_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_MAD_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPAR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC0_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPAR_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_WDOG_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_BACKUP_INT)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_STATUS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPE_OCD_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1A)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1B)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_MAIN_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_MAIN_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_INP_SEL)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page4_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE4_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CLR_COMMIT)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR0)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR1)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR2)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN2_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN2_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN2_CLEAR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_MASK2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_STATUS2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_CLEAR2)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_CLEAR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CODEC_MISC_MASK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CODEC_MISC_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_CODEC_MISC_CLEAR)] = WCD934X_WRITE, +}; + +const u8 wcd934x_page5_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE5_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEVICE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_REVISION)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_H_COMMAND)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_MASTER_ADDRESS_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_MASTER_ADDRESS_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SLAVE_ADDRESS_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SLAVE_ADDRESS_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_COMM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_FRAME_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH1_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH3_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SW_EVENT_RD)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_SW_EVENT_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SAMPLING_FREQ)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_SEL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_RAM_CNTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BANK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_10)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_11)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_12)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_13)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_14)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_15)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_16)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_17)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_18)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_19)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_20)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_21)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_22)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_23)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_24)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_25)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_26)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_27)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_28)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_29)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_30)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_31)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_32)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_33)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_34)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_35)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_36)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_37)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_38)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_39)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TOP_CTRL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TOP_CTRL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_MUTE_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_STATUS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_FS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_IN_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_GPOUT_ENABLE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_GPOUT_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_MASK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_IP_TESTING)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS4)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR0)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR1)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR2)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR4)] = WCD934X_WRITE, +}; + +const u8 wcd934x_page6_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_ANA_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_BIAS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_RCO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_PAGE6_SPARE2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_PAGE6_SPARE3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_BUCK_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_BUCK_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_RX_SUPPLIES)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_HPH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_EAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_LO_1_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MAD_SETUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_MECH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_ELECT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_ZDET)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_RESULT_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_MBHC_RESULT_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_MBHC_RESULT_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB2_RAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_VBADC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BIAS_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BIAS_VBG_FINE_ADJ)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CTRL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_TEST_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_4)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_5)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_MODE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_MODE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_MODE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_MODE_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_VCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_VCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_VCL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_10)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_FILTER_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_FILTER_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_DRIVER_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_DRIVER_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_DRIVER_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_EXT_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_EXT_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_OUT_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_OUT_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_TEST_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_TEST_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_CLK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_ANA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_SPARE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_SPARE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_BCS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_STATUS_SPARE_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MBHC_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_SUBBLOCK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_IBIAS_FE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_BIAS_ADC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_FE_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_ADC_REF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_ADC_IO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_ADC_SAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_DEBUG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_BIAS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_STB_LOADS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_SLOWRAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB1_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB1_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB1_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB2_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB2_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB2_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB3_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB3_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB3_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB4_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB4_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB4_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_ADC_VCM)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_BIAS_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_ADC_INT1_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_ADC_INT2_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_START)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_STOP_9P6M)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_STOP_12P288M)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TEST_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_ADC_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_ATEST_REFCTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TEST_BLK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TXFE_CLKDIV)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_SAR1_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_1_2_SAR2_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_3_4_TEST_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_ADC_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_ATEST_REFCTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_TEST_BLK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_TXFE_CLKDIV)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_SAR1_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_3_4_SAR2_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CLASSH_MODE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_MODE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_MODE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_VCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_VCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_BUCK_TMUX_A_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_BUCK_SW_DRV_CNTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_SPARE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_AUX_SW_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_PA_AUX_IN_CONN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_TIMER_DIV)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_OCP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_OCP_COUNT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_EAR_DAC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_EAR_AMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_LDO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_RDACBUFF_CNP2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_RDAC_LDO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_CNP1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_LOWPOWER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_REF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_LDO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_SELO_DAC_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_BUCK_RST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_BUCK_VREF_ERRAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_FLYB_ERRAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_FLYB_BUFF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_FLYB_MID_RST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_HPH_R_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_HPH_CNP_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_CNP_WG_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_CNP_WG_TIME)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_OCP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_AUTO_CHOP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_CHOP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_PA_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_PA_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_CLK_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_CLK_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_LDO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_REFBUFF_UHQA_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_REFBUFF_LP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_DAC_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_DAC_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_EN_REG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_CMBUFF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_ICTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_EN_DBG_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_CNP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_DAC_CTL_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_STATUS_REG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EAR_EAR_MISC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_MISC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LO2_COMPANDER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LO1_COMPANDER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_COMMON)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_BYPASS_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_CNP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_CORE_OUT_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LDO_OUT_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_COM_SWCAP_REFBUF_FREQ)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_COM_PA_FREQ)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_RESERVED_REG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LO1_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_DIFF_LO_LO1_STATUS_2)] = WCD934X_READ, +}; + +const u8 wcd934x_page7_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_ANA_NEW_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_ANA_HPH2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_ANA_HPH3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_ANA_LDO_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_LDO_OCP_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_TX_LDO_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_TX_DRV_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_RX_CONFIG_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_RX_CONFIG_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_PLL_ENABLES)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_PLL_PRESET)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_PLL_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CLK_SYS_PLL_ENABLES)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_PLL_PRESET)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_PLL_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CLK_SYS_MCLK_PRG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_MCLK2_PRG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_MCLK2_PRG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_XO_PRG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_XO_CAP_XTP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_XO_CAP_XTM)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_BST_EN_DLY)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_CTRL_ILIM)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_VOUT_SETTING)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_A_STARTUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_STARTUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_FREQ1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_FREQ2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_ELECT_REM_CLAMP_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_PLUG_DETECT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_ZDET_ANA_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_ZDET_RAMP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_FSM_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MBHC_NEW_ADC_RESULT)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_NEW_AMIC_4_5_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_NEW_ADC_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_NEW_ADC_DOUTMSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_VBADC_NEW_ADC_DOUTLSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_HD2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_VREF_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_MISC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_MISC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_MISC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_LDO_LP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_TX_LDO_TEST)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_TX_DRV_TEST)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_TEST_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_CLK_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RESERVED_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RESERVED_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_L_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_M_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_N_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_PFD_CP_DSM_PROG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_VCO_PROG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_LDO_LOCK_CFG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_DIG_LOCK_DET_CFG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_POST_DIV_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_POST_DIV_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_REF_DIV_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_REF_DIV_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_FILTER_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_FILTER_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_L_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_M_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_N_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_TEST_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_VCO_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_TEST_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_LDO_LOCK_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_XO_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_XO_TEST2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_VCOMP_HYST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_VLOOP_FILTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_IDELTA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_ILIM_STARTUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_MIN_ONTIME)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_MAX_ONTIME)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_TIMING)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_TMUX_A_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_SW_DRV_CNTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_SPARE1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_SPARE2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_SPARE_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_A)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_D)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_INC_WAIT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_IBLEED_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_CPROVR_TEST)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_CTL_A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_CTL_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_TIMEOUT_PERIOD)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_HPF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_REF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_COMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SPARE_2)] = WCD934X_READ_WRITE, + +}; + +const u8 wcd934x_page10_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE10_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_CLK_RESET_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_MODE_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_MODE_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FF_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FB_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_LPF_FF_A_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_LPF_FF_B_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_LPF_FB_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_SMLPF_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_DCFLT_SHIFT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_IIR_ADAPT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_IIR_COEFF_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_IIR_COEFF_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FF_A_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FF_B_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FB_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_RC_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FIFO_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_RC0_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_RC1_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_RC0_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_RC1_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_CLK_RESET_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_MODE_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_MODE_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FF_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FB_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_LPF_FF_A_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_LPF_FF_B_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_LPF_FB_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_SMLPF_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_DCFLT_SHIFT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_IIR_ADAPT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_IIR_COEFF_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_IIR_COEFF_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FF_A_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FF_B_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FB_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_RC_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FIFO_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_RC0_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_RC1_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_RC0_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_RC1_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0)] = + WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page11_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE11_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page12_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE12_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_CRC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_DLY_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_DECAY_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_HPH_V_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_EAR_V_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_HPH_V_HD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_EAR_V_HD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K1_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K1_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K2_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K2_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_IDLE_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_IDLE_HPH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_IDLE_EAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_TEST0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_OVR_VREF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_RF_PROC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_RF_PROC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_DEBUG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD_MON)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_MON_VAL)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_BAN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_ACCESS_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_REF_HQ0_EC_REF_HQ_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_REF_HQ0_EC_REF_HQ_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_REF_HQ1_EC_REF_HQ_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_REF_HQ1_EC_REF_HQ_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FIFO)] = WCD934X_READ, +}; + +const u8 wcd934x_page13_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE13_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_ANC_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_EC_REF_HQ_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_CTRL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DSD0_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG3)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page14_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE14_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_40_43)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_40_43)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_40_43)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_40_43)] = WCD934X_READ, +}; + +const u8 wcd934x_page15_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE15_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC0_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC0_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SPLINE_SRC1_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC1_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SPLINE_SRC2_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC2_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SPLINE_SRC3_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC3_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC0_RC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC0_RC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC1_RC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC1_RC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC_RC_RST_DBG_CNTR)] = + WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page_0x50_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE80_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_NOM_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_NOM_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_MAX_SVS2_STEP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_START)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_CPR_STATUS)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page_0x80_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE80_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_NOM_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_NOM_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_MAX_SVS2_STEP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_START)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_CPR_STATUS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_PAGE128_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_BIST_MODE_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_RF_PA_ON_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_INTR1_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_INTR2_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SWR_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SWR_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_2_SCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SLIMBUS_DATA1_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SLIMBUS_DATA2_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SLIMBUS_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2C_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2C_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_RX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_TX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_SCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_WS_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_RX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_TX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_SCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_WS_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC1_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC1_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC2_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC2_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC3_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC3_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_JTCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO1_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO2_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO3_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO4_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_CSN_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_DOUT_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_DIN_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_BA_N_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO0_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_2_RX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_2_WS_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_DRVCTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_DRVCTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TEST_DEBUG_NPL_DLY_TEST_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_NPL_DLY_TEST_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_MEM_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_BUS_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_JTAG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_ANA_DTEST_DIR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_SYSMEM_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_SOC_SW_PWR_SEQ_DELAY)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_NOM_LOW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_NOM_HIGH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_SPI_SLAVE_CHAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_CODEC_DIAGS)] = WCD934X_READ, +}; + +const u8 * const wcd934x_reg[WCD934X_NUM_PAGES] = { + [WCD934X_PAGE_0] = wcd934x_page0_reg_access, + [WCD934X_PAGE_1] = wcd934x_page1_reg_access, + [WCD934X_PAGE_2] = wcd934x_page2_reg_access, + [WCD934X_PAGE_4] = wcd934x_page4_reg_access, + [WCD934X_PAGE_5] = wcd934x_page5_reg_access, + [WCD934X_PAGE_6] = wcd934x_page6_reg_access, + [WCD934X_PAGE_7] = wcd934x_page7_reg_access, + [WCD934X_PAGE_10] = wcd934x_page10_reg_access, + [WCD934X_PAGE_11] = wcd934x_page11_reg_access, + [WCD934X_PAGE_12] = wcd934x_page12_reg_access, + [WCD934X_PAGE_13] = wcd934x_page13_reg_access, + [WCD934X_PAGE_14] = wcd934x_page14_reg_access, + [WCD934X_PAGE_15] = wcd934x_page15_reg_access, + [WCD934X_PAGE_0x50] = wcd934x_page_0x50_reg_access, + [WCD934X_PAGE_0X80] = wcd934x_page_0x80_reg_access, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x.c new file mode 100644 index 0000000000..92139363af --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x.c @@ -0,0 +1,11497 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd934x.h" +#include "wcd934x-mbhc.h" +#include "wcd934x-routing.h" +#include "wcd934x-dsp-cntl.h" +#include "wcd934x_irq.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd934x-dsd.h" + +#define WCD934X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD934X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400) + +#define WCD934X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +#define WCD934X_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define WCD934X_FORMATS_S16_LE (SNDRV_PCM_FMTBIT_S16_LE) + +#define MICB_LOAD_PROP "qcom,vreg-micb" +#define MICB_LOAD_DEFAULT 30400 + +/* Macros for packing register writes into a U32 */ +#define WCD934X_PACKED_REG_SIZE sizeof(u32) +#define WCD934X_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \ + do { \ + ((reg) = ((packed >> 16) & (0xffff))); \ + ((mask) = ((packed >> 8) & (0xff))); \ + ((val) = ((packed) & (0xff))); \ + } while (0) + +#define STRING(name) #name +#define WCD_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define WCD_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define WCD_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +/* + * Timeout in milli seconds and it is the wait time for + * slim channel removal interrupt to receive. + */ +#define WCD934X_SLIM_CLOSE_TIMEOUT 1000 +#define WCD934X_SLIM_IRQ_OVERFLOW (1 << 0) +#define WCD934X_SLIM_IRQ_UNDERFLOW (1 << 1) +#define WCD934X_SLIM_IRQ_PORT_CLOSED (1 << 2) +#define WCD934X_MCLK_CLK_12P288MHZ 12288000 +#define WCD934X_MCLK_CLK_9P6MHZ 9600000 + +#define WCD934X_INTERP_MUX_NUM_INPUTS 3 +#define WCD934X_NUM_INTERPOLATORS 9 +#define WCD934X_NUM_DECIMATORS 9 +#define WCD934X_RX_PATH_CTL_OFFSET 20 + +#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE)) + +#define WCD934X_REG_BITS 8 +#define WCD934X_MAX_VALID_ADC_MUX 13 +#define WCD934X_INVALID_ADC_MUX 9 + +#define WCD934X_AMIC_PWR_LEVEL_LP 0 +#define WCD934X_AMIC_PWR_LEVEL_DEFAULT 1 +#define WCD934X_AMIC_PWR_LEVEL_HP 2 +#define WCD934X_AMIC_PWR_LEVEL_HYBRID 3 +#define WCD934X_AMIC_PWR_LVL_MASK 0x60 +#define WCD934X_AMIC_PWR_LVL_SHIFT 0x5 + +#define WCD934X_DEC_PWR_LVL_MASK 0x06 +#define WCD934X_DEC_PWR_LVL_LP 0x02 +#define WCD934X_DEC_PWR_LVL_HP 0x04 +#define WCD934X_DEC_PWR_LVL_DF 0x00 +#define WCD934X_DEC_PWR_LVL_HYBRID WCD934X_DEC_PWR_LVL_DF +#define WCD934X_STRING_LEN 100 + +#define WCD934X_CDC_SIDETONE_IIR_COEFF_MAX 5 +#define WCD934X_CDC_REPEAT_WRITES_MAX 16 +#define WCD934X_DIG_CORE_REG_MIN WCD934X_CDC_ANC0_CLK_RESET_CTL +#define WCD934X_DIG_CORE_REG_MAX 0xFFF + +#define WCD934X_CHILD_DEVICES_MAX 6 + +#define WCD934X_MAX_MICBIAS 4 +#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone" +#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone" +#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone" +#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone" + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +#define CPE_ERR_WDOG_BITE BIT(0) +#define CPE_FATAL_IRQS CPE_ERR_WDOG_BITE + +#define WCD934X_MAD_AUDIO_FIRMWARE_PATH "wcd934x/wcd934x_mad_audio.bin" + +#define TAVIL_VERSION_ENTRY_SIZE 17 + +#define WCD934X_DIG_CORE_COLLAPSE_TIMER_MS (5 * 1000) + +enum { + POWER_COLLAPSE, + POWER_RESUME, +}; + +static int dig_core_collapse_enable = 1; +module_param(dig_core_collapse_enable, int, 0664); +MODULE_PARM_DESC(dig_core_collapse_enable, "enable/disable power gating"); + +/* dig_core_collapse timer in seconds */ +static int dig_core_collapse_timer = (WCD934X_DIG_CORE_COLLAPSE_TIMER_MS/1000); +module_param(dig_core_collapse_timer, int, 0664); +MODULE_PARM_DESC(dig_core_collapse_timer, "timer for power gating"); + +#define TAVIL_HPH_REG_RANGE_1 (WCD934X_HPH_R_DAC_CTL - WCD934X_HPH_CNP_EN + 1) +#define TAVIL_HPH_REG_RANGE_2 (WCD934X_HPH_NEW_ANA_HPH3 -\ + WCD934X_HPH_NEW_ANA_HPH2 + 1) +#define TAVIL_HPH_REG_RANGE_3 (WCD934X_HPH_NEW_INT_PA_RDAC_MISC3 -\ + WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL + 1) +#define TAVIL_HPH_TOTAL_REG (TAVIL_HPH_REG_RANGE_1 + TAVIL_HPH_REG_RANGE_2 +\ + TAVIL_HPH_REG_RANGE_3) + +enum { + VI_SENSE_1, + VI_SENSE_2, + AUDIO_NOMINAL, + HPH_PA_DELAY, + CLSH_Z_CONFIG, + ANC_MIC_AMIC1, + ANC_MIC_AMIC2, + ANC_MIC_AMIC3, + ANC_MIC_AMIC4, + CLK_INTERNAL, + CLK_MODE, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + AIF2_PB, + AIF2_CAP, + AIF3_PB, + AIF3_CAP, + AIF4_PB, + AIF4_VIFEED, + AIF4_MAD_TX, + NUM_CODEC_DAIS, +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, + INTn_1_INP_SEL_IIR0, + INTn_1_INP_SEL_IIR1, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_RX4, + INTn_1_INP_SEL_RX5, + INTn_1_INP_SEL_RX6, + INTn_1_INP_SEL_RX7, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_PROXIMITY, +}; + +enum { + INTERP_MAIN_PATH, + INTERP_MIX_PATH, +}; + +struct tavil_idle_detect_config { + u8 hph_idle_thr; + u8 hph_idle_detect_en; +}; + +struct tavil_cpr_reg_defaults { + int wr_data; + int wr_addr; +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +static struct interp_sample_rate sr_val_tbl[] = { + {8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5}, + {192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA}, + {176400, 0xB}, {352800, 0xC}, +}; + +static const struct wcd9xxx_ch tavil_rx_chs[WCD934X_RX_MAX] = { + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER, 0), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 1, 1), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 2, 2), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 3, 3), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 4, 4), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 5, 5), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 6, 6), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 7, 7), +}; + +static const struct wcd9xxx_ch tavil_tx_chs[WCD934X_TX_MAX] = { + WCD9XXX_CH(0, 0), + WCD9XXX_CH(1, 1), + WCD9XXX_CH(2, 2), + WCD9XXX_CH(3, 3), + WCD9XXX_CH(4, 4), + WCD9XXX_CH(5, 5), + WCD9XXX_CH(6, 6), + WCD9XXX_CH(7, 7), + WCD9XXX_CH(8, 8), + WCD9XXX_CH(9, 9), + WCD9XXX_CH(10, 10), + WCD9XXX_CH(11, 11), + WCD9XXX_CH(12, 12), + WCD9XXX_CH(13, 13), + WCD9XXX_CH(14, 14), + WCD9XXX_CH(15, 15), +}; + +static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = { + 0, /* AIF1_PB */ + BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX), /* AIF1_CAP */ + 0, /* AIF2_PB */ + BIT(AIF1_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX), /* AIF2_CAP */ + 0, /* AIF3_PB */ + BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF4_MAD_TX), /* AIF3_CAP */ + 0, /* AIF4_PB */ +}; + +/* Codec supports 2 IIR filters */ +enum { + IIR0 = 0, + IIR1, + IIR_MAX, +}; + +/* Each IIR has 5 Filter Stages */ +enum { + BAND1 = 0, + BAND2, + BAND3, + BAND4, + BAND5, + BAND_MAX, +}; + +enum { + COMPANDER_1, /* HPH_L */ + COMPANDER_2, /* HPH_R */ + COMPANDER_3, /* LO1_DIFF */ + COMPANDER_4, /* LO2_DIFF */ + COMPANDER_5, /* LO3_SE - not used in Tavil */ + COMPANDER_6, /* LO4_SE - not used in Tavil */ + COMPANDER_7, /* SWR SPK CH1 */ + COMPANDER_8, /* SWR SPK CH2 */ + COMPANDER_MAX, +}; + +enum { + ASRC_IN_HPHL, + ASRC_IN_LO1, + ASRC_IN_HPHR, + ASRC_IN_LO2, + ASRC_IN_SPKR1, + ASRC_IN_SPKR2, + ASRC_INVALID, +}; + +enum { + ASRC0, + ASRC1, + ASRC2, + ASRC3, + ASRC_MAX, +}; + +enum { + CONV_88P2K_TO_384K, + CONV_96K_TO_352P8K, + CONV_352P8K_TO_384K, + CONV_384K_TO_352P8K, + CONV_384K_TO_384K, + CONV_96K_TO_384K, +}; + +static struct afe_param_slimbus_slave_port_cfg tavil_slimbus_slave_port_cfg = { + .minor_version = 1, + .slimbus_dev_id = AFE_SLIMBUS_DEVICE_1, + .slave_dev_pgd_la = 0, + .slave_dev_intfdev_la = 0, + .bit_width = 16, + .data_format = 0, + .num_channels = 1 +}; + +static struct afe_param_cdc_reg_page_cfg tavil_cdc_reg_page_cfg = { + .minor_version = AFE_API_VERSION_CDC_REG_PAGE_CFG, + .enable = 1, + .proc_id = AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_1, +}; + +static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = { + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_MAIN_CTL_1), + HW_MAD_AUDIO_ENABLE, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_AUDIO_CTL_3), + HW_MAD_AUDIO_SLEEP_TIME, 0xF, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_AUDIO_CTL_4), + HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_CFG), + MAD_AUDIO_INT_DEST_SELECT_REG, 0x2, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_MASK3), + MAD_AUDIO_INT_MASK_REG, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_STATUS3), + MAD_AUDIO_INT_STATUS_REG, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_CLEAR3), + MAD_AUDIO_INT_CLEAR_REG, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_TX_BASE), + SB_PGD_PORT_TX_WATERMARK_N, 0x1E, WCD934X_REG_BITS, 0x1 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_TX_BASE), + SB_PGD_PORT_TX_ENABLE_N, 0x1, WCD934X_REG_BITS, 0x1 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_RX_BASE), + SB_PGD_PORT_RX_WATERMARK_N, 0x1E, WCD934X_REG_BITS, 0x1 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_RX_BASE), + SB_PGD_PORT_RX_ENABLE_N, 0x1, WCD934X_REG_BITS, 0x1 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + WCD934X_CDC_ANC0_IIR_ADAPT_CTL), + AANC_FF_GAIN_ADAPTIVE, 0x4, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + WCD934X_CDC_ANC0_IIR_ADAPT_CTL), + AANC_FFGAIN_ADAPTIVE_EN, 0x8, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + WCD934X_CDC_ANC0_FF_A_GAIN_CTL), + AANC_GAIN_CONTROL, 0xFF, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + SB_PGD_TX_PORT_MULTI_CHANNEL_0(0)), + SB_PGD_TX_PORTn_MULTI_CHNL_0, 0xFF, WCD934X_REG_BITS, 0x4 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + SB_PGD_TX_PORT_MULTI_CHANNEL_1(0)), + SB_PGD_TX_PORTn_MULTI_CHNL_1, 0xFF, WCD934X_REG_BITS, 0x4 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + SB_PGD_RX_PORT_MULTI_CHANNEL_0(0x180, 0)), + SB_PGD_RX_PORTn_MULTI_CHNL_0, 0xFF, WCD934X_REG_BITS, 0x4 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + SB_PGD_RX_PORT_MULTI_CHANNEL_0(0x181, 0)), + SB_PGD_RX_PORTn_MULTI_CHNL_1, 0xFF, WCD934X_REG_BITS, 0x4 + }, +}; + +static struct afe_param_cdc_reg_cfg_data tavil_audio_reg_cfg = { + .num_registers = ARRAY_SIZE(audio_reg_cfg), + .reg_data = audio_reg_cfg, +}; + +static struct afe_param_id_cdc_aanc_version tavil_cdc_aanc_version = { + .cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION, + .aanc_hw_version = AANC_HW_BLOCK_VERSION_2, +}; + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +#define WCD934X_TX_UNMUTE_DELAY_MS 40 + +static int tx_unmute_delay = WCD934X_TX_UNMUTE_DELAY_MS; +module_param(tx_unmute_delay, int, 0664); +MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path"); + +static void tavil_codec_set_tx_hold(struct snd_soc_component *, u16, bool); + +/* Hold instance to soundwire platform device */ +struct tavil_swr_ctrl_data { + struct platform_device *swr_pdev; +}; + +struct wcd_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, void *data), + void *swrm_handle, int action); +}; + +/* Holds all Soundwire and speaker related information */ +struct wcd934x_swr { + struct tavil_swr_ctrl_data *ctrl_data; + struct wcd_swr_ctrl_platform_data plat_data; + struct mutex read_mutex; + struct mutex write_mutex; + struct mutex clk_mutex; + int spkr_gain_offset; + int spkr_mode; + int clk_users; + int rx_7_count; + int rx_8_count; +}; + +struct tx_mute_work { + struct tavil_priv *tavil; + u8 decimator; + struct delayed_work dwork; +}; + +#define WCD934X_SPK_ANC_EN_DELAY_MS 550 +static int spk_anc_en_delay = WCD934X_SPK_ANC_EN_DELAY_MS; +module_param(spk_anc_en_delay, int, 0664); +MODULE_PARM_DESC(spk_anc_en_delay, "delay to enable anc in speaker path"); + +struct spk_anc_work { + struct tavil_priv *tavil; + struct delayed_work dwork; +}; + +struct hpf_work { + struct tavil_priv *tavil; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +struct tavil_priv { + struct device *dev; + struct wcd9xxx *wcd9xxx; + struct snd_soc_component *component; + u32 rx_bias_count; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + s32 micb_ref[TAVIL_MAX_MICBIAS]; + s32 pullup_ref[TAVIL_MAX_MICBIAS]; + + /* ANC related */ + u32 anc_slot; + bool anc_func; + + /* compander */ + int comp_enabled[COMPANDER_MAX]; + int ear_spkr_gain; + + /* class h specific data */ + struct wcd_clsh_cdc_data clsh_d; + /* Tavil Interpolator Mode Select for EAR, HPH_L and HPH_R */ + u32 hph_mode; + + /* Mad switch reference count */ + int mad_switch_cnt; + + /* track tavil interface type */ + u8 intf_type; + + /* to track the status */ + unsigned long status_mask; + + struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg; + + /* num of slim ports required */ + struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS]; + /* Port values for Rx and Tx codec_dai */ + unsigned int rx_port_value[WCD934X_RX_MAX]; + unsigned int tx_port_value; + + struct wcd9xxx_resmgr_v2 *resmgr; + struct wcd934x_swr swr; + struct mutex micb_lock; + + struct delayed_work power_gate_work; + struct mutex power_lock; + + struct clk *wcd_ext_clk; + + /* mbhc module */ + struct wcd934x_mbhc *mbhc; + + struct mutex codec_mutex; + struct work_struct tavil_add_child_devices_work; + struct hpf_work tx_hpf_work[WCD934X_NUM_DECIMATORS]; + struct tx_mute_work tx_mute_dwork[WCD934X_NUM_DECIMATORS]; + struct spk_anc_work spk_anc_dwork; + + unsigned int vi_feed_value; + + /* DSP control */ + struct wcd_dsp_cntl *wdsp_cntl; + + /* cal info for codec */ + struct fw_info *fw_data; + + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + + /* SVS voting related */ + struct mutex svs_mutex; + int svs_ref_cnt; + + int native_clk_users; + /* ASRC users count */ + int asrc_users[ASRC_MAX]; + int asrc_output_mode[ASRC_MAX]; + /* Main path clock users count */ + int main_clk_users[WCD934X_NUM_INTERPOLATORS]; + struct tavil_dsd_config *dsd_config; + struct tavil_idle_detect_config idle_det_cfg; + + int power_active_ref; + u8 sidetone_coeff_array[IIR_MAX][BAND_MAX] + [WCD934X_CDC_SIDETONE_IIR_COEFF_MAX * 4]; + + struct spi_device *spi; + struct platform_device *pdev_child_devices + [WCD934X_CHILD_DEVICES_MAX]; + int child_count; + struct regulator *micb_load; + int micb_load_low; + int micb_load_high; +}; + +static const struct tavil_reg_mask_val tavil_spkr_default[] = { + {WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x58}, + {WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x58}, +}; + +static const struct tavil_reg_mask_val tavil_spkr_mode1[] = { + {WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x00}, + {WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x00}, + {WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x00}, + {WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x00}, + {WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x44}, + {WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44}, +}; + +static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil); + +/** + * tavil_set_spkr_gain_offset - offset the speaker path + * gain with the given offset value. + * + * @component: codec component instance + * @offset: Indicates speaker path gain offset value. + * + * Returns 0 on success or -EINVAL on error. + */ +int tavil_set_spkr_gain_offset(struct snd_soc_component *component, int offset) +{ + struct tavil_priv *priv = snd_soc_component_get_drvdata(component); + + if (!priv) + return -EINVAL; + + priv->swr.spkr_gain_offset = offset; + return 0; +} +EXPORT_SYMBOL(tavil_set_spkr_gain_offset); + +/** + * tavil_set_spkr_mode - Configures speaker compander and smartboost + * settings based on speaker mode. + * + * @component: codec component instance + * @mode: Indicates speaker configuration mode. + * + * Returns 0 on success or -EINVAL on error. + */ +int tavil_set_spkr_mode(struct snd_soc_component *component, int mode) +{ + struct tavil_priv *priv = snd_soc_component_get_drvdata(component); + int i; + const struct tavil_reg_mask_val *regs; + int size; + + if (!priv) + return -EINVAL; + + switch (mode) { + case WCD934X_SPKR_MODE_1: + regs = tavil_spkr_mode1; + size = ARRAY_SIZE(tavil_spkr_mode1); + break; + default: + regs = tavil_spkr_default; + size = ARRAY_SIZE(tavil_spkr_default); + break; + } + + priv->swr.spkr_mode = mode; + for (i = 0; i < size; i++) + snd_soc_component_update_bits(component, regs[i].reg, + regs[i].mask, regs[i].val); + return 0; +} +EXPORT_SYMBOL(tavil_set_spkr_mode); + +/** + * tavil_get_afe_config - returns specific codec configuration to afe to write + * + * @component: codec component instance + * @config_type: Indicates type of configuration to write. + */ +void *tavil_get_afe_config(struct snd_soc_component *component, + enum afe_config_type config_type) +{ + struct tavil_priv *priv = snd_soc_component_get_drvdata(component); + + switch (config_type) { + case AFE_SLIMBUS_SLAVE_CONFIG: + return &priv->slimbus_slave_cfg; + case AFE_CDC_REGISTERS_CONFIG: + return &tavil_audio_reg_cfg; + case AFE_SLIMBUS_SLAVE_PORT_CONFIG: + return &tavil_slimbus_slave_port_cfg; + case AFE_AANC_VERSION: + return &tavil_cdc_aanc_version; + case AFE_CDC_REGISTER_PAGE_CONFIG: + return &tavil_cdc_reg_page_cfg; + default: + dev_info(component->dev, "%s: Unknown config_type 0x%x\n", + __func__, config_type); + return NULL; + } +} +EXPORT_SYMBOL(tavil_get_afe_config); + +static bool is_tavil_playback_dai(int dai_id) +{ + if ((dai_id == AIF1_PB) || (dai_id == AIF2_PB) || + (dai_id == AIF3_PB) || (dai_id == AIF4_PB)) + return true; + + return false; +} + +static int tavil_find_playback_dai_id_for_port(int port_id, + struct tavil_priv *tavil) +{ + struct wcd9xxx_codec_dai_data *dai; + struct wcd9xxx_ch *ch; + int i, slv_port_id; + + for (i = AIF1_PB; i < NUM_CODEC_DAIS; i++) { + if (!is_tavil_playback_dai(i)) + continue; + + dai = &tavil->dai[i]; + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + slv_port_id = wcd9xxx_get_slave_port(ch->ch_num); + if ((slv_port_id > 0) && (slv_port_id == port_id)) + return i; + } + } + + return -EINVAL; +} + +static void tavil_vote_svs(struct tavil_priv *tavil, bool vote) +{ + struct wcd9xxx *wcd9xxx; + + wcd9xxx = tavil->wcd9xxx; + + mutex_lock(&tavil->svs_mutex); + if (vote) { + tavil->svs_ref_cnt++; + if (tavil->svs_ref_cnt == 1) + regmap_update_bits(wcd9xxx->regmap, + WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0, + 0x01, 0x01); + } else { + /* Do not decrement ref count if it is already 0 */ + if (tavil->svs_ref_cnt == 0) + goto done; + + tavil->svs_ref_cnt--; + if (tavil->svs_ref_cnt == 0) + regmap_update_bits(wcd9xxx->regmap, + WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0, + 0x01, 0x00); + } +done: + dev_dbg(tavil->dev, "%s: vote = %s, updated ref cnt = %u\n", __func__, + vote ? "vote" : "Unvote", tavil->svs_ref_cnt); + mutex_unlock(&tavil->svs_mutex); +} + +static int tavil_get_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tavil->anc_slot; + return 0; +} + +static int tavil_put_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + tavil->anc_slot = ucontrol->value.integer.value[0]; + return 0; +} + +static int tavil_get_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (tavil->anc_func == true ? 1 : 0); + return 0; +} + +static int tavil_put_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + + mutex_lock(&tavil->codec_mutex); + tavil->anc_func = (!ucontrol->value.integer.value[0] ? false : true); + dev_dbg(component->dev, "%s: anc_func %x", __func__, tavil->anc_func); + + if (tavil->anc_func == true) { + snd_soc_dapm_enable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_enable_pin(dapm, "ANC EAR"); + snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_enable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_disable_pin(dapm, "EAR PA"); + snd_soc_dapm_disable_pin(dapm, "EAR"); + snd_soc_dapm_disable_pin(dapm, "HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "HPHL"); + snd_soc_dapm_disable_pin(dapm, "HPHR"); + } else { + snd_soc_dapm_disable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR"); + snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_enable_pin(dapm, "EAR PA"); + snd_soc_dapm_enable_pin(dapm, "EAR"); + snd_soc_dapm_enable_pin(dapm, "HPHL"); + snd_soc_dapm_enable_pin(dapm, "HPHR"); + snd_soc_dapm_enable_pin(dapm, "HPHL PA"); + snd_soc_dapm_enable_pin(dapm, "HPHR PA"); + } + mutex_unlock(&tavil->codec_mutex); + + snd_soc_dapm_sync(dapm); + return 0; +} + +static int tavil_codec_enable_anc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + const char *filename; + const struct firmware *fw; + int i; + int ret = 0; + int num_anc_slots; + struct wcd9xxx_anc_header *anc_head; + struct firmware_cal *hwdep_cal = NULL; + u32 anc_writes_size = 0; + int anc_size_remaining; + u32 *anc_ptr; + u16 reg; + u8 mask, val; + size_t cal_size; + const void *data; + + if (!tavil->anc_func) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hwdep_cal = wcdcal_get_fw_cal(tavil->fw_data, WCD9XXX_ANC_CAL); + if (hwdep_cal) { + data = hwdep_cal->data; + cal_size = hwdep_cal->size; + dev_dbg(component->dev, "%s: using hwdep calibration, cal_size %zd", + __func__, cal_size); + } else { + filename = "WCD934X/WCD934X_anc.bin"; + ret = request_firmware(&fw, filename, component->dev); + if (ret < 0) { + dev_err(component->dev, "%s: Failed to acquire ANC data: %d\n", + __func__, ret); + return ret; + } + if (!fw) { + dev_err(component->dev, "%s: Failed to get anc fw\n", + __func__); + return -ENODEV; + } + data = fw->data; + cal_size = fw->size; + dev_dbg(component->dev, "%s: using request_firmware calibration\n", + __func__); + } + if (cal_size < sizeof(struct wcd9xxx_anc_header)) { + dev_err(component->dev, "%s: Invalid cal_size %zd\n", + __func__, cal_size); + ret = -EINVAL; + goto err; + } + /* First number is the number of register writes */ + anc_head = (struct wcd9xxx_anc_header *)(data); + anc_ptr = (u32 *)(data + sizeof(struct wcd9xxx_anc_header)); + anc_size_remaining = cal_size - + sizeof(struct wcd9xxx_anc_header); + num_anc_slots = anc_head->num_anc_slots; + + if (tavil->anc_slot >= num_anc_slots) { + dev_err(component->dev, "%s: Invalid ANC slot selected\n", + __func__); + ret = -EINVAL; + goto err; + } + for (i = 0; i < num_anc_slots; i++) { + if (anc_size_remaining < WCD934X_PACKED_REG_SIZE) { + dev_err(component->dev, "%s: Invalid register format\n", + __func__); + ret = -EINVAL; + goto err; + } + anc_writes_size = (u32)(*anc_ptr); + anc_size_remaining -= sizeof(u32); + anc_ptr += 1; + + if ((anc_writes_size * WCD934X_PACKED_REG_SIZE) > + anc_size_remaining) { + dev_err(component->dev, "%s: Invalid register format\n", + __func__); + ret = -EINVAL; + goto err; + } + + if (tavil->anc_slot == i) + break; + + anc_size_remaining -= (anc_writes_size * + WCD934X_PACKED_REG_SIZE); + anc_ptr += anc_writes_size; + } + if (i == num_anc_slots) { + dev_err(component->dev, "%s: Selected ANC slot not present\n", + __func__); + ret = -EINVAL; + goto err; + } + + i = 0; + + if (!strcmp(w->name, "RX INT1 DAC") || + !strcmp(w->name, "RX INT3 DAC")) + anc_writes_size = anc_writes_size / 2; + else if (!strcmp(w->name, "RX INT2 DAC") || + !strcmp(w->name, "RX INT4 DAC")) + i = anc_writes_size / 2; + + for (; i < anc_writes_size; i++) { + WCD934X_CODEC_UNPACK_ENTRY(anc_ptr[i], reg, mask, val); + snd_soc_component_write(component, reg, (val & mask)); + } + + /* Rate converter clk enable and set bypass mode */ + if (!strcmp(w->name, "RX INT0 DAC") || + !strcmp(w->name, "RX INT1 DAC") || + !strcmp(w->name, "ANC SPK1 PA")) { + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_RC_COMMON_CTL, + 0x05, 0x05); + if (!strcmp(w->name, "RX INT1 DAC")) { + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_FIFO_COMMON_CTL, + 0x66, 0x66); + } + } else if (!strcmp(w->name, "RX INT2 DAC")) { + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_RC_COMMON_CTL, + 0x05, 0x05); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_FIFO_COMMON_CTL, + 0x66, 0x66); + } + if (!strcmp(w->name, "RX INT1 DAC")) + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08); + else if (!strcmp(w->name, "RX INT2 DAC")) + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08); + + if (!hwdep_cal) + release_firmware(fw); + break; + + case SND_SOC_DAPM_POST_PMU: + if (!strcmp(w->name, "ANC HPHL PA") || + !strcmp(w->name, "ANC HPHR PA")) { + /* Remove ANC Rx from reset */ + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x08, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_CLK_RESET_CTL, + 0x08, 0x00); + } + + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_RC_COMMON_CTL, + 0x05, 0x00); + if (!strcmp(w->name, "ANC EAR PA") || + !strcmp(w->name, "ANC SPK1 PA") || + !strcmp(w->name, "ANC HPHL PA")) { + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_MODE_1_CTL, + 0x30, 0x00); + msleep(50); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_MODE_1_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x38, 0x38); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x38, 0x00); + } else if (!strcmp(w->name, "ANC HPHR PA")) { + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_MODE_1_CTL, + 0x30, 0x00); + msleep(50); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_MODE_1_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_CLK_RESET_CTL, + 0x38, 0x38); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_CLK_RESET_CTL, + 0x07, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_ANC1_CLK_RESET_CTL, + 0x38, 0x00); + } + break; + } + + return 0; +err: + if (!hwdep_cal) + release_firmware(fw); + return ret; +} + +static int tavil_get_clkmode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + if (test_bit(CLK_MODE, &tavil_p->status_mask)) + ucontrol->value.enumerated.item[0] = 1; + else + ucontrol->value.enumerated.item[0] = 0; + + dev_dbg(component->dev, "%s: is_low_power_clock: %s\n", __func__, + test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false"); + + return 0; +} + +static int tavil_put_clkmode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + if (ucontrol->value.enumerated.item[0]) + set_bit(CLK_MODE, &tavil_p->status_mask); + else + clear_bit(CLK_MODE, &tavil_p->status_mask); + + dev_dbg(component->dev, "%s: is_low_power_clock: %s\n", __func__, + test_bit(CLK_MODE, &tavil_p->status_mask) ? "true" : "false"); + + return 0; +} + +static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tavil_p->vi_feed_value; + + return 0; +} + +static int tavil_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx *core = dev_get_drvdata(component->dev->parent); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 port_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n", + __func__, enable, port_id, dai_id); + + tavil_p->vi_feed_value = ucontrol->value.integer.value[0]; + + mutex_lock(&tavil_p->codec_mutex); + if (enable) { + if (port_id == WCD934X_TX14 && !test_bit(VI_SENSE_1, + &tavil_p->status_mask)) { + list_add_tail(&core->tx_chs[WCD934X_TX14].list, + &tavil_p->dai[dai_id].wcd9xxx_ch_list); + set_bit(VI_SENSE_1, &tavil_p->status_mask); + } + if (port_id == WCD934X_TX15 && !test_bit(VI_SENSE_2, + &tavil_p->status_mask)) { + list_add_tail(&core->tx_chs[WCD934X_TX15].list, + &tavil_p->dai[dai_id].wcd9xxx_ch_list); + set_bit(VI_SENSE_2, &tavil_p->status_mask); + } + } else { + if (port_id == WCD934X_TX14 && test_bit(VI_SENSE_1, + &tavil_p->status_mask)) { + list_del_init(&core->tx_chs[WCD934X_TX14].list); + clear_bit(VI_SENSE_1, &tavil_p->status_mask); + } + if (port_id == WCD934X_TX15 && test_bit(VI_SENSE_2, + &tavil_p->status_mask)) { + list_del_init(&core->tx_chs[WCD934X_TX15].list); + clear_bit(VI_SENSE_2, &tavil_p->status_mask); + } + } + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tavil_p->tx_port_value; + return 0; +} + +static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx *core = dev_get_drvdata(component->dev->parent); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 port_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + u32 vtable; + + dev_dbg(component->dev, "%s: wname %s cname %s value %u shift %d item %ld\n", + __func__, + widget->name, ucontrol->id.name, tavil_p->tx_port_value, + widget->shift, ucontrol->value.integer.value[0]); + + mutex_lock(&tavil_p->codec_mutex); + if (dai_id >= ARRAY_SIZE(vport_slim_check_table)) { + dev_err(component->dev, "%s: dai_id: %d, out of bounds\n", + __func__, dai_id); + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; + } + vtable = vport_slim_check_table[dai_id]; + + switch (dai_id) { + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + /* only add to the list if value not set */ + if (enable && !(tavil_p->tx_port_value & 1 << port_id)) { + if (wcd9xxx_tx_vport_validation(vtable, port_id, + tavil_p->dai, NUM_CODEC_DAIS)) { + dev_dbg(component->dev, "%s: TX%u is used by other virtual port\n", + __func__, port_id); + mutex_unlock(&tavil_p->codec_mutex); + return 0; + } + tavil_p->tx_port_value |= 1 << port_id; + list_add_tail(&core->tx_chs[port_id].list, + &tavil_p->dai[dai_id].wcd9xxx_ch_list); + } else if (!enable && (tavil_p->tx_port_value & + 1 << port_id)) { + tavil_p->tx_port_value &= ~(1 << port_id); + list_del_init(&core->tx_chs[port_id].list); + } else { + if (enable) + dev_dbg(component->dev, "%s: TX%u port is used by\n" + "this virtual port\n", + __func__, port_id); + else + dev_dbg(component->dev, "%s: TX%u port is not used by\n" + "this virtual port\n", + __func__, port_id); + /* avoid update power function */ + mutex_unlock(&tavil_p->codec_mutex); + return 0; + } + break; + case AIF4_MAD_TX: + break; + default: + dev_err(component->dev, "Unknown AIF %d\n", dai_id); + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; + } + dev_dbg(component->dev, "%s: name %s sname %s updated value %u shift %d\n", + __func__, widget->name, widget->sname, tavil_p->tx_port_value, + widget->shift); + + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static int i2s_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tavil_p->tx_port_value; + return 0; +} + +static int i2s_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + (struct soc_multi_mixer_control *)kcontrol->private_value; + u32 dai_id = widget->shift; + u32 port_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + u32 vtable; + + dev_dbg(component->dev, "%s: wname %s cname %s value %u shift %d item %ld\n", + __func__, + widget->name, ucontrol->id.name, tavil_p->tx_port_value, + widget->shift, ucontrol->value.integer.value[0]); + + mutex_lock(&tavil_p->codec_mutex); + if (dai_id >= ARRAY_SIZE(vport_slim_check_table)) { + dev_err(component->dev, "%s: dai_id: %d, out of bounds\n", + __func__, dai_id); + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; + } + vtable = vport_slim_check_table[dai_id]; + + switch (dai_id) { + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + /* only add to the list if value not set */ + if (enable && !(tavil_p->tx_port_value & 1 << port_id)) { + if (wcd9xxx_tx_vport_validation(vtable, port_id, + tavil_p->dai, NUM_CODEC_DAIS)) { + dev_dbg(component->dev, "%s: TX%u is used by other virtual port\n", + __func__, port_id); + mutex_unlock(&tavil_p->codec_mutex); + return 0; + } + tavil_p->tx_port_value |= 1 << port_id; + } else if (!enable && (tavil_p->tx_port_value & + 1 << port_id)) { + tavil_p->tx_port_value &= ~(1 << port_id); + } else { + if (enable) + dev_dbg(component->dev, "%s: TX%u port is used by\n" + "this virtual port\n", + __func__, port_id); + else + dev_dbg(component->dev, "%s: TX%u port is not used by\n" + "this virtual port\n", + __func__, port_id); + /* avoid update power function */ + mutex_unlock(&tavil_p->codec_mutex); + return 0; + } + break; + default: + dev_err(component->dev, "Unknown AIF %d\n", dai_id); + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; + } + dev_dbg(component->dev, "%s: name %s sname %s updated value %u shift %d\n", + __func__, widget->name, widget->sname, tavil_p->tx_port_value, + widget->shift); + + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static int slim_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = + tavil_p->rx_port_value[widget->shift]; + return 0; +} + +static int slim_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx *core = dev_get_drvdata(component->dev->parent); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + unsigned int rx_port_value; + u32 port_id = widget->shift; + + tavil_p->rx_port_value[port_id] = ucontrol->value.enumerated.item[0]; + rx_port_value = tavil_p->rx_port_value[port_id]; + + mutex_lock(&tavil_p->codec_mutex); + dev_dbg(component->dev, "%s: wname %s cname %s value %u shift %d item %ld\n", + __func__, widget->name, ucontrol->id.name, + rx_port_value, widget->shift, + ucontrol->value.integer.value[0]); + + /* value need to match the Virtual port and AIF number */ + switch (rx_port_value) { + case 0: + list_del_init(&core->rx_chs[port_id].list); + break; + case 1: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF1_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF1_PB].wcd9xxx_ch_list); + break; + case 2: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF2_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF2_PB].wcd9xxx_ch_list); + break; + case 3: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF3_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF3_PB].wcd9xxx_ch_list); + break; + case 4: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF4_PB].wcd9xxx_ch_list)) { + dev_dbg(component->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF4_PB].wcd9xxx_ch_list); + break; + default: + dev_err(component->dev, "Unknown AIF %d\n", rx_port_value); + goto err; + } +rtn: + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + + return 0; +err: + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; +} + +static void tavil_codec_enable_slim_port_intr( + struct wcd9xxx_codec_dai_data *dai, + struct snd_soc_component *component) +{ + struct wcd9xxx_ch *ch; + int port_num = 0; + unsigned short reg = 0; + u8 val = 0; + struct tavil_priv *tavil_p; + + if (!dai || !component) { + pr_err("%s: Invalid params\n", __func__); + return; + } + + tavil_p = snd_soc_component_get_drvdata(component); + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + if (ch->port >= WCD934X_RX_PORT_START_NUMBER) { + port_num = ch->port - WCD934X_RX_PORT_START_NUMBER; + reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + (port_num / 8); + val = wcd9xxx_interface_reg_read(tavil_p->wcd9xxx, + reg); + if (!(val & BYTE_BIT_MASK(port_num))) { + val |= BYTE_BIT_MASK(port_num); + wcd9xxx_interface_reg_write( + tavil_p->wcd9xxx, reg, val); + val = wcd9xxx_interface_reg_read( + tavil_p->wcd9xxx, reg); + } + } else { + port_num = ch->port; + reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8); + val = wcd9xxx_interface_reg_read(tavil_p->wcd9xxx, + reg); + if (!(val & BYTE_BIT_MASK(port_num))) { + val |= BYTE_BIT_MASK(port_num); + wcd9xxx_interface_reg_write(tavil_p->wcd9xxx, + reg, val); + val = wcd9xxx_interface_reg_read( + tavil_p->wcd9xxx, reg); + } + } + } +} + +static int tavil_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai, + bool up) +{ + int ret = 0; + struct wcd9xxx_ch *ch; + + if (up) { + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + ret = wcd9xxx_get_slave_port(ch->ch_num); + if (ret < 0) { + pr_err("%s: Invalid slave port ID: %d\n", + __func__, ret); + ret = -EINVAL; + } else { + set_bit(ret, &dai->ch_mask); + } + } + } else { + ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0), + msecs_to_jiffies( + WCD934X_SLIM_CLOSE_TIMEOUT)); + if (!ret) { + pr_err("%s: Slim close tx/rx wait timeout, ch_mask:0x%lx\n", + __func__, dai->ch_mask); + ret = -ETIMEDOUT; + } else { + ret = 0; + } + } + return ret; +} + +static void tavil_codec_mute_dsd(struct snd_soc_component *component, + struct list_head *ch_list) +{ + u8 dsd0_in; + u8 dsd1_in; + struct wcd9xxx_ch *ch; + + /* Read DSD Input Ports */ + dsd0_in = (snd_soc_component_read32( + component, WCD934X_CDC_DSD0_CFG0) & 0x3C) >> 2; + dsd1_in = (snd_soc_component_read32( + component, WCD934X_CDC_DSD1_CFG0) & 0x3C) >> 2; + + if ((dsd0_in == 0) && (dsd1_in == 0)) + return; + + /* + * Check if the ports getting disabled are connected to DSD inputs. + * If connected, enable DSD mute to avoid DC entering into DSD Filter + */ + list_for_each_entry(ch, ch_list, list) { + if (ch->port == (dsd0_in + WCD934X_RX_PORT_START_NUMBER - 1)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x04, 0x04); + if (ch->port == (dsd1_in + WCD934X_RX_PORT_START_NUMBER - 1)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, + 0x04, 0x04); + } +} + +static int tavil_codec_set_i2s_rx_ch(struct snd_soc_dapm_widget *w, + u32 i2s_reg, bool up) +{ + int rx_fs_rate = -EINVAL; + int i2s_bit_mode; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx_codec_dai_data *dai; + + dai = &tavil_p->dai[w->shift]; + dev_dbg(tavil_p->dev, "%s: %d up/down, %d width, %d rate\n", + __func__, up, dai->bit_width, dai->rate); + if (up) { + if (dai->bit_width == 16) + i2s_bit_mode = 0x01; + else + i2s_bit_mode = 0x00; + + switch (dai->rate) { + case 8000: + rx_fs_rate = 0; + break; + case 16000: + rx_fs_rate = 1; + break; + case 32000: + rx_fs_rate = 2; + break; + case 48000: + rx_fs_rate = 3; + break; + case 96000: + rx_fs_rate = 4; + break; + case 192000: + rx_fs_rate = 5; + break; + case 384000: + rx_fs_rate = 6; + break; + default: + dev_err(tavil_p->dev, "%s: Invalid RX sample rate: %d\n", + __func__, dai->rate); + return -EINVAL; + }; + snd_soc_component_update_bits(component, i2s_reg, + 0x40, i2s_bit_mode << 6); + snd_soc_component_update_bits(component, i2s_reg, + 0x3c, (rx_fs_rate << 2)); + } else { + snd_soc_component_update_bits(component, i2s_reg, + 0x40, 0x00); + snd_soc_component_update_bits(component, i2s_reg, + 0x3c, 0x00); + } + return 0; +} + +static int tavil_codec_set_i2s_tx_ch(struct snd_soc_dapm_widget *w, + u32 i2s_reg, bool up) +{ + int tx_fs_rate = -EINVAL; + int i2s_bit_mode; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx_codec_dai_data *dai; + + dai = &tavil_p->dai[w->shift]; + if (up) { + if (dai->bit_width == 16) + i2s_bit_mode = 0x01; + else + i2s_bit_mode = 0x00; + + snd_soc_component_update_bits( + component, i2s_reg, 0x40, i2s_bit_mode << 6); + + switch (dai->rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 2; + break; + case 48000: + tx_fs_rate = 3; + break; + case 96000: + tx_fs_rate = 4; + break; + case 192000: + tx_fs_rate = 5; + break; + case 384000: + tx_fs_rate = 6; + break; + default: + dev_err(tavil_p->dev, "%s: Invalid sample rate: %d\n", + __func__, dai->rate); + return -EINVAL; + }; + + snd_soc_component_update_bits( + component, i2s_reg, 0x3c, tx_fs_rate << 2); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX0_CFG, + 0x03, 0x01); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX0_CFG, + 0x0C, 0x01); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX1_0_CFG, + 0x03, 0x01); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX1_1_CFG, + 0x05, 0x05); + } else { + snd_soc_component_update_bits(component, i2s_reg, 0x40, 0x00); + snd_soc_component_update_bits(component, i2s_reg, 0x3c, 0x00); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX0_CFG, + 0x03, 0x00); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX0_CFG, + 0x0C, 0x00); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX1_0_CFG, + 0x03, 0x00); + + snd_soc_component_update_bits(component, + WCD934X_DATA_HUB_I2S_TX1_1_CFG, + 0x05, 0x00); + } + return 0; +} + +static int tavil_codec_enable_rx_i2c(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 tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + int ret = -EINVAL; + u32 i2s_reg; + + switch (tavil_p->rx_port_value[w->shift]) { + case AIF1_PB: + case AIF1_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_0_CTL; + break; + case AIF2_PB: + case AIF2_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_1_CTL; + break; + case AIF3_PB: + case AIF3_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_2_CTL; + break; + default: + dev_err(component->dev, "%s Invalid i2s Id received", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret = tavil_codec_set_i2s_rx_ch(w, i2s_reg, true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = tavil_codec_set_i2s_rx_ch(w, i2s_reg, false); + break; + } + + return ret; +} + +static int tavil_codec_enable_rx(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct wcd9xxx *core; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + int ret = 0; + struct wcd9xxx_codec_dai_data *dai; + struct tavil_dsd_config *dsd_conf = tavil_p->dsd_config; + + core = dev_get_drvdata(component->dev->parent); + + dev_dbg(component->dev, "%s: event called! codec name %s num_dai %d\n" + "stream name %s event %d\n", + __func__, component->name, + component->num_dai, w->sname, event); + + dai = &tavil_p->dai[w->shift]; + dev_dbg(component->dev, "%s: w->name %s w->shift %d event %d\n", + __func__, w->name, w->shift, event); + + if (tavil_p->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + ret = tavil_codec_enable_rx_i2c(w, kcontrol, event); + return ret; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dai->bus_down_in_recovery = false; + tavil_codec_enable_slim_port_intr(dai, component); + (void) tavil_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + if (dsd_conf) + tavil_codec_mute_dsd(component, &dai->wcd9xxx_ch_list); + + ret = wcd9xxx_disconnect_port(core, &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(component->dev, "%s: Disconnect RX port, ret = %d\n", + __func__, ret); + + if (!dai->bus_down_in_recovery) + ret = tavil_codec_enable_slim_chmask(dai, false); + else + dev_dbg(component->dev, + "%s: bus in recovery skip enable slim_chmask", + __func__); + ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list, + dai->grph); + break; + } + return ret; +} + +static int tavil_codec_enable_tx_i2c(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 tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + int ret = -EINVAL; + u32 i2s_reg; + + switch (tavil_p->rx_port_value[w->shift]) { + case AIF1_PB: + case AIF1_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_0_CTL; + break; + case AIF2_PB: + case AIF2_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_1_CTL; + break; + case AIF3_PB: + case AIF3_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_2_CTL; + break; + default: + dev_err(component->dev, "%s Invalid i2s Id received", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret = tavil_codec_set_i2s_tx_ch(w, i2s_reg, true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = tavil_codec_set_i2s_tx_ch(w, i2s_reg, false); + break; + } + + return ret; +} + +static int tavil_codec_enable_tx(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 tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct wcd9xxx_codec_dai_data *dai; + struct wcd9xxx *core; + int ret = 0; + + dev_dbg(component->dev, + "%s: w->name %s, w->shift = %d, num_dai %d stream name %s\n", + __func__, w->name, w->shift, + component->num_dai, w->sname); + + dai = &tavil_p->dai[w->shift]; + core = dev_get_drvdata(component->dev->parent); + + if (tavil_p->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + ret = tavil_codec_enable_tx_i2c(w, kcontrol, event); + return ret; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dai->bus_down_in_recovery = false; + tavil_codec_enable_slim_port_intr(dai, component); + (void) tavil_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->grph); + if (!dai->bus_down_in_recovery) + ret = tavil_codec_enable_slim_chmask(dai, false); + if (ret < 0) { + ret = wcd9xxx_disconnect_port(core, + &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(component->dev, "%s: Disconnect RX port, ret = %d\n", + __func__, ret); + } + break; + } + return ret; +} + +static int tavil_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct wcd9xxx *core = NULL; + struct snd_soc_component *component = NULL; + struct tavil_priv *tavil_p = NULL; + int ret = 0; + struct wcd9xxx_codec_dai_data *dai = NULL; + + component = snd_soc_dapm_to_component(w->dapm); + tavil_p = snd_soc_component_get_drvdata(component); + core = dev_get_drvdata(component->dev->parent); + + dev_dbg(component->dev, + "%s: num_dai %d stream name %s w->name %s event %d shift %d\n", + __func__, component->num_dai, w->sname, + w->name, event, w->shift); + + if (w->shift != AIF4_VIFEED) { + pr_err("%s Error in enabling the tx path\n", __func__); + ret = -EINVAL; + goto done; + } + dai = &tavil_p->dai[w->shift]; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (test_bit(VI_SENSE_1, &tavil_p->status_mask)) { + dev_dbg(component->dev, "%s: spkr1 enabled\n", + __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + } + if (test_bit(VI_SENSE_2, &tavil_p->status_mask)) { + pr_debug("%s: spkr2 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + } + dai->bus_down_in_recovery = false; + tavil_codec_enable_slim_port_intr(dai, component); + (void) tavil_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->grph); + if (ret) + dev_err(component->dev, "%s error in close_slim_sch_tx %d\n", + __func__, ret); + if (!dai->bus_down_in_recovery) + ret = tavil_codec_enable_slim_chmask(dai, false); + if (ret < 0) { + ret = wcd9xxx_disconnect_port(core, + &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(component->dev, "%s: Disconnect TX port, ret = %d\n", + __func__, ret); + } + if (test_bit(VI_SENSE_1, &tavil_p->status_mask)) { + /* Disable V&I sensing */ + dev_dbg(component->dev, "%s: spkr1 disabled\n", + __func__); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + } + if (test_bit(VI_SENSE_2, &tavil_p->status_mask)) { + /* Disable V&I sensing */ + dev_dbg(component->dev, "%s: spkr2 disabled\n", + __func__); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + } + break; + } +done: + return ret; +} + +static int tavil_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil->rx_bias_count++; + if (tavil->rx_bias_count == 1) { + snd_soc_component_update_bits(component, + WCD934X_ANA_RX_SUPPLIES, + 0x01, 0x01); + } + break; + case SND_SOC_DAPM_POST_PMD: + tavil->rx_bias_count--; + if (!tavil->rx_bias_count) + snd_soc_component_update_bits(component, + WCD934X_ANA_RX_SUPPLIES, + 0x01, 0x00); + break; + }; + dev_dbg(component->dev, "%s: Current RX BIAS user count: %d\n", + __func__, tavil->rx_bias_count); + + return 0; +} + +static void tavil_spk_anc_update_callback(struct work_struct *work) +{ + struct spk_anc_work *spk_anc_dwork; + struct tavil_priv *tavil; + struct delayed_work *delayed_work; + struct snd_soc_component *component; + + delayed_work = to_delayed_work(work); + spk_anc_dwork = container_of(delayed_work, struct spk_anc_work, dwork); + tavil = spk_anc_dwork->tavil; + component = tavil->component; + + snd_soc_component_update_bits(component, WCD934X_CDC_RX7_RX_PATH_CFG0, + 0x10, 0x10); +} + +static int tavil_codec_enable_spkr_anc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + if (!tavil->anc_func) + return 0; + + dev_dbg(component->dev, "%s: w: %s event: %d anc: %d\n", __func__, + w->name, event, tavil->anc_func); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = tavil_codec_enable_anc(w, kcontrol, event); + schedule_delayed_work(&tavil->spk_anc_dwork.dwork, + msecs_to_jiffies(spk_anc_en_delay)); + break; + case SND_SOC_DAPM_POST_PMD: + cancel_delayed_work_sync(&tavil->spk_anc_dwork.dwork); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_CFG0, + 0x10, 0x00); + ret = tavil_codec_enable_anc(w, kcontrol, event); + break; + } + return ret; +} + +static int tavil_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* + * 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX0_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + WCD934X_CDC_RX0_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX0_RX_PATH_MIX_CTL, + 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + + if (!(strcmp(w->name, "ANC EAR PA"))) { + ret = tavil_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX0_RX_PATH_CFG0, + 0x10, 0x00); + } + break; + }; + + return ret; +} + +static void tavil_codec_override(struct snd_soc_component *component, int mode, + int event) +{ + if (mode == CLS_AB || mode == CLS_AB_HIFI) { + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x00); + break; + } + } +} + +static void tavil_codec_clear_anc_tx_hold(struct tavil_priv *tavil) +{ + if (test_and_clear_bit(ANC_MIC_AMIC1, &tavil->status_mask)) + tavil_codec_set_tx_hold(tavil->component, + WCD934X_ANA_AMIC1, false); + if (test_and_clear_bit(ANC_MIC_AMIC2, &tavil->status_mask)) + tavil_codec_set_tx_hold(tavil->component, + WCD934X_ANA_AMIC2, false); + if (test_and_clear_bit(ANC_MIC_AMIC3, &tavil->status_mask)) + tavil_codec_set_tx_hold(tavil->component, + WCD934X_ANA_AMIC3, false); + if (test_and_clear_bit(ANC_MIC_AMIC4, &tavil->status_mask)) + tavil_codec_set_tx_hold(tavil->component, + WCD934X_ANA_AMIC4, false); +} + + +static void tavil_ocp_control(struct snd_soc_component *component, bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD934X_HPH_OCP_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, WCD934X_RX_OCP_CTL, + 0x0F, 0x02); + } else { + snd_soc_component_update_bits(component, WCD934X_RX_OCP_CTL, + 0x0F, 0x0F); + snd_soc_component_update_bits(component, WCD934X_HPH_OCP_CTL, + 0x10, 0x00); + } +} + +static int tavil_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 tavil_priv *tavil = snd_soc_component_get_drvdata(component); + struct tavil_dsd_config *dsd_conf = tavil->dsd_config; + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_ocp_control(component, false); + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, (0x03 << 1)); + + if ((!(strcmp(w->name, "ANC HPHR PA"))) && + (test_bit(HPH_PA_DELAY, &tavil->status_mask))) + snd_soc_component_update_bits(component, + WCD934X_ANA_HPH, 0xC0, 0xC0); + + set_bit(HPH_PA_DELAY, &tavil->status_mask); + if (dsd_conf && + (snd_soc_component_read32(component, + WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) { + /* Set regulator mode to AB if DSD is enabled */ + snd_soc_component_update_bits(component, + WCD934X_ANA_RX_SUPPLIES, + 0x02, 0x02); + } + break; + case SND_SOC_DAPM_POST_PMU: + if ((!(strcmp(w->name, "ANC HPHR PA")))) { + if ((snd_soc_component_read32(component, + WCD934X_ANA_HPH) & 0xC0) != 0xC0) + /* + * If PA_EN is not set (potentially in ANC case) + * then do nothing for POST_PMU and let left + * channel handle everything. + */ + break; + } + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is needed. + */ + if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) { + if (!tavil->comp_enabled[COMPANDER_2]) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tavil->status_mask); + } + if (tavil->anc_func) { + /* Clear Tx FE HOLD if both PAs are enabled */ + if ((snd_soc_component_read32(tavil->component, + WCD934X_ANA_HPH) & 0xC0) == 0xC0) + tavil_codec_clear_anc_tx_hold(tavil); + } + + snd_soc_component_update_bits(component, WCD934X_HPH_R_TEST, + 0x01, 0x01); + + /* Remove mute */ + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + /* Enable GM3 boost */ + snd_soc_component_update_bits(component, WCD934X_HPH_CNP_WG_CTL, + 0x80, 0x80); + /* Enable AutoChop timer at the end of power up */ + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) & 0x10) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + if (dsd_conf && + (snd_soc_component_read32( + component, WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, 0x04, 0x00); + if (!(strcmp(w->name, "ANC HPHR PA"))) { + pr_debug("%s:Do everything needed for left channel\n", + __func__); + /* Do everything needed for left channel */ + snd_soc_component_update_bits(component, + WCD934X_HPH_L_TEST, + 0x01, 0x01); + + /* Remove mute */ + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + + if (dsd_conf && (snd_soc_component_read32(component, + WCD934X_CDC_DSD0_PATH_CTL) & + 0x01)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x04, 0x00); + /* Remove ANC Rx from reset */ + ret = tavil_codec_enable_anc(w, kcontrol, event); + } + tavil_codec_override(component, tavil->hph_mode, event); + tavil_ocp_control(component, true); + break; + case SND_SOC_DAPM_PRE_PMD: + tavil_ocp_control(component, false); + if (tavil->mbhc) + blocking_notifier_call_chain(&tavil->mbhc->notifier, + WCD_EVENT_PRE_HPHR_PA_OFF, + &tavil->mbhc->wcd_mbhc); + /* Enable DSD Mute before PA disable */ + if (dsd_conf && + (snd_soc_component_read32(component, + WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, + 0x04, 0x04); + snd_soc_component_update_bits(component, WCD934X_HPH_R_TEST, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x10); + if (!(strcmp(w->name, "ANC HPHR PA"))) + snd_soc_component_update_bits(component, + WCD934X_ANA_HPH, 0x40, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA disable. If compander is + * disabled, then 20ms delay is needed after PA disable. + */ + if (!tavil->comp_enabled[COMPANDER_2]) + usleep_range(20000, 20100); + else + usleep_range(5000, 5100); + tavil_codec_override(component, tavil->hph_mode, event); + if (tavil->mbhc) + blocking_notifier_call_chain(&tavil->mbhc->notifier, + WCD_EVENT_POST_HPHR_PA_OFF, + &tavil->mbhc->wcd_mbhc); + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, 0x0); + if (!(strcmp(w->name, "ANC HPHR PA"))) { + ret = tavil_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_CFG0, + 0x10, 0x00); + } + tavil_ocp_control(component, true); + break; + }; + + return ret; +} + +static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + struct tavil_dsd_config *dsd_conf = tavil->dsd_config; + int ret = 0; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_ocp_control(component, false); + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, (0x03 << 1)); + if ((!(strcmp(w->name, "ANC HPHL PA"))) && + (test_bit(HPH_PA_DELAY, &tavil->status_mask))) + snd_soc_component_update_bits(component, + WCD934X_ANA_HPH, + 0xC0, 0xC0); + set_bit(HPH_PA_DELAY, &tavil->status_mask); + if (dsd_conf && + (snd_soc_component_read32(component, + WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) { + /* Set regulator mode to AB if DSD is enabled */ + snd_soc_component_update_bits(component, + WCD934X_ANA_RX_SUPPLIES, + 0x02, 0x02); + } + break; + case SND_SOC_DAPM_POST_PMU: + if (!(strcmp(w->name, "ANC HPHL PA"))) { + if ((snd_soc_component_read32( + component, WCD934X_ANA_HPH) & 0xC0) != 0xC0) + /* + * If PA_EN is not set (potentially in ANC + * case) then do nothing for POST_PMU and + * let right channel handle everything. + */ + break; + } + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is needed. + */ + if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) { + if (!tavil->comp_enabled[COMPANDER_1]) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tavil->status_mask); + } + if (tavil->anc_func) { + /* Clear Tx FE HOLD if both PAs are enabled */ + if ((snd_soc_component_read32( + tavil->component, WCD934X_ANA_HPH) & 0xC0) == + 0xC0) + tavil_codec_clear_anc_tx_hold(tavil); + } + + snd_soc_component_update_bits(component, WCD934X_HPH_L_TEST, + 0x01, 0x01); + /* Remove Mute on primary path */ + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + /* Enable GM3 boost */ + snd_soc_component_update_bits(component, + WCD934X_HPH_CNP_WG_CTL, + 0x80, 0x80); + /* Enable AutoChop timer at the end of power up */ + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) & 0x10) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + if (dsd_conf && + (snd_soc_component_read32( + component, WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x04, 0x00); + if (!(strcmp(w->name, "ANC HPHL PA"))) { + pr_debug("%s:Do everything needed for right channel\n", + __func__); + + /* Do everything needed for right channel */ + snd_soc_component_update_bits(component, + WCD934X_HPH_R_TEST, + 0x01, 0x01); + + /* Remove mute */ + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(component, + WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + if (dsd_conf && (snd_soc_component_read32(component, + WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD1_CFG2, + 0x04, 0x00); + /* Remove ANC Rx from reset */ + ret = tavil_codec_enable_anc(w, kcontrol, event); + } + tavil_codec_override(component, tavil->hph_mode, event); + tavil_ocp_control(component, true); + break; + case SND_SOC_DAPM_PRE_PMD: + tavil_ocp_control(component, false); + if (tavil->mbhc) + blocking_notifier_call_chain(&tavil->mbhc->notifier, + WCD_EVENT_PRE_HPHL_PA_OFF, + &tavil->mbhc->wcd_mbhc); + /* Enable DSD Mute before PA disable */ + if (dsd_conf && + (snd_soc_component_read32(component, + WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) + snd_soc_component_update_bits(component, + WCD934X_CDC_DSD0_CFG2, + 0x04, 0x04); + + snd_soc_component_update_bits(component, WCD934X_HPH_L_TEST, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x10); + if (!(strcmp(w->name, "ANC HPHL PA"))) + snd_soc_component_update_bits(component, + WCD934X_ANA_HPH, + 0x80, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA disable. If compander is + * disabled, then 20ms delay is needed after PA disable. + */ + if (!tavil->comp_enabled[COMPANDER_1]) + usleep_range(20000, 20100); + else + usleep_range(5000, 5100); + tavil_codec_override(component, tavil->hph_mode, event); + if (tavil->mbhc) + blocking_notifier_call_chain(&tavil->mbhc->notifier, + WCD_EVENT_POST_HPHL_PA_OFF, + &tavil->mbhc->wcd_mbhc); + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, 0x0); + if (!(strcmp(w->name, "ANC HPHL PA"))) { + ret = tavil_codec_enable_anc(w, kcontrol, event); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_CFG0, 0x10, 0x00); + } + tavil_ocp_control(component, true); + break; + }; + + return ret; +} + +static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0; + u16 dsd_mute_reg = 0, dsd_clk_reg = 0; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + struct tavil_dsd_config *dsd_conf = tavil->dsd_config; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + if (w->reg == WCD934X_ANA_LO_1_2) { + if (w->shift == 7) { + lineout_vol_reg = WCD934X_CDC_RX3_RX_PATH_CTL; + lineout_mix_vol_reg = WCD934X_CDC_RX3_RX_PATH_MIX_CTL; + dsd_mute_reg = WCD934X_CDC_DSD0_CFG2; + dsd_clk_reg = WCD934X_CDC_DSD0_PATH_CTL; + } else if (w->shift == 6) { + lineout_vol_reg = WCD934X_CDC_RX4_RX_PATH_CTL; + lineout_mix_vol_reg = WCD934X_CDC_RX4_RX_PATH_MIX_CTL; + dsd_mute_reg = WCD934X_CDC_DSD1_CFG2; + dsd_clk_reg = WCD934X_CDC_DSD1_PATH_CTL; + } + } else { + dev_err(component->dev, "%s: Error enabling lineout PA\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_codec_override(component, CLS_AB, event); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, lineout_vol_reg, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32( + component, lineout_mix_vol_reg)) & 0x10) + snd_soc_component_update_bits(component, + lineout_mix_vol_reg, + 0x10, 0x00); + if (dsd_conf && (snd_soc_component_read32( + component, dsd_clk_reg) & 0x01)) + snd_soc_component_update_bits(component, dsd_mute_reg, + 0x04, 0x00); + break; + case SND_SOC_DAPM_PRE_PMD: + if (dsd_conf && (snd_soc_component_read32( + component, dsd_clk_reg) & 0x01)) + snd_soc_component_update_bits(component, dsd_mute_reg, + 0x04, 0x04); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + tavil_codec_override(component, CLS_AB, event); + default: + break; + }; + + return 0; +} + +static int i2s_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = + tavil_p->rx_port_value[widget->shift]; + return 0; +} + +static int i2s_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + unsigned int rx_port_value; + u32 port_id = widget->shift; + + tavil_p->rx_port_value[port_id] = ucontrol->value.enumerated.item[0]; + rx_port_value = tavil_p->rx_port_value[port_id]; + + dev_dbg(component->dev, "%s: wname %s cname %s value %u shift %d item %ld\n", + __func__, widget->name, ucontrol->id.name, + rx_port_value, widget->shift, + ucontrol->value.integer.value[0]); + + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + return 0; +} + +static int tavil_codec_enable_i2s_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + u32 i2s_reg; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + + switch (tavil_p->rx_port_value[w->shift]) { + case AIF1_PB: + case AIF1_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_0_CTL; + break; + case AIF2_PB: + case AIF2_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_1_CTL; + break; + case AIF3_PB: + case AIF3_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_2_CTL; + break; + default: + dev_err(component->dev, "%s Invalid i2s Id received", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = snd_soc_component_update_bits(component, i2s_reg, + 0x01, 0x01); + break; + case SND_SOC_DAPM_POST_PMD: + ret = snd_soc_component_update_bits(component, i2s_reg, + 0x01, 0x00); + break; + } + + return ret; +} + +static int tavil_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Disable AutoChop timer during power up */ + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + + if (tavil->anc_func) + ret = tavil_codec_enable_anc(w, kcontrol, event); + + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + CLS_H_NORMAL); + if (tavil->anc_func) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX0_RX_PATH_CFG0, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + CLS_H_NORMAL); + break; + default: + break; + }; + + return ret; +} + +static int tavil_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int hph_mode = tavil->hph_mode; + u8 dem_inp; + struct tavil_dsd_config *dsd_conf = tavil->dsd_config; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d hph_mode: %d\n", + __func__, w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tavil->anc_func) { + ret = tavil_codec_enable_anc(w, kcontrol, event); + /* 40 msec delay is needed to avoid click and pop */ + msleep(40); + } + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(component, + WCD934X_CDC_RX2_RX_PATH_SEC0) & 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control enable */ + snd_soc_component_update_bits(component, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x01); + /* Disable AutoChop timer during power up */ + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + /* Set RDAC gain */ + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x40); + if (dsd_conf && + (snd_soc_component_read32(component, + WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) + hph_mode = CLS_H_HIFI; + + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + hph_mode); + if (tavil->anc_func) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX2_RX_PATH_CFG0, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + hph_mode); + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control disable */ + snd_soc_component_update_bits(component, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x0); + /* Re-set RDAC gain */ + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x0); + break; + default: + break; + }; + + return 0; +} + +static int tavil_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int hph_mode = tavil->hph_mode; + u8 dem_inp; + int ret = 0; + struct tavil_dsd_config *dsd_conf = tavil->dsd_config; + uint32_t impedl = 0, impedr = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d hph_mode: %d\n", + __func__, w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tavil->anc_func) { + ret = tavil_codec_enable_anc(w, kcontrol, event); + /* 40 msec delay is needed to avoid click and pop */ + msleep(40); + } + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(component, + WCD934X_CDC_RX1_RX_PATH_SEC0) & 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control enable */ + snd_soc_component_update_bits(component, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x01); + /* Disable AutoChop timer during power up */ + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + /* Set RDAC gain */ + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x40); + if (dsd_conf && + (snd_soc_component_read32(component, + WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) + hph_mode = CLS_H_HIFI; + + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + hph_mode); + + if (tavil->anc_func) + snd_soc_component_update_bits(component, + WCD934X_CDC_RX1_RX_PATH_CFG0, + 0x10, 0x10); + + ret = tavil_mbhc_get_impedance(tavil->mbhc, + &impedl, &impedr); + if (!ret) { + wcd_clsh_imped_config(component, impedl, false); + set_bit(CLSH_Z_CONFIG, &tavil->status_mask); + } else { + dev_dbg(component->dev, "%s: Failed to get mbhc impedance %d\n", + __func__, ret); + ret = 0; + } + + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + hph_mode); + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control disable */ + snd_soc_component_update_bits(component, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x0); + /* Re-set RDAC gain */ + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + snd_soc_component_update_bits(component, + WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x0); + + if (test_bit(CLSH_Z_CONFIG, &tavil->status_mask)) { + wcd_clsh_imped_config(component, impedl, true); + clear_bit(CLSH_Z_CONFIG, &tavil->status_mask); + } + break; + default: + break; + }; + + return ret; +} + +static int tavil_codec_lineout_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_LO, + CLS_AB); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_fsm(component, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_LO, + CLS_AB); + break; + } + + return 0; +} + +static int tavil_codec_spk_boost_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 boost_path_ctl, boost_path_cfg1; + u16 reg, reg_mix; + + dev_dbg(component->dev, "%s %s %d\n", __func__, w->name, event); + + if (!strcmp(w->name, "RX INT7 CHAIN")) { + boost_path_ctl = WCD934X_CDC_BOOST0_BOOST_PATH_CTL; + boost_path_cfg1 = WCD934X_CDC_RX7_RX_PATH_CFG1; + reg = WCD934X_CDC_RX7_RX_PATH_CTL; + reg_mix = WCD934X_CDC_RX7_RX_PATH_MIX_CTL; + } else if (!strcmp(w->name, "RX INT8 CHAIN")) { + boost_path_ctl = WCD934X_CDC_BOOST1_BOOST_PATH_CTL; + boost_path_cfg1 = WCD934X_CDC_RX8_RX_PATH_CFG1; + reg = WCD934X_CDC_RX8_RX_PATH_CTL; + reg_mix = WCD934X_CDC_RX8_RX_PATH_MIX_CTL; + } else { + dev_err(component->dev, "%s: unknown widget: %s\n", + __func__, w->name); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x01); + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x10); + snd_soc_component_update_bits(component, reg, 0x10, 0x00); + if ((snd_soc_component_read32(component, reg_mix)) & 0x10) + snd_soc_component_update_bits(component, reg_mix, + 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, boost_path_ctl, + 0x10, 0x00); + snd_soc_component_update_bits(component, boost_path_cfg1, + 0x01, 0x00); + break; + }; + + return 0; +} + +static int __tavil_codec_enable_swr(struct snd_soc_dapm_widget *w, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil; + int ch_cnt = 0; + + tavil = snd_soc_component_get_drvdata(component); + + if (!tavil->swr.ctrl_data) + return -EINVAL; + if (!tavil->swr.ctrl_data[0].swr_pdev) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) || + (strnstr(w->name, "INT7 MIX2", + sizeof("RX INT7 MIX2"))))) + tavil->swr.rx_7_count++; + if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && + !tavil->swr.rx_8_count) + tavil->swr.rx_8_count++; + ch_cnt = !!(tavil->swr.rx_7_count) + tavil->swr.rx_8_count; + + if (wcd9xxx_get_current_power_state(tavil->wcd9xxx, + WCD9XXX_DIG_CORE_REGION_1) + != WCD_REGION_POWER_COLLAPSE_REMOVE) + goto done; + + swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, + SWR_DEVICE_UP, NULL); + swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + break; + case SND_SOC_DAPM_POST_PMD: + if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) || + (strnstr(w->name, "INT7 MIX2", + sizeof("RX INT7 MIX2")))) + tavil->swr.rx_7_count--; + if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && + tavil->swr.rx_8_count) + tavil->swr.rx_8_count--; + ch_cnt = !!(tavil->swr.rx_7_count) + tavil->swr.rx_8_count; + + swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + + break; + } +done: + dev_dbg(tavil->dev, "%s: %s: current swr ch cnt: %d\n", + __func__, w->name, ch_cnt); + + return 0; +} + +static int tavil_codec_enable_swr(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return __tavil_codec_enable_swr(w, event); +} + +static int tavil_codec_config_mad(struct snd_soc_component *component) +{ + int ret = 0; + int idx; + const struct firmware *fw; + struct firmware_cal *hwdep_cal = NULL; + struct wcd_mad_audio_cal *mad_cal = NULL; + const void *data; + const char *filename = WCD934X_MAD_AUDIO_FIRMWARE_PATH; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + size_t cal_size; + + hwdep_cal = wcdcal_get_fw_cal(tavil->fw_data, WCD9XXX_MAD_CAL); + if (hwdep_cal) { + data = hwdep_cal->data; + cal_size = hwdep_cal->size; + dev_dbg(component->dev, "%s: using hwdep calibration\n", + __func__); + } else { + ret = request_firmware(&fw, filename, component->dev); + if (ret || !fw) { + dev_err(component->dev, + "%s: MAD firmware acquire failed, err = %d\n", + __func__, ret); + return -ENODEV; + } + data = fw->data; + cal_size = fw->size; + dev_dbg(component->dev, "%s: using request_firmware calibration\n", + __func__); + } + + if (cal_size < sizeof(*mad_cal)) { + dev_err(component->dev, + "%s: Incorrect size %zd for MAD Cal, expected %zd\n", + __func__, cal_size, sizeof(*mad_cal)); + ret = -ENOMEM; + goto done; + } + + mad_cal = (struct wcd_mad_audio_cal *) (data); + if (!mad_cal) { + dev_err(component->dev, + "%s: Invalid calibration data\n", + __func__); + ret = -EINVAL; + goto done; + } + + snd_soc_component_write(component, WCD934X_SOC_MAD_MAIN_CTL_2, + mad_cal->microphone_info.cycle_time); + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_MAIN_CTL_1, + 0xFF << 3, + ((uint16_t)mad_cal->microphone_info.settle_time) << 3); + + /* Audio */ + snd_soc_component_write(component, WCD934X_SOC_MAD_AUDIO_CTL_8, + mad_cal->audio_info.rms_omit_samples); + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_AUDIO_CTL_1, + 0x07 << 4, mad_cal->audio_info.rms_comp_time << 4); + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_AUDIO_CTL_2, + 0x03 << 2, + mad_cal->audio_info.detection_mechanism << 2); + snd_soc_component_write(component, WCD934X_SOC_MAD_AUDIO_CTL_7, + mad_cal->audio_info.rms_diff_threshold & 0x3F); + snd_soc_component_write(component, WCD934X_SOC_MAD_AUDIO_CTL_5, + mad_cal->audio_info.rms_threshold_lsb); + snd_soc_component_write(component, WCD934X_SOC_MAD_AUDIO_CTL_6, + mad_cal->audio_info.rms_threshold_msb); + + for (idx = 0; idx < ARRAY_SIZE(mad_cal->audio_info.iir_coefficients); + idx++) { + snd_soc_component_update_bits(component, + WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR, + 0x3F, idx); + snd_soc_component_write(component, + WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL, + mad_cal->audio_info.iir_coefficients[idx]); + dev_dbg(component->dev, "%s:MAD Audio IIR Coef[%d] = 0X%x", + __func__, idx, + mad_cal->audio_info.iir_coefficients[idx]); + } + + /* Beacon */ + snd_soc_component_write(component, WCD934X_SOC_MAD_BEACON_CTL_8, + mad_cal->beacon_info.rms_omit_samples); + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_BEACON_CTL_1, + 0x07 << 4, mad_cal->beacon_info.rms_comp_time << 4); + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_BEACON_CTL_2, + 0x03 << 2, + mad_cal->beacon_info.detection_mechanism << 2); + snd_soc_component_write(component, WCD934X_SOC_MAD_BEACON_CTL_7, + mad_cal->beacon_info.rms_diff_threshold & 0x1F); + snd_soc_component_write(component, WCD934X_SOC_MAD_BEACON_CTL_5, + mad_cal->beacon_info.rms_threshold_lsb); + snd_soc_component_write(component, WCD934X_SOC_MAD_BEACON_CTL_6, + mad_cal->beacon_info.rms_threshold_msb); + + for (idx = 0; idx < ARRAY_SIZE(mad_cal->beacon_info.iir_coefficients); + idx++) { + snd_soc_component_update_bits(component, + WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR, + 0x3F, idx); + snd_soc_component_write(component, + WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL, + mad_cal->beacon_info.iir_coefficients[idx]); + dev_dbg(component->dev, "%s:MAD Beacon IIR Coef[%d] = 0X%x", + __func__, idx, + mad_cal->beacon_info.iir_coefficients[idx]); + } + + /* Ultrasound */ + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_ULTR_CTL_1, + 0x07 << 4, + mad_cal->ultrasound_info.rms_comp_time << 4); + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_ULTR_CTL_2, + 0x03 << 2, + mad_cal->ultrasound_info.detection_mechanism << 2); + snd_soc_component_write(component, WCD934X_SOC_MAD_ULTR_CTL_7, + mad_cal->ultrasound_info.rms_diff_threshold & 0x1F); + snd_soc_component_write(component, WCD934X_SOC_MAD_ULTR_CTL_5, + mad_cal->ultrasound_info.rms_threshold_lsb); + snd_soc_component_write(component, WCD934X_SOC_MAD_ULTR_CTL_6, + mad_cal->ultrasound_info.rms_threshold_msb); + +done: + if (!hwdep_cal) + release_firmware(fw); + + return ret; +} + +static int __tavil_codec_enable_mad(struct snd_soc_component *component, + bool enable) +{ + int rc = 0; + + /* Return if CPE INPUT is DEC1 */ + if (snd_soc_component_read32( + component, WCD934X_CPE_SS_SVA_CFG) & 0x04) { + dev_dbg(component->dev, "%s: MAD is bypassed, skip mad %s\n", + __func__, enable ? "enable" : "disable"); + return rc; + } + + dev_dbg(component->dev, "%s: enable = %s\n", __func__, + enable ? "enable" : "disable"); + + if (enable) { + snd_soc_component_update_bits(component, + WCD934X_SOC_MAD_AUDIO_CTL_2, + 0x03, 0x03); + rc = tavil_codec_config_mad(component); + if (rc < 0) { + snd_soc_component_update_bits(component, + WCD934X_SOC_MAD_AUDIO_CTL_2, + 0x03, 0x00); + goto done; + } + + /* Turn on MAD clk */ + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_MAD_CTL, + 0x01, 0x01); + + /* Undo reset for MAD */ + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_MAD_CTL, + 0x02, 0x00); + } else { + snd_soc_component_update_bits(component, + WCD934X_SOC_MAD_AUDIO_CTL_2, + 0x03, 0x00); + /* Reset the MAD block */ + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_MAD_CTL, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_MAD_CTL, + 0x01, 0x00); + } +done: + return rc; +} + +static int tavil_codec_ape_enable_mad(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int rc = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_SVA_CFG, 0x40, 0x40); + rc = __tavil_codec_enable_mad(component, true); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, + WCD934X_CPE_SS_SVA_CFG, 0x40, 0x00); + __tavil_codec_enable_mad(component, false); + break; + } + + dev_dbg(tavil->dev, "%s: event = %d\n", __func__, event); + return rc; +} + +static int tavil_codec_cpe_mad_ctl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int rc = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil->mad_switch_cnt++; + if (tavil->mad_switch_cnt != 1) + goto done; + + snd_soc_component_update_bits(component, WCD934X_CPE_SS_SVA_CFG, + 0x20, 0x20); + rc = __tavil_codec_enable_mad(component, true); + if (rc < 0) { + tavil->mad_switch_cnt--; + goto done; + } + + break; + case SND_SOC_DAPM_PRE_PMD: + tavil->mad_switch_cnt--; + if (tavil->mad_switch_cnt != 0) + goto done; + + snd_soc_component_update_bits(component, WCD934X_CPE_SS_SVA_CFG, + 0x20, 0x00); + __tavil_codec_enable_mad(component, false); + break; + } +done: + dev_dbg(tavil->dev, "%s: event = %d, mad_switch_cnt = %d\n", + __func__, event, tavil->mad_switch_cnt); + return rc; +} + +static int tavil_get_asrc_mode(struct tavil_priv *tavil, int asrc, + u8 main_sr, u8 mix_sr) +{ + u8 asrc_output_mode; + int asrc_mode = CONV_88P2K_TO_384K; + + if ((asrc < 0) || (asrc >= ASRC_MAX)) + return 0; + + asrc_output_mode = tavil->asrc_output_mode[asrc]; + + if (asrc_output_mode) { + /* + * If Mix sample rate is < 96KHz, use 96K to 352.8K + * conversion, or else use 384K to 352.8K conversion + */ + if (mix_sr < 5) + asrc_mode = CONV_96K_TO_352P8K; + else + asrc_mode = CONV_384K_TO_352P8K; + } else { + /* Integer main and Fractional mix path */ + if (main_sr < 8 && mix_sr > 9) { + asrc_mode = CONV_352P8K_TO_384K; + } else if (main_sr > 8 && mix_sr < 8) { + /* Fractional main and Integer mix path */ + if (mix_sr < 5) + asrc_mode = CONV_96K_TO_352P8K; + else + asrc_mode = CONV_384K_TO_352P8K; + } else if (main_sr < 8 && mix_sr < 8) { + /* Integer main and Integer mix path */ + asrc_mode = CONV_96K_TO_384K; + } + } + + return asrc_mode; +} + +static int tavil_codec_wdma3_ctl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Fix to 16KHz */ + snd_soc_component_update_bits(component, WCD934X_DMA_WDMA_CTL_3, + 0xF0, 0x10); + /* Select mclk_1 */ + snd_soc_component_update_bits(component, WCD934X_DMA_WDMA_CTL_3, + 0x02, 0x00); + /* Enable DMA */ + snd_soc_component_update_bits(component, WCD934X_DMA_WDMA_CTL_3, + 0x01, 0x01); + break; + + case SND_SOC_DAPM_POST_PMD: + /* Disable DMA */ + snd_soc_component_update_bits(component, WCD934X_DMA_WDMA_CTL_3, + 0x01, 0x00); + break; + + }; + + return 0; +} + +static int tavil_codec_enable_asrc(struct snd_soc_component *component, + int asrc_in, int event) +{ + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + u16 cfg_reg, ctl_reg, clk_reg, asrc_ctl, mix_ctl_reg, paired_reg; + int asrc, ret = 0; + u8 main_sr, mix_sr, asrc_mode = 0; + + switch (asrc_in) { + case ASRC_IN_HPHL: + cfg_reg = WCD934X_CDC_RX1_RX_PATH_CFG0; + ctl_reg = WCD934X_CDC_RX1_RX_PATH_CTL; + clk_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; + asrc_ctl = WCD934X_MIXING_ASRC0_CTL1; + asrc = ASRC0; + break; + case ASRC_IN_LO1: + cfg_reg = WCD934X_CDC_RX3_RX_PATH_CFG0; + ctl_reg = WCD934X_CDC_RX3_RX_PATH_CTL; + clk_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; + asrc_ctl = WCD934X_MIXING_ASRC0_CTL1; + asrc = ASRC0; + break; + case ASRC_IN_HPHR: + cfg_reg = WCD934X_CDC_RX2_RX_PATH_CFG0; + ctl_reg = WCD934X_CDC_RX2_RX_PATH_CTL; + clk_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; + asrc_ctl = WCD934X_MIXING_ASRC1_CTL1; + asrc = ASRC1; + break; + case ASRC_IN_LO2: + cfg_reg = WCD934X_CDC_RX4_RX_PATH_CFG0; + ctl_reg = WCD934X_CDC_RX4_RX_PATH_CTL; + clk_reg = WCD934X_MIXING_ASRC1_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC0_CLK_RST_CTL; + asrc_ctl = WCD934X_MIXING_ASRC1_CTL1; + asrc = ASRC1; + break; + case ASRC_IN_SPKR1: + cfg_reg = WCD934X_CDC_RX7_RX_PATH_CFG0; + ctl_reg = WCD934X_CDC_RX7_RX_PATH_CTL; + clk_reg = WCD934X_MIXING_ASRC2_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC3_CLK_RST_CTL; + asrc_ctl = WCD934X_MIXING_ASRC2_CTL1; + asrc = ASRC2; + break; + case ASRC_IN_SPKR2: + cfg_reg = WCD934X_CDC_RX8_RX_PATH_CFG0; + ctl_reg = WCD934X_CDC_RX8_RX_PATH_CTL; + clk_reg = WCD934X_MIXING_ASRC3_CLK_RST_CTL; + paired_reg = WCD934X_MIXING_ASRC2_CLK_RST_CTL; + asrc_ctl = WCD934X_MIXING_ASRC3_CTL1; + asrc = ASRC3; + break; + default: + dev_err(component->dev, "%s: Invalid asrc input :%d\n", + __func__, asrc_in); + ret = -EINVAL; + goto done; + }; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (tavil->asrc_users[asrc] == 0) { + if ((snd_soc_component_read32( + component, clk_reg) & 0x02) || + (snd_soc_component_read32( + component, paired_reg) & 0x02)) { + snd_soc_component_update_bits( + component, clk_reg, 0x02, 0x00); + snd_soc_component_update_bits( + component, paired_reg, 0x02, 0x00); + } + snd_soc_component_update_bits( + component, cfg_reg, 0x80, 0x80); + snd_soc_component_update_bits( + component, clk_reg, 0x01, 0x01); + main_sr = snd_soc_component_read32( + component, ctl_reg) & 0x0F; + mix_ctl_reg = ctl_reg + 5; + mix_sr = snd_soc_component_read32( + component, mix_ctl_reg) & 0x0F; + asrc_mode = tavil_get_asrc_mode(tavil, asrc, + main_sr, mix_sr); + dev_dbg(component->dev, "%s: main_sr:%d mix_sr:%d asrc_mode %d\n", + __func__, main_sr, mix_sr, asrc_mode); + snd_soc_component_update_bits(component, asrc_ctl, + 0x07, asrc_mode); + } + tavil->asrc_users[asrc]++; + break; + case SND_SOC_DAPM_POST_PMD: + tavil->asrc_users[asrc]--; + if (tavil->asrc_users[asrc] <= 0) { + tavil->asrc_users[asrc] = 0; + snd_soc_component_update_bits(component, asrc_ctl, + 0x07, 0x00); + snd_soc_component_update_bits(component, cfg_reg, + 0x80, 0x00); + snd_soc_component_update_bits(component, clk_reg, + 0x03, 0x02); + } + break; + }; + + dev_dbg(component->dev, "%s: ASRC%d, users: %d\n", + __func__, asrc, tavil->asrc_users[asrc]); + +done: + return ret; +} + +static int tavil_codec_enable_asrc_resampler(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + u8 cfg, asrc_in; + + cfg = snd_soc_component_read32(component, + WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0); + if (!(cfg & 0xFF)) { + dev_err(component->dev, "%s: ASRC%u input not selected\n", + __func__, w->shift); + return -EINVAL; + } + + switch (w->shift) { + case ASRC0: + asrc_in = ((cfg & 0x03) == 1) ? ASRC_IN_HPHL : ASRC_IN_LO1; + ret = tavil_codec_enable_asrc(component, asrc_in, event); + break; + case ASRC1: + asrc_in = ((cfg & 0x0C) == 4) ? ASRC_IN_HPHR : ASRC_IN_LO2; + ret = tavil_codec_enable_asrc(component, asrc_in, event); + break; + case ASRC2: + asrc_in = ((cfg & 0x30) == 0x20) ? ASRC_IN_SPKR1 : ASRC_INVALID; + ret = tavil_codec_enable_asrc(component, asrc_in, event); + break; + case ASRC3: + asrc_in = ((cfg & 0xC0) == 0x80) ? ASRC_IN_SPKR2 : ASRC_INVALID; + ret = tavil_codec_enable_asrc(component, asrc_in, event); + break; + default: + dev_err(component->dev, "%s: Invalid asrc:%u\n", __func__, + w->shift); + ret = -EINVAL; + break; + }; + + return ret; +} + +static int tavil_enable_native_supply(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (++tavil->native_clk_users == 1) { + snd_soc_component_update_bits(component, + WCD934X_CLK_SYS_PLL_ENABLES, + 0x01, 0x01); + usleep_range(100, 120); + snd_soc_component_update_bits(component, + WCD934X_CLK_SYS_MCLK2_PRG1, + 0x06, 0x02); + snd_soc_component_update_bits(component, + WCD934X_CLK_SYS_MCLK2_PRG1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD934X_CODEC_RPM_CLK_GATE, + 0x04, 0x00); + usleep_range(30, 50); + snd_soc_component_update_bits(component, + WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x10, 0x10); + } + break; + case SND_SOC_DAPM_PRE_PMD: + if (tavil->native_clk_users && + (--tavil->native_clk_users == 0)) { + snd_soc_component_update_bits(component, + WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x10, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CODEC_RPM_CLK_GATE, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD934X_CLK_SYS_MCLK2_PRG1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CLK_SYS_MCLK2_PRG1, + 0x06, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CLK_SYS_PLL_ENABLES, + 0x01, 0x00); + } + break; + } + + dev_dbg(component->dev, "%s: native_clk_users: %d, event: %d\n", + __func__, tavil->native_clk_users, event); + + return 0; +} + +static void tavil_codec_hphdelay_lutbypass(struct snd_soc_component *component, + u16 interp_idx, int event) +{ + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + u8 hph_dly_mask; + u16 hph_lut_bypass_reg = 0; + u16 hph_comp_ctrl7 = 0; + + switch (interp_idx) { + case INTERP_HPHL: + hph_dly_mask = 1; + hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHL_COMP_LUT; + hph_comp_ctrl7 = WCD934X_CDC_COMPANDER1_CTL7; + break; + case INTERP_HPHR: + hph_dly_mask = 2; + hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHR_COMP_LUT; + hph_comp_ctrl7 = WCD934X_CDC_COMPANDER2_CTL7; + break; + default: + break; + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, WCD934X_CDC_CLSH_TEST0, + hph_dly_mask, 0x0); + snd_soc_component_update_bits(component, hph_lut_bypass_reg, + 0x80, 0x80); + if (tavil->hph_mode == CLS_H_ULP) + snd_soc_component_update_bits(component, hph_comp_ctrl7, + 0x20, 0x20); + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, WCD934X_CDC_CLSH_TEST0, + hph_dly_mask, hph_dly_mask); + snd_soc_component_update_bits(component, hph_lut_bypass_reg, + 0x80, 0x00); + snd_soc_component_update_bits(component, hph_comp_ctrl7, + 0x20, 0x0); + } +} + +static void tavil_codec_hd2_control(struct tavil_priv *priv, + u16 interp_idx, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + struct snd_soc_component *component = priv->component; + + if (TAVIL_IS_1_1(priv->wcd9xxx)) + return; + + switch (interp_idx) { + case INTERP_HPHL: + hd2_scale_reg = WCD934X_CDC_RX1_RX_PATH_SEC3; + hd2_enable_reg = WCD934X_CDC_RX1_RX_PATH_CFG0; + break; + case INTERP_HPHR: + hd2_scale_reg = WCD934X_CDC_RX2_RX_PATH_SEC3; + hd2_enable_reg = WCD934X_CDC_RX2_RX_PATH_CFG0; + break; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x14); + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + 0x04, 0x00); + snd_soc_component_update_bits(component, hd2_scale_reg, + 0x3C, 0x00); + } +} + +static int tavil_codec_config_ear_spkr_gain(struct snd_soc_component *component, + int event, int gain_reg) +{ + int comp_gain_offset, val; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + switch (tavil->swr.spkr_mode) { + /* Compander gain in SPKR_MODE1 case is 12 dB */ + case WCD934X_SPKR_MODE_1: + comp_gain_offset = -12; + break; + /* Default case compander gain is 15 dB */ + default: + comp_gain_offset = -15; + break; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Apply ear spkr gain only if compander is enabled */ + if (tavil->comp_enabled[COMPANDER_7] && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL) && + (tavil->ear_spkr_gain != 0)) { + /* For example, val is -8(-12+5-1) for 4dB of gain */ + val = comp_gain_offset + tavil->ear_spkr_gain - 1; + snd_soc_component_write(component, gain_reg, val); + + dev_dbg(component->dev, "%s: RX7 Volume %d dB\n", + __func__, val); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* + * Reset RX7 volume to 0 dB if compander is enabled and + * ear_spkr_gain is non-zero. + */ + if (tavil->comp_enabled[COMPANDER_7] && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL) && + (tavil->ear_spkr_gain != 0)) { + snd_soc_component_write(component, gain_reg, 0x0); + + dev_dbg(component->dev, "%s: Reset RX7 Volume to 0 dB\n", + __func__); + } + break; + } + + return 0; +} + +static int tavil_config_compander(struct snd_soc_component *component, + int interp_n, int event) +{ + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int comp; + u16 comp_ctl0_reg, rx_path_cfg0_reg; + + /* EAR does not have compander */ + if (!interp_n) + return 0; + + comp = interp_n - 1; + dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, tavil->comp_enabled[comp]); + + if (!tavil->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = WCD934X_CDC_COMPANDER1_CTL0 + (comp * 8); + rx_path_cfg0_reg = WCD934X_CDC_RX1_RX_PATH_CFG0 + (comp * 20); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x01); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x04); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x02); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x02, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x01, 0x00); + snd_soc_component_update_bits(component, comp_ctl0_reg, + 0x04, 0x00); + } + + return 0; +} + +static void tavil_codec_idle_detect_control(struct snd_soc_component *component, + int interp, int event) +{ + int reg = 0, mask, val; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + if (!tavil->idle_det_cfg.hph_idle_detect_en) + return; + + if (interp == INTERP_HPHL) { + reg = WCD934X_CDC_RX_IDLE_DET_PATH_CTL; + mask = 0x01; + val = 0x01; + } + if (interp == INTERP_HPHR) { + reg = WCD934X_CDC_RX_IDLE_DET_PATH_CTL; + mask = 0x02; + val = 0x02; + } + + if (reg && SND_SOC_DAPM_EVENT_ON(event)) + snd_soc_component_update_bits(component, reg, mask, val); + + if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, reg, mask, 0x00); + tavil->idle_det_cfg.hph_idle_thr = 0; + snd_soc_component_write(component, WCD934X_CDC_RX_IDLE_DET_CFG3, + 0x0); + } +} + +/** + * tavil_codec_enable_interp_clk - Enable main path Interpolator + * clock. + * + * @component: Codec component instance + * @event: Indicates speaker path gain offset value + * @intp_idx: Interpolator index + * Returns number of main clock users + */ +int tavil_codec_enable_interp_clk(struct snd_soc_component *component, + int event, int interp_idx) +{ + struct tavil_priv *tavil; + u16 main_reg; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + tavil = snd_soc_component_get_drvdata(component); + main_reg = WCD934X_CDC_RX0_RX_PATH_CTL + (interp_idx * 20); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (tavil->main_clk_users[interp_idx] == 0) { + /* Main path PGA mute enable */ + snd_soc_component_update_bits(component, main_reg, + 0x10, 0x10); + /* Clk enable */ + snd_soc_component_update_bits(component, main_reg, + 0x20, 0x20); + tavil_codec_idle_detect_control(component, interp_idx, + event); + tavil_codec_hd2_control(tavil, interp_idx, event); + tavil_codec_hphdelay_lutbypass(component, interp_idx, + event); + tavil_config_compander(component, interp_idx, event); + } + tavil->main_clk_users[interp_idx]++; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + tavil->main_clk_users[interp_idx]--; + if (tavil->main_clk_users[interp_idx] <= 0) { + tavil->main_clk_users[interp_idx] = 0; + tavil_config_compander(component, interp_idx, event); + tavil_codec_hphdelay_lutbypass(component, interp_idx, + event); + tavil_codec_hd2_control(tavil, interp_idx, event); + tavil_codec_idle_detect_control(component, interp_idx, + event); + /* Clk Disable */ + snd_soc_component_update_bits(component, main_reg, + 0x20, 0x00); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x40); + snd_soc_component_update_bits(component, main_reg, + 0x40, 0x00); + /* Reset rate to 48K*/ + snd_soc_component_update_bits(component, main_reg, + 0x0F, 0x04); + } + } + + dev_dbg(component->dev, "%s event %d main_clk_users %d\n", + __func__, event, tavil->main_clk_users[interp_idx]); + + return tavil->main_clk_users[interp_idx]; +} +EXPORT_SYMBOL(tavil_codec_enable_interp_clk); + +static int tavil_anc_out_switch_cb(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + tavil_codec_enable_interp_clk(component, event, w->shift); + + return 0; +} +static int tavil_codec_set_idle_detect_thr(struct snd_soc_component *component, + int interp, int path_type) +{ + int port_id[4] = { 0, 0, 0, 0 }; + int *port_ptr, num_ports; + int bit_width = 0, i; + int mux_reg, mux_reg_val; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int dai_id, idle_thr; + + if ((interp != INTERP_HPHL) && (interp != INTERP_HPHR)) + return 0; + + if (!tavil->idle_det_cfg.hph_idle_detect_en) + return 0; + + port_ptr = &port_id[0]; + num_ports = 0; + + /* + * Read interpolator MUX input registers and find + * which slimbus port is connected and store the port + * numbers in port_id array. + */ + if (path_type == INTERP_MIX_PATH) { + mux_reg = WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1 + + 2 * (interp - 1); + mux_reg_val = snd_soc_component_read32(component, mux_reg) & + 0x0f; + + if ((mux_reg_val >= INTn_2_INP_SEL_RX0) && + (mux_reg_val < INTn_2_INP_SEL_PROXIMITY)) { + *port_ptr++ = mux_reg_val + + WCD934X_RX_PORT_START_NUMBER - 1; + num_ports++; + } + } + + if (path_type == INTERP_MAIN_PATH) { + mux_reg = WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0 + + 2 * (interp - 1); + mux_reg_val = snd_soc_component_read32(component, mux_reg) & + 0x0f; + i = WCD934X_INTERP_MUX_NUM_INPUTS; + + while (i) { + if ((mux_reg_val >= INTn_1_INP_SEL_RX0) && + (mux_reg_val <= INTn_1_INP_SEL_RX7)) { + *port_ptr++ = mux_reg_val + + WCD934X_RX_PORT_START_NUMBER - + INTn_1_INP_SEL_RX0; + num_ports++; + } + mux_reg_val = (snd_soc_component_read32( + component, mux_reg) & 0xf0) >> 4; + mux_reg += 1; + i--; + } + } + + dev_dbg(component->dev, "%s: num_ports: %d, ports[%d %d %d %d]\n", + __func__, num_ports, port_id[0], port_id[1], + port_id[2], port_id[3]); + + i = 0; + while (num_ports) { + dai_id = tavil_find_playback_dai_id_for_port(port_id[i++], + tavil); + + if ((dai_id >= 0) && (dai_id < NUM_CODEC_DAIS)) { + dev_dbg(component->dev, "%s: dai_id: %d bit_width: %d\n", + __func__, dai_id, + tavil->dai[dai_id].bit_width); + + if (tavil->dai[dai_id].bit_width > bit_width) + bit_width = tavil->dai[dai_id].bit_width; + } + + num_ports--; + } + + switch (bit_width) { + case 16: + idle_thr = 0xff; /* F16 */ + break; + case 24: + case 32: + idle_thr = 0x03; /* F22 */ + break; + default: + idle_thr = 0x00; + break; + } + + dev_dbg(component->dev, "%s: (new) idle_thr: %d, (cur) idle_thr: %d\n", + __func__, idle_thr, tavil->idle_det_cfg.hph_idle_thr); + + if ((tavil->idle_det_cfg.hph_idle_thr == 0) || + (idle_thr < tavil->idle_det_cfg.hph_idle_thr)) { + snd_soc_component_write(component, WCD934X_CDC_RX_IDLE_DET_CFG3, + idle_thr); + tavil->idle_det_cfg.hph_idle_thr = idle_thr; + } + + return 0; +} + +static int tavil_codec_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + u16 gain_reg, mix_reg; + int offset_val = 0; + int val = 0; + + if (w->shift >= WCD934X_NUM_INTERPOLATORS || + w->shift == INTERP_LO3_NA || w->shift == INTERP_LO4_NA) { + dev_err(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + }; + + gain_reg = WCD934X_CDC_RX0_RX_VOL_MIX_CTL + + (w->shift * WCD934X_RX_PATH_CTL_OFFSET); + mix_reg = WCD934X_CDC_RX0_RX_PATH_MIX_CTL + + (w->shift * WCD934X_RX_PATH_CTL_OFFSET); + + if (w->shift == INTERP_SPKR1 || w->shift == INTERP_SPKR2) + __tavil_codec_enable_swr(w, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_codec_set_idle_detect_thr(component, w->shift, + INTERP_MIX_PATH); + tavil_codec_enable_interp_clk(component, event, w->shift); + /* Clk enable */ + snd_soc_component_update_bits(component, mix_reg, 0x20, 0x20); + break; + case SND_SOC_DAPM_POST_PMU: + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_MIX_CTL)) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x01); + offset_val = -2; + } + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + tavil_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + case SND_SOC_DAPM_POST_PMD: + /* Clk Disable */ + snd_soc_component_update_bits(component, mix_reg, 0x20, 0x00); + tavil_codec_enable_interp_clk(component, event, w->shift); + /* Reset enable and disable */ + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x40); + snd_soc_component_update_bits(component, mix_reg, 0x40, 0x00); + + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_MIX_CTL)) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x00); + offset_val = 2; + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + } + tavil_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + }; + dev_dbg(component->dev, "%s event %d name %s\n", __func__, + event, w->name); + + return 0; +} + +/** + * tavil_get_dsd_config - Get pointer to dsd config structure + * + * @component: pointer to snd_soc_component structure + * + * Returns pointer to tavil_dsd_config structure + */ +struct tavil_dsd_config *tavil_get_dsd_config( + struct snd_soc_component *component) +{ + struct tavil_priv *tavil; + + if (!component) + return NULL; + + tavil = snd_soc_component_get_drvdata(component); + + if (!tavil) + return NULL; + + return tavil->dsd_config; +} +EXPORT_SYMBOL(tavil_get_dsd_config); + +static int tavil_codec_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (w->shift >= WCD934X_NUM_INTERPOLATORS || + w->shift == INTERP_LO3_NA || w->shift == INTERP_LO4_NA) { + dev_err(component->dev, "%s: Invalid Interpolator value %d for name %s\n", + __func__, w->shift, w->name); + return -EINVAL; + }; + + reg = WCD934X_CDC_RX0_RX_PATH_CTL + (w->shift * + WCD934X_RX_PATH_CTL_OFFSET); + gain_reg = WCD934X_CDC_RX0_RX_VOL_CTL + (w->shift * + WCD934X_RX_PATH_CTL_OFFSET); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_codec_set_idle_detect_thr(component, w->shift, + INTERP_MAIN_PATH); + tavil_codec_enable_interp_clk(component, event, w->shift); + break; + case SND_SOC_DAPM_POST_PMU: + /* apply gain after int clk is enabled */ + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_CTL)) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x01); + offset_val = -2; + } + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + tavil_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + case SND_SOC_DAPM_POST_PMD: + tavil_codec_enable_interp_clk(component, event, w->shift); + + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_CTL)) { + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x00); + offset_val = 2; + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + } + tavil_codec_config_ear_spkr_gain(component, event, gain_reg); + break; + }; + + return 0; +} + +static int tavil_codec_set_iir_gain(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: /* fall through */ + case SND_SOC_DAPM_PRE_PMD: + if (strnstr(w->name, "IIR0", sizeof("IIR0"))) { + snd_soc_component_write(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, + snd_soc_component_read32(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, + snd_soc_component_read32(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, + snd_soc_component_read32(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)); + snd_soc_component_write(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, + snd_soc_component_read32(component, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)); + } else { + snd_soc_component_write(component, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, + snd_soc_component_read32(component, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)); + snd_soc_component_write(component, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, + snd_soc_component_read32(component, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)); + snd_soc_component_write(component, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, + snd_soc_component_read32(component, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)); + } + break; + } + return 0; +} + +static int tavil_codec_find_amic_input(struct snd_soc_component *component, + int adc_mux_n) +{ + u16 mask, shift, adc_mux_in_reg; + u16 amic_mux_sel_reg; + bool is_amic; + + if (adc_mux_n < 0 || adc_mux_n > WCD934X_MAX_VALID_ADC_MUX || + adc_mux_n == WCD934X_INVALID_ADC_MUX) + return 0; + + if (adc_mux_n < 3) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + 2 * adc_mux_n; + mask = 0x03; + shift = 0; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + 2 * adc_mux_n; + } else if (adc_mux_n < 4) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1; + mask = 0x03; + shift = 0; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + 2 * adc_mux_n; + } else if (adc_mux_n < 7) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + 2 * (adc_mux_n - 4); + mask = 0x0C; + shift = 2; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + } else if (adc_mux_n < 8) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1; + mask = 0x0C; + shift = 2; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + } else if (adc_mux_n < 12) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + 2 * (((adc_mux_n == 8) ? (adc_mux_n - 8) : + (adc_mux_n - 9))); + mask = 0x30; + shift = 4; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0 + + ((adc_mux_n == 8) ? (adc_mux_n - 8) : + (adc_mux_n - 9)); + } else if (adc_mux_n < 13) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1; + mask = 0x30; + shift = 4; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 5; + } else { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1; + mask = 0xC0; + shift = 6; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 5; + } + + is_amic = (((snd_soc_component_read32(component, adc_mux_in_reg) & + mask) >> shift) + == 1); + if (!is_amic) + return 0; + + return snd_soc_component_read32(component, amic_mux_sel_reg) & 0x07; +} + +static void tavil_codec_set_tx_hold(struct snd_soc_component *component, + u16 amic_reg, bool set) +{ + u8 mask = 0x20; + u8 val; + + if (amic_reg == WCD934X_ANA_AMIC1 || + amic_reg == WCD934X_ANA_AMIC3) + mask = 0x40; + + val = set ? mask : 0x00; + + switch (amic_reg) { + case WCD934X_ANA_AMIC1: + case WCD934X_ANA_AMIC2: + snd_soc_component_update_bits(component, WCD934X_ANA_AMIC2, + mask, val); + break; + case WCD934X_ANA_AMIC3: + case WCD934X_ANA_AMIC4: + snd_soc_component_update_bits(component, WCD934X_ANA_AMIC4, + mask, val); + break; + default: + dev_dbg(component->dev, "%s: invalid amic: %d\n", + __func__, amic_reg); + break; + } +} + +static int tavil_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int adc_mux_n = w->shift; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int amic_n; + + dev_dbg(component->dev, "%s: event: %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + amic_n = tavil_codec_find_amic_input(component, adc_mux_n); + if (amic_n) { + /* + * Prevent ANC Rx pop by leaving Tx FE in HOLD + * state until PA is up. Track AMIC being used + * so we can release the HOLD later. + */ + set_bit(ANC_MIC_AMIC1 + amic_n - 1, + &tavil->status_mask); + } + break; + default: + break; + } + + return 0; +} + +static u16 tavil_codec_get_amic_pwlvl_reg(struct snd_soc_component *component, + int amic) +{ + u16 pwr_level_reg = 0; + + switch (amic) { + case 1: + case 2: + pwr_level_reg = WCD934X_ANA_AMIC1; + break; + + case 3: + case 4: + pwr_level_reg = WCD934X_ANA_AMIC3; + break; + default: + dev_dbg(component->dev, "%s: invalid amic: %d\n", + __func__, amic); + break; + } + + return pwr_level_reg; +} + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +static void tavil_tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct tavil_priv *tavil; + struct snd_soc_component *component; + u16 dec_cfg_reg, amic_reg, go_bit_reg; + u8 hpf_cut_off_freq; + int amic_n; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + tavil = hpf_work->tavil; + component = tavil->component; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * hpf_work->decimator; + go_bit_reg = dec_cfg_reg + 7; + + dev_dbg(component->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + amic_n = tavil_codec_find_amic_input(component, hpf_work->decimator); + if (amic_n) { + amic_reg = WCD934X_ANA_AMIC1 + amic_n - 1; + tavil_codec_set_tx_hold(component, amic_reg, false); + } + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, go_bit_reg, 0x02, 0x02); + /* Minimum 1 clk cycle delay is required as per HW spec */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, go_bit_reg, 0x02, 0x00); +} + +static void tavil_tx_mute_update_callback(struct work_struct *work) +{ + struct tx_mute_work *tx_mute_dwork; + struct tavil_priv *tavil; + struct delayed_work *delayed_work; + struct snd_soc_component *component; + u16 tx_vol_ctl_reg, hpf_gate_reg; + + delayed_work = to_delayed_work(work); + tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork); + tavil = tx_mute_dwork->tavil; + component = tavil->component; + + tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + + 16 * tx_mute_dwork->decimator; + hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 + + 16 * tx_mute_dwork->decimator; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, 0x10, 0x00); +} + +static int tavil_codec_enable_rx_path_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 sidetone_reg; + + dev_dbg(component->dev, "%s %d %d\n", __func__, event, w->shift); + sidetone_reg = WCD934X_CDC_RX0_RX_PATH_CFG1 + 0x14*(w->shift); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!strcmp(w->name, "RX INT7 MIX2 INP")) + __tavil_codec_enable_swr(w, event); + tavil_codec_enable_interp_clk(component, event, w->shift); + snd_soc_component_update_bits(component, sidetone_reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, sidetone_reg, + 0x10, 0x00); + tavil_codec_enable_interp_clk(component, event, w->shift); + if (!strcmp(w->name, "RX INT7 MIX2 INP")) + __tavil_codec_enable_swr(w, event); + break; + default: + break; + }; + return 0; +} + +static int tavil_codec_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + unsigned int decimator; + char *dec_adc_mux_name = NULL; + char *widget_name = NULL; + char *wname; + int ret = 0, amic_n; + u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + char *dec; + u8 hpf_cut_off_freq; + + dev_dbg(component->dev, "%s %d\n", __func__, event); + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + + wname = widget_name; + dec_adc_mux_name = strsep(&widget_name, " "); + if (!dec_adc_mux_name) { + dev_err(component->dev, "%s: Invalid decimator = %s\n", + __func__, w->name); + ret = -EINVAL; + goto out; + } + dec_adc_mux_name = widget_name; + + dec = strpbrk(dec_adc_mux_name, "012345678"); + if (!dec) { + dev_err(component->dev, "%s: decimator index not found\n", + __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec, 10, &decimator); + if (ret < 0) { + dev_err(component->dev, "%s: Invalid decimator = %s\n", + __func__, wname); + ret = -EINVAL; + goto out; + } + + dev_dbg(component->dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator; + hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 + 16 * decimator; + dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * decimator; + tx_gain_ctl_reg = WCD934X_CDC_TX0_TX_VOL_CTL + 16 * decimator; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + amic_n = tavil_codec_find_amic_input(component, decimator); + if (amic_n) + pwr_level_reg = tavil_codec_get_amic_pwlvl_reg( + component, amic_n); + + if (pwr_level_reg) { + switch ((snd_soc_component_read32( + component, pwr_level_reg) & + WCD934X_AMIC_PWR_LVL_MASK) >> + WCD934X_AMIC_PWR_LVL_SHIFT) { + case WCD934X_AMIC_PWR_LEVEL_LP: + snd_soc_component_update_bits( + component, dec_cfg_reg, + WCD934X_DEC_PWR_LVL_MASK, + WCD934X_DEC_PWR_LVL_LP); + break; + + case WCD934X_AMIC_PWR_LEVEL_HP: + snd_soc_component_update_bits( + component, dec_cfg_reg, + WCD934X_DEC_PWR_LVL_MASK, + WCD934X_DEC_PWR_LVL_HP); + break; + case WCD934X_AMIC_PWR_LEVEL_DEFAULT: + case WCD934X_AMIC_PWR_LEVEL_HYBRID: + default: + snd_soc_component_update_bits( + component, dec_cfg_reg, + WCD934X_DEC_PWR_LVL_MASK, + WCD934X_DEC_PWR_LVL_DF); + break; + } + } + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + hpf_cut_off_freq = (snd_soc_component_read32( + component, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + tavil->tx_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + snd_soc_component_update_bits(component, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x02); + /* + * Minimum 1 clk cycle delay is required as per + * HW spec. + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, hpf_gate_reg, + 0x02, 0x00); + /* schedule work queue to Remove Mute */ + schedule_delayed_work(&tavil->tx_mute_dwork[decimator].dwork, + msecs_to_jiffies(tx_unmute_delay)); + if (tavil->tx_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) + schedule_delayed_work( + &tavil->tx_hpf_work[decimator].dwork, + msecs_to_jiffies(300)); + /* apply gain after decimator is enabled */ + snd_soc_component_write(component, tx_gain_ctl_reg, + snd_soc_component_read32( + component, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + tavil->tx_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x10); + if (cancel_delayed_work_sync( + &tavil->tx_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(component, + dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x02, 0x02); + /* + * Minimum 1 clk cycle delay is required as per + * HW spec. + */ + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, + hpf_gate_reg, + 0x02, 0x00); + } + } + cancel_delayed_work_sync( + &tavil->tx_mute_dwork[decimator].dwork); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + 0x10, 0x00); + snd_soc_component_update_bits(component, dec_cfg_reg, + WCD934X_DEC_PWR_LVL_MASK, + WCD934X_DEC_PWR_LVL_DF); + break; + }; +out: + kfree(wname); + return ret; +} + +static u32 tavil_get_dmic_sample_rate(struct snd_soc_component *component, + unsigned int dmic, + struct wcd9xxx_pdata *pdata) +{ + u8 tx_stream_fs; + u8 adc_mux_index = 0, adc_mux_sel = 0; + bool dec_found = false; + u16 adc_mux_ctl_reg, tx_fs_reg; + u32 dmic_fs; + + while (dec_found == 0 && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) { + if (adc_mux_index < 4) { + adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + (adc_mux_index * 2); + } else if (adc_mux_index < WCD934X_INVALID_ADC_MUX) { + adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_index - 4; + } else if (adc_mux_index == WCD934X_INVALID_ADC_MUX) { + ++adc_mux_index; + continue; + } + adc_mux_sel = ((snd_soc_component_read32( + component, adc_mux_ctl_reg) & + 0xF8) >> 3) - 1; + + if (adc_mux_sel == dmic) { + dec_found = true; + break; + } + + ++adc_mux_index; + } + + if (dec_found && adc_mux_index <= 8) { + tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL + (16 * adc_mux_index); + tx_stream_fs = snd_soc_component_read32( + component, tx_fs_reg) & 0x0F; + if (tx_stream_fs <= 4) { + if (pdata->dmic_sample_rate <= + WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ) + dmic_fs = pdata->dmic_sample_rate; + else + dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ; + } else + dmic_fs = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ; + } else { + dmic_fs = pdata->dmic_sample_rate; + } + + return dmic_fs; +} + +static u8 tavil_get_dmic_clk_val(struct snd_soc_component *component, + u32 mclk_rate, u32 dmic_clk_rate) +{ + u32 div_factor; + u8 dmic_ctl_val; + + dev_dbg(component->dev, + "%s: mclk_rate = %d, dmic_sample_rate = %d\n", + __func__, mclk_rate, dmic_clk_rate); + + /* Default value to return in case of error */ + if (mclk_rate == WCD934X_MCLK_CLK_9P6MHZ) + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2; + else + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3; + + if (dmic_clk_rate == 0) { + dev_err(component->dev, + "%s: dmic_sample_rate cannot be 0\n", + __func__); + goto done; + } + + div_factor = mclk_rate / dmic_clk_rate; + switch (div_factor) { + case 2: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2; + break; + case 3: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3; + break; + case 4: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_4; + break; + case 6: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_6; + break; + case 8: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_8; + break; + case 16: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_16; + break; + default: + dev_err(component->dev, + "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n", + __func__, div_factor, mclk_rate, dmic_clk_rate); + break; + } + +done: + return dmic_ctl_val; +} + +static int tavil_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + dev_dbg(component->dev, "%s: event:%d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_codec_set_tx_hold(component, w->reg, true); + break; + default: + break; + } + + return 0; +} + +static int tavil_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + u8 dmic_rate_val, dmic_rate_shift = 1; + unsigned int dmic; + u32 dmic_sample_rate; + int ret; + char *wname; + + wname = strpbrk(w->name, "012345"); + if (!wname) { + dev_err(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; + } + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(tavil->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD934X_CPE_SS_DMIC0_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(tavil->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD934X_CPE_SS_DMIC1_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(tavil->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD934X_CPE_SS_DMIC2_CTL; + break; + default: + dev_err(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: + dmic_sample_rate = tavil_get_dmic_sample_rate(component, dmic, + pdata); + dmic_rate_val = + tavil_get_dmic_clk_val(component, + pdata->mclk_rate, + dmic_sample_rate); + + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + + break; + case SND_SOC_DAPM_POST_PMD: + dmic_rate_val = + tavil_get_dmic_clk_val(component, + pdata->mclk_rate, + pdata->mad_dmic_sample_rate); + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, 0); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + } + break; + }; + + return 0; +} + +/* + * tavil_mbhc_micb_adjust_voltage: adjust specific micbias voltage + * @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 tavil_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct tavil_priv *tavil = 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 = WCD934X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD934X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD934X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD934X_ANA_MICB4; + break; + default: + return -EINVAL; + } + mutex_lock(&tavil->micb_lock); + + /* + * If requested micbias voltage is same as current micbias + * voltage, then just return. Otherwise, adjust voltage as + * per requested value. If micbias is already enabled, then + * to avoid slow micbias ramp-up or down enable pull-up + * momentarily, change the micbias value and then re-enable + * micbias. + */ + micb_val = snd_soc_component_read32(component, micb_reg); + micb_en = (micb_val & 0xC0) >> 6; + cur_vout_ctl = micb_val & 0x3F; + + req_vout_ctl = wcd934x_get_micb_vout_ctl_val(req_volt); + if (req_vout_ctl < 0) { + ret = -EINVAL; + goto exit; + } + if (cur_vout_ctl == req_vout_ctl) { + ret = 0; + goto exit; + } + + dev_dbg(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(&tavil->micb_lock); + return ret; +} +EXPORT_SYMBOL(tavil_mbhc_micb_adjust_voltage); + +/* + * tavil_micbias_control: enable/disable micbias + * @component: handle to snd_soc_component * + * @micb_num: micbias to be enabled/disabled, e.g. micbias1 or micbias2 + * @req: control requested, enable/disable or pullup enable/disable + * @is_dapm: triggered by dapm or not + * + * return 0 if control is success or error code in case of failure + */ +int tavil_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct tavil_priv *tavil = 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 > TAVIL_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 = WCD934X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD934X_ANA_MICB2; + pre_off_event = WCD_EVENT_PRE_MICBIAS_2_OFF; + post_off_event = WCD_EVENT_POST_MICBIAS_2_OFF; + post_on_event = WCD_EVENT_POST_MICBIAS_2_ON; + post_dapm_on = WCD_EVENT_POST_DAPM_MICBIAS_2_ON; + post_dapm_off = WCD_EVENT_POST_DAPM_MICBIAS_2_OFF; + break; + case MIC_BIAS_3: + micb_reg = WCD934X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD934X_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + mutex_lock(&tavil->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + tavil->pullup_ref[micb_index]++; + if ((tavil->pullup_ref[micb_index] == 1) && + (tavil->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + if (tavil->pullup_ref[micb_index] > 0) + tavil->pullup_ref[micb_index]--; + if ((tavil->pullup_ref[micb_index] == 0) && + (tavil->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + tavil->micb_ref[micb_index]++; + if (tavil->micb_ref[micb_index] == 1) { + if (tavil->micb_load) + regulator_set_load(tavil->micb_load, + tavil->micb_load_high); + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x40); + if (post_on_event && tavil->mbhc) + blocking_notifier_call_chain( + &tavil->mbhc->notifier, + post_on_event, + &tavil->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_on && tavil->mbhc) + blocking_notifier_call_chain(&tavil->mbhc->notifier, + post_dapm_on, &tavil->mbhc->wcd_mbhc); + break; + case MICB_DISABLE: + if (tavil->micb_ref[micb_index] > 0) + tavil->micb_ref[micb_index]--; + if ((tavil->micb_ref[micb_index] == 0) && + (tavil->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((tavil->micb_ref[micb_index] == 0) && + (tavil->pullup_ref[micb_index] == 0)) { + if (pre_off_event && tavil->mbhc) + blocking_notifier_call_chain( + &tavil->mbhc->notifier, + pre_off_event, + &tavil->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + if (post_off_event && tavil->mbhc) + blocking_notifier_call_chain( + &tavil->mbhc->notifier, + post_off_event, + &tavil->mbhc->wcd_mbhc); + if (tavil->micb_load) + regulator_set_load(tavil->micb_load, + tavil->micb_load_low); + } + if (is_dapm && post_dapm_off && tavil->mbhc) + blocking_notifier_call_chain(&tavil->mbhc->notifier, + post_dapm_off, &tavil->mbhc->wcd_mbhc); + break; + }; + + dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, tavil->micb_ref[micb_index], + tavil->pullup_ref[micb_index]); + + mutex_unlock(&tavil->micb_lock); + + return 0; +} +EXPORT_SYMBOL(tavil_micbias_control); + +static int __tavil_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_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: + /* + * MIC BIAS can also be requested by MBHC, + * so use ref count to handle micbias pullup + * and enable requests + */ + tavil_micbias_control(component, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* wait for cnp time */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + tavil_micbias_control(component, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +/* + * tavil_codec_enable_standalone_micbias - enable micbias standalone + * @component: pointer to codec component instance + * @micb_num: number of micbias to be enabled + * @enable: true to enable micbias or false to disable + * + * This function is used to enable micbias (1, 2, 3 or 4) during + * standalone independent of whether TX use-case is running or not + * + * Return: error code in case of failure or 0 for success + */ +int tavil_codec_enable_standalone_micbias(struct snd_soc_component *component, + int micb_num, + bool enable) +{ + const char * const micb_names[] = { + DAPM_MICBIAS1_STANDALONE, DAPM_MICBIAS2_STANDALONE, + DAPM_MICBIAS3_STANDALONE, DAPM_MICBIAS4_STANDALONE + }; + int micb_index = micb_num - 1; + int rc; + + if (!component) { + pr_err("%s: Component memory is NULL\n", __func__); + return -EINVAL; + } + + if ((micb_index < 0) || (micb_index > TAVIL_MAX_MICBIAS - 1)) { + dev_err(component->dev, "%s: Invalid micbias index, micb_ind:%d\n", + __func__, micb_index); + return -EINVAL; + } + + if (enable) + rc = snd_soc_dapm_force_enable_pin( + snd_soc_component_get_dapm(component), + micb_names[micb_index]); + else + rc = snd_soc_dapm_disable_pin( + snd_soc_component_get_dapm(component), + micb_names[micb_index]); + + if (!rc) + snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); + else + dev_err(component->dev, "%s: micbias%d force %s pin failed\n", + __func__, micb_num, (enable ? "enable" : "disable")); + + return rc; +} +EXPORT_SYMBOL(tavil_codec_enable_standalone_micbias); + +static int tavil_codec_force_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_resmgr_enable_master_bias(tavil->resmgr); + tavil_cdc_mclk_enable(component, true); + ret = __tavil_codec_enable_micbias(w, SND_SOC_DAPM_PRE_PMU); + /* Wait for 1ms for better cnp */ + usleep_range(1000, 1100); + tavil_cdc_mclk_enable(component, false); + break; + case SND_SOC_DAPM_POST_PMD: + ret = __tavil_codec_enable_micbias(w, SND_SOC_DAPM_POST_PMD); + wcd_resmgr_disable_master_bias(tavil->resmgr); + break; + } + + return ret; +} + +static int tavil_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return __tavil_codec_enable_micbias(w, event); +} + + +static const struct reg_sequence tavil_hph_reset_tbl[] = { + { WCD934X_HPH_CNP_EN, 0x80 }, + { WCD934X_HPH_CNP_WG_CTL, 0x9A }, + { WCD934X_HPH_CNP_WG_TIME, 0x14 }, + { WCD934X_HPH_OCP_CTL, 0x28 }, + { WCD934X_HPH_AUTO_CHOP, 0x16 }, + { WCD934X_HPH_CHOP_CTL, 0x83 }, + { WCD934X_HPH_PA_CTL1, 0x46 }, + { WCD934X_HPH_PA_CTL2, 0x50 }, + { WCD934X_HPH_L_EN, 0x80 }, + { WCD934X_HPH_L_TEST, 0xE0 }, + { WCD934X_HPH_L_ATEST, 0x50 }, + { WCD934X_HPH_R_EN, 0x80 }, + { WCD934X_HPH_R_TEST, 0xE0 }, + { WCD934X_HPH_R_ATEST, 0x54 }, + { WCD934X_HPH_RDAC_CLK_CTL1, 0x99 }, + { WCD934X_HPH_RDAC_CLK_CTL2, 0x9B }, + { WCD934X_HPH_RDAC_LDO_CTL, 0x33 }, + { WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 }, + { WCD934X_HPH_REFBUFF_UHQA_CTL, 0xA8 }, +}; + +static const struct reg_sequence tavil_hph_reset_tbl_1_0[] = { + { WCD934X_HPH_REFBUFF_LP_CTL, 0x0A }, + { WCD934X_HPH_L_DAC_CTL, 0x00 }, + { WCD934X_HPH_R_DAC_CTL, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH2, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH3, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0xA0 }, + { WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 }, + { WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 }, + { WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xFE }, + { WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x2 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e}, + { WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 }, +}; + +static const struct reg_sequence tavil_hph_reset_tbl_1_1[] = { + { WCD934X_HPH_REFBUFF_LP_CTL, 0x0E }, + { WCD934X_HPH_L_DAC_CTL, 0x00 }, + { WCD934X_HPH_R_DAC_CTL, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH2, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH3, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 }, + { WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0x81 }, + { WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 }, + { WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x81 }, + { WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 }, + { WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xFE }, + { WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x2 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e}, + { WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 }, +}; + +static const struct tavil_reg_mask_val tavil_pa_disable[] = { + { WCD934X_CDC_RX1_RX_PATH_CTL, 0x30, 0x10 }, /* RX1 mute enable */ + { WCD934X_CDC_RX2_RX_PATH_CTL, 0x30, 0x10 }, /* RX2 mute enable */ + { WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 }, /* GM3 boost disable */ + { WCD934X_ANA_HPH, 0x80, 0x00 }, /* HPHL PA disable */ + { WCD934X_ANA_HPH, 0x40, 0x00 }, /* HPHR PA disable */ + { WCD934X_ANA_HPH, 0x20, 0x00 }, /* HPHL REF dsable */ + { WCD934X_ANA_HPH, 0x10, 0x00 }, /* HPHR REF disable */ +}; + +static const struct tavil_reg_mask_val tavil_ocp_en_seq[] = { + { WCD934X_RX_OCP_CTL, 0x0F, 0x02 }, /* OCP number of attempts is 2 */ + { WCD934X_HPH_OCP_CTL, 0xFA, 0x3A }, /* OCP current limit */ + { WCD934X_HPH_L_TEST, 0x01, 0x01 }, /* Enable HPHL OCP */ + { WCD934X_HPH_R_TEST, 0x01, 0x01 }, /* Enable HPHR OCP */ +}; + +static const struct tavil_reg_mask_val tavil_ocp_en_seq_1[] = { + { WCD934X_RX_OCP_CTL, 0x0F, 0x02 }, /* OCP number of attempts is 2 */ + { WCD934X_HPH_OCP_CTL, 0xFA, 0x3A }, /* OCP current limit */ +}; + +/* LO-HIFI */ +static const struct tavil_reg_mask_val tavil_pre_pa_en_lohifi[] = { + { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00 }, + { WCD934X_FLYBACK_VNEG_CTRL_4, 0xf0, 0x80 }, + { WCD934X_HPH_NEW_INT_PA_MISC2, 0x20, 0x20 }, + { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xf0, 0x40 }, + { WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 }, + { WCD934X_RX_BIAS_HPH_LOWPOWER, 0xf0, 0xc0 }, + { WCD934X_HPH_PA_CTL1, 0x0e, 0x02 }, + { WCD934X_HPH_REFBUFF_LP_CTL, 0x06, 0x06 }, +}; + +static const struct tavil_reg_mask_val tavil_pre_pa_en[] = { + { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_MISC2, 0x20, 0x0 }, + { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xf0, 0x40 }, + { WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 }, + { WCD934X_RX_BIAS_HPH_LOWPOWER, 0xf0, 0x80 }, + { WCD934X_HPH_PA_CTL1, 0x0e, 0x06 }, + { WCD934X_HPH_REFBUFF_LP_CTL, 0x06, 0x06 }, +}; + +static const struct tavil_reg_mask_val tavil_post_pa_en[] = { + { WCD934X_HPH_L_TEST, 0x01, 0x01 }, /* Enable HPHL OCP */ + { WCD934X_HPH_R_TEST, 0x01, 0x01 }, /* Enable HPHR OCP */ + { WCD934X_CDC_RX1_RX_PATH_CTL, 0x30, 0x20 }, /* RX1 mute disable */ + { WCD934X_CDC_RX2_RX_PATH_CTL, 0x30, 0x20 }, /* RX2 mute disable */ + { WCD934X_HPH_CNP_WG_CTL, 0x80, 0x80 }, /* GM3 boost enable */ + { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02 }, +}; + +static void tavil_codec_hph_reg_range_read(struct regmap *map, u8 *buf) +{ + regmap_bulk_read(map, WCD934X_HPH_CNP_EN, buf, TAVIL_HPH_REG_RANGE_1); + regmap_bulk_read(map, WCD934X_HPH_NEW_ANA_HPH2, + buf + TAVIL_HPH_REG_RANGE_1, TAVIL_HPH_REG_RANGE_2); + regmap_bulk_read(map, WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + buf + TAVIL_HPH_REG_RANGE_1 + TAVIL_HPH_REG_RANGE_2, + TAVIL_HPH_REG_RANGE_3); +} + +static void tavil_codec_hph_reg_recover(struct tavil_priv *tavil, + struct regmap *map, int pa_status) +{ + int i; + unsigned int reg; + + if (tavil->mbhc) + blocking_notifier_call_chain(&tavil->mbhc->notifier, + WCD_EVENT_OCP_OFF, + &tavil->mbhc->wcd_mbhc); + + if (pa_status & 0xC0) + goto pa_en_restore; + + dev_dbg(tavil->dev, "%s: HPH PA in disable state (0x%x)\n", + __func__, pa_status); + + regmap_write_bits(map, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x10); + regmap_write_bits(map, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x10); + regmap_write_bits(map, WCD934X_ANA_HPH, 0xC0, 0x00); + regmap_write_bits(map, WCD934X_ANA_HPH, 0x30, 0x00); + regmap_write_bits(map, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x00); + regmap_write_bits(map, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x00); + + /* Restore to HW defaults */ + regmap_multi_reg_write(map, tavil_hph_reset_tbl, + ARRAY_SIZE(tavil_hph_reset_tbl)); + if (TAVIL_IS_1_1(tavil->wcd9xxx)) + regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_1, + ARRAY_SIZE(tavil_hph_reset_tbl_1_1)); + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_0, + ARRAY_SIZE(tavil_hph_reset_tbl_1_0)); + + for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq); i++) + regmap_write_bits(map, tavil_ocp_en_seq[i].reg, + tavil_ocp_en_seq[i].mask, + tavil_ocp_en_seq[i].val); + goto end; + + +pa_en_restore: + dev_dbg(tavil->dev, "%s: HPH PA in enable state (0x%x)\n", + __func__, pa_status); + + /* Disable PA and other registers before restoring */ + for (i = 0; i < ARRAY_SIZE(tavil_pa_disable); i++) { + if (TAVIL_IS_1_1(tavil->wcd9xxx) && + (tavil_pa_disable[i].reg == WCD934X_HPH_CNP_WG_CTL)) + continue; + regmap_write_bits(map, tavil_pa_disable[i].reg, + tavil_pa_disable[i].mask, + tavil_pa_disable[i].val); + } + + regmap_multi_reg_write(map, tavil_hph_reset_tbl, + ARRAY_SIZE(tavil_hph_reset_tbl)); + if (TAVIL_IS_1_1(tavil->wcd9xxx)) + regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_1, + ARRAY_SIZE(tavil_hph_reset_tbl_1_1)); + if (TAVIL_IS_1_0(tavil->wcd9xxx)) + regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_0, + ARRAY_SIZE(tavil_hph_reset_tbl_1_0)); + + for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq_1); i++) + regmap_write_bits(map, tavil_ocp_en_seq_1[i].reg, + tavil_ocp_en_seq_1[i].mask, + tavil_ocp_en_seq_1[i].val); + + if (tavil->hph_mode == CLS_H_LOHIFI) { + for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en_lohifi); i++) { + reg = tavil_pre_pa_en_lohifi[i].reg; + if ((TAVIL_IS_1_1(tavil->wcd9xxx)) && + ((reg == WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL) || + (reg == WCD934X_HPH_CNP_WG_CTL) || + (reg == WCD934X_HPH_REFBUFF_LP_CTL))) + continue; + regmap_write_bits(map, + tavil_pre_pa_en_lohifi[i].reg, + tavil_pre_pa_en_lohifi[i].mask, + tavil_pre_pa_en_lohifi[i].val); + } + } else { + for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en); i++) { + reg = tavil_pre_pa_en[i].reg; + if ((TAVIL_IS_1_1(tavil->wcd9xxx)) && + ((reg == WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL) || + (reg == WCD934X_HPH_CNP_WG_CTL) || + (reg == WCD934X_HPH_REFBUFF_LP_CTL))) + continue; + regmap_write_bits(map, tavil_pre_pa_en[i].reg, + tavil_pre_pa_en[i].mask, + tavil_pre_pa_en[i].val); + } + } + + if (TAVIL_IS_1_1(tavil->wcd9xxx)) { + regmap_write(map, WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x84); + regmap_write(map, WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x84); + } + + regmap_write_bits(map, WCD934X_ANA_HPH, 0x0C, pa_status & 0x0C); + regmap_write_bits(map, WCD934X_ANA_HPH, 0x30, 0x30); + /* wait for 100usec after HPH DAC is enabled */ + usleep_range(100, 110); + regmap_write(map, WCD934X_ANA_HPH, pa_status); + /* Sleep for 7msec after PA is enabled */ + usleep_range(7000, 7100); + + for (i = 0; i < ARRAY_SIZE(tavil_post_pa_en); i++) { + if ((TAVIL_IS_1_1(tavil->wcd9xxx)) && + (tavil_post_pa_en[i].reg == WCD934X_HPH_CNP_WG_CTL)) + continue; + regmap_write_bits(map, tavil_post_pa_en[i].reg, + tavil_post_pa_en[i].mask, + tavil_post_pa_en[i].val); + } + +end: + if (tavil->mbhc) { + tavil->mbhc->is_hph_recover = true; + blocking_notifier_call_chain( + &tavil->mbhc->notifier, + WCD_EVENT_OCP_ON, + &tavil->mbhc->wcd_mbhc); + } +} + +static int tavil_codec_reset_hph_registers(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + u8 cache_val[TAVIL_HPH_TOTAL_REG]; + u8 hw_val[TAVIL_HPH_TOTAL_REG]; + int pa_status; + int ret; + + dev_dbg(wcd9xxx->dev, "%s: event: %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + memset(cache_val, 0, TAVIL_HPH_TOTAL_REG); + memset(hw_val, 0, TAVIL_HPH_TOTAL_REG); + + regmap_read(wcd9xxx->regmap, WCD934X_ANA_HPH, &pa_status); + + tavil_codec_hph_reg_range_read(wcd9xxx->regmap, cache_val); + + /* Read register values from HW directly */ + regcache_cache_bypass(wcd9xxx->regmap, true); + tavil_codec_hph_reg_range_read(wcd9xxx->regmap, hw_val); + regcache_cache_bypass(wcd9xxx->regmap, false); + + /* compare both the registers to know if there is corruption */ + ret = memcmp(cache_val, hw_val, TAVIL_HPH_TOTAL_REG); + + /* If both the values are same, it means no corruption */ + if (ret) { + dev_dbg(component->dev, "%s: cache and hw reg are not same\n", + __func__); + tavil_codec_hph_reg_recover(tavil, wcd9xxx->regmap, + pa_status); + } else { + dev_dbg(component->dev, "%s: cache and hw reg are same\n", + __func__); + if (tavil->mbhc) + tavil->mbhc->is_hph_recover = false; + } + break; + default: + break; + }; + + return 0; +} + +static void tavil_restore_iir_coeff(struct tavil_priv *tavil, int iir_idx, + int band_idx) +{ + u16 reg_add; + int no_of_reg = 0; + + regmap_write(tavil->wcd9xxx->regmap, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + reg_add = WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx; + + if (tavil->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) + return; + /* + * Since wcd9xxx_slim_write_repeat() supports only maximum of 16 + * registers at a time, split total 20 writes(5 coefficients per + * band and 4 writes per coefficient) into 16 and 4. + */ + no_of_reg = WCD934X_CDC_REPEAT_WRITES_MAX; + wcd9xxx_slim_write_repeat(tavil->wcd9xxx, reg_add, no_of_reg, + &tavil->sidetone_coeff_array[iir_idx][band_idx][0]); + + no_of_reg = (WCD934X_CDC_SIDETONE_IIR_COEFF_MAX * 4) - + WCD934X_CDC_REPEAT_WRITES_MAX; + wcd9xxx_slim_write_repeat(tavil->wcd9xxx, reg_add, no_of_reg, + &tavil->sidetone_coeff_array[iir_idx][band_idx] + [WCD934X_CDC_REPEAT_WRITES_MAX]); +} + +static int tavil_iir_enable_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + /* IIR filter band registers are at integer multiples of 16 */ + u16 iir_reg = WCD934X_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx; + + ucontrol->value.integer.value[0] = + (snd_soc_component_read32(component, iir_reg) & + (1 << band_idx)) != 0; + + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0]); + return 0; +} + +static int tavil_iir_enable_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + bool iir_band_en_status; + int value = ucontrol->value.integer.value[0]; + u16 iir_reg = WCD934X_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx; + + tavil_restore_iir_coeff(tavil, iir_idx, band_idx); + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_component_update_bits(component, iir_reg, (1 << band_idx), + (value << band_idx)); + + iir_band_en_status = ((snd_soc_component_read32(component, iir_reg) & + (1 << band_idx)) != 0); + dev_dbg(component->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, iir_band_en_status); + return 0; +} + +static uint32_t get_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + int coeff_idx) +{ + uint32_t value = 0; + + /* Address does not automatically update if reading */ + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_component_read32(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx)); + + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_component_read32(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) << 8); + + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_component_read32(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) << 16); + + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_component_read32(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) & 0x3F) << 24); + + return value; +} + +static int tavil_iir_band_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = + get_iir_band_coeff(component, iir_idx, band_idx, 0); + ucontrol->value.integer.value[1] = + get_iir_band_coeff(component, iir_idx, band_idx, 1); + ucontrol->value.integer.value[2] = + get_iir_band_coeff(component, iir_idx, band_idx, 2); + ucontrol->value.integer.value[3] = + get_iir_band_coeff(component, iir_idx, band_idx, 3); + ucontrol->value.integer.value[4] = + get_iir_band_coeff(component, iir_idx, band_idx, 4); + + dev_dbg(component->dev, "%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[1], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[2], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[3], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[4]); + return 0; +} + +static void set_iir_band_coeff(struct snd_soc_component *component, + int iir_idx, int band_idx, + uint32_t value) +{ + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value & 0xFF)); + + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 8) & 0xFF); + + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 24) & 0x3F); +} + +static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int coeff_idx, idx = 0; + + /* + * Mask top bit it is reserved + * Updates addr automatically for each B2 write + */ + snd_soc_component_write(component, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + /* Store the coefficients in sidetone coeff array */ + for (coeff_idx = 0; coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX; + coeff_idx++) { + uint32_t value = ucontrol->value.integer.value[coeff_idx]; + + set_iir_band_coeff(component, iir_idx, band_idx, value); + + /* Four 8 bit values(one 32 bit) per coefficient */ + tavil->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value & 0xFF); + tavil->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 8) & 0xFF; + tavil->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 16) & 0xFF; + tavil->sidetone_coeff_array[iir_idx][band_idx][idx++] = + (value >> 24) & 0xFF; + } + + pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 0), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 1), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 2), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 3), + __func__, iir_idx, band_idx, + get_iir_band_coeff(component, iir_idx, band_idx, 4)); + return 0; +} + +static int tavil_compander_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tavil->comp_enabled[comp]; + return 0; +} + +static int tavil_compander_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, tavil->comp_enabled[comp], value); + tavil->comp_enabled[comp] = value; + + /* Any specific register configuration for compander */ + switch (comp) { + case COMPANDER_1: + /* Set Gain Source Select based on compander enable/disable */ + snd_soc_component_update_bits(component, WCD934X_HPH_L_EN, 0x20, + (value ? 0x00:0x20)); + break; + case COMPANDER_2: + snd_soc_component_update_bits(component, WCD934X_HPH_R_EN, 0x20, + (value ? 0x00:0x20)); + break; + case COMPANDER_3: + case COMPANDER_4: + case COMPANDER_7: + case COMPANDER_8: + break; + default: + /* + * if compander is not enabled for any interpolator, + * it does not cause any audio failure, so do not + * return error in this case, but just print a log + */ + dev_warn(component->dev, "%s: unknown compander: %d\n", + __func__, comp); + }; + return 0; +} + +static int tavil_hph_asrc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int index = -EINVAL; + + if (!strcmp(kcontrol->id.name, "ASRC0 Output Mode")) + index = ASRC0; + if (!strcmp(kcontrol->id.name, "ASRC1 Output Mode")) + index = ASRC1; + + if (tavil && (index >= 0) && (index < ASRC_MAX)) + tavil->asrc_output_mode[index] = + ucontrol->value.integer.value[0]; + + return 0; +} + +static int tavil_hph_asrc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int val = 0; + int index = -EINVAL; + + if (!strcmp(kcontrol->id.name, "ASRC0 Output Mode")) + index = ASRC0; + if (!strcmp(kcontrol->id.name, "ASRC1 Output Mode")) + index = ASRC1; + + if (tavil && (index >= 0) && (index < ASRC_MAX)) + val = tavil->asrc_output_mode[index]; + + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int tavil_hph_idle_detect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int val = 0; + + if (tavil) + val = tavil->idle_det_cfg.hph_idle_detect_en; + + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int tavil_hph_idle_detect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + if (tavil) + tavil->idle_det_cfg.hph_idle_detect_en = + ucontrol->value.integer.value[0]; + + return 0; +} + +static int tavil_dmic_pin_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u16 dmic_pin; + u8 reg_val, pinctl_position; + + pinctl_position = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + dmic_pin = pinctl_position & 0x07; + reg_val = snd_soc_component_read32(component, + WCD934X_TLMM_DMIC1_CLK_PINCFG + dmic_pin - 1); + + ucontrol->value.integer.value[0] = !!reg_val; + + return 0; +} + +static int tavil_dmic_pin_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + u16 ctl_reg, cfg_reg, dmic_pin; + u8 ctl_val, cfg_val, pinctl_position, pinctl_mode, mask; + + /* 0- high or low; 1- high Z */ + pinctl_mode = ucontrol->value.integer.value[0]; + pinctl_position = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + switch (pinctl_position >> 3) { + case 0: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_0; + break; + case 1: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_1; + break; + case 2: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_2; + break; + case 3: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_3; + break; + default: + dev_err(component->dev, "%s: Invalid pinctl position = %d\n", + __func__, pinctl_position); + return -EINVAL; + } + + ctl_val = ~(pinctl_mode << (pinctl_position & 0x07)); + mask = 1 << (pinctl_position & 0x07); + snd_soc_component_update_bits(component, ctl_reg, mask, ctl_val); + + dmic_pin = pinctl_position & 0x07; + cfg_reg = WCD934X_TLMM_DMIC1_CLK_PINCFG + dmic_pin - 1; + if (pinctl_mode) { + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + cfg_val = 0x6; + else + cfg_val = 0xD; + } else + cfg_val = 0; + snd_soc_component_update_bits(component, cfg_reg, 0x1F, cfg_val); + + dev_dbg(component->dev, "%s: reg=0x%x mask=0x%x val=%d reg=0x%x val=%d\n", + __func__, ctl_reg, mask, ctl_val, cfg_reg, cfg_val); + + return 0; +} + +static int tavil_amic_pwr_lvl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u16 amic_reg = 0; + + if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC3; + + if (amic_reg) + ucontrol->value.integer.value[0] = + (snd_soc_component_read32(component, amic_reg) & + WCD934X_AMIC_PWR_LVL_MASK) >> + WCD934X_AMIC_PWR_LVL_SHIFT; + return 0; +} + +static int tavil_amic_pwr_lvl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 mode_val; + u16 amic_reg = 0; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: mode: %d\n", __func__, mode_val); + + if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC3; + + if (amic_reg) + snd_soc_component_update_bits(component, amic_reg, + WCD934X_AMIC_PWR_LVL_MASK, + mode_val << WCD934X_AMIC_PWR_LVL_SHIFT); + return 0; +} + +static const char *const tavil_conn_mad_text[] = { + "NOTUSED1", "ADC1", "ADC2", "ADC3", "ADC4", "NOTUSED5", + "NOTUSED6", "NOTUSED2", "DMIC0", "DMIC1", "DMIC2", "DMIC3", + "DMIC4", "DMIC5", "NOTUSED3", "NOTUSED4" +}; + +static const struct soc_enum tavil_conn_mad_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tavil_conn_mad_text), + tavil_conn_mad_text); + +static int tavil_mad_input_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u8 tavil_mad_input; + + tavil_mad_input = snd_soc_component_read32( + component, WCD934X_SOC_MAD_INP_SEL) & 0x0F; + ucontrol->value.integer.value[0] = tavil_mad_input; + + dev_dbg(component->dev, "%s: tavil_mad_input = %s\n", __func__, + tavil_conn_mad_text[tavil_mad_input]); + + return 0; +} + +static int tavil_mad_input_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct snd_soc_card *card = component->card; + u8 tavil_mad_input; + char mad_amic_input_widget[6]; + const char *mad_input_widget; + const char *source_widget = NULL; + u32 adc, i, mic_bias_found = 0; + int ret = 0; + char *mad_input; + bool is_adc_input = false; + + tavil_mad_input = ucontrol->value.integer.value[0]; + + if (tavil_mad_input >= sizeof(tavil_conn_mad_text)/ + sizeof(tavil_conn_mad_text[0])) { + dev_err(component->dev, + "%s: tavil_mad_input = %d out of bounds\n", + __func__, tavil_mad_input); + return -EINVAL; + } + + if (strnstr(tavil_conn_mad_text[tavil_mad_input], "NOTUSED", + sizeof("NOTUSED"))) { + dev_dbg(component->dev, + "%s: Unsupported tavil_mad_input = %s\n", + __func__, tavil_conn_mad_text[tavil_mad_input]); + /* Make sure the MAD register is updated */ + snd_soc_component_update_bits(component, WCD934X_ANA_MAD_SETUP, + 0x88, 0x00); + return -EINVAL; + } + + if (strnstr(tavil_conn_mad_text[tavil_mad_input], + "ADC", sizeof("ADC"))) { + mad_input = strpbrk(tavil_conn_mad_text[tavil_mad_input], + "1234"); + if (!mad_input) { + dev_err(component->dev, "%s: Invalid MAD input %s\n", + __func__, tavil_conn_mad_text[tavil_mad_input]); + return -EINVAL; + } + + ret = kstrtouint(mad_input, 10, &adc); + if ((ret < 0) || (adc > 4)) { + dev_err(component->dev, "%s: Invalid ADC = %s\n", + __func__, + tavil_conn_mad_text[tavil_mad_input]); + return -EINVAL; + } + + /*AMIC4 and AMIC5 share ADC4*/ + if ((adc == 4) && + (snd_soc_component_read32( + component, WCD934X_TX_NEW_AMIC_4_5_SEL) & 0x10)) + adc = 5; + + snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc); + + mad_input_widget = mad_amic_input_widget; + is_adc_input = true; + } else { + /* DMIC type input widget*/ + mad_input_widget = tavil_conn_mad_text[tavil_mad_input]; + } + + dev_dbg(component->dev, + "%s: tavil input widget = %s, adc_input = %s\n", __func__, + mad_input_widget, is_adc_input ? "true" : "false"); + + for (i = 0; i < card->num_of_dapm_routes; i++) { + if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) { + source_widget = card->of_dapm_routes[i].source; + if (!source_widget) { + dev_err(component->dev, + "%s: invalid source widget\n", + __func__); + return -EINVAL; + } + + if (strnstr(source_widget, + "MIC BIAS1", sizeof("MIC BIAS1"))) { + mic_bias_found = 1; + break; + } else if (strnstr(source_widget, + "MIC BIAS2", sizeof("MIC BIAS2"))) { + mic_bias_found = 2; + break; + } else if (strnstr(source_widget, + "MIC BIAS3", sizeof("MIC BIAS3"))) { + mic_bias_found = 3; + break; + } else if (strnstr(source_widget, + "MIC BIAS4", sizeof("MIC BIAS4"))) { + mic_bias_found = 4; + break; + } + } + } + + if (!mic_bias_found) { + dev_err(component->dev, "%s: mic bias not found for input %s\n", + __func__, mad_input_widget); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: mic_bias found = %d\n", __func__, + mic_bias_found); + + snd_soc_component_update_bits(component, WCD934X_SOC_MAD_INP_SEL, + 0x0F, tavil_mad_input); + snd_soc_component_update_bits(component, WCD934X_ANA_MAD_SETUP, + 0x07, mic_bias_found); + /* for all adc inputs, mad should be in micbias mode with BG enabled */ + if (is_adc_input) + snd_soc_component_update_bits(component, WCD934X_ANA_MAD_SETUP, + 0x88, 0x88); + else + snd_soc_component_update_bits(component, WCD934X_ANA_MAD_SETUP, + 0x88, 0x00); + return 0; +} + +static int tavil_ear_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ear_pa_gain = snd_soc_component_read32(component, WCD934X_ANA_EAR); + + ear_pa_gain = (ear_pa_gain & 0x70) >> 4; + + ucontrol->value.integer.value[0] = ear_pa_gain; + + dev_dbg(component->dev, "%s: ear_pa_gain = 0x%x\n", __func__, + ear_pa_gain); + + return 0; +} + +static int tavil_ear_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + ear_pa_gain = ucontrol->value.integer.value[0] << 4; + + snd_soc_component_update_bits(component, WCD934X_ANA_EAR, + 0x70, ear_pa_gain); + return 0; +} + +static int tavil_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tavil->ear_spkr_gain; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int tavil_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + tavil->ear_spkr_gain = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: gain = %d\n", __func__, + tavil->ear_spkr_gain); + + return 0; +} + +static int tavil_spkr_left_boost_stage_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + bst_state_max = snd_soc_component_read32( + component, WCD934X_CDC_BOOST0_BOOST_CTL); + bst_state_max = (bst_state_max & 0x0c) >> 2; + ucontrol->value.integer.value[0] = bst_state_max; + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int tavil_spkr_left_boost_stage_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + bst_state_max = ucontrol->value.integer.value[0] << 2; + snd_soc_component_update_bits(component, WCD934X_CDC_BOOST0_BOOST_CTL, + 0x0c, bst_state_max); + + return 0; +} + +static int tavil_spkr_right_boost_stage_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + bst_state_max = snd_soc_component_read32(component, + WCD934X_CDC_BOOST1_BOOST_CTL); + bst_state_max = (bst_state_max & 0x0c) >> 2; + ucontrol->value.integer.value[0] = bst_state_max; + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int tavil_spkr_right_boost_stage_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 bst_state_max; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + bst_state_max = ucontrol->value.integer.value[0] << 2; + snd_soc_component_update_bits(component, WCD934X_CDC_BOOST1_BOOST_CTL, + 0x0c, bst_state_max); + + return 0; +} + +static int tavil_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 tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tavil->hph_mode; + return 0; +} + +static int tavil_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tavil_priv *tavil = 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_warn(component->dev, "%s:Invalid HPH Mode, default to Cls-H LOHiFi\n", + __func__); + mode_val = CLS_H_LOHIFI; + } + tavil->hph_mode = mode_val; + return 0; +} + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", + "CLS_H_ULP", "CLS_AB_HIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static const char *const tavil_anc_func_text[] = {"OFF", "ON"}; +static const struct soc_enum tavil_anc_func_enum = + SOC_ENUM_SINGLE_EXT(2, tavil_anc_func_text); + +static const char *const tavil_clkmode_text[] = {"EXTERNAL", "INTERNAL"}; +static SOC_ENUM_SINGLE_EXT_DECL(tavil_clkmode_enum, tavil_clkmode_text); + +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static const char * const rx_cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ", + "CF_NEG_3DB_0P48HZ" +}; + +static const char * const amic_pwr_lvl_text[] = { + "LOW_PWR", "DEFAULT", "HIGH_PERF", "HYBRID" +}; + +static const char * const hph_idle_detect_text[] = { + "OFF", "ON" +}; + +static const char * const asrc_mode_text[] = { + "INT", "FRAC" +}; + +static const char * const tavil_ear_pa_gain_text[] = { + "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", + "G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB" +}; + +static const char * const tavil_ear_spkr_pa_gain_text[] = { + "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB", + "G_4_DB", "G_5_DB", "G_6_DB" +}; + +static const char * const tavil_speaker_boost_stage_text[] = { + "NO_MAX_STATE", "MAX_STATE_1", "MAX_STATE_2" +}; + +static SOC_ENUM_SINGLE_EXT_DECL(tavil_ear_pa_gain_enum, tavil_ear_pa_gain_text); +static SOC_ENUM_SINGLE_EXT_DECL(tavil_ear_spkr_pa_gain_enum, + tavil_ear_spkr_pa_gain_text); +static SOC_ENUM_SINGLE_EXT_DECL(tavil_spkr_boost_stage_enum, + tavil_speaker_boost_stage_text); +static SOC_ENUM_SINGLE_EXT_DECL(amic_pwr_lvl_enum, amic_pwr_lvl_text); +static SOC_ENUM_SINGLE_EXT_DECL(hph_idle_detect_enum, hph_idle_detect_text); +static SOC_ENUM_SINGLE_EXT_DECL(asrc_mode_enum, asrc_mode_text); +static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, WCD934X_CDC_TX0_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, WCD934X_CDC_TX1_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec2_enum, WCD934X_CDC_TX2_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec3_enum, WCD934X_CDC_TX3_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec4_enum, WCD934X_CDC_TX4_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec5_enum, WCD934X_CDC_TX5_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec6_enum, WCD934X_CDC_TX6_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec7_enum, WCD934X_CDC_TX7_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec8_enum, WCD934X_CDC_TX8_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int0_1_enum, WCD934X_CDC_RX0_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int1_1_enum, WCD934X_CDC_RX1_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int2_1_enum, WCD934X_CDC_RX2_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int3_1_enum, WCD934X_CDC_RX3_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int4_1_enum, WCD934X_CDC_RX4_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int7_1_enum, WCD934X_CDC_RX7_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int8_1_enum, WCD934X_CDC_RX8_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct snd_kcontrol_new tavil_snd_controls[] = { + SOC_ENUM_EXT("EAR PA Gain", tavil_ear_pa_gain_enum, + tavil_ear_pa_gain_get, tavil_ear_pa_gain_put), + SOC_ENUM_EXT("EAR SPKR PA Gain", tavil_ear_spkr_pa_gain_enum, + tavil_ear_spkr_pa_gain_get, tavil_ear_spkr_pa_gain_put), + SOC_ENUM_EXT("SPKR Left Boost Max State", tavil_spkr_boost_stage_enum, + tavil_spkr_left_boost_stage_get, + tavil_spkr_left_boost_stage_put), + SOC_ENUM_EXT("SPKR Right Boost Max State", tavil_spkr_boost_stage_enum, + tavil_spkr_right_boost_stage_get, + tavil_spkr_right_boost_stage_put), + SOC_SINGLE_TLV("HPHL Volume", WCD934X_HPH_L_EN, 0, 24, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD934X_HPH_R_EN, 0, 24, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT1 Volume", WCD934X_DIFF_LO_LO1_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT2 Volume", WCD934X_DIFF_LO_LO2_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("ADC1 Volume", WCD934X_ANA_AMIC1, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD934X_ANA_AMIC2, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD934X_ANA_AMIC3, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD934X_ANA_AMIC4, 0, 20, 0, analog_gain), + + SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", + WCD934X_CDC_RX0_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", + WCD934X_CDC_RX1_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", + WCD934X_CDC_RX2_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", + WCD934X_CDC_RX3_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", + WCD934X_CDC_RX4_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", + WCD934X_CDC_RX7_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", + WCD934X_CDC_RX8_RX_VOL_MIX_CTL, -84, 40, digital_gain), + + SOC_SINGLE_S8_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC5 Volume", WCD934X_CDC_TX5_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC6 Volume", WCD934X_CDC_TX6_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL, + -84, 40, digital_gain), + + SOC_SINGLE_S8_TLV("IIR0 INP0 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP1 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP2 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR0 INP3 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP0 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40, + digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40, + digital_gain), + + SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tavil_get_anc_slot, + tavil_put_anc_slot), + SOC_ENUM_EXT("ANC Function", tavil_anc_func_enum, tavil_get_anc_func, + tavil_put_anc_func), + + SOC_ENUM_EXT("CLK MODE", tavil_clkmode_enum, tavil_get_clkmode, + tavil_put_clkmode), + + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), + + SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), + SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), + SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), + SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum), + SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum), + SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum), + SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum), + SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum), + SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum), + SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum), + SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum), + SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum), + SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum), + SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum), + + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + tavil_rx_hph_mode_get, tavil_rx_hph_mode_put), + + SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band2", IIR0, BAND2, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band3", IIR0, BAND3, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band4", IIR0, BAND4, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band5", IIR0, BAND5, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + + SOC_SINGLE_MULTI_EXT("IIR0 Band1", IIR0, BAND1, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band2", IIR0, BAND2, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band3", IIR0, BAND3, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band4", IIR0, BAND4, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band5", IIR0, BAND5, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + + SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0, + tavil_compander_get, tavil_compander_put), + + SOC_ENUM_EXT("ASRC0 Output Mode", asrc_mode_enum, + tavil_hph_asrc_mode_get, tavil_hph_asrc_mode_put), + SOC_ENUM_EXT("ASRC1 Output Mode", asrc_mode_enum, + tavil_hph_asrc_mode_get, tavil_hph_asrc_mode_put), + + SOC_ENUM_EXT("HPH Idle Detect", hph_idle_detect_enum, + tavil_hph_idle_detect_get, tavil_hph_idle_detect_put), + + SOC_ENUM_EXT("MAD Input", tavil_conn_mad_enum, + tavil_mad_input_get, tavil_mad_input_put), + + SOC_SINGLE_EXT("DMIC1_CLK_PIN_MODE", SND_SOC_NOPM, 17, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC1_DATA_PIN_MODE", SND_SOC_NOPM, 18, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC2_CLK_PIN_MODE", SND_SOC_NOPM, 19, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC2_DATA_PIN_MODE", SND_SOC_NOPM, 20, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC3_CLK_PIN_MODE", SND_SOC_NOPM, 21, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC3_DATA_PIN_MODE", SND_SOC_NOPM, 22, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + SOC_ENUM_EXT("AMIC_1_2 PWR MODE", amic_pwr_lvl_enum, + tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put), + SOC_ENUM_EXT("AMIC_3_4 PWR MODE", amic_pwr_lvl_enum, + tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put), + SOC_ENUM_EXT("AMIC_5_6 PWR MODE", amic_pwr_lvl_enum, + tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put), +}; + +static int tavil_dec_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + u16 mic_sel_reg = 0; + u8 mic_sel; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX0_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX4_TX_PATH_CFG0; + else if (e->shift_l == 4) + mic_sel_reg = WCD934X_CDC_TX8_TX_PATH_CFG0; + break; + case WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX1_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX5_TX_PATH_CFG0; + break; + case WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX2_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX6_TX_PATH_CFG0; + break; + case WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX3_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX7_TX_PATH_CFG0; + break; + default: + dev_err(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + + /* ADC: 0, DMIC: 1 */ + mic_sel = val ? 0x0 : 0x1; + if (mic_sel_reg) + snd_soc_component_update_bits(component, mic_sel_reg, 1 << 7, + mic_sel << 7); + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int tavil_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + unsigned short look_ahead_dly_reg = WCD934X_CDC_RX0_RX_PATH_CFG0; + + val = ucontrol->value.enumerated.item[0]; + if (val >= e->items) + return -EINVAL; + + dev_dbg(component->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + if (e->reg == WCD934X_CDC_RX0_RX_PATH_SEC0) + look_ahead_dly_reg = WCD934X_CDC_RX0_RX_PATH_CFG0; + else if (e->reg == WCD934X_CDC_RX1_RX_PATH_SEC0) + look_ahead_dly_reg = WCD934X_CDC_RX1_RX_PATH_CFG0; + else if (e->reg == WCD934X_CDC_RX2_RX_PATH_SEC0) + look_ahead_dly_reg = WCD934X_CDC_RX2_RX_PATH_CFG0; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, look_ahead_dly_reg, + 0x08, (val ? 0x08 : 0x00)); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static const char * const rx_int0_7_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7", "PROXIMITY" +}; + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_sidetone_mix_text[] = { + "ZERO", "SRC0", "SRC1", "SRC_SUM" +}; + +static const char * const cdc_if_tx0_mux_text[] = { + "ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192" +}; +static const char * const cdc_if_tx1_mux_text[] = { + "ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192" +}; +static const char * const cdc_if_tx2_mux_text[] = { + "ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192" +}; +static const char * const cdc_if_tx3_mux_text[] = { + "ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192" +}; +static const char * const cdc_if_tx4_mux_text[] = { + "ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192" +}; +static const char * const cdc_if_tx5_mux_text[] = { + "ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192" +}; +static const char * const cdc_if_tx6_mux_text[] = { + "ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192" +}; +static const char * const cdc_if_tx7_mux_text[] = { + "ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192" +}; +static const char * const cdc_if_tx8_mux_text[] = { + "ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192" +}; +static const char * const cdc_if_tx9_mux_text[] = { + "ZERO", "DEC7", "DEC7_192" +}; +static const char * const cdc_if_tx10_mux_text[] = { + "ZERO", "DEC6", "DEC6_192" +}; +static const char * const cdc_if_tx11_mux_text[] = { + "DEC_0_5", "DEC_9_12", "MAD_AUDIO", "MAD_BRDCST" +}; +static const char * const cdc_if_tx11_inp1_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", + "DEC5", "RX_MIX_TX5", "DEC9_10", "DEC11_12" +}; +static const char * const cdc_if_tx13_mux_text[] = { + "CDC_DEC_5", "MAD_BRDCST" +}; +static const char * const cdc_if_tx13_inp1_mux_text[] = { + "ZERO", "DEC5", "DEC5_192" +}; + +static const char * const iir_inp_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", + "DEC7", "DEC8", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_1_interp_mux_text[] = { + "ZERO", "RX INT0_1 MIX1", +}; + +static const char * const rx_int1_1_interp_mux_text[] = { + "ZERO", "RX INT1_1 MIX1", +}; + +static const char * const rx_int2_1_interp_mux_text[] = { + "ZERO", "RX INT2_1 MIX1", +}; + +static const char * const rx_int3_1_interp_mux_text[] = { + "ZERO", "RX INT3_1 MIX1", +}; + +static const char * const rx_int4_1_interp_mux_text[] = { + "ZERO", "RX INT4_1 MIX1", +}; + +static const char * const rx_int7_1_interp_mux_text[] = { + "ZERO", "RX INT7_1 MIX1", +}; + +static const char * const rx_int8_1_interp_mux_text[] = { + "ZERO", "RX INT8_1 MIX1", +}; + +static const char * const rx_int0_2_interp_mux_text[] = { + "ZERO", "RX INT0_2 MUX", +}; + +static const char * const rx_int1_2_interp_mux_text[] = { + "ZERO", "RX INT1_2 MUX", +}; + +static const char * const rx_int2_2_interp_mux_text[] = { + "ZERO", "RX INT2_2 MUX", +}; + +static const char * const rx_int3_2_interp_mux_text[] = { + "ZERO", "RX INT3_2 MUX", +}; + +static const char * const rx_int4_2_interp_mux_text[] = { + "ZERO", "RX INT4_2 MUX", +}; + +static const char * const rx_int7_2_interp_mux_text[] = { + "ZERO", "RX INT7_2 MUX", +}; + +static const char * const rx_int8_2_interp_mux_text[] = { + "ZERO", "RX INT8_2 MUX", +}; + +static const char * const mad_sel_txt[] = { + "SPE", "MSM" +}; + +static const char * const mad_inp_mux_txt[] = { + "MAD", "DEC1" +}; + +static const char * const adc_mux_text[] = { + "DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2" +}; + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5" +}; + +static const char * const amic_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "ADC4" +}; + +static const char * const amic4_5_sel_text[] = { + "AMIC4", "AMIC5" +}; + +static const char * const anc0_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHL", "ANC_IN_EAR", "ANC_IN_EAR_SPKR", + "ANC_IN_LO1" +}; + +static const char * const anc1_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHR", "ANC_IN_LO2" +}; + +static const char * const rx_echo_mux_text[] = { + "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2", "RX_MIX3", "RX_MIX4", + "RX_MIX5", "RX_MIX6", "RX_MIX7", "RX_MIX8" +}; + +static const char *const slim_rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB" +}; + +static const char *const i2s_rx01_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB" +}; + +static const char *const i2s_rx23_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB" +}; + +static const char *const i2s_rx45_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB" +}; + +static const char *const i2s_rx67_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB" +}; + +static const char *const cdc_if_rx0_mux_text[] = { + "SLIM RX0", "I2S RX0" +}; +static const char *const cdc_if_rx1_mux_text[] = { + "SLIM RX1", "I2S RX1" +}; +static const char *const cdc_if_rx2_mux_text[] = { + "SLIM RX2", "I2S RX2" +}; +static const char *const cdc_if_rx3_mux_text[] = { + "SLIM RX3", "I2S RX3" +}; +static const char *const cdc_if_rx4_mux_text[] = { + "SLIM RX4", "I2S RX4" +}; +static const char *const cdc_if_rx5_mux_text[] = { + "SLIM RX5", "I2S RX5" +}; +static const char *const cdc_if_rx6_mux_text[] = { + "SLIM RX6", "I2S RX6" +}; +static const char *const cdc_if_rx7_mux_text[] = { + "SLIM RX7", "I2S RX7" +}; + +static const char * const asrc0_mux_text[] = { + "ZERO", "ASRC_IN_HPHL", "ASRC_IN_LO1", +}; + +static const char * const asrc1_mux_text[] = { + "ZERO", "ASRC_IN_HPHR", "ASRC_IN_LO2", +}; + +static const char * const asrc2_mux_text[] = { + "ZERO", "ASRC_IN_SPKR1", +}; + +static const char * const asrc3_mux_text[] = { + "ZERO", "ASRC_IN_SPKR2", +}; + +static const char * const native_mux_text[] = { + "OFF", "ON", +}; + +static const char *const wdma3_port0_text[] = { + "RX_MIX_TX0", "DEC0" +}; + +static const char *const wdma3_port1_text[] = { + "RX_MIX_TX1", "DEC1" +}; + +static const char *const wdma3_port2_text[] = { + "RX_MIX_TX2", "DEC2" +}; + +static const char *const wdma3_port3_text[] = { + "RX_MIX_TX3", "DEC3" +}; + +static const char *const wdma3_port4_text[] = { + "RX_MIX_TX4", "DEC4" +}; + +static const char *const wdma3_port5_text[] = { + "RX_MIX_TX5", "DEC5" +}; + +static const char *const wdma3_port6_text[] = { + "RX_MIX_TX6", "DEC6" +}; + +static const char *const wdma3_ch_text[] = { + "PORT_0", "PORT_1", "PORT_2", "PORT_3", "PORT_4", + "PORT_5", "PORT_6", "PORT_7", "PORT_8", +}; + +static const struct snd_kcontrol_new aif4_vi_mixer[] = { + SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, WCD934X_TX14, 1, 0, + tavil_vi_feed_mixer_get, tavil_vi_feed_mixer_put), + SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, WCD934X_TX15, 1, 0, + tavil_vi_feed_mixer_get, tavil_vi_feed_mixer_put), +}; + +static const struct snd_kcontrol_new aif1_slim_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif1_i2s_cap_mixer[] = { + SOC_SINGLE_EXT("I2S TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif2_slim_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif2_i2s_cap_mixer[] = { + SOC_SINGLE_EXT("I2S TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif3_slim_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif3_i2s_cap_mixer[] = { + SOC_SINGLE_EXT("I2S TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), + SOC_SINGLE_EXT("I2S TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + i2s_tx_mixer_get, i2s_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif4_slim_mad_mixer[] = { + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +WCD_DAPM_ENUM_EXT(slim_rx0, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx1, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx2, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx3, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx4, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx5, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx6, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx7, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); + +WCD_DAPM_ENUM(cdc_if_rx0, SND_SOC_NOPM, 0, cdc_if_rx0_mux_text); +WCD_DAPM_ENUM(cdc_if_rx1, SND_SOC_NOPM, 0, cdc_if_rx1_mux_text); +WCD_DAPM_ENUM(cdc_if_rx2, SND_SOC_NOPM, 0, cdc_if_rx2_mux_text); +WCD_DAPM_ENUM(cdc_if_rx3, SND_SOC_NOPM, 0, cdc_if_rx3_mux_text); +WCD_DAPM_ENUM(cdc_if_rx4, SND_SOC_NOPM, 0, cdc_if_rx4_mux_text); +WCD_DAPM_ENUM(cdc_if_rx5, SND_SOC_NOPM, 0, cdc_if_rx5_mux_text); +WCD_DAPM_ENUM(cdc_if_rx6, SND_SOC_NOPM, 0, cdc_if_rx6_mux_text); +WCD_DAPM_ENUM(cdc_if_rx7, SND_SOC_NOPM, 0, cdc_if_rx7_mux_text); + +WCD_DAPM_ENUM(rx_int0_2, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, + rx_int0_7_mix_mux_text); +WCD_DAPM_ENUM(rx_int1_2, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int2_2, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int3_2, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int4_2, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int7_2, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, + rx_int0_7_mix_mux_text); +WCD_DAPM_ENUM(rx_int8_2, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, + rx_int_mix_mux_text); + +WCD_DAPM_ENUM(rx_int0_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int0_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int0_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int1_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int1_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int1_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int2_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int2_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int2_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int3_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int3_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int3_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int4_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int4_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int4_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int7_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int7_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int7_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int8_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int8_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int8_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, + rx_prim_mix_text); + +WCD_DAPM_ENUM(rx_int0_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int1_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int2_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int3_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int4_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int7_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 2, + rx_sidetone_mix_text); + +WCD_DAPM_ENUM(tx_adc_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 4, + adc_mux_text); +WCD_DAPM_ENUM(tx_adc_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 4, + adc_mux_text); +WCD_DAPM_ENUM(tx_adc_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 4, + adc_mux_text); +WCD_DAPM_ENUM(tx_adc_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 6, + adc_mux_text); + + +WCD_DAPM_ENUM(tx_dmic_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 3, + dmic_mux_text); + + +WCD_DAPM_ENUM(tx_amic_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0, + amic_mux_text); + +WCD_DAPM_ENUM(tx_amic4_5, WCD934X_TX_NEW_AMIC_4_5_SEL, 7, amic4_5_sel_text); + +WCD_DAPM_ENUM(cdc_if_tx0, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 0, + cdc_if_tx0_mux_text); +WCD_DAPM_ENUM(cdc_if_tx1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 2, + cdc_if_tx1_mux_text); +WCD_DAPM_ENUM(cdc_if_tx2, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 4, + cdc_if_tx2_mux_text); +WCD_DAPM_ENUM(cdc_if_tx3, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 6, + cdc_if_tx3_mux_text); +WCD_DAPM_ENUM(cdc_if_tx4, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 0, + cdc_if_tx4_mux_text); +WCD_DAPM_ENUM(cdc_if_tx5, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 2, + cdc_if_tx5_mux_text); +WCD_DAPM_ENUM(cdc_if_tx6, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 4, + cdc_if_tx6_mux_text); +WCD_DAPM_ENUM(cdc_if_tx7, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 6, + cdc_if_tx7_mux_text); +WCD_DAPM_ENUM(cdc_if_tx8, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 0, + cdc_if_tx8_mux_text); +WCD_DAPM_ENUM(cdc_if_tx9, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 2, + cdc_if_tx9_mux_text); +WCD_DAPM_ENUM(cdc_if_tx10, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 4, + cdc_if_tx10_mux_text); +WCD_DAPM_ENUM(cdc_if_tx11_inp1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 0, + cdc_if_tx11_inp1_mux_text); +WCD_DAPM_ENUM(cdc_if_tx11, WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0, + cdc_if_tx11_mux_text); +WCD_DAPM_ENUM(cdc_if_tx13_inp1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 4, + cdc_if_tx13_inp1_mux_text); +WCD_DAPM_ENUM(cdc_if_tx13, WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0, + cdc_if_tx13_mux_text); + +WCD_DAPM_ENUM(rx_mix_tx0, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx1, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx2, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx3, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx4, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx5, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx6, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx7, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx8, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4, 0, + rx_echo_mux_text); + +WCD_DAPM_ENUM(iir0_inp0, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir0_inp1, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir0_inp2, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir0_inp3, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp0, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp1, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp2, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp3, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0, + iir_inp_mux_text); + +WCD_DAPM_ENUM(rx_int0_1_interp, SND_SOC_NOPM, 0, rx_int0_1_interp_mux_text); +WCD_DAPM_ENUM(rx_int1_1_interp, SND_SOC_NOPM, 0, rx_int1_1_interp_mux_text); +WCD_DAPM_ENUM(rx_int2_1_interp, SND_SOC_NOPM, 0, rx_int2_1_interp_mux_text); +WCD_DAPM_ENUM(rx_int3_1_interp, SND_SOC_NOPM, 0, rx_int3_1_interp_mux_text); +WCD_DAPM_ENUM(rx_int4_1_interp, SND_SOC_NOPM, 0, rx_int4_1_interp_mux_text); +WCD_DAPM_ENUM(rx_int7_1_interp, SND_SOC_NOPM, 0, rx_int7_1_interp_mux_text); +WCD_DAPM_ENUM(rx_int8_1_interp, SND_SOC_NOPM, 0, rx_int8_1_interp_mux_text); + +WCD_DAPM_ENUM(rx_int0_2_interp, SND_SOC_NOPM, 0, rx_int0_2_interp_mux_text); +WCD_DAPM_ENUM(rx_int1_2_interp, SND_SOC_NOPM, 0, rx_int1_2_interp_mux_text); +WCD_DAPM_ENUM(rx_int2_2_interp, SND_SOC_NOPM, 0, rx_int2_2_interp_mux_text); +WCD_DAPM_ENUM(rx_int3_2_interp, SND_SOC_NOPM, 0, rx_int3_2_interp_mux_text); +WCD_DAPM_ENUM(rx_int4_2_interp, SND_SOC_NOPM, 0, rx_int4_2_interp_mux_text); +WCD_DAPM_ENUM(rx_int7_2_interp, SND_SOC_NOPM, 0, rx_int7_2_interp_mux_text); +WCD_DAPM_ENUM(rx_int8_2_interp, SND_SOC_NOPM, 0, rx_int8_2_interp_mux_text); + +WCD_DAPM_ENUM(mad_sel, WCD934X_CPE_SS_SVA_CFG, 0, + mad_sel_txt); + +WCD_DAPM_ENUM(mad_inp_mux, WCD934X_CPE_SS_SVA_CFG, 2, + mad_inp_mux_txt); + +WCD_DAPM_ENUM_EXT(rx_int0_dem_inp, WCD934X_CDC_RX0_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + tavil_int_dem_inp_mux_put); +WCD_DAPM_ENUM_EXT(rx_int1_dem_inp, WCD934X_CDC_RX1_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + tavil_int_dem_inp_mux_put); +WCD_DAPM_ENUM_EXT(rx_int2_dem_inp, WCD934X_CDC_RX2_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + tavil_int_dem_inp_mux_put); + +WCD_DAPM_ENUM_EXT(tx_adc_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 4, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); + +WCD_DAPM_ENUM(asrc0, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 0, + asrc0_mux_text); +WCD_DAPM_ENUM(asrc1, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 2, + asrc1_mux_text); +WCD_DAPM_ENUM(asrc2, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 4, + asrc2_mux_text); +WCD_DAPM_ENUM(asrc3, WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 6, + asrc3_mux_text); + +WCD_DAPM_ENUM(int1_1_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int2_1_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int3_1_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int4_1_native, SND_SOC_NOPM, 0, native_mux_text); + +WCD_DAPM_ENUM(int1_2_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int2_2_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int3_2_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int4_2_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int7_2_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(int8_2_native, SND_SOC_NOPM, 0, native_mux_text); + +WCD_DAPM_ENUM(anc0_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 0, anc0_fb_mux_text); +WCD_DAPM_ENUM(anc1_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 3, anc1_fb_mux_text); + +WCD_DAPM_ENUM_EXT(i2s_rx0, SND_SOC_NOPM, 0, i2s_rx01_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); +WCD_DAPM_ENUM_EXT(i2s_rx1, SND_SOC_NOPM, 0, i2s_rx01_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); +WCD_DAPM_ENUM_EXT(i2s_rx2, SND_SOC_NOPM, 0, i2s_rx23_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); +WCD_DAPM_ENUM_EXT(i2s_rx3, SND_SOC_NOPM, 0, i2s_rx23_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); +WCD_DAPM_ENUM_EXT(i2s_rx4, SND_SOC_NOPM, 0, i2s_rx45_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); +WCD_DAPM_ENUM_EXT(i2s_rx5, SND_SOC_NOPM, 0, i2s_rx45_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); +WCD_DAPM_ENUM_EXT(i2s_rx6, SND_SOC_NOPM, 0, i2s_rx67_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); +WCD_DAPM_ENUM_EXT(i2s_rx7, SND_SOC_NOPM, 0, i2s_rx67_mux_text, + i2s_rx_mux_get, i2s_rx_mux_put); + +WCD_DAPM_ENUM(wdma3_port0, WCD934X_DMA_WDMA3_PRT_CFG, 0, wdma3_port0_text); +WCD_DAPM_ENUM(wdma3_port1, WCD934X_DMA_WDMA3_PRT_CFG, 1, wdma3_port1_text); +WCD_DAPM_ENUM(wdma3_port2, WCD934X_DMA_WDMA3_PRT_CFG, 2, wdma3_port2_text); +WCD_DAPM_ENUM(wdma3_port3, WCD934X_DMA_WDMA3_PRT_CFG, 3, wdma3_port3_text); +WCD_DAPM_ENUM(wdma3_port4, WCD934X_DMA_WDMA3_PRT_CFG, 4, wdma3_port4_text); +WCD_DAPM_ENUM(wdma3_port5, WCD934X_DMA_WDMA3_PRT_CFG, 5, wdma3_port5_text); +WCD_DAPM_ENUM(wdma3_port6, WCD934X_DMA_WDMA3_PRT_CFG, 6, wdma3_port6_text); + +WCD_DAPM_ENUM(wdma3_ch0, WCD934X_DMA_CH_0_1_CFG_WDMA_3, 0, wdma3_ch_text); +WCD_DAPM_ENUM(wdma3_ch1, WCD934X_DMA_CH_0_1_CFG_WDMA_3, 4, wdma3_ch_text); +WCD_DAPM_ENUM(wdma3_ch2, WCD934X_DMA_CH_2_3_CFG_WDMA_3, 0, wdma3_ch_text); +WCD_DAPM_ENUM(wdma3_ch3, WCD934X_DMA_CH_2_3_CFG_WDMA_3, 4, wdma3_ch_text); + +static const struct snd_kcontrol_new anc_ear_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_ear_spkr_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_spkr_pa_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_hphl_pa_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_hphr_pa_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new mad_cpe1_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new mad_cpe2_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new mad_brdcst_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux0_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux1_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux2_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux3_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux4_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux5_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux6_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux7_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux8_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new rx_int1_asrc_switch[] = { + SOC_DAPM_SINGLE("HPHL Switch", SND_SOC_NOPM, 0, 1, 0), +}; + +static const struct snd_kcontrol_new rx_int2_asrc_switch[] = { + SOC_DAPM_SINGLE("HPHR Switch", SND_SOC_NOPM, 0, 1, 0), +}; + +static const struct snd_kcontrol_new rx_int3_asrc_switch[] = { + SOC_DAPM_SINGLE("LO1 Switch", SND_SOC_NOPM, 0, 1, 0), +}; + +static const struct snd_kcontrol_new rx_int4_asrc_switch[] = { + SOC_DAPM_SINGLE("LO2 Switch", SND_SOC_NOPM, 0, 1, 0), +}; + +static const struct snd_kcontrol_new wdma3_onoff_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_soc_dapm_widget tavil_dapm_i2s_widgets[] = { + + SND_SOC_DAPM_MUX_E("I2S RX0 MUX", SND_SOC_NOPM, WCD934X_RX0, 0, + &i2s_rx0_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("I2S RX1 MUX", SND_SOC_NOPM, WCD934X_RX1, 0, + &i2s_rx1_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("I2S RX2 MUX", SND_SOC_NOPM, WCD934X_RX2, 0, + &i2s_rx2_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("I2S RX3 MUX", SND_SOC_NOPM, WCD934X_RX3, 0, + &i2s_rx3_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("I2S RX4 MUX", SND_SOC_NOPM, WCD934X_RX4, 0, + &i2s_rx4_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("I2S RX5 MUX", SND_SOC_NOPM, WCD934X_RX5, 0, + &i2s_rx5_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("I2S RX6 MUX", SND_SOC_NOPM, WCD934X_RX6, 0, + &i2s_rx6_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("I2S RX7 MUX", SND_SOC_NOPM, WCD934X_RX7, 0, + &i2s_rx7_mux, tavil_codec_enable_i2s_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("I2S RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I2S RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I2S RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I2S RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I2S RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I2S RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I2S RX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I2S RX7", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER_E("I2S TX0", SND_SOC_NOPM, WCD934X_TX0, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX1", SND_SOC_NOPM, WCD934X_TX1, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX2", SND_SOC_NOPM, WCD934X_TX2, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX3", SND_SOC_NOPM, WCD934X_TX3, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX4", SND_SOC_NOPM, WCD934X_TX4, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX5", SND_SOC_NOPM, WCD934X_TX5, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX6", SND_SOC_NOPM, WCD934X_TX6, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX7", SND_SOC_NOPM, WCD934X_TX7, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX8", SND_SOC_NOPM, WCD934X_TX8, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("I2S TX11", SND_SOC_NOPM, WCD934X_TX11, 0, NULL, 0, + tavil_codec_enable_i2s_path, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_i2s_cap_mixer, ARRAY_SIZE(aif1_i2s_cap_mixer)), + SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0, + aif2_i2s_cap_mixer, ARRAY_SIZE(aif2_i2s_cap_mixer)), + SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, + aif3_i2s_cap_mixer, ARRAY_SIZE(aif3_i2s_cap_mixer)), +}; + +static int tavil_dsd_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct tavil_dsd_config *dsd_conf = tavil_p->dsd_config; + int val; + + val = tavil_dsd_get_current_mixer_value(dsd_conf, mc->shift); + + ucontrol->value.integer.value[0] = ((val < 0) ? 0 : val); + + return 0; +} + +static int tavil_dsd_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct tavil_priv *tavil_p = snd_soc_component_get_drvdata(component); + unsigned int wval = ucontrol->value.integer.value[0]; + struct tavil_dsd_config *dsd_conf = tavil_p->dsd_config; + + if (!dsd_conf) + return 0; + + mutex_lock(&tavil_p->codec_mutex); + + tavil_dsd_set_out_select(dsd_conf, mc->shift); + tavil_dsd_set_mixer_value(dsd_conf, mc->shift, wval); + + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mixer_update_power(dapm, kcontrol, wval, NULL); + + return 0; +} + +static const struct snd_kcontrol_new hphl_mixer[] = { + SOC_SINGLE_EXT("DSD HPHL Switch", SND_SOC_NOPM, INTERP_HPHL, 1, 0, + tavil_dsd_mixer_get, tavil_dsd_mixer_put), +}; + +static const struct snd_kcontrol_new hphr_mixer[] = { + SOC_SINGLE_EXT("DSD HPHR Switch", SND_SOC_NOPM, INTERP_HPHR, 1, 0, + tavil_dsd_mixer_get, tavil_dsd_mixer_put), +}; + +static const struct snd_kcontrol_new lo1_mixer[] = { + SOC_SINGLE_EXT("DSD LO1 Switch", SND_SOC_NOPM, INTERP_LO1, 1, 0, + tavil_dsd_mixer_get, tavil_dsd_mixer_put), +}; + +static const struct snd_kcontrol_new lo2_mixer[] = { + SOC_SINGLE_EXT("DSD LO2 Switch", SND_SOC_NOPM, INTERP_LO2, 1, 0, + tavil_dsd_mixer_get, tavil_dsd_mixer_put), +}; + +static const struct snd_soc_dapm_widget tavil_dapm_slim_widgets[] = { + SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM, + AIF4_PB, 0, tavil_codec_enable_rx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM, + AIF4_VIFEED, 0, + tavil_codec_enable_slimvi_feedback, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT("AIF4 MAD", "AIF4 MAD TX", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER("AIF4_VI Mixer", SND_SOC_NOPM, AIF4_VIFEED, 0, + aif4_vi_mixer, ARRAY_SIZE(aif4_vi_mixer)), + SND_SOC_DAPM_INPUT("VIINPUT"), + + WCD_DAPM_MUX("SLIM RX0 MUX", WCD934X_RX0, slim_rx0), + WCD_DAPM_MUX("SLIM RX1 MUX", WCD934X_RX1, slim_rx1), + WCD_DAPM_MUX("SLIM RX2 MUX", WCD934X_RX2, slim_rx2), + WCD_DAPM_MUX("SLIM RX3 MUX", WCD934X_RX3, slim_rx3), + WCD_DAPM_MUX("SLIM RX4 MUX", WCD934X_RX4, slim_rx4), + WCD_DAPM_MUX("SLIM RX5 MUX", WCD934X_RX5, slim_rx5), + WCD_DAPM_MUX("SLIM RX6 MUX", WCD934X_RX6, slim_rx6), + WCD_DAPM_MUX("SLIM RX7 MUX", WCD934X_RX7, slim_rx7), + + SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_slim_cap_mixer, + ARRAY_SIZE(aif1_slim_cap_mixer)), + SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0, + aif2_slim_cap_mixer, + ARRAY_SIZE(aif2_slim_cap_mixer)), + SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, + aif3_slim_cap_mixer, + ARRAY_SIZE(aif3_slim_cap_mixer)), + SND_SOC_DAPM_MIXER("AIF4_MAD Mixer", SND_SOC_NOPM, AIF4_MAD_TX, 0, + aif4_slim_mad_mixer, + ARRAY_SIZE(aif4_slim_mad_mixer)), +}; + +static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM, + AIF1_PB, 0, tavil_codec_enable_rx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM, + AIF2_PB, 0, tavil_codec_enable_rx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM, + AIF3_PB, 0, tavil_codec_enable_rx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + WCD_DAPM_MUX("CDC_IF RX0 MUX", WCD934X_RX0, cdc_if_rx0), + WCD_DAPM_MUX("CDC_IF RX1 MUX", WCD934X_RX1, cdc_if_rx1), + WCD_DAPM_MUX("CDC_IF RX2 MUX", WCD934X_RX2, cdc_if_rx2), + WCD_DAPM_MUX("CDC_IF RX3 MUX", WCD934X_RX3, cdc_if_rx3), + WCD_DAPM_MUX("CDC_IF RX4 MUX", WCD934X_RX4, cdc_if_rx4), + WCD_DAPM_MUX("CDC_IF RX5 MUX", WCD934X_RX5, cdc_if_rx5), + WCD_DAPM_MUX("CDC_IF RX6 MUX", WCD934X_RX6, cdc_if_rx6), + WCD_DAPM_MUX("CDC_IF RX7 MUX", WCD934X_RX7, cdc_if_rx7), + + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_EAR, 0, + &rx_int0_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int1_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int2_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", SND_SOC_NOPM, INTERP_LO1, 0, + &rx_int3_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", SND_SOC_NOPM, INTERP_LO2, 0, + &rx_int4_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", SND_SOC_NOPM, INTERP_SPKR1, 0, + &rx_int7_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", SND_SOC_NOPM, INTERP_SPKR2, 0, + &rx_int8_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + WCD_DAPM_MUX("RX INT0_1 MIX1 INP0", 0, rx_int0_1_mix_inp0), + WCD_DAPM_MUX("RX INT0_1 MIX1 INP1", 0, rx_int0_1_mix_inp1), + WCD_DAPM_MUX("RX INT0_1 MIX1 INP2", 0, rx_int0_1_mix_inp2), + WCD_DAPM_MUX("RX INT1_1 MIX1 INP0", 0, rx_int1_1_mix_inp0), + WCD_DAPM_MUX("RX INT1_1 MIX1 INP1", 0, rx_int1_1_mix_inp1), + WCD_DAPM_MUX("RX INT1_1 MIX1 INP2", 0, rx_int1_1_mix_inp2), + WCD_DAPM_MUX("RX INT2_1 MIX1 INP0", 0, rx_int2_1_mix_inp0), + WCD_DAPM_MUX("RX INT2_1 MIX1 INP1", 0, rx_int2_1_mix_inp1), + WCD_DAPM_MUX("RX INT2_1 MIX1 INP2", 0, rx_int2_1_mix_inp2), + WCD_DAPM_MUX("RX INT3_1 MIX1 INP0", 0, rx_int3_1_mix_inp0), + WCD_DAPM_MUX("RX INT3_1 MIX1 INP1", 0, rx_int3_1_mix_inp1), + WCD_DAPM_MUX("RX INT3_1 MIX1 INP2", 0, rx_int3_1_mix_inp2), + WCD_DAPM_MUX("RX INT4_1 MIX1 INP0", 0, rx_int4_1_mix_inp0), + WCD_DAPM_MUX("RX INT4_1 MIX1 INP1", 0, rx_int4_1_mix_inp1), + WCD_DAPM_MUX("RX INT4_1 MIX1 INP2", 0, rx_int4_1_mix_inp2), + + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp0_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp1_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp2_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp0_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp1_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp2_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, + rx_int1_asrc_switch, ARRAY_SIZE(rx_int1_asrc_switch)), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, + rx_int2_asrc_switch, ARRAY_SIZE(rx_int2_asrc_switch)), + SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, + rx_int3_asrc_switch, ARRAY_SIZE(rx_int3_asrc_switch)), + SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, + rx_int4_asrc_switch, ARRAY_SIZE(rx_int4_asrc_switch)), + SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX3", SND_SOC_NOPM, 0, 0, hphl_mixer, + ARRAY_SIZE(hphl_mixer)), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX3", SND_SOC_NOPM, 0, 0, hphr_mixer, + ARRAY_SIZE(hphr_mixer)), + SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 MIX3", SND_SOC_NOPM, 0, 0, lo1_mixer, + ARRAY_SIZE(lo1_mixer)), + SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 MIX3", SND_SOC_NOPM, 0, 0, lo2_mixer, + ARRAY_SIZE(lo2_mixer)), + SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, tavil_codec_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX INT8 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, tavil_codec_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", SND_SOC_NOPM, INTERP_EAR, + 0, &rx_int0_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", SND_SOC_NOPM, INTERP_HPHL, + 0, &rx_int1_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", SND_SOC_NOPM, INTERP_HPHR, + 0, &rx_int2_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3 MIX2 INP", SND_SOC_NOPM, INTERP_LO1, + 0, &rx_int3_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4 MIX2 INP", SND_SOC_NOPM, INTERP_LO2, + 0, &rx_int4_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7 MIX2 INP", SND_SOC_NOPM, INTERP_SPKR1, + 0, &rx_int7_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + WCD_DAPM_MUX("CDC_IF TX0 MUX", WCD934X_TX0, cdc_if_tx0), + WCD_DAPM_MUX("CDC_IF TX1 MUX", WCD934X_TX1, cdc_if_tx1), + WCD_DAPM_MUX("CDC_IF TX2 MUX", WCD934X_TX2, cdc_if_tx2), + WCD_DAPM_MUX("CDC_IF TX3 MUX", WCD934X_TX3, cdc_if_tx3), + WCD_DAPM_MUX("CDC_IF TX4 MUX", WCD934X_TX4, cdc_if_tx4), + WCD_DAPM_MUX("CDC_IF TX5 MUX", WCD934X_TX5, cdc_if_tx5), + WCD_DAPM_MUX("CDC_IF TX6 MUX", WCD934X_TX6, cdc_if_tx6), + WCD_DAPM_MUX("CDC_IF TX7 MUX", WCD934X_TX7, cdc_if_tx7), + WCD_DAPM_MUX("CDC_IF TX8 MUX", WCD934X_TX8, cdc_if_tx8), + WCD_DAPM_MUX("CDC_IF TX9 MUX", WCD934X_TX9, cdc_if_tx9), + WCD_DAPM_MUX("CDC_IF TX10 MUX", WCD934X_TX10, cdc_if_tx10), + WCD_DAPM_MUX("CDC_IF TX11 MUX", WCD934X_TX11, cdc_if_tx11), + WCD_DAPM_MUX("CDC_IF TX11 INP1 MUX", WCD934X_TX11, cdc_if_tx11_inp1), + WCD_DAPM_MUX("CDC_IF TX13 MUX", WCD934X_TX13, cdc_if_tx13), + WCD_DAPM_MUX("CDC_IF TX13 INP1 MUX", WCD934X_TX13, cdc_if_tx13_inp1), + + SND_SOC_DAPM_MUX_E("ADC MUX0", WCD934X_CDC_TX0_TX_PATH_CTL, 5, 0, + &tx_adc_mux0_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX1", WCD934X_CDC_TX1_TX_PATH_CTL, 5, 0, + &tx_adc_mux1_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX2", WCD934X_CDC_TX2_TX_PATH_CTL, 5, 0, + &tx_adc_mux2_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX3", WCD934X_CDC_TX3_TX_PATH_CTL, 5, 0, + &tx_adc_mux3_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX4", WCD934X_CDC_TX4_TX_PATH_CTL, 5, 0, + &tx_adc_mux4_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX5", WCD934X_CDC_TX5_TX_PATH_CTL, 5, 0, + &tx_adc_mux5_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX6", WCD934X_CDC_TX6_TX_PATH_CTL, 5, 0, + &tx_adc_mux6_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX7", WCD934X_CDC_TX7_TX_PATH_CTL, 5, 0, + &tx_adc_mux7_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX8", WCD934X_CDC_TX8_TX_PATH_CTL, 5, 0, + &tx_adc_mux8_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX10", SND_SOC_NOPM, 10, 0, &tx_adc_mux10_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX11", SND_SOC_NOPM, 11, 0, &tx_adc_mux11_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX12", SND_SOC_NOPM, 12, 0, &tx_adc_mux12_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX13", SND_SOC_NOPM, 13, 0, &tx_adc_mux13_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + WCD_DAPM_MUX("DMIC MUX0", 0, tx_dmic_mux0), + WCD_DAPM_MUX("DMIC MUX1", 0, tx_dmic_mux1), + WCD_DAPM_MUX("DMIC MUX2", 0, tx_dmic_mux2), + WCD_DAPM_MUX("DMIC MUX3", 0, tx_dmic_mux3), + WCD_DAPM_MUX("DMIC MUX4", 0, tx_dmic_mux4), + WCD_DAPM_MUX("DMIC MUX5", 0, tx_dmic_mux5), + WCD_DAPM_MUX("DMIC MUX6", 0, tx_dmic_mux6), + WCD_DAPM_MUX("DMIC MUX7", 0, tx_dmic_mux7), + WCD_DAPM_MUX("DMIC MUX8", 0, tx_dmic_mux8), + WCD_DAPM_MUX("DMIC MUX10", 0, tx_dmic_mux10), + WCD_DAPM_MUX("DMIC MUX11", 0, tx_dmic_mux11), + WCD_DAPM_MUX("DMIC MUX12", 0, tx_dmic_mux12), + WCD_DAPM_MUX("DMIC MUX13", 0, tx_dmic_mux13), + + WCD_DAPM_MUX("AMIC MUX0", 0, tx_amic_mux0), + WCD_DAPM_MUX("AMIC MUX1", 0, tx_amic_mux1), + WCD_DAPM_MUX("AMIC MUX2", 0, tx_amic_mux2), + WCD_DAPM_MUX("AMIC MUX3", 0, tx_amic_mux3), + WCD_DAPM_MUX("AMIC MUX4", 0, tx_amic_mux4), + WCD_DAPM_MUX("AMIC MUX5", 0, tx_amic_mux5), + WCD_DAPM_MUX("AMIC MUX6", 0, tx_amic_mux6), + WCD_DAPM_MUX("AMIC MUX7", 0, tx_amic_mux7), + WCD_DAPM_MUX("AMIC MUX8", 0, tx_amic_mux8), + WCD_DAPM_MUX("AMIC MUX10", 0, tx_amic_mux10), + WCD_DAPM_MUX("AMIC MUX11", 0, tx_amic_mux11), + WCD_DAPM_MUX("AMIC MUX12", 0, tx_amic_mux12), + WCD_DAPM_MUX("AMIC MUX13", 0, tx_amic_mux13), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD934X_ANA_AMIC1, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD934X_ANA_AMIC2, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD934X_ANA_AMIC3, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD934X_ANA_AMIC4, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + + WCD_DAPM_MUX("AMIC4_5 SEL", 0, tx_amic4_5), + + WCD_DAPM_MUX("ANC0 FB MUX", 0, anc0_fb), + WCD_DAPM_MUX("ANC1 FB MUX", 0, anc1_fb), + + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + /* + * Not supply widget, this is used to recover HPH registers. + * It is not connected to any other widgets + */ + SND_SOC_DAPM_SUPPLY("RESET_HPH_REGISTERS", SND_SOC_NOPM, + 0, 0, tavil_codec_reset_hph_registers, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS2_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS3_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM, + AIF1_CAP, 0, tavil_codec_enable_tx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM, + AIF2_CAP, 0, tavil_codec_enable_tx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM, + AIF3_CAP, 0, tavil_codec_enable_tx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("SLIM TX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX7", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX8", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX9", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX10", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX11", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX13", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + WCD_DAPM_MUX("IIR0 INP0 MUX", 0, iir0_inp0), + WCD_DAPM_MUX("IIR0 INP1 MUX", 0, iir0_inp1), + WCD_DAPM_MUX("IIR0 INP2 MUX", 0, iir0_inp2), + WCD_DAPM_MUX("IIR0 INP3 MUX", 0, iir0_inp3), + WCD_DAPM_MUX("IIR1 INP0 MUX", 0, iir1_inp0), + WCD_DAPM_MUX("IIR1 INP1 MUX", 0, iir1_inp1), + WCD_DAPM_MUX("IIR1 INP2 MUX", 0, iir1_inp2), + WCD_DAPM_MUX("IIR1 INP3 MUX", 0, iir1_inp3), + + SND_SOC_DAPM_MIXER_E("IIR0", WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL, + 4, 0, NULL, 0, tavil_codec_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER_E("IIR1", WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL, + 4, 0, NULL, 0, tavil_codec_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER("SRC0", WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SRC1", WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + + WCD_DAPM_MUX("RX MIX TX0 MUX", 0, rx_mix_tx0), + WCD_DAPM_MUX("RX MIX TX1 MUX", 0, rx_mix_tx1), + WCD_DAPM_MUX("RX MIX TX2 MUX", 0, rx_mix_tx2), + WCD_DAPM_MUX("RX MIX TX3 MUX", 0, rx_mix_tx3), + WCD_DAPM_MUX("RX MIX TX4 MUX", 0, rx_mix_tx4), + WCD_DAPM_MUX("RX MIX TX5 MUX", 0, rx_mix_tx5), + WCD_DAPM_MUX("RX MIX TX6 MUX", 0, rx_mix_tx6), + WCD_DAPM_MUX("RX MIX TX7 MUX", 0, rx_mix_tx7), + WCD_DAPM_MUX("RX MIX TX8 MUX", 0, rx_mix_tx8), + WCD_DAPM_MUX("RX INT0 DEM MUX", 0, rx_int0_dem_inp), + WCD_DAPM_MUX("RX INT1 DEM MUX", 0, rx_int1_dem_inp), + WCD_DAPM_MUX("RX INT2 DEM MUX", 0, rx_int2_dem_inp), + + SND_SOC_DAPM_MUX_E("RX INT0_1 INTERP", SND_SOC_NOPM, INTERP_EAR, 0, + &rx_int0_1_interp_mux, tavil_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1_1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int1_1_interp_mux, tavil_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2_1 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int2_1_interp_mux, tavil_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3_1 INTERP", SND_SOC_NOPM, INTERP_LO1, 0, + &rx_int3_1_interp_mux, tavil_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4_1 INTERP", SND_SOC_NOPM, INTERP_LO2, 0, + &rx_int4_1_interp_mux, tavil_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_1 INTERP", SND_SOC_NOPM, INTERP_SPKR1, 0, + &rx_int7_1_interp_mux, tavil_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 INTERP", SND_SOC_NOPM, INTERP_SPKR2, 0, + &rx_int8_1_interp_mux, tavil_codec_enable_main_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + WCD_DAPM_MUX("RX INT0_2 INTERP", 0, rx_int0_2_interp), + WCD_DAPM_MUX("RX INT1_2 INTERP", 0, rx_int1_2_interp), + WCD_DAPM_MUX("RX INT2_2 INTERP", 0, rx_int2_2_interp), + WCD_DAPM_MUX("RX INT3_2 INTERP", 0, rx_int3_2_interp), + WCD_DAPM_MUX("RX INT4_2 INTERP", 0, rx_int4_2_interp), + WCD_DAPM_MUX("RX INT7_2 INTERP", 0, rx_int7_2_interp), + WCD_DAPM_MUX("RX INT8_2 INTERP", 0, rx_int8_2_interp), + + SND_SOC_DAPM_SWITCH("ADC US MUX0", WCD934X_CDC_TX0_TX_PATH_192_CTL, 0, + 0, &adc_us_mux0_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX1", WCD934X_CDC_TX1_TX_PATH_192_CTL, 0, + 0, &adc_us_mux1_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX2", WCD934X_CDC_TX2_TX_PATH_192_CTL, 0, + 0, &adc_us_mux2_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX3", WCD934X_CDC_TX3_TX_PATH_192_CTL, 0, + 0, &adc_us_mux3_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX4", WCD934X_CDC_TX4_TX_PATH_192_CTL, 0, + 0, &adc_us_mux4_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX5", WCD934X_CDC_TX5_TX_PATH_192_CTL, 0, + 0, &adc_us_mux5_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX6", WCD934X_CDC_TX6_TX_PATH_192_CTL, 0, + 0, &adc_us_mux6_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX7", WCD934X_CDC_TX7_TX_PATH_192_CTL, 0, + 0, &adc_us_mux7_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX8", WCD934X_CDC_TX8_TX_PATH_192_CTL, 0, + 0, &adc_us_mux8_switch), + + /* MAD related widgets */ + SND_SOC_DAPM_INPUT("MAD_CPE_INPUT"), + SND_SOC_DAPM_INPUT("MADINPUT"), + + WCD_DAPM_MUX("MAD_SEL MUX", 0, mad_sel), + WCD_DAPM_MUX("MAD_INP MUX", 0, mad_inp_mux), + + SND_SOC_DAPM_SWITCH_E("MAD_BROADCAST", SND_SOC_NOPM, 0, 0, + &mad_brdcst_switch, tavil_codec_ape_enable_mad, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SWITCH_E("MAD_CPE1", SND_SOC_NOPM, 0, 0, + &mad_cpe1_switch, tavil_codec_cpe_mad_ctl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SWITCH_E("MAD_CPE2", SND_SOC_NOPM, 0, 0, + &mad_cpe2_switch, tavil_codec_cpe_mad_ctl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUTPUT("MAD_CPE_OUT1"), + SND_SOC_DAPM_OUTPUT("MAD_CPE_OUT2"), + + SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM, + 0, 0, tavil_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD934X_ANA_HPH, + 5, 0, tavil_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD934X_ANA_HPH, + 4, 0, tavil_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM, + 0, 0, tavil_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM, + 0, 0, tavil_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_PGA_E("EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0, + tavil_codec_enable_ear_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PA", WCD934X_ANA_HPH, 7, 0, NULL, 0, + tavil_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PA", WCD934X_ANA_HPH, 6, 0, NULL, 0, + tavil_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0, + tavil_codec_enable_lineout_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0, + tavil_codec_enable_lineout_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0, + tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC SPK1 PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tavil_codec_enable_spkr_anc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tavil_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tavil_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + SND_SOC_DAPM_OUTPUT("LINEOUT1"), + SND_SOC_DAPM_OUTPUT("LINEOUT2"), + SND_SOC_DAPM_OUTPUT("SPK1 OUT"), + SND_SOC_DAPM_OUTPUT("SPK2 OUT"), + SND_SOC_DAPM_OUTPUT("ANC EAR"), + SND_SOC_DAPM_OUTPUT("ANC HPHL"), + SND_SOC_DAPM_OUTPUT("ANC HPHR"), + + SND_SOC_DAPM_SWITCH("ANC OUT EAR Enable", SND_SOC_NOPM, 0, 0, + &anc_ear_switch), + SND_SOC_DAPM_SWITCH("ANC OUT EAR SPKR Enable", SND_SOC_NOPM, 0, 0, + &anc_ear_spkr_switch), + SND_SOC_DAPM_SWITCH("ANC SPKR PA Enable", SND_SOC_NOPM, 0, 0, + &anc_spkr_pa_switch), + + SND_SOC_DAPM_SWITCH_E("ANC OUT HPHL Enable", SND_SOC_NOPM, INTERP_HPHL, + 0, &anc_hphl_pa_switch, tavil_anc_out_switch_cb, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SWITCH_E("ANC OUT HPHR Enable", SND_SOC_NOPM, INTERP_HPHR, + 0, &anc_hphr_pa_switch, tavil_anc_out_switch_cb, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_rx_bias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("RX INT1 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_HPHL, 0, tavil_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("RX INT2 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_HPHR, 0, tavil_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("RX INT3 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_LO1, 0, tavil_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("RX INT4 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_LO2, 0, tavil_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("RX INT7 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_SPKR1, 0, tavil_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("RX INT8 NATIVE SUPPLY", SND_SOC_NOPM, + INTERP_SPKR2, 0, tavil_enable_native_supply, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + WCD_DAPM_MUX("RX INT1_1 NATIVE MUX", 0, int1_1_native), + WCD_DAPM_MUX("RX INT2_1 NATIVE MUX", 0, int2_1_native), + WCD_DAPM_MUX("RX INT3_1 NATIVE MUX", 0, int3_1_native), + WCD_DAPM_MUX("RX INT4_1 NATIVE MUX", 0, int4_1_native), + + WCD_DAPM_MUX("RX INT1_2 NATIVE MUX", 0, int1_2_native), + WCD_DAPM_MUX("RX INT2_2 NATIVE MUX", 0, int2_2_native), + WCD_DAPM_MUX("RX INT3_2 NATIVE MUX", 0, int3_2_native), + WCD_DAPM_MUX("RX INT4_2 NATIVE MUX", 0, int4_2_native), + WCD_DAPM_MUX("RX INT7_2 NATIVE MUX", 0, int7_2_native), + WCD_DAPM_MUX("RX INT8_2 NATIVE MUX", 0, int8_2_native), + + SND_SOC_DAPM_MUX_E("ASRC0 MUX", SND_SOC_NOPM, ASRC0, 0, + &asrc0_mux, tavil_codec_enable_asrc_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("ASRC1 MUX", SND_SOC_NOPM, ASRC1, 0, + &asrc1_mux, tavil_codec_enable_asrc_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("ASRC2 MUX", SND_SOC_NOPM, ASRC2, 0, + &asrc2_mux, tavil_codec_enable_asrc_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("ASRC3 MUX", SND_SOC_NOPM, ASRC3, 0, + &asrc3_mux, tavil_codec_enable_asrc_resampler, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* WDMA3 widgets */ + WCD_DAPM_MUX("WDMA3 PORT0 MUX", 0, wdma3_port0), + WCD_DAPM_MUX("WDMA3 PORT1 MUX", 1, wdma3_port1), + WCD_DAPM_MUX("WDMA3 PORT2 MUX", 2, wdma3_port2), + WCD_DAPM_MUX("WDMA3 PORT3 MUX", 3, wdma3_port3), + WCD_DAPM_MUX("WDMA3 PORT4 MUX", 4, wdma3_port4), + WCD_DAPM_MUX("WDMA3 PORT5 MUX", 5, wdma3_port5), + WCD_DAPM_MUX("WDMA3 PORT6 MUX", 6, wdma3_port6), + + WCD_DAPM_MUX("WDMA3 CH0 MUX", 0, wdma3_ch0), + WCD_DAPM_MUX("WDMA3 CH1 MUX", 4, wdma3_ch1), + WCD_DAPM_MUX("WDMA3 CH2 MUX", 0, wdma3_ch2), + WCD_DAPM_MUX("WDMA3 CH3 MUX", 4, wdma3_ch3), + + SND_SOC_DAPM_MIXER("WDMA3_CH_MIXER", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH_E("WDMA3_ON_OFF", SND_SOC_NOPM, 0, 0, + &wdma3_onoff_switch, tavil_codec_wdma3_ctl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_OUTPUT("WDMA3_OUT"), +}; + +static int tavil_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct tavil_priv *tavil = + snd_soc_component_get_drvdata(dai->component); + u32 i = 0; + struct wcd9xxx_ch *ch; + int ret = 0; + + switch (dai->id) { + case AIF1_PB: + case AIF2_PB: + case AIF3_PB: + case AIF4_PB: + if (!rx_slot || !rx_num) { + dev_err(tavil->dev, "%s: Invalid rx_slot 0x%pK or rx_num 0x%pK\n", + __func__, rx_slot, rx_num); + ret = -EINVAL; + break; + } + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, + list) { + dev_dbg(tavil->dev, "%s: slot_num %u ch->ch_num %d\n", + __func__, i, ch->ch_num); + rx_slot[i++] = ch->ch_num; + } + *rx_num = i; + dev_dbg(tavil->dev, "%s: dai_name = %s dai_id = %x rx_num = %d\n", + __func__, dai->name, dai->id, i); + if (*rx_num == 0) { + dev_err(tavil->dev, "%s: Channel list empty for dai_name = %s dai_id = %x\n", + __func__, dai->name, dai->id); + ret = -EINVAL; + } + break; + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + case AIF4_MAD_TX: + case AIF4_VIFEED: + if (!tx_slot || !tx_num) { + dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK or tx_num 0x%pK\n", + __func__, tx_slot, tx_num); + ret = -EINVAL; + break; + } + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, + list) { + dev_dbg(tavil->dev, "%s: slot_num %u ch->ch_num %d\n", + __func__, i, ch->ch_num); + tx_slot[i++] = ch->ch_num; + } + *tx_num = i; + dev_dbg(tavil->dev, "%s: dai_name = %s dai_id = %x tx_num = %d\n", + __func__, dai->name, dai->id, i); + if (*tx_num == 0) { + dev_err(tavil->dev, "%s: Channel list empty for dai_name = %s dai_id = %x\n", + __func__, dai->name, dai->id); + ret = -EINVAL; + } + break; + default: + dev_err(tavil->dev, "%s: Invalid DAI ID %x\n", + __func__, dai->id); + ret = -EINVAL; + break; + } + + return ret; +} + +static int tavil_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct tavil_priv *tavil; + struct wcd9xxx *core; + struct wcd9xxx_codec_dai_data *dai_data = NULL; + + tavil = snd_soc_component_get_drvdata(dai->component); + core = dev_get_drvdata(dai->component->dev->parent); + + if (!tx_slot || !rx_slot) { + dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK, rx_slot 0x%pK\n", + __func__, tx_slot, rx_slot); + return -EINVAL; + } + dev_dbg(tavil->dev, "%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n", + __func__, dai->name, dai->id, tx_num, rx_num); + + wcd9xxx_init_slimslave(core, core->slim->laddr, + tx_num, tx_slot, rx_num, rx_slot); + /* Reserve TX13 for MAD data channel */ + dai_data = &tavil->dai[AIF4_MAD_TX]; + if (dai_data) + list_add_tail(&core->tx_chs[WCD934X_TX13].list, + &dai_data->wcd9xxx_ch_list); + + return 0; +} + +static int tavil_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + return 0; +} + +static void tavil_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); +} + +static int tavil_set_decimator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_component *component = dai->component; + struct wcd9xxx_ch *ch; + struct tavil_priv *tavil = + snd_soc_component_get_drvdata(component); + u32 tx_port = 0, tx_fs_rate = 0; + u8 shift = 0, shift_val = 0, tx_mux_sel = 0; + int decimator = -1; + u16 tx_port_reg = 0, tx_fs_reg = 0; + + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + default: + dev_err(tavil->dev, "%s: Invalid TX sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + + }; + + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) { + tx_port = ch->port; + dev_dbg(component->dev, "%s: dai->id = %d, tx_port = %d", + __func__, dai->id, tx_port); + + if ((tx_port < 0) || (tx_port == 12) || (tx_port >= 14)) { + dev_err(component->dev, "%s: Invalid SLIM TX%u port. DAI ID: %d\n", + __func__, tx_port, dai->id); + return -EINVAL; + } + /* Find the SB TX MUX input - which decimator is connected */ + if (tx_port < 4) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0; + shift = (tx_port << 1); + shift_val = 0x03; + } else if ((tx_port >= 4) && (tx_port < 8)) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1; + shift = ((tx_port - 4) << 1); + shift_val = 0x03; + } else if ((tx_port >= 8) && (tx_port < 11)) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2; + shift = ((tx_port - 8) << 1); + shift_val = 0x03; + } else if (tx_port == 11) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 0; + shift_val = 0x0F; + } else if (tx_port == 13) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 4; + shift_val = 0x03; + } + tx_mux_sel = snd_soc_component_read32(component, tx_port_reg) & + (shift_val << shift); + tx_mux_sel = tx_mux_sel >> shift; + + if (tx_port <= 8) { + if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3)) + decimator = tx_port; + } else if (tx_port <= 10) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = ((tx_port == 9) ? 7 : 6); + } else if (tx_port == 11) { + if ((tx_mux_sel >= 1) && (tx_mux_sel < 7)) + decimator = tx_mux_sel - 1; + } else if (tx_port == 13) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = 5; + } + + if (decimator >= 0) { + tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL + + 16 * decimator; + dev_dbg(component->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n", + __func__, decimator, tx_port, sample_rate); + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, tx_fs_rate); + } else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) { + /* Check if the TX Mux input is RX MIX TXn */ + dev_dbg(component->dev, "%s: RX_MIX_TX%u going to CDC_IF TX%u\n", + __func__, tx_port, tx_port); + } else { + dev_err(component->dev, "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int tavil_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp; + u32 j; + u16 int_mux_cfg1, int_fs_reg; + u8 int_mux_cfg1_val; + struct snd_soc_component *component = dai->component; + struct wcd9xxx_ch *ch; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) { + int_2_inp = INTn_2_INP_SEL_RX0 + ch->port - + WCD934X_RX_PORT_START_NUMBER; + if ((int_2_inp < INTn_2_INP_SEL_RX0) || + (int_2_inp > INTn_2_INP_SEL_RX7)) { + dev_err(component->dev, "%s: Invalid RX%u port, Dai ID is %d\n", + __func__, + (ch->port - WCD934X_RX_PORT_START_NUMBER), + dai->id); + return -EINVAL; + } + + int_mux_cfg1 = WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) { + /* Interpolators 5 and 6 are not aviliable in Tavil */ + if (j == INTERP_LO3_NA || j == INTERP_LO4_NA) { + int_mux_cfg1 += 2; + continue; + } + int_mux_cfg1_val = snd_soc_component_read32(component, + int_mux_cfg1) & 0x0F; + if (int_mux_cfg1_val == int_2_inp) { + /* + * Ear mix path supports only 48, 96, 192, + * 384KHz only + */ + if ((j == INTERP_EAR) && + (rate_reg_val < 0x4 || + rate_reg_val > 0x7)) { + dev_err_ratelimited(component->dev, + "%s: Invalid rate for AIF_PB DAI(%d)\n", + __func__, dai->id); + return -EINVAL; + } + + int_fs_reg = WCD934X_CDC_RX0_RX_PATH_MIX_CTL + + 20 * j; + dev_dbg(component->dev, "%s: AIF_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + dev_dbg(component->dev, "%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits(component, + int_fs_reg, 0x0F, rate_reg_val); + } + int_mux_cfg1 += 2; + } + } + return 0; +} + +static int tavil_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp; + u32 j; + u16 int_mux_cfg0, int_mux_cfg1; + u16 int_fs_reg; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 inp0_sel, inp1_sel, inp2_sel; + struct snd_soc_component *component = dai->component; + struct wcd9xxx_ch *ch; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + struct tavil_dsd_config *dsd_conf = tavil->dsd_config; + + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) { + int_1_mix1_inp = INTn_1_INP_SEL_RX0 + ch->port - + WCD934X_RX_PORT_START_NUMBER; + if ((int_1_mix1_inp < INTn_1_INP_SEL_RX0) || + (int_1_mix1_inp > INTn_1_INP_SEL_RX7)) { + dev_err(component->dev, "%s: Invalid RX%u port, Dai ID is %d\n", + __func__, + (ch->port - WCD934X_RX_PORT_START_NUMBER), + dai->id); + return -EINVAL; + } + + int_mux_cfg0 = WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the slim rx port + * is connected + */ + for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) { + /* Interpolators 5 and 6 are not aviliable in Tavil */ + if (j == INTERP_LO3_NA || j == INTERP_LO4_NA) { + int_mux_cfg0 += 2; + continue; + } + int_mux_cfg1 = int_mux_cfg0 + 1; + + int_mux_cfg0_val = snd_soc_component_read32( + component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read32( + component, int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & 0x0F; + inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F; + inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F; + if ((inp0_sel == int_1_mix1_inp) || + (inp1_sel == int_1_mix1_inp) || + (inp2_sel == int_1_mix1_inp)) { + /* + * Ear and speaker primary path does not support + * native sample rates + */ + if ((j == INTERP_EAR || j == INTERP_SPKR1 || + j == INTERP_SPKR2) && + (rate_reg_val > 0x7)) { + dev_err_ratelimited(component->dev, + "%s: Invalid rate for AIF_PB DAI(%d)\n", + __func__, dai->id); + return -EINVAL; + } + + int_fs_reg = WCD934X_CDC_RX0_RX_PATH_CTL + + 20 * j; + dev_dbg(component->dev, + "%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + dev_dbg(component->dev, + "%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_component_update_bits(component, + int_fs_reg, 0x0F, rate_reg_val); + } + int_mux_cfg0 += 2; + } + if (dsd_conf) + tavil_dsd_set_interp_rate(dsd_conf, ch->port, + sample_rate, rate_reg_val); + } + + return 0; +} + + +static int tavil_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_component *component = dai->component; + int rate_val = 0; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) { + if (sample_rate == sr_val_tbl[i].sample_rate) { + rate_val = sr_val_tbl[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) { + dev_err(component->dev, "%s: Unsupported sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + } + + ret = tavil_set_prim_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + ret = tavil_set_mix_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + + return ret; +} + +static int tavil_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + return 0; +} + +static int tavil_vi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tavil_priv *tavil = + snd_soc_component_get_drvdata(dai->component); + + dev_dbg(tavil->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", + __func__, dai->name, dai->id, params_rate(params), + params_channels(params)); + + tavil->dai[dai->id].rate = params_rate(params); + tavil->dai[dai->id].bit_width = 32; + + return 0; +} + +static int tavil_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tavil_priv *tavil = + snd_soc_component_get_drvdata(dai->component); + int ret = 0; + + dev_dbg(tavil->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", + __func__, dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = tavil_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(tavil->dev, "%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16: + tavil->dai[dai->id].bit_width = 16; + break; + case 24: + tavil->dai[dai->id].bit_width = 24; + break; + case 32: + tavil->dai[dai->id].bit_width = 32; + break; + default: + return -EINVAL; + } + tavil->dai[dai->id].rate = params_rate(params); + break; + case SNDRV_PCM_STREAM_CAPTURE: + if (dai->id != AIF4_MAD_TX) + ret = tavil_set_decimator_rate(dai, + params_rate(params)); + if (ret) { + dev_err(tavil->dev, "%s: cannot set TX Decimator rate: %d\n", + __func__, ret); + return ret; + } + switch (params_width(params)) { + case 16: + tavil->dai[dai->id].bit_width = 16; + break; + case 24: + tavil->dai[dai->id].bit_width = 24; + break; + default: + dev_err(tavil->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + }; + tavil->dai[dai->id].rate = params_rate(params); + break; + default: + dev_err(tavil->dev, "%s: Invalid stream type %d\n", __func__, + substream->stream); + return -EINVAL; + }; + + return 0; +} + +static int tavil_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + u32 i2s_reg; + + switch (dai->id) { + case AIF1_PB: + case AIF1_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_0_CTL; + break; + case AIF2_PB: + case AIF2_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_1_CTL; + break; + case AIF3_PB: + case AIF3_CAP: + i2s_reg = WCD934X_DATA_HUB_I2S_2_CTL; + break; + default: + dev_err(dai->component->dev, "%s Invalid i2s Id", __func__); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* CPU is master */ + snd_soc_component_update_bits(dai->component, i2s_reg, + 0x2, 0x0); + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* CPU is slave */ + snd_soc_component_update_bits(dai->component, i2s_reg, + 0x2, 0x2); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct snd_soc_dai_ops tavil_dai_ops = { + .startup = tavil_startup, + .shutdown = tavil_shutdown, + .hw_params = tavil_hw_params, + .prepare = tavil_prepare, + .set_channel_map = tavil_set_channel_map, + .get_channel_map = tavil_get_channel_map, +}; + +static struct snd_soc_dai_ops tavil_i2s_dai_ops = { + .startup = tavil_startup, + .shutdown = tavil_shutdown, + .hw_params = tavil_hw_params, + .prepare = tavil_prepare, + .set_fmt = tavil_set_dai_fmt, +}; + +static struct snd_soc_dai_ops tavil_vi_dai_ops = { + .hw_params = tavil_vi_hw_params, + .set_channel_map = tavil_set_channel_map, + .get_channel_map = tavil_get_channel_map, +}; + +static struct snd_soc_dai_driver tavil_slim_dai[] = { + { + .name = "tavil_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_rx3", + .id = AIF3_PB, + .playback = { + .stream_name = "AIF3 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_tx3", + .id = AIF3_CAP, + .capture = { + .stream_name = "AIF3 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_rx4", + .id = AIF4_PB, + .playback = { + .stream_name = "AIF4 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_vifeedback", + .id = AIF4_VIFEED, + .capture = { + .stream_name = "VIfeed", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_vi_dai_ops, + }, + { + .name = "tavil_mad1", + .id = AIF4_MAD_TX, + .capture = { + .stream_name = "AIF4 MAD TX", + .rates = SNDRV_PCM_RATE_16000, + .formats = WCD934X_FORMATS_S16_LE, + .rate_min = 16000, + .rate_max = 16000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &tavil_dai_ops, + }, +}; + +static struct snd_soc_dai_driver tavil_i2s_dai[] = { + { + .name = "tavil_i2s_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_i2s_dai_ops, + }, + { + .name = "tavil_i2s_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_i2s_dai_ops, + }, + { + .name = "tavil_i2s_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_i2s_dai_ops, + }, + { + .name = "tavil_i2s_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_i2s_dai_ops, + }, + { + .name = "tavil_i2s_rx3", + .id = AIF3_PB, + .playback = { + .stream_name = "AIF3 Playback", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_i2s_dai_ops, + }, + { + .name = "tavil_i2s_tx3", + .id = AIF3_CAP, + .capture = { + .stream_name = "AIF3 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_i2s_dai_ops, + }, +}; + +static void tavil_codec_power_gate_digital_core(struct tavil_priv *tavil) +{ + if (!tavil) + return; + mutex_lock(&tavil->power_lock); + dev_dbg(tavil->dev, "%s: Entering power gating function, %d\n", + __func__, tavil->power_active_ref); + + if (tavil->power_active_ref > 0) + goto exit; + + wcd9xxx_set_power_state(tavil->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_BEGIN, + WCD9XXX_DIG_CORE_REGION_1); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04, 0x04); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x01, 0x00); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x02, 0x00); + wcd9xxx_set_power_state(tavil->wcd9xxx, WCD_REGION_POWER_DOWN, + WCD9XXX_DIG_CORE_REGION_1); +exit: + dev_dbg(tavil->dev, "%s: Exiting power gating function, %d\n", + __func__, tavil->power_active_ref); + mutex_unlock(&tavil->power_lock); +} + +static void tavil_codec_power_gate_work(struct work_struct *work) +{ + struct tavil_priv *tavil; + struct delayed_work *dwork; + + dwork = to_delayed_work(work); + tavil = container_of(dwork, struct tavil_priv, power_gate_work); + + tavil_codec_power_gate_digital_core(tavil); +} + +/* called under power_lock acquisition */ +static int tavil_dig_core_remove_power_collapse(struct tavil_priv *tavil) +{ + regmap_write(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x05); + regmap_write(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x07); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02); + regmap_write(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x03); + + wcd9xxx_set_power_state(tavil->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_REMOVE, + WCD9XXX_DIG_CORE_REGION_1); + regcache_mark_dirty(tavil->wcd9xxx->regmap); + regcache_sync_region(tavil->wcd9xxx->regmap, + WCD934X_DIG_CORE_REG_MIN, + WCD934X_DIG_CORE_REG_MAX); + + return 0; +} + +static int tavil_dig_core_power_collapse(struct tavil_priv *tavil, + int req_state) +{ + int cur_state; + + /* Exit if feature is disabled */ + if (!dig_core_collapse_enable) + return 0; + + mutex_lock(&tavil->power_lock); + if (req_state == POWER_COLLAPSE) + tavil->power_active_ref--; + else if (req_state == POWER_RESUME) + tavil->power_active_ref++; + else + goto unlock_mutex; + + if (tavil->power_active_ref < 0) { + dev_dbg(tavil->dev, + "%s: power_active_ref is negative, reset it\n", + __func__); + tavil->power_active_ref = 0; + goto unlock_mutex; + } + + if (req_state == POWER_COLLAPSE) { + if (tavil->power_active_ref == 0) { + schedule_delayed_work(&tavil->power_gate_work, + msecs_to_jiffies(dig_core_collapse_timer * 1000)); + } + } else if (req_state == POWER_RESUME) { + if (tavil->power_active_ref == 1) { + /* + * At this point, there can be two cases: + * 1. Core already in power collapse state + * 2. Timer kicked in and still did not expire or + * waiting for the power_lock + */ + cur_state = wcd9xxx_get_current_power_state( + tavil->wcd9xxx, + WCD9XXX_DIG_CORE_REGION_1); + if (cur_state == WCD_REGION_POWER_DOWN) { + tavil_dig_core_remove_power_collapse(tavil); + } else { + mutex_unlock(&tavil->power_lock); + cancel_delayed_work_sync( + &tavil->power_gate_work); + mutex_lock(&tavil->power_lock); + } + } + } + +unlock_mutex: + mutex_unlock(&tavil->power_lock); + + return 0; +} + +static int tavil_cdc_req_mclk_enable(struct tavil_priv *tavil, + bool enable) +{ + int ret = 0; + + if (enable) { + ret = clk_prepare_enable(tavil->wcd_ext_clk); + if (ret) { + dev_err(tavil->dev, "%s: ext clk enable failed\n", + __func__); + goto done; + } + /* get BG */ + wcd_resmgr_enable_master_bias(tavil->resmgr); + /* get MCLK */ + wcd_resmgr_enable_clk_block(tavil->resmgr, WCD_CLK_MCLK); + } else { + /* put MCLK */ + wcd_resmgr_disable_clk_block(tavil->resmgr, WCD_CLK_MCLK); + /* put BG */ + wcd_resmgr_disable_master_bias(tavil->resmgr); + clk_disable_unprepare(tavil->wcd_ext_clk); + } + +done: + return ret; +} + +static int __tavil_cdc_mclk_enable_locked(struct tavil_priv *tavil, + bool enable) +{ + int ret = 0; + + if (!tavil->wcd_ext_clk) { + dev_err(tavil->dev, "%s: wcd ext clock is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(tavil->dev, "%s: mclk_enable = %u\n", __func__, enable); + + if (enable) { + tavil_dig_core_power_collapse(tavil, POWER_RESUME); + tavil_vote_svs(tavil, true); + ret = tavil_cdc_req_mclk_enable(tavil, true); + if (ret) + goto done; + } else { + tavil_cdc_req_mclk_enable(tavil, false); + tavil_vote_svs(tavil, false); + tavil_dig_core_power_collapse(tavil, POWER_COLLAPSE); + } + +done: + return ret; +} + +static int __tavil_cdc_mclk_enable(struct tavil_priv *tavil, + bool enable) +{ + int ret; + + WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr); + ret = __tavil_cdc_mclk_enable_locked(tavil, enable); + if (enable) + wcd_resmgr_set_sido_input_src(tavil->resmgr, + SIDO_SOURCE_RCO_BG); + WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr); + + return ret; +} + +static ssize_t tavil_codec_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct tavil_priv *tavil; + struct wcd9xxx *wcd9xxx; + char buffer[TAVIL_VERSION_ENTRY_SIZE]; + int len = 0; + + tavil = (struct tavil_priv *) entry->private_data; + if (!tavil) { + pr_err("%s: tavil priv is null\n", __func__); + return -EINVAL; + } + + wcd9xxx = tavil->wcd9xxx; + + switch (wcd9xxx->version) { + case TAVIL_VERSION_WCD9340_1_0: + len = snprintf(buffer, sizeof(buffer), "WCD9340_1_0\n"); + break; + case TAVIL_VERSION_WCD9341_1_0: + len = snprintf(buffer, sizeof(buffer), "WCD9341_1_0\n"); + break; + case TAVIL_VERSION_WCD9340_1_1: + len = snprintf(buffer, sizeof(buffer), "WCD9340_1_1\n"); + break; + case TAVIL_VERSION_WCD9341_1_1: + len = snprintf(buffer, sizeof(buffer), "WCD9341_1_1\n"); + break; + default: + len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + } + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static struct snd_info_entry_ops tavil_codec_info_ops = { + .read = tavil_codec_version_read, +}; + +/* + * tavil_codec_info_create_codec_entry - creates wcd934x module + * @codec_root: The parent directory + * @component: Codec component instance + * + * Creates wcd934x module and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int tavil_codec_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct tavil_priv *tavil; + struct snd_soc_card *card; + + if (!codec_root || !component) + return -EINVAL; + + tavil = snd_soc_component_get_drvdata(component); + card = component->card; + tavil->entry = snd_info_create_module_entry(codec_root->module, + "tavil", codec_root); + if (!tavil->entry) { + dev_dbg(component->dev, "%s: failed to create wcd934x entry\n", + __func__); + return -ENOMEM; + } + + version_entry = snd_info_create_card_entry(card->snd_card, + "version", + tavil->entry); + if (!version_entry) { + dev_dbg(component->dev, "%s: failed to create wcd934x version entry\n", + __func__); + return -ENOMEM; + } + + version_entry->private_data = tavil; + version_entry->size = TAVIL_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &tavil_codec_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + return -ENOMEM; + } + tavil->version_entry = version_entry; + + return 0; +} +EXPORT_SYMBOL(tavil_codec_info_create_codec_entry); + +/** + * tavil_cdc_mclk_enable - Enable/disable codec mclk + * + * @component: codec component instance + * @enable: Indicates clk enable or disable + * + * Returns 0 on Success and error on failure + */ +int tavil_cdc_mclk_enable(struct snd_soc_component *component, bool enable) +{ + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + return __tavil_cdc_mclk_enable(tavil, enable); +} +EXPORT_SYMBOL(tavil_cdc_mclk_enable); + +static int __tavil_codec_internal_rco_ctrl(struct snd_soc_component *component, + bool enable) +{ + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int ret = 0; + + if (enable) { + if (wcd_resmgr_get_clk_type(tavil->resmgr) == + WCD_CLK_RCO) { + ret = wcd_resmgr_enable_clk_block(tavil->resmgr, + WCD_CLK_RCO); + } else { + ret = tavil_cdc_req_mclk_enable(tavil, true); + if (ret) { + dev_err(component->dev, + "%s: mclk_enable failed, err = %d\n", + __func__, ret); + goto done; + } + wcd_resmgr_set_sido_input_src(tavil->resmgr, + SIDO_SOURCE_RCO_BG); + ret = wcd_resmgr_enable_clk_block(tavil->resmgr, + WCD_CLK_RCO); + ret |= tavil_cdc_req_mclk_enable(tavil, false); + } + + } else { + ret = wcd_resmgr_disable_clk_block(tavil->resmgr, + WCD_CLK_RCO); + } + + if (ret) { + dev_err(component->dev, "%s: Error in %s RCO\n", + __func__, (enable ? "enabling" : "disabling")); + ret = -EINVAL; + } + +done: + return ret; +} + +/* + * tavil_codec_internal_rco_ctrl: Enable/Disable codec's RCO clock + * @component: Handle to the codec + * @enable: Indicates whether clock should be enabled or disabled + */ +static int tavil_codec_internal_rco_ctrl(struct snd_soc_component *component, + bool enable) +{ + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + int ret = 0; + + WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr); + ret = __tavil_codec_internal_rco_ctrl(component, enable); + WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr); + return ret; +} + +/* + * tavil_cdc_mclk_tx_enable: Enable/Disable codec's clock for TX path + * @component: Handle to codec + * @enable: Indicates whether clock should be enabled or disabled + */ +int tavil_cdc_mclk_tx_enable(struct snd_soc_component *component, bool enable) +{ + struct tavil_priv *tavil_p; + int ret = 0; + bool clk_mode; + bool clk_internal; + + if (!component) + return -EINVAL; + + tavil_p = snd_soc_component_get_drvdata(component); + clk_mode = test_bit(CLK_MODE, &tavil_p->status_mask); + clk_internal = test_bit(CLK_INTERNAL, &tavil_p->status_mask); + + dev_dbg(component->dev, "%s: clkmode: %d, enable: %d, clk_internal: %d\n", + __func__, clk_mode, enable, clk_internal); + + if (clk_mode || clk_internal) { + if (enable) { + wcd_resmgr_enable_master_bias(tavil_p->resmgr); + tavil_dig_core_power_collapse(tavil_p, POWER_RESUME); + tavil_vote_svs(tavil_p, true); + ret = tavil_codec_internal_rco_ctrl(component, enable); + set_bit(CLK_INTERNAL, &tavil_p->status_mask); + } else { + clear_bit(CLK_INTERNAL, &tavil_p->status_mask); + tavil_codec_internal_rco_ctrl(component, enable); + tavil_vote_svs(tavil_p, false); + tavil_dig_core_power_collapse(tavil_p, POWER_COLLAPSE); + wcd_resmgr_disable_master_bias(tavil_p->resmgr); + } + } else { + ret = __tavil_cdc_mclk_enable(tavil_p, enable); + } + + return ret; +} +EXPORT_SYMBOL(tavil_cdc_mclk_tx_enable); + +static const struct wcd_resmgr_cb tavil_resmgr_cb = { + .cdc_rco_ctrl = __tavil_codec_internal_rco_ctrl, +}; + +static const struct tavil_reg_mask_val tavil_codec_mclk2_1_1_defaults[] = { + {WCD934X_CLK_SYS_MCLK2_PRG1, 0x60, 0x20}, +}; + +static const struct tavil_reg_mask_val tavil_codec_mclk2_1_0_defaults[] = { + /* + * PLL Settings: + * Clock Root: MCLK2, + * Clock Source: EXT_CLK, + * Clock Destination: MCLK2 + * Clock Freq In: 19.2MHz, + * Clock Freq Out: 11.2896MHz + */ + {WCD934X_CLK_SYS_MCLK2_PRG1, 0x60, 0x20}, + {WCD934X_CLK_SYS_INT_POST_DIV_REG0, 0xFF, 0x5E}, + {WCD934X_CLK_SYS_INT_POST_DIV_REG1, 0x1F, 0x1F}, + {WCD934X_CLK_SYS_INT_REF_DIV_REG0, 0xFF, 0x54}, + {WCD934X_CLK_SYS_INT_REF_DIV_REG1, 0xFF, 0x01}, + {WCD934X_CLK_SYS_INT_FILTER_REG1, 0x07, 0x04}, + {WCD934X_CLK_SYS_INT_PLL_L_VAL, 0xFF, 0x93}, + {WCD934X_CLK_SYS_INT_PLL_N_VAL, 0xFF, 0xFA}, + {WCD934X_CLK_SYS_INT_TEST_REG0, 0xFF, 0x90}, + {WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG, 0xFF, 0x7E}, + {WCD934X_CLK_SYS_INT_VCO_PROG, 0xFF, 0xF8}, + {WCD934X_CLK_SYS_INT_TEST_REG1, 0xFF, 0x68}, + {WCD934X_CLK_SYS_INT_LDO_LOCK_CFG, 0xFF, 0x40}, + {WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG, 0xFF, 0x32}, +}; + +static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = { + {WCD934X_BIAS_VBG_FINE_ADJ, 0xFF, 0x75}, + {WCD934X_CODEC_CPR_SVS_CX_VDD, 0xFF, 0x7C}, /* value in svs mode */ + {WCD934X_CODEC_CPR_SVS2_CX_VDD, 0xFF, 0x58}, /* value in svs2 mode */ + {WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, + {WCD934X_CDC_COMPANDER7_CTL7, 0x1E, 0x18}, + {WCD934X_CDC_RX0_RX_PATH_SEC0, 0x08, 0x0}, + {WCD934X_CDC_CLSH_DECAY_CTRL, 0x03, 0x0}, + {WCD934X_MICB1_TEST_CTL_2, 0x07, 0x01}, + {WCD934X_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {WCD934X_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {WCD934X_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {WCD934X_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x1F, 0x09}, + {WCD934X_CDC_TX0_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX1_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX2_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX3_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX4_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX5_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX6_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX7_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_CDC_TX8_TX_PATH_CFG1, 0x01, 0x00}, + {WCD934X_RX_OCP_CTL, 0x0F, 0x02}, /* OCP number of attempts is 2 */ + {WCD934X_HPH_OCP_CTL, 0xFF, 0x3A}, /* OCP current limit */ + {WCD934X_HPH_L_TEST, 0x01, 0x01}, + {WCD934X_HPH_R_TEST, 0x01, 0x01}, + {WCD934X_CPE_FLL_CONFIG_CTL_2, 0xFF, 0x20}, + {WCD934X_MBHC_NEW_CTL_2, 0x0C, 0x00}, + {WCD934X_CODEC_RPM_CLK_MCLK_CFG, 0x04, 0x04}, +}; + +static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = { + {WCD934X_CDC_COMPANDER1_CTL7, 0x1E, 0x06}, + {WCD934X_CDC_COMPANDER2_CTL7, 0x1E, 0x06}, + {WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xFF, 0x84}, + {WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xFF, 0x84}, + {WCD934X_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD934X_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4}, +}; + +static const struct tavil_cpr_reg_defaults cpr_defaults[] = { + { 0x00000820, 0x00000094 }, + { 0x00000fC0, 0x00000048 }, + { 0x0000f000, 0x00000044 }, + { 0x0000bb80, 0xC0000178 }, + { 0x00000000, 0x00000160 }, + { 0x10854522, 0x00000060 }, + { 0x10854509, 0x00000064 }, + { 0x108544dd, 0x00000068 }, + { 0x108544ad, 0x0000006C }, + { 0x0000077E, 0x00000070 }, + { 0x000007da, 0x00000074 }, + { 0x00000000, 0x00000078 }, + { 0x00000000, 0x0000007C }, + { 0x00042029, 0x00000080 }, + { 0x4002002A, 0x00000090 }, + { 0x4002002B, 0x00000090 }, +}; + +static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = { + {WCD934X_CDC_CLSH_K2_MSB, 0x0F, 0x00}, + {WCD934X_CDC_CLSH_K2_LSB, 0xFF, 0x60}, + {WCD934X_CPE_SS_DMIC_CFG, 0x80, 0x00}, + {WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x58}, + {WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x58}, + {WCD934X_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08}, + {WCD934X_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, + {WCD934X_CDC_TOP_TOP_CFG1, 0x02, 0x02}, + {WCD934X_CDC_TOP_TOP_CFG1, 0x01, 0x01}, + {WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x01, 0x01}, + {WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01}, + {WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD934X_CODEC_RPM_CLK_GATE, 0x08, 0x00}, + {WCD934X_TLMM_DMIC3_CLK_PINCFG, 0xFF, 0x0a}, + {WCD934X_TLMM_DMIC3_DATA_PINCFG, 0xFF, 0x0a}, + {WCD934X_CPE_SS_SVA_CFG, 0x60, 0x00}, + {WCD934X_CPE_SS_CPAR_CFG, 0x10, 0x10}, + {WCD934X_MICB1_TEST_CTL_1, 0xff, 0xfa}, + {WCD934X_MICB2_TEST_CTL_1, 0xff, 0xfa}, + {WCD934X_MICB3_TEST_CTL_1, 0xff, 0xfa}, + {WCD934X_MICB4_TEST_CTL_1, 0xff, 0xfa}, +}; + +static void tavil_codec_init_reg(struct tavil_priv *priv) +{ + struct snd_soc_component *component = priv->component; + u32 i; + + for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_init_common_val); i++) + snd_soc_component_update_bits(component, + tavil_codec_reg_init_common_val[i].reg, + tavil_codec_reg_init_common_val[i].mask, + tavil_codec_reg_init_common_val[i].val); + + if (TAVIL_IS_1_1(priv->wcd9xxx)) { + for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_init_1_1_val); i++) + snd_soc_component_update_bits(component, + tavil_codec_reg_init_1_1_val[i].reg, + tavil_codec_reg_init_1_1_val[i].mask, + tavil_codec_reg_init_1_1_val[i].val); + } +} + +static const struct tavil_reg_mask_val tavil_codec_reg_i2c_defaults[] = { + {WCD934X_CLK_SYS_MCLK_PRG, 0x40, 0x00}, + {WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x01}, + {WCD934X_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x00}, + {WCD934X_CODEC_RPM_CLK_MCLK_CFG, 0x05, 0x05}, + {WCD934X_DATA_HUB_RX0_CFG, 0x71, 0x31}, + {WCD934X_DATA_HUB_RX1_CFG, 0x71, 0x31}, + {WCD934X_DATA_HUB_RX2_CFG, 0x03, 0x01}, + {WCD934X_DATA_HUB_RX3_CFG, 0x03, 0x01}, + {WCD934X_DATA_HUB_I2S_TX0_CFG, 0x01, 0x01}, + {WCD934X_DATA_HUB_I2S_TX0_CFG, 0x04, 0x01}, + {WCD934X_DATA_HUB_I2S_TX1_0_CFG, 0x01, 0x01}, + {WCD934X_DATA_HUB_I2S_TX1_1_CFG, 0x05, 0x05}, + {WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN, 0x1, 0x1}, +}; + +static void tavil_update_reg_defaults(struct tavil_priv *tavil) +{ + u32 i; + struct wcd9xxx *wcd9xxx; + + wcd9xxx = tavil->wcd9xxx; + for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_defaults); i++) + regmap_update_bits(wcd9xxx->regmap, + tavil_codec_reg_defaults[i].reg, + tavil_codec_reg_defaults[i].mask, + tavil_codec_reg_defaults[i].val); + + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_i2c_defaults); i++) { + regmap_update_bits(wcd9xxx->regmap, + tavil_codec_reg_i2c_defaults[i].reg, + tavil_codec_reg_i2c_defaults[i].mask, + tavil_codec_reg_i2c_defaults[i].val); + } + } +} + +static void tavil_update_cpr_defaults(struct tavil_priv *tavil) +{ + int i; + struct wcd9xxx *wcd9xxx; + + wcd9xxx = tavil->wcd9xxx; + if (!TAVIL_IS_1_1(wcd9xxx)) + return; + + __tavil_cdc_mclk_enable(tavil, true); + + regmap_write(wcd9xxx->regmap, WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x2C); + regmap_update_bits(wcd9xxx->regmap, WCD934X_CODEC_RPM_CLK_GATE, + 0x10, 0x00); + + for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) { + regmap_bulk_write(wcd9xxx->regmap, + WCD934X_CODEC_CPR_WR_DATA_0, + (u8 *)&cpr_defaults[i].wr_data, 4); + regmap_bulk_write(wcd9xxx->regmap, + WCD934X_CODEC_CPR_WR_ADDR_0, + (u8 *)&cpr_defaults[i].wr_addr, 4); + } + + __tavil_cdc_mclk_enable(tavil, false); +} + +static void tavil_slim_interface_init_reg(struct snd_soc_component *component) +{ + int i; + struct tavil_priv *priv = snd_soc_component_get_drvdata(component); + + for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) + wcd9xxx_interface_reg_write(priv->wcd9xxx, + WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + i, + 0xFF); +} + +static irqreturn_t tavil_misc_irq(int irq, void *data) +{ + struct tavil_priv *tavil = data; + int misc_val; + + /* Find source of interrupt */ + regmap_read(tavil->wcd9xxx->regmap, WCD934X_INTR_CODEC_MISC_STATUS, + &misc_val); + + if (misc_val & 0x08) { + dev_info(tavil->dev, "%s: irq: %d, DSD DC detected!\n", + __func__, irq); + /* DSD DC interrupt, reset DSD path */ + tavil_dsd_reset(tavil->dsd_config); + } else { + dev_err(tavil->dev, "%s: Codec misc irq: %d, val: 0x%x\n", + __func__, irq, misc_val); + } + + /* Clear interrupt status */ + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_INTR_CODEC_MISC_CLEAR, misc_val, 0x00); + + return IRQ_HANDLED; +} + +static irqreturn_t tavil_slimbus_irq(int irq, void *data) +{ + struct tavil_priv *tavil = data; + unsigned long status = 0; + int i, j, port_id, k; + u32 bit; + u8 val, int_val = 0; + bool tx, cleared; + unsigned short reg = 0; + + for (i = WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0; + i <= WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) { + val = wcd9xxx_interface_reg_read(tavil->wcd9xxx, i); + status |= ((u32)val << (8 * j)); + } + + for_each_set_bit(j, &status, 32) { + tx = (j >= 16 ? true : false); + port_id = (tx ? j - 16 : j); + val = wcd9xxx_interface_reg_read(tavil->wcd9xxx, + WCD934X_SLIM_PGD_PORT_INT_RX_SOURCE0 + j); + if (val) { + if (!tx) + reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + + (port_id / 8); + else + reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + int_val = wcd9xxx_interface_reg_read( + tavil->wcd9xxx, reg); + /* + * Ignore interrupts for ports for which the + * interrupts are not specifically enabled. + */ + if (!(int_val & (1 << (port_id % 8)))) + continue; + } + if (val & WCD934X_SLIM_IRQ_OVERFLOW) + dev_err_ratelimited(tavil->dev, "%s: overflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if (val & WCD934X_SLIM_IRQ_UNDERFLOW) + dev_err_ratelimited(tavil->dev, "%s: underflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if ((val & WCD934X_SLIM_IRQ_OVERFLOW) || + (val & WCD934X_SLIM_IRQ_UNDERFLOW)) { + if (!tx) + reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + + (port_id / 8); + else + reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + int_val = wcd9xxx_interface_reg_read( + tavil->wcd9xxx, reg); + if (int_val & (1 << (port_id % 8))) { + int_val = int_val ^ (1 << (port_id % 8)); + wcd9xxx_interface_reg_write(tavil->wcd9xxx, + reg, int_val); + } + } + if (val & WCD934X_SLIM_IRQ_PORT_CLOSED) { + /* + * INT SOURCE register starts from RX to TX + * but port number in the ch_mask is in opposite way + */ + bit = (tx ? j - 16 : j + 16); + dev_dbg(tavil->dev, "%s: %s port %d closed value %x, bit %u\n", + __func__, (tx ? "TX" : "RX"), port_id, val, + bit); + for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) { + dev_dbg(tavil->dev, "%s: tavil->dai[%d].ch_mask = 0x%lx\n", + __func__, k, tavil->dai[k].ch_mask); + if (test_and_clear_bit(bit, + &tavil->dai[k].ch_mask)) { + cleared = true; + if (!tavil->dai[k].ch_mask) + wake_up( + &tavil->dai[k].dai_wait); + /* + * There are cases when multiple DAIs + * might be using the same slimbus + * channel. Hence don't break here. + */ + } + } + WARN(!cleared, + "Couldn't find slimbus %s port %d for closing\n", + (tx ? "TX" : "RX"), port_id); + } + wcd9xxx_interface_reg_write(tavil->wcd9xxx, + WCD934X_SLIM_PGD_PORT_INT_CLR_RX_0 + + (j / 8), + 1 << (j % 8)); + } + + return IRQ_HANDLED; +} + +static int tavil_setup_irqs(struct tavil_priv *tavil) +{ + int ret = 0; + struct snd_soc_component *component = tavil->component; + struct wcd9xxx *wcd9xxx = tavil->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS, + tavil_slimbus_irq, "SLIMBUS Slave", tavil); + if (ret) + dev_err(component->dev, "%s: Failed to request irq %d\n", + __func__, WCD9XXX_IRQ_SLIMBUS); + else + tavil_slim_interface_init_reg(component); + + /* Register for misc interrupts as well */ + ret = wcd9xxx_request_irq(core_res, WCD934X_IRQ_MISC, + tavil_misc_irq, "CDC MISC Irq", tavil); + if (ret) + dev_err(component->dev, "%s: Failed to request cdc misc irq\n", + __func__); + + return ret; +} + +static void tavil_init_slim_slave_cfg(struct snd_soc_component *component) +{ + struct tavil_priv *priv = snd_soc_component_get_drvdata(component); + struct afe_param_cdc_slimbus_slave_cfg *cfg; + struct wcd9xxx *wcd9xxx = priv->wcd9xxx; + uint64_t eaddr = 0; + + cfg = &priv->slimbus_slave_cfg; + cfg->minor_version = 1; + cfg->tx_slave_port_offset = 0; + cfg->rx_slave_port_offset = 16; + + memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr)); + WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6); + cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF; + cfg->device_enum_addr_msw = eaddr >> 32; + + dev_dbg(component->dev, "%s: slimbus logical address 0x%llx\n", + __func__, eaddr); +} + +static void tavil_cleanup_irqs(struct tavil_priv *tavil) +{ + struct wcd9xxx *wcd9xxx = tavil->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tavil); + wcd9xxx_free_irq(core_res, WCD934X_IRQ_MISC, tavil); +} + +/* + * wcd934x_get_micb_vout_ctl_val: converts micbias from volts to register value + * @micb_mv: micbias in mv + * + * return register value converted + */ +int wcd934x_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < 1000 || micb_mv > 2850) { + pr_err("%s: unsupported micbias voltage\n", __func__); + return -EINVAL; + } + + return (micb_mv - 1000) / 50; +} +EXPORT_SYMBOL(wcd934x_get_micb_vout_ctl_val); + +static int tavil_handle_pdata(struct tavil_priv *tavil, + struct wcd9xxx_pdata *pdata) +{ + struct snd_soc_component *component = tavil->component; + u8 mad_dmic_ctl_val; + u8 anc_ctl_value; + u32 def_dmic_rate, dmic_clk_drv; + int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; + int rc = 0; + + if (!pdata) { + dev_err(component->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl_1 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + vout_ctl_2 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv); + vout_ctl_3 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv); + vout_ctl_4 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb4_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || + vout_ctl_3 < 0 || vout_ctl_4 < 0) { + rc = -EINVAL; + goto done; + } + snd_soc_component_update_bits(component, WCD934X_ANA_MICB1, + 0x3F, vout_ctl_1); + snd_soc_component_update_bits(component, WCD934X_ANA_MICB2, + 0x3F, vout_ctl_2); + snd_soc_component_update_bits(component, WCD934X_ANA_MICB3, + 0x3F, vout_ctl_3); + snd_soc_component_update_bits(component, WCD934X_ANA_MICB4, + 0x3F, vout_ctl_4); + + /* Set the DMIC sample rate */ + switch (pdata->mclk_rate) { + case WCD934X_MCLK_CLK_9P6MHZ: + def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ; + break; + case WCD934X_MCLK_CLK_12P288MHZ: + def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ; + break; + default: + /* should never happen */ + dev_err(component->dev, "%s: Invalid mclk_rate %d\n", + __func__, pdata->mclk_rate); + rc = -EINVAL; + goto done; + }; + + if (pdata->dmic_sample_rate == + WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) { + dev_info(component->dev, "%s: dmic_rate invalid default = %d\n", + __func__, def_dmic_rate); + pdata->dmic_sample_rate = def_dmic_rate; + } + if (pdata->mad_dmic_sample_rate == + WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) { + dev_info(component->dev, "%s: mad_dmic_rate invalid default = %d\n", + __func__, def_dmic_rate); + /* + * use dmic_sample_rate as the default for MAD + * if mad dmic sample rate is undefined + */ + pdata->mad_dmic_sample_rate = pdata->dmic_sample_rate; + } + + if (pdata->dmic_clk_drv == + WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED) { + pdata->dmic_clk_drv = WCD934X_DMIC_CLK_DRIVE_DEFAULT; + dev_dbg(component->dev, + "%s: dmic_clk_strength invalid, default = %d\n", + __func__, pdata->dmic_clk_drv); + } + + switch (pdata->dmic_clk_drv) { + case 2: + dmic_clk_drv = 0; + break; + case 4: + dmic_clk_drv = 1; + break; + case 8: + dmic_clk_drv = 2; + break; + case 16: + dmic_clk_drv = 3; + break; + default: + dev_err(component->dev, + "%s: invalid dmic_clk_drv %d, using default\n", + __func__, pdata->dmic_clk_drv); + dmic_clk_drv = 0; + break; + } + + snd_soc_component_update_bits(component, + WCD934X_TEST_DEBUG_PAD_DRVCTL_0, + 0x0C, dmic_clk_drv << 2); + + /* + * Default the DMIC clk rates to mad_dmic_sample_rate, + * whereas, the anc/txfe dmic rates to dmic_sample_rate + * since the anc/txfe are independent of mad block. + */ + mad_dmic_ctl_val = tavil_get_dmic_clk_val(tavil->component, + pdata->mclk_rate, + pdata->mad_dmic_sample_rate); + snd_soc_component_update_bits(component, WCD934X_CPE_SS_DMIC0_CTL, + 0x0E, mad_dmic_ctl_val << 1); + snd_soc_component_update_bits(component, WCD934X_CPE_SS_DMIC1_CTL, + 0x0E, mad_dmic_ctl_val << 1); + snd_soc_component_update_bits(component, WCD934X_CPE_SS_DMIC2_CTL, + 0x0E, mad_dmic_ctl_val << 1); + + if (dmic_clk_drv == WCD934X_DMIC_CLK_DIV_2) + anc_ctl_value = WCD934X_ANC_DMIC_X2_FULL_RATE; + else + anc_ctl_value = WCD934X_ANC_DMIC_X2_HALF_RATE; + + snd_soc_component_update_bits(component, WCD934X_CDC_ANC0_MODE_2_CTL, + 0x40, anc_ctl_value << 6); + snd_soc_component_update_bits(component, WCD934X_CDC_ANC0_MODE_2_CTL, + 0x20, anc_ctl_value << 5); + snd_soc_component_update_bits(component, WCD934X_CDC_ANC1_MODE_2_CTL, + 0x40, anc_ctl_value << 6); + snd_soc_component_update_bits(component, WCD934X_CDC_ANC1_MODE_2_CTL, + 0x20, anc_ctl_value << 5); + +done: + return rc; +} + +static void tavil_cdc_vote_svs(struct snd_soc_component *component, bool vote) +{ + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + return tavil_vote_svs(tavil, vote); +} + +static struct wcd_dsp_cdc_cb cdc_cb = { + .cdc_clk_en = tavil_codec_internal_rco_ctrl, + .cdc_vote_svs = tavil_cdc_vote_svs, +}; + +static int tavil_wdsp_initialize(struct snd_soc_component *component) +{ + struct wcd9xxx *control; + struct tavil_priv *tavil; + struct wcd_dsp_params params; + int ret = 0; + + control = dev_get_drvdata(component->dev->parent); + tavil = snd_soc_component_get_drvdata(component); + + params.cb = &cdc_cb; + params.irqs.cpe_ipc1_irq = WCD934X_IRQ_CPE1_INTR; + params.irqs.cpe_err_irq = WCD934X_IRQ_CPE_ERROR; + params.irqs.fatal_irqs = CPE_FATAL_IRQS; + params.clk_rate = control->mclk_rate; + params.dsp_instance = 0; + + wcd_dsp_cntl_init(component, ¶ms, &tavil->wdsp_cntl); + if (!tavil->wdsp_cntl) { + dev_err(tavil->dev, "%s: wcd-dsp-control init failed\n", + __func__); + ret = -EINVAL; + } + + return ret; +} + +/* + * tavil_soc_get_mbhc: get wcd934x_mbhc handle of corresponding codec + * @component: handle to snd_soc_component * + * + * return wcd934x_mbhc handle or error code in case of failure + */ +struct wcd934x_mbhc *tavil_soc_get_mbhc(struct snd_soc_component *component) +{ + struct tavil_priv *tavil; + + if (!component) { + pr_err("%s: Invalid params, NULL codec\n", __func__); + return NULL; + } + tavil = snd_soc_component_get_drvdata(component); + + if (!tavil) { + pr_err("%s: Invalid params, NULL tavil\n", __func__); + return NULL; + } + + return tavil->mbhc; +} +EXPORT_SYMBOL(tavil_soc_get_mbhc); + +static void tavil_mclk2_reg_defaults(struct tavil_priv *tavil) +{ + int i; + struct snd_soc_component *component = tavil->component; + + if (TAVIL_IS_1_0(tavil->wcd9xxx)) { + /* MCLK2 configuration */ + for (i = 0; i < ARRAY_SIZE(tavil_codec_mclk2_1_0_defaults); i++) + snd_soc_component_update_bits(component, + tavil_codec_mclk2_1_0_defaults[i].reg, + tavil_codec_mclk2_1_0_defaults[i].mask, + tavil_codec_mclk2_1_0_defaults[i].val); + } + if (TAVIL_IS_1_1(tavil->wcd9xxx)) { + /* MCLK2 configuration */ + for (i = 0; i < ARRAY_SIZE(tavil_codec_mclk2_1_1_defaults); i++) + snd_soc_component_update_bits(component, + tavil_codec_mclk2_1_1_defaults[i].reg, + tavil_codec_mclk2_1_1_defaults[i].mask, + tavil_codec_mclk2_1_1_defaults[i].val); + } +} + +static int tavil_device_down(struct wcd9xxx *wcd9xxx) +{ + struct snd_soc_component *component; + struct tavil_priv *priv; + int count; + int decimator; + int ret; + + component = (struct snd_soc_component *)(wcd9xxx->ssr_priv); + if (!component->card) { + dev_err(component->dev, "%s: sound card is not enumerated.\n", + __func__); + return -EINVAL; + } + + priv = snd_soc_component_get_drvdata(component); + for (count = 0; count < NUM_CODEC_DAIS; count++) + priv->dai[count].bus_down_in_recovery = true; + snd_event_notify(priv->dev->parent, SND_EVENT_DOWN); + + if (priv->mbhc) + priv->mbhc->wcd_mbhc.deinit_in_progress = true; + if (delayed_work_pending(&priv->spk_anc_dwork.dwork)) + cancel_delayed_work(&priv->spk_anc_dwork.dwork); + for (decimator = 0; decimator < WCD934X_NUM_DECIMATORS; decimator++) { + if (delayed_work_pending + (&priv->tx_mute_dwork[decimator].dwork)) + cancel_delayed_work + (&priv->tx_mute_dwork[decimator].dwork); + if (delayed_work_pending + (&priv->tx_hpf_work[decimator].dwork)) + cancel_delayed_work + (&priv->tx_hpf_work[decimator].dwork); + } + if (delayed_work_pending(&priv->power_gate_work)) + cancel_delayed_work_sync(&priv->power_gate_work); + if (priv->mbhc) { + if (delayed_work_pending(&priv->mbhc->wcd_mbhc.mbhc_btn_dwork)) { + ret = cancel_delayed_work( + &priv->mbhc->wcd_mbhc.mbhc_btn_dwork); + if (ret) + priv->mbhc->wcd_mbhc.mbhc_cb->lock_sleep + (&priv->mbhc->wcd_mbhc, false); + } + } + + if (priv->swr.ctrl_data) { + if (is_snd_event_fwk_enabled()) + swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev, + SWR_DEVICE_DOWN, NULL); + } + tavil_dsd_reset(priv->dsd_config); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + if (!is_snd_event_fwk_enabled()) + snd_soc_card_change_online_state(component->card, 0); +#endif /* CONFIG_AUDIO_QGKI */ + wcd_dsp_ssr_event(priv->wdsp_cntl, WCD_CDC_DOWN_EVENT); + wcd_resmgr_set_sido_input_src_locked(priv->resmgr, + SIDO_SOURCE_INTERNAL); + + return 0; +} + +static int tavil_post_reset_cb(struct wcd9xxx *wcd9xxx) +{ + int i, ret = 0; + struct wcd9xxx *control; + struct snd_soc_component *component; + struct tavil_priv *tavil; + struct wcd9xxx_pdata *pdata; + struct wcd_mbhc *mbhc; + + component = (struct snd_soc_component *)(wcd9xxx->ssr_priv); + if (!component->card) { + dev_err(component->dev, "%s: sound card is not enumerated.\n", + __func__); + return -EINVAL; + } + tavil = snd_soc_component_get_drvdata(component); + control = dev_get_drvdata(component->dev->parent); + + wcd9xxx_set_power_state(tavil->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_REMOVE, + WCD9XXX_DIG_CORE_REGION_1); + + mutex_lock(&tavil->codec_mutex); + + tavil_vote_svs(tavil, true); + tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la = + control->slim_slave->laddr; + tavil_slimbus_slave_port_cfg.slave_dev_pgd_la = + control->slim->laddr; + tavil_init_slim_slave_cfg(component); +#if IS_ENABLED(CONFIG_AUDIO_QGKI) + if (!is_snd_event_fwk_enabled()) + snd_soc_card_change_online_state(component->card, 1); +#endif /* CONFIG_AUDIO_QGKI */ + + for (i = 0; i < TAVIL_MAX_MICBIAS; i++) + tavil->micb_ref[i] = 0; + + dev_dbg(component->dev, "%s: MCLK Rate = %x\n", + __func__, control->mclk_rate); + + if (control->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ) + snd_soc_component_update_bits(component, + WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x00); + else if (control->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ) + snd_soc_component_update_bits(component, + WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x01); + tavil_update_reg_defaults(tavil); + wcd_resmgr_post_ssr_v2(tavil->resmgr); + tavil_codec_init_reg(tavil); + __tavil_enable_efuse_sensing(tavil); + tavil_mclk2_reg_defaults(tavil); + + __tavil_cdc_mclk_enable(tavil, true); + regcache_mark_dirty(component->regmap); + regcache_sync(component->regmap); + __tavil_cdc_mclk_enable(tavil, false); + + tavil_update_cpr_defaults(tavil); + + pdata = dev_get_platdata(component->dev->parent); + ret = tavil_handle_pdata(tavil, pdata); + if (ret < 0) + dev_err(component->dev, "%s: invalid pdata\n", __func__); + + /* Initialize MBHC module */ + if (tavil->mbhc) { + mbhc = &tavil->mbhc->wcd_mbhc; + ret = tavil_mbhc_post_ssr_init(tavil->mbhc, component); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto done; + } else { + tavil_mbhc_hs_detect(component, mbhc->mbhc_cfg); + } + } + /* DSD initialization */ + ret = tavil_dsd_post_ssr_init(tavil->dsd_config); + if (ret) + dev_dbg(tavil->dev, "%s: DSD init failed\n", __func__); + + tavil_cleanup_irqs(tavil); + ret = tavil_setup_irqs(tavil); + if (ret) { + dev_err(component->dev, "%s: tavil irq setup failed %d\n", + __func__, ret); + goto done; + } + + if (tavil->swr.ctrl_data && is_snd_event_fwk_enabled()) + swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + tavil_set_spkr_mode(component, tavil->swr.spkr_mode); + /* + * Once the codec initialization is completed, the svs vote + * can be released allowing the codec to go to SVS2. + */ + tavil_vote_svs(tavil, false); + wcd_dsp_ssr_event(tavil->wdsp_cntl, WCD_CDC_UP_EVENT); + snd_event_notify(tavil->dev->parent, SND_EVENT_UP); + +done: + mutex_unlock(&tavil->codec_mutex); + return ret; +} + +static int tavil_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd9xxx *control; + struct tavil_priv *tavil; + struct wcd9xxx_pdata *pdata; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int i, ret; + void *ptr = NULL; + + control = dev_get_drvdata(component->dev->parent); + + snd_soc_component_init_regmap(component, control->regmap); + + dev_info(component->dev, "%s()\n", __func__); + tavil = snd_soc_component_get_drvdata(component); + tavil->intf_type = wcd9xxx_get_intf_type(); + + control->dev_down = tavil_device_down; + control->post_reset = tavil_post_reset_cb; + control->ssr_priv = (void *)component; + + /* Resource Manager post Init */ + ret = wcd_resmgr_post_init(tavil->resmgr, &tavil_resmgr_cb, component); + if (ret) { + dev_err(component->dev, "%s: wcd resmgr post init failed\n", + __func__); + goto err; + } + /* Class-H Init */ + wcd_clsh_init(&tavil->clsh_d); + /* Default HPH Mode to Class-H Low HiFi */ + tavil->hph_mode = CLS_H_LOHIFI; + + tavil->fw_data = devm_kzalloc(component->dev, sizeof(*(tavil->fw_data)), + GFP_KERNEL); + if (!tavil->fw_data) + goto err; + + set_bit(WCD9XXX_ANC_CAL, tavil->fw_data->cal_bit); + set_bit(WCD9XXX_MBHC_CAL, tavil->fw_data->cal_bit); + set_bit(WCD9XXX_MAD_CAL, tavil->fw_data->cal_bit); + set_bit(WCD9XXX_VBAT_CAL, tavil->fw_data->cal_bit); + + ret = wcd_cal_create_hwdep(tavil->fw_data, + WCD9XXX_CODEC_HWDEP_NODE, component); + if (ret < 0) { + dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret); + goto err_hwdep; + } + + /* Initialize MBHC module */ + ret = tavil_mbhc_init(&tavil->mbhc, component, tavil->fw_data); + if (ret) { + pr_err("%s: mbhc initialization failed\n", __func__); + goto err_hwdep; + } + + tavil->component = component; + for (i = 0; i < COMPANDER_MAX; i++) + tavil->comp_enabled[i] = 0; + + tavil_codec_init_reg(tavil); + + pdata = dev_get_platdata(component->dev->parent); + ret = tavil_handle_pdata(tavil, pdata); + if (ret < 0) { + dev_err(component->dev, "%s: bad pdata\n", __func__); + goto err_hwdep; + } + + ptr = devm_kzalloc(component->dev, (sizeof(tavil_rx_chs) + + sizeof(tavil_tx_chs)), GFP_KERNEL); + if (!ptr) { + ret = -ENOMEM; + goto err_hwdep; + } + + for (i = 0; i < NUM_CODEC_DAIS; i++) { + INIT_LIST_HEAD(&tavil->dai[i].wcd9xxx_ch_list); + init_waitqueue_head(&tavil->dai[i].dai_wait); + } + + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + snd_soc_dapm_new_controls(dapm, tavil_dapm_slim_widgets, + ARRAY_SIZE(tavil_dapm_slim_widgets)); + snd_soc_dapm_add_routes(dapm, tavil_slim_audio_map, + ARRAY_SIZE(tavil_slim_audio_map)); + tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la = + control->slim_slave->laddr; + tavil_slimbus_slave_port_cfg.slave_dev_pgd_la = + control->slim->laddr; + tavil_slimbus_slave_port_cfg.slave_port_mapping[0] = + WCD934X_TX13; + tavil_init_slim_slave_cfg(component); + } else { + snd_soc_dapm_new_controls(dapm, tavil_dapm_i2s_widgets, + ARRAY_SIZE(tavil_dapm_i2s_widgets)); + snd_soc_dapm_add_routes(dapm, tavil_i2s_audio_map, + ARRAY_SIZE(tavil_i2s_audio_map)); + } + + control->num_rx_port = WCD934X_RX_MAX; + control->rx_chs = ptr; + memcpy(control->rx_chs, tavil_rx_chs, sizeof(tavil_rx_chs)); + control->num_tx_port = WCD934X_TX_MAX; + control->tx_chs = ptr + sizeof(tavil_rx_chs); + memcpy(control->tx_chs, tavil_tx_chs, sizeof(tavil_tx_chs)); + + ret = tavil_setup_irqs(tavil); + if (ret) { + dev_err(tavil->dev, "%s: tavil irq setup failed %d\n", + __func__, ret); + goto err_pdata; + } + + for (i = 0; i < WCD934X_NUM_DECIMATORS; i++) { + tavil->tx_hpf_work[i].tavil = tavil; + tavil->tx_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&tavil->tx_hpf_work[i].dwork, + tavil_tx_hpf_corner_freq_callback); + + tavil->tx_mute_dwork[i].tavil = tavil; + tavil->tx_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&tavil->tx_mute_dwork[i].dwork, + tavil_tx_mute_update_callback); + } + + tavil->spk_anc_dwork.tavil = tavil; + INIT_DELAYED_WORK(&tavil->spk_anc_dwork.dwork, + tavil_spk_anc_update_callback); + + tavil_mclk2_reg_defaults(tavil); + + /* DSD initialization */ + tavil->dsd_config = tavil_dsd_init(component); + if (IS_ERR_OR_NULL(tavil->dsd_config)) + dev_dbg(tavil->dev, "%s: DSD init failed\n", __func__); + + mutex_lock(&tavil->codec_mutex); + snd_soc_dapm_disable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHL"); + snd_soc_dapm_disable_pin(dapm, "ANC HPHR"); + snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA"); + mutex_unlock(&tavil->codec_mutex); + + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "AIF2 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF2 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "AIF3 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF3 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "WDMA3_OUT"); + + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + snd_soc_dapm_ignore_suspend(dapm, "AIF4 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX"); + snd_soc_dapm_ignore_suspend(dapm, "VIfeed"); + } + + snd_soc_dapm_sync(dapm); + + tavil_wdsp_initialize(component); + + /* + * Once the codec initialization is completed, the svs vote + * can be released allowing the codec to go to SVS2. + */ + tavil_vote_svs(tavil, false); + + return ret; + +err_pdata: + devm_kfree(component->dev, ptr); + control->rx_chs = NULL; + control->tx_chs = NULL; +err_hwdep: + devm_kfree(component->dev, tavil->fw_data); + tavil->fw_data = NULL; +err: + return ret; +} + +static void tavil_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd9xxx *control; + struct tavil_priv *tavil = snd_soc_component_get_drvdata(component); + + control = dev_get_drvdata(component->dev->parent); + devm_kfree(component->dev, control->rx_chs); + /* slimslave deinit in wcd core looks for this value */ + control->num_rx_port = 0; + control->num_tx_port = 0; + control->rx_chs = NULL; + control->tx_chs = NULL; + tavil_cleanup_irqs(tavil); + + if (tavil->wdsp_cntl) + wcd_dsp_cntl_deinit(&tavil->wdsp_cntl); + + /* Deinitialize MBHC module */ + tavil_mbhc_deinit(component); + tavil->mbhc = NULL; + + return; +} + +static const struct snd_soc_component_driver soc_codec_dev_tavil = { + .name = WCD934X_DRV_NAME, + .probe = tavil_soc_codec_probe, + .remove = tavil_soc_codec_remove, + .controls = tavil_snd_controls, + .num_controls = ARRAY_SIZE(tavil_snd_controls), + .dapm_widgets = tavil_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tavil_dapm_widgets), + .dapm_routes = tavil_audio_map, + .num_dapm_routes = ARRAY_SIZE(tavil_audio_map), +}; + +#ifdef CONFIG_PM +static int tavil_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tavil_priv *tavil = platform_get_drvdata(pdev); + + if (!tavil) { + dev_err(dev, "%s: tavil private data is NULL\n", __func__); + return -EINVAL; + } + dev_dbg(dev, "%s: system suspend\n", __func__); + if (delayed_work_pending(&tavil->power_gate_work) && + cancel_delayed_work_sync(&tavil->power_gate_work)) + tavil_codec_power_gate_digital_core(tavil); + return 0; +} + +static int tavil_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tavil_priv *tavil = platform_get_drvdata(pdev); + + if (!tavil) { + dev_err(dev, "%s: tavil private data is NULL\n", __func__); + return -EINVAL; + } + dev_dbg(dev, "%s: system resume\n", __func__); + return 0; +} + +static const struct dev_pm_ops tavil_pm_ops = { + .suspend = tavil_suspend, + .resume = tavil_resume, +}; +#endif + +static int wcd9xxx_swrm_i2c_bulk_write(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_reg_val *bulk_reg, + size_t len) +{ + int i, ret = 0; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + + swr_wr_addr_base = WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD934X_SWR_AHB_BRIDGE_WR_DATA_0; + + for (i = 0; i < (len * 2); i += 2) { + /* First Write the Data to register */ + ret = regmap_bulk_write(wcd9xxx->regmap, + swr_wr_data_base, bulk_reg[i].buf, 4); + if (ret < 0) { + dev_err(wcd9xxx->dev, "%s: WR Data Failure\n", + __func__); + break; + } + /* Next Write Address */ + ret = regmap_bulk_write(wcd9xxx->regmap, + swr_wr_addr_base, + bulk_reg[i+1].buf, 4); + if (ret < 0) { + dev_err(wcd9xxx->dev, "%s: WR Addr Failure\n", + __func__); + break; + } + } + return ret; +} + +static int tavil_swrm_read(void *handle, int reg) +{ + struct tavil_priv *tavil; + struct wcd9xxx *wcd9xxx; + unsigned short swr_rd_addr_base; + unsigned short swr_rd_data_base; + int val, ret; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + wcd9xxx = tavil->wcd9xxx; + + dev_dbg(tavil->dev, "%s: Reading soundwire register, 0x%x\n", + __func__, reg); + swr_rd_addr_base = WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0; + swr_rd_data_base = WCD934X_SWR_AHB_BRIDGE_RD_DATA_0; + + mutex_lock(&tavil->swr.read_mutex); + ret = regmap_bulk_write(wcd9xxx->regmap, swr_rd_addr_base, + (u8 *)®, 4); + if (ret < 0) { + dev_err(tavil->dev, "%s: RD Addr Failure\n", __func__); + goto done; + } + ret = regmap_bulk_read(wcd9xxx->regmap, swr_rd_data_base, + (u8 *)&val, 4); + if (ret < 0) { + dev_err(tavil->dev, "%s: RD Data Failure\n", __func__); + goto done; + } + ret = val; +done: + mutex_unlock(&tavil->swr.read_mutex); + + return ret; +} + +static int tavil_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len) +{ + struct tavil_priv *tavil; + struct wcd9xxx *wcd9xxx; + struct wcd9xxx_reg_val *bulk_reg; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + int i, j, ret; + + if (!handle || !reg || !val) { + pr_err("%s: NULL parameter\n", __func__); + return -EINVAL; + } + if (len <= 0) { + pr_err("%s: Invalid size: %zu\n", __func__, len); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + wcd9xxx = tavil->wcd9xxx; + + swr_wr_addr_base = WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD934X_SWR_AHB_BRIDGE_WR_DATA_0; + + bulk_reg = kzalloc((2 * len * sizeof(struct wcd9xxx_reg_val)), + GFP_KERNEL); + if (!bulk_reg) + return -ENOMEM; + + for (i = 0, j = 0; i < (len * 2); i += 2, j++) { + bulk_reg[i].reg = swr_wr_data_base; + bulk_reg[i].buf = (u8 *)(&val[j]); + bulk_reg[i].bytes = 4; + bulk_reg[i+1].reg = swr_wr_addr_base; + bulk_reg[i+1].buf = (u8 *)(®[j]); + bulk_reg[i+1].bytes = 4; + } + + mutex_lock(&tavil->swr.write_mutex); + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, + (len * 2), false); + else + ret = wcd9xxx_swrm_i2c_bulk_write(wcd9xxx, bulk_reg, len); + if (ret) { + dev_err(tavil->dev, "%s: swrm bulk write failed, ret: %d\n", + __func__, ret); + } + mutex_unlock(&tavil->swr.write_mutex); + + kfree(bulk_reg); + return ret; +} + +static int tavil_swrm_write(void *handle, int reg, int val) +{ + struct tavil_priv *tavil; + struct wcd9xxx *wcd9xxx; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + struct wcd9xxx_reg_val bulk_reg[2]; + int ret; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + wcd9xxx = tavil->wcd9xxx; + + swr_wr_addr_base = WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD934X_SWR_AHB_BRIDGE_WR_DATA_0; + + /* First Write the Data to register */ + bulk_reg[0].reg = swr_wr_data_base; + bulk_reg[0].buf = (u8 *)(&val); + bulk_reg[0].bytes = 4; + bulk_reg[1].reg = swr_wr_addr_base; + bulk_reg[1].buf = (u8 *)(®); + bulk_reg[1].bytes = 4; + + mutex_lock(&tavil->swr.write_mutex); + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2, false); + else + ret = wcd9xxx_swrm_i2c_bulk_write(wcd9xxx, bulk_reg, 1); + if (ret < 0) + dev_err(tavil->dev, "%s: WR Data Failure\n", __func__); + mutex_unlock(&tavil->swr.write_mutex); + + return ret; +} + +static int tavil_swrm_clock(void *handle, bool enable) +{ + struct tavil_priv *tavil; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + + mutex_lock(&tavil->swr.clk_mutex); + dev_dbg(tavil->dev, "%s: swrm clock %s\n", + __func__, (enable?"enable" : "disable")); + if (enable) { + tavil->swr.clk_users++; + if (tavil->swr.clk_users == 1) { + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_TEST_DEBUG_NPL_DLY_TEST_1, + 0x10, 0x00); + __tavil_cdc_mclk_enable(tavil, true); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + } + } else { + tavil->swr.clk_users--; + if (tavil->swr.clk_users == 0) { + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + __tavil_cdc_mclk_enable(tavil, false); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_TEST_DEBUG_NPL_DLY_TEST_1, + 0x10, 0x10); + } + } + dev_dbg(tavil->dev, "%s: swrm clock users %d\n", + __func__, tavil->swr.clk_users); + mutex_unlock(&tavil->swr.clk_mutex); + + return 0; +} + +static int tavil_swrm_handle_irq(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action) +{ + struct tavil_priv *tavil; + int ret = 0; + struct wcd9xxx *wcd9xxx; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *) handle; + wcd9xxx = tavil->wcd9xxx; + + if (action) { + ret = wcd9xxx_request_irq(&wcd9xxx->core_res, + WCD934X_IRQ_SOUNDWIRE, + swrm_irq_handler, + "Tavil SWR Master", swrm_handle); + if (ret) + dev_err(tavil->dev, "%s: Failed to request irq %d\n", + __func__, WCD934X_IRQ_SOUNDWIRE); + } else + wcd9xxx_free_irq(&wcd9xxx->core_res, WCD934X_IRQ_SOUNDWIRE, + swrm_handle); + + return ret; +} + +static void tavil_codec_add_spi_device(struct tavil_priv *tavil, + struct device_node *node) +{ + struct spi_master *master; + struct spi_device *spi; + u32 prop_value; + int rc; + + /* Read the master bus num from DT node */ + rc = of_property_read_u32(node, "qcom,master-bus-num", + &prop_value); + if (rc < 0) { + dev_err(tavil->dev, "%s: prop %s not found in node %s", + __func__, "qcom,master-bus-num", node->full_name); + goto done; + } + + /* Get the reference to SPI master */ + master = spi_busnum_to_master(prop_value); + if (!master) { + dev_err(tavil->dev, "%s: Invalid spi_master for bus_num %u\n", + __func__, prop_value); + goto done; + } + + /* Allocate the spi device */ + spi = spi_alloc_device(master); + if (!spi) { + dev_err(tavil->dev, "%s: spi_alloc_device failed\n", + __func__); + goto err_spi_alloc_dev; + } + + /* Initialize device properties */ + if (of_modalias_node(node, spi->modalias, + sizeof(spi->modalias)) < 0) { + dev_err(tavil->dev, "%s: cannot find modalias for %s\n", + __func__, node->full_name); + goto err_dt_parse; + } + + rc = of_property_read_u32(node, "qcom,chip-select", + &prop_value); + if (rc < 0) { + dev_err(tavil->dev, "%s: prop %s not found in node %s", + __func__, "qcom,chip-select", node->full_name); + goto err_dt_parse; + } + spi->chip_select = prop_value; + + rc = of_property_read_u32(node, "qcom,max-frequency", + &prop_value); + if (rc < 0) { + dev_err(tavil->dev, "%s: prop %s not found in node %s", + __func__, "qcom,max-frequency", node->full_name); + goto err_dt_parse; + } + spi->max_speed_hz = prop_value; + + spi->dev.of_node = node; + + rc = spi_add_device(spi); + if (rc < 0) { + dev_err(tavil->dev, "%s: spi_add_device failed\n", __func__); + goto err_dt_parse; + } + + tavil->spi = spi; + /* Put the reference to SPI master */ + put_device(&master->dev); + + return; + +err_dt_parse: + spi_dev_put(spi); + +err_spi_alloc_dev: + /* Put the reference to SPI master */ + put_device(&master->dev); +done: + return; +} + +static void tavil_add_child_devices(struct work_struct *work) +{ + struct tavil_priv *tavil; + struct platform_device *pdev; + struct device_node *node; + struct wcd9xxx *wcd9xxx; + struct tavil_swr_ctrl_data *swr_ctrl_data = NULL, *temp; + int ret, ctrl_num = 0; + struct wcd_swr_ctrl_platform_data *platdata; + char plat_dev_name[WCD934X_STRING_LEN]; + + tavil = container_of(work, struct tavil_priv, + tavil_add_child_devices_work); + if (!tavil) { + pr_err("%s: Memory for WCD934X does not exist\n", + __func__); + return; + } + wcd9xxx = tavil->wcd9xxx; + if (!wcd9xxx) { + pr_err("%s: Memory for WCD9XXX does not exist\n", + __func__); + return; + } + if (!wcd9xxx->dev->of_node) { + dev_err(wcd9xxx->dev, "%s: DT node for wcd9xxx does not exist\n", + __func__); + return; + } + + platdata = &tavil->swr.plat_data; + tavil->child_count = 0; + + for_each_child_of_node(wcd9xxx->dev->of_node, node) { + + /* Parse and add the SPI device node */ + if (!strcmp(node->name, "wcd_spi")) { + tavil_codec_add_spi_device(tavil, node); + continue; + } + + /* Parse other child device nodes and add platform device */ + if (!strcmp(node->name, "swr_master")) + strlcpy(plat_dev_name, "tavil_swr_ctrl", + (WCD934X_STRING_LEN - 1)); + else if (strnstr(node->name, "msm_cdc_pinctrl", + strlen("msm_cdc_pinctrl")) != NULL) + strlcpy(plat_dev_name, node->name, + (WCD934X_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err_mem; + } + pdev->dev.parent = tavil->dev; + pdev->dev.of_node = node; + + if (strcmp(node->name, "swr_master") == 0) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto err_pdev_add; + } + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto err_pdev_add; + } + + if (strcmp(node->name, "swr_master") == 0) { + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct tavil_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(wcd9xxx->dev, "out of memory\n"); + ret = -ENOMEM; + goto err_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Added soundwire ctrl device(s)\n", + __func__); + tavil->swr.ctrl_data = swr_ctrl_data; + } + if (tavil->child_count < WCD934X_CHILD_DEVICES_MAX) + tavil->pdev_child_devices[tavil->child_count++] = pdev; + else + goto err_mem; + } + + return; + +err_pdev_add: + platform_device_put(pdev); +err_mem: + return; +} + +static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil) +{ + int val, rc; + + WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr); + __tavil_cdc_mclk_enable_locked(tavil, true); + + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01); + /* + * 5ms sleep required after enabling efuse control + * before checking the status. + */ + usleep_range(5000, 5500); + wcd_resmgr_set_sido_input_src(tavil->resmgr, + SIDO_SOURCE_RCO_BG); + + WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr); + + rc = regmap_read(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val); + if (rc || (!(val & 0x01))) + WARN(1, "%s: Efuse sense is not complete val=%x, ret=%d\n", + __func__, val, rc); + + __tavil_cdc_mclk_enable(tavil, false); + + return rc; +} + +static void ___tavil_get_codec_fine_version(struct tavil_priv *tavil) +{ + int val1, val2, version; + struct regmap *regmap; + u16 id_minor; + u32 version_mask = 0; + + regmap = tavil->wcd9xxx->regmap; + version = tavil->wcd9xxx->version; + id_minor = tavil->wcd9xxx->codec_type->id_minor; + + regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val1); + regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val2); + + dev_dbg(tavil->dev, "%s: chip version :0x%x 0x:%x\n", + __func__, val1, val2); + + version_mask |= (!!((u8)val1 & 0x80)) << DSD_DISABLED_MASK; + version_mask |= (!!((u8)val2 & 0x01)) << SLNQ_DISABLED_MASK; + + switch (version_mask) { + case DSD_DISABLED | SLNQ_DISABLED: + if (id_minor == cpu_to_le16(0)) + version = TAVIL_VERSION_WCD9340_1_0; + else if (id_minor == cpu_to_le16(0x01)) + version = TAVIL_VERSION_WCD9340_1_1; + break; + case SLNQ_DISABLED: + if (id_minor == cpu_to_le16(0)) + version = TAVIL_VERSION_WCD9341_1_0; + else if (id_minor == cpu_to_le16(0x01)) + version = TAVIL_VERSION_WCD9341_1_1; + break; + } + + tavil->wcd9xxx->version = version; + tavil->wcd9xxx->codec_type->version = version; +} + +/* + * tavil_get_wcd_dsp_cntl: Get the reference to wcd_dsp_cntl + * @dev: Device pointer for codec device + * + * This API gets the reference to codec's struct wcd_dsp_cntl + */ +struct wcd_dsp_cntl *tavil_get_wcd_dsp_cntl(struct device *dev) +{ + struct platform_device *pdev; + struct tavil_priv *tavil; + + if (!dev) { + pr_err("%s: Invalid device\n", __func__); + return NULL; + } + + pdev = to_platform_device(dev); + tavil = platform_get_drvdata(pdev); + + return tavil->wdsp_cntl; +} +EXPORT_SYMBOL(tavil_get_wcd_dsp_cntl); + +static void wcd934x_ssr_disable(struct device *dev, void *data) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev); + struct tavil_priv *tavil; + struct snd_soc_component *component; + int count = 0; + + if (!wcd9xxx) { + dev_dbg(dev, "%s: wcd9xxx pointer NULL.\n", __func__); + return; + } + component = (struct snd_soc_component *)(wcd9xxx->ssr_priv); + tavil = snd_soc_component_get_drvdata(component); + + for (count = 0; count < NUM_CODEC_DAIS; count++) + tavil->dai[count].bus_down_in_recovery = true; +} + +static const struct snd_event_ops wcd934x_ssr_ops = { + .disable = wcd934x_ssr_disable, +}; + +static int tavil_probe(struct platform_device *pdev) +{ + int ret = 0, len = 0; + struct tavil_priv *tavil; + struct clk *wcd_ext_clk; + struct wcd9xxx_resmgr_v2 *resmgr; + struct wcd9xxx_power_region *cdc_pwr; + const __be32 *micb_prop; + + tavil = devm_kzalloc(&pdev->dev, sizeof(struct tavil_priv), + GFP_KERNEL); + if (!tavil) + return -ENOMEM; + + tavil->intf_type = wcd9xxx_get_intf_type(); + if (tavil->intf_type != WCD9XXX_INTERFACE_TYPE_I2C && + tavil->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + devm_kfree(&pdev->dev, tavil); + return -EPROBE_DEFER; + } + + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + if (gpr_get_modem_state() == GPR_SUBSYS_DOWN) { + dev_dbg(&pdev->dev, "%s: dsp down\n", __func__); + devm_kfree(&pdev->dev, tavil); + return -EPROBE_DEFER; + } + } + + platform_set_drvdata(pdev, tavil); + + tavil->wcd9xxx = dev_get_drvdata(pdev->dev.parent); + tavil->dev = &pdev->dev; + INIT_DELAYED_WORK(&tavil->power_gate_work, tavil_codec_power_gate_work); + mutex_init(&tavil->power_lock); + INIT_WORK(&tavil->tavil_add_child_devices_work, + tavil_add_child_devices); + mutex_init(&tavil->micb_lock); + mutex_init(&tavil->swr.read_mutex); + mutex_init(&tavil->swr.write_mutex); + mutex_init(&tavil->swr.clk_mutex); + mutex_init(&tavil->codec_mutex); + mutex_init(&tavil->svs_mutex); + + /* + * Codec hardware by default comes up in SVS mode. + * Initialize the svs_ref_cnt to 1 to reflect the hardware + * state in the driver. + */ + tavil->svs_ref_cnt = 1; + + cdc_pwr = devm_kzalloc(&pdev->dev, sizeof(struct wcd9xxx_power_region), + GFP_KERNEL); + if (!cdc_pwr) { + ret = -ENOMEM; + goto err_resmgr; + } + tavil->wcd9xxx->wcd9xxx_pwr[WCD9XXX_DIG_CORE_REGION_1] = cdc_pwr; + cdc_pwr->pwr_collapse_reg_min = WCD934X_DIG_CORE_REG_MIN; + cdc_pwr->pwr_collapse_reg_max = WCD934X_DIG_CORE_REG_MAX; + wcd9xxx_set_power_state(tavil->wcd9xxx, + WCD_REGION_POWER_COLLAPSE_REMOVE, + WCD9XXX_DIG_CORE_REGION_1); + /* + * Init resource manager so that if child nodes such as SoundWire + * requests for clock, resource manager can honor the request + */ + resmgr = wcd_resmgr_init(&tavil->wcd9xxx->core_res, NULL); + if (IS_ERR(resmgr)) { + ret = PTR_ERR(resmgr); + dev_err(&pdev->dev, "%s: Failed to initialize wcd resmgr\n", + __func__); + goto err_resmgr; + } + tavil->resmgr = resmgr; + tavil->swr.plat_data.handle = (void *) tavil; + tavil->swr.plat_data.read = tavil_swrm_read; + tavil->swr.plat_data.write = tavil_swrm_write; + tavil->swr.plat_data.bulk_write = tavil_swrm_bulk_write; + tavil->swr.plat_data.clk = tavil_swrm_clock; + tavil->swr.plat_data.handle_irq = tavil_swrm_handle_irq; + tavil->swr.spkr_gain_offset = WCD934X_RX_GAIN_OFFSET_0_DB; + + /* Register for Clock */ + wcd_ext_clk = clk_get(tavil->wcd9xxx->dev, "wcd_clk"); + if (IS_ERR(wcd_ext_clk)) { + dev_err(tavil->wcd9xxx->dev, "%s: clk get %s failed\n", + __func__, "wcd_ext_clk"); + goto err_clk; + } + tavil->wcd_ext_clk = wcd_ext_clk; + set_bit(AUDIO_NOMINAL, &tavil->status_mask); + /* Update codec register default values */ + dev_dbg(&pdev->dev, "%s: MCLK Rate = %x\n", __func__, + tavil->wcd9xxx->mclk_rate); + if (tavil->wcd9xxx->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ) + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x00); + else if (tavil->wcd9xxx->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ) + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x01); + tavil_update_reg_defaults(tavil); + __tavil_enable_efuse_sensing(tavil); + ___tavil_get_codec_fine_version(tavil); + tavil_update_cpr_defaults(tavil); + + /* Register with soc framework */ + if (tavil->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) + ret = snd_soc_register_component(&pdev->dev, + &soc_codec_dev_tavil, + tavil_i2s_dai, + ARRAY_SIZE(tavil_i2s_dai)); + else + ret = snd_soc_register_component(&pdev->dev, + &soc_codec_dev_tavil, + tavil_slim_dai, + ARRAY_SIZE(tavil_slim_dai)); + + if (ret) { + dev_err(&pdev->dev, "%s: Codec registration failed\n", + __func__); + goto err_cdc_reg; + } + schedule_work(&tavil->tavil_add_child_devices_work); + + ret = snd_event_client_register(pdev->dev.parent, + &wcd934x_ssr_ops, NULL); + if (!ret) { + snd_event_notify(pdev->dev.parent, SND_EVENT_UP); + } else { + pr_err("%s: Registration with SND event fwk failed ret = %d\n", + __func__, ret); + ret = 0; + } + + tavil->micb_load = NULL; + + if (of_get_property(tavil->wcd9xxx->dev->of_node, + "qcom,vreg-micb-supply", NULL)) { + micb_prop = of_get_property(tavil->wcd9xxx->dev->of_node, + "qcom,cdc-vdd-mic-bias-current", + &len); + if (!micb_prop || (len != (2 * sizeof(__be32)))) { + tavil->micb_load_low = MICB_LOAD_DEFAULT; + tavil->micb_load_high = MICB_LOAD_DEFAULT; + } else { + tavil->micb_load_low = be32_to_cpup(&micb_prop[0]); + tavil->micb_load_high = be32_to_cpup(&micb_prop[1]); + } + tavil->micb_load = regulator_get(&pdev->dev, MICB_LOAD_PROP); + if (IS_ERR(tavil->micb_load)) + dev_dbg(tavil->dev, "%s micb load get failed\n", + __func__); + } + + return ret; + +err_cdc_reg: + clk_put(tavil->wcd_ext_clk); +err_clk: + wcd_resmgr_remove(tavil->resmgr); +err_resmgr: + mutex_destroy(&tavil->micb_lock); + mutex_destroy(&tavil->svs_mutex); + mutex_destroy(&tavil->codec_mutex); + mutex_destroy(&tavil->swr.read_mutex); + mutex_destroy(&tavil->swr.write_mutex); + mutex_destroy(&tavil->swr.clk_mutex); + devm_kfree(&pdev->dev, tavil); + + return ret; +} + +static int tavil_remove(struct platform_device *pdev) +{ + struct tavil_priv *tavil; + int count = 0; + + tavil = platform_get_drvdata(pdev); + if (!tavil) + return -EINVAL; + + /* do dsd deinit before codec->component->regmap becomes freed */ + if (tavil->dsd_config) { + tavil_dsd_deinit(tavil->dsd_config); + tavil->dsd_config = NULL; + } + + snd_event_client_deregister(pdev->dev.parent); + + if (tavil->spi) + spi_unregister_device(tavil->spi); + for (count = 0; count < tavil->child_count && + count < WCD934X_CHILD_DEVICES_MAX; count++) + platform_device_unregister(tavil->pdev_child_devices[count]); + + if (tavil->micb_load) + regulator_put(tavil->micb_load); + + mutex_destroy(&tavil->micb_lock); + mutex_destroy(&tavil->svs_mutex); + mutex_destroy(&tavil->codec_mutex); + mutex_destroy(&tavil->swr.read_mutex); + mutex_destroy(&tavil->swr.write_mutex); + mutex_destroy(&tavil->swr.clk_mutex); + + snd_soc_unregister_component(&pdev->dev); + clk_put(tavil->wcd_ext_clk); + wcd_resmgr_remove(tavil->resmgr); + devm_kfree(&pdev->dev, tavil); + return 0; +} + +static struct platform_driver tavil_codec_driver = { + .probe = tavil_probe, + .remove = tavil_remove, + .driver = { + .name = "tavil_codec", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &tavil_pm_ops, +#endif + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(tavil_codec_driver); + +MODULE_DESCRIPTION("Tavil Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x.h new file mode 100644 index 0000000000..f2924cd14d --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x.h @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ +#ifndef WCD934X_H +#define WCD934X_H + +#include +#include "wcd934x-dsp-cntl.h" +#include +#include +#include + +#define WCD934X_DRV_NAME "tavil_codec" + +#define WCD934X_REGISTER_START_OFFSET 0x800 +#define WCD934X_SB_PGD_PORT_RX_BASE 0x40 +#define WCD934X_SB_PGD_PORT_TX_BASE 0x50 +#define WCD934X_RX_PORT_START_NUMBER 16 + +#define WCD934X_DMIC_CLK_DIV_2 0x0 +#define WCD934X_DMIC_CLK_DIV_3 0x1 +#define WCD934X_DMIC_CLK_DIV_4 0x2 +#define WCD934X_DMIC_CLK_DIV_6 0x3 +#define WCD934X_DMIC_CLK_DIV_8 0x4 +#define WCD934X_DMIC_CLK_DIV_16 0x5 +#define WCD934X_DMIC_CLK_DRIVE_DEFAULT 0x02 + +#define WCD934X_ANC_DMIC_X2_FULL_RATE 1 +#define WCD934X_ANC_DMIC_X2_HALF_RATE 0 + +#define TAVIL_MAX_MICBIAS 4 +#define TAVIL_NUM_INTERPOLATORS 9 +#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64 + +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) + +/* Feature masks to distinguish codec version */ +#define DSD_DISABLED_MASK 0 +#define SLNQ_DISABLED_MASK 1 + +#define DSD_DISABLED (1 << DSD_DISABLED_MASK) +#define SLNQ_DISABLED (1 << SLNQ_DISABLED_MASK) + +/* Number of input and output Slimbus port */ +enum { + WCD934X_RX0 = 0, + WCD934X_RX1, + WCD934X_RX2, + WCD934X_RX3, + WCD934X_RX4, + WCD934X_RX5, + WCD934X_RX6, + WCD934X_RX7, + WCD934X_RX_MAX, +}; + +enum { + WCD934X_TX0 = 0, + WCD934X_TX1, + WCD934X_TX2, + WCD934X_TX3, + WCD934X_TX4, + WCD934X_TX5, + WCD934X_TX6, + WCD934X_TX7, + WCD934X_TX8, + WCD934X_TX9, + WCD934X_TX10, + WCD934X_TX11, + WCD934X_TX12, + WCD934X_TX13, + WCD934X_TX14, + WCD934X_TX15, + WCD934X_TX_MAX, +}; + +enum { + INTERP_EAR = 0, + INTERP_HPHL, + INTERP_HPHR, + INTERP_LO1, + INTERP_LO2, + INTERP_LO3_NA, /* LO3 not avalible in Tavil*/ + INTERP_LO4_NA, + INTERP_SPKR1, + INTERP_SPKR2, + INTERP_MAX, +}; + +/* + * Selects compander and smart boost settings + * for a given speaker mode + */ +enum { + WCD934X_SPKR_MODE_DEFAULT, + WCD934X_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */ +}; + +/* + * Rx path gain offsets + */ +enum { + WCD934X_RX_GAIN_OFFSET_M1P5_DB, + WCD934X_RX_GAIN_OFFSET_0_DB, +}; + +/* + * Dai data structure holds the + * dai specific info like rate, + * channel number etc. + */ +struct tavil_codec_dai_data { + u32 rate; + u32 *ch_num; + u32 ch_act; + u32 ch_tot; +}; + +/* + * Structure used to update codec + * register defaults after reset + */ +struct tavil_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD934X) +extern void *tavil_get_afe_config(struct snd_soc_component *component, + enum afe_config_type config_type); +extern int tavil_cdc_mclk_enable(struct snd_soc_component *component, + bool enable); +extern int tavil_cdc_mclk_tx_enable(struct snd_soc_component *component, + bool enable); +extern int tavil_set_spkr_mode(struct snd_soc_component *component, int mode); +extern int tavil_set_spkr_gain_offset(struct snd_soc_component *component, + int offset); +extern struct wcd_dsp_cntl *tavil_get_wcd_dsp_cntl(struct device *dev); +extern int wcd934x_get_micb_vout_ctl_val(u32 micb_mv); +extern int tavil_micbias_control(struct snd_soc_component *component, + int micb_num, + int req, bool is_dapm); +extern int tavil_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, + int micb_num); +extern struct wcd934x_mbhc *tavil_soc_get_mbhc( + struct snd_soc_component *component); +extern int tavil_codec_enable_interp_clk(struct snd_soc_component *component, + int event, int intp_idx); +extern struct tavil_dsd_config *tavil_get_dsd_config( + struct snd_soc_component *component); +extern int tavil_codec_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component); +#else +extern void *tavil_get_afe_config(struct snd_soc_component *component, + enum afe_config_type config_type) +{ + return NULL; +} +extern int tavil_cdc_mclk_enable(struct snd_soc_component *component, + bool enable) +{ + return 0; +} +extern int tavil_cdc_mclk_tx_enable(struct snd_soc_component *component, + bool enable) +{ + return 0; +} +extern int tavil_set_spkr_mode(struct snd_soc_component *component, int mode) +{ + return 0; +} +extern int tavil_set_spkr_gain_offset(struct snd_soc_component *component, + int offset) +{ + return 0; +} +extern struct wcd_dsp_cntl *tavil_get_wcd_dsp_cntl(struct device *dev) +{ + return NULL; +} +extern int wcd934x_get_micb_vout_ctl_val(u32 micb_mv) +{ + return 0; +} +extern int tavil_micbias_control(struct snd_soc_component *component, + int micb_num, + int req, bool is_dapm) +{ + return 0; +} +extern int tavil_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, + int micb_num) +{ + return 0; +} +extern struct wcd934x_mbhc *tavil_soc_get_mbhc( + struct snd_soc_component *component) +{ + return NULL; +} +extern int tavil_codec_enable_interp_clk(struct snd_soc_component *component, + int event, int intp_idx) +{ + return 0; +} +extern struct tavil_dsd_config *tavil_get_dsd_config( + struct snd_soc_component *component) +{ + return NULL; +} +extern int tavil_codec_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} + +#endif + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x_irq.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x_irq.h new file mode 100644 index 0000000000..b880e97f20 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/wcd934x_irq.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD934X_IRQ_H_ +#define __WCD934X_IRQ_H_ + +enum { + /* INTR_REG 0 */ + WCD934X_IRQ_MISC = 1, + WCD934X_IRQ_HPH_PA_OCPL_FAULT, + WCD934X_IRQ_HPH_PA_OCPR_FAULT, + WCD934X_IRQ_EAR_PA_OCP_FAULT, + WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, + WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, + WCD934X_IRQ_EAR_PA_CNP_COMPLETE, + /* INTR_REG 1 */ + WCD934X_IRQ_MBHC_SW_DET, + WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, + WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD934X_IRQ_RESERVED_0, + WCD934X_IRQ_RESERVED_1, + WCD934X_IRQ_RESERVED_2, + /* INTR_REG 2 */ + WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, + WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, + WCD934X_IRQ_SLNQ_ANALOG_ERROR, + WCD934X_IRQ_RESERVED_3, + WCD934X_IRQ_SOUNDWIRE, + WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, + WCD934X_IRQ_RCO_ERROR, + WCD934X_IRQ_CPE_ERROR, + /* INTR_REG 3 */ + WCD934X_IRQ_MAD_AUDIO, + WCD934X_IRQ_MAD_BEACON, + WCD934X_IRQ_MAD_ULTRASOUND, + WCD934X_IRQ_VBAT_ATTACK, + WCD934X_IRQ_VBAT_RESTORE, + WCD934X_IRQ_CPE1_INTR, + WCD934X_IRQ_RESERVED_4, + WCD934X_IRQ_SLNQ_DIGITAL, + WCD934X_NUM_IRQS, +}; + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/Kbuild new file mode 100644 index 0000000000..a2e9200fe8 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/Kbuild @@ -0,0 +1,125 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_KALAMA), y) + include $(AUDIO_ROOT)/config/kalamaauto.conf + INCS += -include $(AUDIO_ROOT)/config/kalamaautoconf.h + endif + ifeq ($(CONFIG_ARCH_PINEAPPLE), y) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.h + endif + ifeq ($(CONFIG_ARCH_PITTI), y) + include $(AUDIO_ROOT)/config/pittiauto.conf + INCS += -include $(AUDIO_ROOT)/config/pittiautoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ WCD9378 ############ + +# for WCD9378 Codec +ifdef CONFIG_SND_SOC_WCD9378 + WCD9378_OBJS += wcd9378.o + WCD9378_OBJS += wcd9378-regmap.o + WCD9378_OBJS += wcd9378-tables.o + WCD9378_OBJS += wcd9378-mbhc.o +endif + +ifdef CONFIG_SND_SOC_WCD9378_SLAVE + WCD9378_SLAVE_OBJS += wcd9378-slave.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +ccflags-y += $(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) +ccflags-y += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +ccflags-y += -Wheader-guard +endif + + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_WCD9378) += wcd9378_dlkm.o +wcd9378_dlkm-y := $(WCD9378_OBJS) + +obj-$(CONFIG_SND_SOC_WCD9378_SLAVE) += wcd9378_slave_dlkm.o +wcd9378_slave_dlkm-y := $(WCD9378_SLAVE_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/Makefile b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/internal.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/internal.h new file mode 100644 index 0000000000..9465a41f2c --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/internal.h @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _WCD9378_INTERNAL_H +#define _WCD9378_INTERNAL_H + +#include +#include +#include +#include +#include "wcd9378-mbhc.h" +#include "wcd9378.h" + +#define SWR_SCP_CONTROL 0x44 +#define SWR_SCP_HOST_CLK_DIV2_CTL_BANK 0xE0 +#define WCD9378_MAX_MICBIAS 3 +#define SIM_MIC_NUM 3 + + +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) +#define MAX_PORT 8 +#define MAX_CH_PER_PORT 8 +#define TX_ADC_MAX 3 +#define SWR_NUM_PORTS 4 + +enum { + TX_HDR12 = 0, + TX_HDR34, + TX_HDR_MAX, +}; + +enum { + SIM_MIC0, + SIM_MIC1, + SIM_MIC2, + SIM_JACK, + MICB_VAL_NUM, +}; + +extern struct regmap_config wcd9378_regmap_config; + +struct codec_port_info { + u32 slave_port_type; + u32 master_port_type; + u32 ch_mask; + u32 num_ch; + u32 ch_rate; +}; + +enum { + RX_CLK_9P6MHZ, + RX_CLK_12P288MHZ, + RX_CLK_11P2896MHZ, +}; + +enum { + RX_PATH, + TX_PATH, +}; + +struct wcd9378_priv { + struct device *dev; + u32 sys_usage; + /* to track the sys_usage status */ + unsigned long sys_usage_status; + u32 wcd_mode; + + 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[WCD9378_MAX_MICBIAS]; + s32 pullup_ref[WCD9378_MAX_MICBIAS]; + + u32 micb_sel[SIM_MIC_NUM]; + u32 micb_val[MICB_VAL_NUM]; + + struct device_node *wcd_rst_np; + + struct mutex micb_lock; + struct mutex wakeup_lock; + struct mutex sys_usage_lock; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + int hdr_en[TX_HDR_MAX]; + /* class h specific info */ + struct wcd_clsh_cdc_info clsh_info; + /* mbhc module */ + struct wcd9378_mbhc *mbhc; + + u32 hph_mode; + u16 hph_gain; + u32 curr_micbias2; + u32 rx2_clk_mode; + u32 tx_mode[TX_ADC_MAX]; + s32 adc_count; + bool comp1_enable; + bool comp2_enable; + bool ldoh; + bool bcs_dis; + bool dapm_bias_off; + 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 swr_port_params tx_port_params[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config swr_tx_port_params[SWR_UC_MAX]; + 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); + int (*wakeup)(void *handle, bool enable); + u32 version; + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + struct snd_info_entry *variant_entry; + int flyback_cur_det_disable; + u8 tx_master_ch_map[WCD9378_MAX_SLAVE_CH_TYPES]; + bool usbc_hs_status; + /* wcd to swr dmic notification */ + bool notify_swr_dmic; + u8 rx_swrclk; + u8 rx_clkscale; + u8 tx_swrclk; + u8 tx_clkscale; + struct blocking_notifier_head notifier; +}; + +struct wcd9378_micbias_setting { + u8 ldoh_v; + u32 cfilt1_mv; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u32 micb1_usage_val; + u32 micb2_usage_val; + u32 micb3_usage_val; + + u8 bias1_cfilt_sel; +}; + +struct wcd9378_pdata { + struct device_node *rst_np; + struct device_node *rx_slave; + struct device_node *tx_slave; + struct wcd9378_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 { + /* INTR_CTRL_INT_MASK_0 */ + WCD9378_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD9378_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD9378_IRQ_MBHC_ELECT_INS_REM_DET, + WCD9378_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD9378_IRQ_MBHC_SW_DET, + WCD9378_IRQ_HPHR_OCP_INT, + WCD9378_IRQ_HPHR_CNP_INT, + WCD9378_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD9378_IRQ_HPHL_CNP_INT, + WCD9378_IRQ_EAR_CNP_INT, + WCD9378_IRQ_EAR_SCD_INT, + WCD9378_IRQ_AUX_CNP_INT, + WCD9378_IRQ_AUX_SCD_INT, + WCD9378_IRQ_HPHL_PDM_WD_INT, + WCD9378_IRQ_HPHR_PDM_WD_INT, + WCD9378_IRQ_AUX_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD9378_IRQ_LDORT_SCD_INT, + WCD9378_IRQ_MBHC_MOISTURE_INT, + WCD9378_IRQ_HPHL_SURGE_DET_INT, + WCD9378_IRQ_HPHR_SURGE_DET_INT, + WCD9378_IRQ_SAPU_PROT_MODE_CHG, + WCD9378_NUM_IRQS, +}; + +extern struct wcd9378_mbhc *wcd9378_soc_get_mbhc( + struct snd_soc_component *component); +extern void wcd9378_disable_bcs_before_slow_insert( + struct snd_soc_component *component, + bool bcs_disable); +extern int wcd9378_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int volt, int micb_num); +extern int wcd9378_get_micb_vout_ctl_val(u32 micb_mv); +extern int wcd9378_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm); +#endif /* _WCD9378_INTERNAL_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-mbhc.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-mbhc.c new file mode 100644 index 0000000000..59902ec494 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-mbhc.c @@ -0,0 +1,1188 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd9378-registers.h" +#include "internal.h" + +#define WCD9378_ZDET_SUPPORTED true +/* Z value defined in milliohm */ +#define WCD9378_ZDET_VAL_0 0 +#define WCD9378_ZDET_VAL_32 32000 +#define WCD9378_ZDET_VAL_400 400000 +#define WCD9378_ZDET_VAL_2500 2500000 +#define WCD9378_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define WCD9378_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define WCD9378_ZDET_NUM_MEASUREMENTS 900 +#define WCD9378_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define WCD9378_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD9378_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define WCD9378_MBHC_ZDET_CONST (86 * 16384) +#define WCD9378_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", + WCD9378_ANA_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + WCD9378_ANA_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + WCD9378_ANA_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + WCD9378_MBHC_NEW_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + WCD9378_ANA_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + WCD9378_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + WCD9378_ANA_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + WCD9378_ANA_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + WCD9378_ANA_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + WCD9378_ANA_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + WCD9378_ANA_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + WCD9378_ANA_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + WCD9378_MBHC_NEW_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + WCD9378_MBHC_NEW_CTL_1, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + WCD9378_MBHC_NEW_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + WCD9378_ANA_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE", + WCD9378_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + WCD9378_ANA_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + WCD9378_ANA_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + WCD9378_ANA_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + WCD9378_HPH_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + WCD9378_ANA_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + WCD9378_ANA_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + WCD9378_ANA_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + WCD9378_ANA_MICB2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + WCD9378_HPH_CNP_WG_TIME, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + WCD9378_ANA_HPH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + WCD9378_ANA_HPH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + WCD9378_ANA_HPH, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + WCD9378_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", + WCD9378_MBHC_CTL_BCS, 0x02, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + WCD9378_MBHC_NEW_FSM_STATUS, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + WCD9378_MBHC_NEW_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD9378_MBHC_NEW_FSM_STATUS, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD9378_HPH_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD9378_HPH_PA_CTL2, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", + WCD9378_HPH_L_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN", + WCD9378_HPH_R_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS", + SWRS_SCP_SDCA_INTSTAT_1, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS", + SWRS_SCP_SDCA_INTSTAT_1, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN", + WCD9378_MBHC_NEW_CTL_1, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD9378_MBHC_NEW_FSM_STATUS, + 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD9378_MBHC_NEW_FSM_STATUS, + 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD9378_MBHC_NEW_ADC_RESULT, + 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD9378_ANA_MICB2, 0x3F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE", + WCD9378_MBHC_NEW_CTL_1, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE", + WCD9378_MBHC_NEW_CTL_1, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN", + WCD9378_ANA_MBHC_ZDET, 0x02, 1, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = WCD9378_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = WCD9378_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = WCD9378_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = WCD9378_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = WCD9378_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = WCD9378_IRQ_HPHL_OCP_INT, + .hph_right_ocp = WCD9378_IRQ_HPHR_OCP_INT, +}; + +struct wcd9378_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static int wcd9378_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct wcd9378_priv *wcd9378 = dev_get_drvdata(component->dev); + + return wcd_request_irq(&wcd9378->irq_info, irq, name, handler, data); +} + +static void wcd9378_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct wcd9378_priv *wcd9378 = dev_get_drvdata(component->dev); + + if (enable) + wcd_enable_irq(&wcd9378->irq_info, irq); + else + wcd_disable_irq(&wcd9378->irq_info, irq); +} + +static int wcd9378_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct wcd9378_priv *wcd9378 = dev_get_drvdata(component->dev); + + wcd_free_irq(&wcd9378->irq_info, irq, data); + + return 0; +} + +static void wcd9378_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD9378_MBHC_NEW_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, WCD9378_MBHC_NEW_CTL_1, + 0x80, 0x00); +} + +static int wcd9378_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read(component, WCD9378_ANA_MBHC_RESULT_3) & 0x7; +} + +static void wcd9378_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_ELECT, + 0x01, 0x00); +} + +static void wcd9378_mbhc_get_micbias_val(struct wcd_mbhc *mbhc, + int *mb) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd9378_priv *wcd9378 = dev_get_drvdata(component->dev); + + *mb = wcd9378->curr_micbias2; +} + +static void wcd9378_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, WCD9378_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 wcd9378_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd9378_priv *wcd9378 = dev_get_drvdata(component->dev); + + wcd9378->wakeup((void *)wcd9378, lock); + + return true; +} + +static int wcd9378_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct wcd9378_mbhc *wcd9378_mbhc; + + wcd9378_mbhc = container_of(mbhc, struct wcd9378_mbhc, wcd_mbhc); + + if (enable) + return blocking_notifier_chain_register(&wcd9378_mbhc->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd9378_mbhc->notifier, nblock); +} + +static bool wcd9378_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd9378_priv *wcd9378 = + dev_get_drvdata(component->dev); + + if (micb_num == MIC_BIAS_2) { + if (wcd9378->curr_micbias2) + return true; + } + return false; +} + +static bool wcd9378_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + if (snd_soc_component_read(component, WCD9378_PDE47_ACT_PS)) + return false; + else + return true; +} + +static void wcd9378_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, + WCD9378_MBHC_NEW_INT_MECH_DET_CURRENT, + 0x1F, pull_up_cur); +} + +static int wcd9378_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + return wcd9378_micbias_control(component, micb_num, req, false); +} + +static void wcd9378_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD9378_ANA_MICB2_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, WCD9378_ANA_MICB2_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, WCD9378_ANA_MICB2_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD9378_ANA_MICB2_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *wcd9378_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct wcd9378_mbhc *wcd9378_mbhc; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + wcd9378_mbhc = container_of(mbhc, struct wcd9378_mbhc, wcd_mbhc); + + if (!component) { + pr_err("%s: NULL component pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(wcd9378_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 wcd9378_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd9378_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 = wcd9378_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + + return rc; +} + +static inline void wcd9378_mbhc_get_result_params(struct wcd9378_priv *wcd9378, + 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(wcd9378->regmap, WCD9378_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < WCD9378_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd9378->regmap, WCD9378_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd9378->regmap, WCD9378_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(wcd9378->regmap, WCD9378_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = WCD9378_MBHC_GET_X1(val); + c1 = WCD9378_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(wcd9378->dev, + "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", + __func__, c1, x1); + *zdet = WCD9378_ZDET_VAL_0; + goto ramp_down; + } + d1 = d1_a[c1]; + denom = (x1 * d1) - (1 << (14 - noff)); + if (denom > 0) + *zdet = (WCD9378_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = WCD9378_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(wcd9378->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(wcd9378->regmap, + WCD9378_ANA_MBHC_RESULT_1, &val); + regmap_read(wcd9378->regmap, + WCD9378_ANA_MBHC_RESULT_2, &val1); + val = val << 0x08; + val |= val1; + x1 = WCD9378_MBHC_GET_X1(val); + i++; + if (i == WCD9378_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void wcd9378_mbhc_zdet_ramp(struct snd_soc_component *component, + struct wcd9378_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct wcd9378_priv *wcd9378 = dev_get_drvdata(component->dev); + int32_t zdet = 0; + + snd_soc_component_update_bits(component, WCD9378_MBHC_NEW_ZDET_ANA_CTL, + 0x70, zdet_param->ldo_ctl << 4); + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_BTN5, 0xFC, + zdet_param->btn5); + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_BTN6, 0xFC, + zdet_param->btn6); + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_BTN7, 0xFC, + zdet_param->btn7); + snd_soc_component_update_bits(component, WCD9378_MBHC_NEW_ZDET_ANA_CTL, + 0x0F, zdet_param->noff); + snd_soc_component_update_bits(component, WCD9378_MBHC_NEW_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_ZDET, 0x80, 0x80); + dev_dbg(wcd9378->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + wcd9378_mbhc_get_result_params(wcd9378, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_ZDET, 0x40, 0x40); + dev_dbg(wcd9378->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + wcd9378_mbhc_get_result_params(wcd9378, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void wcd9378_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 < (WCD9378_ZDET_VAL_400/1000)) + q1 = snd_soc_component_read(component, + WCD9378_EFUSE_REG_23 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read(component, + WCD9378_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 wcd9378_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd9378_priv *wcd9378 = 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 wcd9378_mbhc_zdet_param zdet_param[] = { + {4, 0, 4, 0x08, 0x14, 0x18}, /* 0ohm < Z < 32ohm */ + {2, 0, 3, 0x20, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ + {2, 4, 6, 0x20, 0x7C, 0x90}, /* 400ohm < Z < 2500ohm */ + {2, 5, 7, 0x20, 0x7C, 0x90}, /* >2500ohm or < 0ohm */ + }; + struct wcd9378_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_read(component, WCD9378_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read(component, WCD9378_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read(component, WCD9378_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read(component, WCD9378_MBHC_CTL_CLK); + reg4 = snd_soc_component_read(component, WCD9378_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read(component, WCD9378_ANA_MBHC_ELECT) & 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_MECH, 0x01, 0x00); + + /* Disable surge protection before impedance detection. + * This is done to give correct value for high impedance. + */ + regmap_update_bits(wcd9378->regmap, + WCD9378_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00); + /* 1ms delay needed after disable surge protection */ + usleep_range(1000, 1010); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + wcd9378_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + + if (!WCD9378_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) + goto left_ch_impedance; + + /* Second ramp for left ch */ + if ((z1L < WCD9378_ZDET_VAL_32) && + (z1L >= WCD9378_ZDET_VAL_0)) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1L > WCD9378_ZDET_VAL_400) && + (z1L <= WCD9378_ZDET_VAL_2500)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if ((z1L > WCD9378_ZDET_VAL_2500) || + (z1L < WCD9378_ZDET_VAL_0)) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd9378_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + +left_ch_impedance: + if ((z1L == WCD9378_ZDET_FLOATING_IMPEDANCE) || + (z1L > WCD9378_ZDET_VAL_100K)) { + *zl = WCD9378_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1L/1000; + wcd9378_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 */ + wcd9378_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if (WCD9378_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { + if ((((z1R > WCD9378_ZDET_VAL_2500) || + (z1R < WCD9378_ZDET_VAL_0)) && + (zdet_param_ptr->noff == 0x6)) || + ((*zl) != WCD9378_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* Second ramp for right ch */ + if ((z1R < WCD9378_ZDET_VAL_32) && + (z1R >= WCD9378_ZDET_VAL_0)) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1R > WCD9378_ZDET_VAL_400) && + (z1R <= WCD9378_ZDET_VAL_2500)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if ((z1L > WCD9378_ZDET_VAL_2500) || + (z1L < WCD9378_ZDET_VAL_0)) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd9378_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + } +right_ch_impedance: + if ((z1R == WCD9378_ZDET_FLOATING_IMPEDANCE) || + (z1R > WCD9378_ZDET_VAL_100K)) { + *zr = WCD9378_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R/1000; + wcd9378_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 == WCD9378_ZDET_FLOATING_IMPEDANCE) && + (*zr == WCD9378_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == WCD9378_ZDET_FLOATING_IMPEDANCE) || + (*zr == WCD9378_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, WCD9378_HPH_R_ATEST, 0x01, 0x01); + snd_soc_component_update_bits(component, WCD9378_HPH_PA_CTL2, 0x40, 0x01); + if (*zl < (WCD9378_ZDET_VAL_32/1000)) + wcd9378_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls, NULL, d1); + else + wcd9378_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls, NULL, d1); + snd_soc_component_update_bits(component, WCD9378_HPH_PA_CTL2, 0x40, 0x00); + snd_soc_component_update_bits(component, WCD9378_HPH_R_ATEST, 0x01, 0x00); + z1Ls /= 1000; + wcd9378_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; + } + + /* Enable surge protection again after impedance detection */ + regmap_update_bits(wcd9378->regmap, + WCD9378_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); +zdet_complete: + snd_soc_component_write(component, WCD9378_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD9378_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD9378_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD9378_MBHC_NEW_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD9378_MBHC_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd9378->regmap, + WCD9378_ANA_MBHC_ELECT, 0x80, 0x80); +} + +static void wcd9378_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_MECH, + 0x02, 0x00); + } +} + +static void wcd9378_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD9378_HPH_PA_CTL2, + 0x40, 0x40); + snd_soc_component_update_bits(component, WCD9378_HPH_PA_CTL2, + 0x10, 0x10); + } else { + snd_soc_component_update_bits(component, WCD9378_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD9378_HPH_PA_CTL2, + 0x10, 0x00); + } +} + +static void wcd9378_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, WCD9378_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, WCD9378_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + snd_soc_component_update_bits(component, WCD9378_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); +} + +static void wcd9378_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, WCD9378_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); + else + snd_soc_component_update_bits(component, WCD9378_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); +} + +static bool wcd9378_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, WCD9378_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, WCD9378_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_read(component, WCD9378_MBHC_NEW_CTL_2) & 0x0C)) + goto done; + + wcd9378_mbhc_moisture_detect_en(mbhc, true); + /* Read moisture comparator status */ + ret = ((snd_soc_component_read(component, WCD9378_MBHC_NEW_FSM_STATUS) + & 0x20) ? 0 : 1); + +done: + return ret; + +} + +static void wcd9378_mbhc_moisture_polling_ctrl(struct wcd_mbhc *mbhc, + bool enable) +{ + struct snd_soc_component *component = mbhc->component; + + snd_soc_component_update_bits(component, + WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, + 0x04, (enable << 2)); +} + +static void wcd9378_mbhc_bcs_enable(struct wcd_mbhc *mbhc, + bool bcs_enable) +{ + if (bcs_enable) + wcd9378_disable_bcs_before_slow_insert(mbhc->component, false); + else + wcd9378_disable_bcs_before_slow_insert(mbhc->component, true); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = wcd9378_mbhc_request_irq, + .irq_control = wcd9378_mbhc_irq_control, + .free_irq = wcd9378_mbhc_free_irq, + .clk_setup = wcd9378_mbhc_clk_setup, + .map_btn_code_to_num = wcd9378_mbhc_btn_to_num, + .mbhc_bias = wcd9378_mbhc_mbhc_bias_control, + .get_micbias_val = wcd9378_mbhc_get_micbias_val, + .set_btn_thr = wcd9378_mbhc_program_btn_thr, + .lock_sleep = wcd9378_mbhc_lock_sleep, + .register_notifier = wcd9378_mbhc_register_notifier, + .micbias_enable_status = wcd9378_mbhc_micb_en_status, + .hph_pa_on_status = wcd9378_mbhc_hph_pa_on_status, + .hph_pull_up_control_v2 = wcd9378_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = wcd9378_mbhc_request_micbias, + .mbhc_micb_ramp_control = wcd9378_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = wcd9378_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = wcd9378_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = wcd9378_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = wcd9378_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = wcd9378_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = wcd9378_mbhc_moisture_config, + .mbhc_get_moisture_status = wcd9378_mbhc_get_moisture_status, + .mbhc_moisture_polling_ctrl = wcd9378_mbhc_moisture_polling_ctrl, + .mbhc_moisture_detect_en = wcd9378_mbhc_moisture_detect_en, + .bcs_enable = wcd9378_mbhc_bcs_enable, +}; + +static int wcd9378_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_mbhc *wcd9378_mbhc = wcd9378_soc_get_mbhc(component); + struct wcd_mbhc *mbhc; + + if (!wcd9378_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + + mbhc = &wcd9378_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 wcd9378_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 wcd9378_mbhc *wcd9378_mbhc = wcd9378_soc_get_mbhc(component); + + if (!wcd9378_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(&wcd9378_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, + wcd9378_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + wcd9378_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + wcd9378_hph_impedance_get, NULL), +}; + +/* + * wcd9378_mbhc_get_impedance: get impedance of headphone + * left and right channels + * @wcd9378_mbhc: handle to struct wcd9378_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 wcd9378_mbhc_get_impedance(struct wcd9378_mbhc *wcd9378_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (!wcd9378_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(&wcd9378_mbhc->wcd_mbhc, zl, zr); +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_get_impedance); + +/* + * wcd9378_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 wcd9378_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct wcd9378_priv *wcd9378 = NULL; + struct wcd9378_mbhc *wcd9378_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd9378 = snd_soc_component_get_drvdata(component); + if (!wcd9378) { + pr_err("%s: wcd9378 is NULL\n", __func__); + return -EINVAL; + } + + wcd9378_mbhc = wcd9378->mbhc; + if (!wcd9378_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + + return wcd_mbhc_start(&wcd9378_mbhc->wcd_mbhc, mbhc_cfg); +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_hs_detect); + +/* + * wcd9378_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void wcd9378_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = NULL; + struct wcd9378_mbhc *wcd9378_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + wcd9378 = snd_soc_component_get_drvdata(component); + if (!wcd9378) { + pr_err("%s: wcd9378 is NULL\n", __func__); + return; + } + + wcd9378_mbhc = wcd9378->mbhc; + if (!wcd9378_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", __func__); + return; + } + wcd_mbhc_stop(&wcd9378_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_hs_detect_exit); + +/* + * wcd9378_mbhc_ssr_down: stop mbhc during + * wcd9378 subsystem restart + * mbhc: pointer to wcd937x_mbhc structure + * component: handle to snd_soc_component * + */ +void wcd9378_mbhc_ssr_down(struct wcd9378_mbhc *mbhc, + struct snd_soc_component *component) +{ + struct wcd_mbhc *wcd_mbhc = NULL; + + if (!mbhc || !component) + return; + + wcd_mbhc = &mbhc->wcd_mbhc; + if (!wcd_mbhc) { + dev_err(component->dev, "%s: wcd_mbhc is NULL\n", __func__); + return; + } + + wcd9378_mbhc_hs_detect_exit(component); + wcd_mbhc_deinit(wcd_mbhc); +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_ssr_down); + +/* + * wcd9378_mbhc_post_ssr_init: initialize mbhc for + * wcd9378 post subsystem restart + * @mbhc: poniter to wcd9378_mbhc structure + * @component: handle to snd_soc_component * + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int wcd9378_mbhc_post_ssr_init(struct wcd9378_mbhc *mbhc, + struct snd_soc_component *component) +{ + int ret = 0; + struct wcd_mbhc *wcd_mbhc = NULL; + struct wcd9378_priv *wcd9378 = 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; + } + + wcd9378 = dev_get_drvdata(component->dev); + if (wcd9378 == NULL) { + pr_err("%s: wcd9378 is NULL\n", __func__); + return -EINVAL; + } + + /* Reset detection type to insertion after SSR recovery */ + snd_soc_component_update_bits(component, WCD9378_ANA_MBHC_MECH, + 0x20, 0x20); + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, WCD9378_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto done; + } + + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_MBHC_ELECT_INS_REM_DET); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_MBHC_ELECT_INS_REM_LEG_DET); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_EAR_SCD_INT); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_AUX_SCD_INT); + +done: + return ret; +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_post_ssr_init); + +/* + * wcd9378_mbhc_init: initialize mbhc for wcd9378 + * @mbhc: poniter to wcd9378_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 wcd9378_mbhc_init(struct wcd9378_mbhc **mbhc, + struct snd_soc_component *component) +{ + struct wcd9378_mbhc *wcd9378_mbhc = NULL; + struct wcd_mbhc *wcd_mbhc = NULL; + int ret = 0; + struct wcd9378_pdata *pdata; + struct wcd9378_priv *wcd9378 = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd9378 = dev_get_drvdata(component->dev); + if (!wcd9378) { + pr_err("%s: wcd9378 is NULL\n", __func__); + return -EINVAL; + } + + wcd9378_mbhc = devm_kzalloc(component->dev, sizeof(struct wcd9378_mbhc), + GFP_KERNEL); + if (!wcd9378_mbhc) + return -ENOMEM; + + BLOCKING_INIT_NOTIFIER_HEAD(&wcd9378_mbhc->notifier); + wcd_mbhc = &wcd9378_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; + + pdata = dev_get_platdata(component->dev); + if (!pdata) { + dev_err(component->dev, "%s: pdata pointer is NULL\n", + __func__); + ret = -EINVAL; + goto err; + } + wcd_mbhc->micb_mv = pdata->micbias.micb2_mv; + + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, + &intr_ids, wcd_mbhc_registers, + WCD9378_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto err; + } + + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_MBHC_ELECT_INS_REM_DET); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_MBHC_ELECT_INS_REM_LEG_DET); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_EAR_SCD_INT); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_AUX_SCD_INT); + + (*mbhc) = wcd9378_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: + return ret; +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_init); + +/* + * wcd9378_mbhc_deinit: deinitialize mbhc for wcd9378 + * @codec: handle to snd_soc_component * + */ +void wcd9378_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378; + struct wcd9378_mbhc *wcd9378_mbhc; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + wcd9378 = snd_soc_component_get_drvdata(component); + if (!wcd9378) { + pr_err("%s: wcd9378 is NULL\n", __func__); + return; + } + + wcd9378_mbhc = wcd9378->mbhc; + if (wcd9378_mbhc) + wcd_mbhc_deinit(&wcd9378_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-mbhc.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-mbhc.h new file mode 100644 index 0000000000..dfceed344a --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-mbhc.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef __WCD9378_MBHC_H__ +#define __WCD9378_MBHC_H__ +#include + +struct wcd9378_mbhc { + struct wcd_mbhc wcd_mbhc; + struct blocking_notifier_head notifier; + struct fw_info *fw_data; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD9378) +extern int wcd9378_mbhc_init(struct wcd9378_mbhc **mbhc, + struct snd_soc_component *component); +extern void wcd9378_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern int wcd9378_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void wcd9378_mbhc_deinit(struct snd_soc_component *component); +extern void wcd9378_mbhc_ssr_down(struct wcd9378_mbhc *mbhc, + struct snd_soc_component *component); +extern int wcd9378_mbhc_post_ssr_init(struct wcd9378_mbhc *mbhc, + struct snd_soc_component *component); +extern int wcd9378_mbhc_get_impedance(struct wcd9378_mbhc *wcd9378_mbhc, + uint32_t *zl, uint32_t *zr); +#else +static inline int wcd9378_mbhc_init(struct wcd9378_mbhc **mbhc, + struct snd_soc_component *component) +{ + return 0; +} +static inline void wcd9378_mbhc_hs_detect_exit( + struct snd_soc_component *component) +{ +} +static inline int wcd9378_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void wcd9378_mbhc_deinit(struct snd_soc_component *component) +{ +} +static inline void wcd9378_mbhc_ssr_down(struct wcd9378_mbhc *mbhc, + struct snd_soc_component *component) +{ +} +static inline int wcd9378_mbhc_post_ssr_init(struct wcd9378_mbhc *mbhc, + struct snd_soc_component *component) +{ + return 0; +} + +static inline int wcd9378_mbhc_get_impedance(struct wcd9378_mbhc *wcd9378_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + +#endif /* __WCD9378_MBHC_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-reg-masks.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-reg-masks.h new file mode 100644 index 0000000000..fbd1c06fa9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-reg-masks.h @@ -0,0 +1,3414 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef WCD9378_REG_MASKS_H +#define WCD9378_REG_MASKS_H +#include +#include +#include "wcd9378-registers.h" + +/* Use in conjunction with wcd9378-reg-shifts.c for field values. */ +/* field_value = (register_value & field_mask) >> field_shift */ + +#define FIELD_MASK(register_name, field_name) \ +WCD9378_##register_name##_##field_name##_MASK + +/* WCD9378_FUNC_EXT_ID_0 Fields: */ +#define WCD9378_FUNC_EXT_ID_0_FUNC_EXT_ID_0_MASK 0xff + +/* WCD9378_FUNC_EXT_ID_1 Fields: */ +#define WCD9378_FUNC_EXT_ID_1_FUNC_EXT_ID_1_MASK 0xff + +/* WCD9378_FUNC_EXT_VER Fields: */ +#define WCD9378_FUNC_EXT_VER_FUNC_EXT_VER_MASK 0xff + +/* WCD9378_FUNC_STAT Fields: */ +#define WCD9378_FUNC_STAT_FUNC_STAT_MASK 0xff + +/* WCD9378_DEV_MANU_ID_0 Fields: */ +#define WCD9378_DEV_MANU_ID_0_DEV_MANU_ID_0_MASK 0xff + +/* WCD9378_DEV_MANU_ID_1 Fields: */ +#define WCD9378_DEV_MANU_ID_1_DEV_MANU_ID_1_MASK 0xff + +/* WCD9378_DEV_PART_ID_0 Fields: */ +#define WCD9378_DEV_PART_ID_0_DEV_PART_ID_0_MASK 0xff + +/* WCD9378_DEV_PART_ID_1 Fields: */ +#define WCD9378_DEV_PART_ID_1_DEV_PART_ID_1_MASK 0xff + +/* WCD9378_DEV_VER Fields: */ +#define WCD9378_DEV_VER_DEV_VER_MASK 0xff + + +/* WCD9378_A_PAGE Fields: */ +#define WCD9378_A_PAGE_VALUE_MASK 0xff + +/* WCD9378_ANA_BIAS Fields: */ +#define WCD9378_ANA_BIAS_ANALOG_BIAS_EN_MASK 0x80 +#define WCD9378_ANA_BIAS_PRECHRG_EN_MASK 0x40 +#define WCD9378_ANA_BIAS_PRECHRG_CTL_MODE_MASK 0x20 + +/* WCD9378_ANA_RX_SUPPLIES Fields: */ +#define WCD9378_ANA_RX_SUPPLIES_CLASSG_CP_EN_MASK 0x80 +#define WCD9378_ANA_RX_SUPPLIES_NCP_EN_MASK 0x40 +#define WCD9378_ANA_RX_SUPPLIES_SEQ_BYPASS_MASK 0x20 +#define WCD9378_ANA_RX_SUPPLIES_SDCA_BYPASS_MASK 0x10 +#define WCD9378_ANA_RX_SUPPLIES_SYS_USAGE_BYP_MASK 0x08 +#define WCD9378_ANA_RX_SUPPLIES_ANA_SEQ_BYPASS_MASK 0x02 +#define WCD9378_ANA_RX_SUPPLIES_RX_BIAS_ENABLE_MASK 0x01 + +/* WCD9378_ANA_HPH Fields: */ +#define WCD9378_ANA_HPH_HPHL_ENABLE_MASK 0x80 +#define WCD9378_ANA_HPH_HPHR_ENABLE_MASK 0x40 +#define WCD9378_ANA_HPH_HPHL_REF_ENABLE_MASK 0x20 +#define WCD9378_ANA_HPH_HPHR_REF_ENABLE_MASK 0x10 +#define WCD9378_ANA_HPH_PWR_LEVEL_MASK 0x0c +#define WCD9378_ANA_HPH_LOW_HIFI_CTL_MASK 0x02 + +/* WCD9378_ANA_EAR Fields: */ +#define WCD9378_ANA_EAR_ENABLE_MASK 0x80 +#define WCD9378_ANA_EAR_SHORT_PROT_EN_MASK 0x40 +#define WCD9378_ANA_EAR_OUT_IMPEDANCE_MASK 0x20 +#define WCD9378_ANA_EAR_DAC_CLK_SEL_MASK 0x01 + +/* WCD9378_ANA_EAR_COMPANDER_CTL Fields: */ +#define WCD9378_ANA_EAR_COMPANDER_CTL_GAIN_OVRD_REG_MASK 0x80 +#define WCD9378_ANA_EAR_COMPANDER_CTL_EAR_GAIN_MASK 0x7c +#define WCD9378_ANA_EAR_COMPANDER_CTL_COMP_DFF_BYP_MASK 0x02 +#define WCD9378_ANA_EAR_COMPANDER_CTL_COMP_DFF_CLK_EDGE_MASK 0x01 + +/* WCD9378_ANA_TX_CH1 Fields: */ +#define WCD9378_ANA_TX_CH1_ENABLE_MASK 0x80 +#define WCD9378_ANA_TX_CH1_PWR_LEVEL_MASK 0x60 +#define WCD9378_ANA_TX_CH1_GAIN_MASK 0x1f + +/* WCD9378_ANA_TX_CH2 Fields: */ +#define WCD9378_ANA_TX_CH2_ENABLE_MASK 0x80 +#define WCD9378_ANA_TX_CH2_HPF1_INIT_MASK 0x40 +#define WCD9378_ANA_TX_CH2_HPF2_INIT_MASK 0x20 +#define WCD9378_ANA_TX_CH2_GAIN_MASK 0x1f + +/* WCD9378_ANA_TX_CH3 Fields: */ +#define WCD9378_ANA_TX_CH3_ENABLE_MASK 0x80 +#define WCD9378_ANA_TX_CH3_PWR_LEVEL_MASK 0x60 +#define WCD9378_ANA_TX_CH3_GAIN_MASK 0x1f + +/* WCD9378_ANA_TX_CH3_HPF Fields: */ +#define WCD9378_ANA_TX_CH3_HPF_HPF3_INIT_MASK 0x40 + +/* WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC Fields: */ +#define WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC_MICB1_DSP_OVERRIDE_MASK 0x80 +#define WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC_MICB1_DSP_CTRL_MASK 0x60 +#define WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC_MICB2_DSP_OVERRIDE_MASK 0x10 +#define WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC_MICB2_DSP_CTRL_MASK 0x0c + +/* WCD9378_ANA_MICB3_DSP_EN_LOGIC Fields: */ +#define WCD9378_ANA_MICB3_DSP_EN_LOGIC_MICB3_DSP_OVERRIDE_MASK 0x80 +#define WCD9378_ANA_MICB3_DSP_EN_LOGIC_MICB3_DSP_CTRL_MASK 0x60 + +/* WCD9378_ANA_MBHC_MECH Fields: */ +#define WCD9378_ANA_MBHC_MECH_L_DET_EN_MASK 0x80 +#define WCD9378_ANA_MBHC_MECH_GND_DET_EN_MASK 0x40 +#define WCD9378_ANA_MBHC_MECH_MECH_DETECT_TYPE_MASK 0x20 +#define WCD9378_ANA_MBHC_MECH_HPHL_PLUG_TYPE_MASK 0x10 +#define WCD9378_ANA_MBHC_MECH_GND_PLUG_TYPE_MASK 0x08 +#define WCD9378_ANA_MBHC_MECH_MECH_HS_L_PULLUP_COMP_EN_MASK 0x04 +#define WCD9378_ANA_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN_MASK 0x02 +#define WCD9378_ANA_MBHC_MECH_SW_HPH_L_P_100K_TO_GND_MASK 0x01 + +/* WCD9378_ANA_MBHC_ELECT Fields: */ +#define WCD9378_ANA_MBHC_ELECT_FSM_EN_MASK 0x80 +#define WCD9378_ANA_MBHC_ELECT_BTNDET_ISRC_CTL_MASK 0x70 +#define WCD9378_ANA_MBHC_ELECT_ELECT_DET_TYPE_MASK 0x08 +#define WCD9378_ANA_MBHC_ELECT_ELECT_SCHMT_ISRC_CTL_MASK 0x06 +#define WCD9378_ANA_MBHC_ELECT_BIAS_EN_MASK 0x01 + +/* WCD9378_ANA_MBHC_ZDET Fields: */ +#define WCD9378_ANA_MBHC_ZDET_ZDET_L_MEAS_EN_MASK 0x80 +#define WCD9378_ANA_MBHC_ZDET_ZDET_R_MEAS_EN_MASK 0x40 +#define WCD9378_ANA_MBHC_ZDET_ZDET_CHG_EN_MASK 0x20 +#define WCD9378_ANA_MBHC_ZDET_ELECT_ISRC_EN_MASK 0x02 + +/* WCD9378_ANA_MBHC_RESULT_1 Fields: */ +#define WCD9378_ANA_MBHC_RESULT_1_Z_RESULT_MSB_MASK 0xff + +/* WCD9378_ANA_MBHC_RESULT_2 Fields: */ +#define WCD9378_ANA_MBHC_RESULT_2_Z_RESULT_LSB_MASK 0xff + +/* WCD9378_ANA_MBHC_RESULT_3 Fields: */ +#define WCD9378_ANA_MBHC_RESULT_3_MIC_SCHMT_RESULT_MASK 0x20 +#define WCD9378_ANA_MBHC_RESULT_3_IN2P_CLAMP_STATE_MASK 0x10 +#define WCD9378_ANA_MBHC_RESULT_3_BTN_RESULT_MASK 0x07 + +/* WCD9378_ANA_MBHC_BTN0 Fields: */ +#define WCD9378_ANA_MBHC_BTN0_VTH_MASK 0xfc + +/* WCD9378_ANA_MBHC_BTN1 Fields: */ +#define WCD9378_ANA_MBHC_BTN1_VTH_MASK 0xfc + +/* WCD9378_ANA_MBHC_BTN2 Fields: */ +#define WCD9378_ANA_MBHC_BTN2_VTH_MASK 0xfc + +/* WCD9378_ANA_MBHC_BTN3 Fields: */ +#define WCD9378_ANA_MBHC_BTN3_VTH_MASK 0xfc + +/* WCD9378_ANA_MBHC_BTN4 Fields: */ +#define WCD9378_ANA_MBHC_BTN4_VTH_MASK 0xfc +#define WCD9378_ANA_MBHC_BTN4_VDD_SW_IO_SEL_MASK 0x02 +#define WCD9378_ANA_MBHC_BTN4_LKGCOMP_EN_MASK 0x01 + +/* WCD9378_ANA_MBHC_BTN5 Fields: */ +#define WCD9378_ANA_MBHC_BTN5_VTH_MASK 0xfc + +/* WCD9378_ANA_MBHC_BTN6 Fields: */ +#define WCD9378_ANA_MBHC_BTN6_VTH_MASK 0xfc + +/* WCD9378_ANA_MBHC_BTN7 Fields: */ +#define WCD9378_ANA_MBHC_BTN7_VTH_MASK 0xfc + +/* WCD9378_ANA_MICB1 Fields: */ +#define WCD9378_ANA_MICB1_ENABLE_MASK 0xc0 +#define WCD9378_ANA_MICB1_VOUT_CTL_MASK 0x3f + +/* WCD9378_ANA_MICB2 Fields: */ +#define WCD9378_ANA_MICB2_ENABLE_MASK 0xc0 +#define WCD9378_ANA_MICB2_VOUT_CTL_MASK 0x3f + +/* WCD9378_ANA_MICB2_RAMP Fields: */ +#define WCD9378_ANA_MICB2_RAMP_RAMP_ENABLE_MASK 0x80 +#define WCD9378_ANA_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE_MASK 0x40 +#define WCD9378_ANA_MICB2_RAMP_ALLSW_OVRD_ENABLE_MASK 0x20 +#define WCD9378_ANA_MICB2_RAMP_SHIFT_CTL_MASK 0x1c + +/* WCD9378_ANA_MICB3 Fields: */ +#define WCD9378_ANA_MICB3_ENABLE_MASK 0xc0 +#define WCD9378_ANA_MICB3_PRECHARGE_OVERRIDE_MICB3_MASK 0x20 +#define WCD9378_ANA_MICB3_PRECHARGE_CLK_SEL_MICB3_MASK 0x18 +#define WCD9378_ANA_MICB3_SDCA_BYPASS_MASK 0x04 + +/* WCD9378_BIAS_CTL Fields: */ +#define WCD9378_BIAS_CTL_BG_FAST_MODE_EN_MASK 0x80 +#define WCD9378_BIAS_CTL_DC_START_UP_EN_MASK 0x20 +#define WCD9378_BIAS_CTL_TRAN_START_UP_EN_MASK 0x10 +#define WCD9378_BIAS_CTL_OTA_BIAS_CTL_MASK 0x08 +#define WCD9378_BIAS_CTL_ATEST_CTL_MASK 0x04 +#define WCD9378_BIAS_CTL_EFUSE_EN_MASK 0x02 + +/* WCD9378_BIAS_VBG_FINE_ADJ Fields: */ +#define WCD9378_BIAS_VBG_FINE_ADJ_VBG_FINE_ADJ_MASK 0xf0 +#define WCD9378_BIAS_VBG_FINE_ADJ_EN_DTEST_BG_STATUS_MASK 0x08 +#define WCD9378_BIAS_VBG_FINE_ADJ_PRECHARGE_TIMER_COUNT_MASK 0x07 + +/* WCD9378_LDOL_VDDCX_ADJUST Fields: */ +#define WCD9378_LDOL_VDDCX_ADJUST_RC_ZERO_FREQ_TUNE_MASK 0x0c +#define WCD9378_LDOL_VDDCX_ADJUST_VDDCX_ADJUST_MASK 0x03 + +/* WCD9378_LDOL_DISABLE_LDOL Fields: */ +#define WCD9378_LDOL_DISABLE_LDOL_DISABLE_LDOL_MASK 0x01 + +/* WCD9378_MBHC_CTL_CLK Fields: */ +#define WCD9378_MBHC_CTL_CLK_CLK_SEL_MASK 0x40 +#define WCD9378_MBHC_CTL_CLK_COMP_CLK_CTL_MASK 0x30 +#define WCD9378_MBHC_CTL_CLK_COMP_AZ_CTL_MASK 0x0c +#define WCD9378_MBHC_CTL_CLK_TEST_CLK_EN_MASK 0x02 +#define WCD9378_MBHC_CTL_CLK_COMP_AVG_BYP_EN_MASK 0x01 + +/* WCD9378_MBHC_CTL_ANA Fields: */ +#define WCD9378_MBHC_CTL_ANA_BIAS_SEL_MASK 0x80 + +/* WCD9378_MBHC_CTL_SPARE_1 Fields: */ +#define WCD9378_MBHC_CTL_SPARE_1_SPARE_BITS_MASK 0xfc +#define WCD9378_MBHC_CTL_SPARE_1_BIASGEN_RES_CTRL_MASK 0x03 + +/* WCD9378_MBHC_CTL_SPARE_2 Fields: */ +#define WCD9378_MBHC_CTL_SPARE_2_SPARE_BITS_MASK 0xff + +/* WCD9378_MBHC_CTL_BCS Fields: */ +#define WCD9378_MBHC_CTL_BCS_FAST_INT_OVRD_EN_MASK 0x80 +#define WCD9378_MBHC_CTL_BCS_ELECT_REM_FAST_REG_OVRD_MASK 0x40 +#define WCD9378_MBHC_CTL_BCS_BTN_RELEASE_FAST_REG_OVRD_MASK 0x20 +#define WCD9378_MBHC_CTL_BCS_BTN_PRESS_FAST_REG_OVRD_MASK 0x10 +#define WCD9378_MBHC_CTL_BCS_ANC_DET_EN_MASK 0x02 +#define WCD9378_MBHC_CTL_BCS_DEBUG_1_MASK 0x01 + +/* WCD9378_MBHC_MOISTURE_DET_FSM_STATUS Fields: */ +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_ELECT_IN2P_COMP_MASK 0x80 +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_MECH_HS_G_COMP_MASK 0x40 +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_MECH_HS_M_COMP_MASK 0x20 +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_MECH_HS_L_COMP_MASK 0x10 +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_MOISTURE_INTR_MASK 0x08 +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_MOISTURE_GTPOLLING_STATUS_MASK 0x04 +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_MOISTURE_DET_STATUS_MASK 0x02 +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS_SAMPLE_CLK_LDET_MASK 0x01 + +/* WCD9378_MBHC_TEST_CTL Fields: */ +#define WCD9378_MBHC_TEST_CTL_FAST_DBNC_TIMER_MASK 0x30 +#define WCD9378_MBHC_TEST_CTL_ATEST_MASK 0x0f + +/* WCD9378_LDOH_MODE Fields: */ +#define WCD9378_LDOH_MODE_LDOH_EN_MASK 0x80 +#define WCD9378_LDOH_MODE_PWRDN_STATE_MASK 0x40 +#define WCD9378_LDOH_MODE_SLOWRAMP_EN_MASK 0x20 +#define WCD9378_LDOH_MODE_VOUT_ADJUST_MASK 0x18 +#define WCD9378_LDOH_MODE_VOUT_COARSE_ADJ_MASK 0x07 + +/* WCD9378_LDOH_BIAS Fields: */ +#define WCD9378_LDOH_BIAS_IBIAS_REF_MASK 0xe0 +#define WCD9378_LDOH_BIAS_IBIAS_ERR_AMP_MASK 0x18 +#define WCD9378_LDOH_BIAS_IBIAS_NATIVE_DEVICE_MASK 0x04 +#define WCD9378_LDOH_BIAS_IBIAS_BUFFER_BLEED_MASK 0x02 + +/* WCD9378_LDOH_STB_LOADS Fields: */ +#define WCD9378_LDOH_STB_LOADS_STB_LOADS_1_UA_MASK 0xf0 +#define WCD9378_LDOH_STB_LOADS_STB_LOAD_10_UA_MASK 0x08 + +/* WCD9378_LDOH_SLOWRAMP Fields: */ +#define WCD9378_LDOH_SLOWRAMP_SLOWRAMP_IBIAS_MASK 0xc0 +#define WCD9378_LDOH_SLOWRAMP_SLOWRAMP_RESET_TIME_MASK 0x30 + +/* WCD9378_MICB1_TEST_CTL_1 Fields: */ +#define WCD9378_MICB1_TEST_CTL_1_NOISE_FILT_RES_VAL_MASK 0xe0 +#define WCD9378_MICB1_TEST_CTL_1_EN_VREFGEN_MASK 0x10 +#define WCD9378_MICB1_TEST_CTL_1_EN_LDO_MASK 0x08 +#define WCD9378_MICB1_TEST_CTL_1_LDO_BLEEDER_CTRL_MASK 0x07 + +/* WCD9378_MICB1_TEST_CTL_2 Fields: */ +#define WCD9378_MICB1_TEST_CTL_2_IBIAS_VREFGEN_MASK 0xc0 +#define WCD9378_MICB1_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_MASK 0x20 +#define WCD9378_MICB1_TEST_CTL_2_SPARE_BITS_MASK 0x18 +#define WCD9378_MICB1_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK 0x07 + +/* WCD9378_MICB1_TEST_CTL_3 Fields: */ +#define WCD9378_MICB1_TEST_CTL_3_CFILT_REF_EN_MASK 0x80 +#define WCD9378_MICB1_TEST_CTL_3_RZ_LDO_VAL_MASK 0x70 +#define WCD9378_MICB1_TEST_CTL_3_IBIAS_LDO_STG3_MASK 0x0c +#define WCD9378_MICB1_TEST_CTL_3_ATEST_CTRL_MASK 0x03 + +/* WCD9378_MICB2_TEST_CTL_1 Fields: */ +#define WCD9378_MICB2_TEST_CTL_1_NOISE_FILT_RES_VAL_MASK 0xe0 +#define WCD9378_MICB2_TEST_CTL_1_EN_VREFGEN_MASK 0x10 +#define WCD9378_MICB2_TEST_CTL_1_EN_LDO_MASK 0x08 +#define WCD9378_MICB2_TEST_CTL_1_LDO_BLEEDER_CTRL_MASK 0x07 + +/* WCD9378_MICB2_TEST_CTL_2 Fields: */ +#define WCD9378_MICB2_TEST_CTL_2_IBIAS_VREFGEN_MASK 0xc0 +#define WCD9378_MICB2_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_MASK 0x20 +#define WCD9378_MICB2_TEST_CTL_2_SPARE_BITS_MASK 0x18 +#define WCD9378_MICB2_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK 0x07 + +/* WCD9378_MICB2_TEST_CTL_3 Fields: */ +#define WCD9378_MICB2_TEST_CTL_3_CFILT_REF_EN_MASK 0x80 +#define WCD9378_MICB2_TEST_CTL_3_RZ_LDO_VAL_MASK 0x70 +#define WCD9378_MICB2_TEST_CTL_3_IBIAS_LDO_STG3_MASK 0x0c +#define WCD9378_MICB2_TEST_CTL_3_ATEST_CTRL_MASK 0x03 + +/* WCD9378_MICB3_TEST_CTL_1 Fields: */ +#define WCD9378_MICB3_TEST_CTL_1_PRECHARGE_OVERRIDE_MICB1_MASK 0x80 +#define WCD9378_MICB3_TEST_CTL_1_PRECHARGE_CLK_SEL_MICB1_MASK 0x60 +#define WCD9378_MICB3_TEST_CTL_1_EN_VREFGEN3_MASK 0x10 +#define WCD9378_MICB3_TEST_CTL_1_EN_LDO3_MASK 0x08 +#define WCD9378_MICB3_TEST_CTL_1_LDO_BLEEDER_CTRL3_MASK 0x07 + +/* WCD9378_MICB3_TEST_CTL_2 Fields: */ +#define WCD9378_MICB3_TEST_CTL_2_FILTER_POLYRES_EN_MICB2_MASK 0x80 +#define WCD9378_MICB3_TEST_CTL_2_PRECHARGE_OVERRIDE_MICB2_MASK 0x40 +#define WCD9378_MICB3_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS3_MASK 0x20 +#define WCD9378_MICB3_TEST_CTL_2_PRECHARGE_CLK_SEL_MICB2_MASK 0x18 +#define WCD9378_MICB3_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK 0x07 + +/* WCD9378_MICB3_TEST_CTL_3 Fields: */ +#define WCD9378_MICB3_TEST_CTL_3_FILTER_MOSRES_EN_MICB2_MASK 0x80 +#define WCD9378_MICB3_TEST_CTL_3_RZ_LDO_VAL_MASK 0x70 +#define WCD9378_MICB3_TEST_CTL_3_IBIAS_LDO_STG3_MASK 0x0c +#define WCD9378_MICB3_TEST_CTL_3_ATEST_CTRL_MASK 0x03 + +/* WCD9378_TX_COM_ADC_VCM Fields: */ +#define WCD9378_TX_COM_ADC_VCM_VCM_L2_12P288_MASK 0x30 +#define WCD9378_TX_COM_ADC_VCM_VCM_L2_9P6_MASK 0x0c +#define WCD9378_TX_COM_ADC_VCM_VCM_DEFAULT_MASK 0x03 + +/* WCD9378_TX_COM_BIAS_ATEST Fields: */ +#define WCD9378_TX_COM_BIAS_ATEST_TX_CURR_EN_MASK 0x80 +#define WCD9378_TX_COM_BIAS_ATEST_SC_BIAS_EN_MASK 0x40 +#define WCD9378_TX_COM_BIAS_ATEST_SC_BIAS_VREF_SEL_MASK 0x20 +#define WCD9378_TX_COM_BIAS_ATEST_ATEST4_EN_MASK 0x08 +#define WCD9378_TX_COM_BIAS_ATEST_ATEST3_EN_MASK 0x04 +#define WCD9378_TX_COM_BIAS_ATEST_ATEST2_EN_MASK 0x02 +#define WCD9378_TX_COM_BIAS_ATEST_ATEST1_EN_MASK 0x01 + +/* WCD9378_TX_COM_SPARE1 Fields: */ +#define WCD9378_TX_COM_SPARE1_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_SPARE2 Fields: */ +#define WCD9378_TX_COM_SPARE2_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_TXFE_DIV_CTL Fields: */ +#define WCD9378_TX_COM_TXFE_DIV_CTL_SEQ_BYPASS_MASK 0x80 +#define WCD9378_TX_COM_TXFE_DIV_CTL_FB_SW_DRIVE_MASK 0x20 +#define WCD9378_TX_COM_TXFE_DIV_CTL_EN_CKGEN_INIT_MASK 0x10 +#define WCD9378_TX_COM_TXFE_DIV_CTL_N_PAUSE_MASK 0x03 + +/* WCD9378_TX_COM_TXFE_DIV_START Fields: */ +#define WCD9378_TX_COM_TXFE_DIV_START_DIV_MASK 0xff + +/* WCD9378_TX_COM_SPARE3 Fields: */ +#define WCD9378_TX_COM_SPARE3_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_SPARE4 Fields: */ +#define WCD9378_TX_COM_SPARE4_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_1_2_TEST_EN Fields: */ +#define WCD9378_TX_1_2_TEST_EN_TXFE1_EN_MASK 0x80 +#define WCD9378_TX_1_2_TEST_EN_ADC1_EN_MASK 0x40 +#define WCD9378_TX_1_2_TEST_EN_TXFE1_BYPASS_MASK 0x20 +#define WCD9378_TX_1_2_TEST_EN_TXFE1_CLK_MODE_MASK 0x10 +#define WCD9378_TX_1_2_TEST_EN_TXFE2_EN_MASK 0x08 +#define WCD9378_TX_1_2_TEST_EN_ADC2_EN_MASK 0x04 +#define WCD9378_TX_1_2_TEST_EN_TXFE2_BYPASS_MASK 0x02 +#define WCD9378_TX_1_2_TEST_EN_TXFE2_CLK_MODE_MASK 0x01 + +/* WCD9378_TX_1_2_ADC_IB Fields: */ +#define WCD9378_TX_1_2_ADC_IB_ADC2_DEM_MODE_MASK 0xc0 +#define WCD9378_TX_1_2_ADC_IB_ADC2_DEM_OPERATION_MASK 0x30 +#define WCD9378_TX_1_2_ADC_IB_L2_DAC_DLY_MASK 0x0c +#define WCD9378_TX_1_2_ADC_IB_DEFAULT_DAC_DLY_MASK 0x03 + +/* WCD9378_TX_1_2_ATEST_REFCTL Fields: */ +#define WCD9378_TX_1_2_ATEST_REFCTL_ATEST_CTL_MASK 0xf0 +#define WCD9378_TX_1_2_ATEST_REFCTL_TXFE_INCM_REF_MASK 0x0c +#define WCD9378_TX_1_2_ATEST_REFCTL_TXFE_HP_GAIN_MODE_MASK 0x02 +#define WCD9378_TX_1_2_ATEST_REFCTL_SPARE_BITS_0_0_MASK 0x01 + +/* WCD9378_TX_1_2_TEST_CTL Fields: */ +#define WCD9378_TX_1_2_TEST_CTL_TXFE_HP_GAIN_MASK 0x80 +#define WCD9378_TX_1_2_TEST_CTL_REF_CAP_MASK 0x40 +#define WCD9378_TX_1_2_TEST_CTL_ADC1_DEM_MODE_MASK 0x30 +#define WCD9378_TX_1_2_TEST_CTL_ADC1_DEM_OPERATION_MASK 0x0c +#define WCD9378_TX_1_2_TEST_CTL_SAR_ERR_DET_EN_MASK 0x02 +#define WCD9378_TX_1_2_TEST_CTL_SAR_EXT_DELAY_EN_MASK 0x01 + +/* WCD9378_TX_1_2_TEST_BLK_EN1 Fields: */ +#define WCD9378_TX_1_2_TEST_BLK_EN1_ADC1_INT1_EN_MASK 0x80 +#define WCD9378_TX_1_2_TEST_BLK_EN1_ADC1_INT2_EN_MASK 0x40 +#define WCD9378_TX_1_2_TEST_BLK_EN1_ADC1_SAR_EN_MASK 0x20 +#define WCD9378_TX_1_2_TEST_BLK_EN1_ADC1_CMGEN_EN_MASK 0x10 +#define WCD9378_TX_1_2_TEST_BLK_EN1_ADC1_CLKGEN_EN_MASK 0x08 +#define WCD9378_TX_1_2_TEST_BLK_EN1_REF_EN_MASK 0x04 +#define WCD9378_TX_1_2_TEST_BLK_EN1_TXFE1_CLKDIV_EN_MASK 0x02 +#define WCD9378_TX_1_2_TEST_BLK_EN1_TXFE2_CLKDIV_EN_MASK 0x01 + +/* WCD9378_TX_1_2_TXFE1_CLKDIV Fields: */ +#define WCD9378_TX_1_2_TXFE1_CLKDIV_DIV_MASK 0xff + +/* WCD9378_TX_1_2_SAR2_ERR Fields: */ +#define WCD9378_TX_1_2_SAR2_ERR_SAR_ERR_COUNT_MASK 0xff + +/* WCD9378_TX_1_2_SAR1_ERR Fields: */ +#define WCD9378_TX_1_2_SAR1_ERR_SAR_ERR_COUNT_MASK 0xff + +/* WCD9378_TX_3_TEST_EN Fields: */ +#define WCD9378_TX_3_TEST_EN_TXFE3_EN_MASK 0x80 +#define WCD9378_TX_3_TEST_EN_ADC3_EN_MASK 0x40 +#define WCD9378_TX_3_TEST_EN_TXFE3_BYPASS_MASK 0x20 +#define WCD9378_TX_3_TEST_EN_TXFE3_CLK_MODE_MASK 0x10 +#define WCD9378_TX_3_TEST_EN_SPARE_BITS_3_0_MASK 0x0f + +/* WCD9378_TX_3_ADC_IB Fields: */ +#define WCD9378_TX_3_ADC_IB_SPARE_BITS_3_0_MASK 0xf0 +#define WCD9378_TX_3_ADC_IB_L2_DAC_DLY_MASK 0x0c +#define WCD9378_TX_3_ADC_IB_DEFAULT_DAC_DLY_MASK 0x03 + +/* WCD9378_TX_3_ATEST_REFCTL Fields: */ +#define WCD9378_TX_3_ATEST_REFCTL_ATEST_CTL_MASK 0xf0 +#define WCD9378_TX_3_ATEST_REFCTL_TXFE_INCM_REF_MASK 0x0c +#define WCD9378_TX_3_ATEST_REFCTL_TXFE_HP_GAIN_MODE_MASK 0x02 +#define WCD9378_TX_3_ATEST_REFCTL_SPARE_BITS_0_0_MASK 0x01 + +/* WCD9378_TX_3_TEST_CTL Fields: */ +#define WCD9378_TX_3_TEST_CTL_TXFE_HP_GAIN_MASK 0x80 +#define WCD9378_TX_3_TEST_CTL_REF_CAP_MASK 0x40 +#define WCD9378_TX_3_TEST_CTL_ADC3_DEM_MODE_MASK 0x30 +#define WCD9378_TX_3_TEST_CTL_ADC3_DEM_OPERATION_MASK 0x0c +#define WCD9378_TX_3_TEST_CTL_SAR_ERR_DET_EN_MASK 0x02 +#define WCD9378_TX_3_TEST_CTL_SAR_EXT_DELAY_EN_MASK 0x01 + +/* WCD9378_TX_3_TEST_BLK_EN3 Fields: */ +#define WCD9378_TX_3_TEST_BLK_EN3_ADC3_INT1_EN_MASK 0x80 +#define WCD9378_TX_3_TEST_BLK_EN3_ADC3_INT2_EN_MASK 0x40 +#define WCD9378_TX_3_TEST_BLK_EN3_ADC3_SAR_EN_MASK 0x20 +#define WCD9378_TX_3_TEST_BLK_EN3_ADC3_CMGEN_EN_MASK 0x10 +#define WCD9378_TX_3_TEST_BLK_EN3_ADC3_CLKGEN_EN_MASK 0x08 +#define WCD9378_TX_3_TEST_BLK_EN3_REF_EN_MASK 0x04 +#define WCD9378_TX_3_TEST_BLK_EN3_TXFE3_CLKDIV_EN_MASK 0x02 +#define WCD9378_TX_3_TEST_BLK_EN3_SPARE_BITS_0_0_MASK 0x01 + +/* WCD9378_TX_3_TXFE3_CLKDIV Fields: */ +#define WCD9378_TX_3_TXFE3_CLKDIV_DIV_MASK 0xff + +/* WCD9378_TX_3_SAR4_ERR Fields: */ +#define WCD9378_TX_3_SAR4_ERR_SAR_ERR_COUNT_MASK 0xff + +/* WCD9378_TX_3_SAR3_ERR Fields: */ +#define WCD9378_TX_3_SAR3_ERR_SAR_ERR_COUNT_MASK 0xff + +/* WCD9378_TX_3_TEST_BLK_EN2 Fields: */ +#define WCD9378_TX_3_TEST_BLK_EN2_ADC2_INT1_EN_MASK 0x80 +#define WCD9378_TX_3_TEST_BLK_EN2_ADC2_INT2_EN_MASK 0x40 +#define WCD9378_TX_3_TEST_BLK_EN2_ADC2_SAR_EN_MASK 0x20 +#define WCD9378_TX_3_TEST_BLK_EN2_ADC2_CMGEN_EN_MASK 0x10 +#define WCD9378_TX_3_TEST_BLK_EN2_ADC2_CLKGEN_EN_MASK 0x08 +#define WCD9378_TX_3_TEST_BLK_EN2_ADC12_VREF_NONL2_MASK 0x06 +#define WCD9378_TX_3_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN_MASK 0x01 + +/* WCD9378_TX_3_TXFE2_CLKDIV Fields: */ +#define WCD9378_TX_3_TXFE2_CLKDIV_DIV_MASK 0xff + +/* WCD9378_TX_3_SPARE1 Fields: */ +#define WCD9378_TX_3_SPARE1_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_3_TEST_BLK_EN4 Fields: */ +#define WCD9378_TX_3_TEST_BLK_EN4_SPARE_BITS_7_3_MASK 0xf8 +#define WCD9378_TX_3_TEST_BLK_EN4_ADC34_VREF_NONL2_MASK 0x06 +#define WCD9378_TX_3_TEST_BLK_EN4_SPARE_BITS_0_0_MASK 0x01 + +/* WCD9378_TX_3_SPARE2 Fields: */ +#define WCD9378_TX_3_SPARE2_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_3_SPARE3 Fields: */ +#define WCD9378_TX_3_SPARE3_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_RX_AUX_SW_CTL Fields: */ +#define WCD9378_RX_AUX_SW_CTL_AUXL_SW_EN_MASK 0x80 +#define WCD9378_RX_AUX_SW_CTL_AUXR_SW_EN_MASK 0x40 +#define WCD9378_RX_AUX_SW_CTL_AUXL2R_SW_EN_MASK 0x20 + +/* WCD9378_RX_PA_AUX_IN_CONN Fields: */ +#define WCD9378_RX_PA_AUX_IN_CONN_HPHL_AUX_IN_MASK 0x80 +#define WCD9378_RX_PA_AUX_IN_CONN_HPHR_AUX_IN_MASK 0x40 +#define WCD9378_RX_PA_AUX_IN_CONN_EAR_AUX_IN_MASK 0x20 +#define WCD9378_RX_PA_AUX_IN_CONN_AUX_AUX_IN_MASK 0x10 + +/* WCD9378_RX_TIMER_DIV Fields: */ +#define WCD9378_RX_TIMER_DIV_RX_CLK_DIVIDER_OVWT_MASK 0x80 +#define WCD9378_RX_TIMER_DIV_RX_CLK_DIVIDER_MASK 0x7f + +/* WCD9378_RX_OCP_CTL Fields: */ +#define WCD9378_RX_OCP_CTL_SPARE_BITS_MASK 0xf0 +#define WCD9378_RX_OCP_CTL_N_CONNECTION_ATTEMPTS_MASK 0x0f + +/* WCD9378_RX_OCP_COUNT Fields: */ +#define WCD9378_RX_OCP_COUNT_RUN_N_CYCLES_MASK 0xf0 +#define WCD9378_RX_OCP_COUNT_WAIT_N_CYCLES_MASK 0x0f + +/* WCD9378_RX_BIAS_EAR_DAC Fields: */ +#define WCD9378_RX_BIAS_EAR_DAC_EAR_DAC_5_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_EAR_DAC_ATEST_RX_BIAS_MASK 0x0f + +/* WCD9378_RX_BIAS_EAR_AMP Fields: */ +#define WCD9378_RX_BIAS_EAR_AMP_EAR_AMP_10_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_EAR_AMP_EAR_AMP_5_UA_MASK 0x0f + +/* WCD9378_RX_BIAS_HPH_LDO Fields: */ +#define WCD9378_RX_BIAS_HPH_LDO_HPH_NVLDO2_5_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_HPH_LDO_HPH_NVLDO1_4P5_UA_MASK 0x0f + +/* WCD9378_RX_BIAS_HPH_PA Fields: */ +#define WCD9378_RX_BIAS_HPH_PA_HPH_CONSTOP_5_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_HPH_PA_HPH_AMP_5_UA_MASK 0x0f + +/* WCD9378_RX_BIAS_HPH_RDACBUFF_CNP2 Fields: */ +#define WCD9378_RX_BIAS_HPH_RDACBUFF_CNP2_RDAC_BUF_4_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_HPH_RDACBUFF_CNP2_HPH_CNP_10_UA_MASK 0x0f + +/* WCD9378_RX_BIAS_HPH_RDAC_LDO Fields: */ +#define WCD9378_RX_BIAS_HPH_RDAC_LDO_RDAC_LDO_1P65_4_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_HPH_RDAC_LDO_RDAC_LDO_N1P65_4_UA_MASK 0x0f + +/* WCD9378_RX_BIAS_HPH_CNP1 Fields: */ +#define WCD9378_RX_BIAS_HPH_CNP1_HPH_CNP_4_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_HPH_CNP1_HPH_CNP_3_UA_MASK 0x0f + +/* WCD9378_RX_BIAS_HPH_LOWPOWER Fields: */ +#define WCD9378_RX_BIAS_HPH_LOWPOWER_HPH_AMP_LP_1P5_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_HPH_LOWPOWER_RDAC_BUF_LP_0P5_UA_MASK 0x0f + +/* WCD9378_RX_BIAS_AUX_DAC Fields: */ +#define WCD9378_RX_BIAS_AUX_DAC_AUX_DAC_5_UA_MASK 0xf0 + +/* WCD9378_RX_BIAS_AUX_AMP Fields: */ +#define WCD9378_RX_BIAS_AUX_AMP_AUX_AMP_10_UA_MASK 0xf0 +#define WCD9378_RX_BIAS_AUX_AMP_AUX_AMP_5_UA_MASK 0x0f + +/* WCD9378_RX_SPARE_1 Fields: */ +#define WCD9378_RX_SPARE_1_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_RX_SPARE_2 Fields: */ +#define WCD9378_RX_SPARE_2_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_RX_SPARE_3 Fields: */ +#define WCD9378_RX_SPARE_3_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_RX_SPARE_4 Fields: */ +#define WCD9378_RX_SPARE_4_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_RX_SPARE_5 Fields: */ +#define WCD9378_RX_SPARE_5_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_RX_SPARE_6 Fields: */ +#define WCD9378_RX_SPARE_6_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_RX_SPARE_7 Fields: */ +#define WCD9378_RX_SPARE_7_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_HPH_L_STATUS Fields: */ +#define WCD9378_HPH_L_STATUS_CMPDR_GAIN_MASK 0xf8 +#define WCD9378_HPH_L_STATUS_OCP_COMP_DETECT_MASK 0x04 +#define WCD9378_HPH_L_STATUS_OCP_LIMIT_MASK 0x02 +#define WCD9378_HPH_L_STATUS_PA_READY_MASK 0x01 + +/* WCD9378_HPH_R_STATUS Fields: */ +#define WCD9378_HPH_R_STATUS_CMPDR_GAIN_MASK 0xf8 +#define WCD9378_HPH_R_STATUS_OCP_COMP_DETECT_MASK 0x04 +#define WCD9378_HPH_R_STATUS_OCP_LIMIT_MASK 0x02 +#define WCD9378_HPH_R_STATUS_PA_READY_MASK 0x01 + +/* WCD9378_HPH_CNP_EN Fields: */ +#define WCD9378_HPH_CNP_EN_FSM_CLK_EN_MASK 0x80 +#define WCD9378_HPH_CNP_EN_FSM_RESET_MASK 0x40 +#define WCD9378_HPH_CNP_EN_CNP_IREF_SEL_MASK 0x20 +#define WCD9378_HPH_CNP_EN_FSM_OVERRIDE_EN_MASK 0x08 +#define WCD9378_HPH_CNP_EN_WG_LR_SEL_MASK 0x04 +#define WCD9378_HPH_CNP_EN_DBG_CURR_DIRECTION_R_MASK 0x02 +#define WCD9378_HPH_CNP_EN_DBG_VREF_EN_MASK 0x01 + +/* WCD9378_HPH_CNP_WG_CTL Fields: */ +#define WCD9378_HPH_CNP_WG_CTL_GM3_BOOST_EN_MASK 0x80 +#define WCD9378_HPH_CNP_WG_CTL_NO_PD_SEQU_MASK 0x40 +#define WCD9378_HPH_CNP_WG_CTL_VREF_TIMER_MASK 0x38 +#define WCD9378_HPH_CNP_WG_CTL_CURR_LDIV_CTL_MASK 0x07 + +/* WCD9378_HPH_CNP_WG_TIME Fields: */ +#define WCD9378_HPH_CNP_WG_TIME_WG_FINE_TIMER_MASK 0xff + +/* WCD9378_HPH_OCP_CTL Fields: */ +#define WCD9378_HPH_OCP_CTL_OCP_CURR_LIMIT_MASK 0xe0 +#define WCD9378_HPH_OCP_CTL_OCP_FSM_EN_MASK 0x10 +#define WCD9378_HPH_OCP_CTL_SPARE_BITS_MASK 0x08 +#define WCD9378_HPH_OCP_CTL_SCD_OP_EN_MASK 0x02 + +/* WCD9378_HPH_AUTO_CHOP Fields: */ +#define WCD9378_HPH_AUTO_CHOP_AUTO_CHOPPER_MODE_MASK 0x20 +#define WCD9378_HPH_AUTO_CHOP_GAIN_THRESHOLD_MASK 0x1f + +/* WCD9378_HPH_CHOP_CTL Fields: */ +#define WCD9378_HPH_CHOP_CTL_CHOPPER_EN_MASK 0x80 +#define WCD9378_HPH_CHOP_CTL_CLK_INV_MASK 0x40 +#define WCD9378_HPH_CHOP_CTL_DIV2_DIV_BY_2_MASK 0x04 +#define WCD9378_HPH_CHOP_CTL_DIV2_DIV_BY_2_4_6_8_MASK 0x03 + +/* WCD9378_HPH_PA_CTL1 Fields: */ +#define WCD9378_HPH_PA_CTL1_GM3_IBIAS_CTL_MASK 0xf0 +#define WCD9378_HPH_PA_CTL1_GM3_IB_SCALE_MASK 0x0e + +/* WCD9378_HPH_PA_CTL2 Fields: */ +#define WCD9378_HPH_PA_CTL2_SPARE_BITS_MASK 0x80 +#define WCD9378_HPH_PA_CTL2_HPHPA_GND_R_MASK 0x40 +#define WCD9378_HPH_PA_CTL2_HPHPA_GND_L_MASK 0x10 + +/* WCD9378_HPH_L_EN Fields: */ +#define WCD9378_HPH_L_EN_CONST_SEL_L_MASK 0xc0 +#define WCD9378_HPH_L_EN_GAIN_SOURCE_SEL_MASK 0x20 +#define WCD9378_HPH_L_EN_PA_GAIN_MASK 0x1f + +/* WCD9378_HPH_L_TEST Fields: */ +#define WCD9378_HPH_L_TEST_PDN_EN_MASK 0x80 +#define WCD9378_HPH_L_TEST_PDN_AMP2_EN_MASK 0x40 +#define WCD9378_HPH_L_TEST_PDN_AMP_EN_MASK 0x20 +#define WCD9378_HPH_L_TEST_PA_CNP_SW_CONN_MASK 0x10 +#define WCD9378_HPH_L_TEST_PA_CNP_SW_OFF_MASK 0x08 +#define WCD9378_HPH_L_TEST_PA_CNP_SW_ON_MASK 0x04 +#define WCD9378_HPH_L_TEST_OCP_DET_EN_MASK 0x01 + +/* WCD9378_HPH_L_ATEST Fields: */ +#define WCD9378_HPH_L_ATEST_DACL_REF_ATEST1_CONN_MASK 0x80 +#define WCD9378_HPH_L_ATEST_LDO1_L_ATEST2_CONN_MASK 0x40 +#define WCD9378_HPH_L_ATEST_LDO_L_ATEST2_CAL_MASK 0x20 +#define WCD9378_HPH_L_ATEST_LDO2_L_ATEST2_CONN_MASK 0x10 +#define WCD9378_HPH_L_ATEST_HPHPA_GND_OVR_MASK 0x08 +#define WCD9378_HPH_L_ATEST_CNP_EXD2_MASK 0x02 +#define WCD9378_HPH_L_ATEST_CNP_EXD1_MASK 0x01 + +/* WCD9378_HPH_R_EN Fields: */ +#define WCD9378_HPH_R_EN_CONST_SEL_R_MASK 0xc0 +#define WCD9378_HPH_R_EN_GAIN_SOURCE_SEL_MASK 0x20 +#define WCD9378_HPH_R_EN_PA_GAIN_MASK 0x1f + +/* WCD9378_HPH_R_TEST Fields: */ +#define WCD9378_HPH_R_TEST_PDN_EN_MASK 0x80 +#define WCD9378_HPH_R_TEST_PDN_AMP2_EN_MASK 0x40 +#define WCD9378_HPH_R_TEST_PDN_AMP_EN_MASK 0x20 +#define WCD9378_HPH_R_TEST_PA_CNP_SW_CONN_MASK 0x10 +#define WCD9378_HPH_R_TEST_PA_CNP_SW_OFF_MASK 0x08 +#define WCD9378_HPH_R_TEST_PA_CNP_SW_ON_MASK 0x04 +#define WCD9378_HPH_R_TEST_OCP_DET_EN_MASK 0x01 + +/* WCD9378_HPH_R_ATEST Fields: */ +#define WCD9378_HPH_R_ATEST_DACR_REF_ATEST1_CONN_MASK 0x80 +#define WCD9378_HPH_R_ATEST_LDO1_R_ATEST2_CONN_MASK 0x40 +#define WCD9378_HPH_R_ATEST_LDO_R_ATEST2_CAL_MASK 0x20 +#define WCD9378_HPH_R_ATEST_LDO2_R_ATEST2_CONN_MASK 0x10 +#define WCD9378_HPH_R_ATEST_LDO_1P65V_ATEST1_CONN_MASK 0x08 +#define WCD9378_HPH_R_ATEST_HPH_GE_EFUSE_MASK 0x04 +#define WCD9378_HPH_R_ATEST_HPHPA_GND_OVR_MASK 0x02 + +/* WCD9378_HPH_RDAC_CLK_CTL1 Fields: */ +#define WCD9378_HPH_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN_MASK 0x80 +#define WCD9378_HPH_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_DIV_CTRL_MASK 0x70 +#define WCD9378_HPH_RDAC_CLK_CTL1_SPARE_BITS_MASK 0x0f + +/* WCD9378_HPH_RDAC_CLK_CTL2 Fields: */ +#define WCD9378_HPH_RDAC_CLK_CTL2_SPARE_BITS_MASK 0xf0 +#define WCD9378_HPH_RDAC_CLK_CTL2_PREREF_SC_CLK_EN_MASK 0x08 +#define WCD9378_HPH_RDAC_CLK_CTL2_PREREF_SC_CLK_DIVIDER_CTRL_MASK 0x07 + +/* WCD9378_HPH_RDAC_LDO_CTL Fields: */ +#define WCD9378_HPH_RDAC_LDO_CTL_LDO_1P65_BYPASS_MASK 0x80 +#define WCD9378_HPH_RDAC_LDO_CTL_LDO_1P65_OUTCTL_MASK 0x70 +#define WCD9378_HPH_RDAC_LDO_CTL_N1P65V_LDO_BYPASS_MASK 0x08 +#define WCD9378_HPH_RDAC_LDO_CTL_N1P65_LDO_OUTCTL_MASK 0x07 + +/* WCD9378_HPH_RDAC_CHOP_CLK_LP_CTL Fields: */ +#define WCD9378_HPH_RDAC_CHOP_CLK_LP_CTL_OPAMP_CHOP_CLK_EN_LP_MASK 0x80 + +/* WCD9378_HPH_REFBUFF_UHQA_CTL Fields: */ +#define WCD9378_HPH_REFBUFF_UHQA_CTL_OPAMP_IQ_PROG_MASK 0xc0 +#define WCD9378_HPH_REFBUFF_UHQA_CTL_SPARE_BITS_MASK 0x3f + +/* WCD9378_HPH_REFBUFF_LP_CTL Fields: */ +#define WCD9378_HPH_REFBUFF_LP_CTL_SPARE_BITS_MASK 0xc0 +#define WCD9378_HPH_REFBUFF_LP_CTL_OPAMP_IQ_PROG_MASK 0x30 +#define WCD9378_HPH_REFBUFF_LP_CTL_EN_PREREF_FILT_STARTUP_CLKDIV_MASK 0x08 +#define WCD9378_HPH_REFBUFF_LP_CTL_PREREF_FILT_STARTUP_CLKDIV_CTL_MASK 0x06 +#define WCD9378_HPH_REFBUFF_LP_CTL_PREREF_FILT_BYPASS_MASK 0x01 + +/* WCD9378_HPH_L_DAC_CTL Fields: */ +#define WCD9378_HPH_L_DAC_CTL_DAC_REF_EN_MASK 0x40 +#define WCD9378_HPH_L_DAC_CTL_DAC_SAMPLE_EDGE_SELECT_MASK 0x20 +#define WCD9378_HPH_L_DAC_CTL_DATA_RESET_MASK 0x10 +#define WCD9378_HPH_L_DAC_CTL_INV_DATA_MASK 0x08 +#define WCD9378_HPH_L_DAC_CTL_DAC_L_EN_OV_MASK 0x04 +#define WCD9378_HPH_L_DAC_CTL_DAC_LDO_UHQA_OV_MASK 0x02 +#define WCD9378_HPH_L_DAC_CTL_DAC_LDO_POWERMODE_MASK 0x01 + +/* WCD9378_HPH_R_DAC_CTL Fields: */ +#define WCD9378_HPH_R_DAC_CTL_DAC_REF_EN_MASK 0x40 +#define WCD9378_HPH_R_DAC_CTL_DAC_SAMPLE_EDGE_SELECT_MASK 0x20 +#define WCD9378_HPH_R_DAC_CTL_DATA_RESET_MASK 0x10 +#define WCD9378_HPH_R_DAC_CTL_INV_DATA_MASK 0x08 +#define WCD9378_HPH_R_DAC_CTL_DAC_R_EN_OV_MASK 0x04 +#define WCD9378_HPH_R_DAC_CTL_DAC_PREREF_UHQA_OV_MASK 0x02 +#define WCD9378_HPH_R_DAC_CTL_DAC_PREREF_POWERMODE_MASK 0x01 + +/* WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL Fields: */ +#define WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHL_PSURGE_MASK 0xc0 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHL_NSURGE_MASK 0x30 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHR_PSURGE_MASK 0x0c +#define WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHR_NSURGE_MASK 0x03 + +/* WCD9378_HPH_SURGE_HPHLR_SURGE_EN Fields: */ +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN_EN_SURGE_PROTECTION_HPHL_MASK 0x80 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN_EN_SURGE_PROTECTION_HPHR_MASK 0x40 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN_SEL_SURGE_COMP_IQ_MASK 0x30 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN_SURGE_VOLT_MODE_SHUTOFF_EN_MASK 0x08 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN_LATCH_INTR_OP_STG_HIZ_EN_MASK 0x04 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN_SURGE_LATCH_REG_RESET_MASK 0x02 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN_SWTICH_VN_VNDAC_NSURGE_EN_MASK 0x01 + +/* WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1 Fields: */ +#define WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1_EN_VNEG_PULLDN_MASK 0x80 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1_EN_OFFSET_36MV_NSURGE_RESLADDER_MASK 0x40 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1_EN_NMOS_LAMP_MASK 0x20 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1_SPARE_BITS_MASK 0x1f + +/* WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS Fields: */ +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHL_CLAMP_SW_STATUS_MASK 0x80 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHR_CLAMP_SW_STATUS_MASK 0x40 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHL_PSURGE_COMP_STATUS_MASK 0x20 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHL_NSURGE_COMP_STATUS_MASK 0x10 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHR_PSURGE_COMP_STATUS_MASK 0x08 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHR_NSURGE_COMP_STATUS_MASK 0x04 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHL_SURGE_DET_INTR_EN_MASK 0x02 +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS_HPHR_SURGE_DET_INTR_EN_MASK 0x01 + +/* WCD9378_EAR_EAR_EN_REG Fields: */ +#define WCD9378_EAR_EAR_EN_REG_EAR_DAC_DATA_RESET_MASK 0x80 +#define WCD9378_EAR_EAR_EN_REG_EAR_DAC_DATA_EN_MASK 0x40 +#define WCD9378_EAR_EAR_EN_REG_EAR_DAC_REF_EN_MASK 0x20 +#define WCD9378_EAR_EAR_EN_REG_EAR_VCM_EN_MASK 0x10 +#define WCD9378_EAR_EAR_EN_REG_EAR_AMP_EN_MASK 0x08 +#define WCD9378_EAR_EAR_EN_REG_EAR_BIAS_EN_MASK 0x04 +#define WCD9378_EAR_EAR_EN_REG_EAR_CNP_FSM_EN_MASK 0x02 +#define WCD9378_EAR_EAR_EN_REG_EAR_OUTPUT_SHORT_MASK 0x01 + +/* WCD9378_EAR_EAR_PA_CON Fields: */ +#define WCD9378_EAR_EAR_PA_CON_EAR_ANA_AUX_EN_MASK 0x80 +#define WCD9378_EAR_EAR_PA_CON_EAR_CMFB_SF_BYPASS_MASK 0x40 +#define WCD9378_EAR_EAR_PA_CON_EAR_SF_CURR_MASK 0x20 +#define WCD9378_EAR_EAR_PA_CON_EAR_BTI_CTL_MASK 0x10 +#define WCD9378_EAR_EAR_PA_CON_EAR_GM3_IBIAS_CTL_MASK 0x0f + +/* WCD9378_EAR_EAR_SP_CON Fields: */ +#define WCD9378_EAR_EAR_SP_CON_EAR_SP_INT_EN_MASK 0x80 +#define WCD9378_EAR_EAR_SP_CON_EAR_SP_AUTO_SHT_DWN_MASK 0x40 +#define WCD9378_EAR_EAR_SP_CON_SP_LIMIT_CURR_NMOS_MASK 0x38 +#define WCD9378_EAR_EAR_SP_CON_SP_LIMIT_CURR_PMOS_MASK 0x07 + +/* WCD9378_EAR_EAR_DAC_CON Fields: */ +#define WCD9378_EAR_EAR_DAC_CON_DAC_SAMPLE_EDGE_SEL_MASK 0x80 +#define WCD9378_EAR_EAR_DAC_CON_REF_DBG_EN_MASK 0x40 +#define WCD9378_EAR_EAR_DAC_CON_REF_DBG_GAIN_MASK 0x38 +#define WCD9378_EAR_EAR_DAC_CON_GAIN_DAC_MASK 0x06 +#define WCD9378_EAR_EAR_DAC_CON_INV_DATA_MASK 0x01 + +/* WCD9378_EAR_EAR_CNP_FSM_CON Fields: */ +#define WCD9378_EAR_EAR_CNP_FSM_CON_CNP_FSM_CLK_DIV1_MASK 0xf0 +#define WCD9378_EAR_EAR_CNP_FSM_CON_CNP_FSM_CLK_DIV2_MASK 0x0c +#define WCD9378_EAR_EAR_CNP_FSM_CON_SCD_FSM_DEGLITCH_SEL_MASK 0x03 + +/* WCD9378_EAR_TEST_CTL Fields: */ +#define WCD9378_EAR_TEST_CTL_DTEST_EN_MASK 0x80 +#define WCD9378_EAR_TEST_CTL_DTEST_SEL_2_MASK 0x40 +#define WCD9378_EAR_TEST_CTL_EAR_RDAC_ATEST_EN_MASK 0x20 +#define WCD9378_EAR_TEST_CTL_EAR_PA_ATEST_SEL_MASK 0x1f + +/* WCD9378_EAR_STATUS_REG_1 Fields: */ +#define WCD9378_EAR_STATUS_REG_1_SP_INT_MASK 0x80 +#define WCD9378_EAR_STATUS_REG_1_SP_ALL_OUT_MASK 0x40 +#define WCD9378_EAR_STATUS_REG_1_SP_NMOS_OUT_MASK 0x20 +#define WCD9378_EAR_STATUS_REG_1_SP_PMOS_OUT_MASK 0x10 +#define WCD9378_EAR_STATUS_REG_1_PA_READY_MASK 0x08 +#define WCD9378_EAR_STATUS_REG_1_CNP_FSM_STATUS_MASK 0x04 + +/* WCD9378_EAR_STATUS_REG_2 Fields: */ +#define WCD9378_EAR_STATUS_REG_2_PA_EN_MASK 0x80 +#define WCD9378_EAR_STATUS_REG_2_BIAS_EN_MASK 0x40 +#define WCD9378_EAR_STATUS_REG_2_DAC_EN_MASK 0x20 +#define WCD9378_EAR_STATUS_REG_2_VCM_EN_MASK 0x10 +#define WCD9378_EAR_STATUS_REG_2_CLK_EN_MASK 0x08 +#define WCD9378_EAR_STATUS_REG_2_SCD_EN_MASK 0x04 +#define WCD9378_EAR_STATUS_REG_2_SHORT_EN_MASK 0x02 +#define WCD9378_EAR_STATUS_REG_2_DAC_RESET_MASK 0x01 + +/* WCD9378_A_PAGE Fields: */ +#define WCD9378_A_PAGE_VALUE_MASK 0xff + +/* WCD9378_HPH_NEW_ANA_HPH2 Fields: */ +#define WCD9378_HPH_NEW_ANA_HPH2_LP_PWR_CTL_MASK 0xc0 +#define WCD9378_HPH_NEW_ANA_HPH2_SPARE_BITS_MASK 0x3f + +/* WCD9378_HPH_NEW_ANA_HPH3 Fields: */ +#define WCD9378_HPH_NEW_ANA_HPH3_SPARE_BITS_MASK 0xff + +/* WCD9378_SLEEP_CTL Fields: */ +#define WCD9378_SLEEP_CTL_BG_EN_MASK 0x80 +#define WCD9378_SLEEP_CTL_LDOL_BG_SEL_MASK 0x40 +#define WCD9378_SLEEP_CTL_LDORT_REF_SEL_MASK 0x30 +#define WCD9378_SLEEP_CTL_BG_CTL_MASK 0x0e +#define WCD9378_SLEEP_CTL_DUALVIO_DTEST_EN_MASK 0x01 + +/* WCD9378_SLEEP_WATCHDOG_CTL Fields: */ +#define WCD9378_SLEEP_WATCHDOG_CTL_EN_WATCHDOG_MASK 0x80 +#define WCD9378_SLEEP_WATCHDOG_CTL_EN_WATCHDOG_VREFGEN_MASK 0x40 +#define WCD9378_SLEEP_WATCHDOG_CTL_BYPASS_WATCHDOG_MASK 0x20 +#define WCD9378_SLEEP_WATCHDOG_CTL_ATEST_CTL_MASK 0x1c + +/* WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL Fields: */ +#define WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL_FSM_ELECT_CLAMP_EN_MASK 0x80 +#define WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL_SLNQ_ELECT_CLAMP_EN_MASK 0x40 +#define WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL_SLNQ_FAIL_CLAMP_EN_MASK 0x20 +#define WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL_SLNQ_ELECT_REM_RST_MASK 0x10 + +/* WCD9378_MBHC_NEW_CTL_1 Fields: */ +#define WCD9378_MBHC_NEW_CTL_1_RCO_EN_MASK 0x80 +#define WCD9378_MBHC_NEW_CTL_1_ADC_MODE_MASK 0x40 +#define WCD9378_MBHC_NEW_CTL_1_DETECTION_DONE_MASK 0x20 +#define WCD9378_MBHC_NEW_CTL_1_ADC_ENABLE_MASK 0x10 +#define WCD9378_MBHC_NEW_CTL_1_BTN_DBNC_CTL_MASK 0x0f + +/* WCD9378_MBHC_NEW_CTL_2 Fields: */ +#define WCD9378_MBHC_NEW_CTL_2_MUX_CTL_MASK 0x70 +#define WCD9378_MBHC_NEW_CTL_2_M_RTH_CTL_MASK 0x0c +#define WCD9378_MBHC_NEW_CTL_2_HS_VREF_CTL_MASK 0x03 + +/* WCD9378_MBHC_NEW_PLUG_DETECT_CTL Fields: */ +#define WCD9378_MBHC_NEW_PLUG_DETECT_CTL_SPARE_BITS_7_6_MASK 0xc0 +#define WCD9378_MBHC_NEW_PLUG_DETECT_CTL_MIC_CLAMP_CTL_MASK 0x30 +#define WCD9378_MBHC_NEW_PLUG_DETECT_CTL_INSREM_DBNC_CTL_MASK 0x0f + +/* WCD9378_MBHC_NEW_ZDET_ANA_CTL Fields: */ +#define WCD9378_MBHC_NEW_ZDET_ANA_CTL_AVERAGING_EN_MASK 0x80 +#define WCD9378_MBHC_NEW_ZDET_ANA_CTL_ZDET_MAXV_CTL_MASK 0x70 +#define WCD9378_MBHC_NEW_ZDET_ANA_CTL_ZDET_RANGE_CTL_MASK 0x0f + +/* WCD9378_MBHC_NEW_ZDET_RAMP_CTL Fields: */ +#define WCD9378_MBHC_NEW_ZDET_RAMP_CTL_ZDET_RAMP_TIME_CTL_MASK 0x0f + +/* WCD9378_MBHC_NEW_FSM_STATUS Fields: */ +#define WCD9378_MBHC_NEW_FSM_STATUS_ADC_TIMEOUT_MASK 0x80 +#define WCD9378_MBHC_NEW_FSM_STATUS_ADC_COMPLETE_MASK 0x40 +#define WCD9378_MBHC_NEW_FSM_STATUS_HS_M_COMP_STATUS_MASK 0x20 +#define WCD9378_MBHC_NEW_FSM_STATUS_FAST_PRESS_FLAG_STATUS_MASK 0x10 +#define WCD9378_MBHC_NEW_FSM_STATUS_FAST_REMOVAL_FLAG_STATUS_MASK 0x08 +#define WCD9378_MBHC_NEW_FSM_STATUS_REMOVAL_FLAG_STATUS_MASK 0x04 +#define WCD9378_MBHC_NEW_FSM_STATUS_ELECT_REM_RT_STATUS_MASK 0x02 +#define WCD9378_MBHC_NEW_FSM_STATUS_BTN_STATUS_MASK 0x01 + +/* WCD9378_MBHC_NEW_ADC_RESULT Fields: */ +#define WCD9378_MBHC_NEW_ADC_RESULT_ADC_RESULT_MASK 0xff + +/* WCD9378_AUX_AUXPA Fields: */ +#define WCD9378_AUX_AUXPA_AUX_PA_EN_MASK 0x80 +#define WCD9378_AUX_AUXPA_AUX_PA_SHORT_PROT_EN_MASK 0x40 +#define WCD9378_AUX_AUXPA_AUX_PA_OUT_IMP_MASK 0x20 +#define WCD9378_AUX_AUXPA_AUX_PA_CLK_SEL_MASK 0x10 + +/* WCD9378_DIE_CRACK_DIE_CRK_DET_EN Fields: */ +#define WCD9378_DIE_CRACK_DIE_CRK_DET_EN_DIE_CRK_DET_EN_MASK 0x80 +#define WCD9378_DIE_CRACK_DIE_CRK_DET_EN_SEL_CURR_INJCT_PT_MRING_MASK 0x40 + +/* WCD9378_DIE_CRACK_DIE_CRK_DET_OUT Fields: */ +#define WCD9378_DIE_CRACK_DIE_CRK_DET_OUT_DIE_CRK_DET_OUT_MASK 0x80 + +/* WCD9378_TX_NEW_TX_CH12_MUX Fields: */ +#define WCD9378_TX_NEW_TX_CH12_MUX_SPARE_BITS_MASK 0x80 +#define WCD9378_TX_NEW_TX_CH12_MUX_SYS_USAGE_BYP_MASK 0x40 +#define WCD9378_TX_NEW_TX_CH12_MUX_CH2_SEL_MASK 0x38 +#define WCD9378_TX_NEW_TX_CH12_MUX_CH1_SEL_MASK 0x07 + +/* WCD9378_TX_NEW_TX_CH34_MUX Fields: */ +#define WCD9378_TX_NEW_TX_CH34_MUX_SPARE_BITS_MASK 0xf8 +#define WCD9378_TX_NEW_TX_CH34_MUX_CH3_SEL_MASK 0x07 + +/* WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL Fields: */ +#define WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL_RDAC_GAINCTL_MASK 0xf0 +#define WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL_REFBUF_CMFB2_ZERO_PROG_MASK 0x08 +#define WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL_SPARE_BITS_MASK 0x07 + +/* WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L Fields: */ +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L_EN_HD2_RES_DIV_L_MASK 0x80 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L_HD2_RES_DIV_PULLGND_L_MASK 0x40 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L_SPARE_BITS_MASK 0x20 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L_SELECT_HD2_RES_DIV_L_MASK 0x10 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L_MASK 0x0f + +/* WCD9378_HPH_NEW_INT_RDAC_VREF_CTL Fields: */ +#define WCD9378_HPH_NEW_INT_RDAC_VREF_CTL_EN_REFCURRENT_RDEG_SHORT_MASK 0x80 +#define WCD9378_HPH_NEW_INT_RDAC_VREF_CTL_RDAC_REFBUF_RFB_9K_MASK 0x40 +#define WCD9378_HPH_NEW_INT_RDAC_VREF_CTL_LP_RDAC_REFBUF_RFB_CTL_MASK 0x30 +#define WCD9378_HPH_NEW_INT_RDAC_VREF_CTL_RDAC_REFCURRENT_IREF_2UA_MASK 0x08 +#define WCD9378_HPH_NEW_INT_RDAC_VREF_CTL_SPARE_BITS_MASK 0x07 + +/* WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL Fields: */ +#define WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL_REFBUF_RFB_OVRIDE_MASK 0x80 +#define WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL_REFBUF_IREF_OVRIDE_MASK 0x40 +#define WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL_REFCURRENT_RDEG_CTL_OVRIDE_MASK 0x20 +#define WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL_REFBUF_CMFB2_ZERO_OVRIDE_MASK 0x10 +#define WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL_RDAC_IDLE_DETECT_OVERRIDE_MASK 0x08 +#define WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL_SPARE_BITS_MASK 0x07 + +/* WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R Fields: */ +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R_EN_HD2_RES_DIV_R_MASK 0x80 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R_HD2_RES_DIV_PULLGND_R_MASK 0x40 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R_SPARE_BITS_MASK 0x20 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R_SELECT_HD2_RES_DIV_R_MASK 0x10 +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R_MASK 0x0f + +/* WCD9378_HPH_NEW_INT_PA_MISC1 Fields: */ +#define WCD9378_HPH_NEW_INT_PA_MISC1_EN_AUTO_CMPDR_DETECTION_MASK 0x80 +#define WCD9378_HPH_NEW_INT_PA_MISC1_EN_PA_IDLE_DETECT_OVERRIDE_MASK 0x40 +#define WCD9378_HPH_NEW_INT_PA_MISC1_D_PZ_INF_EN_MASK 0x20 +#define WCD9378_HPH_NEW_INT_PA_MISC1_SPARE_BITS_MASK 0x18 +#define WCD9378_HPH_NEW_INT_PA_MISC1_PA_CHOP_EN_OVERRIDE_MASK 0x04 +#define WCD9378_HPH_NEW_INT_PA_MISC1_OCP_FSM_LOCK_EN_MASK 0x02 +#define WCD9378_HPH_NEW_INT_PA_MISC1_AUTOCHOP_PDN_SEQ_OVERRIDE_MASK 0x01 + +/* WCD9378_HPH_NEW_INT_PA_MISC2 Fields: */ +#define WCD9378_HPH_NEW_INT_PA_MISC2_HPHPA_HI_Z_MASK 0x80 +#define WCD9378_HPH_NEW_INT_PA_MISC2_HPH_PSRR_ENH_MASK 0x40 +#define WCD9378_HPH_NEW_INT_PA_MISC2_FORCE_IQCTRL_MASK 0x20 +#define WCD9378_HPH_NEW_INT_PA_MISC2_FORCE_PSRREH_MASK 0x10 +#define WCD9378_HPH_NEW_INT_PA_MISC2_CHOP_CLKLAP_SEL_MASK 0x08 +#define WCD9378_HPH_NEW_INT_PA_MISC2_SPARE_BITS_MASK 0x04 +#define WCD9378_HPH_NEW_INT_PA_MISC2_IDLE_DETECT_L_DTEST_ENABLE_MASK 0x02 +#define WCD9378_HPH_NEW_INT_PA_MISC2_IDLE_DETECT_R_DTEST_ENABLE_MASK 0x01 + +/* WCD9378_HPH_NEW_INT_PA_RDAC_MISC Fields: */ +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC_CNP_WG_FINE_TIME_LSB_CTL_MASK 0xf0 +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC_SPARE_BITS_MASK 0x0c +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC_RDAC_PSW_REG_CTL_MASK 0x03 + +/* WCD9378_HPH_NEW_INT_HPH_TIMER1 Fields: */ +#define WCD9378_HPH_NEW_INT_HPH_TIMER1_CURR_IDIV_CTL_CMPDR_OFF_MASK 0xe0 +#define WCD9378_HPH_NEW_INT_HPH_TIMER1_CURR_IDIV_CTL_AUTOCHOP_MASK 0x1c +#define WCD9378_HPH_NEW_INT_HPH_TIMER1_AUTOCHOP_TIMER_CTL_EN_MASK 0x02 +#define WCD9378_HPH_NEW_INT_HPH_TIMER1_SPARE_BITS_MASK 0x01 + +/* WCD9378_HPH_NEW_INT_HPH_TIMER2 Fields: */ +#define WCD9378_HPH_NEW_INT_HPH_TIMER2_VREF_TIMER_IDLESTATE_MASK 0xe0 +#define WCD9378_HPH_NEW_INT_HPH_TIMER2_CNP_WG_FINE_TIME_LSB_CTL_IDLE_MASK 0x1e +#define WCD9378_HPH_NEW_INT_HPH_TIMER2_SPARE_BITS_MASK 0x01 + +/* WCD9378_HPH_NEW_INT_HPH_TIMER3 Fields: */ +#define WCD9378_HPH_NEW_INT_HPH_TIMER3_WG_FINE_TIMER_CMPDR_OFF_MASK 0xff + +/* WCD9378_HPH_NEW_INT_HPH_TIMER4 Fields: */ +#define WCD9378_HPH_NEW_INT_HPH_TIMER4_WG_FINE_TIMER_AUTOCHOP_MASK 0xff + +/* WCD9378_HPH_NEW_INT_PA_RDAC_MISC2 Fields: */ +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC2_SPARE_BITS_MASK 0xff + +/* WCD9378_HPH_NEW_INT_PA_RDAC_MISC3 Fields: */ +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC3_SPARE_BITS_MASK 0xff + +/* WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI Fields: */ +#define WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI_HPHPA_BIAS_LOHIFI_MASK 0xf0 +#define WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI_HPHRDAC_BIAS_LOHIFI_MASK 0x0f + +/* WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_ULP Fields: */ +#define WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_ULP_SPARE_BITS_MASK 0xf0 +#define WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_ULP_HPHRDAC_BIAS_ULP_MASK 0x0f + +/* WCD9378_RX_NEW_INT_HPH_RDAC_LDO_LP Fields: */ +#define WCD9378_RX_NEW_INT_HPH_RDAC_LDO_LP_HPHRDAC_1P6VLDO_BIAS_LP_MASK 0xf0 +#define WCD9378_RX_NEW_INT_HPH_RDAC_LDO_LP_HPHRDAC_N1P6VLDO_BIAS_LP_MASK 0x0f + +/* WCD9378_CP_CLASSG_CP_CTRL_0 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_0_DIS_CP_LDO_MASK 0x10 +#define WCD9378_CP_CLASSG_CP_CTRL_0_EN_VPOS_CMP_MASK 0x08 +#define WCD9378_CP_CLASSG_CP_CTRL_0_EN_VPOS_CMP_OV_MASK 0x04 +#define WCD9378_CP_CLASSG_CP_CTRL_0_EN_CP_VAL_MASK 0x02 +#define WCD9378_CP_CLASSG_CP_CTRL_0_EN_CP_OV_MASK 0x01 + +/* WCD9378_CP_CLASSG_CP_CTRL_1 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_1_TNOV_SEL_MASK 0x01 + +/* WCD9378_CP_CLASSG_CP_CTRL_2 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_2_IB_LDO_SEL_MASK 0xc0 +#define WCD9378_CP_CLASSG_CP_CTRL_2_VGN_LDO_SEL_MASK 0x3c +#define WCD9378_CP_CLASSG_CP_CTRL_2_SW_SIZE_MASK 0x03 + +/* WCD9378_CP_CLASSG_CP_CTRL_3 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_3_IB_CMP_SEL_MASK 0x60 +#define WCD9378_CP_CLASSG_CP_CTRL_3_VHYST_CMP_SEL_MASK 0x18 +#define WCD9378_CP_CLASSG_CP_CTRL_3_VTH_CMP_SEL_MASK 0x07 + +/* WCD9378_CP_CLASSG_CP_CTRL_4 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_4_DTEST_EN_MASK 0x80 +#define WCD9378_CP_CLASSG_CP_CTRL_4_DTEST_SEL_MASK 0x70 +#define WCD9378_CP_CLASSG_CP_CTRL_4_ATEST_EN_MASK 0x08 +#define WCD9378_CP_CLASSG_CP_CTRL_4_ATEST_SEL_MASK 0x07 + +/* WCD9378_CP_CLASSG_CP_CTRL_5 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_5_VPOS_FILT_RSEL_MASK 0x0c +#define WCD9378_CP_CLASSG_CP_CTRL_5_VDD_CP_LPF_R_SEL_MASK 0x03 + +/* WCD9378_CP_CLASSG_CP_CTRL_6 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_6_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_CP_CLASSG_CP_CTRL_7 Fields: */ +#define WCD9378_CP_CLASSG_CP_CTRL_7_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_CP_VNEGDAC_CTRL_0 Fields: */ +#define WCD9378_CP_VNEGDAC_CTRL_0_IB_LDO_SEL_MASK 0xc0 +#define WCD9378_CP_VNEGDAC_CTRL_0_VGN_LDO_SEL_MASK 0x3c +#define WCD9378_CP_VNEGDAC_CTRL_0_SW_SIZE_MASK 0x03 + +/* WCD9378_CP_VNEGDAC_CTRL_1 Fields: */ +#define WCD9378_CP_VNEGDAC_CTRL_1_TNOV_SEL_NCP_MASK 0x01 + +/* WCD9378_CP_VNEGDAC_CTRL_2 Fields: */ +#define WCD9378_CP_VNEGDAC_CTRL_2_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_CP_VNEGDAC_CTRL_3 Fields: */ +#define WCD9378_CP_VNEGDAC_CTRL_3_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_CP_CP_DTOP_CTRL_0 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_0_SWR_CLK_RATE_MASK 0x80 +#define WCD9378_CP_CP_DTOP_CTRL_0_CP_CLK_EDGE_SEL_MASK 0x40 +#define WCD9378_CP_CP_DTOP_CTRL_0_TEST_INT_CLK_MASK 0x20 +#define WCD9378_CP_CP_DTOP_CTRL_0_NCP_CLK_EDGE_SEL_MASK 0x10 +#define WCD9378_CP_CP_DTOP_CTRL_0_NCP_TEST_INT_CLK_MASK 0x08 +#define WCD9378_CP_CP_DTOP_CTRL_0_OVERRIDE_SWR_CLK_RATE_MASK 0x04 + +/* WCD9378_CP_CP_DTOP_CTRL_1 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_1_VTH_1_SEL_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_1_VTH_0_SEL_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_2 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_2_VTH_3_SEL_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_2_VTH_2_SEL_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_3 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_3_VTH_5_SEL_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_3_VTH_4_SEL_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_4 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_4_VTH_7_SEL_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_4_VTH_6_SEL_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_5 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_5_VTH_9_SEL_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_5_VTH_8_SEL_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_6 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_6_VTH_11_SEL_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_6_VTH_10_SEL_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_7 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_7_VTH_12_SEL_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_8 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_8_TPW_G0P5_PH1_SEL_MASK 0xf0 +#define WCD9378_CP_CP_DTOP_CTRL_8_TPW_G0P5_PH2_SEL_MASK 0x0f + +/* WCD9378_CP_CP_DTOP_CTRL_9 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_9_TPW_G1_PH1_SEL_MASK 0xf0 +#define WCD9378_CP_CP_DTOP_CTRL_9_DISABLE_TWAIT_MASK 0x08 +#define WCD9378_CP_CP_DTOP_CTRL_9_TWAIT_G1_STEP3_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_10 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_10_TWAIT_G1_STEP2_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_10_TWAIT_G1_STEP1_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_11 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_11_TWAIT_G0P5_STEP3_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_12 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_12_TWAIT_G0P5_STEP2_MASK 0x38 +#define WCD9378_CP_CP_DTOP_CTRL_12_TWAIT_G0P5_STEP1_MASK 0x07 + +/* WCD9378_CP_CP_DTOP_CTRL_13 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_13_INVERT_CP_CLKS_MASK 0x80 +#define WCD9378_CP_CP_DTOP_CTRL_13_GATE_OFF_S10P_MASK 0x40 +#define WCD9378_CP_CP_DTOP_CTRL_13_GATE_OFF_S6P_MASK 0x20 +#define WCD9378_CP_CP_DTOP_CTRL_13_GATE_OFF_S5N_MASK 0x10 +#define WCD9378_CP_CP_DTOP_CTRL_13_GATE_OFF_S4N_MASK 0x08 +#define WCD9378_CP_CP_DTOP_CTRL_13_GATE_OFF_S3P_MASK 0x04 +#define WCD9378_CP_CP_DTOP_CTRL_13_GATE_OFF_S2N_MASK 0x02 +#define WCD9378_CP_CP_DTOP_CTRL_13_GATE_OFF_S1P_MASK 0x01 + +/* WCD9378_CP_CP_DTOP_CTRL_14 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_14_OVERRIDE_VREF_MASK 0x80 +#define WCD9378_CP_CP_DTOP_CTRL_14_OVERRIDE_FSW_VAL_MASK 0x78 +#define WCD9378_CP_CP_DTOP_CTRL_14_OVERRIDE_FSW_MASK 0x04 +#define WCD9378_CP_CP_DTOP_CTRL_14_OVERRIDE_G_VAL_MASK 0x02 +#define WCD9378_CP_CP_DTOP_CTRL_14_OVERRIDE_G_MASK 0x01 + +/* WCD9378_CP_CP_DTOP_CTRL_15 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_15_OVERRIDE_VREF_VAL_MASK 0xff + +/* WCD9378_CP_CP_DTOP_CTRL_16 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_16_OVERRIDE_SWSIZE_VAL_MASK 0x06 +#define WCD9378_CP_CP_DTOP_CTRL_16_OVERRIDE_SWSIZE_MASK 0x01 + +/* WCD9378_CP_CP_DTOP_CTRL_17 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_17_TPW_PH1_SEL_MASK 0x0f + +/* WCD9378_CP_CP_DTOP_CTRL_18 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_18_OVERRIDE_NCP_FSW_VAL_MASK 0x78 +#define WCD9378_CP_CP_DTOP_CTRL_18_OVERRIDE_NCP_FSW_MASK 0x04 +#define WCD9378_CP_CP_DTOP_CTRL_18_INVERT_CLKS_MASK 0x02 +#define WCD9378_CP_CP_DTOP_CTRL_18_GATE_OFF_NCP_CLK_MASK 0x01 + +/* WCD9378_CP_CP_DTOP_CTRL_19 Fields: */ +#define WCD9378_CP_CP_DTOP_CTRL_19_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL Fields: */ +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL_ONCOUNT_MASK 0x60 +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL_OFFCOUNT_MASK 0x1f + +/* WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL Fields: */ +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL_HPHL_PA_EN_MASK 0x40 +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL_DTEST_EN_MASK 0x30 +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL_MOISTURE_OVRD_POLLING_MASK 0x08 +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL_MOISTURE_EN_POLLING_MASK 0x04 +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL_MOISTURE_DBNC_TIME_MASK 0x03 + +/* WCD9378_MBHC_NEW_INT_MECH_DET_CURRENT Fields: */ +#define WCD9378_MBHC_NEW_INT_MECH_DET_CURRENT_HSDET_PULLUP_CTL_MASK 0x1f + +/* WCD9378_MBHC_NEW_INT_SPARE_2 Fields: */ +#define WCD9378_MBHC_NEW_INT_SPARE_2_ZDET_TIMER_MASK 0x80 +#define WCD9378_MBHC_NEW_INT_SPARE_2_SPARE_BITS_6_0_MASK 0x7f + +/* WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON Fields: */ +#define WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON_EAR_CHOPPER_EN_MASK 0x80 +#define WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_DIV_MASK 0x78 +#define WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_INV_MASK 0x04 +#define WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_OVERLAP_MASK 0x02 +#define WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON_SCD_SHTDWN_FAST_PATH_DIS_MASK 0x01 + +/* WCD9378_EAR_INT_NEW_CNP_VCM_CON1 Fields: */ +#define WCD9378_EAR_INT_NEW_CNP_VCM_CON1_SCD_EN_TIME_SEL_MASK 0x80 +#define WCD9378_EAR_INT_NEW_CNP_VCM_CON1_NO_DYN_BIAS_DURING_STARTUP_MASK 0x40 +#define WCD9378_EAR_INT_NEW_CNP_VCM_CON1_CNP_VCM_GEN_START_MASK 0x3f + +/* WCD9378_EAR_INT_NEW_CNP_VCM_CON2 Fields: */ +#define WCD9378_EAR_INT_NEW_CNP_VCM_CON2_DTEST_SEL_MASK 0xc0 +#define WCD9378_EAR_INT_NEW_CNP_VCM_CON2_CNP_VCM_GEN_STOP_MASK 0x3f + +/* WCD9378_EAR_INT_NEW_EAR_DYNAMIC_BIAS Fields: */ +#define WCD9378_EAR_INT_NEW_EAR_DYNAMIC_BIAS_EAR_DYN_BIAS_SEL_MASK 0xe0 +#define WCD9378_EAR_INT_NEW_EAR_DYNAMIC_BIAS_EAR_BIAS_CURR_MASK 0x1f + +/* WCD9378_AUX_INT_EN_REG Fields: */ +#define WCD9378_AUX_INT_EN_REG_DAC_DATA_RESET_MASK 0x80 +#define WCD9378_AUX_INT_EN_REG_DAC_DATA_EN_MASK 0x40 +#define WCD9378_AUX_INT_EN_REG_DAC_REF_EN_MASK 0x20 +#define WCD9378_AUX_INT_EN_REG_AMP_EN_MASK 0x10 +#define WCD9378_AUX_INT_EN_REG_BIAS_EN_MASK 0x08 +#define WCD9378_AUX_INT_EN_REG_OUTPUT_SHORT_MASK 0x04 +#define WCD9378_AUX_INT_EN_REG_CNP_FSM_RESET_MASK 0x02 +#define WCD9378_AUX_INT_EN_REG_REG_OVERRIDE_EN_MASK 0x01 + +/* WCD9378_AUX_INT_PA_CTRL Fields: */ +#define WCD9378_AUX_INT_PA_CTRL_SPARE_BITS_7_6_MASK 0xc0 +#define WCD9378_AUX_INT_PA_CTRL_CMFB_LSF_CURR_MASK 0x20 +#define WCD9378_AUX_INT_PA_CTRL_BTI_CTL_MASK 0x10 +#define WCD9378_AUX_INT_PA_CTRL_GM3_IBIAS_CTL_MASK 0x0f + +/* WCD9378_AUX_INT_SP_CTRL Fields: */ +#define WCD9378_AUX_INT_SP_CTRL_SP_INT_EN_MASK 0x80 +#define WCD9378_AUX_INT_SP_CTRL_SP_AUTO_SHUT_DOWN_MASK 0x40 +#define WCD9378_AUX_INT_SP_CTRL_SP_LIMIT_CURR_NMOS_MASK 0x38 +#define WCD9378_AUX_INT_SP_CTRL_SP_LIMIT_CURR_PMOS_MASK 0x07 + +/* WCD9378_AUX_INT_DAC_CTRL Fields: */ +#define WCD9378_AUX_INT_DAC_CTRL_DAC_SAMPLE_EDGE_SEL_MASK 0x80 +#define WCD9378_AUX_INT_DAC_CTRL_REF_DBG_EN_MASK 0x40 +#define WCD9378_AUX_INT_DAC_CTRL_REF_DBG_GAIN_MASK 0x38 +#define WCD9378_AUX_INT_DAC_CTRL_GAIN_DAC_MASK 0x06 +#define WCD9378_AUX_INT_DAC_CTRL_INV_DATA_MASK 0x01 + +/* WCD9378_AUX_INT_CLK_CTRL Fields: */ +#define WCD9378_AUX_INT_CLK_CTRL_GNDSW_TIMER_MASK 0xe0 +#define WCD9378_AUX_INT_CLK_CTRL_SCD_DEGLITCH_SEL_MASK 0x18 +#define WCD9378_AUX_INT_CLK_CTRL_SPARE_BITS_2_0_MASK 0x07 + +/* WCD9378_AUX_INT_TEST_CTRL Fields: */ +#define WCD9378_AUX_INT_TEST_CTRL_SPARE_BITS_7_5_MASK 0xe0 +#define WCD9378_AUX_INT_TEST_CTRL_DAC_ATEST_EN_MASK 0x10 +#define WCD9378_AUX_INT_TEST_CTRL_PA_ATEST_EN_MASK 0x08 +#define WCD9378_AUX_INT_TEST_CTRL_PA_ATEST_SEL_MASK 0x07 + +/* WCD9378_AUX_INT_STATUS_REG Fields: */ +#define WCD9378_AUX_INT_STATUS_REG_SP_INT_MASK 0x80 +#define WCD9378_AUX_INT_STATUS_REG_SP_OUT_MASK 0x40 +#define WCD9378_AUX_INT_STATUS_REG_SP_NMOS_OUT_MASK 0x20 +#define WCD9378_AUX_INT_STATUS_REG_SP_PMOS_OUT_MASK 0x10 +#define WCD9378_AUX_INT_STATUS_REG_PA_READY_MASK 0x08 +#define WCD9378_AUX_INT_STATUS_REG_SPARE_BITS_2_0_MASK 0x07 + +/* WCD9378_AUX_INT_MISC Fields: */ +#define WCD9378_AUX_INT_MISC_SPARE_BITS_7_4_MASK 0xf0 +#define WCD9378_AUX_INT_MISC_PA_GAIN_MASK 0x0f + +/* WCD9378_SLEEP_INT_WATCHDOG_CTL_1 Fields: */ +#define WCD9378_SLEEP_INT_WATCHDOG_CTL_1_VREF_HI_CTL_MASK 0x1f + +/* WCD9378_SLEEP_INT_WATCHDOG_CTL_2 Fields: */ +#define WCD9378_SLEEP_INT_WATCHDOG_CTL_2_VREF_LO_CTL_MASK 0x1f + +/* WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1 Fields: */ +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1_SEL_EDGE_DET_MASK 0xc0 +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1_EN_RINGM_ATEST_MASK 0x20 +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1_EN_RINGP_ATEST_MASK 0x10 +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1_RING_CURR_SEL_MASK 0x0e +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1_EN_VREF_ATEST_MASK 0x01 + +/* WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2 Fields: */ +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2_REF_CURR_SEL_MASK 0xe0 +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2_COMP_STG1_IBIAS_MASK 0x18 +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2_COMP_STG2_IBIAS_MASK 0x06 +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2_EN_ATEST_MASK 0x01 + +/* WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L2 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L2_DIV_L2_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L1 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L1_DIV_L1_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L0 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L0_DIV_L0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_SPARE1 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE1_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_SPARE2 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE2_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L2 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L2_NINIT_L2_MASK 0xc0 +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L2_SPARE_BITS_4_0_MASK 0x1f + +/* WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L1 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L1_NINIT_L1_MASK 0xc0 +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L1_SPARE_BITS_4_0_MASK 0x1f + +/* WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L0 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L0_NINIT_L0_MASK 0xc0 +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L0_SPARE_BITS_4_0_MASK 0x1f + +/* WCD9378_TX_COM_NEW_INT_SPARE3 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE3_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_SPARE4 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE4_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_SPARE5 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE5_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_SPARE6 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE6_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_SPARE7 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE7_SPARE_BITS_7_0_MASK 0xff + +/* WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1_ICTRL_SCBIAS_L2_MASK 0xf0 +#define WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1_ICTRL_SCBIAS_L1_MASK 0x0f + +/* WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L0 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L0_ICTRL_SCBIAS_L0_MASK 0xf0 +#define WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L0_SPARE_BITS_3_0_MASK 0x0f + +/* WCD9378_TX_COM_NEW_INT_TXADC_INT_L2 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L2_INT1_L2_MASK 0xf0 +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L2_INT2_L2_MASK 0x0f + +/* WCD9378_TX_COM_NEW_INT_TXADC_INT_L1 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L1_INT1_L1_MASK 0xf0 +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L1_INT2_L1_MASK 0x0f + +/* WCD9378_TX_COM_NEW_INT_TXADC_INT_L0 Fields: */ +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L0_INT1_L0_MASK 0xf0 +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L0_INT2_L0_MASK 0x0f + +/* WCD9378_TX_COM_NEW_INT_SPARE8 Fields: */ +#define WCD9378_TX_COM_NEW_INT_SPARE8_SPARE_BITS_7_0_MASK 0xff + + +/* WCD9378_TAMBORA_PAGE Fields: */ +#define WCD9378_TAMBORA_PAGE_PAG_REG_MASK 0xff + +/* WCD9378_CHIP_ID0 Fields: */ +#define WCD9378_CHIP_ID0_BYTE_0_MASK 0xff + +/* WCD9378_CHIP_ID1 Fields: */ +#define WCD9378_CHIP_ID1_BYTE_1_MASK 0xff + +/* WCD9378_CHIP_ID2 Fields: */ +#define WCD9378_CHIP_ID2_BYTE_2_MASK 0xff + +/* WCD9378_CHIP_ID3 Fields: */ +#define WCD9378_CHIP_ID3_BYTE_3_MASK 0xff + +/* WCD9378_SWR_TX_CLK_RATE Fields: */ +#define WCD9378_SWR_TX_CLK_RATE_CLK_RATE_BK_1_MASK 0xf0 +#define WCD9378_SWR_TX_CLK_RATE_CLK_RATE_BK_0_MASK 0x0f + +/* WCD9378_CDC_RST_CTL Fields: */ +#define WCD9378_CDC_RST_CTL_ANA_SW_RST_N_MASK 0x02 +#define WCD9378_CDC_RST_CTL_DIG_SW_RST_N_MASK 0x01 + +/* WCD9378_TOP_CLK_CFG Fields: */ +#define WCD9378_TOP_CLK_CFG_RX_CLK_CFG_MASK 0x06 +#define WCD9378_TOP_CLK_CFG_TX_CLK_CFG_MASK 0x01 + +/* WCD9378_CDC_ANA_CLK_CTL Fields: */ +#define WCD9378_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN_MASK 0x04 +#define WCD9378_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN_MASK 0x02 +#define WCD9378_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN_MASK 0x01 + +/* WCD9378_CDC_DIG_CLK_CTL Fields: */ +#define WCD9378_CDC_DIG_CLK_CTL_TXD2_CLK_EN_MASK 0x40 +#define WCD9378_CDC_DIG_CLK_CTL_TXD1_CLK_EN_MASK 0x20 +#define WCD9378_CDC_DIG_CLK_CTL_TXD0_CLK_EN_MASK 0x10 +#define WCD9378_CDC_DIG_CLK_CTL_RXD2_CLK_EN_MASK 0x04 +#define WCD9378_CDC_DIG_CLK_CTL_RXD1_CLK_EN_MASK 0x02 +#define WCD9378_CDC_DIG_CLK_CTL_RXD0_CLK_EN_MASK 0x01 + +/* WCD9378_SWR_RST_EN Fields: */ +#define WCD9378_SWR_RST_EN_RX_RESET_SYNC_LOST_EN_MASK 0x20 +#define WCD9378_SWR_RST_EN_RX_RESET_SWR_BUS_EN_MASK 0x10 +#define WCD9378_SWR_RST_EN_RX_RESET_SWR_REG_EN_MASK 0x08 +#define WCD9378_SWR_RST_EN_TX_RESET_SYNC_LOST_EN_MASK 0x04 +#define WCD9378_SWR_RST_EN_TX_RESET_SWR_BUS_EN_MASK 0x02 +#define WCD9378_SWR_RST_EN_TX_RESET_SWR_REG_EN_MASK 0x01 + +/* WCD9378_CDC_PATH_MODE Fields: */ +#define WCD9378_CDC_PATH_MODE_RX2_CLK_RATE_MASK 0x40 + +/* WCD9378_CDC_RX_RST Fields: */ +#define WCD9378_CDC_RX_RST_RX2_SOFT_RST_MASK 0x04 +#define WCD9378_CDC_RX_RST_RX1_SOFT_RST_MASK 0x02 +#define WCD9378_CDC_RX_RST_RX0_SOFT_RST_MASK 0x01 + +/* WCD9378_CDC_RX0_CTL Fields: */ +#define WCD9378_CDC_RX0_CTL_DSM_DITHER_ENABLE_MASK 0x80 +#define WCD9378_CDC_RX0_CTL_DEM_DITHER_ENABLE_MASK 0x40 +#define WCD9378_CDC_RX0_CTL_DEM_MID_ENABLE_MASK 0x20 +#define WCD9378_CDC_RX0_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_MASK 0x10 +#define WCD9378_CDC_RX0_CTL_DEM_SWITCHING_BLOCK_ENABLE_MASK 0x08 +#define WCD9378_CDC_RX0_CTL_DEM_SEGMENTING_BLOCK_ENABLE_MASK 0x04 +#define WCD9378_CDC_RX0_CTL_DEM_BYPASS_MASK 0x02 + +/* WCD9378_CDC_RX1_CTL Fields: */ +#define WCD9378_CDC_RX1_CTL_DSM_DITHER_ENABLE_MASK 0x80 +#define WCD9378_CDC_RX1_CTL_DEM_DITHER_ENABLE_MASK 0x40 +#define WCD9378_CDC_RX1_CTL_DEM_MID_ENABLE_MASK 0x20 +#define WCD9378_CDC_RX1_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_MASK 0x10 +#define WCD9378_CDC_RX1_CTL_DEM_SWITCHING_BLOCK_ENABLE_MASK 0x08 +#define WCD9378_CDC_RX1_CTL_DEM_SEGMENTING_BLOCK_ENABLE_MASK 0x04 +#define WCD9378_CDC_RX1_CTL_DEM_BYPASS_MASK 0x02 + +/* WCD9378_CDC_RX2_CTL Fields: */ +#define WCD9378_CDC_RX2_CTL_DSM_DITHER_ENABLE_MASK 0x80 +#define WCD9378_CDC_RX2_CTL_DEM_DITHER_ENABLE_MASK 0x40 +#define WCD9378_CDC_RX2_CTL_DEM_MID_ENABLE_MASK 0x20 +#define WCD9378_CDC_RX2_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_MASK 0x10 +#define WCD9378_CDC_RX2_CTL_DEM_SWITCHING_BLOCK_ENABLE_MASK 0x08 +#define WCD9378_CDC_RX2_CTL_DEM_SEGMENTING_BLOCK_ENABLE_MASK 0x04 +#define WCD9378_CDC_RX2_CTL_DEM_BYPASS_MASK 0x02 + +/* WCD9378_CDC_TX_ANA_MODE_0_1 Fields: */ +#define WCD9378_CDC_TX_ANA_MODE_0_1_TXD1_MODE_MASK 0xf0 +#define WCD9378_CDC_TX_ANA_MODE_0_1_TXD0_MODE_MASK 0x0f + +/* WCD9378_CDC_TX_ANA_MODE_2_3 Fields: */ +#define WCD9378_CDC_TX_ANA_MODE_2_3_TXD2_MODE_MASK 0x0f + +/* WCD9378_CDC_COMP_CTL_0 Fields: */ +#define WCD9378_CDC_COMP_CTL_0_EAR_COMP_EN_MASK 0x04 +#define WCD9378_CDC_COMP_CTL_0_HPHL_COMP_EN_MASK 0x02 +#define WCD9378_CDC_COMP_CTL_0_HPHR_COMP_EN_MASK 0x01 + +/* WCD9378_CDC_ANA_TX_CLK_CTL Fields: */ +#define WCD9378_CDC_ANA_TX_CLK_CTL_ANA_TX2_ADC_CLK_EN_MASK 0x08 +#define WCD9378_CDC_ANA_TX_CLK_CTL_ANA_TX1_ADC_CLK_EN_MASK 0x04 +#define WCD9378_CDC_ANA_TX_CLK_CTL_ANA_TX0_ADC_CLK_EN_MASK 0x02 +#define WCD9378_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN_MASK 0x01 + +/* WCD9378_CDC_HPH_DSM_A1_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_A1_0_COEF_A1_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_A1_1 Fields: */ +#define WCD9378_CDC_HPH_DSM_A1_1_COEF_A1_MASK 0x01 + +/* WCD9378_CDC_HPH_DSM_A2_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_A2_0_COEF_A2_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_A2_1 Fields: */ +#define WCD9378_CDC_HPH_DSM_A2_1_COEF_A2_MASK 0x0f + +/* WCD9378_CDC_HPH_DSM_A3_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_A3_0_COEF_A3_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_A3_1 Fields: */ +#define WCD9378_CDC_HPH_DSM_A3_1_COEF_A3_MASK 0x07 + +/* WCD9378_CDC_HPH_DSM_A4_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_A4_0_COEF_A4_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_A4_1 Fields: */ +#define WCD9378_CDC_HPH_DSM_A4_1_COEF_A4_MASK 0x03 + +/* WCD9378_CDC_HPH_DSM_A5_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_A5_0_COEF_A5_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_A5_1 Fields: */ +#define WCD9378_CDC_HPH_DSM_A5_1_COEF_A5_MASK 0x03 + +/* WCD9378_CDC_HPH_DSM_A6_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_A6_0_COEF_A6_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_A7_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_A7_0_COEF_A7_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_C_0 Fields: */ +#define WCD9378_CDC_HPH_DSM_C_0_COEF_C3_MASK 0xf0 +#define WCD9378_CDC_HPH_DSM_C_0_COEF_C2_MASK 0x0f + +/* WCD9378_CDC_HPH_DSM_C_1 Fields: */ +#define WCD9378_CDC_HPH_DSM_C_1_COEF_C5_MASK 0xf0 +#define WCD9378_CDC_HPH_DSM_C_1_COEF_C4_MASK 0x0f + +/* WCD9378_CDC_HPH_DSM_C_2 Fields: */ +#define WCD9378_CDC_HPH_DSM_C_2_COEF_C7_MASK 0xf0 +#define WCD9378_CDC_HPH_DSM_C_2_COEF_C6_MASK 0x0f + +/* WCD9378_CDC_HPH_DSM_C_3 Fields: */ +#define WCD9378_CDC_HPH_DSM_C_3_COEF_C7_MASK 0x3f + +/* WCD9378_CDC_HPH_DSM_R1 Fields: */ +#define WCD9378_CDC_HPH_DSM_R1_SAT_LIMIT_R1_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_R2 Fields: */ +#define WCD9378_CDC_HPH_DSM_R2_SAT_LIMIT_R2_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_R3 Fields: */ +#define WCD9378_CDC_HPH_DSM_R3_SAT_LIMIT_R3_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_R4 Fields: */ +#define WCD9378_CDC_HPH_DSM_R4_SAT_LIMIT_R4_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_R5 Fields: */ +#define WCD9378_CDC_HPH_DSM_R5_SAT_LIMIT_R5_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_R6 Fields: */ +#define WCD9378_CDC_HPH_DSM_R6_SAT_LIMIT_R6_MASK 0xff + +/* WCD9378_CDC_HPH_DSM_R7 Fields: */ +#define WCD9378_CDC_HPH_DSM_R7_SAT_LIMIT_R7_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_A1_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_A1_0_COEF_A1_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_A1_1 Fields: */ +#define WCD9378_CDC_AUX_DSM_A1_1_COEF_A1_MASK 0x01 + +/* WCD9378_CDC_AUX_DSM_A2_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_A2_0_COEF_A2_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_A2_1 Fields: */ +#define WCD9378_CDC_AUX_DSM_A2_1_COEF_A2_MASK 0x0f + +/* WCD9378_CDC_AUX_DSM_A3_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_A3_0_COEF_A3_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_A3_1 Fields: */ +#define WCD9378_CDC_AUX_DSM_A3_1_COEF_A3_MASK 0x07 + +/* WCD9378_CDC_AUX_DSM_A4_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_A4_0_COEF_A4_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_A4_1 Fields: */ +#define WCD9378_CDC_AUX_DSM_A4_1_COEF_A4_MASK 0x03 + +/* WCD9378_CDC_AUX_DSM_A5_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_A5_0_COEF_A5_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_A5_1 Fields: */ +#define WCD9378_CDC_AUX_DSM_A5_1_COEF_A5_MASK 0x03 + +/* WCD9378_CDC_AUX_DSM_A6_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_A6_0_COEF_A6_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_A7_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_A7_0_COEF_A7_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_C_0 Fields: */ +#define WCD9378_CDC_AUX_DSM_C_0_COEF_C3_MASK 0xf0 +#define WCD9378_CDC_AUX_DSM_C_0_COEF_C2_MASK 0x0f + +/* WCD9378_CDC_AUX_DSM_C_1 Fields: */ +#define WCD9378_CDC_AUX_DSM_C_1_COEF_C5_MASK 0xf0 +#define WCD9378_CDC_AUX_DSM_C_1_COEF_C4_MASK 0x0f + +/* WCD9378_CDC_AUX_DSM_C_2 Fields: */ +#define WCD9378_CDC_AUX_DSM_C_2_COEF_C7_MASK 0xf0 +#define WCD9378_CDC_AUX_DSM_C_2_COEF_C6_MASK 0x0f + +/* WCD9378_CDC_AUX_DSM_C_3 Fields: */ +#define WCD9378_CDC_AUX_DSM_C_3_COEF_C7_MASK 0x3f + +/* WCD9378_CDC_AUX_DSM_R1 Fields: */ +#define WCD9378_CDC_AUX_DSM_R1_SAT_LIMIT_R1_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_R2 Fields: */ +#define WCD9378_CDC_AUX_DSM_R2_SAT_LIMIT_R2_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_R3 Fields: */ +#define WCD9378_CDC_AUX_DSM_R3_SAT_LIMIT_R3_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_R4 Fields: */ +#define WCD9378_CDC_AUX_DSM_R4_SAT_LIMIT_R4_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_R5 Fields: */ +#define WCD9378_CDC_AUX_DSM_R5_SAT_LIMIT_R5_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_R6 Fields: */ +#define WCD9378_CDC_AUX_DSM_R6_SAT_LIMIT_R6_MASK 0xff + +/* WCD9378_CDC_AUX_DSM_R7 Fields: */ +#define WCD9378_CDC_AUX_DSM_R7_SAT_LIMIT_R7_MASK 0xff + +/* WCD9378_CDC_HPH_GAIN_RX_0 Fields: */ +#define WCD9378_CDC_HPH_GAIN_RX_0_GAIN_RX_MASK 0xff + +/* WCD9378_CDC_HPH_GAIN_RX_1 Fields: */ +#define WCD9378_CDC_HPH_GAIN_RX_1_GAIN_RX_MASK 0xff + +/* WCD9378_CDC_HPH_GAIN_DSD_0 Fields: */ +#define WCD9378_CDC_HPH_GAIN_DSD_0_GAIN_DSD_MASK 0xff + +/* WCD9378_CDC_HPH_GAIN_DSD_1 Fields: */ +#define WCD9378_CDC_HPH_GAIN_DSD_1_GAIN_DSD_MASK 0xff + +/* WCD9378_CDC_HPH_GAIN_DSD_2 Fields: */ +#define WCD9378_CDC_HPH_GAIN_DSD_2_GAIN_LATCH_MASK 0x02 +#define WCD9378_CDC_HPH_GAIN_DSD_2_GAIN_DSD_MASK 0x01 + +/* WCD9378_CDC_AUX_GAIN_DSD_0 Fields: */ +#define WCD9378_CDC_AUX_GAIN_DSD_0_GAIN_DSD_MASK 0xff + +/* WCD9378_CDC_AUX_GAIN_DSD_1 Fields: */ +#define WCD9378_CDC_AUX_GAIN_DSD_1_GAIN_DSD_MASK 0xff + +/* WCD9378_CDC_AUX_GAIN_DSD_2 Fields: */ +#define WCD9378_CDC_AUX_GAIN_DSD_2_GAIN_LATCH_MASK 0x02 +#define WCD9378_CDC_AUX_GAIN_DSD_2_GAIN_DSD_MASK 0x01 + +/* WCD9378_CDC_HPH_GAIN_CTL Fields: */ +#define WCD9378_CDC_HPH_GAIN_CTL_HPH_STEREO_EN_MASK 0x10 +#define WCD9378_CDC_HPH_GAIN_CTL_HPHR_RX_EN_MASK 0x08 +#define WCD9378_CDC_HPH_GAIN_CTL_HPHL_RX_EN_MASK 0x04 +#define WCD9378_CDC_HPH_GAIN_CTL_HPHR_DSD_EN_MASK 0x02 +#define WCD9378_CDC_HPH_GAIN_CTL_HPHL_DSD_EN_MASK 0x01 + +/* WCD9378_CDC_AUX_GAIN_CTL Fields: */ +#define WCD9378_CDC_AUX_GAIN_CTL_AUX_EN_MASK 0x01 + +/* WCD9378_CDC_PATH_CTL Fields: */ +#define WCD9378_CDC_PATH_CTL_AUX_MUX_SEL_MASK 0x10 +#define WCD9378_CDC_PATH_CTL_EAR_1BIT_MODE_MASK 0x02 +#define WCD9378_CDC_PATH_CTL_EAR_MUX_SEL_MASK 0x01 + +/* WCD9378_CDC_SWR_CLG Fields: */ +#define WCD9378_CDC_SWR_CLG_CLG_CTL_MASK 0xff + +/* WCD9378_SWR_CLG_BYP Fields: */ +#define WCD9378_SWR_CLG_BYP_SWR_CLG_BYP_MASK 0x01 + +/* WCD9378_CDC_TX0_CTL Fields: */ +#define WCD9378_CDC_TX0_CTL_REQ_FB_SEL_MASK 0x40 +#define WCD9378_CDC_TX0_CTL_TX_DITHER_EN_MASK 0x20 +#define WCD9378_CDC_TX0_CTL_RANDOM_REGION_MASK 0x1f + +/* WCD9378_CDC_TX1_CTL Fields: */ +#define WCD9378_CDC_TX1_CTL_REQ_FB_SEL_MASK 0x40 +#define WCD9378_CDC_TX1_CTL_TX_DITHER_EN_MASK 0x20 +#define WCD9378_CDC_TX1_CTL_RANDOM_REGION_MASK 0x1f + +/* WCD9378_CDC_TX2_CTL Fields: */ +#define WCD9378_CDC_TX2_CTL_REQ_FB_SEL_MASK 0x40 +#define WCD9378_CDC_TX2_CTL_TX_DITHER_EN_MASK 0x20 +#define WCD9378_CDC_TX2_CTL_RANDOM_REGION_MASK 0x1f + +/* WCD9378_CDC_TX_RST Fields: */ +#define WCD9378_CDC_TX_RST_TX2_SOFT_RST_MASK 0x04 +#define WCD9378_CDC_TX_RST_TX1_SOFT_RST_MASK 0x02 +#define WCD9378_CDC_TX_RST_TX0_SOFT_RST_MASK 0x01 + +/* WCD9378_CDC_REQ_CTL Fields: */ +#define WCD9378_CDC_REQ_CTL_TX2_WIDE_BAND_MASK 0x10 +#define WCD9378_CDC_REQ_CTL_TX1_WIDE_BAND_MASK 0x08 +#define WCD9378_CDC_REQ_CTL_TX0_WIDE_BAND_MASK 0x04 +#define WCD9378_CDC_REQ_CTL_FS_RATE_4P8_MASK 0x02 +#define WCD9378_CDC_REQ_CTL_DEM_BYPASS_MASK 0x01 + +/* WCD9378_CDC_RST Fields: */ +#define WCD9378_CDC_RST_TX_SOFT_RST_MASK 0x02 +#define WCD9378_CDC_RST_RX_SOFT_RST_MASK 0x01 + +/* WCD9378_CDC_AMIC_CTL Fields: */ +#define WCD9378_CDC_AMIC_CTL_AMIC4_IN_SEL_MASK 0x04 +#define WCD9378_CDC_AMIC_CTL_AMIC3_IN_SEL_MASK 0x02 +#define WCD9378_CDC_AMIC_CTL_AMIC1_IN_SEL_MASK 0x01 + +/* WCD9378_CDC_DMIC_CTL Fields: */ +#define WCD9378_CDC_DMIC_CTL_DMIC_LEGACY_SW_MODE_MASK 0x08 +#define WCD9378_CDC_DMIC_CTL_DMIC_DIV_BAK_EN_MASK 0x04 +#define WCD9378_CDC_DMIC_CTL_CLK_SCALE_EN_MASK 0x02 +#define WCD9378_CDC_DMIC_CTL_SOFT_RESET_MASK 0x01 + +/* WCD9378_CDC_DMIC1_CTL Fields: */ +#define WCD9378_CDC_DMIC1_CTL_DMIC_CLK_SCALE_SEL_MASK 0x70 +#define WCD9378_CDC_DMIC1_CTL_DMIC_CLK_EN_MASK 0x08 +#define WCD9378_CDC_DMIC1_CTL_DMIC_CLK_SEL_MASK 0x07 + +/* WCD9378_CDC_DMIC2_CTL Fields: */ +#define WCD9378_CDC_DMIC2_CTL_DMIC_LEFT_EN_MASK 0x80 +#define WCD9378_CDC_DMIC2_CTL_DMIC_CLK_SCALE_SEL_MASK 0x70 +#define WCD9378_CDC_DMIC2_CTL_DMIC_CLK_EN_MASK 0x08 +#define WCD9378_CDC_DMIC2_CTL_DMIC_CLK_SEL_MASK 0x07 + +/* WCD9378_CDC_DMIC3_CTL Fields: */ +#define WCD9378_CDC_DMIC3_CTL_DMIC_CLK_SCALE_SEL_MASK 0x70 +#define WCD9378_CDC_DMIC3_CTL_DMIC_CLK_EN_MASK 0x08 +#define WCD9378_CDC_DMIC3_CTL_DMIC_CLK_SEL_MASK 0x07 + +/* WCD9378_EFUSE_PRG_CTL Fields: */ +#define WCD9378_EFUSE_PRG_CTL_PRG_ADDR_MASK 0xff + +/* WCD9378_EFUSE_CTL Fields: */ +#define WCD9378_EFUSE_CTL_EFUSE_ST_CNT_MASK 0x3c +#define WCD9378_EFUSE_CTL_EFUSE_SOFT_RST_N_MASK 0x02 +#define WCD9378_EFUSE_CTL_EFUSE_EN_MASK 0x01 + +/* WCD9378_CDC_DMIC_RATE_1_2 Fields: */ +#define WCD9378_CDC_DMIC_RATE_1_2_DMIC2_RATE_MASK 0xf0 +#define WCD9378_CDC_DMIC_RATE_1_2_DMIC1_RATE_MASK 0x0f + +/* WCD9378_CDC_DMIC_RATE_3_4 Fields: */ +#define WCD9378_CDC_DMIC_RATE_3_4_DMIC3_RATE_MASK 0x0f + +/* WCD9378_PDM_WD_EN_OVRD Fields: */ +#define WCD9378_PDM_WD_EN_OVRD_RX2_MASK 0x10 +#define WCD9378_PDM_WD_EN_OVRD_RX1_MASK 0x0c +#define WCD9378_PDM_WD_EN_OVRD_RX0_MASK 0x03 + +/* WCD9378_PDM_WD_CTL0 Fields: */ +#define WCD9378_PDM_WD_CTL0_HOLD_OFF_MASK 0x80 +#define WCD9378_PDM_WD_CTL0_TIME_OUT_SEL_DSD_MASK 0x60 +#define WCD9378_PDM_WD_CTL0_TIME_OUT_SEL_PCM_MASK 0x18 +#define WCD9378_PDM_WD_CTL0_PDM_WD_EN_MASK 0x07 + +/* WCD9378_PDM_WD_CTL1 Fields: */ +#define WCD9378_PDM_WD_CTL1_HOLD_OFF_MASK 0x80 +#define WCD9378_PDM_WD_CTL1_TIME_OUT_SEL_DSD_MASK 0x60 +#define WCD9378_PDM_WD_CTL1_TIME_OUT_SEL_PCM_MASK 0x18 +#define WCD9378_PDM_WD_CTL1_PDM_WD_EN_MASK 0x07 + +/* WCD9378_PDM_WD_CTL2 Fields: */ +#define WCD9378_PDM_WD_CTL2_HOLD_OFF_MASK 0x08 +#define WCD9378_PDM_WD_CTL2_TIME_OUT_SEL_MASK 0x06 +#define WCD9378_PDM_WD_CTL2_PDM_WD_EN_MASK 0x01 + +/* WCD9378_RAMP_CTL Fields: */ +#define WCD9378_RAMP_CTL_RX2_RAMP_EN_MASK 0x04 +#define WCD9378_RAMP_CTL_RX1_RAMP_EN_MASK 0x02 +#define WCD9378_RAMP_CTL_RX0_RAMP_EN_MASK 0x01 + +/* WCD9378_ACT_DET_CTL Fields: */ +#define WCD9378_ACT_DET_CTL_RX2_ACT_DET_EN_MASK 0x04 +#define WCD9378_ACT_DET_CTL_RX1_ACT_DET_EN_MASK 0x02 +#define WCD9378_ACT_DET_CTL_RX0_ACT_DET_EN_MASK 0x01 + +/* WCD9378_ACT_DET_HOOKUP0 Fields: */ +#define WCD9378_ACT_DET_HOOKUP0_RX2_INPUT_MUTE_MASK 0x04 +#define WCD9378_ACT_DET_HOOKUP0_RX1_INPUT_MUTE_MASK 0x02 +#define WCD9378_ACT_DET_HOOKUP0_RX0_INPUT_MUTE_MASK 0x01 + +/* WCD9378_ACT_DET_HOOKUP1 Fields: */ +#define WCD9378_ACT_DET_HOOKUP1_RX2_OUTPUT_MUTE_MASK 0x04 +#define WCD9378_ACT_DET_HOOKUP1_RX1_OUTPUT_MUTE_MASK 0x02 +#define WCD9378_ACT_DET_HOOKUP1_RX0_OUTPUT_MUTE_MASK 0x01 + +/* WCD9378_ACT_DET_HOOKUP2 Fields: */ +#define WCD9378_ACT_DET_HOOKUP2_RX2_DSD_GAIN_CSR_EN_MASK 0x10 +#define WCD9378_ACT_DET_HOOKUP2_RX1_DSD_GAIN_CSR_EN_MASK 0x08 +#define WCD9378_ACT_DET_HOOKUP2_RX1_PCM_GAIN_CSR_EN_MASK 0x04 +#define WCD9378_ACT_DET_HOOKUP2_RX0_DSD_GAIN_CSR_EN_MASK 0x02 +#define WCD9378_ACT_DET_HOOKUP2_RX0_PCM_GAIN_CSR_EN_MASK 0x01 + +/* WCD9378_ACT_DET_DLY_BUF_EN Fields: */ +#define WCD9378_ACT_DET_DLY_BUF_EN_RX2_DSD_DLY_BUF_EN_MASK 0x10 +#define WCD9378_ACT_DET_DLY_BUF_EN_RX1_DSD_DLY_BUF_EN_MASK 0x08 +#define WCD9378_ACT_DET_DLY_BUF_EN_RX1_PCM_DLY_BUF_EN_MASK 0x04 +#define WCD9378_ACT_DET_DLY_BUF_EN_RX0_DSD_DLY_BUF_EN_MASK 0x02 +#define WCD9378_ACT_DET_DLY_BUF_EN_RX0_PCM_DLY_BUF_EN_MASK 0x01 + +/* WCD9378_INTR_MODE Fields: */ +#define WCD9378_INTR_MODE_SWR_PULSE_CLR_MASK 0x20 +#define WCD9378_INTR_MODE_SWR_RX_INT_OUT_EN_MASK 0x10 +#define WCD9378_INTR_MODE_GPIO_1_INT_OUT_EN_MASK 0x08 +#define WCD9378_INTR_MODE_GPIO_0_INT_OUT_EN_MASK 0x04 +#define WCD9378_INTR_MODE_SWR_INTR_LEVEL_MASK 0x02 +#define WCD9378_INTR_MODE_INT_POLARITY_MASK 0x01 + +/* WCD9378_INTR_STATUS_0 Fields: */ +#define WCD9378_INTR_STATUS_0_HPHL_OCP_INT_MASK 0x80 +#define WCD9378_INTR_STATUS_0_HPHR_CNP_INT_MASK 0x40 +#define WCD9378_INTR_STATUS_0_HPHR_OCP_INT_MASK 0x20 +#define WCD9378_INTR_STATUS_0_MBHC_SW_INT_MASK 0x10 +#define WCD9378_INTR_STATUS_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD9378_INTR_STATUS_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD9378_INTR_STATUS_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD9378_INTR_STATUS_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD9378_INTR_STATUS_1 Fields: */ +#define WCD9378_INTR_STATUS_1_AUX_PDM_WD_INT_MASK 0x80 +#define WCD9378_INTR_STATUS_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD9378_INTR_STATUS_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD9378_INTR_STATUS_1_AUX_SCD_INT_MASK 0x10 +#define WCD9378_INTR_STATUS_1_AUX_CNP_INT_MASK 0x08 +#define WCD9378_INTR_STATUS_1_EAR_SCD_INT_MASK 0x04 +#define WCD9378_INTR_STATUS_1_EAR_CNP_INT_MASK 0x02 +#define WCD9378_INTR_STATUS_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD9378_INTR_STATUS_2 Fields: */ +#define WCD9378_INTR_STATUS_2_HIDTX_CUR_OWNER_CHG_MASK 0x80 +#define WCD9378_INTR_STATUS_2_SAPU_PROT_MODE_CHG_MASK 0x40 +#define WCD9378_INTR_STATUS_2_GPIO_1_INT_MASK 0x20 +#define WCD9378_INTR_STATUS_2_GPIO_0_INT_MASK 0x10 +#define WCD9378_INTR_STATUS_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD9378_INTR_STATUS_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD9378_INTR_STATUS_2_MBHC_MOISTRUE_INT_MASK 0x02 +#define WCD9378_INTR_STATUS_2_LDORT_SCD_INT_MASK 0x01 + +/* WCD9378_INTR_STATUS_3 Fields: */ +#define WCD9378_INTR_STATUS_3_SM2_STAT_ALERT_MASK 0x20 +#define WCD9378_INTR_STATUS_3_SM1_STAT_ALERT_MASK 0x10 +#define WCD9378_INTR_STATUS_3_SM0_STAT_ALERT_MASK 0x08 +#define WCD9378_INTR_STATUS_3_SJ_STAT_ALERT_MASK 0x04 +#define WCD9378_INTR_STATUS_3_SA_STAT_ALERT_MASK 0x02 + +/* WCD9378_INTR_MASK_0 Fields: */ +#define WCD9378_INTR_MASK_0_HPHL_OCP_INT_MASK 0x80 +#define WCD9378_INTR_MASK_0_HPHR_CNP_INT_MASK 0x40 +#define WCD9378_INTR_MASK_0_HPHR_OCP_INT_MASK 0x20 +#define WCD9378_INTR_MASK_0_MBHC_SW_INT_MASK 0x10 +#define WCD9378_INTR_MASK_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD9378_INTR_MASK_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD9378_INTR_MASK_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD9378_INTR_MASK_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD9378_INTR_MASK_1 Fields: */ +#define WCD9378_INTR_MASK_1_AUX_PDM_WD_INT_MASK 0x80 +#define WCD9378_INTR_MASK_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD9378_INTR_MASK_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD9378_INTR_MASK_1_AUX_SCD_INT_MASK 0x10 +#define WCD9378_INTR_MASK_1_AUX_CNP_INT_MASK 0x08 +#define WCD9378_INTR_MASK_1_EAR_SCD_INT_MASK 0x04 +#define WCD9378_INTR_MASK_1_EAR_CNP_INT_MASK 0x02 +#define WCD9378_INTR_MASK_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD9378_INTR_MASK_2 Fields: */ +#define WCD9378_INTR_MASK_2_HIDTX_CUR_OWNER_CHG_MASK 0x80 +#define WCD9378_INTR_MASK_2_SAPU_PROT_MODE_CHG_MASK 0x40 +#define WCD9378_INTR_MASK_2_GPIO_1_INT_MASK 0x20 +#define WCD9378_INTR_MASK_2_GPIO_0_INT_MASK 0x10 +#define WCD9378_INTR_MASK_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD9378_INTR_MASK_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD9378_INTR_MASK_2_MBHC_MOISTRUE_INT_MASK 0x02 +#define WCD9378_INTR_MASK_2_LDORT_SCD_INT_MASK 0x01 + +/* WCD9378_INTR_MASK_3 Fields: */ +#define WCD9378_INTR_MASK_3_SM2_STAT_ALERT_MASK 0x20 +#define WCD9378_INTR_MASK_3_SM1_STAT_ALERT_MASK 0x10 +#define WCD9378_INTR_MASK_3_SM0_STAT_ALERT_MASK 0x08 +#define WCD9378_INTR_MASK_3_SJ_STAT_ALERT_MASK 0x04 +#define WCD9378_INTR_MASK_3_SA_STAT_ALERT_MASK 0x02 + +/* WCD9378_INTR_SET_0 Fields: */ +#define WCD9378_INTR_SET_0_HPHL_OCP_INT_MASK 0x80 +#define WCD9378_INTR_SET_0_HPHR_CNP_INT_MASK 0x40 +#define WCD9378_INTR_SET_0_HPHR_OCP_INT_MASK 0x20 +#define WCD9378_INTR_SET_0_MBHC_SW_INT_MASK 0x10 +#define WCD9378_INTR_SET_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD9378_INTR_SET_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD9378_INTR_SET_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD9378_INTR_SET_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD9378_INTR_SET_1 Fields: */ +#define WCD9378_INTR_SET_1_AUX_PDM_WD_INT_MASK 0x80 +#define WCD9378_INTR_SET_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD9378_INTR_SET_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD9378_INTR_SET_1_AUX_SCD_INT_MASK 0x10 +#define WCD9378_INTR_SET_1_AUX_CNP_INT_MASK 0x08 +#define WCD9378_INTR_SET_1_EAR_SCD_INT_MASK 0x04 +#define WCD9378_INTR_SET_1_EAR_CNP_INT_MASK 0x02 +#define WCD9378_INTR_SET_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD9378_INTR_SET_2 Fields: */ +#define WCD9378_INTR_SET_2_HIDTX_CUR_OWNER_CHG_MASK 0x80 +#define WCD9378_INTR_SET_2_SAPU_PROT_MODE_CHG_MASK 0x40 +#define WCD9378_INTR_SET_2_GPIO_1_INT_MASK 0x20 +#define WCD9378_INTR_SET_2_GPIO_0_INT_MASK 0x10 +#define WCD9378_INTR_SET_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD9378_INTR_SET_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD9378_INTR_SET_2_MBHC_MOISTRUE_INT_MASK 0x02 +#define WCD9378_INTR_SET_2_LDORT_SCD_INT_MASK 0x01 + +/* WCD9378_INTR_SET_3 Fields: */ +#define WCD9378_INTR_SET_3_SM2_STAT_ALERT_MASK 0x20 +#define WCD9378_INTR_SET_3_SM1_STAT_ALERT_MASK 0x10 +#define WCD9378_INTR_SET_3_SM0_STAT_ALERT_MASK 0x08 +#define WCD9378_INTR_SET_3_SJ_STAT_ALERT_MASK 0x04 +#define WCD9378_INTR_SET_3_SA_STAT_ALERT_MASK 0x02 + +/* WCD9378_INTR_TEST_0 Fields: */ +#define WCD9378_INTR_TEST_0_HPHL_OCP_INT_MASK 0x80 +#define WCD9378_INTR_TEST_0_HPHR_CNP_INT_MASK 0x40 +#define WCD9378_INTR_TEST_0_HPHR_OCP_INT_MASK 0x20 +#define WCD9378_INTR_TEST_0_MBHC_SW_INT_MASK 0x10 +#define WCD9378_INTR_TEST_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD9378_INTR_TEST_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD9378_INTR_TEST_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD9378_INTR_TEST_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD9378_INTR_TEST_1 Fields: */ +#define WCD9378_INTR_TEST_1_AUX_PDM_WD_INT_MASK 0x80 +#define WCD9378_INTR_TEST_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD9378_INTR_TEST_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD9378_INTR_TEST_1_AUX_SCD_INT_MASK 0x10 +#define WCD9378_INTR_TEST_1_AUX_CNP_INT_MASK 0x08 +#define WCD9378_INTR_TEST_1_EAR_SCD_INT_MASK 0x04 +#define WCD9378_INTR_TEST_1_EAR_CNP_INT_MASK 0x02 +#define WCD9378_INTR_TEST_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD9378_INTR_TEST_2 Fields: */ +#define WCD9378_INTR_TEST_2_HIDTX_CUR_OWNER_CHG_MASK 0x80 +#define WCD9378_INTR_TEST_2_SAPU_PROT_MODE_CHG_MASK 0x40 +#define WCD9378_INTR_TEST_2_GPIO_1_INT_MASK 0x20 +#define WCD9378_INTR_TEST_2_GPIO_0_INT_MASK 0x10 +#define WCD9378_INTR_TEST_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD9378_INTR_TEST_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD9378_INTR_TEST_2_MBHC_MOISTRUE_INT_MASK 0x02 +#define WCD9378_INTR_TEST_2_LDORT_SCD_INT_MASK 0x01 + +/* WCD9378_INTR_TEST_3 Fields: */ +#define WCD9378_INTR_TEST_3_SM2_STAT_ALERT_MASK 0x20 +#define WCD9378_INTR_TEST_3_SM1_STAT_ALERT_MASK 0x10 +#define WCD9378_INTR_TEST_3_SM0_STAT_ALERT_MASK 0x08 +#define WCD9378_INTR_TEST_3_SJ_STAT_ALERT_MASK 0x04 +#define WCD9378_INTR_TEST_3_SA_STAT_ALERT_MASK 0x02 + +/* WCD9378_TX_MODE_DBG_EN Fields: */ +#define WCD9378_TX_MODE_DBG_EN_TXD2_MODE_DBG_EN_MASK 0x04 +#define WCD9378_TX_MODE_DBG_EN_TXD1_MODE_DBG_EN_MASK 0x02 +#define WCD9378_TX_MODE_DBG_EN_TXD0_MODE_DBG_EN_MASK 0x01 + +/* WCD9378_TX_MODE_DBG_0_1 Fields: */ +#define WCD9378_TX_MODE_DBG_0_1_TXD1_MODE_DBG_MASK 0xf0 +#define WCD9378_TX_MODE_DBG_0_1_TXD0_MODE_DBG_MASK 0x0f + +/* WCD9378_TX_MODE_DBG_2_3 Fields: */ +#define WCD9378_TX_MODE_DBG_2_3_TXD2_MODE_DBG_MASK 0x0f + +/* WCD9378_LB_IN_SEL_CTL Fields: */ +#define WCD9378_LB_IN_SEL_CTL_AUX_LB_IN_SEL_MASK 0x0c +#define WCD9378_LB_IN_SEL_CTL_HPH_LB_IN_SEL_MASK 0x03 + +/* WCD9378_LOOP_BACK_MODE Fields: */ +#define WCD9378_LOOP_BACK_MODE_TX_DATA_EDGE_MASK 0x10 +#define WCD9378_LOOP_BACK_MODE_RX_DATA_EDGE_MASK 0x08 +#define WCD9378_LOOP_BACK_MODE_LOOPBACK_MODE_MASK 0x07 + +/* WCD9378_SWR_DAC_TEST Fields: */ +#define WCD9378_SWR_DAC_TEST_SWR_DAC_TEST_MASK 0x01 + +/* WCD9378_SWR_HM_TEST_RX_0 Fields: */ +#define WCD9378_SWR_HM_TEST_RX_0_ALT_MODE_MASK 0x80 +#define WCD9378_SWR_HM_TEST_RX_0_IO_MODE_MASK 0x40 +#define WCD9378_SWR_HM_TEST_RX_0_LN2_T_DATA_OE_MASK 0x20 +#define WCD9378_SWR_HM_TEST_RX_0_LN2_T_DATA_OUT_MASK 0x10 +#define WCD9378_SWR_HM_TEST_RX_0_LN2_T_KEEPER_EN_MASK 0x08 +#define WCD9378_SWR_HM_TEST_RX_0_LN1_T_DATA_OE_MASK 0x04 +#define WCD9378_SWR_HM_TEST_RX_0_LN1_T_DATA_OUT_MASK 0x02 +#define WCD9378_SWR_HM_TEST_RX_0_LN1_T_KEEPER_EN_MASK 0x01 + +/* WCD9378_SWR_HM_TEST_TX_0 Fields: */ +#define WCD9378_SWR_HM_TEST_TX_0_ALT_MODE_MASK 0x80 +#define WCD9378_SWR_HM_TEST_TX_0_IO_MODE_MASK 0x40 +#define WCD9378_SWR_HM_TEST_TX_0_LN2_T_DATA_OE_MASK 0x20 +#define WCD9378_SWR_HM_TEST_TX_0_LN2_T_DATA_OUT_MASK 0x10 +#define WCD9378_SWR_HM_TEST_TX_0_LN2_T_KEEPER_EN_MASK 0x08 +#define WCD9378_SWR_HM_TEST_TX_0_LN1_T_DATA_OE_MASK 0x04 +#define WCD9378_SWR_HM_TEST_TX_0_LN1_T_DATA_OUT_MASK 0x02 +#define WCD9378_SWR_HM_TEST_TX_0_LN1_T_KEEPER_EN_MASK 0x01 + +/* WCD9378_SWR_HM_TEST_RX_1 Fields: */ +#define WCD9378_SWR_HM_TEST_RX_1_DTEST_SEL_MASK 0x1c +#define WCD9378_SWR_HM_TEST_RX_1_LN2_DLY_CELL_TEST_EN_MASK 0x02 +#define WCD9378_SWR_HM_TEST_RX_1_LN1_DLY_CELL_TEST_EN_MASK 0x01 + +/* WCD9378_SWR_HM_TEST_TX_1 Fields: */ +#define WCD9378_SWR_HM_TEST_TX_1_DTEST_SEL_MASK 0x3c +#define WCD9378_SWR_HM_TEST_TX_1_LN2_DLY_CELL_TEST_EN_MASK 0x02 +#define WCD9378_SWR_HM_TEST_TX_1_LN1_DLY_CELL_TEST_EN_MASK 0x01 + +/* WCD9378_SWR_HM_TEST_0 Fields: */ +#define WCD9378_SWR_HM_TEST_0_TX_LN2_T_DATA_IN_MASK 0x80 +#define WCD9378_SWR_HM_TEST_0_TX_LN2_T_CLK_IN_MASK 0x40 +#define WCD9378_SWR_HM_TEST_0_TX_LN1_T_DATA_IN_MASK 0x20 +#define WCD9378_SWR_HM_TEST_0_TX_LN1_T_CLK_IN_MASK 0x10 +#define WCD9378_SWR_HM_TEST_0_RX_LN2_T_DATA_IN_MASK 0x08 +#define WCD9378_SWR_HM_TEST_0_RX_LN2_T_CLK_IN_MASK 0x04 +#define WCD9378_SWR_HM_TEST_0_RX_LN1_T_DATA_IN_MASK 0x02 +#define WCD9378_SWR_HM_TEST_0_RX_LN1_T_CLK_IN_MASK 0x01 + +/* WCD9378_PAD_CTL_SWR_0 Fields: */ +#define WCD9378_PAD_CTL_SWR_0_SWR_SLEW_PRG_MASK 0xf0 +#define WCD9378_PAD_CTL_SWR_0_SWR_DRIVE_PRG_MASK 0x0f + +/* WCD9378_PAD_CTL_SWR_1 Fields: */ +#define WCD9378_PAD_CTL_SWR_1_SWR_TDZ_PRG_MASK 0x0f + +/* WCD9378_I2C_CTL Fields: */ +#define WCD9378_I2C_CTL_ACTIVE_MODE_MASK 0x01 + +/* WCD9378_LEGACY_SW_MODE Fields: */ +#define WCD9378_LEGACY_SW_MODE_USE_LOCAL_INTR_CTRL_MASK 0x08 +#define WCD9378_LEGACY_SW_MODE_CDC_LEGACY_ACCESS_MASK 0x04 +#define WCD9378_LEGACY_SW_MODE_MIPI_SWR_V1P1_MASK 0x02 +#define WCD9378_LEGACY_SW_MODE_CDC_TX_TANGGU_SW_MODE_MASK 0x01 + +/* WCD9378_EFUSE_TEST_CTL_0 Fields: */ +#define WCD9378_EFUSE_TEST_CTL_0_EFUSE_TEST_CTL_LSB_MASK 0xff + +/* WCD9378_EFUSE_TEST_CTL_1 Fields: */ +#define WCD9378_EFUSE_TEST_CTL_1_EFUSE_TEST_CTL_MSB_MASK 0xff + +/* WCD9378_EFUSE_T_DATA_0 Fields: */ +#define WCD9378_EFUSE_T_DATA_0_EFUSE_DATA_MASK 0xff + +/* WCD9378_PAD_CTL_PDM_RX0 Fields: */ +#define WCD9378_PAD_CTL_PDM_RX0_PDM_SLEW_PRG_MASK 0xf0 +#define WCD9378_PAD_CTL_PDM_RX0_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD9378_PAD_CTL_PDM_RX1 Fields: */ +#define WCD9378_PAD_CTL_PDM_RX1_PDM_SLEW_PRG_MASK 0xf0 +#define WCD9378_PAD_CTL_PDM_RX1_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD9378_PAD_CTL_PDM_TX0 Fields: */ +#define WCD9378_PAD_CTL_PDM_TX0_PDM_SLEW_PRG_MASK 0xf0 +#define WCD9378_PAD_CTL_PDM_TX0_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD9378_PAD_CTL_PDM_TX1 Fields: */ +#define WCD9378_PAD_CTL_PDM_TX1_PDM_SLEW_PRG_MASK 0xf0 +#define WCD9378_PAD_CTL_PDM_TX1_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD9378_PAD_INP_DIS_0 Fields: */ +#define WCD9378_PAD_INP_DIS_0_DMIC3_CLK_MASK 0x20 +#define WCD9378_PAD_INP_DIS_0_DMIC3_DATA_MASK 0x10 +#define WCD9378_PAD_INP_DIS_0_DMIC2_CLK_MASK 0x08 +#define WCD9378_PAD_INP_DIS_0_DMIC2_DATA_MASK 0x04 +#define WCD9378_PAD_INP_DIS_0_DMIC1_CLK_MASK 0x02 +#define WCD9378_PAD_INP_DIS_0_DMIC1_DATA_MASK 0x01 + +/* WCD9378_DRIVE_STRENGTH_0 Fields: */ +#define WCD9378_DRIVE_STRENGTH_0_DS_DMIC2_CLK_MASK 0xc0 +#define WCD9378_DRIVE_STRENGTH_0_DS_DMIC2_DATA_MASK 0x30 +#define WCD9378_DRIVE_STRENGTH_0_DS_DMIC1_CLK_MASK 0x0c +#define WCD9378_DRIVE_STRENGTH_0_DS_DMIC1_DATA_MASK 0x03 + +/* WCD9378_DRIVE_STRENGTH_1 Fields: */ +#define WCD9378_DRIVE_STRENGTH_1_DS_DMIC3_CLK_MASK 0x0c +#define WCD9378_DRIVE_STRENGTH_1_DS_DMIC3_DATA_MASK 0x03 + +/* WCD9378_RX_DATA_EDGE_CTL Fields: */ +#define WCD9378_RX_DATA_EDGE_CTL_HPH_CLH_EDGE_MASK 0x20 +#define WCD9378_RX_DATA_EDGE_CTL_AUX_DOUT_EDGE_MASK 0x10 +#define WCD9378_RX_DATA_EDGE_CTL_HPHR_DOUT_EDGE_MASK 0x08 +#define WCD9378_RX_DATA_EDGE_CTL_HPHL_DOUT_EDGE_MASK 0x04 +#define WCD9378_RX_DATA_EDGE_CTL_HPHR_GAIN_EDGE_MASK 0x02 +#define WCD9378_RX_DATA_EDGE_CTL_HPHL_GAIN_EDGE_MASK 0x01 + +/* WCD9378_TX_DATA_EDGE_CTL Fields: */ +#define WCD9378_TX_DATA_EDGE_CTL_TX_WE_DLY_MASK 0x18 +#define WCD9378_TX_DATA_EDGE_CTL_TX2_DIN_EDGE_MASK 0x04 +#define WCD9378_TX_DATA_EDGE_CTL_TX1_DIN_EDGE_MASK 0x02 +#define WCD9378_TX_DATA_EDGE_CTL_TX0_DIN_EDGE_MASK 0x01 + +/* WCD9378_GPIO_MODE Fields: */ +#define WCD9378_GPIO_MODE_GPIO_3_EN_MASK 0x10 +#define WCD9378_GPIO_MODE_GPIO_2_EN_MASK 0x08 +#define WCD9378_GPIO_MODE_GPIO_1_EN_MASK 0x04 +#define WCD9378_GPIO_MODE_GPIO_0_EN_MASK 0x02 +#define WCD9378_GPIO_MODE_TEST_MODE_MASK 0x01 + +/* WCD9378_PIN_CTL_OE Fields: */ +#define WCD9378_PIN_CTL_OE_TEST_PIN_CTL_OE_MASK 0x10 +#define WCD9378_PIN_CTL_OE_GPIO_3_PIN_CTL_OE_MASK 0x08 +#define WCD9378_PIN_CTL_OE_GPIO_2_PIN_CTL_OE_MASK 0x04 +#define WCD9378_PIN_CTL_OE_GPIO_1_PIN_CTL_OE_MASK 0x02 +#define WCD9378_PIN_CTL_OE_GPIO_0_PIN_CTL_OE_MASK 0x01 + +/* WCD9378_PIN_CTL_DATA_0 Fields: */ +#define WCD9378_PIN_CTL_DATA_0_PAD_DMIC3_CLK_MASK 0x20 +#define WCD9378_PIN_CTL_DATA_0_PAD_DMIC3_DATA_MASK 0x10 +#define WCD9378_PIN_CTL_DATA_0_PAD_DMIC2_CLK_MASK 0x08 +#define WCD9378_PIN_CTL_DATA_0_PAD_DMIC2_DATA_MASK 0x04 +#define WCD9378_PIN_CTL_DATA_0_PAD_DMIC1_CLK_MASK 0x02 +#define WCD9378_PIN_CTL_DATA_0_PAD_DMIC1_DATA_MASK 0x01 + +/* WCD9378_PIN_STATUS_0 Fields: */ +#define WCD9378_PIN_STATUS_0_PAD_DMIC3_CLK_MASK 0x20 +#define WCD9378_PIN_STATUS_0_PAD_DMIC3_DATA_MASK 0x10 +#define WCD9378_PIN_STATUS_0_PAD_DMIC2_CLK_MASK 0x08 +#define WCD9378_PIN_STATUS_0_PAD_DMIC2_DATA_MASK 0x04 +#define WCD9378_PIN_STATUS_0_PAD_DMIC1_CLK_MASK 0x02 +#define WCD9378_PIN_STATUS_0_PAD_DMIC1_DATA_MASK 0x01 + +/* WCD9378_DIG_DEBUG_CTL Fields: */ +#define WCD9378_DIG_DEBUG_CTL_DIG_DEBUG_CTL_MASK 0xff + +/* WCD9378_DIG_DEBUG_EN Fields: */ +#define WCD9378_DIG_DEBUG_EN_TX_DBG_MODE_MASK 0x02 +#define WCD9378_DIG_DEBUG_EN_RX_DBG_MODE_MASK 0x01 + +/* WCD9378_ANA_CSR_DBG_ADD Fields: */ +#define WCD9378_ANA_CSR_DBG_ADD_ADD_MASK 0xff + +/* WCD9378_ANA_CSR_DBG_CTL Fields: */ +#define WCD9378_ANA_CSR_DBG_CTL_WR_VALUE_MASK 0xc0 +#define WCD9378_ANA_CSR_DBG_CTL_RD_VALUE_MASK 0x38 +#define WCD9378_ANA_CSR_DBG_CTL_DBG_PAGE_SEL_MASK 0x06 +#define WCD9378_ANA_CSR_DBG_CTL_DBG_EN_MASK 0x01 + +/* WCD9378_SSP_DBG Fields: */ +#define WCD9378_SSP_DBG_RX_SSP_DBG_MASK 0x02 +#define WCD9378_SSP_DBG_TX_SSP_DBG_MASK 0x01 + +/* WCD9378_MODE_STATUS_0 Fields: */ +#define WCD9378_MODE_STATUS_0_ATE_7_MASK 0x80 +#define WCD9378_MODE_STATUS_0_ATE_6_MASK 0x40 +#define WCD9378_MODE_STATUS_0_ATE_5_MASK 0x20 +#define WCD9378_MODE_STATUS_0_ATE_4_MASK 0x10 +#define WCD9378_MODE_STATUS_0_ATE_3_MASK 0x08 +#define WCD9378_MODE_STATUS_0_ATE_2_MASK 0x04 +#define WCD9378_MODE_STATUS_0_ATE_1_MASK 0x02 +#define WCD9378_MODE_STATUS_0_SWR_TEST_MASK 0x01 + +/* WCD9378_MODE_STATUS_1 Fields: */ +#define WCD9378_MODE_STATUS_1_SWR_PAD_TEST_MASK 0x02 +#define WCD9378_MODE_STATUS_1_EFUSE_MODE_MASK 0x01 + +/* WCD9378_SPARE_0 Fields: */ +#define WCD9378_SPARE_0_SPARE_REG_0_MASK 0xffff + +/* WCD9378_SPARE_1 Fields: */ +#define WCD9378_SPARE_1_SPARE_REG_1_MASK 0xffffff + +/* WCD9378_SPARE_2 Fields: */ +#define WCD9378_SPARE_2_SPARE_REG_2_MASK 0xffffffff + +/* WCD9378_EFUSE_REG_0 Fields: */ +#define WCD9378_EFUSE_REG_0_SPARE_BITS_MASK 0xe0 +#define WCD9378_EFUSE_REG_0_WCD9378_ID_MASK 0x1e +#define WCD9378_EFUSE_REG_0_EFUSE_BLOWN_MASK 0x01 + +/* WCD9378_EFUSE_REG_1 Fields: */ +#define WCD9378_EFUSE_REG_1_LOT_ID_0_MASK 0xff + +/* WCD9378_EFUSE_REG_2 Fields: */ +#define WCD9378_EFUSE_REG_2_LOT_ID_1_MASK 0xff + +/* WCD9378_EFUSE_REG_3 Fields: */ +#define WCD9378_EFUSE_REG_3_LOT_ID_2_MASK 0xff + +/* WCD9378_EFUSE_REG_4 Fields: */ +#define WCD9378_EFUSE_REG_4_LOT_ID_3_MASK 0xff + +/* WCD9378_EFUSE_REG_5 Fields: */ +#define WCD9378_EFUSE_REG_5_LOT_ID_4_MASK 0xff + +/* WCD9378_EFUSE_REG_6 Fields: */ +#define WCD9378_EFUSE_REG_6_LOT_ID_5_MASK 0xff + +/* WCD9378_EFUSE_REG_7 Fields: */ +#define WCD9378_EFUSE_REG_7_LOT_ID_6_MASK 0xff + +/* WCD9378_EFUSE_REG_8 Fields: */ +#define WCD9378_EFUSE_REG_8_LOT_ID_7_MASK 0xff + +/* WCD9378_EFUSE_REG_9 Fields: */ +#define WCD9378_EFUSE_REG_9_LOT_ID_8_MASK 0xff + +/* WCD9378_EFUSE_REG_10 Fields: */ +#define WCD9378_EFUSE_REG_10_LOT_ID_9_MASK 0xff + +/* WCD9378_EFUSE_REG_11 Fields: */ +#define WCD9378_EFUSE_REG_11_LOT_ID_10_MASK 0xff + +/* WCD9378_EFUSE_REG_12 Fields: */ +#define WCD9378_EFUSE_REG_12_LOT_ID_11_MASK 0xff + +/* WCD9378_EFUSE_REG_13 Fields: */ +#define WCD9378_EFUSE_REG_13_WAFER_ID_MASK 0xff + +/* WCD9378_EFUSE_REG_14 Fields: */ +#define WCD9378_EFUSE_REG_14_X_DIE_LOCATION_MASK 0xff + +/* WCD9378_EFUSE_REG_15 Fields: */ +#define WCD9378_EFUSE_REG_15_Y_DIE_LOCATION_MASK 0xff + +/* WCD9378_EFUSE_REG_16 Fields: */ +#define WCD9378_EFUSE_REG_16_FAB_ID_MASK 0xff + +/* WCD9378_EFUSE_REG_17 Fields: */ +#define WCD9378_EFUSE_REG_17_TEST_PROGRAM_REV_MASK 0xff + +/* WCD9378_EFUSE_REG_18 Fields: */ +#define WCD9378_EFUSE_REG_18_DIE_REVISION_MASK 0xff + +/* WCD9378_EFUSE_REG_19 Fields: */ +#define WCD9378_EFUSE_REG_19_MFG_ID_SPARE_MASK 0xff + +/* WCD9378_EFUSE_REG_20 Fields: */ +#define WCD9378_EFUSE_REG_20_I2C_SLV_ID_BLOWN_MASK 0x80 +#define WCD9378_EFUSE_REG_20_I2C_SLAVE_ID_MASK 0x7f + +/* WCD9378_EFUSE_REG_21 Fields: */ +#define WCD9378_EFUSE_REG_21_MBHC_IMP_DET_0_MASK 0xff + +/* WCD9378_EFUSE_REG_22 Fields: */ +#define WCD9378_EFUSE_REG_22_MBHC_IMP_DET_1_MASK 0xff + +/* WCD9378_EFUSE_REG_23 Fields: */ +#define WCD9378_EFUSE_REG_23_SWR_PAD_DRIVE_PRG_1P8V_MASK 0xf0 +#define WCD9378_EFUSE_REG_23_SWR_SLEW_PRG_1P8V_MASK 0x0f + +/* WCD9378_EFUSE_REG_24 Fields: */ +#define WCD9378_EFUSE_REG_24_SPARE_BITS_MASK 0xe0 +#define WCD9378_EFUSE_REG_24_SWR_PAD_BLOWN_MASK 0x10 +#define WCD9378_EFUSE_REG_24_SWR_TDZ_DELAY_PRG_1P8V_MASK 0x0f + +/* WCD9378_EFUSE_REG_25 Fields: */ +#define WCD9378_EFUSE_REG_25_MBHC_IMP_DET_2_MASK 0xff + +/* WCD9378_EFUSE_REG_26 Fields: */ +#define WCD9378_EFUSE_REG_26_MBHC_IMP_DET_3_MASK 0xff + +/* WCD9378_EFUSE_REG_27 Fields: */ +#define WCD9378_EFUSE_REG_27_HPH_DSD_DIS_MASK 0x80 +#define WCD9378_EFUSE_REG_27_BG_TUNE_BLOWN_MASK 0x40 +#define WCD9378_EFUSE_REG_27_BG_TUNE_MASK 0x30 +#define WCD9378_EFUSE_REG_27_EFUSE_HPH_MASK 0x0f + +/* WCD9378_EFUSE_REG_28 Fields: */ +#define WCD9378_EFUSE_REG_28_SPARE_BITS_MASK 0xff + +/* WCD9378_EFUSE_REG_29 Fields: */ +#define WCD9378_EFUSE_REG_29_SPARE_BITS_MASK 0xe0 +#define WCD9378_EFUSE_REG_29_TX_LP_DIS_MASK 0x10 +#define WCD9378_EFUSE_REG_29_TX_HP_DIS_MASK 0x08 +#define WCD9378_EFUSE_REG_29_DMIC_DIS_MASK 0x04 +#define WCD9378_EFUSE_REG_29_PLATFORM_MASK 0x02 +#define WCD9378_EFUSE_REG_29_PLATFORM_BLOWN_MASK 0x01 + +/* WCD9378_EFUSE_REG_30 Fields: */ +#define WCD9378_EFUSE_REG_30_SPARE_BITS_MASK 0xf0 +#define WCD9378_EFUSE_REG_30_SWR_SLEW_PRG_1P2V_MASK 0x0f + +/* WCD9378_EFUSE_REG_31 Fields: */ +#define WCD9378_EFUSE_REG_31_SWR_PAD_DRIVE_PRG_1P2V_MASK 0xf0 +#define WCD9378_EFUSE_REG_31_SWR_TDZ_DELAY_PRG_1P2V_MASK 0x0f + +/* WCD9378_TX_REQ_FB_CTL_2 Fields: */ +#define WCD9378_TX_REQ_FB_CTL_2_L0_FB_T2_MASK 0xf0 +#define WCD9378_TX_REQ_FB_CTL_2_L0_FB_T1_MASK 0x0f + +/* WCD9378_TX_REQ_FB_CTL_3 Fields: */ +#define WCD9378_TX_REQ_FB_CTL_3_L1_FB_T2_MASK 0xf0 +#define WCD9378_TX_REQ_FB_CTL_3_L1_FB_T1_MASK 0x0f + +/* WCD9378_TX_REQ_FB_CTL_4 Fields: */ +#define WCD9378_TX_REQ_FB_CTL_4_L2_FB_T2_MASK 0xf0 +#define WCD9378_TX_REQ_FB_CTL_4_L2_FB_T1_MASK 0x0f + +/* WCD9378_DEM_BYPASS_DATA0 Fields: */ +#define WCD9378_DEM_BYPASS_DATA0_DEM_BYPASS_DATA0_MASK 0xff + +/* WCD9378_DEM_BYPASS_DATA1 Fields: */ +#define WCD9378_DEM_BYPASS_DATA1_DEM_BYPASS_DATA0_MASK 0xff + +/* WCD9378_DEM_BYPASS_DATA2 Fields: */ +#define WCD9378_DEM_BYPASS_DATA2_DEM_BYPASS_DATA0_MASK 0xff + +/* WCD9378_DEM_BYPASS_DATA3 Fields: */ +#define WCD9378_DEM_BYPASS_DATA3_DEM_BYPASS_DATA0_MASK 0x03 + +/* WCD9378_RX0_PCM_RAMP_STEP Fields: */ +#define WCD9378_RX0_PCM_RAMP_STEP_RX0_RAMP_STEP_MASK 0xff + +/* WCD9378_RX0_DSD_RAMP_STEP Fields: */ +#define WCD9378_RX0_DSD_RAMP_STEP_RX0_RAMP_STEP_MASK 0xff + +/* WCD9378_RX1_PCM_RAMP_STEP Fields: */ +#define WCD9378_RX1_PCM_RAMP_STEP_RX1_RAMP_STEP_MASK 0xff + +/* WCD9378_RX1_DSD_RAMP_STEP Fields: */ +#define WCD9378_RX1_DSD_RAMP_STEP_RX1_RAMP_STEP_MASK 0xff + +/* WCD9378_RX2_RAMP_STEP Fields: */ +#define WCD9378_RX2_RAMP_STEP_RX2_RAMP_STEP_MASK 0xff + +/* WCD9378_PLATFORM_CTL Fields: */ +#define WCD9378_PLATFORM_CTL_MODE_MASK 0x01 + +/* WCD9378_CLK_DIV_CFG Fields: */ +#define WCD9378_CLK_DIV_CFG_TX_DIV_EN_MASK 0x02 +#define WCD9378_CLK_DIV_CFG_RX_DIV_EN_MASK 0x01 + +/* WCD9378_DRE_DLY_VAL Fields: */ +#define WCD9378_DRE_DLY_VAL_SWR_HPHR_MASK 0xf0 +#define WCD9378_DRE_DLY_VAL_SWR_HPHL_MASK 0x0f + + +/* WCD9378_SYS_USAGE_CTRL Fields: */ +#define WCD9378_SYS_USAGE_CTRL_SYS_USAGE_CTRL_MASK 0x0f + +/* WCD9378_SURGE_CTL Fields: */ +#define WCD9378_SURGE_CTL_SURGE_EN_MASK 0x01 + +/* WCD9378_SEQ_CTL Fields: */ +#define WCD9378_SEQ_CTL_TX2_SEQ_SOFT_RST_MASK 0x10 +#define WCD9378_SEQ_CTL_TX1_SEQ_SOFT_RST_MASK 0x08 +#define WCD9378_SEQ_CTL_TX0_SEQ_SOFT_RST_MASK 0x04 +#define WCD9378_SEQ_CTL_SA_SEQ_SOFT_RST_MASK 0x02 +#define WCD9378_SEQ_CTL_SJ_SEQ_SOFT_RST_MASK 0x01 + +/* WCD9378_HPH_UP_T0 Fields: */ +#define WCD9378_HPH_UP_T0_HPH_UP_T0_MASK 0x07 + +/* WCD9378_HPH_UP_T1 Fields: */ +#define WCD9378_HPH_UP_T1_HPH_UP_T1_MASK 0x07 + +/* WCD9378_HPH_UP_T2 Fields: */ +#define WCD9378_HPH_UP_T2_HPH_UP_T2_MASK 0x07 + +/* WCD9378_HPH_UP_T3 Fields: */ +#define WCD9378_HPH_UP_T3_HPH_UP_T3_MASK 0x07 + +/* WCD9378_HPH_UP_T4 Fields: */ +#define WCD9378_HPH_UP_T4_HPH_UP_T4_MASK 0x07 + +/* WCD9378_HPH_UP_T5 Fields: */ +#define WCD9378_HPH_UP_T5_HPH_UP_T5_MASK 0x07 + +/* WCD9378_HPH_UP_T6 Fields: */ +#define WCD9378_HPH_UP_T6_HPH_UP_T6_MASK 0x07 + +/* WCD9378_HPH_UP_T7 Fields: */ +#define WCD9378_HPH_UP_T7_HPH_UP_T7_MASK 0x07 + +/* WCD9378_HPH_UP_T8 Fields: */ +#define WCD9378_HPH_UP_T8_HPH_UP_T8_MASK 0x07 + +/* WCD9378_HPH_UP_T9 Fields: */ +#define WCD9378_HPH_UP_T9_HPH_UP_T9_MASK 0x07 + +/* WCD9378_HPH_UP_T10 Fields: */ +#define WCD9378_HPH_UP_T10_HPH_UP_T10_MASK 0x07 + +/* WCD9378_HPH_DN_T0 Fields: */ +#define WCD9378_HPH_DN_T0_HPH_DN_T0_MASK 0x07 + +/* WCD9378_HPH_DN_T1 Fields: */ +#define WCD9378_HPH_DN_T1_HPH_DN_T1_MASK 0x07 + +/* WCD9378_HPH_DN_T2 Fields: */ +#define WCD9378_HPH_DN_T2_HPH_DN_T2_MASK 0x07 + +/* WCD9378_HPH_DN_T3 Fields: */ +#define WCD9378_HPH_DN_T3_HPH_DN_T3_MASK 0x07 + +/* WCD9378_HPH_DN_T4 Fields: */ +#define WCD9378_HPH_DN_T4_HPH_DN_T4_MASK 0x07 + +/* WCD9378_HPH_DN_T5 Fields: */ +#define WCD9378_HPH_DN_T5_HPH_DN_T5_MASK 0x07 + +/* WCD9378_HPH_DN_T6 Fields: */ +#define WCD9378_HPH_DN_T6_HPH_DN_T6_MASK 0x07 + +/* WCD9378_HPH_DN_T7 Fields: */ +#define WCD9378_HPH_DN_T7_HPH_DN_T7_MASK 0x07 + +/* WCD9378_HPH_DN_T8 Fields: */ +#define WCD9378_HPH_DN_T8_HPH_DN_T8_MASK 0x07 + +/* WCD9378_HPH_DN_T9 Fields: */ +#define WCD9378_HPH_DN_T9_HPH_DN_T9_MASK 0x07 + +/* WCD9378_HPH_DN_T10 Fields: */ +#define WCD9378_HPH_DN_T10_HPH_DN_T10_MASK 0x07 + +/* WCD9378_HPH_UP_STAGE_LOC_0 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_0_HPH_UP_STAGE_LOC_0_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_1 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_1_HPH_UP_STAGE_LOC_1_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_2 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_2_HPH_UP_STAGE_LOC_2_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_3 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_3_HPH_UP_STAGE_LOC_3_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_4 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_4_HPH_UP_STAGE_LOC_4_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_5 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_5_HPH_UP_STAGE_LOC_5_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_6 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_6_HPH_UP_STAGE_LOC_6_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_7 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_7_HPH_UP_STAGE_LOC_7_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_8 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_8_HPH_UP_STAGE_LOC_8_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_9 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_9_HPH_UP_STAGE_LOC_9_MASK 0x0f + +/* WCD9378_HPH_UP_STAGE_LOC_10 Fields: */ +#define WCD9378_HPH_UP_STAGE_LOC_10_HPH_UP_STAGE_LOC_10_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_0 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_0_HPH_DN_STAGE_LOC_0_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_1 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_1_HPH_DN_STAGE_LOC_1_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_2 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_2_HPH_DN_STAGE_LOC_2_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_3 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_3_HPH_DN_STAGE_LOC_3_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_4 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_4_HPH_DN_STAGE_LOC_4_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_5 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_5_HPH_DN_STAGE_LOC_5_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_6 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_6_HPH_DN_STAGE_LOC_6_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_7 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_7_HPH_DN_STAGE_LOC_7_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_8 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_8_HPH_DN_STAGE_LOC_8_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_9 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_9_HPH_DN_STAGE_LOC_9_MASK 0x0f + +/* WCD9378_HPH_DN_STAGE_LOC_10 Fields: */ +#define WCD9378_HPH_DN_STAGE_LOC_10_HPH_DN_STAGE_LOC_10_MASK 0x0f + +/* WCD9378_SA_UP_T0 Fields: */ +#define WCD9378_SA_UP_T0_SA_UP_T0_MASK 0x07 + +/* WCD9378_SA_UP_T1 Fields: */ +#define WCD9378_SA_UP_T1_SA_UP_T1_MASK 0x07 + +/* WCD9378_SA_UP_T2 Fields: */ +#define WCD9378_SA_UP_T2_SA_UP_T2_MASK 0x07 + +/* WCD9378_SA_UP_T3 Fields: */ +#define WCD9378_SA_UP_T3_SA_UP_T3_MASK 0x07 + +/* WCD9378_SA_UP_T4 Fields: */ +#define WCD9378_SA_UP_T4_SA_UP_T4_MASK 0x07 + +/* WCD9378_SA_UP_T5 Fields: */ +#define WCD9378_SA_UP_T5_SA_UP_T5_MASK 0x07 + +/* WCD9378_SA_UP_T6 Fields: */ +#define WCD9378_SA_UP_T6_SA_UP_T6_MASK 0x07 + +/* WCD9378_SA_UP_T7 Fields: */ +#define WCD9378_SA_UP_T7_SA_UP_T7_MASK 0x07 + +/* WCD9378_SA_DN_T0 Fields: */ +#define WCD9378_SA_DN_T0_SA_DN_T0_MASK 0x07 + +/* WCD9378_SA_DN_T1 Fields: */ +#define WCD9378_SA_DN_T1_SA_DN_T1_MASK 0x07 + +/* WCD9378_SA_DN_T2 Fields: */ +#define WCD9378_SA_DN_T2_SA_DN_T2_MASK 0x07 + +/* WCD9378_SA_DN_T3 Fields: */ +#define WCD9378_SA_DN_T3_SA_DN_T3_MASK 0x07 + +/* WCD9378_SA_DN_T4 Fields: */ +#define WCD9378_SA_DN_T4_SA_DN_T4_MASK 0x07 + +/* WCD9378_SA_DN_T5 Fields: */ +#define WCD9378_SA_DN_T5_SA_DN_T5_MASK 0x07 + +/* WCD9378_SA_DN_T6 Fields: */ +#define WCD9378_SA_DN_T6_SA_DN_T6_MASK 0x07 + +/* WCD9378_SA_DN_T7 Fields: */ +#define WCD9378_SA_DN_T7_SA_DN_T7_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_0 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_0_SA_UP_STAGE_LOC_0_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_1 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_1_SA_UP_STAGE_LOC_1_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_2 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_2_SA_UP_STAGE_LOC_2_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_3 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_3_SA_UP_STAGE_LOC_3_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_4 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_4_SA_UP_STAGE_LOC_4_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_5 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_5_SA_UP_STAGE_LOC_5_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_6 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_6_SA_UP_STAGE_LOC_6_MASK 0x07 + +/* WCD9378_SA_UP_STAGE_LOC_7 Fields: */ +#define WCD9378_SA_UP_STAGE_LOC_7_SA_UP_STAGE_LOC_7_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_0 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_0_SA_DN_STAGE_LOC_0_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_1 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_1_SA_DN_STAGE_LOC_1_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_2 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_2_SA_DN_STAGE_LOC_2_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_3 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_3_SA_DN_STAGE_LOC_3_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_4 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_4_SA_DN_STAGE_LOC_4_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_5 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_5_SA_DN_STAGE_LOC_5_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_6 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_6_SA_DN_STAGE_LOC_6_MASK 0x07 + +/* WCD9378_SA_DN_STAGE_LOC_7 Fields: */ +#define WCD9378_SA_DN_STAGE_LOC_7_SA_DN_STAGE_LOC_7_MASK 0x07 + +/* WCD9378_TX0_UP_T0 Fields: */ +#define WCD9378_TX0_UP_T0_TX0_UP_T0_MASK 0x07 + +/* WCD9378_TX0_UP_T1 Fields: */ +#define WCD9378_TX0_UP_T1_TX0_UP_T1_MASK 0x07 + +/* WCD9378_TX0_UP_T2 Fields: */ +#define WCD9378_TX0_UP_T2_TX0_UP_T2_MASK 0x07 + +/* WCD9378_TX0_UP_T3 Fields: */ +#define WCD9378_TX0_UP_T3_TX0_UP_T3_MASK 0x07 + +/* WCD9378_TX0_DN_T0 Fields: */ +#define WCD9378_TX0_DN_T0_TX0_DN_T0_MASK 0x07 + +/* WCD9378_TX0_DN_T1 Fields: */ +#define WCD9378_TX0_DN_T1_TX0_DN_T1_MASK 0x07 + +/* WCD9378_TX0_DN_T2 Fields: */ +#define WCD9378_TX0_DN_T2_TX0_DN_T2_MASK 0x07 + +/* WCD9378_TX0_DN_T3 Fields: */ +#define WCD9378_TX0_DN_T3_TX0_DN_T3_MASK 0x07 + +/* WCD9378_TX0_UP_STAGE_LOC_0 Fields: */ +#define WCD9378_TX0_UP_STAGE_LOC_0_TX0_UP_STAGE_LOC_0_MASK 0x03 + +/* WCD9378_TX0_UP_STAGE_LOC_1 Fields: */ +#define WCD9378_TX0_UP_STAGE_LOC_1_TX0_UP_STAGE_LOC_1_MASK 0x03 + +/* WCD9378_TX0_UP_STAGE_LOC_2 Fields: */ +#define WCD9378_TX0_UP_STAGE_LOC_2_TX0_UP_STAGE_LOC_2_MASK 0x03 + +/* WCD9378_TX0_UP_STAGE_LOC_3 Fields: */ +#define WCD9378_TX0_UP_STAGE_LOC_3_TX0_UP_STAGE_LOC_3_MASK 0x03 + +/* WCD9378_TX0_DN_STAGE_LOC_0 Fields: */ +#define WCD9378_TX0_DN_STAGE_LOC_0_TX0_DN_STAGE_LOC_0_MASK 0x03 + +/* WCD9378_TX0_DN_STAGE_LOC_1 Fields: */ +#define WCD9378_TX0_DN_STAGE_LOC_1_TX0_DN_STAGE_LOC_1_MASK 0x03 + +/* WCD9378_TX0_DN_STAGE_LOC_2 Fields: */ +#define WCD9378_TX0_DN_STAGE_LOC_2_TX0_DN_STAGE_LOC_2_MASK 0x03 + +/* WCD9378_TX0_DN_STAGE_LOC_3 Fields: */ +#define WCD9378_TX0_DN_STAGE_LOC_3_TX0_DN_STAGE_LOC_3_MASK 0x03 + +/* WCD9378_TX1_UP_T0 Fields: */ +#define WCD9378_TX1_UP_T0_TX1_UP_T0_MASK 0x07 + +/* WCD9378_TX1_UP_T1 Fields: */ +#define WCD9378_TX1_UP_T1_TX1_UP_T1_MASK 0x07 + +/* WCD9378_TX1_UP_T2 Fields: */ +#define WCD9378_TX1_UP_T2_TX1_UP_T2_MASK 0x07 + +/* WCD9378_TX1_UP_T3 Fields: */ +#define WCD9378_TX1_UP_T3_TX1_UP_T3_MASK 0x07 + +/* WCD9378_TX1_DN_T0 Fields: */ +#define WCD9378_TX1_DN_T0_TX1_DN_T0_MASK 0x07 + +/* WCD9378_TX1_DN_T1 Fields: */ +#define WCD9378_TX1_DN_T1_TX1_DN_T1_MASK 0x07 + +/* WCD9378_TX1_DN_T2 Fields: */ +#define WCD9378_TX1_DN_T2_TX1_DN_T2_MASK 0x07 + +/* WCD9378_TX1_DN_T3 Fields: */ +#define WCD9378_TX1_DN_T3_TX1_DN_T3_MASK 0x07 + +/* WCD9378_TX1_UP_STAGE_LOC_0 Fields: */ +#define WCD9378_TX1_UP_STAGE_LOC_0_TX1_UP_STAGE_LOC_0_MASK 0x03 + +/* WCD9378_TX1_UP_STAGE_LOC_1 Fields: */ +#define WCD9378_TX1_UP_STAGE_LOC_1_TX1_UP_STAGE_LOC_1_MASK 0x03 + +/* WCD9378_TX1_UP_STAGE_LOC_2 Fields: */ +#define WCD9378_TX1_UP_STAGE_LOC_2_TX1_UP_STAGE_LOC_2_MASK 0x03 + +/* WCD9378_TX1_UP_STAGE_LOC_3 Fields: */ +#define WCD9378_TX1_UP_STAGE_LOC_3_TX1_UP_STAGE_LOC_3_MASK 0x03 + +/* WCD9378_TX1_DN_STAGE_LOC_0 Fields: */ +#define WCD9378_TX1_DN_STAGE_LOC_0_TX1_DN_STAGE_LOC_0_MASK 0x03 + +/* WCD9378_TX1_DN_STAGE_LOC_1 Fields: */ +#define WCD9378_TX1_DN_STAGE_LOC_1_TX1_DN_STAGE_LOC_1_MASK 0x03 + +/* WCD9378_TX1_DN_STAGE_LOC_2 Fields: */ +#define WCD9378_TX1_DN_STAGE_LOC_2_TX1_DN_STAGE_LOC_2_MASK 0x03 + +/* WCD9378_TX1_DN_STAGE_LOC_3 Fields: */ +#define WCD9378_TX1_DN_STAGE_LOC_3_TX1_DN_STAGE_LOC_3_MASK 0x03 + +/* WCD9378_TX2_UP_T0 Fields: */ +#define WCD9378_TX2_UP_T0_TX2_UP_T0_MASK 0x07 + +/* WCD9378_TX2_UP_T1 Fields: */ +#define WCD9378_TX2_UP_T1_TX2_UP_T1_MASK 0x07 + +/* WCD9378_TX2_UP_T2 Fields: */ +#define WCD9378_TX2_UP_T2_TX2_UP_T2_MASK 0x07 + +/* WCD9378_TX2_UP_T3 Fields: */ +#define WCD9378_TX2_UP_T3_TX2_UP_T3_MASK 0x07 + +/* WCD9378_TX2_DN_T0 Fields: */ +#define WCD9378_TX2_DN_T0_TX2_DN_T0_MASK 0x07 + +/* WCD9378_TX2_DN_T1 Fields: */ +#define WCD9378_TX2_DN_T1_TX2_DN_T1_MASK 0x07 + +/* WCD9378_TX2_DN_T2 Fields: */ +#define WCD9378_TX2_DN_T2_TX2_DN_T2_MASK 0x07 + +/* WCD9378_TX2_DN_T3 Fields: */ +#define WCD9378_TX2_DN_T3_TX2_DN_T3_MASK 0x07 + +/* WCD9378_TX2_UP_STAGE_LOC_0 Fields: */ +#define WCD9378_TX2_UP_STAGE_LOC_0_TX2_UP_STAGE_LOC_0_MASK 0x03 + +/* WCD9378_TX2_UP_STAGE_LOC_1 Fields: */ +#define WCD9378_TX2_UP_STAGE_LOC_1_TX2_UP_STAGE_LOC_1_MASK 0x03 + +/* WCD9378_TX2_UP_STAGE_LOC_2 Fields: */ +#define WCD9378_TX2_UP_STAGE_LOC_2_TX2_UP_STAGE_LOC_2_MASK 0x03 + +/* WCD9378_TX2_UP_STAGE_LOC_3 Fields: */ +#define WCD9378_TX2_UP_STAGE_LOC_3_TX2_UP_STAGE_LOC_3_MASK 0x03 + +/* WCD9378_TX2_DN_STAGE_LOC_0 Fields: */ +#define WCD9378_TX2_DN_STAGE_LOC_0_TX2_DN_STAGE_LOC_0_MASK 0x03 + +/* WCD9378_TX2_DN_STAGE_LOC_1 Fields: */ +#define WCD9378_TX2_DN_STAGE_LOC_1_TX2_DN_STAGE_LOC_1_MASK 0x03 + +/* WCD9378_TX2_DN_STAGE_LOC_2 Fields: */ +#define WCD9378_TX2_DN_STAGE_LOC_2_TX2_DN_STAGE_LOC_2_MASK 0x03 + +/* WCD9378_TX2_DN_STAGE_LOC_3 Fields: */ +#define WCD9378_TX2_DN_STAGE_LOC_3_TX2_DN_STAGE_LOC_3_MASK 0x03 + +/* WCD9378_SEQ_HPH_STAT Fields: */ +#define WCD9378_SEQ_HPH_STAT_HPH_FUNC_FAULTY_MASK 0x04 +#define WCD9378_SEQ_HPH_STAT_HPH_PWR_UP_RDY_MASK 0x02 +#define WCD9378_SEQ_HPH_STAT_HPH_PWR_DN_RDY_MASK 0x01 + +/* WCD9378_SEQ_SA_STAT Fields: */ +#define WCD9378_SEQ_SA_STAT_SA_PWR_UP_RDY_MASK 0x02 +#define WCD9378_SEQ_SA_STAT_SA_PWR_DN_RDY_MASK 0x01 + +/* WCD9378_SEQ_TX0_STAT Fields: */ +#define WCD9378_SEQ_TX0_STAT_TX0_PWR_UP_RDY_MASK 0x02 +#define WCD9378_SEQ_TX0_STAT_TX0_PWR_DN_RDY_MASK 0x01 + +/* WCD9378_SEQ_TX1_STAT Fields: */ +#define WCD9378_SEQ_TX1_STAT_TX1_FUNC_FAULTY_MASK 0x04 +#define WCD9378_SEQ_TX1_STAT_TX1_PWR_UP_RDY_MASK 0x02 +#define WCD9378_SEQ_TX1_STAT_TX1_PWR_DN_RDY_MASK 0x01 + +/* WCD9378_SEQ_TX2_STAT Fields: */ +#define WCD9378_SEQ_TX2_STAT_TX2_PWR_UP_RDY_MASK 0x02 +#define WCD9378_SEQ_TX2_STAT_TX2_PWR_DN_RDY_MASK 0x01 + +/* WCD9378_MICB_REMAP_TABLE_VAL_0 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_0_MICB_REMAP_TABLE_VAL_0_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_1 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_1_MICB_REMAP_TABLE_VAL_1_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_2 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_2_MICB_REMAP_TABLE_VAL_2_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_3 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_3_MICB_REMAP_TABLE_VAL_3_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_4 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_4_MICB_REMAP_TABLE_VAL_4_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_5 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_5_MICB_REMAP_TABLE_VAL_5_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_6 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_6_MICB_REMAP_TABLE_VAL_6_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_7 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_7_MICB_REMAP_TABLE_VAL_7_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_8 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_8_MICB_REMAP_TABLE_VAL_8_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_9 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_9_MICB_REMAP_TABLE_VAL_9_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_10 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_10_MICB_REMAP_TABLE_VAL_10_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_11 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_11_MICB_REMAP_TABLE_VAL_11_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_12 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_12_MICB_REMAP_TABLE_VAL_12_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_13 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_13_MICB_REMAP_TABLE_VAL_13_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_14 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_14_MICB_REMAP_TABLE_VAL_14_MASK 0xff + +/* WCD9378_MICB_REMAP_TABLE_VAL_15 Fields: */ +#define WCD9378_MICB_REMAP_TABLE_VAL_15_MICB_REMAP_TABLE_VAL_15_MASK 0xff + +/* WCD9378_SM0_MB_SEL Fields: */ +#define WCD9378_SM0_MB_SEL_SM0_MB_SEL_MASK 0x03 + +/* WCD9378_SM1_MB_SEL Fields: */ +#define WCD9378_SM1_MB_SEL_SM1_MB_SEL_MASK 0x03 + +/* WCD9378_SM2_MB_SEL Fields: */ +#define WCD9378_SM2_MB_SEL_SM2_MB_SEL_MASK 0x03 + +/* WCD9378_MB_PULLUP_EN Fields: */ +#define WCD9378_MB_PULLUP_EN_MB3_1P8V_OR_PULLUP_SEL_MASK 0x04 +#define WCD9378_MB_PULLUP_EN_MB2_1P8V_OR_PULLUP_SEL_MASK 0x02 +#define WCD9378_MB_PULLUP_EN_MB1_1P8V_OR_PULLUP_SEL_MASK 0x01 + +/* WCD9378_BYP_EN_CTL0 Fields: */ +#define WCD9378_BYP_EN_CTL0_TX2_SEQ_BYP_EN_MASK 0x10 +#define WCD9378_BYP_EN_CTL0_TX1_SEQ_BYP_EN_MASK 0x08 +#define WCD9378_BYP_EN_CTL0_TX0_SEQ_BYP_EN_MASK 0x04 +#define WCD9378_BYP_EN_CTL0_SA_SEQ_BYP_EN_MASK 0x02 +#define WCD9378_BYP_EN_CTL0_HPH_SEQ_BYP_EN_MASK 0x01 + +/* WCD9378_BYP_EN_CTL1 Fields: */ +#define WCD9378_BYP_EN_CTL1_SYS_USAGE_BYP_EN_MASK 0x04 +#define WCD9378_BYP_EN_CTL1_SDCA_BYP_EN_MASK 0x02 +#define WCD9378_BYP_EN_CTL1_DIG_SEQ_BYP_EN_MASK 0x01 + +/* WCD9378_BYP_EN_CTL2 Fields: */ +#define WCD9378_BYP_EN_CTL2_RX_CLK_BYP_EN_MASK 0x80 +#define WCD9378_BYP_EN_CTL2_TX_CLK_BANK1_BYP_EN_MASK 0x40 +#define WCD9378_BYP_EN_CTL2_TX_CLK_BANK0_BYP_EN_MASK 0x20 +#define WCD9378_BYP_EN_CTL2_HPH_VALID_CFG_BYP_EN_MASK 0x10 +#define WCD9378_BYP_EN_CTL2_SA_VALID_CFG_BYP_EN_MASK 0x08 +#define WCD9378_BYP_EN_CTL2_TX2_VALID_CFG_BYP_EN_MASK 0x04 +#define WCD9378_BYP_EN_CTL2_TX1_VALID_CFG_BYP_EN_MASK 0x02 +#define WCD9378_BYP_EN_CTL2_TX0_VALID_CFG_BYP_EN_MASK 0x01 + +/* WCD9378_SEQ_OVRRIDE_CTL0 Fields: */ +#define WCD9378_SEQ_OVRRIDE_CTL0_HPHR_COMP_EN_OVR_MASK 0x80 +#define WCD9378_SEQ_OVRRIDE_CTL0_HPHL_COMP_EN_OVR_MASK 0x40 +#define WCD9378_SEQ_OVRRIDE_CTL0_CLASSAB_EN_OVR_MASK 0x20 +#define WCD9378_SEQ_OVRRIDE_CTL0_TX2_SEQ_EN_OVR_MASK 0x10 +#define WCD9378_SEQ_OVRRIDE_CTL0_TX1_SEQ_EN_OVR_MASK 0x08 +#define WCD9378_SEQ_OVRRIDE_CTL0_TX0_SEQ_EN_OVR_MASK 0x04 +#define WCD9378_SEQ_OVRRIDE_CTL0_SA_SEQ_EN_OVR_MASK 0x02 +#define WCD9378_SEQ_OVRRIDE_CTL0_HPH_SEQ_EN_OVR_MASK 0x01 + +/* WCD9378_SEQ_OVRRIDE_CTL1 Fields: */ +#define WCD9378_SEQ_OVRRIDE_CTL1_RX2_MUTE_OVR_MASK 0x80 +#define WCD9378_SEQ_OVRRIDE_CTL1_RX1_MUTE_OVR_MASK 0x40 +#define WCD9378_SEQ_OVRRIDE_CTL1_RX0_MUTE_OVR_MASK 0x20 +#define WCD9378_SEQ_OVRRIDE_CTL1_TX2_SEQ_TRIGGER_OVR_MASK 0x10 +#define WCD9378_SEQ_OVRRIDE_CTL1_TX1_SEQ_TRIGGER_OVR_MASK 0x08 +#define WCD9378_SEQ_OVRRIDE_CTL1_TX0_SEQ_TRIGGER_OVR_MASK 0x04 +#define WCD9378_SEQ_OVRRIDE_CTL1_SA_SEQ_TRIGGER_OVR_MASK 0x02 +#define WCD9378_SEQ_OVRRIDE_CTL1_HPH_SEQ_TRIGGER_OVR_MASK 0x01 + +/* WCD9378_SEQ_OVRRIDE_CTL2 Fields: */ +#define WCD9378_SEQ_OVRRIDE_CTL2_TX2_VALID_CFG_OVR_MASK 0x40 +#define WCD9378_SEQ_OVRRIDE_CTL2_TX1_VALID_CFG_OVR_MASK 0x20 +#define WCD9378_SEQ_OVRRIDE_CTL2_TX0_VALID_CFG_OVR_MASK 0x10 +#define WCD9378_SEQ_OVRRIDE_CTL2_SA_VALID_CFG_OVR_MASK 0x08 +#define WCD9378_SEQ_OVRRIDE_CTL2_HPH_VALID_CFG_OVR_MASK 0x04 +#define WCD9378_SEQ_OVRRIDE_CTL2_SJ_USAGE_OVR_MASK 0x03 + +/* WCD9378_HPH_SEQ_OVRRIDE_CTL0 Fields: */ +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_ANA_CLKS_EN_MASK 0x80 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_DIG_CLKS_EN_MASK 0x40 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_RX_BIAS_EN_MASK 0x20 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_NCP_EN_MASK 0x10 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_CLASSG_CP_EN_MASK 0x08 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_ACT_DET_EN_MASK 0x04 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_PAS_EN_MASK 0x02 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0_ACTUAL_PS_MASK 0x01 + +/* WCD9378_HPH_SEQ_OVRRIDE_CTL1 Fields: */ +#define WCD9378_HPH_SEQ_OVRRIDE_CTL1_HREF_EN_MASK 0x04 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL1_SET_POWER_LEVEL_MASK 0x02 +#define WCD9378_HPH_SEQ_OVRRIDE_CTL1_AUTOCHOP_TIMER_CTL_EN_MASK 0x01 + +/* WCD9378_SA_SEQ_OVRRIDE_CTL Fields: */ +#define WCD9378_SA_SEQ_OVRRIDE_CTL_ANA_CLKS_EN_MASK 0x80 +#define WCD9378_SA_SEQ_OVRRIDE_CTL_DIG_CLKS_EN_MASK 0x40 +#define WCD9378_SA_SEQ_OVRRIDE_CTL_RX_BIAS_EN_MASK 0x20 +#define WCD9378_SA_SEQ_OVRRIDE_CTL_NCP_EN_MASK 0x10 +#define WCD9378_SA_SEQ_OVRRIDE_CTL_CLASSG_CP_EN_MASK 0x08 +#define WCD9378_SA_SEQ_OVRRIDE_CTL_ACT_DET_EN_MASK 0x04 +#define WCD9378_SA_SEQ_OVRRIDE_CTL_PAS_EN_MASK 0x02 +#define WCD9378_SA_SEQ_OVRRIDE_CTL_ACTUAL_PS_MASK 0x01 + +/* WCD9378_TX0_SEQ_OVRRIDE_CTL Fields: */ +#define WCD9378_TX0_SEQ_OVRRIDE_CTL_TX0_TXDN_CLK_EN_MASK 0x08 +#define WCD9378_TX0_SEQ_OVRRIDE_CTL_TX0_SET_POWER_LEVEL_MASK 0x04 +#define WCD9378_TX0_SEQ_OVRRIDE_CTL_TX0_HPF_INIT_MASK 0x02 +#define WCD9378_TX0_SEQ_OVRRIDE_CTL_ACTUAL_PS_MASK 0x01 + +/* WCD9378_TX1_SEQ_OVRRIDE_CTL Fields: */ +#define WCD9378_TX1_SEQ_OVRRIDE_CTL_TX1_TXDN_CLK_EN_MASK 0x08 +#define WCD9378_TX1_SEQ_OVRRIDE_CTL_TX1_SET_POWER_LEVEL_MASK 0x04 +#define WCD9378_TX1_SEQ_OVRRIDE_CTL_TX1_HPF_INIT_MASK 0x02 +#define WCD9378_TX1_SEQ_OVRRIDE_CTL_ACTUAL_PS_MASK 0x01 + +/* WCD9378_TX2_SEQ_OVRRIDE_CTL Fields: */ +#define WCD9378_TX2_SEQ_OVRRIDE_CTL_TX2_TXDN_CLK_EN_MASK 0x08 +#define WCD9378_TX2_SEQ_OVRRIDE_CTL_TX2_SET_POWER_LEVEL_MASK 0x04 +#define WCD9378_TX2_SEQ_OVRRIDE_CTL_TX2_HPF_INIT_MASK 0x02 +#define WCD9378_TX2_SEQ_OVRRIDE_CTL_ACTUAL_PS_MASK 0x01 + +/* WCD9378_FORCE_CTL Fields: */ +#define WCD9378_FORCE_CTL_FORCE_CLASSG_CP_EN_MASK 0x20 +#define WCD9378_FORCE_CTL_FORCE_NCP_EN_MASK 0x10 +#define WCD9378_FORCE_CTL_FORCE_RX_BIAS_EN_MASK 0x08 +#define WCD9378_FORCE_CTL_FORCE_ANA_DIV4_EN_MASK 0x04 +#define WCD9378_FORCE_CTL_FORCE_ANA_DIV2_EN_MASK 0x02 +#define WCD9378_FORCE_CTL_FORCE_ANA_DIV1_EN_MASK 0x01 + + +/* WCD9378_DEVICE_DET Fields: */ +#define WCD9378_DEVICE_DET_ACCESSORY_TYPE_MASK 0x07 + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_0 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_0_TYPE0_WRAP_OSCNX_TPRESS_MIN_0_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_0 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_0_TYPE0_WRAP_OSCNX_TPRESS_MAX_0_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_0 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_0_TYPE0_WRAP_OSCNX_TRELEASE_MIN_0_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_0 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_0_TYPE0_WRAP_OSCNX_TRELEASE_MAX_0_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_0 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_0_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_0_MASK 0x0f + +/* WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_0 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_0_TYPE0_WRAP_OSCNX_OUTPUT_SEL_0_MASK 0x01 + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_1 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_1_TYPE0_WRAP_OSCNX_TPRESS_MIN_1_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_1 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_1_TYPE0_WRAP_OSCNX_TPRESS_MAX_1_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_1 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_1_TYPE0_WRAP_OSCNX_TRELEASE_MIN_1_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_1 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_1_TYPE0_WRAP_OSCNX_TRELEASE_MAX_1_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_1 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_1_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_1_MASK 0x0f + +/* WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_1 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_1_TYPE0_WRAP_OSCNX_OUTPUT_SEL_1_MASK 0x01 + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_2 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_2_TYPE0_WRAP_OSCNX_TPRESS_MIN_2_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_2 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_2_TYPE0_WRAP_OSCNX_TPRESS_MAX_2_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_2 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_2_TYPE0_WRAP_OSCNX_TRELEASE_MIN_2_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_2 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_2_TYPE0_WRAP_OSCNX_TRELEASE_MAX_2_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_2 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_2_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_2_MASK 0x0f + +/* WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_2 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_2_TYPE0_WRAP_OSCNX_OUTPUT_SEL_2_MASK 0x01 + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_3 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_3_TYPE0_WRAP_OSCNX_TPRESS_MIN_3_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_3 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_3_TYPE0_WRAP_OSCNX_TPRESS_MAX_3_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_3 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_3_TYPE0_WRAP_OSCNX_TRELEASE_MIN_3_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_3 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_3_TYPE0_WRAP_OSCNX_TRELEASE_MAX_3_MASK 0xff + +/* WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_3 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_3_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_3_MASK 0x0f + +/* WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_3 Fields: */ +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_3_TYPE0_WRAP_OSCNX_OUTPUT_SEL_3_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_0 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_0_TYPE1_WRAP_OSCNX_TPRESS_MIN_0_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_0 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_0_TYPE1_WRAP_OSCNX_TPRESS_MAX_0_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_0 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_0_TYPE1_WRAP_OSCNX_TRELEASE_MIN_0_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_0 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_0_TYPE1_WRAP_OSCNX_TRELEASE_MAX_0_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_0 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_0_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_0_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_0 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_0_TYPE1_WRAP_OSCNX_OUTPUT_SEL_0_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_0 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_0_TYPE1_WRAP_HOLD_TPRESS_MIN_0_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_0 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_0_TYPE1_WRAP_HOLD_TRELEASE_MIN_0_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_0 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_0_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_0_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_0 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_0_TYPE1_WRAP_RO_TDEBOUNCE_0_MASK 0x1f + +/* WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_0 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_0_TYPE1_WRAP_RO_HDL_BT_ASSIGN_0_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RTC_OOC_SEL_0 Fields: */ +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_0_TYPE1_WRAP_RTC_OOC_SEL_0_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_1 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_1_TYPE1_WRAP_OSCNX_TPRESS_MIN_1_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_1 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_1_TYPE1_WRAP_OSCNX_TPRESS_MAX_1_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_1 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_1_TYPE1_WRAP_OSCNX_TRELEASE_MIN_1_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_1 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_1_TYPE1_WRAP_OSCNX_TRELEASE_MAX_1_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_1 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_1_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_1_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_1 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_1_TYPE1_WRAP_OSCNX_OUTPUT_SEL_1_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_1 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_1_TYPE1_WRAP_HOLD_TPRESS_MIN_1_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_1 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_1_TYPE1_WRAP_HOLD_TRELEASE_MIN_1_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_1 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_1_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_1_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_1 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_1_TYPE1_WRAP_RO_TDEBOUNCE_1_MASK 0x1f + +/* WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_1 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_1_TYPE1_WRAP_RO_HDL_BT_ASSIGN_1_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RTC_OOC_SEL_1 Fields: */ +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_1_TYPE1_WRAP_RTC_OOC_SEL_1_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_2 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_2_TYPE1_WRAP_OSCNX_TPRESS_MIN_2_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_2 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_2_TYPE1_WRAP_OSCNX_TPRESS_MAX_2_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_2 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_2_TYPE1_WRAP_OSCNX_TRELEASE_MIN_2_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_2 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_2_TYPE1_WRAP_OSCNX_TRELEASE_MAX_2_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_2 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_2_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_2_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_2 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_2_TYPE1_WRAP_OSCNX_OUTPUT_SEL_2_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_2 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_2_TYPE1_WRAP_HOLD_TPRESS_MIN_2_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_2 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_2_TYPE1_WRAP_HOLD_TRELEASE_MIN_2_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_2 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_2_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_2_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_2 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_2_TYPE1_WRAP_RO_TDEBOUNCE_2_MASK 0x1f + +/* WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_2 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_2_TYPE1_WRAP_RO_HDL_BT_ASSIGN_2_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RTC_OOC_SEL_2 Fields: */ +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_2_TYPE1_WRAP_RTC_OOC_SEL_2_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_3 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_3_TYPE1_WRAP_OSCNX_TPRESS_MIN_3_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_3 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_3_TYPE1_WRAP_OSCNX_TPRESS_MAX_3_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_3 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_3_TYPE1_WRAP_OSCNX_TRELEASE_MIN_3_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_3 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_3_TYPE1_WRAP_OSCNX_TRELEASE_MAX_3_MASK 0xff + +/* WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_3 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_3_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_3_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_3 Fields: */ +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_3_TYPE1_WRAP_OSCNX_OUTPUT_SEL_3_MASK 0x01 + +/* WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_3 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_3_TYPE1_WRAP_HOLD_TPRESS_MIN_3_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_3 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_3_TYPE1_WRAP_HOLD_TRELEASE_MIN_3_MASK 0xff + +/* WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_3 Fields: */ +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_3_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_3_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_3 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_3_TYPE1_WRAP_RO_TDEBOUNCE_3_MASK 0x1f + +/* WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_3 Fields: */ +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_3_TYPE1_WRAP_RO_HDL_BT_ASSIGN_3_MASK 0x0f + +/* WCD9378_TYPE1_WRAP_RTC_OOC_SEL_3 Fields: */ +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_3_TYPE1_WRAP_RTC_OOC_SEL_3_MASK 0x01 + +/* WCD9378_SDCA_MESSAGE_GATE Fields: */ +#define WCD9378_SDCA_MESSAGE_GATE_CLAMP_ELEC_SEL_MASK 0x01 + +/* WCD9378_MBHC_DATA_IN_EDGE Fields: */ +#define WCD9378_MBHC_DATA_IN_EDGE_RISE_EDGE_EN_MASK 0x01 + +/* WCD9378_MBHC_RESET Fields: */ +#define WCD9378_MBHC_RESET_SOFT_RST_MASK 0x01 + +/* WCD9378_MBHC_DEBUG Fields: */ +#define WCD9378_MBHC_DEBUG_UMP_WR_NO_STOP_EN_MASK 0x02 +#define WCD9378_MBHC_DEBUG_UMP_RD_ALL_EN_MASK 0x01 + +/* WCD9378_MBHC_DEBUG_UMP_0 Fields: */ +#define WCD9378_MBHC_DEBUG_UMP_0_UMP_DATA_IN_7_0_MASK 0xff + +/* WCD9378_MBHC_DEBUG_UMP_1 Fields: */ +#define WCD9378_MBHC_DEBUG_UMP_1_UMP_DATA_IN_15_8_MASK 0xff + +/* WCD9378_MBHC_DEBUG_UMP_2 Fields: */ +#define WCD9378_MBHC_DEBUG_UMP_2_UMP_DATA_IN_23_16_MASK 0xff + + +/* WCD9378_HID_FUNC_EXT_ID_0 Fields: */ +#define WCD9378_HID_FUNC_EXT_ID_0_FUNC_EXT_ID_0_MASK 0xff + +/* WCD9378_HID_FUNC_EXT_ID_1 Fields: */ +#define WCD9378_HID_FUNC_EXT_ID_1_FUNC_EXT_ID_1_MASK 0xff + +/* WCD9378_HID_FUNC_EXT_VER Fields: */ +#define WCD9378_HID_FUNC_EXT_VER_FUNC_EXT_VER_MASK 0xff + +/* WCD9378_HID_FUNC_STAT Fields: */ +#define WCD9378_HID_FUNC_STAT_FUNC_STAT_MASK 0xff + +/* WCD9378_HID_CUR_OWNER Fields: */ +#define WCD9378_HID_CUR_OWNER_HID_CUR_OWNER_MASK 0x01 + +/* WCD9378_HID_MSG_OFFSET Fields: */ +#define WCD9378_HID_MSG_OFFSET_HID_MSG_OFFSET_MASK 0xffffffff + +/* WCD9378_HID_MSG_LENGTH Fields: */ +#define WCD9378_HID_MSG_LENGTH_HID_MSG_LENGTH_MASK 0xffffffff + +/* WCD9378_HID_DEV_MANU_ID_0 Fields: */ +#define WCD9378_HID_DEV_MANU_ID_0_DEV_MANU_ID_0_MASK 0xff + +/* WCD9378_HID_DEV_MANU_ID_1 Fields: */ +#define WCD9378_HID_DEV_MANU_ID_1_DEV_MANU_ID_1_MASK 0xff + +/* WCD9378_HID_DEV_PART_ID_0 Fields: */ +#define WCD9378_HID_DEV_PART_ID_0_DEV_PART_ID_0_MASK 0xff + +/* WCD9378_HID_DEV_PART_ID_1 Fields: */ +#define WCD9378_HID_DEV_PART_ID_1_DEV_PART_ID_1_MASK 0xff + +/* WCD9378_HID_DEV_VER Fields: */ +#define WCD9378_HID_DEV_VER_DEV_VER_MASK 0xff + + +/* WCD9378_SMP_AMP_FUNC_EXT_ID_0 Fields: */ +#define WCD9378_SMP_AMP_FUNC_EXT_ID_0_FUNC_EXT_ID_0_MASK 0xff + +/* WCD9378_SMP_AMP_FUNC_EXT_ID_1 Fields: */ +#define WCD9378_SMP_AMP_FUNC_EXT_ID_1_FUNC_EXT_ID_1_MASK 0xff + +/* WCD9378_SMP_AMP_FUNC_EXT_VER Fields: */ +#define WCD9378_SMP_AMP_FUNC_EXT_VER_FUNC_EXT_VER_MASK 0xff + +/* WCD9378_XU22_BYP Fields: */ +#define WCD9378_XU22_BYP_XU22_BYP_MASK 0x01 + +/* WCD9378_PDE22_REQ_PS Fields: */ +#define WCD9378_PDE22_REQ_PS_PDE22_REQ_PS_MASK 0xff + +/* WCD9378_FU23_MUTE Fields: */ +#define WCD9378_FU23_MUTE_FU23_MUTE_MASK 0x01 + +/* WCD9378_PDE23_REQ_PS Fields: */ +#define WCD9378_PDE23_REQ_PS_PDE23_REQ_PS_MASK 0xff + +/* WCD9378_SMP_AMP_FUNC_STAT Fields: */ +#define WCD9378_SMP_AMP_FUNC_STAT_FUNC_STAT_MASK 0xff + +/* WCD9378_FUNC_ACT Fields: */ +#define WCD9378_FUNC_ACT_FUNC_ACT_MASK 0x01 + +/* WCD9378_PDE22_ACT_PS Fields: */ +#define WCD9378_PDE22_ACT_PS_PDE22_ACT_PS_MASK 0xff + +/* WCD9378_SAPU29_PROT_MODE Fields: */ +#define WCD9378_SAPU29_PROT_MODE_SAPU29_PROT_MODE_MASK 0xff + +/* WCD9378_SAPU29_PROT_STAT Fields: */ +#define WCD9378_SAPU29_PROT_STAT_SAPU29_PROT_STAT_MASK 0xff + +/* WCD9378_PDE23_ACT_PS Fields: */ +#define WCD9378_PDE23_ACT_PS_PDE23_ACT_PS_MASK 0xff + +/* WCD9378_SMP_AMP_DEV_MANU_ID_0 Fields: */ +#define WCD9378_SMP_AMP_DEV_MANU_ID_0_DEV_MANU_ID_0_MASK 0xff + +/* WCD9378_SMP_AMP_DEV_MANU_ID_1 Fields: */ +#define WCD9378_SMP_AMP_DEV_MANU_ID_1_DEV_MANU_ID_1_MASK 0xff + +/* WCD9378_SMP_AMP_DEV_PART_ID_0 Fields: */ +#define WCD9378_SMP_AMP_DEV_PART_ID_0_DEV_PART_ID_0_MASK 0xff + +/* WCD9378_SMP_AMP_DEV_PART_ID_1 Fields: */ +#define WCD9378_SMP_AMP_DEV_PART_ID_1_DEV_PART_ID_1_MASK 0xff + +/* WCD9378_SMP_AMP_DEV_VER Fields: */ +#define WCD9378_SMP_AMP_DEV_VER_DEV_VER_MASK 0xff + + +/* WCD9378_CMT_GRP_MASK Fields: */ +#define WCD9378_CMT_GRP_MASK_CMT_GRP_MASK_MASK 0xff + +/* WCD9378_SMP_JACK_FUNC_EXT_ID_0 Fields: */ +#define WCD9378_SMP_JACK_FUNC_EXT_ID_0_FUNC_EXT_ID_0_MASK 0xff + +/* WCD9378_SMP_JACK_FUNC_EXT_ID_1 Fields: */ +#define WCD9378_SMP_JACK_FUNC_EXT_ID_1_FUNC_EXT_ID_1_MASK 0xff + +/* WCD9378_SMP_JACK_FUNC_EXT_VER Fields: */ +#define WCD9378_SMP_JACK_FUNC_EXT_VER_FUNC_EXT_VER_MASK 0xff + +/* WCD9378_IT41_USAGE Fields: */ +#define WCD9378_IT41_USAGE_IT41_USAGE_MASK 0xff + +/* WCD9378_XU42_BYP Fields: */ +#define WCD9378_XU42_BYP_XU42_BYP_MASK 0x01 + +/* WCD9378_PDE42_REQ_PS Fields: */ +#define WCD9378_PDE42_REQ_PS_PDE42_REQ_PS_MASK 0xff + +/* WCD9378_FU42_MUTE_CH1 Fields: */ +#define WCD9378_FU42_MUTE_CH1_FU42_MUTE_CH1_MASK 0x01 + +/* WCD9378_FU42_MUTE_CH2 Fields: */ +#define WCD9378_FU42_MUTE_CH2_FU42_MUTE_CH2_MASK 0x01 + +/* WCD9378_FU42_CH_VOL_CH1 Fields: */ +#define WCD9378_FU42_CH_VOL_CH1_FU42_CH_VOL_CH1_MASK 0xffff + +/* WCD9378_FU42_CH_VOL_CH2 Fields: */ +#define WCD9378_FU42_CH_VOL_CH2_FU42_CH_VOL_CH2_MASK 0xffff + +/* WCD9378_SU43_SELECTOR Fields: */ +#define WCD9378_SU43_SELECTOR_SU43_SELECTOR_MASK 0x01 + +/* WCD9378_SU45_SELECTOR Fields: */ +#define WCD9378_SU45_SELECTOR_SU45_SELECTOR_MASK 0x01 + +/* WCD9378_PDE47_REQ_PS Fields: */ +#define WCD9378_PDE47_REQ_PS_PDE47_REQ_PS_MASK 0xff + +/* WCD9378_GE35_SEL_MODE Fields: */ +#define WCD9378_GE35_SEL_MODE_GE35_SEL_MODE_MASK 0xff + +/* WCD9378_GE35_DET_MODE Fields: */ +#define WCD9378_GE35_DET_MODE_GE35_DET_MODE_MASK 0xff + +/* WCD9378_IT31_MICB Fields: */ +#define WCD9378_IT31_MICB_IT31_MICB_MASK 0xff + +/* WCD9378_IT31_USAGE Fields: */ +#define WCD9378_IT31_USAGE_IT31_USAGE_MASK 0xff + +/* WCD9378_PDE34_REQ_PS Fields: */ +#define WCD9378_PDE34_REQ_PS_PDE34_REQ_PS_MASK 0xff + +/* WCD9378_SU45_TX_SELECTOR Fields: */ +#define WCD9378_SU45_TX_SELECTOR_SU45_TX_SELECTOR_MASK 0x01 + +/* WCD9378_XU36_BYP Fields: */ +#define WCD9378_XU36_BYP_XU36_BYP_MASK 0x01 + +/* WCD9378_PDE36_REQ_PS Fields: */ +#define WCD9378_PDE36_REQ_PS_PDE36_REQ_PS_MASK 0xff + +/* WCD9378_OT36_USAGE Fields: */ +#define WCD9378_OT36_USAGE_OT36_USAGE_MASK 0xff + +/* WCD9378_SMP_JACK_FUNC_STAT Fields: */ +#define WCD9378_SMP_JACK_FUNC_STAT_FUNC_STAT_MASK 0xff + +/* WCD9378_SMP_JACK_FUNC_ACT Fields: */ +#define WCD9378_SMP_JACK_FUNC_ACT_FUNC_ACT_MASK 0x01 + +/* WCD9378_PDE42_ACT_PS Fields: */ +#define WCD9378_PDE42_ACT_PS_PDE42_ACT_PS_MASK 0xff + +/* WCD9378_PDE47_ACT_PS Fields: */ +#define WCD9378_PDE47_ACT_PS_PDE47_ACT_PS_MASK 0xff + +/* WCD9378_PDE34_ACT_PS Fields: */ +#define WCD9378_PDE34_ACT_PS_PDE34_ACT_PS_MASK 0xff + +/* WCD9378_PDE36_ACT_PS Fields: */ +#define WCD9378_PDE36_ACT_PS_PDE36_ACT_PS_MASK 0xff + +/* WCD9378_SMP_JACK_DEV_MANU_ID_0 Fields: */ +#define WCD9378_SMP_JACK_DEV_MANU_ID_0_DEV_MANU_ID_0_MASK 0xff + +/* WCD9378_SMP_JACK_DEV_MANU_ID_1 Fields: */ +#define WCD9378_SMP_JACK_DEV_MANU_ID_1_DEV_MANU_ID_1_MASK 0xff + +/* WCD9378_SMP_JACK_DEV_PART_ID_0 Fields: */ +#define WCD9378_SMP_JACK_DEV_PART_ID_0_DEV_PART_ID_0_MASK 0xff + +/* WCD9378_SMP_JACK_DEV_PART_ID_1 Fields: */ +#define WCD9378_SMP_JACK_DEV_PART_ID_1_DEV_PART_ID_1_MASK 0xff + +/* WCD9378_SMP_JACK_DEV_VER Fields: */ +#define WCD9378_SMP_JACK_DEV_VER_DEV_VER_MASK 0xff + + +/* WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_0_FUNC_EXT_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_1_FUNC_EXT_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_FUNC_EXT_VER Fields: */ +#define WCD9378_SMP_MIC_CTRL0_FUNC_EXT_VER_FUNC_EXT_VER_MASK 0xff + +/* WCD9378_IT11_MICB Fields: */ +#define WCD9378_IT11_MICB_IT11_MICB_MASK 0xff + +/* WCD9378_IT11_USAGE Fields: */ +#define WCD9378_IT11_USAGE_IT11_USAGE_MASK 0xff + +/* WCD9378_PDE11_REQ_PS Fields: */ +#define WCD9378_PDE11_REQ_PS_PDE11_REQ_PS_MASK 0xff + +/* WCD9378_OT10_USAGE Fields: */ +#define WCD9378_OT10_USAGE_OT10_USAGE_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_FUNC_STAT Fields: */ +#define WCD9378_SMP_MIC_CTRL0_FUNC_STAT_FUNC_STAT_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_FUNC_ACT Fields: */ +#define WCD9378_SMP_MIC_CTRL0_FUNC_ACT_FUNC_ACT_MASK 0x01 + +/* WCD9378_PDE11_ACT_PS Fields: */ +#define WCD9378_PDE11_ACT_PS_PDE11_ACT_PS_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_0_DEV_MANU_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_1_DEV_MANU_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_0_DEV_PART_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_1_DEV_PART_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL0_DEV_VER Fields: */ +#define WCD9378_SMP_MIC_CTRL0_DEV_VER_DEV_VER_MASK 0xff + + +/* WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_0_FUNC_EXT_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_1_FUNC_EXT_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_FUNC_EXT_VER Fields: */ +#define WCD9378_SMP_MIC_CTRL1_FUNC_EXT_VER_FUNC_EXT_VER_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_IT11_MICB Fields: */ +#define WCD9378_SMP_MIC_CTRL1_IT11_MICB_IT11_MICB_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_IT11_USAGE Fields: */ +#define WCD9378_SMP_MIC_CTRL1_IT11_USAGE_IT11_USAGE_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS Fields: */ +#define WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS_PDE11_REQ_PS_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_OT10_USAGE Fields: */ +#define WCD9378_SMP_MIC_CTRL1_OT10_USAGE_OT10_USAGE_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_FUNC_STAT Fields: */ +#define WCD9378_SMP_MIC_CTRL1_FUNC_STAT_FUNC_STAT_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_FUNC_ACT Fields: */ +#define WCD9378_SMP_MIC_CTRL1_FUNC_ACT_FUNC_ACT_MASK 0x01 + +/* WCD9378_SMP_MIC_CTRL1_PDE11_ACT_PS Fields: */ +#define WCD9378_SMP_MIC_CTRL1_PDE11_ACT_PS_PDE11_ACT_PS_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_0_DEV_MANU_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_1_DEV_MANU_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_0_DEV_PART_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_1_DEV_PART_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL1_DEV_VER Fields: */ +#define WCD9378_SMP_MIC_CTRL1_DEV_VER_DEV_VER_MASK 0xff + + +/* WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_0_FUNC_EXT_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_1_FUNC_EXT_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_FUNC_EXT_VER Fields: */ +#define WCD9378_SMP_MIC_CTRL2_FUNC_EXT_VER_FUNC_EXT_VER_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_IT11_MICB Fields: */ +#define WCD9378_SMP_MIC_CTRL2_IT11_MICB_IT11_MICB_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_IT11_USAGE Fields: */ +#define WCD9378_SMP_MIC_CTRL2_IT11_USAGE_IT11_USAGE_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS Fields: */ +#define WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS_PDE11_REQ_PS_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_OT10_USAGE Fields: */ +#define WCD9378_SMP_MIC_CTRL2_OT10_USAGE_OT10_USAGE_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_FUNC_STAT Fields: */ +#define WCD9378_SMP_MIC_CTRL2_FUNC_STAT_FUNC_STAT_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_FUNC_ACT Fields: */ +#define WCD9378_SMP_MIC_CTRL2_FUNC_ACT_FUNC_ACT_MASK 0x01 + +/* WCD9378_SMP_MIC_CTRL2_PDE11_ACT_PS Fields: */ +#define WCD9378_SMP_MIC_CTRL2_PDE11_ACT_PS_PDE11_ACT_PS_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_0_DEV_MANU_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_1_DEV_MANU_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_0 Fields: */ +#define WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_0_DEV_PART_ID_0_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_1 Fields: */ +#define WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_1_DEV_PART_ID_1_MASK 0xff + +/* WCD9378_SMP_MIC_CTRL2_DEV_VER Fields: */ +#define WCD9378_SMP_MIC_CTRL2_DEV_VER_DEV_VER_MASK 0xff + + +/* WCD9378_REPORT_ID Fields: */ +#define WCD9378_REPORT_ID_REPORT_ID_MASK 0xff + +/* WCD9378_MESSAGE0 Fields: */ +#define WCD9378_MESSAGE0_MESSAGE0_MASK 0xff + +/* WCD9378_MESSAGE1 Fields: */ +#define WCD9378_MESSAGE1_MESSAGE1_MASK 0xff + +/* WCD9378_MESSAGE2 Fields: */ +#define WCD9378_MESSAGE2_MESSAGE2_MASK 0xff + + +#endif /* WCD9378_REG_MASKS_H */ + diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-registers.h new file mode 100644 index 0000000000..ed5b6030e1 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-registers.h @@ -0,0 +1,905 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef WCD9378_REGISTERS_H +#define WCD9378_REGISTERS_H + +enum { + REG_NO_ACCESS, + RD_REG, + WR_REG, + RD_WR_REG, +}; + +#define WCD9378_BASE 0x3fffffff + +#define WCD9378_REG(reg) (((reg & 0x0ff00000) >> 8) | (reg & 0xfff)) + +#define WCD9378_FUNC0_BASE (WCD9378_BASE+0x01) +#define WCD9378_FUNC_EXT_ID_0 (WCD9378_FUNC0_BASE+0x48) +#define WCD9378_FUNC_EXT_ID_1 (WCD9378_FUNC0_BASE+0x49) +#define WCD9378_FUNC_EXT_VER (WCD9378_FUNC0_BASE+0x50) +#define WCD9378_FUNC_STAT (WCD9378_FUNC0_BASE+0x80000) +#define WCD9378_DEV_MANU_ID_0 (WCD9378_FUNC0_BASE+0x100060) +#define WCD9378_DEV_MANU_ID_1 (WCD9378_FUNC0_BASE+0x100061) +#define WCD9378_DEV_PART_ID_0 (WCD9378_FUNC0_BASE+0x100068) +#define WCD9378_DEV_PART_ID_1 (WCD9378_FUNC0_BASE+0x100069) +#define WCD9378_DEV_VER (WCD9378_FUNC0_BASE+0x100070) + +#define WCD9378_A_BASE (WCD9378_BASE+0x180001) +#define WCD9378_ANA_PAGE (WCD9378_A_BASE+0x00) +#define WCD9378_ANA_BIAS (WCD9378_A_BASE+0x01) +#define WCD9378_ANA_RX_SUPPLIES (WCD9378_A_BASE+0x08) +#define WCD9378_ANA_HPH (WCD9378_A_BASE+0x09) +#define WCD9378_ANA_EAR (WCD9378_A_BASE+0x0a) +#define WCD9378_ANA_EAR_COMPANDER_CTL (WCD9378_A_BASE+0x0b) +#define WCD9378_ANA_TX_CH1 (WCD9378_A_BASE+0x0e) +#define WCD9378_ANA_TX_CH2 (WCD9378_A_BASE+0x0f) +#define WCD9378_ANA_TX_CH3 (WCD9378_A_BASE+0x10) +#define WCD9378_ANA_TX_CH3_HPF (WCD9378_A_BASE+0x11) +#define WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC (WCD9378_A_BASE+0x12) +#define WCD9378_ANA_MICB3_DSP_EN_LOGIC (WCD9378_A_BASE+0x13) +#define WCD9378_ANA_MBHC_MECH (WCD9378_A_BASE+0x14) +#define WCD9378_ANA_MBHC_ELECT (WCD9378_A_BASE+0x15) +#define WCD9378_ANA_MBHC_ZDET (WCD9378_A_BASE+0x16) +#define WCD9378_ANA_MBHC_RESULT_1 (WCD9378_A_BASE+0x17) +#define WCD9378_ANA_MBHC_RESULT_2 (WCD9378_A_BASE+0x18) +#define WCD9378_ANA_MBHC_RESULT_3 (WCD9378_A_BASE+0x19) +#define WCD9378_ANA_MBHC_BTN0 (WCD9378_A_BASE+0x1a) +#define WCD9378_ANA_MBHC_BTN1 (WCD9378_A_BASE+0x1b) +#define WCD9378_ANA_MBHC_BTN2 (WCD9378_A_BASE+0x1c) +#define WCD9378_ANA_MBHC_BTN3 (WCD9378_A_BASE+0x1d) +#define WCD9378_ANA_MBHC_BTN4 (WCD9378_A_BASE+0x1e) +#define WCD9378_ANA_MBHC_BTN5 (WCD9378_A_BASE+0x1f) +#define WCD9378_ANA_MBHC_BTN6 (WCD9378_A_BASE+0x20) +#define WCD9378_ANA_MBHC_BTN7 (WCD9378_A_BASE+0x21) +#define WCD9378_ANA_MICB1 (WCD9378_A_BASE+0x22) +#define WCD9378_ANA_MICB2 (WCD9378_A_BASE+0x23) +#define WCD9378_ANA_MICB2_RAMP (WCD9378_A_BASE+0x24) +#define WCD9378_ANA_MICB3 (WCD9378_A_BASE+0x25) +#define WCD9378_BIAS_CTL (WCD9378_A_BASE+0x28) +#define WCD9378_BIAS_VBG_FINE_ADJ (WCD9378_A_BASE+0x29) +#define WCD9378_LDOL_VDDCX_ADJUST (WCD9378_A_BASE+0x40) +#define WCD9378_LDOL_DISABLE_LDOL (WCD9378_A_BASE+0x41) +#define WCD9378_MBHC_CTL_CLK (WCD9378_A_BASE+0x56) +#define WCD9378_MBHC_CTL_ANA (WCD9378_A_BASE+0x57) +#define WCD9378_MBHC_CTL_SPARE_1 (WCD9378_A_BASE+0x58) +#define WCD9378_MBHC_CTL_SPARE_2 (WCD9378_A_BASE+0x59) +#define WCD9378_MBHC_CTL_BCS (WCD9378_A_BASE+0x5a) +#define WCD9378_MBHC_MOISTURE_DET_FSM_STATUS (WCD9378_A_BASE+0x5b) +#define WCD9378_MBHC_TEST_CTL (WCD9378_A_BASE+0x5c) +#define WCD9378_LDOH_MODE (WCD9378_A_BASE+0x67) +#define WCD9378_LDOH_BIAS (WCD9378_A_BASE+0x68) +#define WCD9378_LDOH_STB_LOADS (WCD9378_A_BASE+0x69) +#define WCD9378_LDOH_SLOWRAMP (WCD9378_A_BASE+0x6a) +#define WCD9378_MICB1_TEST_CTL_1 (WCD9378_A_BASE+0x6b) +#define WCD9378_MICB1_TEST_CTL_2 (WCD9378_A_BASE+0x6c) +#define WCD9378_MICB1_TEST_CTL_3 (WCD9378_A_BASE+0x6d) +#define WCD9378_MICB2_TEST_CTL_1 (WCD9378_A_BASE+0x6e) +#define WCD9378_MICB2_TEST_CTL_2 (WCD9378_A_BASE+0x6f) +#define WCD9378_MICB2_TEST_CTL_3 (WCD9378_A_BASE+0x70) +#define WCD9378_MICB3_TEST_CTL_1 (WCD9378_A_BASE+0x71) +#define WCD9378_MICB3_TEST_CTL_2 (WCD9378_A_BASE+0x72) +#define WCD9378_MICB3_TEST_CTL_3 (WCD9378_A_BASE+0x73) +#define WCD9378_TX_COM_ADC_VCM (WCD9378_A_BASE+0x77) +#define WCD9378_TX_COM_BIAS_ATEST (WCD9378_A_BASE+0x78) +#define WCD9378_TX_COM_SPARE1 (WCD9378_A_BASE+0x79) +#define WCD9378_TX_COM_SPARE2 (WCD9378_A_BASE+0x7a) +#define WCD9378_TX_COM_TXFE_DIV_CTL (WCD9378_A_BASE+0x7b) +#define WCD9378_TX_COM_TXFE_DIV_START (WCD9378_A_BASE+0x7c) +#define WCD9378_TX_COM_SPARE3 (WCD9378_A_BASE+0x7d) +#define WCD9378_TX_COM_SPARE4 (WCD9378_A_BASE+0x7e) +#define WCD9378_TX_1_2_TEST_EN (WCD9378_A_BASE+0x7f) +#define WCD9378_TX_1_2_ADC_IB (WCD9378_A_BASE+0x80) +#define WCD9378_TX_1_2_ATEST_REFCTL (WCD9378_A_BASE+0x81) +#define WCD9378_TX_1_2_TEST_CTL (WCD9378_A_BASE+0x82) +#define WCD9378_TX_1_2_TEST_BLK_EN1 (WCD9378_A_BASE+0x83) +#define WCD9378_TX_1_2_TXFE1_CLKDIV (WCD9378_A_BASE+0x84) +#define WCD9378_TX_1_2_SAR2_ERR (WCD9378_A_BASE+0x85) +#define WCD9378_TX_1_2_SAR1_ERR (WCD9378_A_BASE+0x86) +#define WCD9378_TX_3_TEST_EN (WCD9378_A_BASE+0x87) +#define WCD9378_TX_3_ADC_IB (WCD9378_A_BASE+0x88) +#define WCD9378_TX_3_ATEST_REFCTL (WCD9378_A_BASE+0x89) +#define WCD9378_TX_3_TEST_CTL (WCD9378_A_BASE+0x8a) +#define WCD9378_TX_3_TEST_BLK_EN3 (WCD9378_A_BASE+0x8b) +#define WCD9378_TX_3_TXFE3_CLKDIV (WCD9378_A_BASE+0x8c) +#define WCD9378_TX_3_SAR4_ERR (WCD9378_A_BASE+0x8d) +#define WCD9378_TX_3_SAR3_ERR (WCD9378_A_BASE+0x8e) +#define WCD9378_TX_3_TEST_BLK_EN2 (WCD9378_A_BASE+0x8f) +#define WCD9378_TX_3_TXFE2_CLKDIV (WCD9378_A_BASE+0x90) +#define WCD9378_TX_3_SPARE1 (WCD9378_A_BASE+0x91) +#define WCD9378_TX_3_TEST_BLK_EN4 (WCD9378_A_BASE+0x92) +#define WCD9378_TX_3_SPARE2 (WCD9378_A_BASE+0x93) +#define WCD9378_TX_3_SPARE3 (WCD9378_A_BASE+0x94) +#define WCD9378_RX_AUX_SW_CTL (WCD9378_A_BASE+0xb3) +#define WCD9378_RX_PA_AUX_IN_CONN (WCD9378_A_BASE+0xb4) +#define WCD9378_RX_TIMER_DIV (WCD9378_A_BASE+0xb5) +#define WCD9378_RX_OCP_CTL (WCD9378_A_BASE+0xb6) +#define WCD9378_RX_OCP_COUNT (WCD9378_A_BASE+0xb7) +#define WCD9378_RX_BIAS_EAR_DAC (WCD9378_A_BASE+0xb8) +#define WCD9378_RX_BIAS_EAR_AMP (WCD9378_A_BASE+0xb9) +#define WCD9378_RX_BIAS_HPH_LDO (WCD9378_A_BASE+0xba) +#define WCD9378_RX_BIAS_HPH_PA (WCD9378_A_BASE+0xbb) +#define WCD9378_RX_BIAS_HPH_RDACBUFF_CNP2 (WCD9378_A_BASE+0xbc) +#define WCD9378_RX_BIAS_HPH_RDAC_LDO (WCD9378_A_BASE+0xbd) +#define WCD9378_RX_BIAS_HPH_CNP1 (WCD9378_A_BASE+0xbe) +#define WCD9378_RX_BIAS_HPH_LOWPOWER (WCD9378_A_BASE+0xbf) +#define WCD9378_RX_BIAS_AUX_DAC (WCD9378_A_BASE+0xc0) +#define WCD9378_RX_BIAS_AUX_AMP (WCD9378_A_BASE+0xc1) +#define WCD9378_RX_SPARE_1 (WCD9378_A_BASE+0xc2) +#define WCD9378_RX_SPARE_2 (WCD9378_A_BASE+0xc3) +#define WCD9378_RX_SPARE_3 (WCD9378_A_BASE+0xc4) +#define WCD9378_RX_SPARE_4 (WCD9378_A_BASE+0xc5) +#define WCD9378_RX_SPARE_5 (WCD9378_A_BASE+0xc6) +#define WCD9378_RX_SPARE_6 (WCD9378_A_BASE+0xc7) +#define WCD9378_RX_SPARE_7 (WCD9378_A_BASE+0xc8) +#define WCD9378_HPH_L_STATUS (WCD9378_A_BASE+0xc9) +#define WCD9378_HPH_R_STATUS (WCD9378_A_BASE+0xca) +#define WCD9378_HPH_CNP_EN (WCD9378_A_BASE+0xcb) +#define WCD9378_HPH_CNP_WG_CTL (WCD9378_A_BASE+0xcc) +#define WCD9378_HPH_CNP_WG_TIME (WCD9378_A_BASE+0xcd) +#define WCD9378_HPH_OCP_CTL (WCD9378_A_BASE+0xce) +#define WCD9378_HPH_AUTO_CHOP (WCD9378_A_BASE+0xcf) +#define WCD9378_HPH_CHOP_CTL (WCD9378_A_BASE+0xd0) +#define WCD9378_HPH_PA_CTL1 (WCD9378_A_BASE+0xd1) +#define WCD9378_HPH_PA_CTL2 (WCD9378_A_BASE+0xd2) +#define WCD9378_HPH_L_EN (WCD9378_A_BASE+0xd3) +#define WCD9378_HPH_L_TEST (WCD9378_A_BASE+0xd4) +#define WCD9378_HPH_L_ATEST (WCD9378_A_BASE+0xd5) +#define WCD9378_HPH_R_EN (WCD9378_A_BASE+0xd6) +#define WCD9378_HPH_R_TEST (WCD9378_A_BASE+0xd7) +#define WCD9378_HPH_R_ATEST (WCD9378_A_BASE+0xd8) +#define WCD9378_HPH_RDAC_CLK_CTL1 (WCD9378_A_BASE+0xd9) +#define WCD9378_HPH_RDAC_CLK_CTL2 (WCD9378_A_BASE+0xda) +#define WCD9378_HPH_RDAC_LDO_CTL (WCD9378_A_BASE+0xdb) +#define WCD9378_HPH_RDAC_CHOP_CLK_LP_CTL (WCD9378_A_BASE+0xdc) +#define WCD9378_HPH_REFBUFF_UHQA_CTL (WCD9378_A_BASE+0xdd) +#define WCD9378_HPH_REFBUFF_LP_CTL (WCD9378_A_BASE+0xde) +#define WCD9378_HPH_L_DAC_CTL (WCD9378_A_BASE+0xdf) +#define WCD9378_HPH_R_DAC_CTL (WCD9378_A_BASE+0xe0) +#define WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL (WCD9378_A_BASE+0xe1) +#define WCD9378_HPH_SURGE_HPHLR_SURGE_EN (WCD9378_A_BASE+0xe2) +#define WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1 (WCD9378_A_BASE+0xe3) +#define WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS (WCD9378_A_BASE+0xe4) +#define WCD9378_EAR_EAR_EN_REG (WCD9378_A_BASE+0xe9) +#define WCD9378_EAR_EAR_PA_CON (WCD9378_A_BASE+0xea) +#define WCD9378_EAR_EAR_SP_CON (WCD9378_A_BASE+0xeb) +#define WCD9378_EAR_EAR_DAC_CON (WCD9378_A_BASE+0xec) +#define WCD9378_EAR_EAR_CNP_FSM_CON (WCD9378_A_BASE+0xed) +#define WCD9378_EAR_TEST_CTL (WCD9378_A_BASE+0xee) +#define WCD9378_EAR_STATUS_REG_1 (WCD9378_A_BASE+0xef) +#define WCD9378_EAR_STATUS_REG_2 (WCD9378_A_BASE+0xf0) +#define WCD9378_ANA_NEW_PAGE (WCD9378_A_BASE+0x100) +#define WCD9378_HPH_NEW_ANA_HPH2 (WCD9378_A_BASE+0x101) +#define WCD9378_HPH_NEW_ANA_HPH3 (WCD9378_A_BASE+0x102) +#define WCD9378_SLEEP_CTL (WCD9378_A_BASE+0x103) +#define WCD9378_SLEEP_WATCHDOG_CTL (WCD9378_A_BASE+0x104) +#define WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL (WCD9378_A_BASE+0x11f) +#define WCD9378_MBHC_NEW_CTL_1 (WCD9378_A_BASE+0x120) +#define WCD9378_MBHC_NEW_CTL_2 (WCD9378_A_BASE+0x121) +#define WCD9378_MBHC_NEW_PLUG_DETECT_CTL (WCD9378_A_BASE+0x122) +#define WCD9378_MBHC_NEW_ZDET_ANA_CTL (WCD9378_A_BASE+0x123) +#define WCD9378_MBHC_NEW_ZDET_RAMP_CTL (WCD9378_A_BASE+0x124) +#define WCD9378_MBHC_NEW_FSM_STATUS (WCD9378_A_BASE+0x125) +#define WCD9378_MBHC_NEW_ADC_RESULT (WCD9378_A_BASE+0x126) +#define WCD9378_AUX_AUXPA (WCD9378_A_BASE+0x128) +#define WCD9378_DIE_CRACK_DIE_CRK_DET_EN (WCD9378_A_BASE+0x12c) +#define WCD9378_DIE_CRACK_DIE_CRK_DET_OUT (WCD9378_A_BASE+0x12d) +#define WCD9378_TX_NEW_TX_CH12_MUX (WCD9378_A_BASE+0x12e) +#define WCD9378_TX_NEW_TX_CH34_MUX (WCD9378_A_BASE+0x12f) +#define WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL (WCD9378_A_BASE+0x132) +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L (WCD9378_A_BASE+0x133) +#define WCD9378_HPH_NEW_INT_RDAC_VREF_CTL (WCD9378_A_BASE+0x134) +#define WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL (WCD9378_A_BASE+0x135) +#define WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R (WCD9378_A_BASE+0x136) +#define WCD9378_HPH_NEW_INT_PA_MISC1 (WCD9378_A_BASE+0x137) +#define WCD9378_HPH_NEW_INT_PA_MISC2 (WCD9378_A_BASE+0x138) +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC (WCD9378_A_BASE+0x139) +#define WCD9378_HPH_NEW_INT_HPH_TIMER1 (WCD9378_A_BASE+0x13a) +#define WCD9378_HPH_NEW_INT_HPH_TIMER2 (WCD9378_A_BASE+0x13b) +#define WCD9378_HPH_NEW_INT_HPH_TIMER3 (WCD9378_A_BASE+0x13c) +#define WCD9378_HPH_NEW_INT_HPH_TIMER4 (WCD9378_A_BASE+0x13d) +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC2 (WCD9378_A_BASE+0x13e) +#define WCD9378_HPH_NEW_INT_PA_RDAC_MISC3 (WCD9378_A_BASE+0x13f) +#define WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (WCD9378_A_BASE+0x145) +#define WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_ULP (WCD9378_A_BASE+0x146) +#define WCD9378_RX_NEW_INT_HPH_RDAC_LDO_LP (WCD9378_A_BASE+0x147) +#define WCD9378_CP_CLASSG_CP_CTRL_0 (WCD9378_A_BASE+0x150) +#define WCD9378_CP_CLASSG_CP_CTRL_1 (WCD9378_A_BASE+0x151) +#define WCD9378_CP_CLASSG_CP_CTRL_2 (WCD9378_A_BASE+0x152) +#define WCD9378_CP_CLASSG_CP_CTRL_3 (WCD9378_A_BASE+0x153) +#define WCD9378_CP_CLASSG_CP_CTRL_4 (WCD9378_A_BASE+0x154) +#define WCD9378_CP_CLASSG_CP_CTRL_5 (WCD9378_A_BASE+0x155) +#define WCD9378_CP_CLASSG_CP_CTRL_6 (WCD9378_A_BASE+0x156) +#define WCD9378_CP_CLASSG_CP_CTRL_7 (WCD9378_A_BASE+0x157) +#define WCD9378_CP_VNEGDAC_CTRL_0 (WCD9378_A_BASE+0x158) +#define WCD9378_CP_VNEGDAC_CTRL_1 (WCD9378_A_BASE+0x159) +#define WCD9378_CP_VNEGDAC_CTRL_2 (WCD9378_A_BASE+0x15a) +#define WCD9378_CP_VNEGDAC_CTRL_3 (WCD9378_A_BASE+0x15b) +#define WCD9378_CP_CP_DTOP_CTRL_0 (WCD9378_A_BASE+0x15c) +#define WCD9378_CP_CP_DTOP_CTRL_1 (WCD9378_A_BASE+0x15d) +#define WCD9378_CP_CP_DTOP_CTRL_2 (WCD9378_A_BASE+0x15e) +#define WCD9378_CP_CP_DTOP_CTRL_3 (WCD9378_A_BASE+0x15f) +#define WCD9378_CP_CP_DTOP_CTRL_4 (WCD9378_A_BASE+0x160) +#define WCD9378_CP_CP_DTOP_CTRL_5 (WCD9378_A_BASE+0x161) +#define WCD9378_CP_CP_DTOP_CTRL_6 (WCD9378_A_BASE+0x162) +#define WCD9378_CP_CP_DTOP_CTRL_7 (WCD9378_A_BASE+0x163) +#define WCD9378_CP_CP_DTOP_CTRL_8 (WCD9378_A_BASE+0x164) +#define WCD9378_CP_CP_DTOP_CTRL_9 (WCD9378_A_BASE+0x165) +#define WCD9378_CP_CP_DTOP_CTRL_10 (WCD9378_A_BASE+0x166) +#define WCD9378_CP_CP_DTOP_CTRL_11 (WCD9378_A_BASE+0x167) +#define WCD9378_CP_CP_DTOP_CTRL_12 (WCD9378_A_BASE+0x168) +#define WCD9378_CP_CP_DTOP_CTRL_13 (WCD9378_A_BASE+0x169) +#define WCD9378_CP_CP_DTOP_CTRL_14 (WCD9378_A_BASE+0x16a) +#define WCD9378_CP_CP_DTOP_CTRL_15 (WCD9378_A_BASE+0x16b) +#define WCD9378_CP_CP_DTOP_CTRL_16 (WCD9378_A_BASE+0x16c) +#define WCD9378_CP_CP_DTOP_CTRL_17 (WCD9378_A_BASE+0x16d) +#define WCD9378_CP_CP_DTOP_CTRL_18 (WCD9378_A_BASE+0x16e) +#define WCD9378_CP_CP_DTOP_CTRL_19 (WCD9378_A_BASE+0x16f) +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL (WCD9378_A_BASE+0x1af) +#define WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL (WCD9378_A_BASE+0x1b0) +#define WCD9378_MBHC_NEW_INT_MECH_DET_CURRENT (WCD9378_A_BASE+0x1b1) +#define WCD9378_MBHC_NEW_INT_SPARE_2 (WCD9378_A_BASE+0x1b2) +#define WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON (WCD9378_A_BASE+0x1b7) +#define WCD9378_EAR_INT_NEW_CNP_VCM_CON1 (WCD9378_A_BASE+0x1b8) +#define WCD9378_EAR_INT_NEW_CNP_VCM_CON2 (WCD9378_A_BASE+0x1b9) +#define WCD9378_EAR_INT_NEW_EAR_DYNAMIC_BIAS (WCD9378_A_BASE+0x1ba) +#define WCD9378_AUX_INT_EN_REG (WCD9378_A_BASE+0x1bd) +#define WCD9378_AUX_INT_PA_CTRL (WCD9378_A_BASE+0x1be) +#define WCD9378_AUX_INT_SP_CTRL (WCD9378_A_BASE+0x1bf) +#define WCD9378_AUX_INT_DAC_CTRL (WCD9378_A_BASE+0x1c0) +#define WCD9378_AUX_INT_CLK_CTRL (WCD9378_A_BASE+0x1c1) +#define WCD9378_AUX_INT_TEST_CTRL (WCD9378_A_BASE+0x1c2) +#define WCD9378_AUX_INT_STATUS_REG (WCD9378_A_BASE+0x1c3) +#define WCD9378_AUX_INT_MISC (WCD9378_A_BASE+0x1c4) +#define WCD9378_SLEEP_INT_WATCHDOG_CTL_1 (WCD9378_A_BASE+0x1d0) +#define WCD9378_SLEEP_INT_WATCHDOG_CTL_2 (WCD9378_A_BASE+0x1d1) +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1 (WCD9378_A_BASE+0x1d3) +#define WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2 (WCD9378_A_BASE+0x1d4) +#define WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L2 (WCD9378_A_BASE+0x1d5) +#define WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L1 (WCD9378_A_BASE+0x1d6) +#define WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L0 (WCD9378_A_BASE+0x1d7) +#define WCD9378_TX_COM_NEW_INT_SPARE1 (WCD9378_A_BASE+0x1d8) +#define WCD9378_TX_COM_NEW_INT_SPARE2 (WCD9378_A_BASE+0x1d9) +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L2 (WCD9378_A_BASE+0x1da) +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L1 (WCD9378_A_BASE+0x1db) +#define WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L0 (WCD9378_A_BASE+0x1dc) +#define WCD9378_TX_COM_NEW_INT_SPARE3 (WCD9378_A_BASE+0x1dd) +#define WCD9378_TX_COM_NEW_INT_SPARE4 (WCD9378_A_BASE+0x1de) +#define WCD9378_TX_COM_NEW_INT_SPARE5 (WCD9378_A_BASE+0x1df) +#define WCD9378_TX_COM_NEW_INT_SPARE6 (WCD9378_A_BASE+0x1e0) +#define WCD9378_TX_COM_NEW_INT_SPARE7 (WCD9378_A_BASE+0x1e1) +#define WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1 (WCD9378_A_BASE+0x1e2) +#define WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L0 (WCD9378_A_BASE+0x1e3) +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L2 (WCD9378_A_BASE+0x1e4) +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L1 (WCD9378_A_BASE+0x1e5) +#define WCD9378_TX_COM_NEW_INT_TXADC_INT_L0 (WCD9378_A_BASE+0x1e6) +#define WCD9378_TX_COM_NEW_INT_SPARE8 (WCD9378_A_BASE+0x1e7) + +#define WCD9378_TAMBORA_BASE (WCD9378_BASE+0x180401) +#define WCD9378_TAMBORA_PAGE (WCD9378_TAMBORA_BASE+0x00) +#define WCD9378_CHIP_ID0 (WCD9378_TAMBORA_BASE+0x01) +#define WCD9378_CHIP_ID1 (WCD9378_TAMBORA_BASE+0x02) +#define WCD9378_CHIP_ID2 (WCD9378_TAMBORA_BASE+0x03) +#define WCD9378_CHIP_ID3 (WCD9378_TAMBORA_BASE+0x04) +#define WCD9378_SWR_TX_CLK_RATE (WCD9378_TAMBORA_BASE+0x05) +#define WCD9378_CDC_RST_CTL (WCD9378_TAMBORA_BASE+0x06) +#define WCD9378_TOP_CLK_CFG (WCD9378_TAMBORA_BASE+0x07) +#define WCD9378_CDC_ANA_CLK_CTL (WCD9378_TAMBORA_BASE+0x08) +#define WCD9378_CDC_DIG_CLK_CTL (WCD9378_TAMBORA_BASE+0x09) +#define WCD9378_SWR_RST_EN (WCD9378_TAMBORA_BASE+0x0a) +#define WCD9378_CDC_PATH_MODE (WCD9378_TAMBORA_BASE+0x0b) +#define WCD9378_CDC_RX_RST (WCD9378_TAMBORA_BASE+0x0c) +#define WCD9378_CDC_RX0_CTL (WCD9378_TAMBORA_BASE+0x0d) +#define WCD9378_CDC_RX1_CTL (WCD9378_TAMBORA_BASE+0x0e) +#define WCD9378_CDC_RX2_CTL (WCD9378_TAMBORA_BASE+0x0f) +#define WCD9378_CDC_TX_ANA_MODE_0_1 (WCD9378_TAMBORA_BASE+0x10) +#define WCD9378_CDC_TX_ANA_MODE_2_3 (WCD9378_TAMBORA_BASE+0x11) +#define WCD9378_CDC_COMP_CTL_0 (WCD9378_TAMBORA_BASE+0x14) +#define WCD9378_CDC_ANA_TX_CLK_CTL (WCD9378_TAMBORA_BASE+0x17) +#define WCD9378_CDC_HPH_DSM_A1_0 (WCD9378_TAMBORA_BASE+0x18) +#define WCD9378_CDC_HPH_DSM_A1_1 (WCD9378_TAMBORA_BASE+0x19) +#define WCD9378_CDC_HPH_DSM_A2_0 (WCD9378_TAMBORA_BASE+0x1a) +#define WCD9378_CDC_HPH_DSM_A2_1 (WCD9378_TAMBORA_BASE+0x1b) +#define WCD9378_CDC_HPH_DSM_A3_0 (WCD9378_TAMBORA_BASE+0x1c) +#define WCD9378_CDC_HPH_DSM_A3_1 (WCD9378_TAMBORA_BASE+0x1d) +#define WCD9378_CDC_HPH_DSM_A4_0 (WCD9378_TAMBORA_BASE+0x1e) +#define WCD9378_CDC_HPH_DSM_A4_1 (WCD9378_TAMBORA_BASE+0x1f) +#define WCD9378_CDC_HPH_DSM_A5_0 (WCD9378_TAMBORA_BASE+0x20) +#define WCD9378_CDC_HPH_DSM_A5_1 (WCD9378_TAMBORA_BASE+0x21) +#define WCD9378_CDC_HPH_DSM_A6_0 (WCD9378_TAMBORA_BASE+0x22) +#define WCD9378_CDC_HPH_DSM_A7_0 (WCD9378_TAMBORA_BASE+0x23) +#define WCD9378_CDC_HPH_DSM_C_0 (WCD9378_TAMBORA_BASE+0x24) +#define WCD9378_CDC_HPH_DSM_C_1 (WCD9378_TAMBORA_BASE+0x25) +#define WCD9378_CDC_HPH_DSM_C_2 (WCD9378_TAMBORA_BASE+0x26) +#define WCD9378_CDC_HPH_DSM_C_3 (WCD9378_TAMBORA_BASE+0x27) +#define WCD9378_CDC_HPH_DSM_R1 (WCD9378_TAMBORA_BASE+0x28) +#define WCD9378_CDC_HPH_DSM_R2 (WCD9378_TAMBORA_BASE+0x29) +#define WCD9378_CDC_HPH_DSM_R3 (WCD9378_TAMBORA_BASE+0x2a) +#define WCD9378_CDC_HPH_DSM_R4 (WCD9378_TAMBORA_BASE+0x2b) +#define WCD9378_CDC_HPH_DSM_R5 (WCD9378_TAMBORA_BASE+0x2c) +#define WCD9378_CDC_HPH_DSM_R6 (WCD9378_TAMBORA_BASE+0x2d) +#define WCD9378_CDC_HPH_DSM_R7 (WCD9378_TAMBORA_BASE+0x2e) +#define WCD9378_CDC_AUX_DSM_A1_0 (WCD9378_TAMBORA_BASE+0x2f) +#define WCD9378_CDC_AUX_DSM_A1_1 (WCD9378_TAMBORA_BASE+0x30) +#define WCD9378_CDC_AUX_DSM_A2_0 (WCD9378_TAMBORA_BASE+0x31) +#define WCD9378_CDC_AUX_DSM_A2_1 (WCD9378_TAMBORA_BASE+0x32) +#define WCD9378_CDC_AUX_DSM_A3_0 (WCD9378_TAMBORA_BASE+0x33) +#define WCD9378_CDC_AUX_DSM_A3_1 (WCD9378_TAMBORA_BASE+0x34) +#define WCD9378_CDC_AUX_DSM_A4_0 (WCD9378_TAMBORA_BASE+0x35) +#define WCD9378_CDC_AUX_DSM_A4_1 (WCD9378_TAMBORA_BASE+0x36) +#define WCD9378_CDC_AUX_DSM_A5_0 (WCD9378_TAMBORA_BASE+0x37) +#define WCD9378_CDC_AUX_DSM_A5_1 (WCD9378_TAMBORA_BASE+0x38) +#define WCD9378_CDC_AUX_DSM_A6_0 (WCD9378_TAMBORA_BASE+0x39) +#define WCD9378_CDC_AUX_DSM_A7_0 (WCD9378_TAMBORA_BASE+0x3a) +#define WCD9378_CDC_AUX_DSM_C_0 (WCD9378_TAMBORA_BASE+0x3b) +#define WCD9378_CDC_AUX_DSM_C_1 (WCD9378_TAMBORA_BASE+0x3c) +#define WCD9378_CDC_AUX_DSM_C_2 (WCD9378_TAMBORA_BASE+0x3d) +#define WCD9378_CDC_AUX_DSM_C_3 (WCD9378_TAMBORA_BASE+0x3e) +#define WCD9378_CDC_AUX_DSM_R1 (WCD9378_TAMBORA_BASE+0x3f) +#define WCD9378_CDC_AUX_DSM_R2 (WCD9378_TAMBORA_BASE+0x40) +#define WCD9378_CDC_AUX_DSM_R3 (WCD9378_TAMBORA_BASE+0x41) +#define WCD9378_CDC_AUX_DSM_R4 (WCD9378_TAMBORA_BASE+0x42) +#define WCD9378_CDC_AUX_DSM_R5 (WCD9378_TAMBORA_BASE+0x43) +#define WCD9378_CDC_AUX_DSM_R6 (WCD9378_TAMBORA_BASE+0x44) +#define WCD9378_CDC_AUX_DSM_R7 (WCD9378_TAMBORA_BASE+0x45) +#define WCD9378_CDC_HPH_GAIN_RX_0 (WCD9378_TAMBORA_BASE+0x46) +#define WCD9378_CDC_HPH_GAIN_RX_1 (WCD9378_TAMBORA_BASE+0x47) +#define WCD9378_CDC_HPH_GAIN_DSD_0 (WCD9378_TAMBORA_BASE+0x48) +#define WCD9378_CDC_HPH_GAIN_DSD_1 (WCD9378_TAMBORA_BASE+0x49) +#define WCD9378_CDC_HPH_GAIN_DSD_2 (WCD9378_TAMBORA_BASE+0x4a) +#define WCD9378_CDC_AUX_GAIN_DSD_0 (WCD9378_TAMBORA_BASE+0x4b) +#define WCD9378_CDC_AUX_GAIN_DSD_1 (WCD9378_TAMBORA_BASE+0x4c) +#define WCD9378_CDC_AUX_GAIN_DSD_2 (WCD9378_TAMBORA_BASE+0x4d) +#define WCD9378_CDC_HPH_GAIN_CTL (WCD9378_TAMBORA_BASE+0x4e) +#define WCD9378_CDC_AUX_GAIN_CTL (WCD9378_TAMBORA_BASE+0x4f) +#define WCD9378_CDC_PATH_CTL (WCD9378_TAMBORA_BASE+0x50) +#define WCD9378_CDC_SWR_CLG (WCD9378_TAMBORA_BASE+0x51) +#define WCD9378_SWR_CLG_BYP (WCD9378_TAMBORA_BASE+0x52) +#define WCD9378_CDC_TX0_CTL (WCD9378_TAMBORA_BASE+0x53) +#define WCD9378_CDC_TX1_CTL (WCD9378_TAMBORA_BASE+0x54) +#define WCD9378_CDC_TX2_CTL (WCD9378_TAMBORA_BASE+0x55) +#define WCD9378_CDC_TX_RST (WCD9378_TAMBORA_BASE+0x56) +#define WCD9378_CDC_REQ_CTL (WCD9378_TAMBORA_BASE+0x57) +#define WCD9378_CDC_RST (WCD9378_TAMBORA_BASE+0x58) +#define WCD9378_CDC_AMIC_CTL (WCD9378_TAMBORA_BASE+0x5a) +#define WCD9378_CDC_DMIC_CTL (WCD9378_TAMBORA_BASE+0x5b) +#define WCD9378_CDC_DMIC1_CTL (WCD9378_TAMBORA_BASE+0x5c) +#define WCD9378_CDC_DMIC2_CTL (WCD9378_TAMBORA_BASE+0x5d) +#define WCD9378_CDC_DMIC3_CTL (WCD9378_TAMBORA_BASE+0x5e) +#define WCD9378_EFUSE_PRG_CTL (WCD9378_TAMBORA_BASE+0x60) +#define WCD9378_EFUSE_CTL (WCD9378_TAMBORA_BASE+0x61) +#define WCD9378_CDC_DMIC_RATE_1_2 (WCD9378_TAMBORA_BASE+0x62) +#define WCD9378_CDC_DMIC_RATE_3_4 (WCD9378_TAMBORA_BASE+0x63) +#define WCD9378_PDM_WD_EN_OVRD (WCD9378_TAMBORA_BASE+0x64) +#define WCD9378_PDM_WD_CTL0 (WCD9378_TAMBORA_BASE+0x65) +#define WCD9378_PDM_WD_CTL1 (WCD9378_TAMBORA_BASE+0x66) +#define WCD9378_PDM_WD_CTL2 (WCD9378_TAMBORA_BASE+0x67) +#define WCD9378_RAMP_CTL (WCD9378_TAMBORA_BASE+0x68) +#define WCD9378_ACT_DET_CTL (WCD9378_TAMBORA_BASE+0x69) +#define WCD9378_ACT_DET_HOOKUP0 (WCD9378_TAMBORA_BASE+0x6a) +#define WCD9378_ACT_DET_HOOKUP1 (WCD9378_TAMBORA_BASE+0x6b) +#define WCD9378_ACT_DET_HOOKUP2 (WCD9378_TAMBORA_BASE+0x6c) +#define WCD9378_ACT_DET_DLY_BUF_EN (WCD9378_TAMBORA_BASE+0x6d) +#define WCD9378_INTR_MODE (WCD9378_TAMBORA_BASE+0x6e) +#define WCD9378_INTR_STATUS_0 (WCD9378_TAMBORA_BASE+0x6f) +#define WCD9378_INTR_STATUS_1 (WCD9378_TAMBORA_BASE+0x70) +#define WCD9378_INTR_STATUS_2 (WCD9378_TAMBORA_BASE+0x71) +#define WCD9378_INTR_STATUS_3 (WCD9378_TAMBORA_BASE+0x72) +#define WCD9378_INTR_MASK_0 (WCD9378_TAMBORA_BASE+0x73) +#define WCD9378_INTR_MASK_1 (WCD9378_TAMBORA_BASE+0x74) +#define WCD9378_INTR_MASK_2 (WCD9378_TAMBORA_BASE+0x75) +#define WCD9378_INTR_MASK_3 (WCD9378_TAMBORA_BASE+0x76) +#define WCD9378_INTR_SET_0 (WCD9378_TAMBORA_BASE+0x77) +#define WCD9378_INTR_SET_1 (WCD9378_TAMBORA_BASE+0x78) +#define WCD9378_INTR_SET_2 (WCD9378_TAMBORA_BASE+0x79) +#define WCD9378_INTR_SET_3 (WCD9378_TAMBORA_BASE+0x7a) +#define WCD9378_INTR_TEST_0 (WCD9378_TAMBORA_BASE+0x7b) +#define WCD9378_INTR_TEST_1 (WCD9378_TAMBORA_BASE+0x7c) +#define WCD9378_INTR_TEST_2 (WCD9378_TAMBORA_BASE+0x7d) +#define WCD9378_INTR_TEST_3 (WCD9378_TAMBORA_BASE+0x7e) +#define WCD9378_TX_MODE_DBG_EN (WCD9378_TAMBORA_BASE+0x7f) +#define WCD9378_TX_MODE_DBG_0_1 (WCD9378_TAMBORA_BASE+0x80) +#define WCD9378_TX_MODE_DBG_2_3 (WCD9378_TAMBORA_BASE+0x81) +#define WCD9378_LB_IN_SEL_CTL (WCD9378_TAMBORA_BASE+0x82) +#define WCD9378_LOOP_BACK_MODE (WCD9378_TAMBORA_BASE+0x83) +#define WCD9378_SWR_DAC_TEST (WCD9378_TAMBORA_BASE+0x84) +#define WCD9378_SWR_HM_TEST_RX_0 (WCD9378_TAMBORA_BASE+0x85) +#define WCD9378_SWR_HM_TEST_TX_0 (WCD9378_TAMBORA_BASE+0x86) +#define WCD9378_SWR_HM_TEST_RX_1 (WCD9378_TAMBORA_BASE+0x87) +#define WCD9378_SWR_HM_TEST_TX_1 (WCD9378_TAMBORA_BASE+0x88) +#define WCD9378_SWR_HM_TEST_0 (WCD9378_TAMBORA_BASE+0x8a) +#define WCD9378_PAD_CTL_SWR_0 (WCD9378_TAMBORA_BASE+0x8c) +#define WCD9378_PAD_CTL_SWR_1 (WCD9378_TAMBORA_BASE+0x8d) +#define WCD9378_I2C_CTL (WCD9378_TAMBORA_BASE+0x8e) +#define WCD9378_LEGACY_SW_MODE (WCD9378_TAMBORA_BASE+0x8f) +#define WCD9378_EFUSE_TEST_CTL_0 (WCD9378_TAMBORA_BASE+0x90) +#define WCD9378_EFUSE_TEST_CTL_1 (WCD9378_TAMBORA_BASE+0x91) +#define WCD9378_EFUSE_T_DATA_0 (WCD9378_TAMBORA_BASE+0x92) +#define WCD9378_PAD_CTL_PDM_RX0 (WCD9378_TAMBORA_BASE+0x94) +#define WCD9378_PAD_CTL_PDM_RX1 (WCD9378_TAMBORA_BASE+0x95) +#define WCD9378_PAD_CTL_PDM_TX0 (WCD9378_TAMBORA_BASE+0x96) +#define WCD9378_PAD_CTL_PDM_TX1 (WCD9378_TAMBORA_BASE+0x97) +#define WCD9378_PAD_INP_DIS_0 (WCD9378_TAMBORA_BASE+0x99) +#define WCD9378_DRIVE_STRENGTH_0 (WCD9378_TAMBORA_BASE+0x9b) +#define WCD9378_DRIVE_STRENGTH_1 (WCD9378_TAMBORA_BASE+0x9c) +#define WCD9378_RX_DATA_EDGE_CTL (WCD9378_TAMBORA_BASE+0x9e) +#define WCD9378_TX_DATA_EDGE_CTL (WCD9378_TAMBORA_BASE+0x9f) +#define WCD9378_GPIO_MODE (WCD9378_TAMBORA_BASE+0xa0) +#define WCD9378_PIN_CTL_OE (WCD9378_TAMBORA_BASE+0xa1) +#define WCD9378_PIN_CTL_DATA_0 (WCD9378_TAMBORA_BASE+0xa2) +#define WCD9378_PIN_STATUS_0 (WCD9378_TAMBORA_BASE+0xa4) +#define WCD9378_DIG_DEBUG_CTL (WCD9378_TAMBORA_BASE+0xa6) +#define WCD9378_DIG_DEBUG_EN (WCD9378_TAMBORA_BASE+0xa7) +#define WCD9378_ANA_CSR_DBG_ADD (WCD9378_TAMBORA_BASE+0xa8) +#define WCD9378_ANA_CSR_DBG_CTL (WCD9378_TAMBORA_BASE+0xa9) +#define WCD9378_SSP_DBG (WCD9378_TAMBORA_BASE+0xaa) +#define WCD9378_MODE_STATUS_0 (WCD9378_TAMBORA_BASE+0xab) +#define WCD9378_MODE_STATUS_1 (WCD9378_TAMBORA_BASE+0xac) +#define WCD9378_SPARE_0 (WCD9378_TAMBORA_BASE+0xad) +#define WCD9378_SPARE_1 (WCD9378_TAMBORA_BASE+0xae) +#define WCD9378_SPARE_2 (WCD9378_TAMBORA_BASE+0xaf) +#define WCD9378_EFUSE_REG_0 (WCD9378_TAMBORA_BASE+0xb0) +#define WCD9378_EFUSE_REG_1 (WCD9378_TAMBORA_BASE+0xb1) +#define WCD9378_EFUSE_REG_2 (WCD9378_TAMBORA_BASE+0xb2) +#define WCD9378_EFUSE_REG_3 (WCD9378_TAMBORA_BASE+0xb3) +#define WCD9378_EFUSE_REG_4 (WCD9378_TAMBORA_BASE+0xb4) +#define WCD9378_EFUSE_REG_5 (WCD9378_TAMBORA_BASE+0xb5) +#define WCD9378_EFUSE_REG_6 (WCD9378_TAMBORA_BASE+0xb6) +#define WCD9378_EFUSE_REG_7 (WCD9378_TAMBORA_BASE+0xb7) +#define WCD9378_EFUSE_REG_8 (WCD9378_TAMBORA_BASE+0xb8) +#define WCD9378_EFUSE_REG_9 (WCD9378_TAMBORA_BASE+0xb9) +#define WCD9378_EFUSE_REG_10 (WCD9378_TAMBORA_BASE+0xba) +#define WCD9378_EFUSE_REG_11 (WCD9378_TAMBORA_BASE+0xbb) +#define WCD9378_EFUSE_REG_12 (WCD9378_TAMBORA_BASE+0xbc) +#define WCD9378_EFUSE_REG_13 (WCD9378_TAMBORA_BASE+0xbd) +#define WCD9378_EFUSE_REG_14 (WCD9378_TAMBORA_BASE+0xbe) +#define WCD9378_EFUSE_REG_15 (WCD9378_TAMBORA_BASE+0xbf) +#define WCD9378_EFUSE_REG_16 (WCD9378_TAMBORA_BASE+0xc0) +#define WCD9378_EFUSE_REG_17 (WCD9378_TAMBORA_BASE+0xc1) +#define WCD9378_EFUSE_REG_18 (WCD9378_TAMBORA_BASE+0xc2) +#define WCD9378_EFUSE_REG_19 (WCD9378_TAMBORA_BASE+0xc3) +#define WCD9378_EFUSE_REG_20 (WCD9378_TAMBORA_BASE+0xc4) +#define WCD9378_EFUSE_REG_21 (WCD9378_TAMBORA_BASE+0xc5) +#define WCD9378_EFUSE_REG_22 (WCD9378_TAMBORA_BASE+0xc6) +#define WCD9378_EFUSE_REG_23 (WCD9378_TAMBORA_BASE+0xc7) +#define WCD9378_EFUSE_REG_24 (WCD9378_TAMBORA_BASE+0xc8) +#define WCD9378_EFUSE_REG_25 (WCD9378_TAMBORA_BASE+0xc9) +#define WCD9378_EFUSE_REG_26 (WCD9378_TAMBORA_BASE+0xca) +#define WCD9378_EFUSE_REG_27 (WCD9378_TAMBORA_BASE+0xcb) +#define WCD9378_EFUSE_REG_28 (WCD9378_TAMBORA_BASE+0xcc) +#define WCD9378_EFUSE_REG_29 (WCD9378_TAMBORA_BASE+0xcd) +#define WCD9378_EFUSE_REG_30 (WCD9378_TAMBORA_BASE+0xce) +#define WCD9378_EFUSE_REG_31 (WCD9378_TAMBORA_BASE+0xcf) +#define WCD9378_TX_REQ_FB_CTL_2 (WCD9378_TAMBORA_BASE+0xd2) +#define WCD9378_TX_REQ_FB_CTL_3 (WCD9378_TAMBORA_BASE+0xd3) +#define WCD9378_TX_REQ_FB_CTL_4 (WCD9378_TAMBORA_BASE+0xd4) +#define WCD9378_DEM_BYPASS_DATA0 (WCD9378_TAMBORA_BASE+0xd5) +#define WCD9378_DEM_BYPASS_DATA1 (WCD9378_TAMBORA_BASE+0xd6) +#define WCD9378_DEM_BYPASS_DATA2 (WCD9378_TAMBORA_BASE+0xd7) +#define WCD9378_DEM_BYPASS_DATA3 (WCD9378_TAMBORA_BASE+0xd8) +#define WCD9378_RX0_PCM_RAMP_STEP (WCD9378_TAMBORA_BASE+0xd9) +#define WCD9378_RX0_DSD_RAMP_STEP (WCD9378_TAMBORA_BASE+0xda) +#define WCD9378_RX1_PCM_RAMP_STEP (WCD9378_TAMBORA_BASE+0xdb) +#define WCD9378_RX1_DSD_RAMP_STEP (WCD9378_TAMBORA_BASE+0xdc) +#define WCD9378_RX2_RAMP_STEP (WCD9378_TAMBORA_BASE+0xdd) +#define WCD9378_PLATFORM_CTL (WCD9378_TAMBORA_BASE+0xf0) +#define WCD9378_CLK_DIV_CFG (WCD9378_TAMBORA_BASE+0xf1) +#define WCD9378_DRE_DLY_VAL (WCD9378_TAMBORA_BASE+0xf2) + +#define WCD9378_SEQR_BASE (WCD9378_BASE+0x180501) +#define WCD9378_SYS_USAGE_CTRL (WCD9378_SEQR_BASE+0x01) +#define WCD9378_SURGE_CTL (WCD9378_SEQR_BASE+0x02) +#define WCD9378_SEQ_CTL (WCD9378_SEQR_BASE+0x03) +#define WCD9378_HPH_UP_T0 (WCD9378_SEQR_BASE+0x10) +#define WCD9378_HPH_UP_T1 (WCD9378_SEQR_BASE+0x11) +#define WCD9378_HPH_UP_T2 (WCD9378_SEQR_BASE+0x12) +#define WCD9378_HPH_UP_T3 (WCD9378_SEQR_BASE+0x13) +#define WCD9378_HPH_UP_T4 (WCD9378_SEQR_BASE+0x14) +#define WCD9378_HPH_UP_T5 (WCD9378_SEQR_BASE+0x15) +#define WCD9378_HPH_UP_T6 (WCD9378_SEQR_BASE+0x16) +#define WCD9378_HPH_UP_T7 (WCD9378_SEQR_BASE+0x17) +#define WCD9378_HPH_UP_T8 (WCD9378_SEQR_BASE+0x18) +#define WCD9378_HPH_UP_T9 (WCD9378_SEQR_BASE+0x19) +#define WCD9378_HPH_UP_T10 (WCD9378_SEQR_BASE+0x1a) +#define WCD9378_HPH_DN_T0 (WCD9378_SEQR_BASE+0x1b) +#define WCD9378_HPH_DN_T1 (WCD9378_SEQR_BASE+0x1c) +#define WCD9378_HPH_DN_T2 (WCD9378_SEQR_BASE+0x1d) +#define WCD9378_HPH_DN_T3 (WCD9378_SEQR_BASE+0x1e) +#define WCD9378_HPH_DN_T4 (WCD9378_SEQR_BASE+0x1f) +#define WCD9378_HPH_DN_T5 (WCD9378_SEQR_BASE+0x20) +#define WCD9378_HPH_DN_T6 (WCD9378_SEQR_BASE+0x21) +#define WCD9378_HPH_DN_T7 (WCD9378_SEQR_BASE+0x22) +#define WCD9378_HPH_DN_T8 (WCD9378_SEQR_BASE+0x23) +#define WCD9378_HPH_DN_T9 (WCD9378_SEQR_BASE+0x24) +#define WCD9378_HPH_DN_T10 (WCD9378_SEQR_BASE+0x25) +#define WCD9378_HPH_UP_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x26) +#define WCD9378_HPH_UP_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x27) +#define WCD9378_HPH_UP_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x28) +#define WCD9378_HPH_UP_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x29) +#define WCD9378_HPH_UP_STAGE_LOC_4 (WCD9378_SEQR_BASE+0x2a) +#define WCD9378_HPH_UP_STAGE_LOC_5 (WCD9378_SEQR_BASE+0x2b) +#define WCD9378_HPH_UP_STAGE_LOC_6 (WCD9378_SEQR_BASE+0x2c) +#define WCD9378_HPH_UP_STAGE_LOC_7 (WCD9378_SEQR_BASE+0x2d) +#define WCD9378_HPH_UP_STAGE_LOC_8 (WCD9378_SEQR_BASE+0x2e) +#define WCD9378_HPH_UP_STAGE_LOC_9 (WCD9378_SEQR_BASE+0x2f) +#define WCD9378_HPH_UP_STAGE_LOC_10 (WCD9378_SEQR_BASE+0x30) +#define WCD9378_HPH_DN_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x31) +#define WCD9378_HPH_DN_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x32) +#define WCD9378_HPH_DN_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x33) +#define WCD9378_HPH_DN_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x34) +#define WCD9378_HPH_DN_STAGE_LOC_4 (WCD9378_SEQR_BASE+0x35) +#define WCD9378_HPH_DN_STAGE_LOC_5 (WCD9378_SEQR_BASE+0x36) +#define WCD9378_HPH_DN_STAGE_LOC_6 (WCD9378_SEQR_BASE+0x37) +#define WCD9378_HPH_DN_STAGE_LOC_7 (WCD9378_SEQR_BASE+0x38) +#define WCD9378_HPH_DN_STAGE_LOC_8 (WCD9378_SEQR_BASE+0x39) +#define WCD9378_HPH_DN_STAGE_LOC_9 (WCD9378_SEQR_BASE+0x3a) +#define WCD9378_HPH_DN_STAGE_LOC_10 (WCD9378_SEQR_BASE+0x3b) +#define WCD9378_SA_UP_T0 (WCD9378_SEQR_BASE+0x40) +#define WCD9378_SA_UP_T1 (WCD9378_SEQR_BASE+0x41) +#define WCD9378_SA_UP_T2 (WCD9378_SEQR_BASE+0x42) +#define WCD9378_SA_UP_T3 (WCD9378_SEQR_BASE+0x43) +#define WCD9378_SA_UP_T4 (WCD9378_SEQR_BASE+0x44) +#define WCD9378_SA_UP_T5 (WCD9378_SEQR_BASE+0x45) +#define WCD9378_SA_UP_T6 (WCD9378_SEQR_BASE+0x46) +#define WCD9378_SA_UP_T7 (WCD9378_SEQR_BASE+0x47) +#define WCD9378_SA_DN_T0 (WCD9378_SEQR_BASE+0x48) +#define WCD9378_SA_DN_T1 (WCD9378_SEQR_BASE+0x49) +#define WCD9378_SA_DN_T2 (WCD9378_SEQR_BASE+0x4a) +#define WCD9378_SA_DN_T3 (WCD9378_SEQR_BASE+0x4b) +#define WCD9378_SA_DN_T4 (WCD9378_SEQR_BASE+0x4c) +#define WCD9378_SA_DN_T5 (WCD9378_SEQR_BASE+0x4d) +#define WCD9378_SA_DN_T6 (WCD9378_SEQR_BASE+0x4e) +#define WCD9378_SA_DN_T7 (WCD9378_SEQR_BASE+0x4f) +#define WCD9378_SA_UP_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x50) +#define WCD9378_SA_UP_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x51) +#define WCD9378_SA_UP_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x52) +#define WCD9378_SA_UP_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x53) +#define WCD9378_SA_UP_STAGE_LOC_4 (WCD9378_SEQR_BASE+0x54) +#define WCD9378_SA_UP_STAGE_LOC_5 (WCD9378_SEQR_BASE+0x55) +#define WCD9378_SA_UP_STAGE_LOC_6 (WCD9378_SEQR_BASE+0x56) +#define WCD9378_SA_UP_STAGE_LOC_7 (WCD9378_SEQR_BASE+0x57) +#define WCD9378_SA_DN_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x58) +#define WCD9378_SA_DN_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x59) +#define WCD9378_SA_DN_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x5a) +#define WCD9378_SA_DN_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x5b) +#define WCD9378_SA_DN_STAGE_LOC_4 (WCD9378_SEQR_BASE+0x5c) +#define WCD9378_SA_DN_STAGE_LOC_5 (WCD9378_SEQR_BASE+0x5d) +#define WCD9378_SA_DN_STAGE_LOC_6 (WCD9378_SEQR_BASE+0x5e) +#define WCD9378_SA_DN_STAGE_LOC_7 (WCD9378_SEQR_BASE+0x5f) +#define WCD9378_TX0_UP_T0 (WCD9378_SEQR_BASE+0x60) +#define WCD9378_TX0_UP_T1 (WCD9378_SEQR_BASE+0x61) +#define WCD9378_TX0_UP_T2 (WCD9378_SEQR_BASE+0x62) +#define WCD9378_TX0_UP_T3 (WCD9378_SEQR_BASE+0x63) +#define WCD9378_TX0_DN_T0 (WCD9378_SEQR_BASE+0x64) +#define WCD9378_TX0_DN_T1 (WCD9378_SEQR_BASE+0x65) +#define WCD9378_TX0_DN_T2 (WCD9378_SEQR_BASE+0x66) +#define WCD9378_TX0_DN_T3 (WCD9378_SEQR_BASE+0x67) +#define WCD9378_TX0_UP_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x68) +#define WCD9378_TX0_UP_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x69) +#define WCD9378_TX0_UP_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x6a) +#define WCD9378_TX0_UP_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x6b) +#define WCD9378_TX0_DN_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x6c) +#define WCD9378_TX0_DN_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x6d) +#define WCD9378_TX0_DN_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x6e) +#define WCD9378_TX0_DN_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x6f) +#define WCD9378_TX1_UP_T0 (WCD9378_SEQR_BASE+0x70) +#define WCD9378_TX1_UP_T1 (WCD9378_SEQR_BASE+0x71) +#define WCD9378_TX1_UP_T2 (WCD9378_SEQR_BASE+0x72) +#define WCD9378_TX1_UP_T3 (WCD9378_SEQR_BASE+0x73) +#define WCD9378_TX1_DN_T0 (WCD9378_SEQR_BASE+0x74) +#define WCD9378_TX1_DN_T1 (WCD9378_SEQR_BASE+0x75) +#define WCD9378_TX1_DN_T2 (WCD9378_SEQR_BASE+0x76) +#define WCD9378_TX1_DN_T3 (WCD9378_SEQR_BASE+0x77) +#define WCD9378_TX1_UP_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x78) +#define WCD9378_TX1_UP_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x79) +#define WCD9378_TX1_UP_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x7a) +#define WCD9378_TX1_UP_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x7b) +#define WCD9378_TX1_DN_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x7c) +#define WCD9378_TX1_DN_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x7d) +#define WCD9378_TX1_DN_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x7e) +#define WCD9378_TX1_DN_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x7f) +#define WCD9378_TX2_UP_T0 (WCD9378_SEQR_BASE+0x80) +#define WCD9378_TX2_UP_T1 (WCD9378_SEQR_BASE+0x81) +#define WCD9378_TX2_UP_T2 (WCD9378_SEQR_BASE+0x82) +#define WCD9378_TX2_UP_T3 (WCD9378_SEQR_BASE+0x83) +#define WCD9378_TX2_DN_T0 (WCD9378_SEQR_BASE+0x84) +#define WCD9378_TX2_DN_T1 (WCD9378_SEQR_BASE+0x85) +#define WCD9378_TX2_DN_T2 (WCD9378_SEQR_BASE+0x86) +#define WCD9378_TX2_DN_T3 (WCD9378_SEQR_BASE+0x87) +#define WCD9378_TX2_UP_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x88) +#define WCD9378_TX2_UP_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x89) +#define WCD9378_TX2_UP_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x8a) +#define WCD9378_TX2_UP_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x8b) +#define WCD9378_TX2_DN_STAGE_LOC_0 (WCD9378_SEQR_BASE+0x8c) +#define WCD9378_TX2_DN_STAGE_LOC_1 (WCD9378_SEQR_BASE+0x8d) +#define WCD9378_TX2_DN_STAGE_LOC_2 (WCD9378_SEQR_BASE+0x8e) +#define WCD9378_TX2_DN_STAGE_LOC_3 (WCD9378_SEQR_BASE+0x8f) +#define WCD9378_SEQ_HPH_STAT (WCD9378_SEQR_BASE+0x90) +#define WCD9378_SEQ_SA_STAT (WCD9378_SEQR_BASE+0x91) +#define WCD9378_SEQ_TX0_STAT (WCD9378_SEQR_BASE+0x92) +#define WCD9378_SEQ_TX1_STAT (WCD9378_SEQR_BASE+0x93) +#define WCD9378_SEQ_TX2_STAT (WCD9378_SEQR_BASE+0x94) +#define WCD9378_MICB_REMAP_TABLE_VAL_0 (WCD9378_SEQR_BASE+0xa0) +#define WCD9378_MICB_REMAP_TABLE_VAL_1 (WCD9378_SEQR_BASE+0xa1) +#define WCD9378_MICB_REMAP_TABLE_VAL_2 (WCD9378_SEQR_BASE+0xa2) +#define WCD9378_MICB_REMAP_TABLE_VAL_3 (WCD9378_SEQR_BASE+0xa3) +#define WCD9378_MICB_REMAP_TABLE_VAL_4 (WCD9378_SEQR_BASE+0xa4) +#define WCD9378_MICB_REMAP_TABLE_VAL_5 (WCD9378_SEQR_BASE+0xa5) +#define WCD9378_MICB_REMAP_TABLE_VAL_6 (WCD9378_SEQR_BASE+0xa6) +#define WCD9378_MICB_REMAP_TABLE_VAL_7 (WCD9378_SEQR_BASE+0xa7) +#define WCD9378_MICB_REMAP_TABLE_VAL_8 (WCD9378_SEQR_BASE+0xa8) +#define WCD9378_MICB_REMAP_TABLE_VAL_9 (WCD9378_SEQR_BASE+0xa9) +#define WCD9378_MICB_REMAP_TABLE_VAL_10 (WCD9378_SEQR_BASE+0xaa) +#define WCD9378_MICB_REMAP_TABLE_VAL_11 (WCD9378_SEQR_BASE+0xab) +#define WCD9378_MICB_REMAP_TABLE_VAL_12 (WCD9378_SEQR_BASE+0xac) +#define WCD9378_MICB_REMAP_TABLE_VAL_13 (WCD9378_SEQR_BASE+0xad) +#define WCD9378_MICB_REMAP_TABLE_VAL_14 (WCD9378_SEQR_BASE+0xae) +#define WCD9378_MICB_REMAP_TABLE_VAL_15 (WCD9378_SEQR_BASE+0xaf) +#define WCD9378_SM0_MB_SEL (WCD9378_SEQR_BASE+0xb0) +#define WCD9378_SM1_MB_SEL (WCD9378_SEQR_BASE+0xb1) +#define WCD9378_SM2_MB_SEL (WCD9378_SEQR_BASE+0xb2) +#define WCD9378_MB_PULLUP_EN (WCD9378_SEQR_BASE+0xb3) +#define WCD9378_BYP_EN_CTL0 (WCD9378_SEQR_BASE+0xc0) +#define WCD9378_BYP_EN_CTL1 (WCD9378_SEQR_BASE+0xc1) +#define WCD9378_BYP_EN_CTL2 (WCD9378_SEQR_BASE+0xc2) +#define WCD9378_SEQ_OVRRIDE_CTL0 (WCD9378_SEQR_BASE+0xc3) +#define WCD9378_SEQ_OVRRIDE_CTL1 (WCD9378_SEQR_BASE+0xc4) +#define WCD9378_SEQ_OVRRIDE_CTL2 (WCD9378_SEQR_BASE+0xc5) +#define WCD9378_HPH_SEQ_OVRRIDE_CTL0 (WCD9378_SEQR_BASE+0xc7) +#define WCD9378_HPH_SEQ_OVRRIDE_CTL1 (WCD9378_SEQR_BASE+0xc8) +#define WCD9378_SA_SEQ_OVRRIDE_CTL (WCD9378_SEQR_BASE+0xc9) +#define WCD9378_TX0_SEQ_OVRRIDE_CTL (WCD9378_SEQR_BASE+0xca) +#define WCD9378_TX1_SEQ_OVRRIDE_CTL (WCD9378_SEQR_BASE+0xcb) +#define WCD9378_TX2_SEQ_OVRRIDE_CTL (WCD9378_SEQR_BASE+0xcc) +#define WCD9378_FORCE_CTL (WCD9378_SEQR_BASE+0xcd) + +#define WCD9378_MBHC_BASE (WCD9378_BASE+0x180601) +#define WCD9378_DEVICE_DET (WCD9378_MBHC_BASE+0x01) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_0 (WCD9378_MBHC_BASE+0x10) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_0 (WCD9378_MBHC_BASE+0x11) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_0 (WCD9378_MBHC_BASE+0x12) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_0 (WCD9378_MBHC_BASE+0x13) +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_0 (WCD9378_MBHC_BASE+0x14) +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_0 (WCD9378_MBHC_BASE+0x15) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_1 (WCD9378_MBHC_BASE+0x20) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_1 (WCD9378_MBHC_BASE+0x21) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_1 (WCD9378_MBHC_BASE+0x22) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_1 (WCD9378_MBHC_BASE+0x23) +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_1 (WCD9378_MBHC_BASE+0x24) +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_1 (WCD9378_MBHC_BASE+0x25) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_2 (WCD9378_MBHC_BASE+0x30) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_2 (WCD9378_MBHC_BASE+0x31) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_2 (WCD9378_MBHC_BASE+0x32) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_2 (WCD9378_MBHC_BASE+0x33) +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_2 (WCD9378_MBHC_BASE+0x34) +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_2 (WCD9378_MBHC_BASE+0x35) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_3 (WCD9378_MBHC_BASE+0x40) +#define WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_3 (WCD9378_MBHC_BASE+0x41) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_3 (WCD9378_MBHC_BASE+0x42) +#define WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_3 (WCD9378_MBHC_BASE+0x43) +#define WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_3 (WCD9378_MBHC_BASE+0x44) +#define WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_3 (WCD9378_MBHC_BASE+0x45) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_0 (WCD9378_MBHC_BASE+0x50) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_0 (WCD9378_MBHC_BASE+0x51) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_0 (WCD9378_MBHC_BASE+0x52) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_0 (WCD9378_MBHC_BASE+0x53) +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_0 (WCD9378_MBHC_BASE+0x54) +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_0 (WCD9378_MBHC_BASE+0x55) +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_0 (WCD9378_MBHC_BASE+0x56) +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_0 (WCD9378_MBHC_BASE+0x57) +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_0 (WCD9378_MBHC_BASE+0x58) +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_0 (WCD9378_MBHC_BASE+0x59) +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_0 (WCD9378_MBHC_BASE+0x5b) +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_0 (WCD9378_MBHC_BASE+0x5c) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_1 (WCD9378_MBHC_BASE+0x60) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_1 (WCD9378_MBHC_BASE+0x61) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_1 (WCD9378_MBHC_BASE+0x62) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_1 (WCD9378_MBHC_BASE+0x63) +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_1 (WCD9378_MBHC_BASE+0x64) +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_1 (WCD9378_MBHC_BASE+0x65) +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_1 (WCD9378_MBHC_BASE+0x66) +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_1 (WCD9378_MBHC_BASE+0x67) +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_1 (WCD9378_MBHC_BASE+0x68) +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_1 (WCD9378_MBHC_BASE+0x69) +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_1 (WCD9378_MBHC_BASE+0x6b) +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_1 (WCD9378_MBHC_BASE+0x6c) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_2 (WCD9378_MBHC_BASE+0x70) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_2 (WCD9378_MBHC_BASE+0x71) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_2 (WCD9378_MBHC_BASE+0x72) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_2 (WCD9378_MBHC_BASE+0x73) +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_2 (WCD9378_MBHC_BASE+0x74) +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_2 (WCD9378_MBHC_BASE+0x75) +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_2 (WCD9378_MBHC_BASE+0x76) +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_2 (WCD9378_MBHC_BASE+0x77) +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_2 (WCD9378_MBHC_BASE+0x78) +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_2 (WCD9378_MBHC_BASE+0x79) +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_2 (WCD9378_MBHC_BASE+0x7b) +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_2 (WCD9378_MBHC_BASE+0x7c) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_3 (WCD9378_MBHC_BASE+0x80) +#define WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_3 (WCD9378_MBHC_BASE+0x81) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_3 (WCD9378_MBHC_BASE+0x82) +#define WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_3 (WCD9378_MBHC_BASE+0x83) +#define WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_3 (WCD9378_MBHC_BASE+0x84) +#define WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_3 (WCD9378_MBHC_BASE+0x85) +#define WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_3 (WCD9378_MBHC_BASE+0x86) +#define WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_3 (WCD9378_MBHC_BASE+0x87) +#define WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_3 (WCD9378_MBHC_BASE+0x88) +#define WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_3 (WCD9378_MBHC_BASE+0x89) +#define WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_3 (WCD9378_MBHC_BASE+0x8b) +#define WCD9378_TYPE1_WRAP_RTC_OOC_SEL_3 (WCD9378_MBHC_BASE+0x8c) +#define WCD9378_SDCA_MESSAGE_GATE (WCD9378_MBHC_BASE+0x8d) +#define WCD9378_MBHC_DATA_IN_EDGE (WCD9378_MBHC_BASE+0x90) +#define WCD9378_MBHC_RESET (WCD9378_MBHC_BASE+0x91) +#define WCD9378_MBHC_DEBUG (WCD9378_MBHC_BASE+0x92) +#define WCD9378_MBHC_DEBUG_UMP_0 (WCD9378_MBHC_BASE+0x93) +#define WCD9378_MBHC_DEBUG_UMP_1 (WCD9378_MBHC_BASE+0x94) +#define WCD9378_MBHC_DEBUG_UMP_2 (WCD9378_MBHC_BASE+0x95) + +#define WCD9378_HID_BASE (WCD9378_BASE+0x400001) +#define WCD9378_HID_FUNC_EXT_ID_0 (WCD9378_HID_BASE+0x48) +#define WCD9378_HID_FUNC_EXT_ID_1 (WCD9378_HID_BASE+0x49) +#define WCD9378_HID_FUNC_EXT_VER (WCD9378_HID_BASE+0x50) +#define WCD9378_HID_FUNC_STAT (WCD9378_HID_BASE+0x80000) +#define WCD9378_HID_CUR_OWNER (WCD9378_HID_BASE+0x80080) +#define WCD9378_HID_MSG_OFFSET (WCD9378_HID_BASE+0x80090) +#define WCD9378_HID_MSG_LENGTH (WCD9378_HID_BASE+0x80098) +#define WCD9378_HID_DEV_MANU_ID_0 (WCD9378_HID_BASE+0x100060) +#define WCD9378_HID_DEV_MANU_ID_1 (WCD9378_HID_BASE+0x100061) +#define WCD9378_HID_DEV_PART_ID_0 (WCD9378_HID_BASE+0x100068) +#define WCD9378_HID_DEV_PART_ID_1 (WCD9378_HID_BASE+0x100069) +#define WCD9378_HID_DEV_VER (WCD9378_HID_BASE+0x100070) + +#define WCD9378_SMP_AMP_BASE (WCD9378_BASE+0x800001) +#define WCD9378_SMP_AMP_FUNC_EXT_ID_0 (WCD9378_SMP_AMP_BASE+0x48) +#define WCD9378_SMP_AMP_FUNC_EXT_ID_1 (WCD9378_SMP_AMP_BASE+0x49) +#define WCD9378_SMP_AMP_FUNC_EXT_VER (WCD9378_SMP_AMP_BASE+0x50) +#define WCD9378_XU22_BYP (WCD9378_SMP_AMP_BASE+0x188) +#define WCD9378_PDE22_REQ_PS (WCD9378_SMP_AMP_BASE+0x208) +#define WCD9378_FU23_MUTE (WCD9378_SMP_AMP_BASE+0x388) +#define WCD9378_PDE23_REQ_PS (WCD9378_SMP_AMP_BASE+0x408) +#define WCD9378_SMP_AMP_FUNC_STAT (WCD9378_SMP_AMP_BASE+0x80000) +#define WCD9378_FUNC_ACT (WCD9378_SMP_AMP_BASE+0x80008) +#define WCD9378_PDE22_ACT_PS (WCD9378_SMP_AMP_BASE+0x80200) +#define WCD9378_SAPU29_PROT_MODE (WCD9378_SMP_AMP_BASE+0x80280) +#define WCD9378_SAPU29_PROT_STAT (WCD9378_SMP_AMP_BASE+0x80288) +#define WCD9378_PDE23_ACT_PS (WCD9378_SMP_AMP_BASE+0x80400) +#define WCD9378_SMP_AMP_DEV_MANU_ID_0 (WCD9378_SMP_AMP_BASE+0x100060) +#define WCD9378_SMP_AMP_DEV_MANU_ID_1 (WCD9378_SMP_AMP_BASE+0x100061) +#define WCD9378_SMP_AMP_DEV_PART_ID_0 (WCD9378_SMP_AMP_BASE+0x100068) +#define WCD9378_SMP_AMP_DEV_PART_ID_1 (WCD9378_SMP_AMP_BASE+0x100069) +#define WCD9378_SMP_AMP_DEV_VER (WCD9378_SMP_AMP_BASE+0x100070) + +#define WCD9378_SMP_JACK_BASE (WCD9378_BASE+0xc00001) +#define WCD9378_CMT_GRP_MASK (WCD9378_SMP_JACK_BASE+0x08) +#define WCD9378_SMP_JACK_FUNC_EXT_ID_0 (WCD9378_SMP_JACK_BASE+0x48) +#define WCD9378_SMP_JACK_FUNC_EXT_ID_1 (WCD9378_SMP_JACK_BASE+0x49) +#define WCD9378_SMP_JACK_FUNC_EXT_VER (WCD9378_SMP_JACK_BASE+0x50) +#define WCD9378_IT41_USAGE (WCD9378_SMP_JACK_BASE+0xa0) +#define WCD9378_XU42_BYP (WCD9378_SMP_JACK_BASE+0x208) +#define WCD9378_PDE42_REQ_PS (WCD9378_SMP_JACK_BASE+0x288) +#define WCD9378_FU42_MUTE_CH1 (WCD9378_SMP_JACK_BASE+0x309) +#define WCD9378_FU42_MUTE_CH2 (WCD9378_SMP_JACK_BASE+0x30a) +#define WCD9378_FU42_CH_VOL_CH1 (WCD9378_SMP_JACK_BASE+0x311) +#define WCD9378_FU42_CH_VOL_CH2 (WCD9378_SMP_JACK_BASE+0x312) +#define WCD9378_SU43_SELECTOR (WCD9378_SMP_JACK_BASE+0x388) +#define WCD9378_SU45_SELECTOR (WCD9378_SMP_JACK_BASE+0x408) +#define WCD9378_PDE47_REQ_PS (WCD9378_SMP_JACK_BASE+0x488) +#define WCD9378_GE35_SEL_MODE (WCD9378_SMP_JACK_BASE+0x608) +#define WCD9378_GE35_DET_MODE (WCD9378_SMP_JACK_BASE+0x610) +#define WCD9378_IT31_MICB (WCD9378_SMP_JACK_BASE+0x798) +#define WCD9378_IT31_USAGE (WCD9378_SMP_JACK_BASE+0x7a0) +#define WCD9378_PDE34_REQ_PS (WCD9378_SMP_JACK_BASE+0x808) +#define WCD9378_SU45_TX_SELECTOR (WCD9378_SMP_JACK_BASE+0x908) +#define WCD9378_XU36_BYP (WCD9378_SMP_JACK_BASE+0x988) +#define WCD9378_PDE36_REQ_PS (WCD9378_SMP_JACK_BASE+0xa08) +#define WCD9378_OT36_USAGE (WCD9378_SMP_JACK_BASE+0xb20) +#define WCD9378_SMP_JACK_FUNC_STAT (WCD9378_SMP_JACK_BASE+0x80000) +#define WCD9378_SMP_JACK_FUNC_ACT (WCD9378_SMP_JACK_BASE+0x80008) +#define WCD9378_PDE42_ACT_PS (WCD9378_SMP_JACK_BASE+0x80280) +#define WCD9378_PDE47_ACT_PS (WCD9378_SMP_JACK_BASE+0x80480) +#define WCD9378_PDE34_ACT_PS (WCD9378_SMP_JACK_BASE+0x80800) +#define WCD9378_PDE36_ACT_PS (WCD9378_SMP_JACK_BASE+0x80a00) +#define WCD9378_SMP_JACK_DEV_MANU_ID_0 (WCD9378_SMP_JACK_BASE+0x100060) +#define WCD9378_SMP_JACK_DEV_MANU_ID_1 (WCD9378_SMP_JACK_BASE+0x100061) +#define WCD9378_SMP_JACK_DEV_PART_ID_0 (WCD9378_SMP_JACK_BASE+0x100068) +#define WCD9378_SMP_JACK_DEV_PART_ID_1 (WCD9378_SMP_JACK_BASE+0x100069) +#define WCD9378_SMP_JACK_DEV_VER (WCD9378_SMP_JACK_BASE+0x100070) + +#define WCD9378_SMP_MIC_CTRL0_BASE (WCD9378_BASE+0x1000001) +#define WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_0 (WCD9378_SMP_MIC_CTRL0_BASE+0x48) +#define WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_1 (WCD9378_SMP_MIC_CTRL0_BASE+0x49) +#define WCD9378_SMP_MIC_CTRL0_FUNC_EXT_VER (WCD9378_SMP_MIC_CTRL0_BASE+0x50) +#define WCD9378_IT11_MICB (WCD9378_SMP_MIC_CTRL0_BASE+0x98) +#define WCD9378_IT11_USAGE (WCD9378_SMP_MIC_CTRL0_BASE+0xa0) +#define WCD9378_PDE11_REQ_PS (WCD9378_SMP_MIC_CTRL0_BASE+0x108) +#define WCD9378_OT10_USAGE (WCD9378_SMP_MIC_CTRL0_BASE+0x3a0) +#define WCD9378_SMP_MIC_CTRL0_FUNC_STAT (WCD9378_SMP_MIC_CTRL0_BASE+0x80000) +#define WCD9378_SMP_MIC_CTRL0_FUNC_ACT (WCD9378_SMP_MIC_CTRL0_BASE+0x80008) +#define WCD9378_PDE11_ACT_PS (WCD9378_SMP_MIC_CTRL0_BASE+0x80100) +#define WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_0 (WCD9378_SMP_MIC_CTRL0_BASE+0x100060) +#define WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_1 (WCD9378_SMP_MIC_CTRL0_BASE+0x100061) +#define WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_0 (WCD9378_SMP_MIC_CTRL0_BASE+0x100068) +#define WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_1 (WCD9378_SMP_MIC_CTRL0_BASE+0x100069) +#define WCD9378_SMP_MIC_CTRL0_DEV_VER (WCD9378_SMP_MIC_CTRL0_BASE+0x100070) + +#define WCD9378_SMP_MIC_CTRL1_BASE (WCD9378_BASE+0x1400001) +#define WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_0 (WCD9378_SMP_MIC_CTRL1_BASE+0x48) +#define WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_1 (WCD9378_SMP_MIC_CTRL1_BASE+0x49) +#define WCD9378_SMP_MIC_CTRL1_FUNC_EXT_VER (WCD9378_SMP_MIC_CTRL1_BASE+0x50) +#define WCD9378_SMP_MIC_CTRL1_IT11_MICB (WCD9378_SMP_MIC_CTRL1_BASE+0x98) +#define WCD9378_SMP_MIC_CTRL1_IT11_USAGE (WCD9378_SMP_MIC_CTRL1_BASE+0xa0) +#define WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS (WCD9378_SMP_MIC_CTRL1_BASE+0x108) +#define WCD9378_SMP_MIC_CTRL1_OT10_USAGE (WCD9378_SMP_MIC_CTRL1_BASE+0x3a0) +#define WCD9378_SMP_MIC_CTRL1_FUNC_STAT (WCD9378_SMP_MIC_CTRL1_BASE+0x80000) +#define WCD9378_SMP_MIC_CTRL1_FUNC_ACT (WCD9378_SMP_MIC_CTRL1_BASE+0x80008) +#define WCD9378_SMP_MIC_CTRL1_PDE11_ACT_PS (WCD9378_SMP_MIC_CTRL1_BASE+0x80100) +#define WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_0 (WCD9378_SMP_MIC_CTRL1_BASE+0x100060) +#define WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_1 (WCD9378_SMP_MIC_CTRL1_BASE+0x100061) +#define WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_0 (WCD9378_SMP_MIC_CTRL1_BASE+0x100068) +#define WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_1 (WCD9378_SMP_MIC_CTRL1_BASE+0x100069) +#define WCD9378_SMP_MIC_CTRL1_DEV_VER (WCD9378_SMP_MIC_CTRL1_BASE+0x100070) + +#define WCD9378_SMP_MIC_CTRL2_BASE (WCD9378_BASE+0x1800001) +#define WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_0 (WCD9378_SMP_MIC_CTRL2_BASE+0x48) +#define WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_1 (WCD9378_SMP_MIC_CTRL2_BASE+0x49) +#define WCD9378_SMP_MIC_CTRL2_FUNC_EXT_VER (WCD9378_SMP_MIC_CTRL2_BASE+0x50) +#define WCD9378_SMP_MIC_CTRL2_IT11_MICB (WCD9378_SMP_MIC_CTRL2_BASE+0x98) +#define WCD9378_SMP_MIC_CTRL2_IT11_USAGE (WCD9378_SMP_MIC_CTRL2_BASE+0xa0) +#define WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS (WCD9378_SMP_MIC_CTRL2_BASE+0x108) +#define WCD9378_SMP_MIC_CTRL2_OT10_USAGE (WCD9378_SMP_MIC_CTRL2_BASE+0x3a0) +#define WCD9378_SMP_MIC_CTRL2_FUNC_STAT (WCD9378_SMP_MIC_CTRL2_BASE+0x80000) +#define WCD9378_SMP_MIC_CTRL2_FUNC_ACT (WCD9378_SMP_MIC_CTRL2_BASE+0x80008) +#define WCD9378_SMP_MIC_CTRL2_PDE11_ACT_PS (WCD9378_SMP_MIC_CTRL2_BASE+0x80100) +#define WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_0 (WCD9378_SMP_MIC_CTRL2_BASE+0x100060) +#define WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_1 (WCD9378_SMP_MIC_CTRL2_BASE+0x100061) +#define WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_0 (WCD9378_SMP_MIC_CTRL2_BASE+0x100068) +#define WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_1 (WCD9378_SMP_MIC_CTRL2_BASE+0x100069) +#define WCD9378_SMP_MIC_CTRL2_DEV_VER (WCD9378_SMP_MIC_CTRL2_BASE+0x100070) + +#define WCD9378_HID_MEM_BASE (WCD9378_BASE+0x4000001) +#define WCD9378_REPORT_ID (WCD9378_HID_MEM_BASE+0x01) +#define WCD9378_MESSAGE0 (WCD9378_HID_MEM_BASE+0x02) +#define WCD9378_MESSAGE1 (WCD9378_HID_MEM_BASE+0x03) +#define WCD9378_MESSAGE2 (WCD9378_HID_MEM_BASE+0x04) + +#define WCD9378_NUM_REGISTERS (WCD9378_SMP_MIC_CTRL2_DEV_VER - WCD9378_BASE + 1) +#define WCD9378_MAX_REGISTER (WCD9378_MESSAGE2 + 1) + +#define WCD9378_TX_NEW_TX_CH12_MUX_CH2_SEL_SHIFT 0x03 +#define WCD9378_TX_NEW_TX_CH12_MUX_CH1_SEL_SHIFT 0x00 +#define WCD9378_TX_NEW_TX_CH34_MUX_CH3_SEL_SHIFT 0x00 +#define WCD9378_CDC_HPH_GAIN_CTL_HPHR_RX_EN_SHIFT 0x03 +#define WCD9378_CDC_HPH_GAIN_CTL_HPHL_RX_EN_SHIFT 0x02 +#define WCD9378_CDC_AUX_GAIN_CTL_AUX_EN_SHIFT 0x00 + +#define WCD9378_CN_MBQ_ENABLE_MASK (0x6000) +#define WCD9378_CN_ENABLE_MASK (0x4000) + +#define WCD9378_FU42_CH_VOL_CH1_MSB (WCD9378_FU42_CH_VOL_CH1 | WCD9378_CN_MBQ_ENABLE_MASK) +#define WCD9378_FU42_CH_VOL_CH1_LSB (WCD9378_FU42_CH_VOL_CH1 | WCD9378_CN_ENABLE_MASK) +#define WCD9378_FU42_CH_VOL_CH2_MSB (WCD9378_FU42_CH_VOL_CH2 | WCD9378_CN_MBQ_ENABLE_MASK) +#define WCD9378_FU42_CH_VOL_CH2_LSB (WCD9378_FU42_CH_VOL_CH2 | WCD9378_CN_ENABLE_MASK) +#define WCD9378_FU42_MUTE_CH1_CN (WCD9378_FU42_MUTE_CH1 | WCD9378_CN_ENABLE_MASK) +#define WCD9378_FU42_MUTE_CH2_CN (WCD9378_FU42_MUTE_CH2 | WCD9378_CN_ENABLE_MASK) + +#define SWRS_SCP_BASE_CLK_BASE (0x004d) +#define SWRS_SCP_BUSCLOCK_SCALE_BANK0 (0x0062) +#define SWRS_SCP_BUSCLOCK_SCALE_BANK1 (0x0072) + +#define SWRS_SCP_SDCA_INTMASK_1 (0x0000005c) +#define SWRS_SCP_SDCA_INTMASK_2 (0x0000005d) +#define SWRS_SCP_SDCA_INTMASK_3 (0x0000005e) + +#define SWRS_SCP_SDCA_INTSTAT_1 (0x00000058) +#define SWRS_SCP_SDCA_INTSTAT_2 (0x00000059) +#define SWRS_SCP_SDCA_INTSTAT_3 (0x0000005a) + +#define SWRS_SCP_SDCA_INTRTYPE_1 (0x000000f4) +#define SWRS_SCP_SDCA_INTRTYPE_2 (0x000000f8) +#define SWRS_SCP_SDCA_INTRTYPE_3 (0x000000fc) + + +#endif /* WCD9378_REGISTERS_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-regmap.c new file mode 100644 index 0000000000..e35701bad2 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-regmap.c @@ -0,0 +1,945 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include "wcd9378-registers.h" + +extern const u8 wcd9378_reg_access[WCD9378_NUM_REGISTERS]; + +static struct reg_default wcd9378_defaults[] = { + {SWRS_SCP_SDCA_INTSTAT_1, 0x00}, + {SWRS_SCP_SDCA_INTSTAT_2, 0x00}, + {SWRS_SCP_SDCA_INTSTAT_2, 0x00}, + {SWRS_SCP_SDCA_INTMASK_1, 0x00}, + {SWRS_SCP_SDCA_INTMASK_2, 0x00}, + {SWRS_SCP_SDCA_INTMASK_3, 0x00}, + {SWRS_SCP_SDCA_INTRTYPE_1, 0x00}, + {SWRS_SCP_SDCA_INTRTYPE_2, 0x00}, + {SWRS_SCP_SDCA_INTRTYPE_3, 0x00}, + {WCD9378_FUNC_EXT_ID_0, 0x00}, + {WCD9378_FUNC_EXT_ID_1, 0x00}, + {WCD9378_FUNC_EXT_VER, 0x00}, + {WCD9378_FUNC_STAT, 0x67}, + {WCD9378_DEV_MANU_ID_0, 0x17}, + {WCD9378_DEV_MANU_ID_1, 0x02}, + {WCD9378_DEV_PART_ID_0, 0x10}, + {WCD9378_DEV_PART_ID_1, 0x01}, + {WCD9378_DEV_VER, 0x10}, + {WCD9378_ANA_PAGE, 0x00}, + {WCD9378_ANA_BIAS, 0x00}, + {WCD9378_ANA_RX_SUPPLIES, 0x00}, + {WCD9378_ANA_HPH, 0x0c}, + {WCD9378_ANA_EAR, 0x00}, + {WCD9378_ANA_EAR_COMPANDER_CTL, 0x02}, + {WCD9378_ANA_TX_CH1, 0x20}, + {WCD9378_ANA_TX_CH2, 0x00}, + {WCD9378_ANA_TX_CH3, 0x20}, + {WCD9378_ANA_TX_CH3_HPF, 0x00}, + {WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00}, + {WCD9378_ANA_MICB3_DSP_EN_LOGIC, 0x00}, + {WCD9378_ANA_MBHC_MECH, 0x39}, + {WCD9378_ANA_MBHC_ELECT, 0x08}, + {WCD9378_ANA_MBHC_ZDET, 0x00}, + {WCD9378_ANA_MBHC_RESULT_1, 0x00}, + {WCD9378_ANA_MBHC_RESULT_2, 0x00}, + {WCD9378_ANA_MBHC_RESULT_3, 0x00}, + {WCD9378_ANA_MBHC_BTN0, 0x00}, + {WCD9378_ANA_MBHC_BTN1, 0x10}, + {WCD9378_ANA_MBHC_BTN2, 0x20}, + {WCD9378_ANA_MBHC_BTN3, 0x30}, + {WCD9378_ANA_MBHC_BTN4, 0x40}, + {WCD9378_ANA_MBHC_BTN5, 0x50}, + {WCD9378_ANA_MBHC_BTN6, 0x60}, + {WCD9378_ANA_MBHC_BTN7, 0x70}, + {WCD9378_ANA_MICB1, 0x10}, + {WCD9378_ANA_MICB2, 0x10}, + {WCD9378_ANA_MICB2_RAMP, 0x00}, + {WCD9378_ANA_MICB3, 0x00}, + {WCD9378_BIAS_CTL, 0x2a}, + {WCD9378_BIAS_VBG_FINE_ADJ, 0x55}, + {WCD9378_LDOL_VDDCX_ADJUST, 0x01}, + {WCD9378_LDOL_DISABLE_LDOL, 0x00}, + {WCD9378_MBHC_CTL_CLK, 0x00}, + {WCD9378_MBHC_CTL_ANA, 0x00}, + {WCD9378_MBHC_CTL_SPARE_1, 0x02}, + {WCD9378_MBHC_CTL_SPARE_2, 0x00}, + {WCD9378_MBHC_CTL_BCS, 0x00}, + {WCD9378_MBHC_MOISTURE_DET_FSM_STATUS, 0x00}, + {WCD9378_MBHC_TEST_CTL, 0x00}, + {WCD9378_LDOH_MODE, 0x2b}, + {WCD9378_LDOH_BIAS, 0x68}, + {WCD9378_LDOH_STB_LOADS, 0x00}, + {WCD9378_LDOH_SLOWRAMP, 0x50}, + {WCD9378_MICB1_TEST_CTL_1, 0x1a}, + {WCD9378_MICB1_TEST_CTL_2, 0x00}, + {WCD9378_MICB1_TEST_CTL_3, 0xa4}, + {WCD9378_MICB2_TEST_CTL_1, 0x1a}, + {WCD9378_MICB2_TEST_CTL_2, 0x00}, + {WCD9378_MICB2_TEST_CTL_3, 0x24}, + {WCD9378_MICB3_TEST_CTL_1, 0x9a}, + {WCD9378_MICB3_TEST_CTL_2, 0x80}, + {WCD9378_MICB3_TEST_CTL_3, 0x24}, + {WCD9378_TX_COM_ADC_VCM, 0x39}, + {WCD9378_TX_COM_BIAS_ATEST, 0xe0}, + {WCD9378_TX_COM_SPARE1, 0x00}, + {WCD9378_TX_COM_SPARE2, 0x00}, + {WCD9378_TX_COM_TXFE_DIV_CTL, 0x22}, + {WCD9378_TX_COM_TXFE_DIV_START, 0x00}, + {WCD9378_TX_COM_SPARE3, 0x00}, + {WCD9378_TX_COM_SPARE4, 0x00}, + {WCD9378_TX_1_2_TEST_EN, 0xcc}, + {WCD9378_TX_1_2_ADC_IB, 0xe9}, + {WCD9378_TX_1_2_ATEST_REFCTL, 0x0b}, + {WCD9378_TX_1_2_TEST_CTL, 0x38}, + {WCD9378_TX_1_2_TEST_BLK_EN1, 0xff}, + {WCD9378_TX_1_2_TXFE1_CLKDIV, 0x00}, + {WCD9378_TX_1_2_SAR2_ERR, 0x00}, + {WCD9378_TX_1_2_SAR1_ERR, 0x00}, + {WCD9378_TX_3_TEST_EN, 0xcc}, + {WCD9378_TX_3_ADC_IB, 0xe9}, + {WCD9378_TX_3_ATEST_REFCTL, 0x0b}, + {WCD9378_TX_3_TEST_CTL, 0x38}, + {WCD9378_TX_3_TEST_BLK_EN3, 0xff}, + {WCD9378_TX_3_TXFE3_CLKDIV, 0x00}, + {WCD9378_TX_3_SAR4_ERR, 0x00}, + {WCD9378_TX_3_SAR3_ERR, 0x00}, + {WCD9378_TX_3_TEST_BLK_EN2, 0xfb}, + {WCD9378_TX_3_TXFE2_CLKDIV, 0x00}, + {WCD9378_TX_3_SPARE1, 0x00}, + {WCD9378_TX_3_TEST_BLK_EN4, 0xfb}, + {WCD9378_TX_3_SPARE2, 0x00}, + {WCD9378_TX_3_SPARE3, 0x00}, + {WCD9378_RX_AUX_SW_CTL, 0x00}, + {WCD9378_RX_PA_AUX_IN_CONN, 0x00}, + {WCD9378_RX_TIMER_DIV, 0x32}, + {WCD9378_RX_OCP_CTL, 0x1f}, + {WCD9378_RX_OCP_COUNT, 0x77}, + {WCD9378_RX_BIAS_EAR_DAC, 0xa0}, + {WCD9378_RX_BIAS_EAR_AMP, 0xaa}, + {WCD9378_RX_BIAS_HPH_LDO, 0xa9}, + {WCD9378_RX_BIAS_HPH_PA, 0xaa}, + {WCD9378_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8a}, + {WCD9378_RX_BIAS_HPH_RDAC_LDO, 0x88}, + {WCD9378_RX_BIAS_HPH_CNP1, 0x82}, + {WCD9378_RX_BIAS_HPH_LOWPOWER, 0x82}, + {WCD9378_RX_BIAS_AUX_DAC, 0xa0}, + {WCD9378_RX_BIAS_AUX_AMP, 0xaa}, + {WCD9378_RX_SPARE_1, 0x50}, + {WCD9378_RX_SPARE_2, 0x00}, + {WCD9378_RX_SPARE_3, 0x08}, + {WCD9378_RX_SPARE_4, 0x44}, + {WCD9378_RX_SPARE_5, 0x40}, + {WCD9378_RX_SPARE_6, 0xaa}, + {WCD9378_RX_SPARE_7, 0x14}, + {WCD9378_HPH_L_STATUS, 0x04}, + {WCD9378_HPH_R_STATUS, 0x04}, + {WCD9378_HPH_CNP_EN, 0x80}, + {WCD9378_HPH_CNP_WG_CTL, 0x9a}, + {WCD9378_HPH_CNP_WG_TIME, 0x14}, + {WCD9378_HPH_OCP_CTL, 0x28}, + {WCD9378_HPH_AUTO_CHOP, 0x16}, + {WCD9378_HPH_CHOP_CTL, 0x83}, + {WCD9378_HPH_PA_CTL1, 0x46}, + {WCD9378_HPH_PA_CTL2, 0x50}, + {WCD9378_HPH_L_EN, 0x80}, + {WCD9378_HPH_L_TEST, 0xe0}, + {WCD9378_HPH_L_ATEST, 0x50}, + {WCD9378_HPH_R_EN, 0x80}, + {WCD9378_HPH_R_TEST, 0xe0}, + {WCD9378_HPH_R_ATEST, 0x54}, + {WCD9378_HPH_RDAC_CLK_CTL1, 0x99}, + {WCD9378_HPH_RDAC_CLK_CTL2, 0x9b}, + {WCD9378_HPH_RDAC_LDO_CTL, 0x33}, + {WCD9378_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00}, + {WCD9378_HPH_REFBUFF_UHQA_CTL, 0xa8}, + {WCD9378_HPH_REFBUFF_LP_CTL, 0x0e}, + {WCD9378_HPH_L_DAC_CTL, 0x20}, + {WCD9378_HPH_R_DAC_CTL, 0x20}, + {WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55}, + {WCD9378_HPH_SURGE_HPHLR_SURGE_EN, 0x19}, + {WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1, 0xa0}, + {WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS, 0x00}, + {WCD9378_EAR_EAR_EN_REG, 0x22}, + {WCD9378_EAR_EAR_PA_CON, 0x44}, + {WCD9378_EAR_EAR_SP_CON, 0xdb}, + {WCD9378_EAR_EAR_DAC_CON, 0x80}, + {WCD9378_EAR_EAR_CNP_FSM_CON, 0xb2}, + {WCD9378_EAR_TEST_CTL, 0x00}, + {WCD9378_EAR_STATUS_REG_1, 0x00}, + {WCD9378_EAR_STATUS_REG_2, 0x00}, + {WCD9378_ANA_NEW_PAGE, 0x00}, + {WCD9378_HPH_NEW_ANA_HPH2, 0x00}, + {WCD9378_HPH_NEW_ANA_HPH3, 0x00}, + {WCD9378_SLEEP_CTL, 0x16}, + {WCD9378_SLEEP_WATCHDOG_CTL, 0x00}, + {WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00}, + {WCD9378_MBHC_NEW_CTL_1, 0x0e}, + {WCD9378_MBHC_NEW_CTL_2, 0x05}, + {WCD9378_MBHC_NEW_PLUG_DETECT_CTL, 0xe9}, + {WCD9378_MBHC_NEW_ZDET_ANA_CTL, 0x0f}, + {WCD9378_MBHC_NEW_ZDET_RAMP_CTL, 0x00}, + {WCD9378_MBHC_NEW_FSM_STATUS, 0x00}, + {WCD9378_MBHC_NEW_ADC_RESULT, 0x00}, + {WCD9378_AUX_AUXPA, 0x00}, + {WCD9378_DIE_CRACK_DIE_CRK_DET_EN, 0x00}, + {WCD9378_DIE_CRACK_DIE_CRK_DET_OUT, 0x00}, + {WCD9378_TX_NEW_TX_CH12_MUX, 0x11}, + {WCD9378_TX_NEW_TX_CH34_MUX, 0x23}, + {WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40}, + {WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81}, + {WCD9378_HPH_NEW_INT_RDAC_VREF_CTL, 0x10}, + {WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00}, + {WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81}, + {WCD9378_HPH_NEW_INT_PA_MISC1, 0x22}, + {WCD9378_HPH_NEW_INT_PA_MISC2, 0x00}, + {WCD9378_HPH_NEW_INT_PA_RDAC_MISC, 0x01}, + {WCD9378_HPH_NEW_INT_HPH_TIMER1, 0xfe}, + {WCD9378_HPH_NEW_INT_HPH_TIMER2, 0x02}, + {WCD9378_HPH_NEW_INT_HPH_TIMER3, 0x4e}, + {WCD9378_HPH_NEW_INT_HPH_TIMER4, 0x54}, + {WCD9378_HPH_NEW_INT_PA_RDAC_MISC2, 0x00}, + {WCD9378_HPH_NEW_INT_PA_RDAC_MISC3, 0x00}, + {WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62}, + {WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01}, + {WCD9378_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11}, + {WCD9378_CP_CLASSG_CP_CTRL_0, 0x00}, + {WCD9378_CP_CLASSG_CP_CTRL_1, 0x00}, + {WCD9378_CP_CLASSG_CP_CTRL_2, 0x23}, + {WCD9378_CP_CLASSG_CP_CTRL_3, 0x03}, + {WCD9378_CP_CLASSG_CP_CTRL_4, 0x00}, + {WCD9378_CP_CLASSG_CP_CTRL_5, 0x0a}, + {WCD9378_CP_CLASSG_CP_CTRL_6, 0x00}, + {WCD9378_CP_CLASSG_CP_CTRL_7, 0x00}, + {WCD9378_CP_VNEGDAC_CTRL_0, 0x23}, + {WCD9378_CP_VNEGDAC_CTRL_1, 0x00}, + {WCD9378_CP_VNEGDAC_CTRL_2, 0x00}, + {WCD9378_CP_VNEGDAC_CTRL_3, 0x00}, + {WCD9378_CP_CP_DTOP_CTRL_0, 0x00}, + {WCD9378_CP_CP_DTOP_CTRL_1, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_2, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_3, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_4, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_5, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_6, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_7, 0x03}, + {WCD9378_CP_CP_DTOP_CTRL_8, 0x33}, + {WCD9378_CP_CP_DTOP_CTRL_9, 0x63}, + {WCD9378_CP_CP_DTOP_CTRL_10, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_11, 0x03}, + {WCD9378_CP_CP_DTOP_CTRL_12, 0x1b}, + {WCD9378_CP_CP_DTOP_CTRL_13, 0x00}, + {WCD9378_CP_CP_DTOP_CTRL_14, 0x00}, + {WCD9378_CP_CP_DTOP_CTRL_15, 0xff}, + {WCD9378_CP_CP_DTOP_CTRL_16, 0x00}, + {WCD9378_CP_CP_DTOP_CTRL_17, 0x06}, + {WCD9378_CP_CP_DTOP_CTRL_18, 0x00}, + {WCD9378_CP_CP_DTOP_CTRL_19, 0x00}, + {WCD9378_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57}, + {WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01}, + {WCD9378_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00}, + {WCD9378_MBHC_NEW_INT_SPARE_2, 0x00}, + {WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON, 0xa8}, + {WCD9378_EAR_INT_NEW_CNP_VCM_CON1, 0x42}, + {WCD9378_EAR_INT_NEW_CNP_VCM_CON2, 0x22}, + {WCD9378_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00}, + {WCD9378_AUX_INT_EN_REG, 0x00}, + {WCD9378_AUX_INT_PA_CTRL, 0x06}, + {WCD9378_AUX_INT_SP_CTRL, 0xd2}, + {WCD9378_AUX_INT_DAC_CTRL, 0x80}, + {WCD9378_AUX_INT_CLK_CTRL, 0x50}, + {WCD9378_AUX_INT_TEST_CTRL, 0x00}, + {WCD9378_AUX_INT_STATUS_REG, 0x00}, + {WCD9378_AUX_INT_MISC, 0x00}, + {WCD9378_SLEEP_INT_WATCHDOG_CTL_1, 0x0a}, + {WCD9378_SLEEP_INT_WATCHDOG_CTL_2, 0x0a}, + {WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02}, + {WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60}, + {WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L2, 0xff}, + {WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L1, 0x7f}, + {WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L0, 0x3f}, + {WCD9378_TX_COM_NEW_INT_SPARE1, 0x1f}, + {WCD9378_TX_COM_NEW_INT_SPARE2, 0x0f}, + {WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L2, 0xd7}, + {WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L1, 0xc8}, + {WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L0, 0xc6}, + {WCD9378_TX_COM_NEW_INT_SPARE3, 0x95}, + {WCD9378_TX_COM_NEW_INT_SPARE4, 0x6a}, + {WCD9378_TX_COM_NEW_INT_SPARE5, 0x05}, + {WCD9378_TX_COM_NEW_INT_SPARE6, 0xa5}, + {WCD9378_TX_COM_NEW_INT_SPARE7, 0x13}, + {WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1, 0x88}, + {WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L0, 0x42}, + {WCD9378_TX_COM_NEW_INT_TXADC_INT_L2, 0xff}, + {WCD9378_TX_COM_NEW_INT_TXADC_INT_L1, 0x64}, + {WCD9378_TX_COM_NEW_INT_TXADC_INT_L0, 0x64}, + {WCD9378_TX_COM_NEW_INT_SPARE8, 0x77}, + {WCD9378_TAMBORA_PAGE, 0x00}, + {WCD9378_CHIP_ID0, 0x00}, + {WCD9378_CHIP_ID1, 0x00}, + {WCD9378_CHIP_ID2, 0x10}, + {WCD9378_CHIP_ID3, 0x01}, + {WCD9378_SWR_TX_CLK_RATE, 0x00}, + {WCD9378_CDC_RST_CTL, 0x03}, + {WCD9378_TOP_CLK_CFG, 0x00}, + {WCD9378_CDC_ANA_CLK_CTL, 0x00}, + {WCD9378_CDC_DIG_CLK_CTL, 0x70}, + {WCD9378_SWR_RST_EN, 0x1f}, + {WCD9378_CDC_PATH_MODE, 0x00}, + {WCD9378_CDC_RX_RST, 0x00}, + {WCD9378_CDC_RX0_CTL, 0xfc}, + {WCD9378_CDC_RX1_CTL, 0xfc}, + {WCD9378_CDC_RX2_CTL, 0xfc}, + {WCD9378_CDC_TX_ANA_MODE_0_1, 0x00}, + {WCD9378_CDC_TX_ANA_MODE_2_3, 0x00}, + {WCD9378_CDC_COMP_CTL_0, 0x00}, + {WCD9378_CDC_ANA_TX_CLK_CTL, 0x0e}, + {WCD9378_CDC_HPH_DSM_A1_0, 0x00}, + {WCD9378_CDC_HPH_DSM_A1_1, 0x01}, + {WCD9378_CDC_HPH_DSM_A2_0, 0x63}, + {WCD9378_CDC_HPH_DSM_A2_1, 0x04}, + {WCD9378_CDC_HPH_DSM_A3_0, 0xac}, + {WCD9378_CDC_HPH_DSM_A3_1, 0x04}, + {WCD9378_CDC_HPH_DSM_A4_0, 0x1a}, + {WCD9378_CDC_HPH_DSM_A4_1, 0x03}, + {WCD9378_CDC_HPH_DSM_A5_0, 0xbc}, + {WCD9378_CDC_HPH_DSM_A5_1, 0x02}, + {WCD9378_CDC_HPH_DSM_A6_0, 0xc7}, + {WCD9378_CDC_HPH_DSM_A7_0, 0xf8}, + {WCD9378_CDC_HPH_DSM_C_0, 0x47}, + {WCD9378_CDC_HPH_DSM_C_1, 0x43}, + {WCD9378_CDC_HPH_DSM_C_2, 0xb1}, + {WCD9378_CDC_HPH_DSM_C_3, 0x17}, + {WCD9378_CDC_HPH_DSM_R1, 0x4d}, + {WCD9378_CDC_HPH_DSM_R2, 0x29}, + {WCD9378_CDC_HPH_DSM_R3, 0x34}, + {WCD9378_CDC_HPH_DSM_R4, 0x59}, + {WCD9378_CDC_HPH_DSM_R5, 0x66}, + {WCD9378_CDC_HPH_DSM_R6, 0x87}, + {WCD9378_CDC_HPH_DSM_R7, 0x64}, + {WCD9378_CDC_AUX_DSM_A1_0, 0x00}, + {WCD9378_CDC_AUX_DSM_A1_1, 0x01}, + {WCD9378_CDC_AUX_DSM_A2_0, 0x96}, + {WCD9378_CDC_AUX_DSM_A2_1, 0x09}, + {WCD9378_CDC_AUX_DSM_A3_0, 0xab}, + {WCD9378_CDC_AUX_DSM_A3_1, 0x05}, + {WCD9378_CDC_AUX_DSM_A4_0, 0x1c}, + {WCD9378_CDC_AUX_DSM_A4_1, 0x02}, + {WCD9378_CDC_AUX_DSM_A5_0, 0x17}, + {WCD9378_CDC_AUX_DSM_A5_1, 0x02}, + {WCD9378_CDC_AUX_DSM_A6_0, 0xaa}, + {WCD9378_CDC_AUX_DSM_A7_0, 0xe3}, + {WCD9378_CDC_AUX_DSM_C_0, 0x69}, + {WCD9378_CDC_AUX_DSM_C_1, 0x54}, + {WCD9378_CDC_AUX_DSM_C_2, 0x02}, + {WCD9378_CDC_AUX_DSM_C_3, 0x15}, + {WCD9378_CDC_AUX_DSM_R1, 0xa4}, + {WCD9378_CDC_AUX_DSM_R2, 0xb5}, + {WCD9378_CDC_AUX_DSM_R3, 0x86}, + {WCD9378_CDC_AUX_DSM_R4, 0x85}, + {WCD9378_CDC_AUX_DSM_R5, 0xaa}, + {WCD9378_CDC_AUX_DSM_R6, 0xe2}, + {WCD9378_CDC_AUX_DSM_R7, 0x62}, + {WCD9378_CDC_HPH_GAIN_RX_0, 0x55}, + {WCD9378_CDC_HPH_GAIN_RX_1, 0xa9}, + {WCD9378_CDC_HPH_GAIN_DSD_0, 0x3d}, + {WCD9378_CDC_HPH_GAIN_DSD_1, 0x2e}, + {WCD9378_CDC_HPH_GAIN_DSD_2, 0x01}, + {WCD9378_CDC_AUX_GAIN_DSD_0, 0x00}, + {WCD9378_CDC_AUX_GAIN_DSD_1, 0xfc}, + {WCD9378_CDC_AUX_GAIN_DSD_2, 0x01}, + {WCD9378_CDC_HPH_GAIN_CTL, 0x00}, + {WCD9378_CDC_AUX_GAIN_CTL, 0x00}, + {WCD9378_CDC_PATH_CTL, 0x00}, + {WCD9378_CDC_SWR_CLG, 0x00}, + {WCD9378_SWR_CLG_BYP, 0x00}, + {WCD9378_CDC_TX0_CTL, 0x68}, + {WCD9378_CDC_TX1_CTL, 0x68}, + {WCD9378_CDC_TX2_CTL, 0x68}, + {WCD9378_CDC_TX_RST, 0x00}, + {WCD9378_CDC_REQ_CTL, 0x01}, + {WCD9378_CDC_RST, 0x00}, + {WCD9378_CDC_AMIC_CTL, 0x07}, + {WCD9378_CDC_DMIC_CTL, 0x04}, + {WCD9378_CDC_DMIC1_CTL, 0x01}, + {WCD9378_CDC_DMIC2_CTL, 0x01}, + {WCD9378_CDC_DMIC3_CTL, 0x01}, + {WCD9378_EFUSE_PRG_CTL, 0x00}, + {WCD9378_EFUSE_CTL, 0x2b}, + {WCD9378_CDC_DMIC_RATE_1_2, 0x11}, + {WCD9378_CDC_DMIC_RATE_3_4, 0x01}, + {WCD9378_PDM_WD_EN_OVRD, 0x00}, + {WCD9378_PDM_WD_CTL0, 0x0f}, + {WCD9378_PDM_WD_CTL1, 0x0f}, + {WCD9378_PDM_WD_CTL2, 0x01}, + {WCD9378_RAMP_CTL, 0x07}, + {WCD9378_ACT_DET_CTL, 0x00}, + {WCD9378_ACT_DET_HOOKUP0, 0x00}, + {WCD9378_ACT_DET_HOOKUP1, 0x07}, + {WCD9378_ACT_DET_HOOKUP2, 0x00}, + {WCD9378_ACT_DET_DLY_BUF_EN, 0x1f}, + {WCD9378_INTR_MODE, 0x00}, + {WCD9378_INTR_STATUS_0, 0x00}, + {WCD9378_INTR_STATUS_1, 0x00}, + {WCD9378_INTR_STATUS_2, 0x00}, + {WCD9378_INTR_STATUS_3, 0x00}, + {WCD9378_INTR_MASK_0, 0xff}, + {WCD9378_INTR_MASK_1, 0xff}, + {WCD9378_INTR_MASK_2, 0x3f}, + {WCD9378_INTR_MASK_3, 0x00}, + {WCD9378_INTR_SET_0, 0x00}, + {WCD9378_INTR_SET_1, 0x00}, + {WCD9378_INTR_SET_2, 0x00}, + {WCD9378_INTR_SET_3, 0x00}, + {WCD9378_INTR_TEST_0, 0x00}, + {WCD9378_INTR_TEST_1, 0x00}, + {WCD9378_INTR_TEST_2, 0x00}, + {WCD9378_INTR_TEST_3, 0x3e}, + {WCD9378_TX_MODE_DBG_EN, 0x00}, + {WCD9378_TX_MODE_DBG_0_1, 0x00}, + {WCD9378_TX_MODE_DBG_2_3, 0x00}, + {WCD9378_LB_IN_SEL_CTL, 0x00}, + {WCD9378_LOOP_BACK_MODE, 0x00}, + {WCD9378_SWR_DAC_TEST, 0x00}, + {WCD9378_SWR_HM_TEST_RX_0, 0x40}, + {WCD9378_SWR_HM_TEST_TX_0, 0x40}, + {WCD9378_SWR_HM_TEST_RX_1, 0x00}, + {WCD9378_SWR_HM_TEST_TX_1, 0x00}, + {WCD9378_SWR_HM_TEST_0, 0x00}, + {WCD9378_PAD_CTL_SWR_0, 0x8f}, + {WCD9378_PAD_CTL_SWR_1, 0x06}, + {WCD9378_I2C_CTL, 0x00}, + {WCD9378_LEGACY_SW_MODE, 0x00}, + {WCD9378_EFUSE_TEST_CTL_0, 0x00}, + {WCD9378_EFUSE_TEST_CTL_1, 0x00}, + {WCD9378_EFUSE_T_DATA_0, 0x00}, + {WCD9378_PAD_CTL_PDM_RX0, 0xf1}, + {WCD9378_PAD_CTL_PDM_RX1, 0xf1}, + {WCD9378_PAD_CTL_PDM_TX0, 0xf1}, + {WCD9378_PAD_CTL_PDM_TX1, 0xf1}, + {WCD9378_PAD_INP_DIS_0, 0x2a}, + {WCD9378_DRIVE_STRENGTH_0, 0x00}, + {WCD9378_DRIVE_STRENGTH_1, 0x00}, + {WCD9378_RX_DATA_EDGE_CTL, 0x1c}, + {WCD9378_TX_DATA_EDGE_CTL, 0x10}, + {WCD9378_GPIO_MODE, 0x00}, + {WCD9378_PIN_CTL_OE, 0x00}, + {WCD9378_PIN_CTL_DATA_0, 0x00}, + {WCD9378_PIN_STATUS_0, 0x00}, + {WCD9378_DIG_DEBUG_CTL, 0x00}, + {WCD9378_DIG_DEBUG_EN, 0x00}, + {WCD9378_ANA_CSR_DBG_ADD, 0x00}, + {WCD9378_ANA_CSR_DBG_CTL, 0x48}, + {WCD9378_SSP_DBG, 0x00}, + {WCD9378_MODE_STATUS_0, 0x00}, + {WCD9378_MODE_STATUS_1, 0x00}, + {WCD9378_SPARE_0, 0x00}, + {WCD9378_SPARE_1, 0x00}, + {WCD9378_SPARE_2, 0x00}, + {WCD9378_EFUSE_REG_0, 0x00}, + {WCD9378_EFUSE_REG_1, 0xff}, + {WCD9378_EFUSE_REG_2, 0xff}, + {WCD9378_EFUSE_REG_3, 0xff}, + {WCD9378_EFUSE_REG_4, 0xff}, + {WCD9378_EFUSE_REG_5, 0xff}, + {WCD9378_EFUSE_REG_6, 0xff}, + {WCD9378_EFUSE_REG_7, 0xff}, + {WCD9378_EFUSE_REG_8, 0xff}, + {WCD9378_EFUSE_REG_9, 0xff}, + {WCD9378_EFUSE_REG_10, 0xff}, + {WCD9378_EFUSE_REG_11, 0xff}, + {WCD9378_EFUSE_REG_12, 0xff}, + {WCD9378_EFUSE_REG_13, 0xff}, + {WCD9378_EFUSE_REG_14, 0xff}, + {WCD9378_EFUSE_REG_15, 0xff}, + {WCD9378_EFUSE_REG_16, 0xff}, + {WCD9378_EFUSE_REG_17, 0xff}, + {WCD9378_EFUSE_REG_18, 0xff}, + {WCD9378_EFUSE_REG_19, 0xff}, + {WCD9378_EFUSE_REG_20, 0x0e}, + {WCD9378_EFUSE_REG_21, 0x00}, + {WCD9378_EFUSE_REG_22, 0x00}, + {WCD9378_EFUSE_REG_23, 0xf6}, + {WCD9378_EFUSE_REG_24, 0x17}, + {WCD9378_EFUSE_REG_25, 0x00}, + {WCD9378_EFUSE_REG_26, 0x00}, + {WCD9378_EFUSE_REG_27, 0x00}, + {WCD9378_EFUSE_REG_28, 0x00}, + {WCD9378_EFUSE_REG_29, 0x00}, + {WCD9378_EFUSE_REG_30, 0x09}, + {WCD9378_EFUSE_REG_31, 0xf6}, + {WCD9378_TX_REQ_FB_CTL_2, 0x11}, + {WCD9378_TX_REQ_FB_CTL_3, 0x00}, + {WCD9378_TX_REQ_FB_CTL_4, 0x00}, + {WCD9378_DEM_BYPASS_DATA0, 0x55}, + {WCD9378_DEM_BYPASS_DATA1, 0x55}, + {WCD9378_DEM_BYPASS_DATA2, 0x55}, + {WCD9378_DEM_BYPASS_DATA3, 0x01}, + {WCD9378_RX0_PCM_RAMP_STEP, 0x05}, + {WCD9378_RX0_DSD_RAMP_STEP, 0x0e}, + {WCD9378_RX1_PCM_RAMP_STEP, 0x05}, + {WCD9378_RX1_DSD_RAMP_STEP, 0x0e}, + {WCD9378_RX2_RAMP_STEP, 0x0e}, + {WCD9378_PLATFORM_CTL, 0x01}, + {WCD9378_CLK_DIV_CFG, 0x03}, + {WCD9378_DRE_DLY_VAL, 0x88}, + {WCD9378_SYS_USAGE_CTRL, 0x00}, + {WCD9378_SURGE_CTL, 0x00}, + {WCD9378_SEQ_CTL, 0x00}, + {WCD9378_HPH_UP_T0, 0x02}, + {WCD9378_HPH_UP_T1, 0x02}, + {WCD9378_HPH_UP_T2, 0x02}, + {WCD9378_HPH_UP_T3, 0x02}, + {WCD9378_HPH_UP_T4, 0x02}, + {WCD9378_HPH_UP_T5, 0x03}, + {WCD9378_HPH_UP_T6, 0x02}, + {WCD9378_HPH_UP_T7, 0x06}, + {WCD9378_HPH_UP_T8, 0x02}, + {WCD9378_HPH_UP_T9, 0x02}, + {WCD9378_HPH_UP_T10, 0x00}, + {WCD9378_HPH_DN_T0, 0x05}, + {WCD9378_HPH_DN_T1, 0x06}, + {WCD9378_HPH_DN_T2, 0x02}, + {WCD9378_HPH_DN_T3, 0x02}, + {WCD9378_HPH_DN_T4, 0x02}, + {WCD9378_HPH_DN_T5, 0x02}, + {WCD9378_HPH_DN_T6, 0x02}, + {WCD9378_HPH_DN_T7, 0x02}, + {WCD9378_HPH_DN_T8, 0x02}, + {WCD9378_HPH_DN_T9, 0x02}, + {WCD9378_HPH_DN_T10, 0x02}, + {WCD9378_HPH_UP_STAGE_LOC_0, 0x00}, + {WCD9378_HPH_UP_STAGE_LOC_1, 0x01}, + {WCD9378_HPH_UP_STAGE_LOC_2, 0x02}, + {WCD9378_HPH_UP_STAGE_LOC_3, 0x03}, + {WCD9378_HPH_UP_STAGE_LOC_4, 0x04}, + {WCD9378_HPH_UP_STAGE_LOC_5, 0x05}, + {WCD9378_HPH_UP_STAGE_LOC_6, 0x06}, + {WCD9378_HPH_UP_STAGE_LOC_7, 0x07}, + {WCD9378_HPH_UP_STAGE_LOC_8, 0x08}, + {WCD9378_HPH_UP_STAGE_LOC_9, 0x09}, + {WCD9378_HPH_UP_STAGE_LOC_10, 0x0a}, + {WCD9378_HPH_DN_STAGE_LOC_0, 0x08}, + {WCD9378_HPH_DN_STAGE_LOC_1, 0x09}, + {WCD9378_HPH_DN_STAGE_LOC_2, 0x06}, + {WCD9378_HPH_DN_STAGE_LOC_3, 0x05}, + {WCD9378_HPH_DN_STAGE_LOC_4, 0x04}, + {WCD9378_HPH_DN_STAGE_LOC_5, 0x03}, + {WCD9378_HPH_DN_STAGE_LOC_6, 0x07}, + {WCD9378_HPH_DN_STAGE_LOC_7, 0x01}, + {WCD9378_HPH_DN_STAGE_LOC_8, 0x02}, + {WCD9378_HPH_DN_STAGE_LOC_9, 0x0a}, + {WCD9378_HPH_DN_STAGE_LOC_10, 0x00}, + {WCD9378_SA_UP_T0, 0x02}, + {WCD9378_SA_UP_T1, 0x02}, + {WCD9378_SA_UP_T2, 0x02}, + {WCD9378_SA_UP_T3, 0x02}, + {WCD9378_SA_UP_T4, 0x02}, + {WCD9378_SA_UP_T5, 0x06}, + {WCD9378_SA_UP_T6, 0x02}, + {WCD9378_SA_UP_T7, 0x00}, + {WCD9378_SA_DN_T0, 0x05}, + {WCD9378_SA_DN_T1, 0x06}, + {WCD9378_SA_DN_T2, 0x02}, + {WCD9378_SA_DN_T3, 0x02}, + {WCD9378_SA_DN_T4, 0x02}, + {WCD9378_SA_DN_T5, 0x03}, + {WCD9378_SA_DN_T6, 0x02}, + {WCD9378_SA_DN_T7, 0x06}, + {WCD9378_SA_UP_STAGE_LOC_0, 0x00}, + {WCD9378_SA_UP_STAGE_LOC_1, 0x01}, + {WCD9378_SA_UP_STAGE_LOC_2, 0x02}, + {WCD9378_SA_UP_STAGE_LOC_3, 0x03}, + {WCD9378_SA_UP_STAGE_LOC_4, 0x04}, + {WCD9378_SA_UP_STAGE_LOC_5, 0x05}, + {WCD9378_SA_UP_STAGE_LOC_6, 0x06}, + {WCD9378_SA_UP_STAGE_LOC_7, 0x07}, + {WCD9378_SA_DN_STAGE_LOC_0, 0x05}, + {WCD9378_SA_DN_STAGE_LOC_1, 0x06}, + {WCD9378_SA_DN_STAGE_LOC_2, 0x04}, + {WCD9378_SA_DN_STAGE_LOC_3, 0x03}, + {WCD9378_SA_DN_STAGE_LOC_4, 0x02}, + {WCD9378_SA_DN_STAGE_LOC_5, 0x01}, + {WCD9378_SA_DN_STAGE_LOC_6, 0x07}, + {WCD9378_SA_DN_STAGE_LOC_7, 0x00}, + {WCD9378_TX0_UP_T0, 0x02}, + {WCD9378_TX0_UP_T1, 0x02}, + {WCD9378_TX0_UP_T2, 0x02}, + {WCD9378_TX0_UP_T3, 0x00}, + {WCD9378_TX0_DN_T0, 0x02}, + {WCD9378_TX0_DN_T1, 0x02}, + {WCD9378_TX0_DN_T2, 0x02}, + {WCD9378_TX0_DN_T3, 0x00}, + {WCD9378_TX0_UP_STAGE_LOC_0, 0x00}, + {WCD9378_TX0_UP_STAGE_LOC_1, 0x01}, + {WCD9378_TX0_UP_STAGE_LOC_2, 0x02}, + {WCD9378_TX0_UP_STAGE_LOC_3, 0x03}, + {WCD9378_TX0_DN_STAGE_LOC_0, 0x02}, + {WCD9378_TX0_DN_STAGE_LOC_1, 0x00}, + {WCD9378_TX0_DN_STAGE_LOC_2, 0x01}, + {WCD9378_TX0_DN_STAGE_LOC_3, 0x03}, + {WCD9378_TX1_UP_T0, 0x02}, + {WCD9378_TX1_UP_T1, 0x02}, + {WCD9378_TX1_UP_T2, 0x02}, + {WCD9378_TX1_UP_T3, 0x00}, + {WCD9378_TX1_DN_T0, 0x02}, + {WCD9378_TX1_DN_T1, 0x02}, + {WCD9378_TX1_DN_T2, 0x02}, + {WCD9378_TX1_DN_T3, 0x00}, + {WCD9378_TX1_UP_STAGE_LOC_0, 0x00}, + {WCD9378_TX1_UP_STAGE_LOC_1, 0x01}, + {WCD9378_TX1_UP_STAGE_LOC_2, 0x02}, + {WCD9378_TX1_UP_STAGE_LOC_3, 0x03}, + {WCD9378_TX1_DN_STAGE_LOC_0, 0x02}, + {WCD9378_TX1_DN_STAGE_LOC_1, 0x00}, + {WCD9378_TX1_DN_STAGE_LOC_2, 0x01}, + {WCD9378_TX1_DN_STAGE_LOC_3, 0x03}, + {WCD9378_TX2_UP_T0, 0x02}, + {WCD9378_TX2_UP_T1, 0x02}, + {WCD9378_TX2_UP_T2, 0x02}, + {WCD9378_TX2_UP_T3, 0x00}, + {WCD9378_TX2_DN_T0, 0x02}, + {WCD9378_TX2_DN_T1, 0x02}, + {WCD9378_TX2_DN_T2, 0x02}, + {WCD9378_TX2_DN_T3, 0x00}, + {WCD9378_TX2_UP_STAGE_LOC_0, 0x00}, + {WCD9378_TX2_UP_STAGE_LOC_1, 0x01}, + {WCD9378_TX2_UP_STAGE_LOC_2, 0x02}, + {WCD9378_TX2_UP_STAGE_LOC_3, 0x03}, + {WCD9378_TX2_DN_STAGE_LOC_0, 0x02}, + {WCD9378_TX2_DN_STAGE_LOC_1, 0x00}, + {WCD9378_TX2_DN_STAGE_LOC_2, 0x01}, + {WCD9378_TX2_DN_STAGE_LOC_3, 0x03}, + {WCD9378_SEQ_HPH_STAT, 0x00}, + {WCD9378_SEQ_SA_STAT, 0x00}, + {WCD9378_SEQ_TX0_STAT, 0x00}, + {WCD9378_SEQ_TX1_STAT, 0x00}, + {WCD9378_SEQ_TX2_STAT, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_0, 0x18}, + {WCD9378_MICB_REMAP_TABLE_VAL_1, 0x22}, + {WCD9378_MICB_REMAP_TABLE_VAL_2, 0x24}, + {WCD9378_MICB_REMAP_TABLE_VAL_3, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_4, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_5, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_6, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_7, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_8, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_9, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_10, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_11, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_12, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_13, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_14, 0x00}, + {WCD9378_MICB_REMAP_TABLE_VAL_15, 0x00}, + {WCD9378_SM0_MB_SEL, 0x00}, + {WCD9378_SM1_MB_SEL, 0x00}, + {WCD9378_SM2_MB_SEL, 0x00}, + {WCD9378_MB_PULLUP_EN, 0x00}, + {WCD9378_BYP_EN_CTL0, 0x00}, + {WCD9378_BYP_EN_CTL1, 0x00}, + {WCD9378_BYP_EN_CTL2, 0x00}, + {WCD9378_SEQ_OVRRIDE_CTL0, 0x00}, + {WCD9378_SEQ_OVRRIDE_CTL1, 0x00}, + {WCD9378_SEQ_OVRRIDE_CTL2, 0x00}, + {WCD9378_HPH_SEQ_OVRRIDE_CTL0, 0x00}, + {WCD9378_HPH_SEQ_OVRRIDE_CTL1, 0x00}, + {WCD9378_SA_SEQ_OVRRIDE_CTL, 0x00}, + {WCD9378_TX0_SEQ_OVRRIDE_CTL, 0x00}, + {WCD9378_TX1_SEQ_OVRRIDE_CTL, 0x00}, + {WCD9378_TX2_SEQ_OVRRIDE_CTL, 0x00}, + {WCD9378_FORCE_CTL, 0x00}, + {WCD9378_DEVICE_DET, 0x03}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_0, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_0, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_0, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_0, 0x01}, + {WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_0, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_0, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_1, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_1, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_1, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_1, 0x01}, + {WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_1, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_1, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_2, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_2, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_2, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_2, 0x01}, + {WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_2, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_2, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_3, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_3, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_3, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_3, 0x01}, + {WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_3, 0x00}, + {WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_3, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_0, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_0, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_0, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_0, 0x01}, + {WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_0, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_0, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_0, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_0, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_0, 0x00}, + {WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_0, 0x00}, + {WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_0, 0x00}, + {WCD9378_TYPE1_WRAP_RTC_OOC_SEL_0, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_1, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_1, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_1, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_1, 0x01}, + {WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_1, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_1, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_1, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_1, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_1, 0x00}, + {WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_1, 0x00}, + {WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_1, 0x00}, + {WCD9378_TYPE1_WRAP_RTC_OOC_SEL_1, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_2, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_2, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_2, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_2, 0x01}, + {WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_2, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_2, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_2, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_2, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_2, 0x00}, + {WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_2, 0x00}, + {WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_2, 0x00}, + {WCD9378_TYPE1_WRAP_RTC_OOC_SEL_2, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_3, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_3, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_3, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_3, 0x01}, + {WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_3, 0x00}, + {WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_3, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_3, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_3, 0x00}, + {WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_3, 0x00}, + {WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_3, 0x00}, + {WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_3, 0x00}, + {WCD9378_TYPE1_WRAP_RTC_OOC_SEL_3, 0x00}, + {WCD9378_SDCA_MESSAGE_GATE, 0x00}, + {WCD9378_MBHC_DATA_IN_EDGE, 0x00}, + {WCD9378_MBHC_RESET, 0x00}, + {WCD9378_MBHC_DEBUG, 0x00}, + {WCD9378_MBHC_DEBUG_UMP_0, 0x00}, + {WCD9378_MBHC_DEBUG_UMP_1, 0x00}, + {WCD9378_MBHC_DEBUG_UMP_2, 0x00}, + {WCD9378_HID_FUNC_EXT_ID_0, 0x00}, + {WCD9378_HID_FUNC_EXT_ID_1, 0x00}, + {WCD9378_HID_FUNC_EXT_VER, 0x00}, + {WCD9378_HID_FUNC_STAT, 0x67}, + {WCD9378_HID_CUR_OWNER, 0x01}, + {WCD9378_HID_MSG_OFFSET, 0x44000001}, + {WCD9378_HID_MSG_LENGTH, 0x04}, + {WCD9378_HID_DEV_MANU_ID_0, 0x17}, + {WCD9378_HID_DEV_MANU_ID_1, 0x02}, + {WCD9378_HID_DEV_PART_ID_0, 0x10}, + {WCD9378_HID_DEV_PART_ID_1, 0x01}, + {WCD9378_HID_DEV_VER, 0x10}, + {WCD9378_SMP_AMP_FUNC_EXT_ID_0, 0x00}, + {WCD9378_SMP_AMP_FUNC_EXT_ID_1, 0x00}, + {WCD9378_SMP_AMP_FUNC_EXT_VER, 0x00}, + {WCD9378_XU22_BYP, 0x01}, + {WCD9378_PDE22_REQ_PS, 0x03}, + {WCD9378_FU23_MUTE, 0x01}, + {WCD9378_PDE23_REQ_PS, 0x03}, + {WCD9378_SMP_AMP_FUNC_STAT, 0x67}, + {WCD9378_FUNC_ACT, 0x00}, + {WCD9378_PDE22_ACT_PS, 0x03}, + {WCD9378_SAPU29_PROT_MODE, 0x00}, + {WCD9378_SAPU29_PROT_STAT, 0x00}, + {WCD9378_PDE23_ACT_PS, 0x03}, + {WCD9378_SMP_AMP_DEV_MANU_ID_0, 0x17}, + {WCD9378_SMP_AMP_DEV_MANU_ID_1, 0x02}, + {WCD9378_SMP_AMP_DEV_PART_ID_0, 0x10}, + {WCD9378_SMP_AMP_DEV_PART_ID_1, 0x01}, + {WCD9378_SMP_AMP_DEV_VER, 0x10}, + {WCD9378_CMT_GRP_MASK, 0x00}, + {WCD9378_SMP_JACK_FUNC_EXT_ID_0, 0x00}, + {WCD9378_SMP_JACK_FUNC_EXT_ID_1, 0x00}, + {WCD9378_SMP_JACK_FUNC_EXT_VER, 0x00}, + {WCD9378_IT41_USAGE, 0x03}, + {WCD9378_XU42_BYP, 0x01}, + {WCD9378_PDE42_REQ_PS, 0x03}, + {WCD9378_FU42_MUTE_CH1, 0x01}, + {WCD9378_FU42_MUTE_CH2, 0x01}, + {WCD9378_FU42_MUTE_CH1_CN, 0x01}, + {WCD9378_FU42_MUTE_CH2_CN, 0x01}, + {WCD9378_FU42_CH_VOL_CH1, 0xe200}, + {WCD9378_FU42_CH_VOL_CH1_MSB, 0xe2}, + {WCD9378_FU42_CH_VOL_CH1_LSB, 0x00}, + {WCD9378_FU42_CH_VOL_CH2, 0xe200}, + {WCD9378_FU42_CH_VOL_CH2_MSB, 0xe2}, + {WCD9378_FU42_CH_VOL_CH2_LSB, 0x00}, + {WCD9378_SU43_SELECTOR, 0x01}, + {WCD9378_SU45_SELECTOR, 0x01}, + {WCD9378_PDE47_REQ_PS, 0x03}, + {WCD9378_GE35_SEL_MODE, 0x00}, + {WCD9378_GE35_DET_MODE, 0x00}, + {WCD9378_IT31_MICB, 0x00}, + {WCD9378_IT31_USAGE, 0x03}, + {WCD9378_PDE34_REQ_PS, 0x03}, + {WCD9378_SU45_TX_SELECTOR, 0x01}, + {WCD9378_XU36_BYP, 0x01}, + {WCD9378_PDE36_REQ_PS, 0x03}, + {WCD9378_OT36_USAGE, 0x03}, + {WCD9378_SMP_JACK_FUNC_STAT, 0x67}, + {WCD9378_SMP_JACK_FUNC_ACT, 0x00}, + {WCD9378_PDE42_ACT_PS, 0x03}, + {WCD9378_PDE47_ACT_PS, 0x03}, + {WCD9378_PDE34_ACT_PS, 0x03}, + {WCD9378_PDE36_ACT_PS, 0x03}, + {WCD9378_SMP_JACK_DEV_MANU_ID_0, 0x17}, + {WCD9378_SMP_JACK_DEV_MANU_ID_1, 0x02}, + {WCD9378_SMP_JACK_DEV_PART_ID_0, 0x10}, + {WCD9378_SMP_JACK_DEV_PART_ID_1, 0x01}, + {WCD9378_SMP_JACK_DEV_VER, 0x10}, + {WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_0, 0x00}, + {WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_1, 0x00}, + {WCD9378_SMP_MIC_CTRL0_FUNC_EXT_VER, 0x00}, + {WCD9378_IT11_MICB, 0x00}, + {WCD9378_IT11_USAGE, 0x03}, + {WCD9378_PDE11_REQ_PS, 0x03}, + {WCD9378_OT10_USAGE, 0x03}, + {WCD9378_SMP_MIC_CTRL0_FUNC_STAT, 0x67}, + {WCD9378_SMP_MIC_CTRL0_FUNC_ACT, 0x00}, + {WCD9378_PDE11_ACT_PS, 0x03}, + {WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_0, 0x17}, + {WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_1, 0x02}, + {WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_0, 0x10}, + {WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_1, 0x01}, + {WCD9378_SMP_MIC_CTRL0_DEV_VER, 0x10}, + {WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_0, 0x00}, + {WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_1, 0x00}, + {WCD9378_SMP_MIC_CTRL1_FUNC_EXT_VER, 0x00}, + {WCD9378_SMP_MIC_CTRL1_IT11_MICB, 0x00}, + {WCD9378_SMP_MIC_CTRL1_IT11_USAGE, 0x03}, + {WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS, 0x03}, + {WCD9378_SMP_MIC_CTRL1_OT10_USAGE, 0x03}, + {WCD9378_SMP_MIC_CTRL1_FUNC_STAT, 0x67}, + {WCD9378_SMP_MIC_CTRL1_FUNC_ACT, 0x00}, + {WCD9378_SMP_MIC_CTRL1_PDE11_ACT_PS, 0x03}, + {WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_0, 0x17}, + {WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_1, 0x02}, + {WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_0, 0x10}, + {WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_1, 0x01}, + {WCD9378_SMP_MIC_CTRL1_DEV_VER, 0x10}, + {WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_0, 0x00}, + {WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_1, 0x00}, + {WCD9378_SMP_MIC_CTRL2_FUNC_EXT_VER, 0x00}, + {WCD9378_SMP_MIC_CTRL2_IT11_MICB, 0x00}, + {WCD9378_SMP_MIC_CTRL2_IT11_USAGE, 0x03}, + {WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS, 0x03}, + {WCD9378_SMP_MIC_CTRL2_OT10_USAGE, 0x03}, + {WCD9378_SMP_MIC_CTRL2_FUNC_STAT, 0x67}, + {WCD9378_SMP_MIC_CTRL2_FUNC_ACT, 0x00}, + {WCD9378_SMP_MIC_CTRL2_PDE11_ACT_PS, 0x03}, + {WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_0, 0x17}, + {WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_1, 0x02}, + {WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_0, 0x10}, + {WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_1, 0x01}, + {WCD9378_SMP_MIC_CTRL2_DEV_VER, 0x10}, + {WCD9378_REPORT_ID, 0x01}, + {WCD9378_MESSAGE0, 0x00}, + {WCD9378_MESSAGE1, 0x00}, + {WCD9378_MESSAGE2, 0x00}, +}; + +static bool wcd9378_readable_register(struct device *dev, unsigned int reg) +{ + if (reg <= WCD9378_BASE) { + switch (reg) { + case SWRS_SCP_SDCA_INTSTAT_1: + case SWRS_SCP_SDCA_INTSTAT_2: + case SWRS_SCP_SDCA_INTSTAT_3: + case SWRS_SCP_SDCA_INTMASK_1: + case SWRS_SCP_SDCA_INTMASK_2: + case SWRS_SCP_SDCA_INTMASK_3: + case SWRS_SCP_SDCA_INTRTYPE_1: + case SWRS_SCP_SDCA_INTRTYPE_2: + case SWRS_SCP_SDCA_INTRTYPE_3: + break; + default: + return false; + } + } + + if (wcd9378_reg_access[WCD9378_REG(reg)] & RD_REG) + return true; + else + return false; +} + +static bool wcd9378_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg <= WCD9378_BASE) { + switch (reg) { + case SWRS_SCP_SDCA_INTSTAT_1: + case SWRS_SCP_SDCA_INTSTAT_2: + case SWRS_SCP_SDCA_INTSTAT_3: + case SWRS_SCP_SDCA_INTMASK_1: + case SWRS_SCP_SDCA_INTMASK_2: + case SWRS_SCP_SDCA_INTMASK_3: + case SWRS_SCP_SDCA_INTRTYPE_1: + case SWRS_SCP_SDCA_INTRTYPE_2: + case SWRS_SCP_SDCA_INTRTYPE_3: + break; + default: + return false; + } + } + + if (wcd9378_reg_access[WCD9378_REG(reg)] & WR_REG) + return true; + else + return false; +} + +static bool wcd9378_volatile_register(struct device *dev, unsigned int reg) +{ + + if (reg <= WCD9378_BASE) { + switch (reg) { + case SWRS_SCP_SDCA_INTSTAT_1: + case SWRS_SCP_SDCA_INTSTAT_2: + case SWRS_SCP_SDCA_INTSTAT_3: + case SWRS_SCP_SDCA_INTMASK_1: + case SWRS_SCP_SDCA_INTMASK_2: + case SWRS_SCP_SDCA_INTMASK_3: + case SWRS_SCP_SDCA_INTRTYPE_1: + case SWRS_SCP_SDCA_INTRTYPE_2: + case SWRS_SCP_SDCA_INTRTYPE_3: + return true; + default: + return false; + } + } + + if ((wcd9378_reg_access[WCD9378_REG(reg)] & RD_REG) && + !(wcd9378_reg_access[WCD9378_REG(reg)] & WR_REG)) + return true; + else + return false; +} + +struct regmap_config wcd9378_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd9378_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd9378_defaults), + .max_register = WCD9378_MAX_REGISTER, + .volatile_reg = wcd9378_volatile_register, + .readable_reg = wcd9378_readable_register, + .writeable_reg = wcd9378_writeable_register, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .can_multi_write = true, + .use_single_read = true, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-slave.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-slave.c new file mode 100644 index 0000000000..ec998f6962 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-slave.c @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_DEBUG_FS +#include +#include +#include + +#define SWR_SLV_MAX_REG_ADDR 0x2009 +#define SWR_SLV_START_REG_ADDR 0x40 +#define SWR_SLV_MAX_BUF_LEN 20 +#define BYTES_PER_LINE 12 +#define SWR_SLV_RD_BUF_LEN 8 +#define SWR_SLV_WR_BUF_LEN 32 +#define SWR_SLV_MAX_DEVICES 2 +#endif /* CONFIG_DEBUG_FS */ + +#define SWR_MAX_RETRY 5 + +struct wcd9378_slave_priv { + struct swr_device *swr_slave; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_wcd9378_dent; + struct dentry *debugfs_peek; + struct dentry *debugfs_poke; + struct dentry *debugfs_reg_dump; + unsigned int read_data; +#endif +}; + +#ifdef CONFIG_DEBUG_FS +static int get_parameters(char *buf, u32 *param1, int num_of_par) +{ + char *token = NULL; + int base = 0, cnt = 0; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +static bool is_swr_slv_reg_readable(int reg) +{ + int ret = true; + + if (((reg > 0x46) && (reg < 0x4A)) || + ((reg > 0x4A) && (reg < 0x50)) || + ((reg > 0x55) && (reg < 0xD0)) || + ((reg > 0xD0) && (reg < 0xE0)) || + ((reg > 0xE0) && (reg < 0xF0)) || + ((reg > 0xF0) && (reg < 0x100)) || + ((reg > 0x105) && (reg < 0x120)) || + ((reg > 0x205) && (reg < 0x220)) || + ((reg > 0x305) && (reg < 0x320)) || + ((reg > 0x405) && (reg < 0x420)) || + ((reg > 0x128) && (reg < 0x130)) || + ((reg > 0x228) && (reg < 0x230)) || + ((reg > 0x328) && (reg < 0x330)) || + ((reg > 0x428) && (reg < 0x430)) || + ((reg > 0x138) && (reg < 0x205)) || + ((reg > 0x238) && (reg < 0x305)) || + ((reg > 0x338) && (reg < 0x405)) || + ((reg > 0x438) && (reg < 0x2000))) + ret = false; + + return ret; +} + +static ssize_t wcd9378_swrslave_reg_show(struct swr_device *pdev, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[SWR_SLV_MAX_BUF_LEN]; + + if (!ubuf || !ppos) + return 0; + + for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR); + i <= SWR_SLV_MAX_REG_ADDR; i++) { + if (!is_swr_slv_reg_readable(i)) + continue; + swr_read(pdev, pdev->dev_num, i, ®_val, 1); + len = scnprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, + (reg_val & 0xFF)); + if (((total + len) >= count - 1) || (len < 0)) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + pr_err("%s: fail to copy reg dump\n", __func__); + total = -EFAULT; + goto copy_err; + } + total += len; + *ppos += len; + } + +copy_err: + *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE; + return total; +} + +static ssize_t codec_debug_dump(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct swr_device *pdev; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + return wcd9378_swrslave_reg_show(pdev, ubuf, count, ppos); +} + +static ssize_t codec_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char lbuf[SWR_SLV_RD_BUF_LEN]; + struct swr_device *pdev = NULL; + struct wcd9378_slave_priv *wcd9378_slave = NULL; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd9378_slave = swr_get_dev_data(pdev); + if (!wcd9378_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + snprintf(lbuf, sizeof(lbuf), "0x%x\n", + (wcd9378_slave->read_data & 0xFF)); + + return simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); +} + +static ssize_t codec_debug_peek_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev = NULL; + struct wcd9378_slave_priv *wcd9378_slave = NULL; + + if (!cnt || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd9378_slave = swr_get_dev_data(pdev); + if (!wcd9378_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 1); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))) + return -EINVAL; + swr_read(pdev, pdev->dev_num, param[0], &wcd9378_slave->read_data, 1); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static ssize_t codec_debug_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev; + + if (!file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 2); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && + (param[1] <= 0xFF) && (rc == 0))) + return -EINVAL; + swr_write(pdev, pdev->dev_num, param[0], ¶m[1]); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static const struct file_operations codec_debug_write_ops = { + .open = simple_open, + .write = codec_debug_write, +}; + +static const struct file_operations codec_debug_read_ops = { + .open = simple_open, + .read = codec_debug_read, + .write = codec_debug_peek_write, +}; + +static const struct file_operations codec_debug_dump_ops = { + .open = simple_open, + .read = codec_debug_dump, +}; +#endif + +static int wcd9378_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); + int retry = SWR_MAX_RETRY; + + if (!pdev) { + pr_err("%s: invalid swr device handle\n", __func__); + return -EINVAL; + } + + do { + /* Add delay for soundwire enumeration */ + usleep_range(100, 110); + ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); + } while (ret && --retry); + + if (ret) { + dev_dbg(&pdev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, devnum, pdev->addr); + ret = -EPROBE_DEFER; + return ret; + } + pdev->dev_num = devnum; + + return ret; +} + +static void wcd9378_slave_unbind(struct device *dev, + struct device *master, void *data) +{ + struct wcd9378_slave_priv *wcd9378_slave = NULL; + struct swr_device *pdev = to_swr_device(dev); + + wcd9378_slave = swr_get_dev_data(pdev); + if (!wcd9378_slave) { + dev_err(&pdev->dev, "%s: wcd9378_slave is NULL\n", __func__); + return; + } +} + +static const struct swr_device_id wcd9378_swr_id[] = { + {"wcd9378-slave", 0}, + {} +}; + +static const struct of_device_id wcd9378_swr_dt_match[] = { + { + .compatible = "qcom,wcd9378-slave", + }, + {} +}; + +static const struct component_ops wcd9378_slave_comp_ops = { + .bind = wcd9378_slave_bind, + .unbind = wcd9378_slave_unbind, +}; + +static int wcd9378_swr_probe(struct swr_device *pdev) +{ + struct wcd9378_slave_priv *wcd9378_slave = NULL; + + wcd9378_slave = devm_kzalloc(&pdev->dev, + sizeof(struct wcd9378_slave_priv), GFP_KERNEL); + if (!wcd9378_slave) + return -ENOMEM; + + swr_set_dev_data(pdev, wcd9378_slave); + + wcd9378_slave->swr_slave = pdev; + +#ifdef CONFIG_DEBUG_FS + if (!wcd9378_slave->debugfs_wcd9378_dent) { + wcd9378_slave->debugfs_wcd9378_dent = debugfs_create_dir( + dev_name(&pdev->dev), 0); + if (!IS_ERR(wcd9378_slave->debugfs_wcd9378_dent)) { + wcd9378_slave->debugfs_peek = + debugfs_create_file("swrslave_peek", + S_IFREG | 0444, + wcd9378_slave->debugfs_wcd9378_dent, + (void *) pdev, + &codec_debug_read_ops); + + wcd9378_slave->debugfs_poke = + debugfs_create_file("swrslave_poke", + S_IFREG | 0444, + wcd9378_slave->debugfs_wcd9378_dent, + (void *) pdev, + &codec_debug_write_ops); + + wcd9378_slave->debugfs_reg_dump = + debugfs_create_file( + "swrslave_reg_dump", + S_IFREG | 0444, + wcd9378_slave->debugfs_wcd9378_dent, + (void *) pdev, + &codec_debug_dump_ops); + } + } +#endif + + return component_add(&pdev->dev, &wcd9378_slave_comp_ops); +} + +static int wcd9378_swr_remove(struct swr_device *pdev) +{ +#ifdef CONFIG_DEBUG_FS + struct wcd9378_slave_priv *wcd9378_slave = swr_get_dev_data(pdev); + + if (wcd9378_slave) { + debugfs_remove_recursive(wcd9378_slave->debugfs_wcd9378_dent); + wcd9378_slave->debugfs_wcd9378_dent = NULL; + } +#endif + component_del(&pdev->dev, &wcd9378_slave_comp_ops); + swr_set_dev_data(pdev, NULL); + swr_remove_device(pdev); + + return 0; +} + +static struct swr_driver wcd9378_slave_driver = { + .driver = { + .name = "wcd9378-slave", + .owner = THIS_MODULE, + .of_match_table = wcd9378_swr_dt_match, + }, + .probe = wcd9378_swr_probe, + .remove = wcd9378_swr_remove, + .id_table = wcd9378_swr_id, +}; + +static int __init wcd9378_slave_init(void) +{ + return swr_driver_register(&wcd9378_slave_driver); +} + +static void __exit wcd9378_slave_exit(void) +{ + swr_driver_unregister(&wcd9378_slave_driver); +} + +module_init(wcd9378_slave_init); +module_exit(wcd9378_slave_exit); + +MODULE_DESCRIPTION("WCD9378 Swr Slave driver"); +MODULE_LICENSE("GPL"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-tables.c new file mode 100644 index 0000000000..744e808c79 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378-tables.c @@ -0,0 +1,851 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include "wcd9378-registers.h" + +const u8 wcd9378_reg_access[] = { + [WCD9378_REG(SWRS_SCP_SDCA_INTSTAT_1)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTSTAT_2)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTSTAT_3)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTMASK_1)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTMASK_2)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTMASK_3)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTRTYPE_1)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTRTYPE_2)] = RD_WR_REG, + [WCD9378_REG(SWRS_SCP_SDCA_INTRTYPE_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FUNC_EXT_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_FUNC_EXT_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_FUNC_EXT_VER)] = RD_REG, + [WCD9378_REG(WCD9378_FUNC_STAT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DEV_MANU_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_DEV_MANU_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_DEV_PART_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_DEV_PART_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_DEV_VER)] = RD_REG, + [WCD9378_REG(WCD9378_ANA_PAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_BIAS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_RX_SUPPLIES)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_HPH)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_EAR)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_EAR_COMPANDER_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_TX_CH1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_TX_CH2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_TX_CH3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_TX_CH3_HPF)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MICB1_MICB2_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MICB3_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_MECH)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_ELECT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_ZDET)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_RESULT_1)] = RD_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_RESULT_2)] = RD_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_RESULT_3)] = RD_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MBHC_BTN7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MICB1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MICB2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MICB2_RAMP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_MICB3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_BIAS_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_BIAS_VBG_FINE_ADJ)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LDOL_VDDCX_ADJUST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LDOL_DISABLE_LDOL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_CTL_CLK)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_CTL_ANA)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_CTL_SPARE_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_CTL_SPARE_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_CTL_BCS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_MOISTURE_DET_FSM_STATUS)] = RD_REG, + [WCD9378_REG(WCD9378_MBHC_TEST_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LDOH_MODE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LDOH_BIAS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LDOH_STB_LOADS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LDOH_SLOWRAMP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB1_TEST_CTL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB1_TEST_CTL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB1_TEST_CTL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB2_TEST_CTL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB2_TEST_CTL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB2_TEST_CTL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB3_TEST_CTL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB3_TEST_CTL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB3_TEST_CTL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_ADC_VCM)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_BIAS_ATEST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_SPARE1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_SPARE2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_TXFE_DIV_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_TXFE_DIV_START)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_SPARE3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_SPARE4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_1_2_TEST_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_1_2_ADC_IB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_1_2_ATEST_REFCTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_1_2_TEST_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_1_2_TEST_BLK_EN1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_1_2_TXFE1_CLKDIV)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_1_2_SAR2_ERR)] = RD_REG, + [WCD9378_REG(WCD9378_TX_1_2_SAR1_ERR)] = RD_REG, + [WCD9378_REG(WCD9378_TX_3_TEST_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_ADC_IB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_ATEST_REFCTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_TEST_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_TEST_BLK_EN3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_TXFE3_CLKDIV)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_SAR4_ERR)] = RD_REG, + [WCD9378_REG(WCD9378_TX_3_SAR3_ERR)] = RD_REG, + [WCD9378_REG(WCD9378_TX_3_TEST_BLK_EN2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_TXFE2_CLKDIV)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_SPARE1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_TEST_BLK_EN4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_SPARE2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_3_SPARE3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_AUX_SW_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_PA_AUX_IN_CONN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_TIMER_DIV)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_OCP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_OCP_COUNT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_EAR_DAC)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_EAR_AMP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_HPH_LDO)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_HPH_PA)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_HPH_RDACBUFF_CNP2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_HPH_RDAC_LDO)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_HPH_CNP1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_HPH_LOWPOWER)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_AUX_DAC)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_BIAS_AUX_AMP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_SPARE_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_SPARE_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_SPARE_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_SPARE_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_SPARE_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_SPARE_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_SPARE_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_L_STATUS)] = RD_REG, + [WCD9378_REG(WCD9378_HPH_R_STATUS)] = RD_REG, + [WCD9378_REG(WCD9378_HPH_CNP_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_CNP_WG_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_CNP_WG_TIME)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_OCP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_AUTO_CHOP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_CHOP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_PA_CTL1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_PA_CTL2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_L_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_L_TEST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_L_ATEST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_R_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_R_TEST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_R_ATEST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_RDAC_CLK_CTL1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_RDAC_CLK_CTL2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_RDAC_LDO_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_RDAC_CHOP_CLK_LP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_REFBUFF_UHQA_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_REFBUFF_LP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_L_DAC_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_R_DAC_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_SURGE_HPHLR_SURGE_COMP_SEL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_SURGE_HPHLR_SURGE_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_SURGE_HPHLR_SURGE_MISC1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_SURGE_HPHLR_SURGE_STATUS)] = RD_REG, + [WCD9378_REG(WCD9378_EAR_EAR_EN_REG)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_EAR_PA_CON)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_EAR_SP_CON)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_EAR_DAC_CON)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_EAR_CNP_FSM_CON)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_TEST_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_STATUS_REG_1)] = RD_REG, + [WCD9378_REG(WCD9378_EAR_STATUS_REG_2)] = RD_REG, + [WCD9378_REG(WCD9378_ANA_NEW_PAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_ANA_HPH2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_ANA_HPH3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SLEEP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SLEEP_WATCHDOG_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_ELECT_REM_CLAMP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_CTL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_CTL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_PLUG_DETECT_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_ZDET_ANA_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_ZDET_RAMP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_FSM_STATUS)] = RD_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_ADC_RESULT)] = RD_REG, + [WCD9378_REG(WCD9378_AUX_AUXPA)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DIE_CRACK_DIE_CRK_DET_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DIE_CRACK_DIE_CRK_DET_OUT)] = RD_REG, + [WCD9378_REG(WCD9378_TX_NEW_TX_CH12_MUX)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_NEW_TX_CH34_MUX)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_RDAC_VREF_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_PA_MISC1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_PA_MISC2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_PA_RDAC_MISC)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_HPH_TIMER1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_HPH_TIMER2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_HPH_TIMER3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_HPH_TIMER4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_PA_RDAC_MISC2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_NEW_INT_PA_RDAC_MISC3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_NEW_INT_HPH_RDAC_LDO_LP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CLASSG_CP_CTRL_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_VNEGDAC_CTRL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_VNEGDAC_CTRL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_VNEGDAC_CTRL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_VNEGDAC_CTRL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_8)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_9)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_10)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_11)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_12)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_13)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_14)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_15)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_16)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_17)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_18)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CP_CP_DTOP_CTRL_19)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_INT_MECH_DET_CURRENT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_NEW_INT_SPARE_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_INT_NEW_EAR_CHOPPER_CON)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_INT_NEW_CNP_VCM_CON1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_INT_NEW_CNP_VCM_CON2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EAR_INT_NEW_EAR_DYNAMIC_BIAS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_AUX_INT_EN_REG)] = RD_WR_REG, + [WCD9378_REG(WCD9378_AUX_INT_PA_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_AUX_INT_SP_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_AUX_INT_DAC_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_AUX_INT_CLK_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_AUX_INT_TEST_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_AUX_INT_STATUS_REG)] = RD_REG, + [WCD9378_REG(WCD9378_AUX_INT_MISC)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SLEEP_INT_WATCHDOG_CTL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SLEEP_INT_WATCHDOG_CTL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DIE_CRACK_INT_DIE_CRK_DET_INT2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXFE_DIVSTOP_L0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXFE_NINIT_L0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXADC_SCBIAS_L0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXADC_INT_L2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXADC_INT_L1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_TXADC_INT_L0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_COM_NEW_INT_SPARE8)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TAMBORA_PAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CHIP_ID0)] = RD_REG, + [WCD9378_REG(WCD9378_CHIP_ID1)] = RD_REG, + [WCD9378_REG(WCD9378_CHIP_ID2)] = RD_REG, + [WCD9378_REG(WCD9378_CHIP_ID3)] = RD_REG, + [WCD9378_REG(WCD9378_SWR_TX_CLK_RATE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_RST_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TOP_CLK_CFG)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_ANA_CLK_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_DIG_CLK_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_RST_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_PATH_MODE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_RX_RST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_RX0_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_RX1_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_RX2_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_TX_ANA_MODE_0_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_TX_ANA_MODE_2_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_COMP_CTL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_ANA_TX_CLK_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A1_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A1_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A2_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A2_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A3_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A3_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A4_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A4_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A5_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A5_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A6_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_A7_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_C_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_C_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_C_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_C_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_R1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_R2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_R3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_R4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_R5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_R6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_DSM_R7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A1_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A1_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A2_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A2_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A3_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A3_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A4_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A4_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A5_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A5_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A6_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_A7_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_C_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_C_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_C_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_C_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_R1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_R2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_R3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_R4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_R5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_R6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_DSM_R7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_GAIN_RX_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_GAIN_RX_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_GAIN_DSD_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_GAIN_DSD_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_GAIN_DSD_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_GAIN_DSD_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_GAIN_DSD_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_GAIN_DSD_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_HPH_GAIN_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AUX_GAIN_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_PATH_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_SWR_CLG)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_CLG_BYP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_TX0_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_TX1_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_TX2_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_TX_RST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_REQ_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_RST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_AMIC_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_DMIC_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_DMIC1_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_DMIC2_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_DMIC3_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EFUSE_PRG_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EFUSE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_DMIC_RATE_1_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CDC_DMIC_RATE_3_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDM_WD_EN_OVRD)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDM_WD_CTL0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDM_WD_CTL1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDM_WD_CTL2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RAMP_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ACT_DET_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ACT_DET_HOOKUP0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ACT_DET_HOOKUP1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ACT_DET_HOOKUP2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ACT_DET_DLY_BUF_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_MODE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_STATUS_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_STATUS_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_STATUS_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_STATUS_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_MASK_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_MASK_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_MASK_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_MASK_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_SET_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_SET_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_SET_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_SET_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_TEST_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_TEST_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_TEST_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_INTR_TEST_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_MODE_DBG_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_MODE_DBG_0_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_MODE_DBG_2_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LB_IN_SEL_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LOOP_BACK_MODE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_DAC_TEST)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_HM_TEST_RX_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_HM_TEST_TX_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_HM_TEST_RX_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_HM_TEST_TX_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SWR_HM_TEST_0)] = RD_REG, + [WCD9378_REG(WCD9378_PAD_CTL_SWR_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PAD_CTL_SWR_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_I2C_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_LEGACY_SW_MODE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EFUSE_TEST_CTL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EFUSE_TEST_CTL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EFUSE_T_DATA_0)] = RD_REG, + [WCD9378_REG(WCD9378_PAD_CTL_PDM_RX0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PAD_CTL_PDM_RX1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PAD_CTL_PDM_TX0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PAD_CTL_PDM_TX1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PAD_INP_DIS_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DRIVE_STRENGTH_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DRIVE_STRENGTH_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_GPIO_MODE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PIN_CTL_OE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PIN_CTL_DATA_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PIN_STATUS_0)] = RD_REG, + [WCD9378_REG(WCD9378_DIG_DEBUG_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DIG_DEBUG_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_CSR_DBG_ADD)] = RD_WR_REG, + [WCD9378_REG(WCD9378_ANA_CSR_DBG_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SSP_DBG)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MODE_STATUS_0)] = RD_REG, + [WCD9378_REG(WCD9378_MODE_STATUS_1)] = RD_REG, + [WCD9378_REG(WCD9378_SPARE_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SPARE_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SPARE_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_0)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_1)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_2)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_3)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_4)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_5)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_6)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_7)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_8)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_9)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_10)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_11)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_12)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_13)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_14)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_15)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_16)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_17)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_18)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_19)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_20)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_21)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_22)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_23)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_24)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_25)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_26)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_27)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_28)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_29)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_30)] = RD_REG, + [WCD9378_REG(WCD9378_EFUSE_REG_31)] = RD_REG, + [WCD9378_REG(WCD9378_TX_REQ_FB_CTL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_REQ_FB_CTL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX_REQ_FB_CTL_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DEM_BYPASS_DATA0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DEM_BYPASS_DATA1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DEM_BYPASS_DATA2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DEM_BYPASS_DATA3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX0_PCM_RAMP_STEP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX0_DSD_RAMP_STEP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX1_PCM_RAMP_STEP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX1_DSD_RAMP_STEP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_RX2_RAMP_STEP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PLATFORM_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_CLK_DIV_CFG)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DRE_DLY_VAL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SYS_USAGE_CTRL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SURGE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SEQ_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T8)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T9)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_T10)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T8)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T9)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_T10)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_8)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_9)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_UP_STAGE_LOC_10)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_8)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_9)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_DN_STAGE_LOC_10)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_T7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_T7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_UP_STAGE_LOC_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_DN_STAGE_LOC_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_UP_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_DN_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_UP_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_DN_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_T0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_T1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_T2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_T3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_UP_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_STAGE_LOC_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_STAGE_LOC_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_STAGE_LOC_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_DN_STAGE_LOC_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SEQ_HPH_STAT)] = RD_REG, + [WCD9378_REG(WCD9378_SEQ_SA_STAT)] = RD_REG, + [WCD9378_REG(WCD9378_SEQ_TX0_STAT)] = RD_REG, + [WCD9378_REG(WCD9378_SEQ_TX1_STAT)] = RD_REG, + [WCD9378_REG(WCD9378_SEQ_TX2_STAT)] = RD_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_4)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_5)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_6)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_7)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_8)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_9)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_10)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_11)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_12)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_13)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_14)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MICB_REMAP_TABLE_VAL_15)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SM0_MB_SEL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SM1_MB_SEL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SM2_MB_SEL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MB_PULLUP_EN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_BYP_EN_CTL0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_BYP_EN_CTL1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_BYP_EN_CTL2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SEQ_OVRRIDE_CTL0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SEQ_OVRRIDE_CTL1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SEQ_OVRRIDE_CTL2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_SEQ_OVRRIDE_CTL0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HPH_SEQ_OVRRIDE_CTL1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SA_SEQ_OVRRIDE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX0_SEQ_OVRRIDE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX1_SEQ_OVRRIDE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TX2_SEQ_OVRRIDE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FORCE_CTL)] = RD_WR_REG, + [WCD9378_REG(WCD9378_DEVICE_DET)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MIN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TPRESS_MAX_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MIN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_TRELEASE_MAX_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_HDL_BT_ASSIGN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE0_WRAP_OSCNX_OUTPUT_SEL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RTC_OOC_SEL_0)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RTC_OOC_SEL_1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RTC_OOC_SEL_2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MIN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TPRESS_MAX_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MIN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_TRELEASE_MAX_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_HDL_BT_ASSIGN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_OSCNX_OUTPUT_SEL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TPRESS_MIN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_TRELEASE_MIN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_HOLD_HDL_BT_ASSIGN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_TDEBOUNCE_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RO_HDL_BT_ASSIGN_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_TYPE1_WRAP_RTC_OOC_SEL_3)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SDCA_MESSAGE_GATE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_DATA_IN_EDGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_RESET)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_DEBUG)] = RD_WR_REG, + [WCD9378_REG(WCD9378_MBHC_DEBUG_UMP_0)] = RD_REG, + [WCD9378_REG(WCD9378_MBHC_DEBUG_UMP_1)] = RD_REG, + [WCD9378_REG(WCD9378_MBHC_DEBUG_UMP_2)] = RD_REG, + [WCD9378_REG(WCD9378_HID_FUNC_EXT_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_HID_FUNC_EXT_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_HID_FUNC_EXT_VER)] = RD_REG, + [WCD9378_REG(WCD9378_HID_FUNC_STAT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HID_CUR_OWNER)] = RD_WR_REG, + [WCD9378_REG(WCD9378_HID_MSG_OFFSET)] = RD_REG, + [WCD9378_REG(WCD9378_HID_MSG_LENGTH)] = RD_REG, + [WCD9378_REG(WCD9378_HID_DEV_MANU_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_HID_DEV_MANU_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_HID_DEV_PART_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_HID_DEV_PART_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_HID_DEV_VER)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_FUNC_EXT_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_FUNC_EXT_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_FUNC_EXT_VER)] = RD_REG, + [WCD9378_REG(WCD9378_XU22_BYP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE22_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU23_MUTE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE23_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_AMP_FUNC_STAT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FUNC_ACT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE22_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_SAPU29_PROT_MODE)] = RD_REG, + [WCD9378_REG(WCD9378_SAPU29_PROT_STAT)] = RD_REG, + [WCD9378_REG(WCD9378_PDE23_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_DEV_MANU_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_DEV_MANU_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_DEV_PART_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_DEV_PART_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_AMP_DEV_VER)] = RD_REG, + [WCD9378_REG(WCD9378_CMT_GRP_MASK)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_JACK_FUNC_EXT_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_FUNC_EXT_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_FUNC_EXT_VER)] = RD_REG, + [WCD9378_REG(WCD9378_IT41_USAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_XU42_BYP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE42_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_MUTE_CH1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_MUTE_CH2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_MUTE_CH1_CN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_MUTE_CH2_CN)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_CH_VOL_CH1)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_CH_VOL_CH1_MSB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_CH_VOL_CH1_LSB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_CH_VOL_CH2)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_CH_VOL_CH2_MSB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_FU42_CH_VOL_CH2_LSB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SU43_SELECTOR)] = RD_REG, + [WCD9378_REG(WCD9378_SU45_SELECTOR)] = RD_REG, + [WCD9378_REG(WCD9378_PDE47_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_GE35_SEL_MODE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_GE35_DET_MODE)] = RD_REG, + [WCD9378_REG(WCD9378_IT31_MICB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_IT31_USAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE34_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SU45_TX_SELECTOR)] = RD_REG, + [WCD9378_REG(WCD9378_XU36_BYP)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE36_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_OT36_USAGE)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_FUNC_STAT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_JACK_FUNC_ACT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE42_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_PDE47_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_PDE34_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_PDE36_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_DEV_MANU_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_DEV_MANU_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_DEV_PART_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_DEV_PART_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_JACK_DEV_VER)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_FUNC_EXT_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_FUNC_EXT_VER)] = RD_REG, + [WCD9378_REG(WCD9378_IT11_MICB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_IT11_USAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE11_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_OT10_USAGE)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_FUNC_STAT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_FUNC_ACT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_PDE11_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_DEV_MANU_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_DEV_PART_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL0_DEV_VER)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_FUNC_EXT_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_FUNC_EXT_VER)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_IT11_MICB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_IT11_USAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_OT10_USAGE)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_FUNC_STAT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_FUNC_ACT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_PDE11_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_DEV_MANU_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_DEV_PART_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL1_DEV_VER)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_FUNC_EXT_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_FUNC_EXT_VER)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_IT11_MICB)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_IT11_USAGE)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_OT10_USAGE)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_FUNC_STAT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_FUNC_ACT)] = RD_WR_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_PDE11_ACT_PS)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_DEV_MANU_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_0)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_DEV_PART_ID_1)] = RD_REG, + [WCD9378_REG(WCD9378_SMP_MIC_CTRL2_DEV_VER)] = RD_REG, + [WCD9378_REG(WCD9378_REPORT_ID)] = RD_REG, + [WCD9378_REG(WCD9378_MESSAGE0)] = RD_REG, + [WCD9378_REG(WCD9378_MESSAGE1)] = RD_REG, + [WCD9378_REG(WCD9378_MESSAGE2)] = RD_REG, +}; + diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378.c new file mode 100644 index 0000000000..11d37ce992 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378.c @@ -0,0 +1,4710 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wcd9378-reg-masks.h" +#include "wcd9378.h" +#include "internal.h" +#include "asoc/bolero-slave-internal.h" + +#define NUM_SWRS_DT_PARAMS 5 + +#define WCD9378_MOBILE_MODE 0x01 + +#define WCD9378_VERSION_1_0 1 +#define WCD9378_VERSION_ENTRY_SIZE 32 + +#define SWR_BASECLK_19P2MHZ (0x01) +#define SWR_BASECLK_24P576MHZ (0x03) +#define SWR_BASECLK_22P5792MHZ (0x04) + +#define SWR_CLKSCALE_DIV2 (0x02) +#define SWR_CLKSCALE_DIV4 (0x03) + +#define ADC_MODE_VAL_HIFI 0x01 +#define ADC_MODE_VAL_NORMAL 0x03 +#define ADC_MODE_VAL_LP 0x05 + +#define PWR_LEVEL_LOHIFI_VAL 0x00 +#define PWR_LEVEL_LP_VAL 0x01 +#define PWR_LEVEL_HIFI_VAL 0x02 +#define PWR_LEVEL_ULP_VAL 0x03 + +#define MICB_USAGE_VAL_DISABLE 0x00 +#define MICB_USAGE_VAL_PULL_DOWN 0x01 +#define MICB_USAGE_VAL_1P2V 0x02 +#define MICB_USAGE_VAL_1P8VORPULLUP 0x03 +#define MICB_USAGE_VAL_2P5V 0x04 +#define MICB_USAGE_VAL_2P75V 0x05 + +#define MICB_USAGE_VAL_2P2V 0xF0 +#define MICB_USAGE_VAL_2P7V 0xF1 +#define MICB_USAGE_VAL_2P8V 0xF2 + +#define MICB_USAGE_VAL_MICB1_TABLE_VAL 0xF3 +#define MICB_USAGE_VAL_MICB2_TABLE_VAL 0xF4 +#define MICB_USAGE_VAL_MICB3_TABLE_VAL 0xF5 + +#define WCD_TX_SYS_USAGE_BIT_MASK (0xFC) +#define WCD_RX_SYS_USAGE_BIT_MASK (0x1F00) + +#define MICB_NUM_MAX 3 + +#define NUM_ATTEMPTS 20 + +#define WCD9378_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD9378_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WCD9378_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define WCD9378_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = wcd9378_ear_pa_put_gain, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + +#define WCD9378_AUX_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = wcd9378_aux_pa_put_gain, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + +enum { + CODEC_TX = 0, + CODEC_RX, +}; + +enum { + RX2_HP_MODE, + RX2_NORMAL_MODE, +}; + +enum { + CLASS_AB_EN = 0, + TX1_FOR_JACK, + TX2_AMIC4_EN, + TX2_AMIC1_EN, + TX1_AMIC3_EN, + TX1_AMIC2_EN, + TX0_AMIC2_EN, + TX0_AMIC1_EN, + RX2_EAR_EN, + RX2_AUX_EN, + RX1_AUX_EN, + RX0_EAR_EN, + RX0_RX1_HPH_EN, +}; + +enum { + WCD_ADC1 = 0, + WCD_ADC2, + WCD_ADC3, + WCD_ADC4, + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, + WCD_ADC1_MODE, + WCD_ADC2_MODE, + WCD_ADC3_MODE, + WCD_ADC4_MODE, + WCD_AUX_EN, + WCD_EAR_EN, +}; + +enum { + SYS_USAGE_0, + SYS_USAGE_1, + SYS_USAGE_2, + SYS_USAGE_3, + SYS_USAGE_4, + SYS_USAGE_5, + SYS_USAGE_6, + SYS_USAGE_7, + SYS_USAGE_8, + SYS_USAGE_9, + SYS_USAGE_10, + SYS_USAGE_11, + SYS_USAGE_12, + SYS_USAGE_NUM, +}; + +enum { + NO_MICB_USED, + MICB1, + MICB2, + MICB3, + MICB_NUM, +}; + +enum { + ADC_MODE_INVALID = 0, + ADC_MODE_HIFI, + ADC_MODE_NORMAL, + ADC_MODE_LP, +}; + +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000); + +static int wcd9378_reset(struct device *dev); +static int wcd9378_reset_low(struct device *dev); +static void wcd9378_class_load(struct snd_soc_component *component); + +/* sys_usage: + * rx0_rx1_hph_en, + * rx0_ear_en, rx1_aux_en, rx2_aux_en, rx2_ear_en, + * tx0_amic1_en, tx0_amic2_en, tx1_amic2_en, tx1_amic3_en, + * tx2_amic1_en, tx2_amic4_en, tx1_for_jack, class_ab_en; + */ +static const int sys_usage[SYS_USAGE_NUM] = { + [SYS_USAGE_0] = 0x0c95, /*0b0 1100 1001 0101*/ + [SYS_USAGE_1] = 0x12a7, /*0b1 0010 1010 0111*/ + [SYS_USAGE_2] = 0x0c99, /*0b0 1100 1001 1001*/ + [SYS_USAGE_3] = 0x1aab, /*0b1 1010 1010 1011*/ + [SYS_USAGE_4] = 0x0894, /*0b0 1000 1001 0100*/ + [SYS_USAGE_5] = 0x11a6, /*0b1 0001 1010 0110*/ + [SYS_USAGE_6] = 0x0898, /*0b0 1000 1001 1000*/ + [SYS_USAGE_7] = 0x11ab, /*0b1 0001 1010 1011*/ + [SYS_USAGE_8] = 0x126a, /*0b1 0010 0110 1010*/ + [SYS_USAGE_9] = 0x116b, /*0b1 0001 0110 1011*/ + [SYS_USAGE_10] = 0x1ca7, /*0b1 1100 1010 0111*/ + [SYS_USAGE_11] = 0x1195, /*0b1 0001 1001 0101*/ + [SYS_USAGE_12] = 0x1296, /*0b1 0010 1001 0101*/ +}; + +static const struct regmap_irq wcd9378_regmap_irqs[WCD9378_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD9378_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(WCD9378_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(WCD9378_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(WCD9378_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(WCD9378_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(WCD9378_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(WCD9378_IRQ_EAR_SCD_INT, 1, 0x04), + REGMAP_IRQ_REG(WCD9378_IRQ_AUX_CNP_INT, 1, 0x08), + REGMAP_IRQ_REG(WCD9378_IRQ_AUX_SCD_INT, 1, 0x10), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(WCD9378_IRQ_AUX_PDM_WD_INT, 1, 0x80), + REGMAP_IRQ_REG(WCD9378_IRQ_LDORT_SCD_INT, 2, 0x01), + REGMAP_IRQ_REG(WCD9378_IRQ_MBHC_MOISTURE_INT, 2, 0x02), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(WCD9378_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), + REGMAP_IRQ_REG(WCD9378_IRQ_SAPU_PROT_MODE_CHG, 2, 0x40), +}; + +static int wcd9378_handle_post_irq(void *data) +{ + struct wcd9378_priv *wcd9378 = data; + u32 sts1 = 0, sts2 = 0, sts3 = 0; + + regmap_write(wcd9378->regmap, SWRS_SCP_SDCA_INTSTAT_1, 0xff); + regmap_write(wcd9378->regmap, SWRS_SCP_SDCA_INTSTAT_2, 0xff); + regmap_write(wcd9378->regmap, SWRS_SCP_SDCA_INTSTAT_3, 0xff); + + regmap_read(wcd9378->regmap, SWRS_SCP_SDCA_INTSTAT_1, &sts1); + regmap_read(wcd9378->regmap, SWRS_SCP_SDCA_INTSTAT_2, &sts2); + regmap_read(wcd9378->regmap, SWRS_SCP_SDCA_INTSTAT_3, &sts3); + + wcd9378->tx_swr_dev->slave_irq_pending = + ((sts1 || sts2 || sts3) ? true : false); + + return IRQ_HANDLED; +} + +static struct regmap_irq_chip wcd9378_regmap_irq_chip = { + .name = "wcd9378", + .irqs = wcd9378_regmap_irqs, + .num_irqs = ARRAY_SIZE(wcd9378_regmap_irqs), + .num_regs = 3, + .status_base = SWRS_SCP_SDCA_INTSTAT_1, + .unmask_base = SWRS_SCP_SDCA_INTMASK_1, + .type_base = SWRS_SCP_SDCA_INTRTYPE_1, + .ack_base = SWRS_SCP_SDCA_INTSTAT_1, + .use_ack = 1, + .runtime_pm = false, + .handle_post_irq = wcd9378_handle_post_irq, + .irq_drv_data = NULL, +}; + +static int wcd9378_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum) +{ + int ret = 0; + int bank = 0; + + ret = swr_read(dev, devnum, SWR_SCP_CONTROL, &bank, 1); + if (ret) + return -EINVAL; + + return ((bank & 0x40) ? 1 : 0); +} + +static int wcd9378_swr_reset_check(struct wcd9378_priv *wcd9378, int path) +{ + if (((path == TX_PATH) && + (wcd9378->sys_usage_status & WCD_TX_SYS_USAGE_BIT_MASK)) || + ((path == RX_PATH) && + (wcd9378->sys_usage_status & WCD_RX_SYS_USAGE_BIT_MASK))) + return false; + + return true; +} + +static int wcd9378_swr_slvdev_datapath_control(struct device *dev, + int path, bool enable) +{ + struct wcd9378_priv *wcd9378 = NULL; + struct swr_device *swr_dev = NULL; + int bank = 0, ret = 0; + u8 clk_rst = 0x00, scale_rst = 0x00; + u8 swr_clk = 0, clk_scale = 0; + u16 scale_reg = 0, scale_reg2 = 0; + + wcd9378 = dev_get_drvdata(dev); + if (!wcd9378) + return -EINVAL; + + if (path == RX_PATH) { + swr_dev = wcd9378->rx_swr_dev; + swr_clk = wcd9378->rx_swrclk; + clk_scale = wcd9378->rx_clkscale; + } else { + swr_dev = wcd9378->tx_swr_dev; + swr_clk = wcd9378->tx_swrclk; + clk_scale = wcd9378->tx_clkscale; + } + + bank = (wcd9378_swr_slv_get_current_bank(swr_dev, + swr_dev->dev_num) ? 0 : 1); + + scale_reg = (bank ? SWRS_SCP_BUSCLOCK_SCALE_BANK1 : + SWRS_SCP_BUSCLOCK_SCALE_BANK0); + scale_reg2 = (!bank ? SWRS_SCP_BUSCLOCK_SCALE_BANK1 : + SWRS_SCP_BUSCLOCK_SCALE_BANK0); + + if (enable) { + swr_write(swr_dev, swr_dev->dev_num, + SWRS_SCP_BASE_CLK_BASE, &swr_clk); + swr_write(swr_dev, swr_dev->dev_num, + scale_reg, &clk_scale); + swr_write(swr_dev, swr_dev->dev_num, + scale_reg2, &clk_scale); + ret = swr_slvdev_datapath_control(swr_dev, + swr_dev->dev_num, true); + } else { + if (wcd9378_swr_reset_check(wcd9378, path)) { + swr_write(swr_dev, swr_dev->dev_num, + SWRS_SCP_BASE_CLK_BASE, &clk_rst); + swr_write(swr_dev, swr_dev->dev_num, + scale_reg, &scale_rst); + swr_write(swr_dev, swr_dev->dev_num, + scale_reg2, &scale_rst); + } + ret = swr_slvdev_datapath_control(swr_dev, + swr_dev->dev_num, false); + } + + return ret; +} + +static int wcd9378_init_reg(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + u32 val = 0; + + val = snd_soc_component_read(component, WCD9378_EFUSE_REG_16); + if (!val) + snd_soc_component_update_bits(component, WCD9378_MBHC_CTL_SPARE_1, + WCD9378_MBHC_CTL_SPARE_1_BIASGEN_RES_CTRL_MASK, + 0x03); + else + snd_soc_component_update_bits(component, WCD9378_MBHC_CTL_SPARE_1, + WCD9378_MBHC_CTL_SPARE_1_BIASGEN_RES_CTRL_MASK, + 0x01); + + /*0.9 Volts*/ + snd_soc_component_update_bits(component, WCD9378_SLEEP_CTL, + WCD9378_SLEEP_CTL_BG_CTL_MASK, 0x0E); + /*BG_EN ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_SLEEP_CTL, + WCD9378_SLEEP_CTL_BG_EN_MASK, 0x80); + usleep_range(1000, 1010); + /*LDOL_BG_SEL SLEEP_BG*/ + snd_soc_component_update_bits(component, WCD9378_SLEEP_CTL, + WCD9378_SLEEP_CTL_LDOL_BG_SEL_MASK, 0x40); + usleep_range(1000, 1010); + + /*Start up analog master bias. Sequence cannot change*/ + /*VBG_FINE_ADJ 0.005 Volts*/ + snd_soc_component_update_bits(component, WCD9378_BIAS_VBG_FINE_ADJ, + WCD9378_BIAS_VBG_FINE_ADJ_VBG_FINE_ADJ_MASK, 0xB0); + + /*ANALOG_BIAS_EN ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_ANA_BIAS, + WCD9378_ANA_BIAS_ANALOG_BIAS_EN_MASK, 0x80); + /*PRECHRG_EN ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_ANA_BIAS, + WCD9378_ANA_BIAS_PRECHRG_EN_MASK, 0x40); + usleep_range(10000, 10010); + /*PRECHRG_EN DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_ANA_BIAS, + WCD9378_ANA_BIAS_PRECHRG_EN_MASK, 0x00); + /*End Analog Master Bias enable*/ + + /*ANA_TXSCBIAS_CLK_EN ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_ANA_TX_CLK_CTL, + WCD9378_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN_MASK, 0x01); + /*SEQ_BYPASS ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_TX_COM_TXFE_DIV_CTL, + WCD9378_TX_COM_TXFE_DIV_CTL_SEQ_BYPASS_MASK, 0x80); + /*TIME_OUT_SEL_PCM 160_CYCLES*/ + snd_soc_component_update_bits(component, WCD9378_PDM_WD_CTL0, + WCD9378_PDM_WD_CTL0_TIME_OUT_SEL_PCM_MASK, 0x10); + /*TIME_OUT_SEL_PCM 160_CYCLES*/ + snd_soc_component_update_bits(component, WCD9378_PDM_WD_CTL1, + WCD9378_PDM_WD_CTL1_TIME_OUT_SEL_PCM_MASK, 0x10); + /*IBIAS_LDO_DRIVER 5e-06*/ + snd_soc_component_update_bits(component, WCD9378_MICB1_TEST_CTL_2, + WCD9378_MICB1_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK, 0x01); + /*IBIAS_LDO_DRIVER 5e-06*/ + snd_soc_component_update_bits(component, WCD9378_MICB2_TEST_CTL_2, + WCD9378_MICB2_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK, 0x01); + /*IBIAS_LDO_DRIVER 5e-06*/ + snd_soc_component_update_bits(component, WCD9378_MICB3_TEST_CTL_2, + WCD9378_MICB3_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK, 0x01); + + /*HD2_RES_DIV_CTL_L 82.77*/ + snd_soc_component_update_bits(component, WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L, + WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L_MASK, 0x04); + /*HD2_RES_DIV_CTL_R 82.77*/ + snd_soc_component_update_bits(component, WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD9378_HPH_NEW_INT_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R_MASK, 0x04); + + /*RDAC_GAINCTL 0.55*/ + snd_soc_component_update_bits(component, WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL, + WCD9378_HPH_NEW_INT_RDAC_GAIN_CTL_RDAC_GAINCTL_MASK, 0x50); + /*HPH_UP_T0: 0.002*/ + snd_soc_component_update_bits(component, WCD9378_HPH_UP_T0, + WCD9378_HPH_UP_T0_HPH_UP_T0_MASK, 0x05); + /*HPH_UP_T9: 0.002*/ + snd_soc_component_update_bits(component, WCD9378_HPH_UP_T9, + WCD9378_HPH_UP_T9_HPH_UP_T9_MASK, 0x05); + /*HPH_DN_T0: 0.007*/ + snd_soc_component_update_bits(component, WCD9378_HPH_DN_T0, + WCD9378_HPH_DN_T0_HPH_DN_T0_MASK, 0x06); + + /*SM0 MB SEL:MB1*/ + snd_soc_component_update_bits(component, WCD9378_SM0_MB_SEL, + WCD9378_SM0_MB_SEL_SM0_MB_SEL_MASK, 0x01); + /*SM1 MB SEL:MB2*/ + snd_soc_component_update_bits(component, WCD9378_SM1_MB_SEL, + WCD9378_SM1_MB_SEL_SM1_MB_SEL_MASK, 0x02); + /*SM2 MB SEL:MB3*/ + snd_soc_component_update_bits(component, WCD9378_SM2_MB_SEL, + WCD9378_SM2_MB_SEL_SM2_MB_SEL_MASK, 0x03); + + /*INIT SYS_USAGE*/ + snd_soc_component_update_bits(component, + WCD9378_SYS_USAGE_CTRL, + WCD9378_SYS_USAGE_CTRL_SYS_USAGE_CTRL_MASK, + 0); + wcd9378->sys_usage = 0; + + wcd9378_class_load(component); + return 0; +} + +static int wcd9378_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 = 0; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT]; + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + switch (path) { + case CODEC_RX: + map = &wcd9378->rx_port_mapping; + num_ports = wcd9378->num_rx_ports; + break; + case CODEC_TX: + map = &wcd9378->tx_port_mapping; + num_ports = wcd9378->num_tx_ports; + break; + default: + dev_err(component->dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + for (i = 0; i <= num_ports; i++) { + for (j = 0; j < MAX_CH_PER_PORT; j++) { + if ((*map)[i][j].slave_port_type == slv_prt_type) + goto found; + } + } +found: + if (i > num_ports || j == MAX_CH_PER_PORT) { + dev_err(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 wcd9378_parse_port_params(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, max_uc; + int ret = 0; + u32 cnt = 0; + u32 i, j; + struct swr_port_params (*map)[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config (*map_uc)[SWR_UC_MAX]; + struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev); + + switch (path) { + case CODEC_TX: + map = &wcd9378->tx_port_params; + map_uc = &wcd9378->swr_tx_port_params; + break; + default: + ret = -EINVAL; + goto err_port_map; + } + + 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; + } + + max_uc = map_size / (SWR_NUM_PORTS * SWR_PORT_PARAMS * sizeof(u32)); + + if (max_uc != SWR_UC_MAX) { + dev_err(dev, "%s: port params not provided for all usecases\n", + __func__); + ret = -EINVAL; + goto err_port_map; + } + 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, + SWR_NUM_PORTS * SWR_PORT_PARAMS * max_uc); + 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 < max_uc; i++) { + for (j = 0; j < SWR_NUM_PORTS; j++) { + cnt = (i * SWR_NUM_PORTS + j) * SWR_PORT_PARAMS; + (*map)[i][j].offset1 = dt_array[cnt]; + (*map)[i][j].lane_ctrl = dt_array[cnt + 1]; + } + (*map_uc)[i].pp = &(*map)[i][0]; + } + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static int wcd9378_parse_port_mapping(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, map_length; + u32 port_num = 0, 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 = NULL; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT]; + struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev); + + switch (path) { + case CODEC_RX: + map = &wcd9378->rx_port_mapping; + num_ports = &wcd9378->num_rx_ports; + break; + case CODEC_TX: + map = &wcd9378->tx_port_mapping; + num_ports = &wcd9378->num_tx_ports; + break; + default: + dev_err(dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + 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].slave_port_type = slave_port_type; + (*map)[port_num][ch_iter].ch_mask = ch_mask; + (*map)[port_num][ch_iter].master_port_type = master_port_type; + (*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask); + (*map)[port_num][ch_iter++].ch_rate = ch_rate; + old_port_num = port_num; + } + *num_ports = port_num; + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static int wcd9378_tx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, int clk_rate, + u8 enable) +{ + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + u8 port_id, num_ch, ch_mask; + u8 ch_type = 0; + u32 ch_rate; + int slave_ch_idx; + u8 num_port = 1; + int ret = 0; + + ret = wcd9378_set_port_params(component, slv_port_type, &port_id, + &num_ch, &ch_mask, &ch_rate, + &ch_type, CODEC_TX); + if (ret) + return ret; + + if (clk_rate) + ch_rate = clk_rate; + + slave_ch_idx = wcd9378_slave_get_slave_ch_val(slv_port_type); + if (slave_ch_idx != -EINVAL) + ch_type = wcd9378->tx_master_ch_map[slave_ch_idx]; + + dev_dbg(component->dev, "%s slv_ch_idx: %d, mstr_ch_type: %d\n", + __func__, slave_ch_idx, ch_type); + + if (enable) + ret = swr_connect_port(wcd9378->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &ch_type); + else + ret = swr_disconnect_port(wcd9378->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_type); + return ret; + +} + +static int wcd9378_rx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct wcd9378_priv *wcd9378 = 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 = wcd9378_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(wcd9378->rx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + else + ret = swr_disconnect_port(wcd9378->rx_swr_dev, &port_id, + num_port, &ch_mask, &port_type); + return ret; +} + + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + int mode = wcd9378->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) { + wcd9378_rx_connect_port(component, CLSH, + SND_SOC_DAPM_EVENT_ON(event)); + } + if (SND_SOC_DAPM_EVENT_OFF(event)) + ret = wcd9378_swr_slvdev_datapath_control(wcd9378->dev, + RX_PATH, false); + + return ret; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + u32 dmic_clk_reg, dmic_clk_en_reg; + s32 *dmic_clk_cnt; + u8 dmic_ctl_shift = 0; + u8 dmic_clk_shift = 0; + u8 dmic_clk_mask = 0; + u32 dmic2_left_en = 0; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (w->shift) { + case 0: + case 1: + dmic_clk_cnt = &(wcd9378->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD9378_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD9378_CDC_DMIC1_CTL; + dmic_clk_mask = 0x0F; + dmic_clk_shift = 0x00; + dmic_ctl_shift = 0x00; + break; + case 2: + dmic2_left_en = WCD9378_CDC_DMIC2_CTL; + fallthrough; + case 3: + dmic_clk_cnt = &(wcd9378->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD9378_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD9378_CDC_DMIC2_CTL; + dmic_clk_mask = 0xF0; + dmic_clk_shift = 0x04; + dmic_ctl_shift = 0x01; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd9378->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD9378_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD9378_CDC_DMIC3_CTL; + dmic_clk_mask = 0x0F; + dmic_clk_shift = 0x00; + dmic_ctl_shift = 0x02; + break; + default: + dev_err_ratelimited(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, (w->shift + 1), *dmic_clk_cnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD9378_CDC_AMIC_CTL, + (0x01 << dmic_ctl_shift), 0x00); + /* 250us sleep as per HW requirement */ + usleep_range(250, 260); + if (dmic2_left_en) + snd_soc_component_update_bits(component, + dmic2_left_en, 0x80, 0x80); + /* Setting DMIC clock rate to 2.4MHz */ + snd_soc_component_update_bits(component, + dmic_clk_reg, dmic_clk_mask, + (0x03 << dmic_clk_shift)); + snd_soc_component_update_bits(component, + dmic_clk_en_reg, 0x08, 0x08); + /* enable clock scaling */ + snd_soc_component_update_bits(component, + WCD9378_CDC_DMIC_CTL, 0x06, 0x06); + ret = swr_slvdev_datapath_control(wcd9378->tx_swr_dev, + wcd9378->tx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9378_tx_connect_port(component, DMIC0 + (w->shift), 0, + false); + snd_soc_component_update_bits(component, + WCD9378_CDC_AMIC_CTL, + (0x01 << dmic_ctl_shift), + (0x01 << dmic_ctl_shift)); + if (dmic2_left_en) + snd_soc_component_update_bits(component, + dmic2_left_en, 0x80, 0x00); + snd_soc_component_update_bits(component, + dmic_clk_en_reg, 0x08, 0x00); + break; + }; + return ret; +} + +/* + * wcd9378_get_micb_vout_ctl_val: converts micbias from volts to register value + * @micb_mv: micbias in mv + * + * return register value converted + */ +int wcd9378_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_GPL(wcd9378_get_micb_vout_ctl_val); + +/* + * wcd9378_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 + */ +static int wcd9378_micb_table_value_set(struct snd_soc_component *component, + u32 micb_mv, int micb_num) +{ + int vcout_ctl; + + switch (micb_mv) { + case 2200: + return MICB_USAGE_VAL_2P2V; + case 2700: + return MICB_USAGE_VAL_2P7V; + case 2800: + return MICB_USAGE_VAL_2P8V; + default: + vcout_ctl = wcd9378_get_micb_vout_ctl_val(micb_mv); + if (micb_num == MIC_BIAS_1) { + snd_soc_component_update_bits(component, + WCD9378_MICB_REMAP_TABLE_VAL_3, + WCD9378_MICB_REMAP_TABLE_VAL_3_MICB_REMAP_TABLE_VAL_3_MASK, + vcout_ctl); + return MICB_USAGE_VAL_MICB1_TABLE_VAL; + } else if (micb_num == MIC_BIAS_2) { + snd_soc_component_update_bits(component, + WCD9378_MICB_REMAP_TABLE_VAL_4, + WCD9378_MICB_REMAP_TABLE_VAL_4_MICB_REMAP_TABLE_VAL_4_MASK, + vcout_ctl); + return MICB_USAGE_VAL_MICB2_TABLE_VAL; + } else if (micb_num == MIC_BIAS_3) { + snd_soc_component_update_bits(component, + WCD9378_MICB_REMAP_TABLE_VAL_5, + WCD9378_MICB_REMAP_TABLE_VAL_5_MICB_REMAP_TABLE_VAL_5_MASK, + vcout_ctl); + return MICB_USAGE_VAL_MICB3_TABLE_VAL; + } + } + + return 0; +} + +static int wcd9378_micb_usage_value_convert(struct snd_soc_component *component, + u32 micb_mv, int micb_num) +{ + switch (micb_mv) { + case 0: + return MICB_USAGE_VAL_PULL_DOWN; + case 1200: + return MICB_USAGE_VAL_1P2V; + case 1800: + return MICB_USAGE_VAL_1P8VORPULLUP; + case 2500: + return MICB_USAGE_VAL_2P5V; + case 2750: + return MICB_USAGE_VAL_2P75V; + default: + return wcd9378_micb_table_value_set(component, micb_mv, micb_num); + } + + return MICB_USAGE_VAL_DISABLE; +} + +int wcd9378_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + int micb_usage = 0, micb_mask = 0, req_vout_ctl = 0; + + if (wcd9378 == NULL) { + dev_err(component->dev, + "%s: wcd9378 private data is NULL\n", __func__); + return -EINVAL; + } + + switch (micb_num) { + case MIC_BIAS_1: + micb_usage = WCD9378_IT11_USAGE; + micb_mask = WCD9378_IT11_MICB_IT11_MICB_MASK; + break; + case MIC_BIAS_2: + micb_usage = WCD9378_SMP_MIC_CTRL1_IT11_MICB; + micb_mask = WCD9378_SMP_MIC_CTRL1_IT11_MICB_IT11_MICB_MASK; + break; + case MIC_BIAS_3: + micb_usage = WCD9378_SMP_MIC_CTRL2_IT11_MICB; + micb_mask = WCD9378_SMP_MIC_CTRL2_IT11_MICB_IT11_MICB_MASK; + break; + default: + dev_err(component->dev, + "%s: wcd9378 private data is NULL\n", __func__); + break; + } + + mutex_lock(&wcd9378->micb_lock); + + req_vout_ctl = + wcd9378_micb_usage_value_convert(component, req_volt, micb_num); + + snd_soc_component_update_bits(component, + micb_usage, micb_mask, req_vout_ctl); + + if (micb_num == MIC_BIAS_2) { + dev_err(component->dev, + "%s: sj micbias set\n", __func__); + snd_soc_component_update_bits(component, + WCD9378_IT31_MICB, + WCD9378_IT31_MICB_IT31_MICB_MASK, + req_vout_ctl); + wcd9378->curr_micbias2 = req_volt; + } + mutex_unlock(&wcd9378->micb_lock); + return 0; + + +} +EXPORT_SYMBOL_GPL(wcd9378_mbhc_micb_adjust_voltage); + +void wcd9378_disable_bcs_before_slow_insert(struct snd_soc_component *component, + bool bcs_disable) +{ + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + if (wcd9378->update_wcd_event) { + if (bcs_disable) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 0); + else + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 1); + } +} + +static void wcd9378_get_swr_clk_val( + struct snd_soc_component *component, + int rate) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + + switch (rate) { + case SWR_CLK_RATE_4P8MHZ: + wcd9378->tx_swrclk = SWR_BASECLK_19P2MHZ; + wcd9378->tx_clkscale = SWR_CLKSCALE_DIV4; + break; + case SWR_CLK_RATE_9P6MHZ: + wcd9378->tx_swrclk = SWR_BASECLK_19P2MHZ; + wcd9378->tx_clkscale = SWR_CLKSCALE_DIV2; + break; + default: + dev_dbg(component->dev, "%s: unsupport rate: %d\n", + __func__, rate); + break; + } + + dev_dbg(component->dev, "%s: rate: %d, tx_swrclk: 0x%x, tx_clkscale: 0x%x\n", + __func__, rate, wcd9378->tx_swrclk, wcd9378->tx_clkscale); +} + +static int wcd9378_get_clk_rate(int mode) +{ + int rate; + + switch (mode) { + case ADC_MODE_LP: + rate = SWR_CLK_RATE_4P8MHZ; + break; + case ADC_MODE_INVALID: + case ADC_MODE_NORMAL: + case ADC_MODE_HIFI: + default: + rate = SWR_CLK_RATE_9P6MHZ; + break; + } + + pr_debug("%s: mode: %d, rate: %d\n", __func__, mode, rate); + return rate; +} + +static int wcd9378_get_adc_mode_val(int mode) +{ + int ret = 0; + + switch (mode) { + case ADC_MODE_INVALID: + case ADC_MODE_NORMAL: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_HIFI: + ret = ADC_MODE_VAL_HIFI; + break; + case ADC_MODE_LP: + ret = ADC_MODE_VAL_LP; + break; + default: + ret = -EINVAL; + pr_err("%s: invalid ADC mode value %d\n", __func__, mode); + break; + } + return ret; +} + + +static int wcd9378_sys_usage_auto_udpate(struct snd_soc_component *component, + int sys_usage_bit, bool set_enable) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + int i = 0; + + dev_dbg(component->dev, + "%s: enter, current sys_usage: %d, sys_usage_status: 0x%x, sys_usage_bit: %d, set_enable: %d\n", + __func__, wcd9378->sys_usage, + wcd9378->sys_usage_status, + sys_usage_bit, set_enable); + + mutex_lock(&wcd9378->sys_usage_lock); + if (set_enable) { + set_bit(sys_usage_bit, &wcd9378->sys_usage_status); + + if ((sys_usage[wcd9378->sys_usage] & + wcd9378->sys_usage_status) == wcd9378->sys_usage_status) + goto exit; + + for (i = 0; i < SYS_USAGE_NUM; i++) { + if ((sys_usage[i] & wcd9378->sys_usage_status) + == wcd9378->sys_usage_status) { + snd_soc_component_update_bits(component, + WCD9378_SYS_USAGE_CTRL, + WCD9378_SYS_USAGE_CTRL_SYS_USAGE_CTRL_MASK, + i); + wcd9378->sys_usage = i; + dev_dbg(component->dev, "%s: update sys_usage: %d\n", + __func__, wcd9378->sys_usage); + goto exit; + } + } + + dev_dbg(component->dev, "%s: cannot find sys_usage\n", + __func__); + } else { + clear_bit(sys_usage_bit, &wcd9378->sys_usage_status); + } +exit: + mutex_unlock(&wcd9378->sys_usage_lock); + return 0; +} + +static int wcd9378_sys_usage_bit_get( + struct snd_soc_component *component, u32 w_shift, + int *sys_usage_bit, int event) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s: wshift: %d event: %d\n", __func__, + w_shift, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (w_shift) { + case ADC1: + if ((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH12_MUX) & + WCD9378_TX_NEW_TX_CH12_MUX_CH1_SEL_MASK) == 0x01) { + *sys_usage_bit = TX0_AMIC1_EN; + } else if ((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH12_MUX) & + WCD9378_TX_NEW_TX_CH12_MUX_CH1_SEL_MASK) == 0x02) { + *sys_usage_bit = TX0_AMIC2_EN; + } else { + dev_err(component->dev, "%s: unsupport usecase, pls check\n", + __func__); + return -EINVAL; + } + break; + case ADC2: + if ((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH12_MUX) & + WCD9378_TX_NEW_TX_CH12_MUX_CH2_SEL_MASK) == 0x10) { + *sys_usage_bit = TX1_AMIC2_EN; + } else if ((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH12_MUX) & + WCD9378_TX_NEW_TX_CH12_MUX_CH2_SEL_MASK) == 0x18) { + *sys_usage_bit = TX1_AMIC3_EN; + } else { + dev_err(component->dev, "%s: unsupport usecase, pls check\n", + __func__); + return -EINVAL; + } + break; + case ADC3: + if ((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH34_MUX) & + WCD9378_TX_NEW_TX_CH34_MUX_CH3_SEL_MASK) == 0x01) { + *sys_usage_bit = TX2_AMIC1_EN; + } else if ((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH34_MUX) & + WCD9378_TX_NEW_TX_CH34_MUX_CH3_SEL_MASK) == 0x03) { + *sys_usage_bit = TX2_AMIC4_EN; + } else { + dev_err(component->dev, "%s: unsupport usecase, pls check\n", + __func__); + return -EINVAL; + } + break; + default: + break; + } + break; + case SND_SOC_DAPM_POST_PMD: + switch (w_shift) { + case ADC1: + if (test_bit(TX0_AMIC1_EN, &wcd9378->sys_usage_status)) + *sys_usage_bit = TX0_AMIC1_EN; + + if (test_bit(TX0_AMIC2_EN, &wcd9378->sys_usage_status)) + *sys_usage_bit = TX0_AMIC2_EN; + break; + case ADC2: + if (test_bit(TX1_AMIC2_EN, &wcd9378->sys_usage_status)) + *sys_usage_bit = TX1_AMIC2_EN; + + if (test_bit(TX1_AMIC3_EN, &wcd9378->sys_usage_status)) + *sys_usage_bit = TX1_AMIC3_EN; + break; + case ADC3: + if (test_bit(TX2_AMIC1_EN, &wcd9378->sys_usage_status)) + *sys_usage_bit = TX2_AMIC1_EN; + + if (test_bit(TX2_AMIC4_EN, &wcd9378->sys_usage_status)) + *sys_usage_bit = TX2_AMIC4_EN; + break; + default: + break; + } + break; + default: + break; + } + + dev_dbg(component->dev, "%s: done, event: %d, sys_usage_bit: %d\n", + __func__, event, *sys_usage_bit); + return 0; +} + +static int wcd9378_tx_sequencer_enable(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 wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + int mode_val = 0, bank = 0, ret = 0, rate = 0; + int act_ps = 0, sys_usage_bit = 0; + + bank = (wcd9378_swr_slv_get_current_bank(wcd9378->tx_swr_dev, + wcd9378->tx_swr_dev->dev_num) ? 0 : 1); + + dev_dbg(component->dev, "%s wname: %s wshift: %d event: %d\n", __func__, + w->name, w->shift, event); + + ret = wcd9378_sys_usage_bit_get(component, w->shift, &sys_usage_bit, event); + if (ret < 0) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /*Update sys_usage*/ + wcd9378_sys_usage_auto_udpate(component, sys_usage_bit, true); + + mode_val = wcd9378_get_adc_mode_val(wcd9378->tx_mode[w->shift - ADC1]); + if (mode_val < 0) { + dev_dbg(component->dev, + "%s: invalid mode, setting to normal mode\n", + __func__); + mode_val = ADC_MODE_VAL_NORMAL; + } + + rate = wcd9378_get_clk_rate(wcd9378->tx_mode[w->shift - ADC1]); + if (w->shift == ADC2 && !((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH12_MUX) & + WCD9378_TX_NEW_TX_CH12_MUX_CH2_SEL_MASK) == 0x10)) { + if (!wcd9378->bcs_dis) { + wcd9378_tx_connect_port(component, MBHC, + SWR_CLK_RATE_4P8MHZ, true); + set_bit(AMIC2_BCS_ENABLE, &wcd9378->status_mask); + } + } + + set_bit(w->shift - ADC1, &wcd9378->status_mask); + wcd9378_tx_connect_port(component, w->shift, rate, + true); + + wcd9378_get_swr_clk_val(component, rate); + + switch (w->shift) { + case ADC1: + /*SMP MIC0 IT11 USAGE SET*/ + snd_soc_component_update_bits(component, WCD9378_IT11_USAGE, + WCD9378_IT11_USAGE_IT11_USAGE_MASK, mode_val); + + /*Hold TXFE in Initialization During Startup*/ + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH2, + WCD9378_ANA_TX_CH2_HPF1_INIT_MASK, 0x40); + + /*Power up TX0 sequencer*/ + snd_soc_component_update_bits(component, WCD9378_PDE11_REQ_PS, + WCD9378_PDE11_REQ_PS_PDE11_REQ_PS_MASK, 0x00); + break; + case ADC2: + /*Check if amic2 is connected to ADC2 MUX*/ + if ((snd_soc_component_read(component, + WCD9378_TX_NEW_TX_CH12_MUX) & + WCD9378_TX_NEW_TX_CH12_MUX_CH2_SEL_MASK) == 0x10) { + /*SMP JACK IT31 USAGE SET*/ + snd_soc_component_update_bits(component, + WCD9378_IT31_USAGE, + WCD9378_IT31_USAGE_IT31_USAGE_MASK, mode_val); + /*Power up TX1 sequencer*/ + snd_soc_component_update_bits(component, + WCD9378_PDE34_REQ_PS, + WCD9378_PDE34_REQ_PS_PDE34_REQ_PS_MASK, 0x00); + } else { + snd_soc_component_update_bits(component, + WCD9378_SMP_MIC_CTRL1_IT11_USAGE, + WCD9378_SMP_MIC_CTRL1_IT11_USAGE_IT11_USAGE_MASK, + mode_val); + + /*Hold TXFE in Initialization During Startup*/ + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH2, + WCD9378_ANA_TX_CH2_HPF2_INIT_MASK, 0x20); + + /*Power up TX1 sequencer*/ + snd_soc_component_update_bits(component, + WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS, + WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS_PDE11_REQ_PS_MASK, + 0x00); + } + break; + case ADC3: + /*SMP MIC2 IT11 USAGE SET*/ + snd_soc_component_update_bits(component, + WCD9378_SMP_MIC_CTRL2_IT11_USAGE, + WCD9378_SMP_MIC_CTRL2_IT11_USAGE_IT11_USAGE_MASK, + mode_val); + + /*Hold TXFE in Initialization During Startup*/ + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH3_HPF, + WCD9378_ANA_TX_CH3_HPF_HPF3_INIT_MASK, 0x40); + + /*Power up TX2 sequencer*/ + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS, + WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS_PDE11_REQ_PS_MASK, 0x00); + break; + default: + break; + } + /*default delay 800us*/ + usleep_range(800, 810); + + wcd9378_swr_slvdev_datapath_control(wcd9378->dev, TX_PATH, true); + + switch (w->shift) { + case ADC1: + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH2, + WCD9378_ANA_TX_CH2_HPF1_INIT_MASK, 0x00); + + act_ps = snd_soc_component_read(component, WCD9378_PDE11_ACT_PS); + if (act_ps) + dev_dbg(component->dev, + "%s: TX0 sequencer power on failed\n", __func__); + else + dev_dbg(component->dev, + "%s: TX0 sequencer power on success\n", __func__); + break; + case ADC2: + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH2, + WCD9378_ANA_TX_CH2_HPF2_INIT_MASK, 0x00); + + if (test_bit(TX1_AMIC2_EN, &wcd9378->sys_usage_status)) + act_ps = snd_soc_component_read(component, + WCD9378_PDE34_ACT_PS); + else + act_ps = snd_soc_component_read(component, + WCD9378_SMP_MIC_CTRL1_PDE11_ACT_PS); + + if (act_ps) + dev_dbg(component->dev, + "%s: TX1 sequencer power on failed\n", __func__); + else + dev_dbg(component->dev, + "%s: TX1 sequencer power on success\n", __func__); + break; + case ADC3: + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH3_HPF, + WCD9378_ANA_TX_CH3_HPF_HPF3_INIT_MASK, 0x00); + + act_ps = snd_soc_component_read(component, + WCD9378_SMP_MIC_CTRL2_PDE11_ACT_PS); + if (act_ps) + dev_dbg(component->dev, + "%s: TX2 sequencer power on failed\n", __func__); + else + dev_dbg(component->dev, + "%s: TX2 sequencer power on success\n", __func__); + break; + }; + break; + case SND_SOC_DAPM_POST_PMD: + wcd9378_tx_connect_port(component, w->shift, 0, false); + if (w->shift == ADC2 && + test_bit(AMIC2_BCS_ENABLE, &wcd9378->status_mask)) { + wcd9378_tx_connect_port(component, MBHC, 0, + false); + clear_bit(AMIC2_BCS_ENABLE, &wcd9378->status_mask); + } + + switch (w->shift) { + case ADC1: + snd_soc_component_update_bits(component, WCD9378_IT11_USAGE, + WCD9378_IT11_USAGE_IT11_USAGE_MASK, 0x00); + /*Normal TXFE Startup*/ + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH2, + WCD9378_ANA_TX_CH2_HPF1_INIT_MASK, 0x00); + + /*tear down TX0 sequencer*/ + snd_soc_component_update_bits(component, WCD9378_PDE11_REQ_PS, + WCD9378_PDE11_REQ_PS_PDE11_REQ_PS_MASK, 0x03); + + break; + case ADC2: + if (test_bit(TX1_AMIC2_EN, &wcd9378->sys_usage_status)) { + snd_soc_component_update_bits(component, + WCD9378_IT31_USAGE, + WCD9378_IT31_USAGE_IT31_USAGE_MASK, 0x00); + + /*tear down TX1 sequencer*/ + snd_soc_component_update_bits(component, WCD9378_PDE34_REQ_PS, + WCD9378_PDE34_REQ_PS_PDE34_REQ_PS_MASK, 0x03); + } + + if (test_bit(TX1_AMIC3_EN, &wcd9378->sys_usage_status)) { + snd_soc_component_update_bits(component, + WCD9378_SMP_MIC_CTRL1_IT11_USAGE, + WCD9378_SMP_MIC_CTRL1_IT11_USAGE_IT11_USAGE_MASK, + 0x00); + + /*Normal TXFE Startup*/ + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH2, + WCD9378_ANA_TX_CH2_HPF1_INIT_MASK, 0x00); + + /*tear down TX1 sequencer*/ + snd_soc_component_update_bits(component, + WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS, + WCD9378_SMP_MIC_CTRL1_PDE11_REQ_PS_PDE11_REQ_PS_MASK, + 0x03); + } + break; + case ADC3: + snd_soc_component_update_bits(component, + WCD9378_SMP_MIC_CTRL2_IT11_USAGE, + WCD9378_SMP_MIC_CTRL2_IT11_USAGE_IT11_USAGE_MASK, + 0x00); + + /*Normal TXFE Startup*/ + snd_soc_component_update_bits(component, WCD9378_ANA_TX_CH3_HPF, + WCD9378_ANA_TX_CH3_HPF_HPF3_INIT_MASK, 0x00); + + /*tear down TX2 sequencer*/ + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS, + WCD9378_SMP_MIC_CTRL2_PDE11_REQ_PS_PDE11_REQ_PS_MASK, 0x03); + break; + default: + break; + } + /*default delay 800us*/ + usleep_range(800, 810); + + /*Disable sys_usage_status*/ + wcd9378_sys_usage_auto_udpate(component, sys_usage_bit, false); + + wcd9378_swr_slvdev_datapath_control(wcd9378->dev, TX_PATH, false); + break; + default: + break; + } + + return ret; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9378_tx_connect_port(component, w->shift, + SWR_CLK_RATE_2P4MHZ, true); + break; + case SND_SOC_DAPM_POST_PMD: + ret = swr_slvdev_datapath_control(wcd9378->tx_swr_dev, + wcd9378->tx_swr_dev->dev_num, + false); + break; + }; + + return ret; +} + +static int wcd9378_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int micb_num = 0; + + 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 + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9378_micbias_control(component, micb_num, + MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9378_micbias_control(component, micb_num, + MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int wcd9378_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int micb_num = 0; + + dev_dbg(component->dev, "%s: wname: %s, event: %d\n", + __func__, w->name, event); + + if (strnstr(w->name, "VA MIC BIAS1", sizeof("VA MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9378_micbias_control(component, micb_num, + MICB_PULLUP_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9378_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + break; + }; + + return 0; +} + + +/* + * wcd9378_soc_get_mbhc: get wcd9378_mbhc handle of corresponding component + * @component: handle to snd_soc_component * + * + * return wcd9378_mbhc handle or error code in case of failure + */ +struct wcd9378_mbhc *wcd9378_soc_get_mbhc(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378; + + if (!component) { + pr_err_ratelimited("%s: Invalid params, NULL component\n", __func__); + return NULL; + } + wcd9378 = snd_soc_component_get_drvdata(component); + + if (!wcd9378) { + pr_err_ratelimited("%s: wcd9378 is NULL\n", __func__); + return NULL; + } + + return wcd9378->mbhc; +} +EXPORT_SYMBOL_GPL(wcd9378_soc_get_mbhc); + +static int wcd9378_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 wcd9378_priv *wcd9378 = 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: + /*OCP FSM EN*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_OCP_FSM_EN_MASK, 0x10); + /*SCD OP EN*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_SCD_OP_EN_MASK, 0x02); + /*HPHL ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_HPH_GAIN_CTL, + WCD9378_CDC_HPH_GAIN_CTL_HPHL_RX_EN_MASK, 0x04); + /*OPAMP_CHOP_CLK DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_HPH_RDAC_CLK_CTL1, + WCD9378_HPH_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN_MASK, 0x00); + wcd9378_rx_connect_port(component, HPH_L, true); + + if (wcd9378->comp1_enable) { + snd_soc_component_update_bits(component, WCD9378_CDC_COMP_CTL_0, + WCD9378_CDC_COMP_CTL_0_HPHL_COMP_EN_MASK, 0x02); + wcd9378_rx_connect_port(component, COMP_L, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + /*OCP FSM DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_OCP_FSM_EN_MASK, 0x00); + /*SCD OP DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_SCD_OP_EN_MASK, 0x00); + /*HPHL DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_HPH_GAIN_CTL, + WCD9378_CDC_HPH_GAIN_CTL_HPHL_RX_EN_MASK, 0x00); + wcd9378_rx_connect_port(component, HPH_L, false); + + if (wcd9378->comp1_enable) + wcd9378_rx_connect_port(component, COMP_L, false); + break; + default: + break; + }; + + return 0; + +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = 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: + /*OCP FSM EN*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_OCP_FSM_EN_MASK, 0x10); + /*SCD OP EN*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_SCD_OP_EN_MASK, 0x02); + /*HPHR ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_HPH_GAIN_CTL, + WCD9378_CDC_HPH_GAIN_CTL_HPHR_RX_EN_MASK, 0x08); + /*OPAMP_CHOP_CLK DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_HPH_RDAC_CLK_CTL1, + WCD9378_HPH_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN_MASK, 0x00); + + wcd9378_rx_connect_port(component, HPH_R, true); + + if (wcd9378->comp2_enable) { + snd_soc_component_update_bits(component, WCD9378_CDC_COMP_CTL_0, + WCD9378_CDC_COMP_CTL_0_HPHR_COMP_EN_MASK, 0x01); + wcd9378_rx_connect_port(component, COMP_R, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + /*OCP FSM DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_OCP_FSM_EN_MASK, 0x00); + /*SCD OP DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_HPH_OCP_CTL, + WCD9378_HPH_OCP_CTL_SCD_OP_EN_MASK, 0x00); + /*HPHR DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_HPH_GAIN_CTL, + WCD9378_CDC_HPH_GAIN_CTL_HPHR_RX_EN_MASK, 0x00); + wcd9378_rx_connect_port(component, HPH_R, false); + + if (wcd9378->comp2_enable) + wcd9378_rx_connect_port(component, COMP_R, false); + break; + default: + break; + }; + + return 0; + +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + int bank = 0; + int act_ps = 0; + + bank = (wcd9378_swr_slv_get_current_bank(wcd9378->rx_swr_dev, + wcd9378->rx_swr_dev->dev_num) ? 0 : 1); + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x01)); + + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHL_PDM_WD_INT); + + act_ps = snd_soc_component_read(component, WCD9378_PDE47_ACT_PS); + if (act_ps) + dev_dbg(component->dev, + "%s: HPH sequencer power on failed\n", __func__); + else + dev_dbg(component->dev, + "%s: HPH sequencer power on success\n", __func__); + break; + case SND_SOC_DAPM_POST_PMD: + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHL_PDM_WD_INT); + + if (wcd9378->update_wcd_event && wcd9378->comp1_enable) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX1 << 0x10)); + + blocking_notifier_call_chain(&wcd9378->mbhc->notifier, + WCD_EVENT_POST_HPHL_PA_OFF, + &wcd9378->mbhc->wcd_mbhc); + break; + default: + break; + }; + + return 0; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + int act_ps = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10)); + wcd_enable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHR_PDM_WD_INT); + + act_ps = snd_soc_component_read(component, WCD9378_PDE47_ACT_PS); + if (act_ps) + dev_dbg(component->dev, + "%s: HPH sequencer power on failed\n", __func__); + else + dev_dbg(component->dev, + "%s: HPH sequencer power on success\n", __func__); + break; + case SND_SOC_DAPM_POST_PMD: + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHR_PDM_WD_INT); + + if (wcd9378->update_wcd_event && wcd9378->comp2_enable) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX2 << 0x10)); + + blocking_notifier_call_chain(&wcd9378->mbhc->notifier, + WCD_EVENT_POST_HPHR_PA_OFF, + &wcd9378->mbhc->wcd_mbhc); + break; + default: + break; + }; + + return 0; + +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + int ret = 0, act_ps = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9378_swr_slvdev_datapath_control(wcd9378->dev, RX_PATH, true); + + if (test_bit(RX1_AUX_EN, &wcd9378->sys_usage_status)) { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10)); + wcd_enable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHR_PDM_WD_INT); + } else { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10)); + wcd_enable_irq(&wcd9378->irq_info, + WCD9378_IRQ_AUX_PDM_WD_INT); + } + + act_ps = snd_soc_component_read(component, WCD9378_PDE23_ACT_PS); + if (act_ps) + dev_dbg(component->dev, + "%s: SA sequencer power on failed\n", __func__); + else + dev_dbg(component->dev, + "%s: SA sequencer power on success\n", __func__); + break; + case SND_SOC_DAPM_POST_PMD: + if (test_bit(RX1_AUX_EN, &wcd9378->sys_usage_status)) { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHR_PDM_WD_INT); + } else { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10 | 0x1)); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_AUX_PDM_WD_INT); + } + break; + }; + return ret; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + int ret = 0, act_ps = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9378_swr_slvdev_datapath_control(wcd9378->dev, RX_PATH, true); + + if (test_bit(RX0_EAR_EN, &wcd9378->sys_usage_status)) { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHL_PDM_WD_INT); + + } else { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10)); + wcd_enable_irq(&wcd9378->irq_info, + WCD9378_IRQ_AUX_PDM_WD_INT); + } + + act_ps = snd_soc_component_read(component, WCD9378_PDE23_ACT_PS); + if (act_ps) + dev_dbg(component->dev, + "%s: SA sequencer power on failed\n", __func__); + else + dev_dbg(component->dev, + "%s: SA sequencer power on successful\n", __func__); + + break; + case SND_SOC_DAPM_POST_PMD: + if (test_bit(RX0_EAR_EN, &wcd9378->sys_usage_status)) { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_HPHL_PDM_WD_INT); + } else { + if (wcd9378->update_wcd_event) + wcd9378->update_wcd_event(wcd9378->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10 | 0x1)); + wcd_disable_irq(&wcd9378->irq_info, + WCD9378_IRQ_AUX_PDM_WD_INT); + } + break; + }; + return ret; +} + +static int wcd9378_get_hph_pwr_level(int hph_mode) +{ + switch (hph_mode) { + case CLS_H_LOHIFI: + case CLS_AB_LOHIFI: + return PWR_LEVEL_LOHIFI_VAL; + case CLS_H_LP: + case CLS_AB_LP: + return PWR_LEVEL_LP_VAL; + case CLS_H_HIFI: + case CLS_AB_HIFI: + return PWR_LEVEL_HIFI_VAL; + case CLS_H_ULP: + case CLS_AB: + case CLS_H_NORMAL: + default: + return PWR_LEVEL_ULP_VAL; + } + + return PWR_LEVEL_ULP_VAL; +} + +static void wcd9378_hph_set_channel_volume(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + u8 msb_val = 0, lsb_val = 0; + + if ((!wcd9378->comp1_enable) && + (!wcd9378->comp2_enable)) { + msb_val = (wcd9378->hph_gain >> 8); + lsb_val = (wcd9378->hph_gain & 0x00ff); + + regmap_write(wcd9378->regmap, WCD9378_FU42_CH_VOL_CH1_MSB, msb_val); + regmap_write(wcd9378->regmap, WCD9378_FU42_CH_VOL_CH1_LSB, lsb_val); + + regmap_write(wcd9378->regmap, WCD9378_FU42_CH_VOL_CH2_MSB, msb_val); + regmap_write(wcd9378->regmap, WCD9378_FU42_CH_VOL_CH2_LSB, lsb_val); + } +} + +static int wcd9378_hph_sequencer_enable(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 wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + int power_level, ret = 0; + struct swr_device *swr_dev = wcd9378->tx_swr_dev; + u8 commit_val = 0x02; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9378_sys_usage_auto_udpate(component, RX0_RX1_HPH_EN, true); + + regmap_write(wcd9378->regmap, WCD9378_CMT_GRP_MASK, 0x02); + + if ((!wcd9378->comp1_enable) || (!wcd9378->comp2_enable)) { + snd_soc_component_update_bits(component, WCD9378_HPH_UP_T7, + WCD9378_HPH_UP_T7_HPH_UP_T7_MASK, 0x07); + + snd_soc_component_update_bits(component, WCD9378_HPH_DN_T1, + WCD9378_HPH_DN_T1_HPH_DN_T1_MASK, 0x07); + } + + if ((wcd9378->hph_mode == CLS_AB) || + (wcd9378->hph_mode == CLS_AB_HIFI) || + (wcd9378->hph_mode == CLS_AB_LP) || + (wcd9378->hph_mode == CLS_AB_LOHIFI)) + snd_soc_component_update_bits(component, WCD9378_CP_CP_DTOP_CTRL_14, + WCD9378_CP_CP_DTOP_CTRL_14_OVERRIDE_VREF_MASK, 0x80); + + /*GET HPH_MODE*/ + power_level = wcd9378_get_hph_pwr_level(wcd9378->hph_mode); + + /*SET HPH_MODE*/ + snd_soc_component_update_bits(component, WCD9378_IT41_USAGE, + WCD9378_IT41_USAGE_IT41_USAGE_MASK, power_level); + + /*TURN ON HPH SEQUENCER*/ + snd_soc_component_update_bits(component, WCD9378_PDE47_REQ_PS, + WCD9378_PDE47_REQ_PS_PDE47_REQ_PS_MASK, 0x00); + + wcd9378_hph_set_channel_volume(component); + + if ((!wcd9378->comp1_enable) || (!wcd9378->comp2_enable)) + /*PA delay is 22400us*/ + usleep_range(22500, 22510); + else + /*COMP delay is 9400us*/ + usleep_range(9500, 9510); + + regmap_write(wcd9378->regmap, WCD9378_FU42_MUTE_CH1_CN, 0x00); + regmap_write(wcd9378->regmap, WCD9378_FU42_MUTE_CH2_CN, 0x00); + + if (wcd9378->sys_usage == SYS_USAGE_10) + /*FU23 UNMUTE*/ + snd_soc_component_update_bits(component, WCD9378_FU23_MUTE, + WCD9378_FU23_MUTE_FU23_MUTE_MASK, 0x00); + + swr_write(swr_dev, swr_dev->dev_num, 0x004c, &commit_val); + + wcd9378_swr_slvdev_datapath_control(wcd9378->dev, RX_PATH, true); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_write(wcd9378->regmap, WCD9378_FU42_MUTE_CH1_CN, 0x01); + regmap_write(wcd9378->regmap, WCD9378_FU42_MUTE_CH2_CN, 0x01); + + swr_write(swr_dev, swr_dev->dev_num, 0x004c, &commit_val); + + /*TEAR DOWN HPH SEQUENCER*/ + snd_soc_component_update_bits(component, WCD9378_PDE47_REQ_PS, + WCD9378_PDE47_REQ_PS_PDE47_REQ_PS_MASK, 0x03); + + if (!wcd9378->comp1_enable || !wcd9378->comp2_enable) + /*PA delay is 24250us*/ + usleep_range(24300, 24310); + else + /*COMP delay is 11250us*/ + usleep_range(11300, 11310); + + wcd9378_sys_usage_auto_udpate(component, RX0_RX1_HPH_EN, false); + break; + default: + break; + }; + + return ret; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + int ear_rx2 = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + ear_rx2 = snd_soc_component_read(component, WCD9378_CDC_AUX_GAIN_CTL) & + WCD9378_CDC_AUX_GAIN_CTL_AUX_EN_MASK; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /*SHORT_PROT_EN ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_ANA_EAR, + WCD9378_ANA_EAR_SHORT_PROT_EN_MASK, 0x40); + if (!ear_rx2) { + /*RX0 ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_HPH_GAIN_CTL, + WCD9378_CDC_HPH_GAIN_CTL_HPHL_RX_EN_MASK, 0x04); + + wcd9378_sys_usage_auto_udpate(component, RX0_EAR_EN, true); + if (wcd9378->comp1_enable) { + snd_soc_component_update_bits(component, WCD9378_CDC_COMP_CTL_0, + WCD9378_CDC_COMP_CTL_0_EAR_COMP_EN_MASK, 0x04); + wcd9378_rx_connect_port(component, COMP_L, true); + } + wcd9378_rx_connect_port(component, HPH_L, true); + } else { + wcd9378_sys_usage_auto_udpate(component, RX2_EAR_EN, true); + /*FORCE CLASS_AB EN*/ + snd_soc_component_update_bits(component, WCD9378_SEQ_OVRRIDE_CTL0, + WCD9378_SEQ_OVRRIDE_CTL0_CLASSAB_EN_OVR_MASK, 0x20); + + snd_soc_component_update_bits(component, WCD9378_CP_CP_DTOP_CTRL_14, + WCD9378_CP_CP_DTOP_CTRL_14_OVERRIDE_VREF_MASK, 0x80); + + if (wcd9378->rx2_clk_mode) + snd_soc_component_update_bits(component, WCD9378_CDC_PATH_MODE, + WCD9378_CDC_PATH_MODE_RX2_CLK_RATE_MASK, 0x40); + + wcd9378_rx_connect_port(component, LO, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + /*SHORT_PROT_EN DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_ANA_EAR, + WCD9378_ANA_EAR_SHORT_PROT_EN_MASK, 0x00); + if (test_bit(RX0_EAR_EN, &wcd9378->sys_usage_status)) { + /*RX0 DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_HPH_GAIN_CTL, + WCD9378_CDC_HPH_GAIN_CTL_HPHL_RX_EN_MASK, 0x00); + wcd9378_rx_connect_port(component, HPH_L, false); + + if (wcd9378->comp1_enable) { + snd_soc_component_update_bits(component, WCD9378_CDC_COMP_CTL_0, + WCD9378_CDC_COMP_CTL_0_EAR_COMP_EN_MASK, 0x00); + wcd9378_rx_connect_port(component, COMP_L, false); + } + + wcd9378_sys_usage_auto_udpate(component, RX0_EAR_EN, false); + } else { + wcd9378_rx_connect_port(component, LO, false); + wcd9378_sys_usage_auto_udpate(component, RX2_EAR_EN, false); + wcd9378_swr_slvdev_datapath_control(wcd9378->dev, RX_PATH, false); + } + break; + }; + + return 0; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + int aux_rx2 = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + aux_rx2 = snd_soc_component_read(component, WCD9378_CDC_AUX_GAIN_CTL) & + WCD9378_CDC_AUX_GAIN_CTL_AUX_EN_MASK; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /*AUXPA SHORT PROT ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_AUX_AUXPA, + WCD9378_AUX_AUXPA_AUX_PA_SHORT_PROT_EN_MASK, 0x40); + if (!aux_rx2) { + /*RX1 ENABLE*/ + snd_soc_component_update_bits(component, WCD9378_CDC_HPH_GAIN_CTL, + WCD9378_CDC_HPH_GAIN_CTL_HPHR_RX_EN_MASK, 0x08); + + wcd9378_sys_usage_auto_udpate(component, RX1_AUX_EN, true); + wcd9378_rx_connect_port(component, HPH_R, true); + } else { + wcd9378_sys_usage_auto_udpate(component, RX2_AUX_EN, true); + + if (wcd9378->rx2_clk_mode) + snd_soc_component_update_bits(component, WCD9378_CDC_PATH_MODE, + WCD9378_CDC_PATH_MODE_RX2_CLK_RATE_MASK, 0x40); + + wcd9378_rx_connect_port(component, LO, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + /*AUXPA SHORT PROT DISABLE*/ + snd_soc_component_update_bits(component, WCD9378_AUX_AUXPA, + WCD9378_AUX_AUXPA_AUX_PA_SHORT_PROT_EN_MASK, 0x00); + + if (test_bit(RX1_AUX_EN, &wcd9378->sys_usage_status)) { + wcd9378_rx_connect_port(component, HPH_R, false); + wcd9378_sys_usage_auto_udpate(component, RX1_AUX_EN, false); + } else { + wcd9378_rx_connect_port(component, LO, false); + wcd9378_sys_usage_auto_udpate(component, RX2_AUX_EN, false); + wcd9378_swr_slvdev_datapath_control(wcd9378->dev, RX_PATH, false); + } + break; + }; + + return 0; +} + +static int wcd9378_sa_sequencer_enable(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: + /*TURN ON AMP SEQUENCER*/ + snd_soc_component_update_bits(component, WCD9378_PDE23_REQ_PS, + WCD9378_PDE23_REQ_PS_PDE23_REQ_PS_MASK, 0x00); + /*default delay 8550us*/ + usleep_range(8600, 8610); + + /*FU23 UNMUTE*/ + snd_soc_component_update_bits(component, WCD9378_FU23_MUTE, + WCD9378_FU23_MUTE_FU23_MUTE_MASK, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + /*FU23 MUTE*/ + snd_soc_component_update_bits(component, WCD9378_FU23_MUTE, + WCD9378_FU23_MUTE_FU23_MUTE_MASK, 0x01); + + /*TEAR DOWN AMP SEQUENCER*/ + snd_soc_component_update_bits(component, WCD9378_PDE23_REQ_PS, + WCD9378_PDE23_REQ_PS_PDE23_REQ_PS_MASK, 0x03); + /*default delay 1530us*/ + usleep_range(15400, 15410); + break; + default: + break; + }; + + return 0; +} + +int wcd9378_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + struct wcd9378_pdata *pdata = + dev_get_platdata(wcd9378->dev); + struct wcd9378_micbias_setting *mb = &pdata->micbias; + int micb_usage = 0, micb_mask = 0, micb_usage_val = 0; + int pre_off_event = 0, post_off_event = 0; + int post_on_event = 0, post_dapm_off = 0; + int post_dapm_on = 0; + int pull_up_mask = 0, pull_up_en = 0; + int micb_index = 0, ret = 0; + + switch (micb_num) { + case MIC_BIAS_1: + pull_up_mask = WCD9378_MB_PULLUP_EN_MB1_1P8V_OR_PULLUP_SEL_MASK; + pull_up_en = 0x01; + micb_usage = WCD9378_IT11_MICB; + micb_mask = WCD9378_IT11_MICB_IT11_MICB_MASK; + micb_usage_val = mb->micb1_usage_val; + break; + case MIC_BIAS_2: + pull_up_mask = WCD9378_MB_PULLUP_EN_MB2_1P8V_OR_PULLUP_SEL_MASK; + pull_up_en = 0x02; + micb_usage = WCD9378_SMP_MIC_CTRL1_IT11_MICB; + micb_mask = WCD9378_SMP_MIC_CTRL1_IT11_MICB_IT11_MICB_MASK; + micb_usage_val = mb->micb2_usage_val; + 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_usage = WCD9378_SMP_MIC_CTRL2_IT11_MICB; + micb_mask = WCD9378_SMP_MIC_CTRL2_IT11_MICB_IT11_MICB_MASK; + pull_up_mask = WCD9378_MB_PULLUP_EN_MB3_1P8V_OR_PULLUP_SEL_MASK; + pull_up_en = 0x04; + micb_usage_val = mb->micb3_usage_val; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + + mutex_lock(&wcd9378->micb_lock); + + micb_index = micb_num - 1; + switch (req) { + case MICB_PULLUP_ENABLE: + wcd9378->pullup_ref[micb_index]++; + if ((wcd9378->pullup_ref[micb_index] == 1) && + (wcd9378->micb_ref[micb_index] == 0)) { + snd_soc_component_update_bits(component, WCD9378_MB_PULLUP_EN, + pull_up_mask, pull_up_en); + snd_soc_component_update_bits(component, + micb_usage, micb_mask, micb_usage_val); + + if (micb_num == MIC_BIAS_2) { + snd_soc_component_update_bits(component, + WCD9378_IT31_MICB, + WCD9378_IT31_MICB_IT31_MICB_MASK, + micb_usage_val); + wcd9378->curr_micbias2 = mb->micb2_mv; + } + } + break; + case MICB_PULLUP_DISABLE: + if (wcd9378->pullup_ref[micb_index] > 0) + wcd9378->pullup_ref[micb_index]--; + + if ((wcd9378->pullup_ref[micb_index] == 0) && + (wcd9378->micb_ref[micb_index] == 0)) { + snd_soc_component_update_bits(component, micb_usage, micb_mask, 0x01); + + if (micb_num == MIC_BIAS_2) { + snd_soc_component_update_bits(component, + WCD9378_IT31_MICB, + WCD9378_IT31_MICB_IT31_MICB_MASK, + 0x01); + wcd9378->curr_micbias2 = 0; + } + } + break; + case MICB_ENABLE: + wcd9378->micb_ref[micb_index]++; + if (wcd9378->micb_ref[micb_index] == 1) { + dev_dbg(component->dev, "%s: enable micbias, micb_usage:0x%0x, val:0x%0x\n", + __func__, micb_usage, micb_usage_val); + snd_soc_component_update_bits(component, + micb_usage, micb_mask, micb_usage_val); + + if (micb_num == MIC_BIAS_2) { + snd_soc_component_update_bits(component, + WCD9378_IT31_MICB, + WCD9378_IT31_MICB_IT31_MICB_MASK, + micb_usage_val); + wcd9378->curr_micbias2 = mb->micb2_mv; + } + if (post_on_event) + blocking_notifier_call_chain( + &wcd9378->mbhc->notifier, + post_on_event, + &wcd9378->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_on && wcd9378->mbhc) + blocking_notifier_call_chain(&wcd9378->mbhc->notifier, + post_dapm_on, + &wcd9378->mbhc->wcd_mbhc); + break; + case MICB_DISABLE: + if (wcd9378->micb_ref[micb_index] > 0) + wcd9378->micb_ref[micb_index]--; + if ((wcd9378->micb_ref[micb_index] == 0) && + (wcd9378->pullup_ref[micb_index] > 0)) { + snd_soc_component_update_bits(component, WCD9378_MB_PULLUP_EN, + pull_up_mask, pull_up_en); + + if (micb_num == MIC_BIAS_2) + wcd9378->curr_micbias2 = mb->micb2_mv; + } else if ((wcd9378->micb_ref[micb_index] == 0) && + (wcd9378->pullup_ref[micb_index] == 0)) { + if (pre_off_event && wcd9378->mbhc) + blocking_notifier_call_chain( + &wcd9378->mbhc->notifier, + pre_off_event, + &wcd9378->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, micb_usage, + micb_mask, 0x00); + if (micb_num == MIC_BIAS_2) { + snd_soc_component_update_bits(component, + WCD9378_IT31_MICB, + WCD9378_IT31_MICB_IT31_MICB_MASK, + 0x00); + wcd9378->curr_micbias2 = 0; + } + if (post_off_event && wcd9378->mbhc) + blocking_notifier_call_chain( + &wcd9378->mbhc->notifier, + post_off_event, + &wcd9378->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_off && wcd9378->mbhc) + blocking_notifier_call_chain(&wcd9378->mbhc->notifier, + post_dapm_off, + &wcd9378->mbhc->wcd_mbhc); + break; + default: + dev_err(component->dev, "%s: Invalid req event: %d\n", + __func__, req); + return -EINVAL; + } + + dev_dbg(component->dev, + "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, wcd9378->micb_ref[micb_index], + wcd9378->pullup_ref[micb_index]); + + mutex_unlock(&wcd9378->micb_lock); + return ret; +} +EXPORT_SYMBOL_GPL(wcd9378_micbias_control); + + +static int wcd9378_get_logical_addr(struct swr_device *swr_dev) +{ + int ret = 0; + uint8_t devnum = 0; + int num_retry = NUM_ATTEMPTS; + + do { + /* retry after 4ms */ + usleep_range(4000, 4010); + ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum); + } while (ret && --num_retry); + + if (ret) + dev_err(&swr_dev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, devnum, swr_dev->addr); + + swr_dev->dev_num = devnum; + return 0; +} + +static bool get_usbc_hs_status(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + if (mbhc_cfg->enable_usbc_analog) { + if (!(snd_soc_component_read(component, WCD9378_ANA_MBHC_MECH) + & 0x20)) + return true; + } + return false; +} + +int wcd9378_swr_dmic_register_notifier(struct snd_soc_component *component, + struct notifier_block *nblock, + bool enable) +{ + struct wcd9378_priv *wcd9378_priv = NULL; + + if (component == NULL) { + pr_err_ratelimited("%s: wcd9378 component is NULL\n", __func__); + return -EINVAL; + } + + wcd9378_priv = snd_soc_component_get_drvdata(component); + wcd9378_priv->notify_swr_dmic = enable; + if (enable) + return blocking_notifier_chain_register(&wcd9378_priv->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd9378_priv->notifier, nblock); +} +EXPORT_SYMBOL_GPL(wcd9378_swr_dmic_register_notifier); + +static int wcd9378_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + int ret = 0; + struct wcd9378_priv *wcd9378 = dev_get_drvdata((struct device *)data); + struct snd_soc_component *component = wcd9378->component; + struct wcd_mbhc *mbhc; + int rx_clk_type; + + switch (event) { + case BOLERO_SLV_EVT_TX_CH_HOLD_CLEAR: + if (test_bit(WCD_ADC1, &wcd9378->status_mask)) { + snd_soc_component_update_bits(component, + WCD9378_ANA_TX_CH2, 0x40, 0x00); + set_bit(WCD_ADC1_MODE, &wcd9378->status_mask); + clear_bit(WCD_ADC1, &wcd9378->status_mask); + } + if (test_bit(WCD_ADC2, &wcd9378->status_mask)) { + snd_soc_component_update_bits(component, + WCD9378_ANA_TX_CH2, 0x20, 0x00); + set_bit(WCD_ADC2_MODE, &wcd9378->status_mask); + clear_bit(WCD_ADC2, &wcd9378->status_mask); + } + if (test_bit(WCD_ADC3, &wcd9378->status_mask)) { + snd_soc_component_update_bits(component, + WCD9378_ANA_TX_CH3_HPF, 0x40, 0x00); + set_bit(WCD_ADC3_MODE, &wcd9378->status_mask); + clear_bit(WCD_ADC3, &wcd9378->status_mask); + } + break; + case BOLERO_SLV_EVT_PA_OFF_PRE_SSR: + snd_soc_component_update_bits(component, WCD9378_ANA_HPH, + 0xC0, 0x00); + snd_soc_component_update_bits(component, WCD9378_ANA_EAR, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD9378_AUX_AUXPA, + 0x80, 0x00); + break; + case BOLERO_SLV_EVT_SSR_DOWN: + if (wcd9378->notify_swr_dmic) + blocking_notifier_call_chain(&wcd9378->notifier, + WCD9378_EVT_SSR_DOWN, + NULL); + wcd9378->mbhc->wcd_mbhc.deinit_in_progress = true; + mbhc = &wcd9378->mbhc->wcd_mbhc; + wcd9378->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); + wcd9378_mbhc_ssr_down(wcd9378->mbhc, component); + wcd9378_reset_low(wcd9378->dev); + break; + case BOLERO_SLV_EVT_SSR_UP: + wcd9378_reset(wcd9378->dev); + /* allow reset to take effect */ + usleep_range(10000, 10010); + + wcd9378_get_logical_addr(wcd9378->tx_swr_dev); + wcd9378_get_logical_addr(wcd9378->rx_swr_dev); + + wcd9378->tx_swr_dev->scp1_val = 0; + wcd9378->tx_swr_dev->scp2_val = 0; + wcd9378->rx_swr_dev->scp1_val = 0; + wcd9378->rx_swr_dev->scp2_val = 0; + + wcd9378_init_reg(component); + regcache_mark_dirty(wcd9378->regmap); + regcache_sync(wcd9378->regmap); + /* Initialize MBHC module */ + mbhc = &wcd9378->mbhc->wcd_mbhc; + ret = wcd9378_mbhc_post_ssr_init(wcd9378->mbhc, component); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + } else { + wcd9378_mbhc_hs_detect(component, mbhc->mbhc_cfg); + } + wcd9378->mbhc->wcd_mbhc.deinit_in_progress = false; + if (wcd9378->notify_swr_dmic) + blocking_notifier_call_chain(&wcd9378->notifier, + WCD9378_EVT_SSR_UP, + NULL); + if (wcd9378->usbc_hs_status) + mdelay(500); + break; + case BOLERO_SLV_EVT_CLK_NOTIFY: + snd_soc_component_update_bits(component, + WCD9378_TOP_CLK_CFG, 0x06, + ((val >> 0x10) << 0x01)); + + rx_clk_type = (val >> 0x10); + + switch (rx_clk_type) { + case RX_CLK_12P288MHZ: + wcd9378->rx_swrclk = SWR_BASECLK_24P576MHZ; + wcd9378->rx_clkscale = SWR_CLKSCALE_DIV2; + break; + case RX_CLK_11P2896MHZ: + wcd9378->rx_swrclk = SWR_BASECLK_22P5792MHZ; + wcd9378->rx_clkscale = SWR_CLKSCALE_DIV2; + break; + default: + wcd9378->rx_swrclk = SWR_BASECLK_19P2MHZ; + wcd9378->rx_clkscale = SWR_CLKSCALE_DIV2; + break; + } + dev_dbg(component->dev, "%s: base_clk:0x%0x, clk_scale:0x%x\n", + __func__, wcd9378->rx_swrclk, wcd9378->rx_clkscale); + + break; + default: + dev_dbg(component->dev, "%s: invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static int wcd9378_wakeup(void *handle, bool enable) +{ + struct wcd9378_priv *priv; + int ret = 0; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + priv = (struct wcd9378_priv *)handle; + if (!priv->tx_swr_dev) { + pr_err("%s: tx swr dev is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&priv->wakeup_lock); + if (enable) + ret = swr_device_wakeup_vote(priv->tx_swr_dev); + else + ret = swr_device_wakeup_unvote(priv->tx_swr_dev); + mutex_unlock(&priv->wakeup_lock); + + return ret; +} + +static inline int wcd9378_tx_path_get(const char *wname, + unsigned int *path_num) +{ + int ret = 0; + char *widget_name = NULL; + char *w_name = NULL; + char *path_num_char = NULL; + char *path_name = NULL; + + widget_name = kstrndup(wname, 9, GFP_KERNEL); + if (!widget_name) + return -EINVAL; + + w_name = widget_name; + + path_name = strsep(&widget_name, " "); + if (!path_name) { + pr_err("%s: Invalid widget name = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto err; + } + path_num_char = strpbrk(path_name, "0123"); + if (!path_num_char) { + pr_err("%s: tx path index not found\n", + __func__); + ret = -EINVAL; + goto err; + } + ret = kstrtouint(path_num_char, 10, path_num); + if (ret < 0) + pr_err("%s: Invalid tx path = %s\n", + __func__, w_name); + +err: + kfree(w_name); + return ret; +} + +static int wcd9378_tx_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = NULL; + int ret = 0; + unsigned int path = 0; + + if (!component) + return -EINVAL; + + wcd9378 = snd_soc_component_get_drvdata(component); + + if (!wcd9378) + return -EINVAL; + + ret = wcd9378_tx_path_get(kcontrol->id.name, &path); + if (ret < 0) + return ret; + + ucontrol->value.integer.value[0] = wcd9378->tx_mode[path]; + + return 0; +} + +static int wcd9378_tx_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = NULL; + u32 mode_val; + unsigned int path = 0; + int ret = 0; + + if (!component) + return -EINVAL; + + wcd9378 = snd_soc_component_get_drvdata(component); + + if (!wcd9378) + return -EINVAL; + + ret = wcd9378_tx_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: mode: %d\n", __func__, mode_val); + + wcd9378->tx_mode[path] = mode_val; + + return 0; +} + +static int wcd9378_loopback_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 loopback_mode = 0; + + if (!component) + return -EINVAL; + + loopback_mode = (snd_soc_component_read(component, WCD9378_LOOP_BACK_MODE) & + WCD9378_LOOP_BACK_MODE_LOOPBACK_MODE_MASK); + + ucontrol->value.integer.value[0] = loopback_mode; + return 0; +} + +static int wcd9378_loopback_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 loopback_mode = 0; + + if (!component) + return -EINVAL; + + loopback_mode = ucontrol->value.enumerated.item[0]; + + snd_soc_component_update_bits(component, + WCD9378_LOOP_BACK_MODE, + WCD9378_LOOP_BACK_MODE_LOOPBACK_MODE_MASK, + loopback_mode); + + dev_dbg(component->dev, "%s: loopback_mode: %d\n", + __func__, loopback_mode); + return 0; +} + +static int wcd9378_aux_dsm_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 aux_dsm_in = 0; + + if (!component) + return -EINVAL; + + aux_dsm_in = (snd_soc_component_read(component, WCD9378_LB_IN_SEL_CTL) & + WCD9378_LB_IN_SEL_CTL_AUX_LB_IN_SEL_MASK); + + ucontrol->value.integer.value[0] = aux_dsm_in; + return 0; +} + +static int wcd9378_aux_dsm_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 aux_dsm_in = 0; + + if (!component) + return -EINVAL; + + aux_dsm_in = ucontrol->value.enumerated.item[0]; + + snd_soc_component_update_bits(component, + WCD9378_LB_IN_SEL_CTL, + WCD9378_LB_IN_SEL_CTL_AUX_LB_IN_SEL_MASK, + aux_dsm_in); + + dev_dbg(component->dev, "%s: aux_dsm input: %d\n", + __func__, aux_dsm_in); + return 0; +} + +static int wcd9378_hph_dsm_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 hph_dsm_in = 0; + + if (!component) + return -EINVAL; + + hph_dsm_in = (snd_soc_component_read(component, WCD9378_LB_IN_SEL_CTL) & + WCD9378_LB_IN_SEL_CTL_HPH_LB_IN_SEL_MASK); + + ucontrol->value.integer.value[0] = hph_dsm_in; + return 0; +} + +static int wcd9378_hph_dsm_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u32 hph_dsm_in = 0; + + if (!component) + return -EINVAL; + + hph_dsm_in = ucontrol->value.enumerated.item[0]; + + snd_soc_component_update_bits(component, + WCD9378_LB_IN_SEL_CTL, + WCD9378_LB_IN_SEL_CTL_HPH_LB_IN_SEL_MASK, + hph_dsm_in); + + dev_dbg(component->dev, "%s: hph_dsm input: %d\n", + __func__, hph_dsm_in); + return 0; +} + +static int wcd9378_hph_put_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + u16 offset = ucontrol->value.enumerated.item[0]; + u32 temp = 0; + + temp = 0x00 - offset * 0x180; + + wcd9378->hph_gain = (u16)(temp & 0xffff); + + dev_dbg(component->dev, "%s: hph gain is 0x%0x\n", __func__, wcd9378->hph_gain); + return 0; +} + +static int wcd9378_hph_get_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + u32 temp = 0; + u16 offset = 0; + + temp = 0 - wcd9378->hph_gain; + + offset = (u16)(temp & 0xffff); + + offset /= 0x180; + ucontrol->value.enumerated.item[0] = offset; + + dev_dbg(component->dev, "%s: offset is 0x%0x\n", __func__, offset); + return 0; +} + +static int wcd9378_ear_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ear_gain = 0; + + if (component == NULL) + return -EINVAL; + + ear_gain = + snd_soc_component_read(component, WCD9378_ANA_EAR_COMPANDER_CTL) & + WCD9378_ANA_EAR_COMPANDER_CTL_EAR_GAIN_MASK; + + ucontrol->value.enumerated.item[0] = ear_gain; + dev_dbg(component->dev, "%s: get ear_gain val: 0x%x\n", + __func__, ear_gain); + return 0; +} + +static int wcd9378_ear_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int ear_gain = 0; + + if (component == NULL) + return -EINVAL; + + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > 0x10) { + dev_err(component->dev, "%s: Unsupported gain val %ld\n", + __func__, ucontrol->value.integer.value[0]); + return -EINVAL; + } + + ear_gain = ucontrol->value.integer.value[0]; + snd_soc_component_update_bits(component, WCD9378_ANA_EAR_COMPANDER_CTL, + WCD9378_ANA_EAR_COMPANDER_CTL_EAR_GAIN_MASK, + ear_gain); + dev_dbg(component->dev, "%s: set ear_gain val: 0x%x\n", + __func__, ear_gain); + return 0; +} + +static int wcd9378_aux_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int aux_gain = 0; + + if (component == NULL) + return -EINVAL; + + aux_gain = snd_soc_component_read(component, WCD9378_AUX_INT_MISC) & + WCD9378_AUX_INT_MISC_PA_GAIN_MASK; + + ucontrol->value.enumerated.item[0] = aux_gain; + dev_dbg(component->dev, "%s: get aux_gain val: 0x%x\n", + __func__, aux_gain); + return 0; +} + +static int wcd9378_aux_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + int aux_gain = 0; + + if (component == NULL) + return -EINVAL; + + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > 0x8) { + dev_err(component->dev, "%s: Unsupported gain val %ld\n", + __func__, ucontrol->value.integer.value[0]); + return -EINVAL; + } + + aux_gain = ucontrol->value.integer.value[0]; + snd_soc_component_update_bits(component, WCD9378_AUX_INT_MISC, + WCD9378_AUX_INT_MISC_PA_GAIN_MASK, + aux_gain); + dev_dbg(component->dev, "%s: set aux_gain val: 0x%x\n", + __func__, aux_gain); + return 0; +} + +static int wcd9378_rx2_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + + if (ucontrol->value.enumerated.item[0]) + wcd9378->rx2_clk_mode = RX2_NORMAL_MODE; + else + wcd9378->rx2_clk_mode = RX2_HP_MODE; + return 1; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = wcd9378->hph_mode; + + return 0; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + if (wcd9378->hph_mode == ucontrol->value.enumerated.item[0]) + return 0; + + wcd9378->hph_mode = ucontrol->value.enumerated.item[0]; + + return 1; +} + +/* wcd9378_codec_get_dev_num - returns swr device number + * @component: Codec instance + * + * Return: swr device number on success or negative error + * code on failure. + */ +int wcd9378_codec_get_dev_num(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378; + + if (!component) + return -EINVAL; + + wcd9378 = snd_soc_component_get_drvdata(component); + if (!wcd9378 || !wcd9378->rx_swr_dev) { + pr_err("%s: wcd9378 component is NULL\n", __func__); + return -EINVAL; + } + + return wcd9378->rx_swr_dev->dev_num; +} +EXPORT_SYMBOL_GPL(wcd9378_codec_get_dev_num); + +static int wcd9378_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = 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 ? wcd9378->comp2_enable : + wcd9378->comp1_enable; + return 0; +} + +static int wcd9378_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = + 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) + wcd9378->comp2_enable = value; + else + wcd9378->comp1_enable = value; + + dev_dbg(component->dev, "%s: set compander: %d\n", __func__, value); + + return 0; +} + +static int wcd9378_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 wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + struct wcd9378_pdata *pdata = NULL; + int ret = 0; + + pdata = dev_get_platdata(wcd9378->dev); + + if (!pdata) { + dev_err(component->dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (!msm_cdc_is_ondemand_supply(wcd9378->dev, + wcd9378->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck")) + return 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (test_bit(ALLOW_BUCK_DISABLE, &wcd9378->status_mask)) { + dev_dbg(component->dev, + "%s: buck already in enabled state\n", + __func__); + clear_bit(ALLOW_BUCK_DISABLE, &wcd9378->status_mask); + return 0; + } + ret = msm_cdc_enable_ondemand_supply(wcd9378->dev, + wcd9378->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; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd9378->status_mask); + /* + * 200us sleep is required after LDO is enabled as per + * HW requirement + */ + usleep_range(200, 250); + break; + case SND_SOC_DAPM_POST_PMD: + set_bit(ALLOW_BUCK_DISABLE, &wcd9378->status_mask); + break; + } + return 0; +} + +static void wcd9378_tx_get_slave_ch_type_idx(const char *wname, int *ch_idx) +{ + u8 ch_type = 0; + + if (strnstr(wname, "ADC1", sizeof("ADC1"))) + ch_type = ADC1; + else if (strnstr(wname, "ADC2", sizeof("ADC2"))) + ch_type = ADC2; + else if (strnstr(wname, "ADC3", sizeof("ADC3"))) + ch_type = ADC3; + else if (strnstr(wname, "ADC4", sizeof("ADC4"))) + ch_type = ADC4; + else if (strnstr(wname, "DMIC0", sizeof("DMIC0"))) + ch_type = DMIC0; + else if (strnstr(wname, "DMIC1", sizeof("DMIC1"))) + ch_type = DMIC1; + else if (strnstr(wname, "MBHC", sizeof("MBHC"))) + ch_type = MBHC; + else if (strnstr(wname, "DMIC2", sizeof("DMIC2"))) + ch_type = DMIC2; + else if (strnstr(wname, "DMIC3", sizeof("DMIC3"))) + ch_type = DMIC3; + else if (strnstr(wname, "DMIC4", sizeof("DMIC4"))) + ch_type = DMIC4; + else if (strnstr(wname, "DMIC5", sizeof("DMIC5"))) + ch_type = DMIC5; + else + pr_err("%s: port name: %s is not listed\n", __func__, wname); + + if (ch_type) + *ch_idx = wcd9378_slave_get_slave_ch_val(ch_type); + else + *ch_idx = -EINVAL; +} + +static int wcd9378_tx_master_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = NULL; + int slave_ch_idx = -EINVAL; + + if (component == NULL) + return -EINVAL; + + wcd9378 = snd_soc_component_get_drvdata(component); + if (wcd9378 == NULL) + return -EINVAL; + + wcd9378_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + if (slave_ch_idx < 0 || slave_ch_idx >= WCD9378_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + ucontrol->value.integer.value[0] = wcd9378_slave_get_master_ch_val( + wcd9378->tx_master_ch_map[slave_ch_idx]); + + return 0; +} + +static int wcd9378_tx_master_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = NULL; + int slave_ch_idx = -EINVAL, idx = 0; + + if (component == NULL) + return -EINVAL; + + wcd9378 = snd_soc_component_get_drvdata(component); + if (wcd9378 == NULL) + return -EINVAL; + + wcd9378_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + + if (slave_ch_idx < 0 || slave_ch_idx >= WCD9378_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + dev_dbg(component->dev, "%s: slave_ch_idx: %d", __func__, slave_ch_idx); + dev_dbg(component->dev, "%s: ucontrol->value.enumerated.item[0] = %ld\n", + __func__, ucontrol->value.enumerated.item[0]); + + idx = ucontrol->value.enumerated.item[0]; + if (idx < 0 || idx >= ARRAY_SIZE(wcd9378_swr_master_ch_map)) + return -EINVAL; + + wcd9378->tx_master_ch_map[slave_ch_idx] = wcd9378_slave_get_master_ch(idx); + return 0; +} + +static int wcd9378_bcs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd9378->bcs_dis; + + return 0; +} + +static int wcd9378_bcs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + wcd9378->bcs_dis = ucontrol->value.integer.value[0]; + + return 0; +} + +static const char * const loopback_mode_text[] = { + "NO_LP", "SWR_LP1", "SWR_LP2", "SWR_LP3", +}; + +static const struct soc_enum loopback_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(loopback_mode_text), + loopback_mode_text); + +static const char * const aux_dsm_text[] = { + "TX2->AUX", "TX3->AUX", "TX0->AUX", "TX1->AUX", +}; + +static const struct soc_enum aux_dsm_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aux_dsm_text), + aux_dsm_text); + +static const char * const hph_dsm_text[] = { + "HPH_DSM_IN0", "HPH_DSM_IN1", "HPH_DSM_IN2", "HPH_DSM_IN3", +}; + +static const struct soc_enum hph_dsm_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(hph_dsm_text), + hph_dsm_text); + +static const char * const tx_mode_mux_text[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_NORMAL", "ADC_LP", +}; + +static const struct soc_enum tx_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const char * const rx2_mode_text[] = { + "HP", "NORMAL", +}; + +static const struct soc_enum rx2_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx2_mode_text), + rx2_mode_text); + +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", "CLS_AB_LP", "CLS_AB_LOHIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + + +static const char * const ear_pa_gain_text[] = { + "GAIN_6DB", "GAIN_4P5DB", "GAIN_3DB", "GAIN_1P5DB", "GAIN_0DB", + "GAIN_M1P5DB", "GAIN_M3DB", "GAIN_M4P5DB", "GAIN_M6DB", + "GAIN_M7P5DB", "GAIN_M9DB", "GAIN_M10P5DB", "GAIN_M12DB", + "GAIN_M13P5DB", "GAIN_M15DB", "GAIN_M16P5DB", "GAIN_M18DB", +}; + +static const struct soc_enum ear_pa_gain_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ear_pa_gain_text), + ear_pa_gain_text); + +static const char * const aux_pa_gain_text[] = { + "GAIN_6DB", "GAIN_4P5DB", "GAIN_3DB", "GAIN_1P5DB", "GAIN_0DB", + "GAIN_M1P5DB", "GAIN_M3DB", "GAIN_M4P5DB", "GAIN_M6DB", +}; + +static const struct soc_enum aux_pa_gain_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aux_pa_gain_text), + aux_pa_gain_text); + +const char * const tx_master_ch_text[] = { + "ZERO", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", "SWRM_TX1_CH4", + "SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", "SWRM_TX2_CH4", + "SWRM_TX3_CH1", "SWRM_TX3_CH2", "SWRM_TX3_CH3", "SWRM_TX3_CH4", + "SWRM_PCM_IN", +}; + +const struct soc_enum tx_master_ch_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_master_ch_text), + tx_master_ch_text); + +static const struct snd_kcontrol_new wcd9378_snd_controls[] = { + SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0, + wcd9378_get_compander, wcd9378_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0, + wcd9378_get_compander, wcd9378_set_compander), + SOC_SINGLE_EXT("ADC2_BCS Disable", SND_SOC_NOPM, 0, 1, 0, + wcd9378_bcs_get, wcd9378_bcs_put), + + SOC_ENUM_EXT("LOOPBACK Mode", loopback_mode_enum, + wcd9378_loopback_mode_get, wcd9378_loopback_mode_put), + SOC_ENUM_EXT("AUX_LB_IN SEL", aux_dsm_enum, + wcd9378_aux_dsm_get, wcd9378_aux_dsm_put), + SOC_ENUM_EXT("HPH_LB_IN SEL", hph_dsm_enum, + wcd9378_hph_dsm_get, wcd9378_hph_dsm_put), + + SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum, + wcd9378_tx_mode_get, wcd9378_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum, + wcd9378_tx_mode_get, wcd9378_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum, + wcd9378_tx_mode_get, wcd9378_tx_mode_put), + + SOC_ENUM_EXT("RX2 Mode", rx2_mode_enum, + NULL, wcd9378_rx2_mode_put), + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd9378_rx_hph_mode_get, wcd9378_rx_hph_mode_put), + SOC_SINGLE_EXT("HPH Volume", SND_SOC_NOPM, 0, 0x14, 0, + wcd9378_hph_get_gain, wcd9378_hph_put_gain), + SOC_ENUM_EXT("EAR_PA Gain", ear_pa_gain_enum, + wcd9378_ear_pa_gain_get, wcd9378_ear_pa_gain_put), + SOC_ENUM_EXT("AUX_PA Gain", aux_pa_gain_enum, + wcd9378_aux_pa_gain_get, wcd9378_aux_pa_gain_put), + + SOC_SINGLE_TLV("ADC1 Volume", WCD9378_ANA_TX_CH1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD9378_ANA_TX_CH2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD9378_ANA_TX_CH3, 0, 20, 0, + analog_gain), + + SOC_ENUM_EXT("ADC1 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("ADC2 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("ADC3 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("DMIC0 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("DMIC1 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("MBHC ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("DMIC2 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("DMIC3 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("DMIC4 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), + SOC_ENUM_EXT("DMIC5 ChMap", tx_master_ch_enum, + wcd9378_tx_master_ch_get, wcd9378_tx_master_ch_put), +}; + +static const struct snd_kcontrol_new amic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic4_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 char * const adc1_mux_text[] = { + "CH1_AMIC_DISABLE", "CH1_AMIC1", "CH1_AMIC2", "CH1_AMIC3", "CH1_AMIC4" +}; + +static const char * const adc2_mux_text[] = { + "CH2_AMIC_DISABLE", "CH2_AMIC1", "CH2_AMIC2", "CH2_AMIC3", "CH2_AMIC4" +}; + +static const char * const adc3_mux_text[] = { + "CH3_AMIC_DISABLE", "CH3_AMIC1", "CH3_AMIC3", "CH3_AMIC4" +}; + +static const char * const ear_mux_text[] = { + "RX0", "RX2" +}; + +static const char * const aux_mux_text[] = { + "RX1", "RX2" +}; + +static const struct soc_enum adc1_enum = + SOC_ENUM_SINGLE(WCD9378_TX_NEW_TX_CH12_MUX, + WCD9378_TX_NEW_TX_CH12_MUX_CH1_SEL_SHIFT, + ARRAY_SIZE(adc1_mux_text), adc1_mux_text); + +static const struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD9378_TX_NEW_TX_CH12_MUX, + WCD9378_TX_NEW_TX_CH12_MUX_CH2_SEL_SHIFT, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +static const struct soc_enum adc3_enum = + SOC_ENUM_SINGLE(WCD9378_TX_NEW_TX_CH34_MUX, + WCD9378_TX_NEW_TX_CH34_MUX_CH3_SEL_SHIFT, + ARRAY_SIZE(adc3_mux_text), adc3_mux_text); + +static const struct soc_enum ear_enum = + SOC_ENUM_SINGLE(WCD9378_CDC_AUX_GAIN_CTL, + WCD9378_CDC_AUX_GAIN_CTL_AUX_EN_SHIFT, + ARRAY_SIZE(ear_mux_text), ear_mux_text); + +static const struct soc_enum aux_enum = + SOC_ENUM_SINGLE(WCD9378_CDC_AUX_GAIN_CTL, + WCD9378_CDC_AUX_GAIN_CTL_AUX_EN_SHIFT, + ARRAY_SIZE(aux_mux_text), aux_mux_text); + +static const struct snd_kcontrol_new tx_adc1_mux = + SOC_DAPM_ENUM("ADC1 MUX Mux", adc1_enum); + +static const struct snd_kcontrol_new tx_adc2_mux = + SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); + +static const struct snd_kcontrol_new tx_adc3_mux = + SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum); + +static const struct snd_kcontrol_new ear_mux = + SOC_DAPM_ENUM("EAR Mux", ear_enum); + +static const struct snd_kcontrol_new aux_mux = + SOC_DAPM_ENUM("AUX Mux", aux_enum); + +static const struct snd_kcontrol_new dac1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dac2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new ear_mixer_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new aux_mixer_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 struct snd_kcontrol_new rx0_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_soc_dapm_widget wcd9378_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("VA AMIC1"), + SND_SOC_DAPM_INPUT("VA AMIC2"), + SND_SOC_DAPM_INPUT("VA AMIC3"), + SND_SOC_DAPM_INPUT("VA AMIC4"), + + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_AUX"), + + /*tx widgets*/ + SND_SOC_DAPM_MIXER_E("TX0 SEQUENCER", SND_SOC_NOPM, ADC1, 0, + NULL, 0, wcd9378_tx_sequencer_enable, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("TX1 SEQUENCER", SND_SOC_NOPM, ADC2, 0, + NULL, 0, wcd9378_tx_sequencer_enable, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("TX2 SEQUENCER", SND_SOC_NOPM, ADC3, 0, + NULL, 0, wcd9378_tx_sequencer_enable, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC1 MUX", SND_SOC_NOPM, 0, 0, + &tx_adc1_mux), + 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_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd9378_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, + wcd9378_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, + wcd9378_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, + wcd9378_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, + wcd9378_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, + wcd9378_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /*rx widgets*/ + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd9378_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, + wcd9378_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("HPH SEQUENCER", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd9378_hph_sequencer_enable, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd9378_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd9378_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("SA SEQUENCER", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd9378_sa_sequencer_enable, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("EAR_RDAC", NULL, SND_SOC_NOPM, 0, 0, + wcd9378_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("AUX_RDAC", NULL, SND_SOC_NOPM, 0, 0, + wcd9378_codec_aux_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_PGA_E("EAR PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd9378_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AUX PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd9378_codec_enable_aux_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, + wcd9378_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, + wcd9378_enable_clsh, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("AMIC1_MIXER", SND_SOC_NOPM, 0, 0, + amic1_switch, ARRAY_SIZE(amic1_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC2_MIXER", SND_SOC_NOPM, 0, 0, + amic2_switch, ARRAY_SIZE(amic2_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC3_MIXER", SND_SOC_NOPM, 0, 0, + amic3_switch, ARRAY_SIZE(amic3_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC4_MIXER", SND_SOC_NOPM, 0, 0, + amic4_switch, ARRAY_SIZE(amic4_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC1_MIXER", SND_SOC_NOPM, 0, 0, + va_amic1_switch, ARRAY_SIZE(va_amic1_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC2_MIXER", SND_SOC_NOPM, 0, 0, + va_amic2_switch, ARRAY_SIZE(va_amic2_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC3_MIXER", SND_SOC_NOPM, 0, 0, + va_amic3_switch, ARRAY_SIZE(va_amic3_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC4_MIXER", SND_SOC_NOPM, 0, 0, + va_amic4_switch, ARRAY_SIZE(va_amic4_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, DMIC1, + 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), + wcd9378_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, DMIC2, + 0, dmic2_switch, ARRAY_SIZE(dmic2_switch), + wcd9378_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, DMIC3, + 0, dmic3_switch, ARRAY_SIZE(dmic3_switch), + wcd9378_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, DMIC4, + 0, dmic4_switch, ARRAY_SIZE(dmic4_switch), + wcd9378_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, DMIC5, + 0, dmic5_switch, ARRAY_SIZE(dmic5_switch), + wcd9378_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, DMIC6, + 0, dmic6_switch, ARRAY_SIZE(dmic6_switch), + wcd9378_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* micbias widgets*/ + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd9378_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd9378_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd9378_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* micbias pull up widgets*/ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd9378_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd9378_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd9378_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* rx mixer widgets*/ + SND_SOC_DAPM_MUX("EAR_MUX", SND_SOC_NOPM, 0, 0, &ear_mux), + SND_SOC_DAPM_MUX("AUX_MUX", SND_SOC_NOPM, 0, 0, &aux_mux), + SND_SOC_DAPM_MIXER("EAR_MIXER", SND_SOC_NOPM, 0, 0, + ear_mixer_switch, ARRAY_SIZE(ear_mixer_switch)), + SND_SOC_DAPM_MIXER("AUX_MIXER", SND_SOC_NOPM, 0, 0, + aux_mixer_switch, ARRAY_SIZE(aux_mixer_switch)), + SND_SOC_DAPM_MIXER("DAC1", SND_SOC_NOPM, 0, 0, + dac1_switch, ARRAY_SIZE(dac1_switch)), + SND_SOC_DAPM_MIXER("DAC2", SND_SOC_NOPM, 0, 0, + dac2_switch, ARRAY_SIZE(dac2_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("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"), + + /*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 wcd9378_audio_map[] = { +/*ADC-1 (channel-1)*/ + {"ADC1_OUTPUT", NULL, "TX0 SEQUENCER"}, + {"TX0 SEQUENCER", NULL, "ADC1 MUX"}, + {"ADC1 MUX", "CH1_AMIC1", "AMIC1_MIXER"}, + {"ADC1 MUX", "CH1_AMIC2", "AMIC2_MIXER"}, + {"ADC1 MUX", "CH1_AMIC3", "AMIC3_MIXER"}, + {"ADC1 MUX", "CH1_AMIC4", "AMIC4_MIXER"}, + +/*ADC-2 (channel-2)*/ + {"ADC2_OUTPUT", NULL, "TX1 SEQUENCER"}, + {"TX1 SEQUENCER", NULL, "ADC2 MUX"}, + {"ADC2 MUX", "CH2_AMIC1", "AMIC1_MIXER"}, + {"ADC2 MUX", "CH2_AMIC2", "AMIC2_MIXER"}, + {"ADC2 MUX", "CH2_AMIC3", "AMIC3_MIXER"}, + {"ADC2 MUX", "CH2_AMIC4", "AMIC4_MIXER"}, + +/*ADC-3 (channel-3)*/ + {"ADC3_OUTPUT", NULL, "TX2 SEQUENCER"}, + {"TX2 SEQUENCER", NULL, "ADC3 MUX"}, + {"ADC3 MUX", "CH3_AMIC1", "AMIC1_MIXER"}, + {"ADC3 MUX", "CH3_AMIC3", "AMIC3_MIXER"}, + {"ADC3 MUX", "CH3_AMIC4", "AMIC4_MIXER"}, + + {"AMIC1_MIXER", "Switch", "AMIC1"}, + {"AMIC1_MIXER", NULL, "VA_AMIC1_MIXER"}, + {"VA_AMIC1_MIXER", "Switch", "VA AMIC1"}, + + {"AMIC2_MIXER", "Switch", "AMIC2"}, + {"AMIC2_MIXER", NULL, "VA_AMIC2_MIXER"}, + {"VA_AMIC2_MIXER", "Switch", "VA AMIC2"}, + + {"AMIC3_MIXER", "Switch", "AMIC3"}, + {"AMIC3_MIXER", NULL, "VA_AMIC3_MIXER"}, + {"VA_AMIC3_MIXER", "Switch", "VA AMIC3"}, + + {"AMIC4_MIXER", "Switch", "AMIC4"}, + {"AMIC4_MIXER", NULL, "VA_AMIC4_MIXER"}, + {"VA_AMIC4_MIXER", "Switch", "VA AMIC4"}, + + {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, + + {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_MIXER", "Switch", "DMIC3"}, + + {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_MIXER", "Switch", "DMIC4"}, + + {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_MIXER", "Switch", "DMIC5"}, + + {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_MIXER", "Switch", "DMIC6"}, + +/*Headphone playback*/ + {"IN1_HPHL", NULL, "VDD_BUCK"}, + {"IN1_HPHL", NULL, "CLS_H_PORT"}, + {"HPH SEQUENCER", NULL, "IN1_HPHL"}, + {"RDAC1", NULL, "HPH SEQUENCER"}, + {"HPHL_RDAC", "Switch", "RDAC1"}, + {"HPHL PGA", NULL, "HPHL_RDAC"}, + {"HPHL", NULL, "HPHL PGA"}, + + {"IN2_HPHR", NULL, "VDD_BUCK"}, + {"IN2_HPHR", NULL, "CLS_H_PORT"}, + {"HPH SEQUENCER", NULL, "IN2_HPHR"}, + {"RDAC2", NULL, "HPH SEQUENCER"}, + {"HPHR_RDAC", "Switch", "RDAC2"}, + {"HPHR PGA", NULL, "HPHR_RDAC"}, + {"HPHR", NULL, "HPHR PGA"}, + +/*Amplier playback*/ + {"IN3_AUX", NULL, "VDD_BUCK"}, + {"EAR_MUX", "RX0", "IN1_HPHL"}, + {"EAR_MUX", "RX2", "IN3_AUX"}, + {"DAC1", "Switch", "EAR_MUX"}, + {"EAR_RDAC", NULL, "DAC1"}, + {"SA SEQUENCER", NULL, "EAR_RDAC"}, + {"EAR_MIXER", "Switch", "SA SEQUENCER"}, + {"EAR PGA", NULL, "EAR_MIXER"}, + {"EAR", NULL, "EAR PGA"}, + + {"AUX_MUX", "RX1", "IN2_HPHR"}, + {"AUX_MUX", "RX2", "IN3_AUX"}, + {"DAC2", "Switch", "AUX_MUX"}, + {"AUX_RDAC", NULL, "DAC2"}, + {"SA SEQUENCER", NULL, "AUX_RDAC"}, + {"AUX_MIXER", "Switch", "SA SEQUENCER",}, + {"AUX PGA", NULL, "AUX_MIXER"}, + {"AUX", NULL, "AUX PGA"}, +}; + +static ssize_t wcd9378_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct wcd9378_priv *priv; + char buffer[WCD9378_VERSION_ENTRY_SIZE]; + int len = 0; + + priv = (struct wcd9378_priv *) entry->private_data; + if (!priv) { + pr_err("%s: wcd9378 priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->version) { + case WCD9378_VERSION_1_0: + len = scnprintf(buffer, sizeof(buffer), "WCD9378_1_0\n"); + break; + default: + len = scnprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); + } + + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static struct snd_info_entry_ops wcd9378_info_ops = { + .read = wcd9378_version_read, +}; + +/* + * wcd9378_info_create_codec_entry - creates wcd9378 module + * @codec_root: The parent directory + * @component: component instance + * + * Creates wcd9378 module, version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int wcd9378_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct wcd9378_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:wcd9378 module already created\n", __func__); + return 0; + } + card = component->card; + + priv->entry = snd_info_create_module_entry(codec_root->module, + "wcd9378", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create wcd9378 entry\n", + __func__); + return -ENOMEM; + } + priv->entry->mode = S_IFDIR | 0555; + if (snd_info_register(priv->entry) < 0) { + snd_info_free_entry(priv->entry); + 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 wcd9378 version entry\n", + __func__); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + version_entry->private_data = priv; + version_entry->size = WCD9378_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &wcd9378_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->version_entry = version_entry; + + return 0; +} +EXPORT_SYMBOL_GPL(wcd9378_info_create_codec_entry); + +static void wcd9378_class_load(struct snd_soc_component *component) +{ + /*SMP AMP CLASS LOADING*/ + snd_soc_component_update_bits(component, WCD9378_FUNC_ACT, + WCD9378_FUNC_ACT_FUNC_ACT_MASK, 0x01); + usleep_range(20000, 20010); + + snd_soc_component_update_bits(component, WCD9378_SMP_AMP_FUNC_STAT, + WCD9378_SMP_AMP_FUNC_STAT_FUNC_STAT_MASK, 0xFF); + + /*SMP JACK CLASS LOADING*/ + snd_soc_component_update_bits(component, WCD9378_SMP_JACK_FUNC_ACT, + WCD9378_SMP_JACK_FUNC_ACT_FUNC_ACT_MASK, 0x01); + usleep_range(30000, 30010); + + snd_soc_component_update_bits(component, WCD9378_CMT_GRP_MASK, + WCD9378_CMT_GRP_MASK_CMT_GRP_MASK_MASK, 0x02); + + snd_soc_component_update_bits(component, WCD9378_SMP_JACK_FUNC_STAT, + WCD9378_SMP_JACK_FUNC_STAT_FUNC_STAT_MASK, 0xFF); + + /*SMP MIC0 CLASS LOADING*/ + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL0_FUNC_ACT, + WCD9378_SMP_MIC_CTRL0_FUNC_ACT_FUNC_ACT_MASK, 0x01); + usleep_range(5000, 5010); + + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL0_FUNC_STAT, + WCD9378_SMP_MIC_CTRL0_FUNC_STAT_FUNC_STAT_MASK, 0xFF); + + /*SMP MIC1 CLASS LOADING*/ + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL1_FUNC_ACT, + WCD9378_SMP_MIC_CTRL1_FUNC_ACT_FUNC_ACT_MASK, 0x01); + usleep_range(5000, 5010); + + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL1_FUNC_STAT, + WCD9378_SMP_MIC_CTRL1_FUNC_STAT_FUNC_STAT_MASK, 0xFF); + + /*SMP MIC2 CLASS LOADING*/ + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL2_FUNC_ACT, + WCD9378_SMP_MIC_CTRL2_FUNC_ACT_FUNC_ACT_MASK, 0x01); + usleep_range(5000, 5010); + + snd_soc_component_update_bits(component, WCD9378_SMP_MIC_CTRL2_FUNC_STAT, + WCD9378_SMP_MIC_CTRL2_FUNC_STAT_FUNC_STAT_MASK, 0xFF); +} + +static void wcd9378_micb_value_convert(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + struct wcd9378_pdata *pdata = + dev_get_platdata(wcd9378->dev); + struct wcd9378_micbias_setting *mb = &pdata->micbias; + + mb->micb1_usage_val = wcd9378_micb_usage_value_convert(component, + mb->micb1_mv, MIC_BIAS_1); + + mb->micb2_usage_val = wcd9378_micb_usage_value_convert(component, + mb->micb2_mv, MIC_BIAS_2); + + mb->micb3_usage_val = wcd9378_micb_usage_value_convert(component, + mb->micb3_mv, MIC_BIAS_3); + + pr_debug("%s: micb1_usage: 0x%x, micb2_usage: 0x%x, micb3_usage: 0x%x\n", __func__, + mb->micb1_usage_val, mb->micb2_usage_val, mb->micb3_usage_val); +} + +static int wcd9378_wcd_mode_check(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = + snd_soc_component_get_drvdata(component); + + if (snd_soc_component_read(component, + WCD9378_EFUSE_REG_29) + & WCD9378_EFUSE_REG_29_PLATFORM_BLOWN_MASK) { + if (((snd_soc_component_read(component, + WCD9378_EFUSE_REG_29) & + WCD9378_EFUSE_REG_29_PLATFORM_MASK) >> 1) == wcd9378->wcd_mode) + return true; + else + return false; + } else { + if ((snd_soc_component_read(component, WCD9378_PLATFORM_CTL) + & WCD9378_PLATFORM_CTL_MODE_MASK) == wcd9378->wcd_mode) + return true; + else + return false; + } + + return 0; +} + +static int wcd9378_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = -EINVAL; + + wcd9378 = snd_soc_component_get_drvdata(component); + if (!wcd9378) + return -EINVAL; + + wcd9378->component = component; + snd_soc_component_init_regmap(component, wcd9378->regmap); + + devm_regmap_qti_debugfs_register(&wcd9378->tx_swr_dev->dev, wcd9378->regmap); + + ret = wcd9378_wcd_mode_check(component); + if (!ret) { + dev_err(component->dev, "wcd mode check failed\n"); + ret = -EINVAL; + goto exit; + } + + ret = wcd9378_mbhc_init(&wcd9378->mbhc, component); + if (ret) { + pr_err("%s: mbhc initialization failed\n", __func__); + ret = -EINVAL; + goto exit; + } + + 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, "VA AMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC4"); + 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, "ADC1_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC2_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC3_OUTPUT"); + 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(&wcd9378->clsh_info); + + wcd9378_init_reg(component); + + wcd9378_micb_value_convert(component); + + wcd9378->version = WCD9378_VERSION_1_0; + /* Register event notifier */ + wcd9378->nblock.notifier_call = wcd9378_event_notify; + if (wcd9378->register_notifier) { + ret = wcd9378->register_notifier(wcd9378->handle, + &wcd9378->nblock, + true); + if (ret) { + dev_err(component->dev, + "%s: Failed to register notifier %d\n", + __func__, ret); + return ret; + } + } + +exit: + return ret; +} + +static void wcd9378_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + if (!wcd9378) { + dev_err(component->dev, "%s: wcd9378 is already NULL\n", + __func__); + return; + } + if (wcd9378->register_notifier) + wcd9378->register_notifier(wcd9378->handle, + &wcd9378->nblock, + false); +} + +static int wcd9378_soc_codec_suspend(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + if (!wcd9378) + return 0; + wcd9378->dapm_bias_off = true; + return 0; +} + +static int wcd9378_soc_codec_resume(struct snd_soc_component *component) +{ + struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); + + if (!wcd9378) + return 0; + wcd9378->dapm_bias_off = false; + return 0; +} + +static const struct snd_soc_component_driver soc_codec_dev_wcd9378 = { + .name = WCD9378_DRV_NAME, + .probe = wcd9378_soc_codec_probe, + .remove = wcd9378_soc_codec_remove, + .controls = wcd9378_snd_controls, + .num_controls = ARRAY_SIZE(wcd9378_snd_controls), + .dapm_widgets = wcd9378_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd9378_dapm_widgets), + .dapm_routes = wcd9378_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd9378_audio_map), + .suspend = wcd9378_soc_codec_suspend, + .resume = wcd9378_soc_codec_resume, +}; + +static int wcd9378_reset(struct device *dev) +{ + struct wcd9378_priv *wcd9378 = NULL; + int rc = 0; + int value = 0; + + if (!dev) + return -ENODEV; + + wcd9378 = dev_get_drvdata(dev); + if (!wcd9378) + return -EINVAL; + + if (!wcd9378->rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + value = msm_cdc_pinctrl_get_state(wcd9378->rst_np); + if (value > 0) + return 0; + + rc = msm_cdc_pinctrl_select_sleep_state(wcd9378->rst_np); + if (rc) { + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 20us sleep required after pulling the reset gpio to LOW */ + usleep_range(80, 85); + + rc = msm_cdc_pinctrl_select_active_state(wcd9378->rst_np); + if (rc) { + dev_err(dev, "%s: wcd active state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 20us sleep required after pulling the reset gpio to HIGH */ + usleep_range(80, 85); + + return rc; +} + +static int wcd9378_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 wcd9378_dt_parse_micbias_info(struct device *dev, + struct wcd9378_micbias_setting *mb) +{ + u32 prop_val = 0; + int rc = 0; + + /* MB1 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv", + NULL)) { + rc = wcd9378_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 = wcd9378_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 = wcd9378_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 wcd9378_reset_low(struct device *dev) +{ + struct wcd9378_priv *wcd9378 = NULL; + int rc = 0; + + if (!dev) + return -ENODEV; + + wcd9378 = dev_get_drvdata(dev); + if (!wcd9378) + return -EINVAL; + + if (!wcd9378->rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + rc = msm_cdc_pinctrl_select_sleep_state(wcd9378->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 wcd9378_pdata *wcd9378_populate_dt_data(struct device *dev) +{ + struct wcd9378_pdata *pdata = NULL; + + pdata = devm_kzalloc(dev, sizeof(struct wcd9378_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-slave", 0); + pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0); + + wcd9378_dt_parse_micbias_info(dev, &pdata->micbias); + + return pdata; +} + +static struct snd_soc_dai_driver wcd9378_dai[] = { + { + .name = "wcd9378_cdc", + .playback = { + .stream_name = "WCD9378_AIF Playback", + .rates = WCD9378_RATES | WCD9378_FRAC_RATES, + .formats = WCD9378_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .capture = { + .stream_name = "WCD9378_AIF Capture", + .rates = WCD9378_RATES | WCD9378_FRAC_RATES, + .formats = WCD9378_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + }, +}; + +static irqreturn_t wcd9378_wd_handle_irq(int irq, void *data) +{ + pr_err_ratelimited("%s: Watchdog interrupt for irq =%d triggered\n", + __func__, irq); + return IRQ_HANDLED; +} + +static int wcd9378_bind(struct device *dev) +{ + int ret = 0; + struct wcd9378_pdata *pdata = dev_get_platdata(dev); + struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev); + + /* + * Add 5msec delay to provide sufficient time for + * soundwire auto enumeration of slave devices as + * per HW requirement. + */ + usleep_range(5000, 5010); + + ret = component_bind_all(dev, wcd9378); + if (ret) { + dev_err(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + return ret; + } + + wcd9378->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave); + if (!wcd9378->rx_swr_dev) { + dev_err(dev, "%s: Could not find RX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + wcd9378->rx_swr_dev->paging_support = true; + + wcd9378->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave); + if (!wcd9378->tx_swr_dev) { + dev_err(dev, "%s: Could not find TX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + wcd9378->tx_swr_dev->paging_support = true; + + swr_init_port_params(wcd9378->tx_swr_dev, SWR_NUM_PORTS, + wcd9378->swr_tx_port_params); + + wcd9378->regmap = devm_regmap_init_swr(wcd9378->tx_swr_dev, + &wcd9378_regmap_config); + if (!wcd9378->regmap) { + dev_err(dev, "%s: Regmap init failed\n", + __func__); + goto err; + } + + regmap_write(wcd9378->regmap, SWRS_SCP_SDCA_INTRTYPE_1, 0xff); + regmap_write(wcd9378->regmap, SWRS_SCP_SDCA_INTRTYPE_2, 0x0b); + regmap_write(wcd9378->regmap, SWRS_SCP_SDCA_INTRTYPE_3, 0xff); + + wcd9378_regmap_irq_chip.irq_drv_data = wcd9378; + wcd9378->irq_info.wcd_regmap_irq_chip = &wcd9378_regmap_irq_chip; + wcd9378->irq_info.codec_name = "WCD9378"; + wcd9378->irq_info.regmap = wcd9378->regmap; + wcd9378->irq_info.dev = dev; + ret = wcd_irq_init(&wcd9378->irq_info, &wcd9378->virq); + if (ret) { + dev_err(wcd9378->dev, "%s: IRQ init failed: %d\n", + __func__, ret); + goto err; + } + + dev_err(wcd9378->dev, "%s: wcd irq init done\n", + __func__); + wcd9378->tx_swr_dev->slave_irq = wcd9378->virq; + + /* Request for watchdog interrupt */ + wcd_request_irq(&wcd9378->irq_info, WCD9378_IRQ_HPHR_PDM_WD_INT, + "HPHR PDM WD INT", wcd9378_wd_handle_irq, NULL); + wcd_request_irq(&wcd9378->irq_info, WCD9378_IRQ_HPHL_PDM_WD_INT, + "HPHL PDM WD INT", wcd9378_wd_handle_irq, NULL); + wcd_request_irq(&wcd9378->irq_info, WCD9378_IRQ_AUX_PDM_WD_INT, + "AUX PDM WD INT", wcd9378_wd_handle_irq, NULL); + /* Disable watchdog interrupt for HPH and AUX */ + wcd_disable_irq(&wcd9378->irq_info, WCD9378_IRQ_HPHR_PDM_WD_INT); + wcd_disable_irq(&wcd9378->irq_info, WCD9378_IRQ_HPHL_PDM_WD_INT); + wcd_disable_irq(&wcd9378->irq_info, WCD9378_IRQ_AUX_PDM_WD_INT); + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd9378, + wcd9378_dai, ARRAY_SIZE(wcd9378_dai)); + if (ret) { + dev_err(dev, "%s: Codec registration failed\n", + __func__); + goto err_irq; + } + + return ret; +err_irq: + wcd_irq_exit(&wcd9378->irq_info, wcd9378->virq); +err: + component_unbind_all(dev, wcd9378); + return ret; +} + +static void wcd9378_unbind(struct device *dev) +{ + struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev); + + wcd_free_irq(&wcd9378->irq_info, WCD9378_IRQ_HPHR_PDM_WD_INT, NULL); + wcd_free_irq(&wcd9378->irq_info, WCD9378_IRQ_HPHL_PDM_WD_INT, NULL); + wcd_free_irq(&wcd9378->irq_info, WCD9378_IRQ_AUX_PDM_WD_INT, NULL); + wcd_irq_exit(&wcd9378->irq_info, wcd9378->virq); + snd_soc_unregister_component(dev); + component_unbind_all(dev, wcd9378); +} + +static const struct of_device_id wcd9378_dt_match[] = { + { .compatible = "qcom,wcd9378-codec", .data = "wcd9378"}, + {} +}; + +static const struct component_master_ops wcd9378_comp_ops = { + .bind = wcd9378_bind, + .unbind = wcd9378_unbind, +}; + +static int wcd9378_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void wcd9378_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int wcd9378_add_slave_components(struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np, *rx_node, *tx_node; + + np = dev->of_node; + + rx_node = of_parse_phandle(np, "qcom,rx-slave", 0); + if (!rx_node) { + dev_err(dev, "%s: Rx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(rx_node); + component_match_add_release(dev, matchptr, + wcd9378_release_of, + wcd9378_compare_of, + rx_node); + + tx_node = of_parse_phandle(np, "qcom,tx-slave", 0); + if (!tx_node) { + dev_err(dev, "%s: Tx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(tx_node); + component_match_add_release(dev, matchptr, + wcd9378_release_of, + wcd9378_compare_of, + tx_node); + return 0; +} + +static int wcd9378_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct wcd9378_priv *wcd9378 = NULL; + struct wcd9378_pdata *pdata = NULL; + struct wcd_ctrl_platform_data *plat_data = NULL; + struct device *dev = &pdev->dev; + int ret; + + wcd9378 = devm_kzalloc(dev, sizeof(struct wcd9378_priv), + GFP_KERNEL); + if (!wcd9378) + return -ENOMEM; + + dev_set_drvdata(dev, wcd9378); + wcd9378->dev = dev; + + pdata = wcd9378_populate_dt_data(dev); + if (!pdata) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); + return -EINVAL; + } + dev->platform_data = pdata; + + wcd9378->rst_np = pdata->rst_np; + ret = msm_cdc_init_supplies(dev, &wcd9378->supplies, + pdata->regulator, pdata->num_supplies); + if (!wcd9378->supplies) { + dev_err(dev, "%s: Cannot init wcd supplies\n", + __func__); + return ret; + } + + plat_data = dev_get_platdata(dev->parent); + if (!plat_data) { + dev_err(dev, "%s: platform data from parent is NULL\n", + __func__); + return -EINVAL; + } + wcd9378->handle = (void *)plat_data->handle; + if (!wcd9378->handle) { + dev_err(dev, "%s: handle is NULL\n", __func__); + return -EINVAL; + } + + wcd9378->update_wcd_event = plat_data->update_wcd_event; + if (!wcd9378->update_wcd_event) { + dev_err(dev, "%s: update_wcd_event api is null!\n", + __func__); + return -EINVAL; + } + wcd9378->register_notifier = plat_data->register_notifier; + if (!wcd9378->register_notifier) { + dev_err(dev, "%s: register_notifier api is null!\n", + __func__); + return -EINVAL; + } + + ret = of_property_read_u32(dev->of_node, "qcom,wcd-mode", + &wcd9378->wcd_mode); + if (ret) { + dev_dbg(dev, "%s: wcd-mode read failed, use mobile mode\n", + __func__); + wcd9378->wcd_mode = WCD9378_MOBILE_MODE; + } + + ret = msm_cdc_enable_static_supplies(&pdev->dev, wcd9378->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(dev, "%s: wcd static supply enable failed!\n", + __func__); + return ret; + } + + ret = wcd9378_parse_port_mapping(dev, "qcom,rx_swr_ch_map", + CODEC_RX); + ret |= wcd9378_parse_port_mapping(dev, "qcom,tx_swr_ch_map", + CODEC_TX); + + if (ret) { + dev_err(dev, "Failed to read port mapping\n"); + goto err; + } + ret = wcd9378_parse_port_params(dev, "qcom,swr-tx-port-params", + CODEC_TX); + if (ret) { + dev_err(dev, "Failed to read port params\n"); + goto err; + } + + mutex_init(&wcd9378->wakeup_lock); + mutex_init(&wcd9378->micb_lock); + mutex_init(&wcd9378->sys_usage_lock); + ret = wcd9378_add_slave_components(dev, &match); + if (ret) + goto err_lock_init; + + ret = wcd9378_reset(dev); + if (ret == -EPROBE_DEFER) { + dev_err(dev, "%s: wcd reset failed!\n", __func__); + goto err_lock_init; + } + + wcd9378->wakeup = wcd9378_wakeup; + + return component_master_add_with_match(dev, + &wcd9378_comp_ops, match); + +err_lock_init: + mutex_destroy(&wcd9378->micb_lock); + mutex_destroy(&wcd9378->wakeup_lock); + mutex_destroy(&wcd9378->sys_usage_lock); +err: + return ret; +} + +static int wcd9378_remove(struct platform_device *pdev) +{ + struct wcd9378_priv *wcd9378 = NULL; + + wcd9378 = platform_get_drvdata(pdev); + component_master_del(&pdev->dev, &wcd9378_comp_ops); + mutex_destroy(&wcd9378->micb_lock); + mutex_destroy(&wcd9378->wakeup_lock); + mutex_destroy(&wcd9378->sys_usage_lock); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int wcd9378_suspend(struct device *dev) +{ + struct wcd9378_priv *wcd9378 = NULL; + int ret = 0; + struct wcd9378_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd9378 = dev_get_drvdata(dev); + if (!wcd9378) + return -EINVAL; + + pdata = dev_get_platdata(wcd9378->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(ALLOW_BUCK_DISABLE, &wcd9378->status_mask)) { + ret = msm_cdc_disable_ondemand_supply(wcd9378->dev, + wcd9378->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; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd9378->status_mask); + } + if (wcd9378->dapm_bias_off || + (wcd9378->component && + (snd_soc_component_get_bias_level(wcd9378->component) == + SND_SOC_BIAS_OFF))) { + msm_cdc_set_supplies_lpm_mode(wcd9378->dev, + wcd9378->supplies, + pdata->regulator, + pdata->num_supplies, + true); + set_bit(WCD_SUPPLIES_LPM_MODE, &wcd9378->status_mask); + } + return 0; +} + +static int wcd9378_resume(struct device *dev) +{ + struct wcd9378_priv *wcd9378 = NULL; + struct wcd9378_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd9378 = dev_get_drvdata(dev); + if (!wcd9378) + return -EINVAL; + + pdata = dev_get_platdata(wcd9378->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(WCD_SUPPLIES_LPM_MODE, &wcd9378->status_mask)) { + msm_cdc_set_supplies_lpm_mode(wcd9378->dev, + wcd9378->supplies, + pdata->regulator, + pdata->num_supplies, + false); + clear_bit(WCD_SUPPLIES_LPM_MODE, &wcd9378->status_mask); + } + + return 0; +} + +static const struct dev_pm_ops wcd9378_dev_pm_ops = { + .suspend_late = wcd9378_suspend, + .resume_early = wcd9378_resume, +}; +#endif + +static struct platform_driver wcd9378_codec_driver = { + .probe = wcd9378_probe, + .remove = wcd9378_remove, + .driver = { + .name = "wcd9378_codec", + .of_match_table = of_match_ptr(wcd9378_dt_match), +#ifdef CONFIG_PM_SLEEP + .pm = &wcd9378_dev_pm_ops, +#endif + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd9378_codec_driver); +MODULE_DESCRIPTION("WCD9378 Codec driver"); +MODULE_LICENSE("GPL"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378.h new file mode 100644 index 0000000000..2d581c8f1f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9378/wcd9378.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _WCD9378_H +#define _WCD9378_H + +#include +#include +#include + +#define WCD9378_MAX_SLAVE_CH_TYPES 13 +#define ZERO 0 +#define WCD9378_DRV_NAME "wcd9378_codec" + +/* from WCD to SWR DMIC events */ +enum { + WCD9378_EVT_SSR_DOWN, + WCD9378_EVT_SSR_UP, +}; + +struct wcd9378_swr_slave_ch_map { + u8 ch_type; + u8 index; +}; + +static const struct wcd9378_swr_slave_ch_map wcd9378_swr_slv_tx_ch_idx[] = { + {ADC1, 0}, + {ADC2, 1}, + {ADC3, 2}, + {ADC4, 3}, + {DMIC0, 4}, + {DMIC1, 5}, + {MBHC, 6}, + {DMIC2, 6}, + {DMIC3, 7}, + {DMIC4, 8}, + {DMIC5, 9}, + {DMIC6, 10}, + {DMIC7, 11}, +}; + +static int wcd9378_swr_master_ch_map[] = { + ZERO, + SWRM_TX1_CH1, + SWRM_TX1_CH2, + SWRM_TX1_CH3, + SWRM_TX1_CH4, + SWRM_TX2_CH1, + SWRM_TX2_CH2, + SWRM_TX2_CH3, + SWRM_TX2_CH4, + SWRM_TX3_CH1, + SWRM_TX3_CH2, + SWRM_TX3_CH3, + SWRM_TX3_CH4, + SWRM_TX_PCM_IN, +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD9378) +int wcd9378_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component); + +int wcd9378_swr_dmic_register_notifier(struct snd_soc_component *wcd9378, + struct notifier_block *nblock, + bool enable); + +int wcd9378_codec_get_dev_num(struct snd_soc_component *component); + +static inline int wcd9378_slave_get_master_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD9378_MAX_SLAVE_CH_TYPES; i++) + if (ch == wcd9378_swr_master_ch_map[i]) + return i; + return 0; +} + +static inline int wcd9378_slave_get_master_ch(int idx) +{ + return wcd9378_swr_master_ch_map[idx]; +} + +static inline int wcd9378_slave_get_slave_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD9378_MAX_SLAVE_CH_TYPES; i++) + if (ch == wcd9378_swr_slv_tx_ch_idx[i].ch_type) + return wcd9378_swr_slv_tx_ch_idx[i].index; + + return -EINVAL; +} +#else +static inline int wcd9378_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} + +static inline int wcd9378_slave_get_master_ch_val(int ch) +{ + return 0; +} +static inline int wcd9378_slave_get_master_ch(int idx) +{ + return 0; +} +static inline int wcd9378_slave_get_slave_ch_val(int ch) +{ + return 0; +} +static int wcd9378_codec_get_dev_num(struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD9378 */ +#endif /* _WCD9378_H */ + diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Kbuild new file mode 100644 index 0000000000..e0a8d9baf4 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Kbuild @@ -0,0 +1,137 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + + + +ifeq ($(KERNEL_BUILD), 1) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_TRINKET), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KHAJE), y) + include $(AUDIO_ROOT)/config/bengalauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_HOLI), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_BLAIR), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_CLIFFS), y) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ WCD937X ############ + +# for WCD937X Codec +ifdef CONFIG_SND_SOC_WCD937X + WCD937X_OBJS += wcd937x.o + WCD937X_OBJS += wcd937x-regmap.o + WCD937X_OBJS += wcd937x-tables.o + WCD937X_OBJS += wcd937x-mbhc.o +endif + +ifdef CONFIG_SND_SOC_WCD937X_SLAVE + WCD937X_SLAVE_OBJS += wcd937x_slave.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +EXTRA_CFLAGS += $(INCS) + + +CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +EXTRA_CFLAGS += -Wheader-guard +endif + + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_WCD937X) += wcd937x_dlkm.o +wcd937x_dlkm-y := $(WCD937X_OBJS) + +obj-$(CONFIG_SND_SOC_WCD937X_SLAVE) += wcd937x_slave_dlkm.o +wcd937x_slave_dlkm-y := $(WCD937X_SLAVE_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Makefile b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/internal.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/internal.h new file mode 100644 index 0000000000..a47dfeaabe --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/internal.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _WCD937X_INTERNAL_H +#define _WCD937X_INTERNAL_H + +#include +#include +#include +#include +#include "wcd937x-mbhc.h" +#include "wcd937x.h" + +#define WCD937X_MAX_MICBIAS 3 + +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) +#define MAX_PORT 8 +#define MAX_CH_PER_PORT 8 +#define MAX_TX_PWR_CH 2 +#define SWR_NUM_PORTS 4 + +#define WCD937X_MAX_SLAVE_PORT_TYPES 10 +extern struct regmap_config wcd937x_regmap_config; + +struct codec_port_info { + u32 slave_port_type; + u32 master_port_type; + u32 ch_mask; + u32 num_ch; + u32 ch_rate; +}; +struct wcd937x_priv { + struct device *dev; + + int variant; + struct snd_soc_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[WCD937X_MAX_MICBIAS]; + s32 pullup_ref[WCD937X_MAX_MICBIAS]; + + struct fw_info *fw_data; + struct device_node *wcd_rst_np; + + struct mutex micb_lock; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + /* class h specific info */ + struct wcd_clsh_cdc_info clsh_info; + /* mbhc module */ + struct wcd937x_mbhc *mbhc; + + u32 hph_mode; + bool comp1_enable; + bool comp2_enable; + bool bcs_dis; + + 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 swr_port_params tx_port_params[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config swr_tx_port_params[SWR_UC_MAX]; + 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); + int (*wakeup)(void *handle, bool enable); + u32 version; + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + /*Entry for Variant info*/ + struct snd_info_entry *variant_entry; + int ear_rx_path; + int ana_clk_count; + int adc_count; + struct mutex ana_tx_clk_lock; + u8 tx_master_ch_map[WCD937X_MAX_SLAVE_CH_TYPES]; + bool usbc_hs_status; + u32 tx_ch_pwr[MAX_TX_PWR_CH]; +}; + +struct wcd937x_micbias_setting { + u8 ldoh_v; + u32 cfilt1_mv; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u8 bias1_cfilt_sel; +}; + +struct wcd937x_pdata { + struct device_node *rst_np; + struct device_node *rx_slave; + struct device_node *tx_slave; + struct wcd937x_micbias_setting micbias; + + 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 { + /* INTR_CTRL_INT_MASK_0 */ + WCD937X_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD937X_IRQ_MBHC_SW_DET, + WCD937X_IRQ_HPHR_OCP_INT, + WCD937X_IRQ_HPHR_CNP_INT, + WCD937X_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD937X_IRQ_HPHL_CNP_INT, + WCD937X_IRQ_EAR_CNP_INT, + WCD937X_IRQ_EAR_SCD_INT, + WCD937X_IRQ_AUX_CNP_INT, + WCD937X_IRQ_AUX_SCD_INT, + WCD937X_IRQ_HPHL_PDM_WD_INT, + WCD937X_IRQ_HPHR_PDM_WD_INT, + WCD937X_IRQ_AUX_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD937X_IRQ_LDORT_SCD_INT, + WCD937X_IRQ_MBHC_MOISTURE_INT, + WCD937X_IRQ_HPHL_SURGE_DET_INT, + WCD937X_IRQ_HPHR_SURGE_DET_INT, + WCD937X_NUM_IRQS, +}; + +extern void wcd937x_disable_bcs_before_slow_insert( + struct snd_soc_component *component, + bool bcs_disable); +extern struct wcd937x_mbhc *wcd937x_soc_get_mbhc( + struct snd_soc_component *component); +extern int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int volt, int micb_num); +extern int wcd937x_get_micb_vout_ctl_val(u32 micb_mv); +extern int wcd937x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm); +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-mbhc.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-mbhc.c new file mode 100644 index 0000000000..bcf06d3b41 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-mbhc.c @@ -0,0 +1,1158 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd937x-registers.h" +#include +#include +#include "internal.h" + +#define WCD937X_ZDET_SUPPORTED true +/* Z value defined in milliohm */ +#define WCD937X_ZDET_VAL_32 32000 +#define WCD937X_ZDET_VAL_400 400000 +#define WCD937X_ZDET_VAL_1200 1200000 +#define WCD937X_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define WCD937X_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define WCD937X_ZDET_NUM_MEASUREMENTS 900 +#define WCD937X_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define WCD937X_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define WCD937X_MBHC_ZDET_CONST (86 * 16384) +#define WCD937X_MBHC_MOISTURE_RREF R_24_KOHM + +static struct wcd_mbhc_register + wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN", + WCD937X_ANA_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + WCD937X_ANA_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + WCD937X_ANA_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + WCD937X_ANA_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + WCD937X_ANA_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + WCD937X_ANA_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + WCD937X_ANA_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + WCD937X_ANA_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + WCD937X_ANA_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + WCD937X_ANA_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + WCD937X_MBHC_NEW_CTL_1, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + WCD937X_MBHC_NEW_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + WCD937X_ANA_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE", + WCD937X_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + WCD937X_ANA_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + WCD937X_ANA_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + WCD937X_ANA_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + WCD937X_HPH_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + WCD937X_ANA_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + WCD937X_ANA_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + WCD937X_ANA_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + WCD937X_ANA_MICB2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + WCD937X_HPH_CNP_WG_TIME, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + WCD937X_ANA_HPH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + WCD937X_ANA_HPH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + WCD937X_ANA_HPH, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + WCD937X_ANA_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL", + 0, 0, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", + WCD937X_MBHC_CTL_BCS, 0x02, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + WCD937X_MBHC_NEW_FSM_STATUS, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + WCD937X_MBHC_NEW_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD937X_MBHC_NEW_FSM_STATUS, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD937X_HPH_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD937X_HPH_PA_CTL2, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", + WCD937X_HPH_L_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN", + WCD937X_HPH_R_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS", + WCD937X_DIGITAL_INTR_STATUS_0, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS", + WCD937X_DIGITAL_INTR_STATUS_0, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN", + WCD937X_MBHC_NEW_CTL_1, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD937X_MBHC_NEW_FSM_STATUS, + 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD937X_MBHC_NEW_FSM_STATUS, + 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD937X_MBHC_NEW_ADC_RESULT, + 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD937X_ANA_MICB2, 0x3F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE", + WCD937X_MBHC_NEW_CTL_1, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE", + WCD937X_MBHC_NEW_CTL_1, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN", + WCD937X_ANA_MBHC_ZDET, 0x02, 1, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = WCD937X_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = WCD937X_IRQ_HPHL_OCP_INT, + .hph_right_ocp = WCD937X_IRQ_HPHR_OCP_INT, +}; + +struct wcd937x_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static int wcd937x_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(component->dev); + + return wcd_request_irq(&wcd937x->irq_info, irq, name, handler, data); +} + +static void wcd937x_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(component->dev); + + if (enable) + wcd_enable_irq(&wcd937x->irq_info, irq); + else + wcd_disable_irq(&wcd937x->irq_info, irq); +} + +static int wcd937x_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(component->dev); + + wcd_free_irq(&wcd937x->irq_info, irq, data); + + return 0; +} + +static void wcd937x_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_CTL_1, + 0x80, 0x00); +} + +static int wcd937x_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read(component, WCD937X_ANA_MBHC_RESULT_3) & + 0x7; +} + +static void wcd937x_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_ELECT, + 0x01, 0x00); +} + +static void wcd937x_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, + WCD937X_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 wcd937x_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd937x_priv *wcd937x = dev_get_drvdata(component->dev); + + wcd937x->wakeup((void*)wcd937x, lock); + return true; +} + +static int wcd937x_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct wcd937x_mbhc *wcd937x_mbhc; + + wcd937x_mbhc = container_of(mbhc, struct wcd937x_mbhc, wcd_mbhc); + + if (enable) + return blocking_notifier_chain_register(&wcd937x_mbhc->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd937x_mbhc->notifier, nblock); +} + +static bool wcd937x_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + u8 val = 0; + + if (micb_num == MIC_BIAS_2) { + val = ((snd_soc_component_read(mbhc->component, + WCD937X_ANA_MICB2) & 0xC0) + >> 6); + if (val == 0x01) + return true; + } + return false; +} + +static bool wcd937x_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + return (snd_soc_component_read(component, WCD937X_ANA_HPH) & 0xC0) ? + true : false; +} + +static void wcd937x_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, + WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, + 0x1F, pull_up_cur); +} + +static int wcd937x_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + int ret = 0; + + ret = wcd937x_micbias_control(component, micb_num, req, false); + + return ret; +} + +static void wcd937x_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD937X_ANA_MICB2_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, WCD937X_ANA_MICB2_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, WCD937X_ANA_MICB2_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD937X_ANA_MICB2_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *wcd937x_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct wcd937x_mbhc *wcd937x_mbhc; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + wcd937x_mbhc = container_of(mbhc, struct wcd937x_mbhc, wcd_mbhc); + + if (!component) { + pr_err("%s: NULL component pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(wcd937x_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 wcd937x_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd937x_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 = wcd937x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + + return rc; +} + +static inline void wcd937x_mbhc_get_result_params(struct wcd937x_priv *wcd937x, + s16 *d1_a, u16 noff, + int32_t *zdet) +{ + int i; + int val, val1; + s16 c1; + s32 x1, d1; + int32_t denom; + int minCode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 + }; + + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < WCD937X_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = WCD937X_MBHC_GET_X1(val); + c1 = WCD937X_MBHC_GET_C1(val); + /* If ramp is not complete, give additional 5ms */ + if ((c1 < 2) && x1) + usleep_range(5000, 5050); + + if (!c1 || !x1) { + dev_dbg(wcd937x->dev, + "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", + __func__, c1, x1); + goto ramp_down; + } + d1 = d1_a[c1]; + denom = (x1 * d1) - (1 << (14 - noff)); + if (denom > 0) + *zdet = (WCD937X_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = WCD937X_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(wcd937x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + while (x1) { + regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_1, &val); + regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_2, &val1); + val = val << 0x8; + val |= val1; + x1 = WCD937X_MBHC_GET_X1(val); + i++; + if (i == WCD937X_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void wcd937x_mbhc_zdet_ramp(struct snd_soc_component *component, + struct wcd937x_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(component->dev); + int32_t zdet = 0; + + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, + 0x70, zdet_param->ldo_ctl << 4); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN5, 0xFC, + zdet_param->btn5); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN6, 0xFC, + zdet_param->btn6); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN7, 0xFC, + zdet_param->btn7); + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, + 0x0F, zdet_param->noff); + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x80, 0x80); + dev_dbg(wcd937x->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + wcd937x_mbhc_get_result_params(wcd937x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x40, 0x40); + dev_dbg(wcd937x->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + wcd937x_mbhc_get_result_params(wcd937x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void wcd937x_wcd_mbhc_qfuse_cal( + struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) +{ + s16 q1; + int q1_cal; + + if (*z_val < (WCD937X_ZDET_VAL_400/1000)) + q1 = snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r)); + if (q1 & 0x80) + q1_cal = (10000 - ((q1 & 0x7F) * 25)); + else + q1_cal = (10000 + (q1 * 25)); + if (q1_cal > 0) + *z_val = ((*z_val) * 10000) / q1_cal; +} + +static void wcd937x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd937x_priv *wcd937x = 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 wcd937x_mbhc_zdet_param zdet_param[] = { + {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */ + {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ + {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */ + {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */ + }; + struct wcd937x_mbhc_zdet_param *zdet_param_ptr = NULL; + s16 d1_a[][4] = { + {0, 30, 90, 30}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + }; + s16 *d1 = NULL; + + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + reg0 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read(component, WCD937X_MBHC_CTL_CLK); + reg4 = snd_soc_component_read(component, + WCD937X_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read(component, WCD937X_ANA_MBHC_ELECT) & + 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x01, 0x00); + + /* Disable surge protection before impedance detection. + * This is done to give correct value for high impedance. + */ + regmap_update_bits(wcd937x->regmap, + WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00); + /* 1ms delay needed after disable surge protection */ + usleep_range(1000, 1010); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + + if (!WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) + goto left_ch_impedance; + + /* Second ramp for left ch */ + if (z1L < WCD937X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1L > WCD937X_ZDET_VAL_400) && + (z1L <= WCD937X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1L > WCD937X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + +left_ch_impedance: + if ((z1L == WCD937X_ZDET_FLOATING_IMPEDANCE) || + (z1L > WCD937X_ZDET_VAL_100K)) { + *zl = WCD937X_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1L/1000; + wcd937x_wcd_mbhc_qfuse_cal(component, zl, 0); + } + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", + __func__, *zl); + + /* Start of right impedance ramp and calculation */ + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if (WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { + if (((z1R > WCD937X_ZDET_VAL_1200) && + (zdet_param_ptr->noff == 0x6)) || + ((*zl) != WCD937X_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* Second ramp for right ch */ + if (z1R < WCD937X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1R > WCD937X_ZDET_VAL_400) && + (z1R <= WCD937X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1R > WCD937X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, + &z1R, d1); + } +right_ch_impedance: + if ((z1R == WCD937X_ZDET_FLOATING_IMPEDANCE) || + (z1R > WCD937X_ZDET_VAL_100K)) { + *zr = WCD937X_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R/1000; + wcd937x_wcd_mbhc_qfuse_cal(component, zr, 1); + } + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", + __func__, *zr); + + /* Mono/stereo detection */ + if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) && + (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) || + (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE) || + ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) || + ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) { + dev_dbg(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, WCD937X_HPH_R_ATEST, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD937X_HPH_PA_CTL2, + 0x40, 0x01); + if (*zl < (WCD937X_ZDET_VAL_32/1000)) + wcd937x_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls, + NULL, d1); + else + wcd937x_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls, + NULL, d1); + snd_soc_component_update_bits(component, WCD937X_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD937X_HPH_R_ATEST, + 0x02, 0x00); + z1Ls /= 1000; + wcd937x_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; + } + + /* Enable surge protection again after impedance detection */ + regmap_update_bits(wcd937x->regmap, + WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); +zdet_complete: + snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD937X_MBHC_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd937x->regmap, + WCD937X_ANA_MBHC_ELECT, 0x80, 0x80); +} + +static void wcd937x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_MECH, + 0x02, 0x00); + } +} + +static void wcd937x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD937X_HPH_PA_CTL2, + 0x40, 0x40); + snd_soc_component_update_bits(component, WCD937X_HPH_PA_CTL2, + 0x10, 0x10); + } else { + snd_soc_component_update_bits(component, WCD937X_HPH_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD937X_HPH_PA_CTL2, + 0x10, 0x00); + } +} + +static void wcd937x_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, WCD937X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + /* Do not enable moisture detection if jack type is NC */ + if (!mbhc->hphl_swh) { + dev_dbg(component->dev, "%s: disable moisture detection for NC\n", + __func__); + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); +} + +static void wcd937x_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, WCD937X_MBHC_NEW_CTL_2, + 0x0C, mbhc->moist_rref << 2); + else + snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); +} + +static bool wcd937x_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, WCD937X_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, WCD937X_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_read(component, WCD937X_MBHC_NEW_CTL_2) & + 0x0C)) + goto done; + + wcd937x_mbhc_moisture_detect_en(mbhc, true); + /* Read moisture comparator status */ + ret = ((snd_soc_component_read(component, WCD937X_MBHC_NEW_FSM_STATUS) + & 0x20) ? 0 : 1); + +done: + return ret; + +} + +static void wcd937x_mbhc_moisture_polling_ctrl(struct wcd_mbhc *mbhc, + bool enable) +{ + struct snd_soc_component *component = mbhc->component; + + snd_soc_component_update_bits(component, + WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, + 0x04, (enable << 2)); +} + +static void wcd937x_mbhc_bcs_enable(struct wcd_mbhc *mbhc, + bool bcs_enable) +{ + if (bcs_enable) + wcd937x_disable_bcs_before_slow_insert(mbhc->component, false); + else + wcd937x_disable_bcs_before_slow_insert(mbhc->component, true); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = wcd937x_mbhc_request_irq, + .irq_control = wcd937x_mbhc_irq_control, + .free_irq = wcd937x_mbhc_free_irq, + .clk_setup = wcd937x_mbhc_clk_setup, + .map_btn_code_to_num = wcd937x_mbhc_btn_to_num, + .mbhc_bias = wcd937x_mbhc_mbhc_bias_control, + .set_btn_thr = wcd937x_mbhc_program_btn_thr, + .lock_sleep = wcd937x_mbhc_lock_sleep, + .register_notifier = wcd937x_mbhc_register_notifier, + .micbias_enable_status = wcd937x_mbhc_micb_en_status, + .hph_pa_on_status = wcd937x_mbhc_hph_pa_on_status, + .hph_pull_up_control_v2 = wcd937x_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = wcd937x_mbhc_request_micbias, + .mbhc_micb_ramp_control = wcd937x_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = wcd937x_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = wcd937x_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = wcd937x_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = wcd937x_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = wcd937x_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = wcd937x_mbhc_moisture_config, + .mbhc_get_moisture_status = wcd937x_mbhc_get_moisture_status, + .mbhc_moisture_polling_ctrl = wcd937x_mbhc_moisture_polling_ctrl, + .mbhc_moisture_detect_en = wcd937x_mbhc_moisture_detect_en, + .bcs_enable = wcd937x_mbhc_bcs_enable, +}; + +static int wcd937x_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_mbhc *wcd937x_mbhc = wcd937x_soc_get_mbhc(component); + struct wcd_mbhc *mbhc; + + if (!wcd937x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + mbhc = &wcd937x_mbhc->wcd_mbhc; + + ucontrol->value.integer.value[0] = (u32) mbhc->hph_type; + dev_dbg(component->dev, "%s: hph_type = %u\n", __func__, + mbhc->hph_type); + + return 0; +} + +static int wcd937x_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t zl, zr; + bool hphr; + struct soc_multi_mixer_control *mc; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_mbhc *wcd937x_mbhc = wcd937x_soc_get_mbhc(component); + + if (!wcd937x_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(&wcd937x_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, + wcd937x_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + wcd937x_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + wcd937x_hph_impedance_get, NULL), +}; + +/* + * wcd937x_mbhc_get_impedance: get impedance of headphone + * left and right channels + * @wcd937x_mbhc: handle to struct wcd937x_mbhc * + * @zl: handle to left-ch impedance + * @zr: handle to right-ch impedance + * return 0 for success or error code in case of failure + */ +int wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (!wcd937x_mbhc) { + pr_err("%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + if (!zl || !zr) { + pr_err("%s: zl or zr null!\n", __func__); + return -EINVAL; + } + + return wcd_mbhc_get_impedance(&wcd937x_mbhc->wcd_mbhc, zl, zr); +} +EXPORT_SYMBOL(wcd937x_mbhc_get_impedance); + +/* + * wcd937x_mbhc_hs_detect: starts mbhc insertion/removal functionality + * @component: 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 wcd937x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct wcd937x_priv *wcd937x = NULL; + struct wcd937x_mbhc *wcd937x_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd937x = snd_soc_component_get_drvdata(component); + if (!wcd937x) { + pr_err("%s: wcd937x is NULL\n", __func__); + return -EINVAL; + } + + wcd937x_mbhc = wcd937x->mbhc; + if (!wcd937x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return -EINVAL; + } + + return wcd_mbhc_start(&wcd937x_mbhc->wcd_mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(wcd937x_mbhc_hs_detect); + +/* + * wcd937x_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void wcd937x_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = NULL; + struct wcd937x_mbhc *wcd937x_mbhc = NULL; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + wcd937x = snd_soc_component_get_drvdata(component); + if (!wcd937x) { + pr_err("%s: wcd937x is NULL\n", __func__); + return; + } + + wcd937x_mbhc = wcd937x->mbhc; + if (!wcd937x_mbhc) { + dev_err(component->dev, "%s: mbhc not initialized!\n", + __func__); + return; + } + wcd_mbhc_stop(&wcd937x_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL(wcd937x_mbhc_hs_detect_exit); + +/* + * wcd937x_mbhc_ssr_down: stop mbhc during + * wcd937x subsystem restart + * @mbhc: pointer to wcd937x_mbhc structure + * @component: handle to snd_soc_component * + */ +void wcd937x_mbhc_ssr_down(struct wcd937x_mbhc *mbhc, + struct snd_soc_component *component) +{ + struct wcd_mbhc *wcd_mbhc = NULL; + + if (!mbhc || !component) + return; + + wcd_mbhc = &mbhc->wcd_mbhc; + if (wcd_mbhc == NULL) { + dev_err(component->dev, "%s: wcd_mbhc is NULL\n", __func__); + return; + } + + wcd937x_mbhc_hs_detect_exit(component); + wcd_mbhc_deinit(wcd_mbhc); +} +EXPORT_SYMBOL(wcd937x_mbhc_ssr_down); + +/* + * wcd937x_mbhc_post_ssr_init: initialize mbhc for + * wcd937x post subsystem restart + * @mbhc: poniter to wcd937x_mbhc structure + * @component: handle to snd_soc_component * + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc, + struct snd_soc_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; + } + + snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_MECH, + 0x20, 0x20); + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, WCD937X_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto done; + } + +done: + return ret; +} +EXPORT_SYMBOL(wcd937x_mbhc_post_ssr_init); + +/* + * wcd937x_mbhc_init: initialize mbhc for wcd937x + * @mbhc: poniter to wcd937x_mbhc struct pointer to store the configs + * @component: 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 wcd937x_mbhc_init(struct wcd937x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + struct wcd937x_mbhc *wcd937x_mbhc = NULL; + struct wcd_mbhc *wcd_mbhc = NULL; + struct wcd937x_pdata *pdata; + int ret = 0; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd937x_mbhc = devm_kzalloc(component->dev, sizeof(struct wcd937x_mbhc), + GFP_KERNEL); + if (!wcd937x_mbhc) + return -ENOMEM; + + wcd937x_mbhc->fw_data = fw_data; + BLOCKING_INIT_NOTIFIER_HEAD(&wcd937x_mbhc->notifier); + wcd_mbhc = &wcd937x_mbhc->wcd_mbhc; + if (wcd_mbhc == NULL) { + pr_err("%s: wcd_mbhc is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + + /* Setting default mbhc detection logic to ADC */ + wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC; + + pdata = dev_get_platdata(component->dev); + if (!pdata) { + dev_err(component->dev, "%s: pdata pointer is NULL\n", + __func__); + ret = -EINVAL; + goto err; + } + wcd_mbhc->micb_mv = pdata->micbias.micb2_mv; + + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, + &intr_ids, wcd_mbhc_registers, + WCD937X_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto err; + } + + (*mbhc) = wcd937x_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, wcd937x_mbhc); + return ret; +} +EXPORT_SYMBOL(wcd937x_mbhc_init); + +/* + * wcd937x_mbhc_deinit: deinitialize mbhc for wcd937x + * @component: handle to snd_soc_component * + */ +void wcd937x_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x; + struct wcd937x_mbhc *wcd937x_mbhc; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + wcd937x = snd_soc_component_get_drvdata(component); + if (!wcd937x) { + pr_err("%s: wcd937x is NULL\n", __func__); + return; + } + + wcd937x_mbhc = wcd937x->mbhc; + if (wcd937x_mbhc) { + wcd_mbhc_deinit(&wcd937x_mbhc->wcd_mbhc); + devm_kfree(component->dev, wcd937x_mbhc); + } +} +EXPORT_SYMBOL(wcd937x_mbhc_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-mbhc.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-mbhc.h new file mode 100644 index 0000000000..2e6bbe88f6 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-mbhc.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ +#ifndef __WCD937X_MBHC_H__ +#define __WCD937X_MBHC_H__ +#include + +struct wcd937x_mbhc { + struct wcd_mbhc wcd_mbhc; + struct blocking_notifier_head notifier; + struct fw_info *fw_data; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD937X) +extern int wcd937x_mbhc_init(struct wcd937x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data); +extern void wcd937x_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern int wcd937x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void wcd937x_mbhc_deinit(struct snd_soc_component *component); +extern int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc, + struct snd_soc_component *component); +extern void wcd937x_mbhc_ssr_down(struct wcd937x_mbhc *mbhc, + struct snd_soc_component *component); +extern int wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc, + uint32_t *zl, uint32_t *zr); +#else +static inline int wcd937x_mbhc_init(struct wcd937x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + return 0; +} +static inline void wcd937x_mbhc_hs_detect_exit( + struct snd_soc_component *component) +{ +} +static inline int wcd937x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void wcd937x_mbhc_deinit(struct snd_soc_component *component) +{ +} +static inline int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc, + struct snd_soc_component *component) +{ + return 0; +} +static inline void wcd937x_mbhc_ssr_down(struct wcd937x_mbhc *mbhc, + struct snd_soc_component *component) +{ +} +static inline int wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + +#endif /* __WCD937X_MBHC_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-registers.h new file mode 100644 index 0000000000..f2c914f155 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-registers.h @@ -0,0 +1,438 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _WCD937X_REGISTERS_H +#define _WCD937X_REGISTERS_H + +#define WCD937X_BASE_ADDRESS 0x3000 + +#define WCD937X_REG(reg) (reg - WCD937X_BASE_ADDRESS) + +enum { + REG_NO_ACCESS, + RD_REG, + WR_REG, + RD_WR_REG +}; + +#define WCD937X_ANA_BIAS (WCD937X_BASE_ADDRESS+0x001) +#define WCD937X_ANA_RX_SUPPLIES (WCD937X_BASE_ADDRESS+0x008) +#define WCD937X_ANA_HPH (WCD937X_BASE_ADDRESS+0x009) +#define WCD937X_ANA_EAR (WCD937X_BASE_ADDRESS+0x00A) +#define WCD937X_ANA_EAR_COMPANDER_CTL (WCD937X_BASE_ADDRESS+0x00B) +#define WCD937X_ANA_TX_CH1 (WCD937X_BASE_ADDRESS+0x00E) +#define WCD937X_ANA_TX_CH2 (WCD937X_BASE_ADDRESS+0x00F) +#define WCD937X_ANA_TX_CH3 (WCD937X_BASE_ADDRESS+0x010) +#define WCD937X_ANA_TX_CH3_HPF (WCD937X_BASE_ADDRESS+0x011) +#define WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC (WCD937X_BASE_ADDRESS+0x012) +#define WCD937X_ANA_MICB3_DSP_EN_LOGIC (WCD937X_BASE_ADDRESS+0x013) +#define WCD937X_ANA_MBHC_MECH (WCD937X_BASE_ADDRESS+0x014) +#define WCD937X_ANA_MBHC_ELECT (WCD937X_BASE_ADDRESS+0x015) +#define WCD937X_ANA_MBHC_ZDET (WCD937X_BASE_ADDRESS+0x016) +#define WCD937X_ANA_MBHC_RESULT_1 (WCD937X_BASE_ADDRESS+0x017) +#define WCD937X_ANA_MBHC_RESULT_2 (WCD937X_BASE_ADDRESS+0x018) +#define WCD937X_ANA_MBHC_RESULT_3 (WCD937X_BASE_ADDRESS+0x019) +#define WCD937X_ANA_MBHC_BTN0 (WCD937X_BASE_ADDRESS+0x01A) +#define WCD937X_ANA_MBHC_BTN1 (WCD937X_BASE_ADDRESS+0x01B) +#define WCD937X_ANA_MBHC_BTN2 (WCD937X_BASE_ADDRESS+0x01C) +#define WCD937X_ANA_MBHC_BTN3 (WCD937X_BASE_ADDRESS+0x01D) +#define WCD937X_ANA_MBHC_BTN4 (WCD937X_BASE_ADDRESS+0x01E) +#define WCD937X_ANA_MBHC_BTN5 (WCD937X_BASE_ADDRESS+0x01F) +#define WCD937X_ANA_MBHC_BTN6 (WCD937X_BASE_ADDRESS+0x020) +#define WCD937X_ANA_MBHC_BTN7 (WCD937X_BASE_ADDRESS+0x021) +#define WCD937X_ANA_MICB1 (WCD937X_BASE_ADDRESS+0x022) +#define WCD937X_ANA_MICB2 (WCD937X_BASE_ADDRESS+0x023) +#define WCD937X_ANA_MICB2_RAMP (WCD937X_BASE_ADDRESS+0x024) +#define WCD937X_ANA_MICB3 (WCD937X_BASE_ADDRESS+0x025) +#define WCD937X_BIAS_CTL (WCD937X_BASE_ADDRESS+0x028) +#define WCD937X_BIAS_VBG_FINE_ADJ (WCD937X_BASE_ADDRESS+0x029) +#define WCD937X_LDOL_VDDCX_ADJUST (WCD937X_BASE_ADDRESS+0x040) +#define WCD937X_LDOL_DISABLE_LDOL (WCD937X_BASE_ADDRESS+0x041) +#define WCD937X_MBHC_CTL_CLK (WCD937X_BASE_ADDRESS+0x056) +#define WCD937X_MBHC_CTL_ANA (WCD937X_BASE_ADDRESS+0x057) +#define WCD937X_MBHC_CTL_SPARE_1 (WCD937X_BASE_ADDRESS+0x058) +#define WCD937X_MBHC_CTL_SPARE_2 (WCD937X_BASE_ADDRESS+0x059) +#define WCD937X_MBHC_CTL_BCS (WCD937X_BASE_ADDRESS+0x05A) +#define WCD937X_MBHC_MOISTURE_DET_FSM_STATUS (WCD937X_BASE_ADDRESS+0x05B) +#define WCD937X_MBHC_TEST_CTL (WCD937X_BASE_ADDRESS+0x05C) +#define WCD937X_LDOH_MODE (WCD937X_BASE_ADDRESS+0x067) +#define WCD937X_LDOH_BIAS (WCD937X_BASE_ADDRESS+0x068) +#define WCD937X_LDOH_STB_LOADS (WCD937X_BASE_ADDRESS+0x069) +#define WCD937X_LDOH_SLOWRAMP (WCD937X_BASE_ADDRESS+0x06A) +#define WCD937X_MICB1_TEST_CTL_1 (WCD937X_BASE_ADDRESS+0x06B) +#define WCD937X_MICB1_TEST_CTL_2 (WCD937X_BASE_ADDRESS+0x06C) +#define WCD937X_MICB1_TEST_CTL_3 (WCD937X_BASE_ADDRESS+0x06D) +#define WCD937X_MICB2_TEST_CTL_1 (WCD937X_BASE_ADDRESS+0x06E) +#define WCD937X_MICB2_TEST_CTL_2 (WCD937X_BASE_ADDRESS+0x06F) +#define WCD937X_MICB2_TEST_CTL_3 (WCD937X_BASE_ADDRESS+0x070) +#define WCD937X_MICB3_TEST_CTL_1 (WCD937X_BASE_ADDRESS+0x071) +#define WCD937X_MICB3_TEST_CTL_2 (WCD937X_BASE_ADDRESS+0x072) +#define WCD937X_MICB3_TEST_CTL_3 (WCD937X_BASE_ADDRESS+0x073) +#define WCD937X_TX_COM_ADC_VCM (WCD937X_BASE_ADDRESS+0x077) +#define WCD937X_TX_COM_BIAS_ATEST (WCD937X_BASE_ADDRESS+0x078) +#define WCD937X_TX_COM_ADC_INT1_IB (WCD937X_BASE_ADDRESS+0x079) +#define WCD937X_TX_COM_ADC_INT2_IB (WCD937X_BASE_ADDRESS+0x07A) +#define WCD937X_TX_COM_TXFE_DIV_CTL (WCD937X_BASE_ADDRESS+0x07B) +#define WCD937X_TX_COM_TXFE_DIV_START (WCD937X_BASE_ADDRESS+0x07C) +#define WCD937X_TX_COM_TXFE_DIV_STOP_9P6M (WCD937X_BASE_ADDRESS+0x07D) +#define WCD937X_TX_COM_TXFE_DIV_STOP_12P288M (WCD937X_BASE_ADDRESS+0x07E) +#define WCD937X_TX_1_2_TEST_EN (WCD937X_BASE_ADDRESS+0x07F) +#define WCD937X_TX_1_2_ADC_IB (WCD937X_BASE_ADDRESS+0x080) +#define WCD937X_TX_1_2_ATEST_REFCTL (WCD937X_BASE_ADDRESS+0x081) +#define WCD937X_TX_1_2_TEST_CTL (WCD937X_BASE_ADDRESS+0x082) +#define WCD937X_TX_1_2_TEST_BLK_EN (WCD937X_BASE_ADDRESS+0x083) +#define WCD937X_TX_1_2_TXFE_CLKDIV (WCD937X_BASE_ADDRESS+0x084) +#define WCD937X_TX_1_2_SAR2_ERR (WCD937X_BASE_ADDRESS+0x085) +#define WCD937X_TX_1_2_SAR1_ERR (WCD937X_BASE_ADDRESS+0x086) +#define WCD937X_TX_3_TEST_EN (WCD937X_BASE_ADDRESS+0x087) +#define WCD937X_TX_3_ADC_IB (WCD937X_BASE_ADDRESS+0x088) +#define WCD937X_TX_3_ATEST_REFCTL (WCD937X_BASE_ADDRESS+0x089) +#define WCD937X_TX_3_TEST_CTL (WCD937X_BASE_ADDRESS+0x08A) +#define WCD937X_TX_3_TEST_BLK_EN (WCD937X_BASE_ADDRESS+0x08B) +#define WCD937X_TX_3_TXFE_CLKDIV (WCD937X_BASE_ADDRESS+0x08C) +#define WCD937X_TX_3_SPARE_MONO (WCD937X_BASE_ADDRESS+0x08D) +#define WCD937X_TX_3_SAR1_ERR (WCD937X_BASE_ADDRESS+0x08E) +#define WCD937X_CLASSH_MODE_1 (WCD937X_BASE_ADDRESS+0x097) +#define WCD937X_CLASSH_MODE_2 (WCD937X_BASE_ADDRESS+0x098) +#define WCD937X_CLASSH_MODE_3 (WCD937X_BASE_ADDRESS+0x099) +#define WCD937X_CLASSH_CTRL_VCL_1 (WCD937X_BASE_ADDRESS+0x09A) +#define WCD937X_CLASSH_CTRL_VCL_2 (WCD937X_BASE_ADDRESS+0x09B) +#define WCD937X_CLASSH_CTRL_CCL_1 (WCD937X_BASE_ADDRESS+0x09C) +#define WCD937X_CLASSH_CTRL_CCL_2 (WCD937X_BASE_ADDRESS+0x09D) +#define WCD937X_CLASSH_CTRL_CCL_3 (WCD937X_BASE_ADDRESS+0x09E) +#define WCD937X_CLASSH_CTRL_CCL_4 (WCD937X_BASE_ADDRESS+0x09F) +#define WCD937X_CLASSH_CTRL_CCL_5 (WCD937X_BASE_ADDRESS+0x0A0) +#define WCD937X_CLASSH_BUCK_TMUX_A_D (WCD937X_BASE_ADDRESS+0x0A1) +#define WCD937X_CLASSH_BUCK_SW_DRV_CNTL (WCD937X_BASE_ADDRESS+0x0A2) +#define WCD937X_CLASSH_SPARE (WCD937X_BASE_ADDRESS+0x0A3) +#define WCD937X_FLYBACK_EN (WCD937X_BASE_ADDRESS+0x0A4) +#define WCD937X_FLYBACK_VNEG_CTRL_1 (WCD937X_BASE_ADDRESS+0x0A5) +#define WCD937X_FLYBACK_VNEG_CTRL_2 (WCD937X_BASE_ADDRESS+0x0A6) +#define WCD937X_FLYBACK_VNEG_CTRL_3 (WCD937X_BASE_ADDRESS+0x0A7) +#define WCD937X_FLYBACK_VNEG_CTRL_4 (WCD937X_BASE_ADDRESS+0x0A8) +#define WCD937X_FLYBACK_VNEG_CTRL_5 (WCD937X_BASE_ADDRESS+0x0A9) +#define WCD937X_FLYBACK_VNEG_CTRL_6 (WCD937X_BASE_ADDRESS+0x0AA) +#define WCD937X_FLYBACK_VNEG_CTRL_7 (WCD937X_BASE_ADDRESS+0x0AB) +#define WCD937X_FLYBACK_VNEG_CTRL_8 (WCD937X_BASE_ADDRESS+0x0AC) +#define WCD937X_FLYBACK_VNEG_CTRL_9 (WCD937X_BASE_ADDRESS+0x0AD) +#define WCD937X_FLYBACK_VNEGDAC_CTRL_1 (WCD937X_BASE_ADDRESS+0x0AE) +#define WCD937X_FLYBACK_VNEGDAC_CTRL_2 (WCD937X_BASE_ADDRESS+0x0AF) +#define WCD937X_FLYBACK_VNEGDAC_CTRL_3 (WCD937X_BASE_ADDRESS+0x0B0) +#define WCD937X_FLYBACK_CTRL_1 (WCD937X_BASE_ADDRESS+0x0B1) +#define WCD937X_FLYBACK_TEST_CTL (WCD937X_BASE_ADDRESS+0x0B2) +#define WCD937X_RX_AUX_SW_CTL (WCD937X_BASE_ADDRESS+0x0B3) +#define WCD937X_RX_PA_AUX_IN_CONN (WCD937X_BASE_ADDRESS+0x0B4) +#define WCD937X_RX_TIMER_DIV (WCD937X_BASE_ADDRESS+0x0B5) +#define WCD937X_RX_OCP_CTL (WCD937X_BASE_ADDRESS+0x0B6) +#define WCD937X_RX_OCP_COUNT (WCD937X_BASE_ADDRESS+0x0B7) +#define WCD937X_RX_BIAS_EAR_DAC (WCD937X_BASE_ADDRESS+0x0B8) +#define WCD937X_RX_BIAS_EAR_AMP (WCD937X_BASE_ADDRESS+0x0B9) +#define WCD937X_RX_BIAS_HPH_LDO (WCD937X_BASE_ADDRESS+0x0BA) +#define WCD937X_RX_BIAS_HPH_PA (WCD937X_BASE_ADDRESS+0x0BB) +#define WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2 (WCD937X_BASE_ADDRESS+0x0BC) +#define WCD937X_RX_BIAS_HPH_RDAC_LDO (WCD937X_BASE_ADDRESS+0x0BD) +#define WCD937X_RX_BIAS_HPH_CNP1 (WCD937X_BASE_ADDRESS+0x0BE) +#define WCD937X_RX_BIAS_HPH_LOWPOWER (WCD937X_BASE_ADDRESS+0x0BF) +#define WCD937X_RX_BIAS_AUX_DAC (WCD937X_BASE_ADDRESS+0x0C0) +#define WCD937X_RX_BIAS_AUX_AMP (WCD937X_BASE_ADDRESS+0x0C1) +#define WCD937X_RX_BIAS_VNEGDAC_BLEEDER (WCD937X_BASE_ADDRESS+0x0C2) +#define WCD937X_RX_BIAS_MISC (WCD937X_BASE_ADDRESS+0x0C3) +#define WCD937X_RX_BIAS_BUCK_RST (WCD937X_BASE_ADDRESS+0x0C4) +#define WCD937X_RX_BIAS_BUCK_VREF_ERRAMP (WCD937X_BASE_ADDRESS+0x0C5) +#define WCD937X_RX_BIAS_FLYB_ERRAMP (WCD937X_BASE_ADDRESS+0x0C6) +#define WCD937X_RX_BIAS_FLYB_BUFF (WCD937X_BASE_ADDRESS+0x0C7) +#define WCD937X_RX_BIAS_FLYB_MID_RST (WCD937X_BASE_ADDRESS+0x0C8) +#define WCD937X_HPH_L_STATUS (WCD937X_BASE_ADDRESS+0x0C9) +#define WCD937X_HPH_R_STATUS (WCD937X_BASE_ADDRESS+0x0CA) +#define WCD937X_HPH_CNP_EN (WCD937X_BASE_ADDRESS+0x0CB) +#define WCD937X_HPH_CNP_WG_CTL (WCD937X_BASE_ADDRESS+0x0CC) +#define WCD937X_HPH_CNP_WG_TIME (WCD937X_BASE_ADDRESS+0x0CD) +#define WCD937X_HPH_OCP_CTL (WCD937X_BASE_ADDRESS+0x0CE) +#define WCD937X_HPH_AUTO_CHOP (WCD937X_BASE_ADDRESS+0x0CF) +#define WCD937X_HPH_CHOP_CTL (WCD937X_BASE_ADDRESS+0x0D0) +#define WCD937X_HPH_PA_CTL1 (WCD937X_BASE_ADDRESS+0x0D1) +#define WCD937X_HPH_PA_CTL2 (WCD937X_BASE_ADDRESS+0x0D2) +#define WCD937X_HPH_L_EN (WCD937X_BASE_ADDRESS+0x0D3) +#define WCD937X_HPH_L_TEST (WCD937X_BASE_ADDRESS+0x0D4) +#define WCD937X_HPH_L_ATEST (WCD937X_BASE_ADDRESS+0x0D5) +#define WCD937X_HPH_R_EN (WCD937X_BASE_ADDRESS+0x0D6) +#define WCD937X_HPH_R_TEST (WCD937X_BASE_ADDRESS+0x0D7) +#define WCD937X_HPH_R_ATEST (WCD937X_BASE_ADDRESS+0x0D8) +#define WCD937X_HPH_RDAC_CLK_CTL1 (WCD937X_BASE_ADDRESS+0x0D9) +#define WCD937X_HPH_RDAC_CLK_CTL2 (WCD937X_BASE_ADDRESS+0x0DA) +#define WCD937X_HPH_RDAC_LDO_CTL (WCD937X_BASE_ADDRESS+0x0DB) +#define WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL (WCD937X_BASE_ADDRESS+0x0DC) +#define WCD937X_HPH_REFBUFF_UHQA_CTL (WCD937X_BASE_ADDRESS+0x0DD) +#define WCD937X_HPH_REFBUFF_LP_CTL (WCD937X_BASE_ADDRESS+0x0DE) +#define WCD937X_HPH_L_DAC_CTL (WCD937X_BASE_ADDRESS+0x0DF) +#define WCD937X_HPH_R_DAC_CTL (WCD937X_BASE_ADDRESS+0x0E0) +#define WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL (WCD937X_BASE_ADDRESS+0x0E1) +#define WCD937X_HPH_SURGE_HPHLR_SURGE_EN (WCD937X_BASE_ADDRESS+0x0E2) +#define WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1 (WCD937X_BASE_ADDRESS+0x0E3) +#define WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS (WCD937X_BASE_ADDRESS+0x0E4) +#define WCD937X_EAR_EAR_EN_REG (WCD937X_BASE_ADDRESS+0x0E9) +#define WCD937X_EAR_EAR_PA_CON (WCD937X_BASE_ADDRESS+0x0EA) +#define WCD937X_EAR_EAR_SP_CON (WCD937X_BASE_ADDRESS+0x0EB) +#define WCD937X_EAR_EAR_DAC_CON (WCD937X_BASE_ADDRESS+0x0EC) +#define WCD937X_EAR_EAR_CNP_FSM_CON (WCD937X_BASE_ADDRESS+0x0ED) +#define WCD937X_EAR_TEST_CTL (WCD937X_BASE_ADDRESS+0x0EE) +#define WCD937X_EAR_STATUS_REG_1 (WCD937X_BASE_ADDRESS+0x0EF) +#define WCD937X_EAR_STATUS_REG_2 (WCD937X_BASE_ADDRESS+0x0F0) +#define WCD937X_ANA_NEW_PAGE_REGISTER (WCD937X_BASE_ADDRESS+0x100) +#define WCD937X_HPH_NEW_ANA_HPH2 (WCD937X_BASE_ADDRESS+0x101) +#define WCD937X_HPH_NEW_ANA_HPH3 (WCD937X_BASE_ADDRESS+0x102) +#define WCD937X_SLEEP_CTL (WCD937X_BASE_ADDRESS+0x103) +#define WCD937X_SLEEP_WATCHDOG_CTL (WCD937X_BASE_ADDRESS+0x104) +#define WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL (WCD937X_BASE_ADDRESS+0x11F) +#define WCD937X_MBHC_NEW_CTL_1 (WCD937X_BASE_ADDRESS+0x120) +#define WCD937X_MBHC_NEW_CTL_2 (WCD937X_BASE_ADDRESS+0x121) +#define WCD937X_MBHC_NEW_PLUG_DETECT_CTL (WCD937X_BASE_ADDRESS+0x122) +#define WCD937X_MBHC_NEW_ZDET_ANA_CTL (WCD937X_BASE_ADDRESS+0x123) +#define WCD937X_MBHC_NEW_ZDET_RAMP_CTL (WCD937X_BASE_ADDRESS+0x124) +#define WCD937X_MBHC_NEW_FSM_STATUS (WCD937X_BASE_ADDRESS+0x125) +#define WCD937X_MBHC_NEW_ADC_RESULT (WCD937X_BASE_ADDRESS+0x126) +#define WCD937X_TX_NEW_TX_CH2_SEL (WCD937X_BASE_ADDRESS+0x127) +#define WCD937X_AUX_AUXPA (WCD937X_BASE_ADDRESS+0x128) +#define WCD937X_LDORXTX_MODE (WCD937X_BASE_ADDRESS+0x129) +#define WCD937X_LDORXTX_CONFIG (WCD937X_BASE_ADDRESS+0x12A) +#define WCD937X_DIE_CRACK_DIE_CRK_DET_EN (WCD937X_BASE_ADDRESS+0x12C) +#define WCD937X_DIE_CRACK_DIE_CRK_DET_OUT (WCD937X_BASE_ADDRESS+0x12D) +#define WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL (WCD937X_BASE_ADDRESS+0x132) +#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L (WCD937X_BASE_ADDRESS+0x133) +#define WCD937X_HPH_NEW_INT_RDAC_VREF_CTL (WCD937X_BASE_ADDRESS+0x134) +#define WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL (WCD937X_BASE_ADDRESS+0x135) +#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R (WCD937X_BASE_ADDRESS+0x136) +#define WCD937X_HPH_NEW_INT_PA_MISC1 (WCD937X_BASE_ADDRESS+0x137) +#define WCD937X_HPH_NEW_INT_PA_MISC2 (WCD937X_BASE_ADDRESS+0x138) +#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC (WCD937X_BASE_ADDRESS+0x139) +#define WCD937X_HPH_NEW_INT_HPH_TIMER1 (WCD937X_BASE_ADDRESS+0x13A) +#define WCD937X_HPH_NEW_INT_HPH_TIMER2 (WCD937X_BASE_ADDRESS+0x13B) +#define WCD937X_HPH_NEW_INT_HPH_TIMER3 (WCD937X_BASE_ADDRESS+0x13C) +#define WCD937X_HPH_NEW_INT_HPH_TIMER4 (WCD937X_BASE_ADDRESS+0x13D) +#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC2 (WCD937X_BASE_ADDRESS+0x13E) +#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC3 (WCD937X_BASE_ADDRESS+0x13F) +#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (WCD937X_BASE_ADDRESS+0x145) +#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP (WCD937X_BASE_ADDRESS+0x146) +#define WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP (WCD937X_BASE_ADDRESS+0x147) +#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL (WCD937X_BASE_ADDRESS+0x1AF) +#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL \ + (WCD937X_BASE_ADDRESS+0x1B0) +#define WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT (WCD937X_BASE_ADDRESS+0x1B1) +#define WCD937X_MBHC_NEW_INT_SPARE_2 (WCD937X_BASE_ADDRESS+0x1B2) +#define WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON (WCD937X_BASE_ADDRESS+0x1B7) +#define WCD937X_EAR_INT_NEW_CNP_VCM_CON1 (WCD937X_BASE_ADDRESS+0x1B8) +#define WCD937X_EAR_INT_NEW_CNP_VCM_CON2 (WCD937X_BASE_ADDRESS+0x1B9) +#define WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS (WCD937X_BASE_ADDRESS+0x1BA) +#define WCD937X_AUX_INT_EN_REG (WCD937X_BASE_ADDRESS+0x1BD) +#define WCD937X_AUX_INT_PA_CTRL (WCD937X_BASE_ADDRESS+0x1BE) +#define WCD937X_AUX_INT_SP_CTRL (WCD937X_BASE_ADDRESS+0x1BF) +#define WCD937X_AUX_INT_DAC_CTRL (WCD937X_BASE_ADDRESS+0x1C0) +#define WCD937X_AUX_INT_CLK_CTRL (WCD937X_BASE_ADDRESS+0x1C1) +#define WCD937X_AUX_INT_TEST_CTRL (WCD937X_BASE_ADDRESS+0x1C2) +#define WCD937X_AUX_INT_STATUS_REG (WCD937X_BASE_ADDRESS+0x1C3) +#define WCD937X_AUX_INT_MISC (WCD937X_BASE_ADDRESS+0x1C4) +#define WCD937X_LDORXTX_INT_BIAS (WCD937X_BASE_ADDRESS+0x1C5) +#define WCD937X_LDORXTX_INT_STB_LOADS_DTEST (WCD937X_BASE_ADDRESS+0x1C6) +#define WCD937X_LDORXTX_INT_TEST0 (WCD937X_BASE_ADDRESS+0x1C7) +#define WCD937X_LDORXTX_INT_STARTUP_TIMER (WCD937X_BASE_ADDRESS+0x1C8) +#define WCD937X_LDORXTX_INT_TEST1 (WCD937X_BASE_ADDRESS+0x1C9) +#define WCD937X_LDORXTX_INT_STATUS (WCD937X_BASE_ADDRESS+0x1CA) +#define WCD937X_SLEEP_INT_WATCHDOG_CTL_1 (WCD937X_BASE_ADDRESS+0x1D0) +#define WCD937X_SLEEP_INT_WATCHDOG_CTL_2 (WCD937X_BASE_ADDRESS+0x1D1) +#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1 (WCD937X_BASE_ADDRESS+0x1D3) +#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2 (WCD937X_BASE_ADDRESS+0x1D4) +#define WCD937X_DIGITAL_PAGE_REGISTER (WCD937X_BASE_ADDRESS+0x400) +#define WCD937X_DIGITAL_CHIP_ID0 (WCD937X_BASE_ADDRESS+0x401) +#define WCD937X_DIGITAL_CHIP_ID1 (WCD937X_BASE_ADDRESS+0x402) +#define WCD937X_DIGITAL_CHIP_ID2 (WCD937X_BASE_ADDRESS+0x403) +#define WCD937X_DIGITAL_CHIP_ID3 (WCD937X_BASE_ADDRESS+0x404) +#define WCD937X_DIGITAL_CDC_RST_CTL (WCD937X_BASE_ADDRESS+0x406) +#define WCD937X_DIGITAL_TOP_CLK_CFG (WCD937X_BASE_ADDRESS+0x407) +#define WCD937X_DIGITAL_CDC_ANA_CLK_CTL (WCD937X_BASE_ADDRESS+0x408) +#define WCD937X_DIGITAL_CDC_DIG_CLK_CTL (WCD937X_BASE_ADDRESS+0x409) +#define WCD937X_DIGITAL_SWR_RST_EN (WCD937X_BASE_ADDRESS+0x40A) +#define WCD937X_DIGITAL_CDC_PATH_MODE (WCD937X_BASE_ADDRESS+0x40B) +#define WCD937X_DIGITAL_CDC_RX_RST (WCD937X_BASE_ADDRESS+0x40C) +#define WCD937X_DIGITAL_CDC_RX0_CTL (WCD937X_BASE_ADDRESS+0x40D) +#define WCD937X_DIGITAL_CDC_RX1_CTL (WCD937X_BASE_ADDRESS+0x40E) +#define WCD937X_DIGITAL_CDC_RX2_CTL (WCD937X_BASE_ADDRESS+0x40F) +#define WCD937X_DIGITAL_DEM_BYPASS_DATA0 (WCD937X_BASE_ADDRESS+0x410) +#define WCD937X_DIGITAL_DEM_BYPASS_DATA1 (WCD937X_BASE_ADDRESS+0x411) +#define WCD937X_DIGITAL_DEM_BYPASS_DATA2 (WCD937X_BASE_ADDRESS+0x412) +#define WCD937X_DIGITAL_DEM_BYPASS_DATA3 (WCD937X_BASE_ADDRESS+0x413) +#define WCD937X_DIGITAL_CDC_COMP_CTL_0 (WCD937X_BASE_ADDRESS+0x414) +#define WCD937X_DIGITAL_CDC_RX_DELAY_CTL (WCD937X_BASE_ADDRESS+0x417) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_0 (WCD937X_BASE_ADDRESS+0x418) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_1 (WCD937X_BASE_ADDRESS+0x419) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_0 (WCD937X_BASE_ADDRESS+0x41A) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_1 (WCD937X_BASE_ADDRESS+0x41B) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_0 (WCD937X_BASE_ADDRESS+0x41C) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_1 (WCD937X_BASE_ADDRESS+0x41D) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_0 (WCD937X_BASE_ADDRESS+0x41E) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_1 (WCD937X_BASE_ADDRESS+0x41F) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_0 (WCD937X_BASE_ADDRESS+0x420) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_1 (WCD937X_BASE_ADDRESS+0x421) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A6_0 (WCD937X_BASE_ADDRESS+0x422) +#define WCD937X_DIGITAL_CDC_HPH_DSM_A7_0 (WCD937X_BASE_ADDRESS+0x423) +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_0 (WCD937X_BASE_ADDRESS+0x424) +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_1 (WCD937X_BASE_ADDRESS+0x425) +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_2 (WCD937X_BASE_ADDRESS+0x426) +#define WCD937X_DIGITAL_CDC_HPH_DSM_C_3 (WCD937X_BASE_ADDRESS+0x427) +#define WCD937X_DIGITAL_CDC_HPH_DSM_R1 (WCD937X_BASE_ADDRESS+0x428) +#define WCD937X_DIGITAL_CDC_HPH_DSM_R2 (WCD937X_BASE_ADDRESS+0x429) +#define WCD937X_DIGITAL_CDC_HPH_DSM_R3 (WCD937X_BASE_ADDRESS+0x42A) +#define WCD937X_DIGITAL_CDC_HPH_DSM_R4 (WCD937X_BASE_ADDRESS+0x42B) +#define WCD937X_DIGITAL_CDC_HPH_DSM_R5 (WCD937X_BASE_ADDRESS+0x42C) +#define WCD937X_DIGITAL_CDC_HPH_DSM_R6 (WCD937X_BASE_ADDRESS+0x42D) +#define WCD937X_DIGITAL_CDC_HPH_DSM_R7 (WCD937X_BASE_ADDRESS+0x42E) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_0 (WCD937X_BASE_ADDRESS+0x42F) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_1 (WCD937X_BASE_ADDRESS+0x430) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_0 (WCD937X_BASE_ADDRESS+0x431) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_1 (WCD937X_BASE_ADDRESS+0x432) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_0 (WCD937X_BASE_ADDRESS+0x433) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_1 (WCD937X_BASE_ADDRESS+0x434) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_0 (WCD937X_BASE_ADDRESS+0x435) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_1 (WCD937X_BASE_ADDRESS+0x436) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_0 (WCD937X_BASE_ADDRESS+0x437) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_1 (WCD937X_BASE_ADDRESS+0x438) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A6_0 (WCD937X_BASE_ADDRESS+0x439) +#define WCD937X_DIGITAL_CDC_AUX_DSM_A7_0 (WCD937X_BASE_ADDRESS+0x43A) +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_0 (WCD937X_BASE_ADDRESS+0x43B) +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_1 (WCD937X_BASE_ADDRESS+0x43C) +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_2 (WCD937X_BASE_ADDRESS+0x43D) +#define WCD937X_DIGITAL_CDC_AUX_DSM_C_3 (WCD937X_BASE_ADDRESS+0x43E) +#define WCD937X_DIGITAL_CDC_AUX_DSM_R1 (WCD937X_BASE_ADDRESS+0x43F) +#define WCD937X_DIGITAL_CDC_AUX_DSM_R2 (WCD937X_BASE_ADDRESS+0x440) +#define WCD937X_DIGITAL_CDC_AUX_DSM_R3 (WCD937X_BASE_ADDRESS+0x441) +#define WCD937X_DIGITAL_CDC_AUX_DSM_R4 (WCD937X_BASE_ADDRESS+0x442) +#define WCD937X_DIGITAL_CDC_AUX_DSM_R5 (WCD937X_BASE_ADDRESS+0x443) +#define WCD937X_DIGITAL_CDC_AUX_DSM_R6 (WCD937X_BASE_ADDRESS+0x444) +#define WCD937X_DIGITAL_CDC_AUX_DSM_R7 (WCD937X_BASE_ADDRESS+0x445) +#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0 (WCD937X_BASE_ADDRESS+0x446) +#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1 (WCD937X_BASE_ADDRESS+0x447) +#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0 (WCD937X_BASE_ADDRESS+0x448) +#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1 (WCD937X_BASE_ADDRESS+0x449) +#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2 (WCD937X_BASE_ADDRESS+0x44A) +#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0 (WCD937X_BASE_ADDRESS+0x44B) +#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1 (WCD937X_BASE_ADDRESS+0x44C) +#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2 (WCD937X_BASE_ADDRESS+0x44D) +#define WCD937X_DIGITAL_CDC_HPH_GAIN_CTL (WCD937X_BASE_ADDRESS+0x44E) +#define WCD937X_DIGITAL_CDC_AUX_GAIN_CTL (WCD937X_BASE_ADDRESS+0x44F) +#define WCD937X_DIGITAL_CDC_EAR_PATH_CTL (WCD937X_BASE_ADDRESS+0x450) +#define WCD937X_DIGITAL_CDC_SWR_CLH (WCD937X_BASE_ADDRESS+0x451) +#define WCD937X_DIGITAL_SWR_CLH_BYP (WCD937X_BASE_ADDRESS+0x452) +#define WCD937X_DIGITAL_CDC_TX0_CTL (WCD937X_BASE_ADDRESS+0x453) +#define WCD937X_DIGITAL_CDC_TX1_CTL (WCD937X_BASE_ADDRESS+0x454) +#define WCD937X_DIGITAL_CDC_TX2_CTL (WCD937X_BASE_ADDRESS+0x455) +#define WCD937X_DIGITAL_CDC_TX_RST (WCD937X_BASE_ADDRESS+0x456) +#define WCD937X_DIGITAL_CDC_REQ_CTL (WCD937X_BASE_ADDRESS+0x457) +#define WCD937X_DIGITAL_CDC_AMIC_CTL (WCD937X_BASE_ADDRESS+0x45A) +#define WCD937X_DIGITAL_CDC_DMIC_CTL (WCD937X_BASE_ADDRESS+0x45B) +#define WCD937X_DIGITAL_CDC_DMIC1_CTL (WCD937X_BASE_ADDRESS+0x45C) +#define WCD937X_DIGITAL_CDC_DMIC2_CTL (WCD937X_BASE_ADDRESS+0x45D) +#define WCD937X_DIGITAL_CDC_DMIC3_CTL (WCD937X_BASE_ADDRESS+0x45E) +#define WCD937X_DIGITAL_EFUSE_CTL (WCD937X_BASE_ADDRESS+0x45F) +#define WCD937X_DIGITAL_EFUSE_PRG_CTL (WCD937X_BASE_ADDRESS+0x460) +#define WCD937X_DIGITAL_EFUSE_TEST_CTL_0 (WCD937X_BASE_ADDRESS+0x461) +#define WCD937X_DIGITAL_EFUSE_TEST_CTL_1 (WCD937X_BASE_ADDRESS+0x462) +#define WCD937X_DIGITAL_EFUSE_T_DATA_0 (WCD937X_BASE_ADDRESS+0x463) +#define WCD937X_DIGITAL_EFUSE_T_DATA_1 (WCD937X_BASE_ADDRESS+0x464) +#define WCD937X_DIGITAL_PDM_WD_CTL0 (WCD937X_BASE_ADDRESS+0x465) +#define WCD937X_DIGITAL_PDM_WD_CTL1 (WCD937X_BASE_ADDRESS+0x466) +#define WCD937X_DIGITAL_PDM_WD_CTL2 (WCD937X_BASE_ADDRESS+0x467) +#define WCD937X_DIGITAL_INTR_MODE (WCD937X_BASE_ADDRESS+0x46A) +#define WCD937X_DIGITAL_INTR_MASK_0 (WCD937X_BASE_ADDRESS+0x46B) +#define WCD937X_DIGITAL_INTR_MASK_1 (WCD937X_BASE_ADDRESS+0x46C) +#define WCD937X_DIGITAL_INTR_MASK_2 (WCD937X_BASE_ADDRESS+0x46D) +#define WCD937X_DIGITAL_INTR_STATUS_0 (WCD937X_BASE_ADDRESS+0x46E) +#define WCD937X_DIGITAL_INTR_STATUS_1 (WCD937X_BASE_ADDRESS+0x46F) +#define WCD937X_DIGITAL_INTR_STATUS_2 (WCD937X_BASE_ADDRESS+0x470) +#define WCD937X_DIGITAL_INTR_CLEAR_0 (WCD937X_BASE_ADDRESS+0x471) +#define WCD937X_DIGITAL_INTR_CLEAR_1 (WCD937X_BASE_ADDRESS+0x472) +#define WCD937X_DIGITAL_INTR_CLEAR_2 (WCD937X_BASE_ADDRESS+0x473) +#define WCD937X_DIGITAL_INTR_LEVEL_0 (WCD937X_BASE_ADDRESS+0x474) +#define WCD937X_DIGITAL_INTR_LEVEL_1 (WCD937X_BASE_ADDRESS+0x475) +#define WCD937X_DIGITAL_INTR_LEVEL_2 (WCD937X_BASE_ADDRESS+0x476) +#define WCD937X_DIGITAL_INTR_SET_0 (WCD937X_BASE_ADDRESS+0x477) +#define WCD937X_DIGITAL_INTR_SET_1 (WCD937X_BASE_ADDRESS+0x478) +#define WCD937X_DIGITAL_INTR_SET_2 (WCD937X_BASE_ADDRESS+0x479) +#define WCD937X_DIGITAL_INTR_TEST_0 (WCD937X_BASE_ADDRESS+0x47A) +#define WCD937X_DIGITAL_INTR_TEST_1 (WCD937X_BASE_ADDRESS+0x47B) +#define WCD937X_DIGITAL_INTR_TEST_2 (WCD937X_BASE_ADDRESS+0x47C) +#define WCD937X_DIGITAL_CDC_CONN_RX0_CTL (WCD937X_BASE_ADDRESS+0x47F) +#define WCD937X_DIGITAL_CDC_CONN_RX1_CTL (WCD937X_BASE_ADDRESS+0x480) +#define WCD937X_DIGITAL_CDC_CONN_RX2_CTL (WCD937X_BASE_ADDRESS+0x481) +#define WCD937X_DIGITAL_CDC_CONN_TX_CTL (WCD937X_BASE_ADDRESS+0x482) +#define WCD937X_DIGITAL_LOOP_BACK_MODE (WCD937X_BASE_ADDRESS+0x483) +#define WCD937X_DIGITAL_SWR_DAC_TEST (WCD937X_BASE_ADDRESS+0x484) +#define WCD937X_DIGITAL_SWR_HM_TEST_RX_0 (WCD937X_BASE_ADDRESS+0x485) +#define WCD937X_DIGITAL_SWR_HM_TEST_TX_0 (WCD937X_BASE_ADDRESS+0x491) +#define WCD937X_DIGITAL_SWR_HM_TEST_RX_1 (WCD937X_BASE_ADDRESS+0x492) +#define WCD937X_DIGITAL_SWR_HM_TEST_TX_1 (WCD937X_BASE_ADDRESS+0x493) +#define WCD937X_DIGITAL_SWR_HM_TEST (WCD937X_BASE_ADDRESS+0x494) +#define WCD937X_DIGITAL_PAD_CTL_PDM_RX0 (WCD937X_BASE_ADDRESS+0x495) +#define WCD937X_DIGITAL_PAD_CTL_PDM_RX1 (WCD937X_BASE_ADDRESS+0x496) +#define WCD937X_DIGITAL_PAD_CTL_PDM_TX0 (WCD937X_BASE_ADDRESS+0x497) +#define WCD937X_DIGITAL_PAD_CTL_PDM_TX1 (WCD937X_BASE_ADDRESS+0x498) +#define WCD937X_DIGITAL_PAD_INP_DIS_0 (WCD937X_BASE_ADDRESS+0x499) +#define WCD937X_DIGITAL_PAD_INP_DIS_1 (WCD937X_BASE_ADDRESS+0x49A) +#define WCD937X_DIGITAL_DRIVE_STRENGTH_0 (WCD937X_BASE_ADDRESS+0x49B) +#define WCD937X_DIGITAL_DRIVE_STRENGTH_1 (WCD937X_BASE_ADDRESS+0x49C) +#define WCD937X_DIGITAL_DRIVE_STRENGTH_2 (WCD937X_BASE_ADDRESS+0x49D) +#define WCD937X_DIGITAL_RX_DATA_EDGE_CTL (WCD937X_BASE_ADDRESS+0x49E) +#define WCD937X_DIGITAL_TX_DATA_EDGE_CTL (WCD937X_BASE_ADDRESS+0x49F) +#define WCD937X_DIGITAL_GPIO_MODE (WCD937X_BASE_ADDRESS+0x4A0) +#define WCD937X_DIGITAL_PIN_CTL_OE (WCD937X_BASE_ADDRESS+0x4A1) +#define WCD937X_DIGITAL_PIN_CTL_DATA_0 (WCD937X_BASE_ADDRESS+0x4A2) +#define WCD937X_DIGITAL_PIN_CTL_DATA_1 (WCD937X_BASE_ADDRESS+0x4A3) +#define WCD937X_DIGITAL_PIN_STATUS_0 (WCD937X_BASE_ADDRESS+0x4A4) +#define WCD937X_DIGITAL_PIN_STATUS_1 (WCD937X_BASE_ADDRESS+0x4A5) +#define WCD937X_DIGITAL_DIG_DEBUG_CTL (WCD937X_BASE_ADDRESS+0x4A6) +#define WCD937X_DIGITAL_DIG_DEBUG_EN (WCD937X_BASE_ADDRESS+0x4A7) +#define WCD937X_DIGITAL_ANA_CSR_DBG_ADD (WCD937X_BASE_ADDRESS+0x4A8) +#define WCD937X_DIGITAL_ANA_CSR_DBG_CTL (WCD937X_BASE_ADDRESS+0x4A9) +#define WCD937X_DIGITAL_SSP_DBG (WCD937X_BASE_ADDRESS+0x4AA) +#define WCD937X_DIGITAL_MODE_STATUS_0 (WCD937X_BASE_ADDRESS+0x4AB) +#define WCD937X_DIGITAL_MODE_STATUS_1 (WCD937X_BASE_ADDRESS+0x4AC) +#define WCD937X_DIGITAL_SPARE_0 (WCD937X_BASE_ADDRESS+0x4AD) +#define WCD937X_DIGITAL_SPARE_1 (WCD937X_BASE_ADDRESS+0x4AE) +#define WCD937X_DIGITAL_SPARE_2 (WCD937X_BASE_ADDRESS+0x4AF) +#define WCD937X_DIGITAL_EFUSE_REG_0 (WCD937X_BASE_ADDRESS+0x4B0) +#define WCD937X_DIGITAL_EFUSE_REG_1 (WCD937X_BASE_ADDRESS+0x4B1) +#define WCD937X_DIGITAL_EFUSE_REG_2 (WCD937X_BASE_ADDRESS+0x4B2) +#define WCD937X_DIGITAL_EFUSE_REG_3 (WCD937X_BASE_ADDRESS+0x4B3) +#define WCD937X_DIGITAL_EFUSE_REG_4 (WCD937X_BASE_ADDRESS+0x4B4) +#define WCD937X_DIGITAL_EFUSE_REG_5 (WCD937X_BASE_ADDRESS+0x4B5) +#define WCD937X_DIGITAL_EFUSE_REG_6 (WCD937X_BASE_ADDRESS+0x4B6) +#define WCD937X_DIGITAL_EFUSE_REG_7 (WCD937X_BASE_ADDRESS+0x4B7) +#define WCD937X_DIGITAL_EFUSE_REG_8 (WCD937X_BASE_ADDRESS+0x4B8) +#define WCD937X_DIGITAL_EFUSE_REG_9 (WCD937X_BASE_ADDRESS+0x4B9) +#define WCD937X_DIGITAL_EFUSE_REG_10 (WCD937X_BASE_ADDRESS+0x4BA) +#define WCD937X_DIGITAL_EFUSE_REG_11 (WCD937X_BASE_ADDRESS+0x4BB) +#define WCD937X_DIGITAL_EFUSE_REG_12 (WCD937X_BASE_ADDRESS+0x4BC) +#define WCD937X_DIGITAL_EFUSE_REG_13 (WCD937X_BASE_ADDRESS+0x4BD) +#define WCD937X_DIGITAL_EFUSE_REG_14 (WCD937X_BASE_ADDRESS+0x4BE) +#define WCD937X_DIGITAL_EFUSE_REG_15 (WCD937X_BASE_ADDRESS+0x4BF) +#define WCD937X_DIGITAL_EFUSE_REG_16 (WCD937X_BASE_ADDRESS+0x4C0) +#define WCD937X_DIGITAL_EFUSE_REG_17 (WCD937X_BASE_ADDRESS+0x4C1) +#define WCD937X_DIGITAL_EFUSE_REG_18 (WCD937X_BASE_ADDRESS+0x4C2) +#define WCD937X_DIGITAL_EFUSE_REG_19 (WCD937X_BASE_ADDRESS+0x4C3) +#define WCD937X_DIGITAL_EFUSE_REG_20 (WCD937X_BASE_ADDRESS+0x4C4) +#define WCD937X_DIGITAL_EFUSE_REG_21 (WCD937X_BASE_ADDRESS+0x4C5) +#define WCD937X_DIGITAL_EFUSE_REG_22 (WCD937X_BASE_ADDRESS+0x4C6) +#define WCD937X_DIGITAL_EFUSE_REG_23 (WCD937X_BASE_ADDRESS+0x4C7) +#define WCD937X_DIGITAL_EFUSE_REG_24 (WCD937X_BASE_ADDRESS+0x4C8) +#define WCD937X_DIGITAL_EFUSE_REG_25 (WCD937X_BASE_ADDRESS+0x4C9) +#define WCD937X_DIGITAL_EFUSE_REG_26 (WCD937X_BASE_ADDRESS+0x4CA) +#define WCD937X_DIGITAL_EFUSE_REG_27 (WCD937X_BASE_ADDRESS+0x4CB) +#define WCD937X_DIGITAL_EFUSE_REG_28 (WCD937X_BASE_ADDRESS+0x4CC) +#define WCD937X_DIGITAL_EFUSE_REG_29 (WCD937X_BASE_ADDRESS+0x4CD) +#define WCD937X_DIGITAL_EFUSE_REG_30 (WCD937X_BASE_ADDRESS+0x4CE) +#define WCD937X_DIGITAL_EFUSE_REG_31 (WCD937X_BASE_ADDRESS+0x4CF) + +#define WCD937X_REGISTERS_MAX_SIZE (WCD937X_BASE_ADDRESS+0x4D0) +#define WCD937X_MAX_REGISTER (WCD937X_REGISTERS_MAX_SIZE - 1) + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-regmap.c new file mode 100644 index 0000000000..0bbc4b8a8a --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-regmap.c @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "wcd937x-registers.h" + +extern const u8 wcd937x_reg_access[WCD937X_REGISTERS_MAX_SIZE]; + +static const struct reg_default wcd937x_defaults[] = { + { WCD937X_ANA_BIAS, 0x00 }, + { WCD937X_ANA_RX_SUPPLIES, 0x00 }, + { WCD937X_ANA_HPH, 0x0C }, + { WCD937X_ANA_EAR, 0x00 }, + { WCD937X_ANA_EAR_COMPANDER_CTL, 0x02 }, + { WCD937X_ANA_TX_CH1, 0x20 }, + { WCD937X_ANA_TX_CH2, 0x00 }, + { WCD937X_ANA_TX_CH3, 0x20 }, + { WCD937X_ANA_TX_CH3_HPF, 0x00 }, + { WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00 }, + { WCD937X_ANA_MICB3_DSP_EN_LOGIC, 0x00 }, + { WCD937X_ANA_MBHC_MECH, 0x39 }, + { WCD937X_ANA_MBHC_ELECT, 0x08 }, + { WCD937X_ANA_MBHC_ZDET, 0x00 }, + { WCD937X_ANA_MBHC_RESULT_1, 0x00 }, + { WCD937X_ANA_MBHC_RESULT_2, 0x00 }, + { WCD937X_ANA_MBHC_RESULT_3, 0x00 }, + { WCD937X_ANA_MBHC_BTN0, 0x00 }, + { WCD937X_ANA_MBHC_BTN1, 0x10 }, + { WCD937X_ANA_MBHC_BTN2, 0x20 }, + { WCD937X_ANA_MBHC_BTN3, 0x30 }, + { WCD937X_ANA_MBHC_BTN4, 0x40 }, + { WCD937X_ANA_MBHC_BTN5, 0x50 }, + { WCD937X_ANA_MBHC_BTN6, 0x60 }, + { WCD937X_ANA_MBHC_BTN7, 0x70 }, + { WCD937X_ANA_MICB1, 0x10 }, + { WCD937X_ANA_MICB2, 0x10 }, + { WCD937X_ANA_MICB2_RAMP, 0x00 }, + { WCD937X_ANA_MICB3, 0x10 }, + { WCD937X_BIAS_CTL, 0x2A }, + { WCD937X_BIAS_VBG_FINE_ADJ, 0x55 }, + { WCD937X_LDOL_VDDCX_ADJUST, 0x01 }, + { WCD937X_LDOL_DISABLE_LDOL, 0x00 }, + { WCD937X_MBHC_CTL_CLK, 0x00 }, + { WCD937X_MBHC_CTL_ANA, 0x00 }, + { WCD937X_MBHC_CTL_SPARE_1, 0x00 }, + { WCD937X_MBHC_CTL_SPARE_2, 0x00 }, + { WCD937X_MBHC_CTL_BCS, 0x00 }, + { WCD937X_MBHC_MOISTURE_DET_FSM_STATUS, 0x00 }, + { WCD937X_MBHC_TEST_CTL, 0x00 }, + { WCD937X_LDOH_MODE, 0x2B }, + { WCD937X_LDOH_BIAS, 0x68 }, + { WCD937X_LDOH_STB_LOADS, 0x00 }, + { WCD937X_LDOH_SLOWRAMP, 0x50 }, + { WCD937X_MICB1_TEST_CTL_1, 0x1A }, + { WCD937X_MICB1_TEST_CTL_2, 0x18 }, + { WCD937X_MICB1_TEST_CTL_3, 0xA4 }, + { WCD937X_MICB2_TEST_CTL_1, 0x1A }, + { WCD937X_MICB2_TEST_CTL_2, 0x18 }, + { WCD937X_MICB2_TEST_CTL_3, 0xA4 }, + { WCD937X_MICB3_TEST_CTL_1, 0x1A }, + { WCD937X_MICB3_TEST_CTL_2, 0x18 }, + { WCD937X_MICB3_TEST_CTL_3, 0xA4 }, + { WCD937X_TX_COM_ADC_VCM, 0x39 }, + { WCD937X_TX_COM_BIAS_ATEST, 0xC0 }, + { WCD937X_TX_COM_ADC_INT1_IB, 0x6F }, + { WCD937X_TX_COM_ADC_INT2_IB, 0x4F }, + { WCD937X_TX_COM_TXFE_DIV_CTL, 0x2E }, + { WCD937X_TX_COM_TXFE_DIV_START, 0x00 }, + { WCD937X_TX_COM_TXFE_DIV_STOP_9P6M, 0xC7 }, + { WCD937X_TX_COM_TXFE_DIV_STOP_12P288M, 0xFF }, + { WCD937X_TX_1_2_TEST_EN, 0xCC }, + { WCD937X_TX_1_2_ADC_IB, 0x09 }, + { WCD937X_TX_1_2_ATEST_REFCTL, 0x0A }, + { WCD937X_TX_1_2_TEST_CTL, 0x38 }, + { WCD937X_TX_1_2_TEST_BLK_EN, 0xFF }, + { WCD937X_TX_1_2_TXFE_CLKDIV, 0x00 }, + { WCD937X_TX_1_2_SAR2_ERR, 0x00 }, + { WCD937X_TX_1_2_SAR1_ERR, 0x00 }, + { WCD937X_TX_3_TEST_EN, 0xCC }, + { WCD937X_TX_3_ADC_IB, 0x09 }, + { WCD937X_TX_3_ATEST_REFCTL, 0x0A }, + { WCD937X_TX_3_TEST_CTL, 0x38 }, + { WCD937X_TX_3_TEST_BLK_EN, 0xFF }, + { WCD937X_TX_3_TXFE_CLKDIV, 0x00 }, + { WCD937X_TX_3_SPARE_MONO, 0x00 }, + { WCD937X_TX_3_SAR1_ERR, 0x00 }, + { WCD937X_CLASSH_MODE_1, 0x40 }, + { WCD937X_CLASSH_MODE_2, 0x3A }, + { WCD937X_CLASSH_MODE_3, 0x00 }, + { WCD937X_CLASSH_CTRL_VCL_1, 0x70 }, + { WCD937X_CLASSH_CTRL_VCL_2, 0x82 }, + { WCD937X_CLASSH_CTRL_CCL_1, 0x31 }, + { WCD937X_CLASSH_CTRL_CCL_2, 0x80 }, + { WCD937X_CLASSH_CTRL_CCL_3, 0x80 }, + { WCD937X_CLASSH_CTRL_CCL_4, 0x51 }, + { WCD937X_CLASSH_CTRL_CCL_5, 0x00 }, + { WCD937X_CLASSH_BUCK_TMUX_A_D, 0x00 }, + { WCD937X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 }, + { WCD937X_CLASSH_SPARE, 0x00 }, + { WCD937X_FLYBACK_EN, 0x4E }, + { WCD937X_FLYBACK_VNEG_CTRL_1, 0x0B }, + { WCD937X_FLYBACK_VNEG_CTRL_2, 0x45 }, + { WCD937X_FLYBACK_VNEG_CTRL_3, 0x74 }, + { WCD937X_FLYBACK_VNEG_CTRL_4, 0x7F }, + { WCD937X_FLYBACK_VNEG_CTRL_5, 0x83 }, + { WCD937X_FLYBACK_VNEG_CTRL_6, 0x98 }, + { WCD937X_FLYBACK_VNEG_CTRL_7, 0xA9 }, + { WCD937X_FLYBACK_VNEG_CTRL_8, 0x68 }, + { WCD937X_FLYBACK_VNEG_CTRL_9, 0x64 }, + { WCD937X_FLYBACK_VNEGDAC_CTRL_1, 0xED }, + { WCD937X_FLYBACK_VNEGDAC_CTRL_2, 0xF0 }, + { WCD937X_FLYBACK_VNEGDAC_CTRL_3, 0xA6 }, + { WCD937X_FLYBACK_CTRL_1, 0x65 }, + { WCD937X_FLYBACK_TEST_CTL, 0x00 }, + { WCD937X_RX_AUX_SW_CTL, 0x00 }, + { WCD937X_RX_PA_AUX_IN_CONN, 0x00 }, + { WCD937X_RX_TIMER_DIV, 0x32 }, + { WCD937X_RX_OCP_CTL, 0x1F }, + { WCD937X_RX_OCP_COUNT, 0x77 }, + { WCD937X_RX_BIAS_EAR_DAC, 0xA0 }, + { WCD937X_RX_BIAS_EAR_AMP, 0xAA }, + { WCD937X_RX_BIAS_HPH_LDO, 0xA9 }, + { WCD937X_RX_BIAS_HPH_PA, 0xAA }, + { WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A }, + { WCD937X_RX_BIAS_HPH_RDAC_LDO, 0x88 }, + { WCD937X_RX_BIAS_HPH_CNP1, 0x82 }, + { WCD937X_RX_BIAS_HPH_LOWPOWER, 0x82 }, + { WCD937X_RX_BIAS_AUX_DAC, 0xA0 }, + { WCD937X_RX_BIAS_AUX_AMP, 0xAA }, + { WCD937X_RX_BIAS_VNEGDAC_BLEEDER, 0x50 }, + { WCD937X_RX_BIAS_MISC, 0x00 }, + { WCD937X_RX_BIAS_BUCK_RST, 0x08 }, + { WCD937X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 }, + { WCD937X_RX_BIAS_FLYB_ERRAMP, 0x40 }, + { WCD937X_RX_BIAS_FLYB_BUFF, 0xAA }, + { WCD937X_RX_BIAS_FLYB_MID_RST, 0x14 }, + { WCD937X_HPH_L_STATUS, 0x04 }, + { WCD937X_HPH_R_STATUS, 0x04 }, + { WCD937X_HPH_CNP_EN, 0x80 }, + { WCD937X_HPH_CNP_WG_CTL, 0x9A }, + { WCD937X_HPH_CNP_WG_TIME, 0x14 }, + { WCD937X_HPH_OCP_CTL, 0x28 }, + { WCD937X_HPH_AUTO_CHOP, 0x16 }, + { WCD937X_HPH_CHOP_CTL, 0x83 }, + { WCD937X_HPH_PA_CTL1, 0x46 }, + { WCD937X_HPH_PA_CTL2, 0x50 }, + { WCD937X_HPH_L_EN, 0x80 }, + { WCD937X_HPH_L_TEST, 0xE0 }, + { WCD937X_HPH_L_ATEST, 0x50 }, + { WCD937X_HPH_R_EN, 0x80 }, + { WCD937X_HPH_R_TEST, 0xE0 }, + { WCD937X_HPH_R_ATEST, 0x54 }, + { WCD937X_HPH_RDAC_CLK_CTL1, 0x99 }, + { WCD937X_HPH_RDAC_CLK_CTL2, 0x9B }, + { WCD937X_HPH_RDAC_LDO_CTL, 0x33 }, + { WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 }, + { WCD937X_HPH_REFBUFF_UHQA_CTL, 0xA8 }, + { WCD937X_HPH_REFBUFF_LP_CTL, 0x0E }, + { WCD937X_HPH_L_DAC_CTL, 0x20 }, + { WCD937X_HPH_R_DAC_CTL, 0x20 }, + { WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55 }, + { WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0x19 }, + { WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xA0 }, + { WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS, 0x00 }, + { WCD937X_EAR_EAR_EN_REG, 0x22 }, + { WCD937X_EAR_EAR_PA_CON, 0x44 }, + { WCD937X_EAR_EAR_SP_CON, 0xDB }, + { WCD937X_EAR_EAR_DAC_CON, 0x80 }, + { WCD937X_EAR_EAR_CNP_FSM_CON, 0xB2 }, + { WCD937X_EAR_TEST_CTL, 0x00 }, + { WCD937X_EAR_STATUS_REG_1, 0x00 }, + { WCD937X_EAR_STATUS_REG_2, 0x00 }, + { WCD937X_ANA_NEW_PAGE_REGISTER, 0x00 }, + { WCD937X_HPH_NEW_ANA_HPH2, 0x00 }, + { WCD937X_HPH_NEW_ANA_HPH3, 0x00 }, + { WCD937X_SLEEP_CTL, 0x16 }, + { WCD937X_SLEEP_WATCHDOG_CTL, 0x00 }, + { WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 }, + { WCD937X_MBHC_NEW_CTL_1, 0x02 }, + { WCD937X_MBHC_NEW_CTL_2, 0x05 }, + { WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0xE9 }, + { WCD937X_MBHC_NEW_ZDET_ANA_CTL, 0x0F }, + { WCD937X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 }, + { WCD937X_MBHC_NEW_FSM_STATUS, 0x00 }, + { WCD937X_MBHC_NEW_ADC_RESULT, 0x00 }, + { WCD937X_TX_NEW_TX_CH2_SEL, 0x00 }, + { WCD937X_AUX_AUXPA, 0x00 }, + { WCD937X_LDORXTX_MODE, 0x0C }, + { WCD937X_LDORXTX_CONFIG, 0x10 }, + { WCD937X_DIE_CRACK_DIE_CRK_DET_EN, 0x00 }, + { WCD937X_DIE_CRACK_DIE_CRK_DET_OUT, 0x00 }, + { WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 }, + { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81 }, + { WCD937X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 }, + { WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 }, + { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81 }, + { WCD937X_HPH_NEW_INT_PA_MISC1, 0x22 }, + { WCD937X_HPH_NEW_INT_PA_MISC2, 0x00 }, + { WCD937X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 }, + { WCD937X_HPH_NEW_INT_HPH_TIMER1, 0xFE }, + { WCD937X_HPH_NEW_INT_HPH_TIMER2, 0x02 }, + { WCD937X_HPH_NEW_INT_HPH_TIMER3, 0x4E }, + { WCD937X_HPH_NEW_INT_HPH_TIMER4, 0x54 }, + { WCD937X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 }, + { WCD937X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 }, + { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62 }, + { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 }, + { WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 }, + { WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57 }, + { WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01 }, + { WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00 }, + { WCD937X_MBHC_NEW_INT_SPARE_2, 0x00 }, + { WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xA8 }, + { WCD937X_EAR_INT_NEW_CNP_VCM_CON1, 0x42 }, + { WCD937X_EAR_INT_NEW_CNP_VCM_CON2, 0x22 }, + { WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00 }, + { WCD937X_AUX_INT_EN_REG, 0x00 }, + { WCD937X_AUX_INT_PA_CTRL, 0x06 }, + { WCD937X_AUX_INT_SP_CTRL, 0xD2 }, + { WCD937X_AUX_INT_DAC_CTRL, 0x80 }, + { WCD937X_AUX_INT_CLK_CTRL, 0x50 }, + { WCD937X_AUX_INT_TEST_CTRL, 0x00 }, + { WCD937X_AUX_INT_STATUS_REG, 0x00 }, + { WCD937X_AUX_INT_MISC, 0x00 }, + { WCD937X_LDORXTX_INT_BIAS, 0x6E }, + { WCD937X_LDORXTX_INT_STB_LOADS_DTEST, 0x50 }, + { WCD937X_LDORXTX_INT_TEST0, 0x1C }, + { WCD937X_LDORXTX_INT_STARTUP_TIMER, 0xFF }, + { WCD937X_LDORXTX_INT_TEST1, 0x1F }, + { WCD937X_LDORXTX_INT_STATUS, 0x00 }, + { WCD937X_SLEEP_INT_WATCHDOG_CTL_1, 0x0A }, + { WCD937X_SLEEP_INT_WATCHDOG_CTL_2, 0x0A }, + { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02 }, + { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60 }, + { WCD937X_DIGITAL_PAGE_REGISTER, 0x00 }, + { WCD937X_DIGITAL_CHIP_ID0, 0x01 }, + { WCD937X_DIGITAL_CHIP_ID1, 0x00 }, + { WCD937X_DIGITAL_CHIP_ID2, 0x0A }, + { WCD937X_DIGITAL_CHIP_ID3, 0x01 }, + { WCD937X_DIGITAL_CDC_RST_CTL, 0x03 }, + { WCD937X_DIGITAL_TOP_CLK_CFG, 0x00 }, + { WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x00 }, + { WCD937X_DIGITAL_SWR_RST_EN, 0x00 }, + { WCD937X_DIGITAL_CDC_PATH_MODE, 0x55 }, + { WCD937X_DIGITAL_CDC_RX_RST, 0x00 }, + { WCD937X_DIGITAL_CDC_RX0_CTL, 0xFC }, + { WCD937X_DIGITAL_CDC_RX1_CTL, 0xFC }, + { WCD937X_DIGITAL_CDC_RX2_CTL, 0xFC }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA0, 0x55 }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA1, 0x55 }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA2, 0x55 }, + { WCD937X_DIGITAL_DEM_BYPASS_DATA3, 0x01 }, + { WCD937X_DIGITAL_CDC_COMP_CTL_0, 0x00 }, + { WCD937X_DIGITAL_CDC_RX_DELAY_CTL, 0x66 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A3_0, 0xAC }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1A }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A5_0, 0xBC }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A6_0, 0xC7 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_A7_0, 0xF8 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_0, 0x47 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_1, 0x43 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_2, 0xB1 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_C_3, 0x17 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R1, 0x4B }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R2, 0x26 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R3, 0x32 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R4, 0x57 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R5, 0x63 }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R6, 0x7C }, + { WCD937X_DIGITAL_CDC_HPH_DSM_R7, 0x57 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A3_0, 0xAB }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1C }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A6_0, 0xAA }, + { WCD937X_DIGITAL_CDC_AUX_DSM_A7_0, 0xE3 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_0, 0x69 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_1, 0x54 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_2, 0x02 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_C_3, 0x15 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R1, 0xA4 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R2, 0xB5 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R3, 0x86 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R4, 0x85 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R5, 0xAA }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R6, 0xE2 }, + { WCD937X_DIGITAL_CDC_AUX_DSM_R7, 0x62 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xA9 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3D }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2E }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01 }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00 }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xFC }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01 }, + { WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_SWR_CLH, 0x00 }, + { WCD937X_DIGITAL_SWR_CLH_BYP, 0x00 }, + { WCD937X_DIGITAL_CDC_TX0_CTL, 0x68 }, + { WCD937X_DIGITAL_CDC_TX1_CTL, 0x68 }, + { WCD937X_DIGITAL_CDC_TX2_CTL, 0x68 }, + { WCD937X_DIGITAL_CDC_TX_RST, 0x00 }, + { WCD937X_DIGITAL_CDC_REQ_CTL, 0x01 }, + { WCD937X_DIGITAL_CDC_AMIC_CTL, 0x07 }, + { WCD937X_DIGITAL_CDC_DMIC_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_DMIC1_CTL, 0x01 }, + { WCD937X_DIGITAL_CDC_DMIC2_CTL, 0x01 }, + { WCD937X_DIGITAL_CDC_DMIC3_CTL, 0x01 }, + { WCD937X_DIGITAL_EFUSE_CTL, 0x2B }, + { WCD937X_DIGITAL_EFUSE_PRG_CTL, 0x00 }, + { WCD937X_DIGITAL_EFUSE_TEST_CTL_0, 0x00 }, + { WCD937X_DIGITAL_EFUSE_TEST_CTL_1, 0x00 }, + { WCD937X_DIGITAL_EFUSE_T_DATA_0, 0x00 }, + { WCD937X_DIGITAL_EFUSE_T_DATA_1, 0x00 }, + { WCD937X_DIGITAL_PDM_WD_CTL0, 0x00 }, + { WCD937X_DIGITAL_PDM_WD_CTL1, 0x00 }, + { WCD937X_DIGITAL_PDM_WD_CTL2, 0x00 }, + { WCD937X_DIGITAL_INTR_MODE, 0x00 }, + { WCD937X_DIGITAL_INTR_MASK_0, 0xFF }, + { WCD937X_DIGITAL_INTR_MASK_1, 0xFF }, + { WCD937X_DIGITAL_INTR_MASK_2, 0x0F }, + { WCD937X_DIGITAL_INTR_STATUS_0, 0x00 }, + { WCD937X_DIGITAL_INTR_STATUS_1, 0x00 }, + { WCD937X_DIGITAL_INTR_STATUS_2, 0x00 }, + { WCD937X_DIGITAL_INTR_CLEAR_0, 0x00 }, + { WCD937X_DIGITAL_INTR_CLEAR_1, 0x00 }, + { WCD937X_DIGITAL_INTR_CLEAR_2, 0x00 }, + { WCD937X_DIGITAL_INTR_LEVEL_0, 0x00 }, + { WCD937X_DIGITAL_INTR_LEVEL_1, 0x00 }, + { WCD937X_DIGITAL_INTR_LEVEL_2, 0x00 }, + { WCD937X_DIGITAL_INTR_SET_0, 0x00 }, + { WCD937X_DIGITAL_INTR_SET_1, 0x00 }, + { WCD937X_DIGITAL_INTR_SET_2, 0x00 }, + { WCD937X_DIGITAL_INTR_TEST_0, 0x00 }, + { WCD937X_DIGITAL_INTR_TEST_1, 0x00 }, + { WCD937X_DIGITAL_INTR_TEST_2, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_RX0_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_RX1_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_RX2_CTL, 0x00 }, + { WCD937X_DIGITAL_CDC_CONN_TX_CTL, 0x00 }, + { WCD937X_DIGITAL_LOOP_BACK_MODE, 0x00 }, + { WCD937X_DIGITAL_SWR_DAC_TEST, 0x00 }, + { WCD937X_DIGITAL_SWR_HM_TEST_RX_0, 0x40 }, + { WCD937X_DIGITAL_SWR_HM_TEST_TX_0, 0x40 }, + { WCD937X_DIGITAL_SWR_HM_TEST_RX_1, 0x00 }, + { WCD937X_DIGITAL_SWR_HM_TEST_TX_1, 0x00 }, + { WCD937X_DIGITAL_SWR_HM_TEST, 0x00 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_RX0, 0xF1 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_RX1, 0xF1 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_TX0, 0xF1 }, + { WCD937X_DIGITAL_PAD_CTL_PDM_TX1, 0xF1 }, + { WCD937X_DIGITAL_PAD_INP_DIS_0, 0x00 }, + { WCD937X_DIGITAL_PAD_INP_DIS_1, 0x00 }, + { WCD937X_DIGITAL_DRIVE_STRENGTH_0, 0x00 }, + { WCD937X_DIGITAL_DRIVE_STRENGTH_1, 0x00 }, + { WCD937X_DIGITAL_DRIVE_STRENGTH_2, 0x00 }, + { WCD937X_DIGITAL_RX_DATA_EDGE_CTL, 0x1F }, + { WCD937X_DIGITAL_TX_DATA_EDGE_CTL, 0x10 }, + { WCD937X_DIGITAL_GPIO_MODE, 0x00 }, + { WCD937X_DIGITAL_PIN_CTL_OE, 0x00 }, + { WCD937X_DIGITAL_PIN_CTL_DATA_0, 0x00 }, + { WCD937X_DIGITAL_PIN_CTL_DATA_1, 0x00 }, + { WCD937X_DIGITAL_PIN_STATUS_0, 0x00 }, + { WCD937X_DIGITAL_PIN_STATUS_1, 0x00 }, + { WCD937X_DIGITAL_DIG_DEBUG_CTL, 0x00 }, + { WCD937X_DIGITAL_DIG_DEBUG_EN, 0x00 }, + { WCD937X_DIGITAL_ANA_CSR_DBG_ADD, 0x00 }, + { WCD937X_DIGITAL_ANA_CSR_DBG_CTL, 0x48 }, + { WCD937X_DIGITAL_SSP_DBG, 0x00 }, + { WCD937X_DIGITAL_MODE_STATUS_0, 0x00 }, + { WCD937X_DIGITAL_MODE_STATUS_1, 0x00 }, + { WCD937X_DIGITAL_SPARE_0, 0x00 }, + { WCD937X_DIGITAL_SPARE_1, 0x00 }, + { WCD937X_DIGITAL_SPARE_2, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_0, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_1, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_2, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_3, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_4, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_5, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_6, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_7, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_8, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_9, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_10, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_11, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_12, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_13, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_14, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_15, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_16, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_17, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_18, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_19, 0xFF }, + { WCD937X_DIGITAL_EFUSE_REG_20, 0x0E }, + { WCD937X_DIGITAL_EFUSE_REG_21, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_22, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_23, 0xF8 }, + { WCD937X_DIGITAL_EFUSE_REG_24, 0x16 }, + { WCD937X_DIGITAL_EFUSE_REG_25, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_26, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_27, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_28, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_29, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_30, 0x00 }, + { WCD937X_DIGITAL_EFUSE_REG_31, 0x00 }, +}; + +static bool wcd937x_readable_register(struct device *dev, unsigned int reg) +{ + if(reg <= WCD937X_BASE_ADDRESS) + return 0; + return wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG; +} + +static bool wcd937x_writeable_register(struct device *dev, unsigned int reg) +{ + if(reg <= WCD937X_BASE_ADDRESS) + return 0; + return wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG; +} + +static bool wcd937x_volatile_register(struct device *dev, unsigned int reg) +{ + if(reg <= WCD937X_BASE_ADDRESS) + return 0; + if ((wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG) + && !(wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG)) + return true; + return false; +} + +struct regmap_config wcd937x_regmap_config = { + .name = "wcd937x_csr", + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd937x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd937x_defaults), + .max_register = WCD937X_MAX_REGISTER, + .readable_reg = wcd937x_readable_register, + .writeable_reg = wcd937x_writeable_register, + .volatile_reg = wcd937x_volatile_register, + .can_multi_write = true, + .use_single_read = true, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-tables.c new file mode 100644 index 0000000000..3631044bdd --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x-tables.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019 , The Linux Foundation. All rights reserved. + */ + +#include +#include "wcd937x-registers.h" + +const u8 wcd937x_reg_access[WCD937X_REG(WCD937X_REGISTERS_MAX_SIZE)] = { + [WCD937X_REG(WCD937X_ANA_BIAS)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_RX_SUPPLIES)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_HPH)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_EAR)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_EAR_COMPANDER_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_TX_CH1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_TX_CH2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_TX_CH3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_TX_CH3_HPF)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MICB3_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_MECH)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_ELECT)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_ZDET)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_RESULT_1)] = RD_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_RESULT_2)] = RD_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_RESULT_3)] = RD_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN4)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN5)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN6)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MBHC_BTN7)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MICB1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MICB2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MICB2_RAMP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_ANA_MICB3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_BIAS_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_BIAS_VBG_FINE_ADJ)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDOL_VDDCX_ADJUST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDOL_DISABLE_LDOL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_CTL_CLK)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_CTL_ANA)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_CTL_SPARE_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_CTL_SPARE_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_CTL_BCS)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_MOISTURE_DET_FSM_STATUS)] = RD_REG, + [WCD937X_REG(WCD937X_MBHC_TEST_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDOH_MODE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDOH_BIAS)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDOH_STB_LOADS)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDOH_SLOWRAMP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB1_TEST_CTL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB1_TEST_CTL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB1_TEST_CTL_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB2_TEST_CTL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB2_TEST_CTL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB2_TEST_CTL_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB3_TEST_CTL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB3_TEST_CTL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MICB3_TEST_CTL_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_ADC_VCM)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_BIAS_ATEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_ADC_INT1_IB)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_ADC_INT2_IB)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_START)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_STOP_9P6M)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_COM_TXFE_DIV_STOP_12P288M)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_1_2_TEST_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_1_2_ADC_IB)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_1_2_ATEST_REFCTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_1_2_TEST_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_1_2_TEST_BLK_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_1_2_TXFE_CLKDIV)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_1_2_SAR2_ERR)] = RD_REG, + [WCD937X_REG(WCD937X_TX_1_2_SAR1_ERR)] = RD_REG, + [WCD937X_REG(WCD937X_TX_3_TEST_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_3_ADC_IB)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_3_ATEST_REFCTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_3_TEST_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_3_TEST_BLK_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_3_TXFE_CLKDIV)] = RD_WR_REG, + [WCD937X_REG(WCD937X_TX_3_SPARE_MONO)] = RD_REG, + [WCD937X_REG(WCD937X_TX_3_SAR1_ERR)] = RD_REG, + [WCD937X_REG(WCD937X_CLASSH_MODE_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_MODE_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_MODE_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_CTRL_VCL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_CTRL_VCL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_4)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_CTRL_CCL_5)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_BUCK_TMUX_A_D)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_BUCK_SW_DRV_CNTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_CLASSH_SPARE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_4)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_5)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_6)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_7)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_8)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEG_CTRL_9)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEGDAC_CTRL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEGDAC_CTRL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_VNEGDAC_CTRL_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_CTRL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_FLYBACK_TEST_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_AUX_SW_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_PA_AUX_IN_CONN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_TIMER_DIV)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_OCP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_OCP_COUNT)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_EAR_DAC)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_EAR_AMP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_HPH_LDO)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_HPH_PA)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_HPH_RDAC_LDO)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_HPH_CNP1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_HPH_LOWPOWER)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_AUX_DAC)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_AUX_AMP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_VNEGDAC_BLEEDER)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_MISC)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_BUCK_RST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_BUCK_VREF_ERRAMP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_FLYB_ERRAMP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_FLYB_BUFF)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_BIAS_FLYB_MID_RST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_L_STATUS)] = RD_REG, + [WCD937X_REG(WCD937X_HPH_R_STATUS)] = RD_REG, + [WCD937X_REG(WCD937X_HPH_CNP_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_CNP_WG_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_CNP_WG_TIME)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_OCP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_AUTO_CHOP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_CHOP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_PA_CTL1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_PA_CTL2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_L_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_L_TEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_L_ATEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_R_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_R_TEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_R_ATEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_RDAC_CLK_CTL1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_RDAC_CLK_CTL2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_RDAC_LDO_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_REFBUFF_UHQA_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_REFBUFF_LP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_L_DAC_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_R_DAC_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS)] = RD_REG, + [WCD937X_REG(WCD937X_EAR_EAR_EN_REG)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_EAR_PA_CON)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_EAR_SP_CON)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_EAR_DAC_CON)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_EAR_CNP_FSM_CON)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_TEST_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_STATUS_REG_1)] = RD_REG, + [WCD937X_REG(WCD937X_EAR_STATUS_REG_2)] = RD_REG, + [WCD937X_REG(WCD937X_HPH_NEW_ANA_HPH2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_ANA_HPH3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_SLEEP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_SLEEP_WATCHDOG_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_CTL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_CTL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_PLUG_DETECT_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_ZDET_ANA_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_ZDET_RAMP_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_FSM_STATUS)] = RD_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_ADC_RESULT)] = RD_REG, + [WCD937X_REG(WCD937X_TX_NEW_TX_CH2_SEL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_AUXPA)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_MODE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_CONFIG)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIE_CRACK_DIE_CRK_DET_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIE_CRACK_DIE_CRK_DET_OUT)] = RD_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_VREF_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_PA_MISC1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_PA_MISC2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_PA_RDAC_MISC)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_HPH_TIMER4)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_PA_RDAC_MISC2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_HPH_NEW_INT_PA_RDAC_MISC3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL)] + = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT)] = RD_WR_REG, + [WCD937X_REG(WCD937X_MBHC_NEW_INT_SPARE_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_INT_NEW_CNP_VCM_CON1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_INT_NEW_CNP_VCM_CON2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_INT_EN_REG)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_INT_PA_CTRL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_INT_SP_CTRL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_INT_DAC_CTRL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_INT_CLK_CTRL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_INT_TEST_CTRL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_AUX_INT_STATUS_REG)] = RD_REG, + [WCD937X_REG(WCD937X_AUX_INT_MISC)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_INT_BIAS)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_INT_STB_LOADS_DTEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_INT_TEST0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_INT_STARTUP_TIMER)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_INT_TEST1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_LDORXTX_INT_STATUS)] = RD_REG, + [WCD937X_REG(WCD937X_SLEEP_INT_WATCHDOG_CTL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_SLEEP_INT_WATCHDOG_CTL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CHIP_ID0)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_CHIP_ID1)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_CHIP_ID2)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_CHIP_ID3)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_RST_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_TOP_CLK_CFG)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_ANA_CLK_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_DIG_CLK_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_RST_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_PATH_MODE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_RX_RST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_RX0_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_RX1_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_RX2_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DEM_BYPASS_DATA3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_COMP_CTL_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_RX_DELAY_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A1_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A1_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A2_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A2_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A3_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A3_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A4_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A4_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A5_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A5_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A6_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_A7_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_C_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R4)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R5)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R6)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_DSM_R7)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A1_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A1_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A2_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A2_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A3_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A3_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A4_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A4_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A5_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A5_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A6_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_A7_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_C_3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R3)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R4)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R5)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R6)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_DSM_R7)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_HPH_GAIN_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AUX_GAIN_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_EAR_PATH_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_SWR_CLH)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_CLH_BYP)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_TX0_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_TX1_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_TX2_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_TX_RST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_REQ_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_AMIC_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC1_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC2_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_DMIC3_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_PRG_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_TEST_CTL_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_TEST_CTL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_T_DATA_0)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_T_DATA_1)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_PDM_WD_CTL0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PDM_WD_CTL1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PDM_WD_CTL2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_MODE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_MASK_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_MASK_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_MASK_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_STATUS_0)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_STATUS_1)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_STATUS_2)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_CLEAR_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_CLEAR_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_CLEAR_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_LEVEL_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_LEVEL_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_LEVEL_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_SET_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_SET_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_SET_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_TEST_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_TEST_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_INTR_TEST_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_RX0_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_RX1_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_RX2_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_CDC_CONN_TX_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_LOOP_BACK_MODE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_DAC_TEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_RX_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_TX_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_RX_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST_TX_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SWR_HM_TEST)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_RX0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_RX1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_TX0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PAD_CTL_PDM_TX1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PAD_INP_DIS_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PAD_INP_DIS_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DRIVE_STRENGTH_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DRIVE_STRENGTH_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DRIVE_STRENGTH_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_RX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_TX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_GPIO_MODE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PIN_CTL_OE)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PIN_CTL_DATA_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PIN_CTL_DATA_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PIN_STATUS_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_PIN_STATUS_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DIG_DEBUG_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_DIG_DEBUG_EN)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_ANA_CSR_DBG_ADD)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_ANA_CSR_DBG_CTL)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SSP_DBG)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_MODE_STATUS_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_MODE_STATUS_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SPARE_0)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SPARE_1)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_SPARE_2)] = RD_WR_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_0)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_1)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_2)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_3)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_4)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_5)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_6)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_7)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_8)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_9)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_10)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_11)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_12)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_13)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_14)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_15)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_16)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_17)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_18)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_19)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_20)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_21)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_22)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_23)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_24)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_25)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_26)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_27)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_28)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_29)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_30)] = RD_REG, + [WCD937X_REG(WCD937X_DIGITAL_EFUSE_REG_31)] = RD_REG, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x.c new file mode 100644 index 0000000000..c3ac1523a1 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x.c @@ -0,0 +1,3647 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wcd937x-registers.h" +#include "wcd937x.h" +#include "internal.h" +#include "asoc/bolero-slave-internal.h" + +#define WCD9370_VARIANT 0 +#define WCD9375_VARIANT 5 +#define WCD937X_VARIANT_ENTRY_SIZE 32 + +#define NUM_SWRS_DT_PARAMS 5 + +#define WCD937X_VERSION_1_0 1 +#define WCD937X_VERSION_ENTRY_SIZE 32 +#define EAR_RX_PATH_AUX 1 + +#define NUM_ATTEMPTS 5 + +#define WCD937X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD937X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WCD937X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +enum { + CODEC_TX = 0, + CODEC_RX, +}; + +enum { + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, +}; + +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +static int wcd937x_handle_post_irq(void *data); +static int wcd937x_reset(struct device *dev); +static int wcd937x_reset_low(struct device *dev); + +static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(WCD937X_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(WCD937X_IRQ_EAR_SCD_INT, 1, 0x04), + REGMAP_IRQ_REG(WCD937X_IRQ_AUX_CNP_INT, 1, 0x08), + REGMAP_IRQ_REG(WCD937X_IRQ_AUX_SCD_INT, 1, 0x10), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(WCD937X_IRQ_AUX_PDM_WD_INT, 1, 0x80), + REGMAP_IRQ_REG(WCD937X_IRQ_LDORT_SCD_INT, 2, 0x01), + REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), +}; + +static struct regmap_irq_chip wcd937x_regmap_irq_chip = { + .name = "wcd937x", + .irqs = wcd937x_irqs, + .num_irqs = ARRAY_SIZE(wcd937x_irqs), + .num_regs = 3, + .status_base = WCD937X_DIGITAL_INTR_STATUS_0, + .mask_base = WCD937X_DIGITAL_INTR_MASK_0, + .ack_base = WCD937X_DIGITAL_INTR_CLEAR_0, + .use_ack = 1, + .clear_ack = 1, + .type_base = WCD937X_DIGITAL_INTR_LEVEL_0, + .runtime_pm = false, + .handle_post_irq = wcd937x_handle_post_irq, + .irq_drv_data = NULL, +}; + +static struct snd_soc_dai_driver wcd937x_dai[] = { + { + .name = "wcd937x_cdc", + .playback = { + .stream_name = "WCD937X_AIF Playback", + .rates = WCD937X_RATES | WCD937X_FRAC_RATES, + .formats = WCD937X_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .capture = { + .stream_name = "WCD937X_AIF Capture", + .rates = WCD937X_RATES, + .formats = WCD937X_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + }, +}; + +static int wcd937x_handle_post_irq(void *data) +{ + struct wcd937x_priv *wcd937x = data; + u32 status1 = 0, status2 = 0, status3 = 0; + + regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_0, &status1); + regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_1, &status2); + regmap_read(wcd937x->regmap, WCD937X_DIGITAL_INTR_STATUS_2, &status3); + + wcd937x->tx_swr_dev->slave_irq_pending = + ((status1 || status2 || status3) ? true : false); + + return IRQ_HANDLED; +} + +static int wcd937x_init_reg(struct snd_soc_component *component) +{ + u32 val = 0; + + val = snd_soc_component_read(component, WCD937X_DIGITAL_EFUSE_REG_29) + & 0x0F; + if (snd_soc_component_read(component, WCD937X_DIGITAL_EFUSE_REG_16) + == 0x02 || snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_17) > 0x09) { + snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL, + 0x0E, val); + } else { + snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL, + 0x0E, 0x0E); + } + snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL, + 0x80, 0x80); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, WCD937X_SLEEP_CTL, + 0x40, 0x40); + usleep_range(1000, 1010); + snd_soc_component_update_bits(component, WCD937X_LDORXTX_CONFIG, + 0x10, 0x00); + snd_soc_component_update_bits(component, WCD937X_BIAS_VBG_FINE_ADJ, + 0xF0, 0x80); + snd_soc_component_update_bits(component, WCD937X_ANA_BIAS, + 0x80, 0x80); + snd_soc_component_update_bits(component, WCD937X_ANA_BIAS, + 0x40, 0x40); + usleep_range(10000, 10010); + snd_soc_component_update_bits(component, WCD937X_ANA_BIAS, + 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD937X_HPH_SURGE_HPHLR_SURGE_EN, + 0xFF, 0xD9); + snd_soc_component_update_bits(component, WCD937X_MICB1_TEST_CTL_1, + 0xFF, 0xFA); + snd_soc_component_update_bits(component, WCD937X_MICB2_TEST_CTL_1, + 0xFF, 0xFA); + snd_soc_component_update_bits(component, WCD937X_MICB3_TEST_CTL_1, + 0xFF, 0xFA); + snd_soc_component_update_bits(component, WCD937X_MICB1_TEST_CTL_2, + 0x38, 0x00); + snd_soc_component_update_bits(component, WCD937X_MICB2_TEST_CTL_2, + 0x38, 0x00); + snd_soc_component_update_bits(component, WCD937X_MICB3_TEST_CTL_2, + 0x38, 0x00); + /* Set Bandgap Fine Adjustment to +5mV for Tanggu SMIC part */ + if (snd_soc_component_read(component, WCD937X_DIGITAL_EFUSE_REG_16) + == 0x01) { + snd_soc_component_update_bits(component, + WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0); + } else if (snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) { + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x1F, 0x04); + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x1F, 0x04); + snd_soc_component_update_bits(component, + WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0); + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xF0, 0x50); + } + return 0; +} + +static int wcd937x_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 = 0; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL; + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + switch (path) { + case CODEC_RX: + map = &wcd937x->rx_port_mapping; + num_ports = wcd937x->num_rx_ports; + break; + case CODEC_TX: + map = &wcd937x->tx_port_mapping; + num_ports = wcd937x->num_tx_ports; + break; + default: + dev_err(component->dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + for (i = 0; i <= num_ports; i++) { + for (j = 0; j < MAX_CH_PER_PORT; j++) { + if ((*map)[i][j].slave_port_type == slv_prt_type) + goto found; + } + } +found: + if (i > num_ports || j == MAX_CH_PER_PORT) { + dev_err(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; +} + +/* qcom,swr-tx-port-params = , , , ,*UC0* + , , , , *UC1* + , , , ; *UC2* + , , , ; *UC3 */ +static int wcd937x_parse_port_params(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, max_uc; + int ret = 0; + u32 cnt = 0; + u32 i, j; + struct swr_port_params (*map)[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config (*map_uc)[SWR_UC_MAX]; + struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); + + switch (path) { + case CODEC_TX: + map = &wcd937x->tx_port_params; + map_uc = &wcd937x->swr_tx_port_params; + break; + default: + ret = -EINVAL; + goto err_port_map; + } + + 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; + } + + max_uc = map_size / (SWR_NUM_PORTS * SWR_PORT_PARAMS * sizeof(u32)); + + if (max_uc != SWR_UC_MAX) { + dev_err(dev, "%s: port params not provided for all usecases\n", + __func__); + ret = -EINVAL; + goto err_port_map; + } + 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, + SWR_NUM_PORTS * SWR_PORT_PARAMS * max_uc); + 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 < max_uc; i++) { + for (j = 0; j < SWR_NUM_PORTS; j++) { + cnt = (i * SWR_NUM_PORTS + j) * SWR_PORT_PARAMS; + (*map)[i][j].offset1 = dt_array[cnt]; + (*map)[i][j].lane_ctrl = dt_array[cnt + 1]; + } + (*map_uc)[i].pp = &(*map)[i][0]; + } + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static int wcd937x_parse_port_mapping(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, map_length; + u32 port_num = 0, 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 = NULL; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL; + struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); + + switch (path) { + case CODEC_RX: + map = &wcd937x->rx_port_mapping; + num_ports = &wcd937x->num_rx_ports; + break; + case CODEC_TX: + map = &wcd937x->tx_port_mapping; + num_ports = &wcd937x->num_tx_ports; + break; + default: + dev_err(dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + if (!of_find_property(dev->of_node, prop, + &map_size)) { + dev_err(dev, "missing port mapping prop %s\n", prop); + ret = -EINVAL; + goto err; + } + + map_length = map_size / (NUM_SWRS_DT_PARAMS * sizeof(u32)); + + dt_array = kzalloc(map_size, GFP_KERNEL); + + if (!dt_array) { + ret = -ENOMEM; + goto err; + } + 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); + ret = -EINVAL; + goto err_pdata_fail; + } + + for (i = 0; i < map_length; i++) { + port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; + ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; + ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; + master_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 4]; + + if (port_num != old_port_num) + ch_iter = 0; + + (*map)[port_num][ch_iter].slave_port_type = slave_port_type; + (*map)[port_num][ch_iter].ch_mask = ch_mask; + (*map)[port_num][ch_iter].master_port_type = master_port_type; + (*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask); + (*map)[port_num][ch_iter++].ch_rate = ch_rate; + old_port_num = port_num; + } + *num_ports = port_num; + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err: + return ret; +} + +static int wcd937x_tx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + u8 port_id; + u8 num_ch; + u8 ch_mask; + u32 ch_rate; + u8 ch_type = 0; + int slave_ch_idx; + u8 num_port = 1; + int ret = 0; + + ret = wcd937x_set_port_params(component, slv_port_type, &port_id, + &num_ch, &ch_mask, &ch_rate, + &ch_type, CODEC_TX); + + if (ret) + return ret; + + slave_ch_idx = wcd937x_slave_get_slave_ch_val(slv_port_type); + if (slave_ch_idx != -EINVAL) + ch_type = wcd937x->tx_master_ch_map[slave_ch_idx]; + + dev_dbg(component->dev, "%s slv_ch_idx: %d, mstr_ch_type: %d\n", + __func__, slave_ch_idx, ch_type); + + if (enable) + ret = swr_connect_port(wcd937x->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &ch_type); + else + ret = swr_disconnect_port(wcd937x->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_type); + return ret; + +} +static int wcd937x_rx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + u8 port_id; + u8 num_ch; + u8 ch_mask; + u32 ch_rate; + u8 port_type; + u8 num_port = 1; + int ret = 0; + + ret = wcd937x_set_port_params(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(wcd937x->rx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + else + ret = swr_disconnect_port(wcd937x->rx_swr_dev, &port_id, + num_port, &ch_mask, &port_type); + return ret; +} + +static int wcd937x_rx_clk_enable(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (wcd937x->rx_clk_cnt == 0) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_RX0_CTL, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_RX1_CTL, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_RX2_CTL, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02); + } + wcd937x->rx_clk_cnt++; + + return 0; +} + +static int wcd937x_rx_clk_disable(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (wcd937x->rx_clk_cnt == 0) { + dev_dbg(wcd937x->dev, "%s:clk already disabled\n", __func__); + return 0; + } + wcd937x->rx_clk_cnt--; + if (wcd937x->rx_clk_cnt == 0) { + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + 0x01, 0x00); + } + return 0; +} + +/* + * wcd937x_soc_get_mbhc: get wcd937x_mbhc handle of corresponding component + * @component: handle to snd_soc_component * + * + * return wcd937x_mbhc handle or error code in case of failure + */ +struct wcd937x_mbhc *wcd937x_soc_get_mbhc(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x; + + if (!component) { + pr_err("%s: Invalid params, NULL component\n", __func__); + return NULL; + } + wcd937x = snd_soc_component_get_drvdata(component); + + if (!wcd937x) { + pr_err("%s: Invalid params, NULL tavil\n", __func__); + return NULL; + } + + return wcd937x->mbhc; +} +EXPORT_SYMBOL(wcd937x_soc_get_mbhc); + +static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD937X_HPH_RDAC_CLK_CTL1, + 0x80, 0x00); + set_bit(HPH_COMP_DELAY, &wcd937x->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if ((snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) && + ((snd_soc_component_read(component, + WCD937X_ANA_HPH) & 0x0C) == 0x0C)) + snd_soc_component_update_bits(component, + WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x90); + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0F, 0x02); + else if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0F, 0x06); + if (wcd937x->comp1_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD937X_HPH_L_EN, 0x20, 0x00); + if (wcd937x->comp2_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD937X_HPH_R_EN, 0x20, 0x00); + } + /* + * 5ms sleep is required after COMP is enabled as per + * HW requirement + */ + if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_COMP_DELAY, + &wcd937x->status_mask); + } + } else { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x00); + snd_soc_component_update_bits(component, + WCD937X_HPH_L_EN, 0x20, 0x20); + } + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + if ((snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) && + ((snd_soc_component_read(component, + WCD937X_ANA_HPH) & 0x0C) == 0x0C)) + snd_soc_component_update_bits(component, + WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x80); + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0F, 0x01); + break; + } + + return 0; +} + +static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD937X_HPH_RDAC_CLK_CTL1, 0x80, 0x00); + set_bit(HPH_COMP_DELAY, &wcd937x->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + if ((snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) && + ((snd_soc_component_read(component, + WCD937X_ANA_HPH) & 0x0C) == 0x0C)) + snd_soc_component_update_bits(component, + WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x90); + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0F, 0x02); + else if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0F, 0x06); + if (wcd937x->comp2_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD937X_HPH_R_EN, 0x20, 0x00); + if (wcd937x->comp1_enable) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD937X_HPH_L_EN, 0x20, 0x00); + } + /* + * 5ms sleep is required after COMP is enabled as per + * HW requirement + */ + if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_COMP_DELAY, + &wcd937x->status_mask); + } + } else { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD937X_HPH_R_EN, 0x20, 0x20); + } + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + if ((snd_soc_component_read(component, + WCD937X_DIGITAL_EFUSE_REG_16) == 0x02) && + ((snd_soc_component_read(component, + WCD937X_ANA_HPH) & 0x0C) == 0x0C)) + snd_soc_component_update_bits(component, + WCD937X_RX_BIAS_HPH_LOWPOWER, 0xF0, 0x80); + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, + 0x0F, 0x01); + break; + } + + return 0; +} + +static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + 0x01, 0x01); + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0F, 0x02); + else if (hph_mode == CLS_H_LOHIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0F, 0x06); + if (wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x02); + usleep_range(5000, 5010); + snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, + 0x04, 0x00); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + hph_mode); + + break; + case SND_SOC_DAPM_POST_PMD: + if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_HIFI) + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, + 0x0F, 0x01); + if (wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x00); + break; + }; + return 0; + +} + +static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_rx_clk_enable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_AUX_GAIN_CTL, + 0x01, 0x01); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_AUX, + hph_mode); + + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + 0x04, 0x00); + break; + }; + return 0; + +} + +static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int ret = 0; + int hph_mode = wcd937x->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(wcd937x->rx_swr_dev, + wcd937x->rx_swr_dev->dev_num, + true); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + hph_mode); + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + 0x10, 0x10); + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL1, 0x07, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (!wcd937x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10)); + wcd_enable_irq(&wcd937x->irq_info, + WCD937X_IRQ_HPHR_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd937x->irq_info, + WCD937X_IRQ_HPHR_PDM_WD_INT); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + blocking_notifier_call_chain(&wcd937x->mbhc->notifier, + WCD_EVENT_PRE_HPHR_PA_OFF, + &wcd937x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required after PA is disabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (!wcd937x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL1, 0x07, 0x00); + blocking_notifier_call_chain(&wcd937x->mbhc->notifier, + WCD_EVENT_POST_HPHR_PA_OFF, + &wcd937x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + 0x10, 0x00); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + hph_mode); + break; + }; + return ret; +} + +static int wcd937x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int ret = 0; + int hph_mode = wcd937x->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(wcd937x->rx_swr_dev, + wcd937x->rx_swr_dev->dev_num, + true); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + hph_mode); + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + 0x20, 0x20); + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x03); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (!wcd937x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + snd_soc_component_update_bits(component, + WCD937X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&wcd937x->irq_info, + WCD937X_IRQ_HPHL_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd937x->irq_info, + WCD937X_IRQ_HPHL_PDM_WD_INT); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + blocking_notifier_call_chain(&wcd937x->mbhc->notifier, + WCD_EVENT_PRE_HPHL_PA_OFF, + &wcd937x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required after PA is disabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (!wcd937x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x00); + blocking_notifier_call_chain(&wcd937x->mbhc->notifier, + WCD_EVENT_POST_HPHL_PA_OFF, + &wcd937x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + 0x20, 0x00); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + hph_mode); + break; + }; + return ret; +} + +static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->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(wcd937x->rx_swr_dev, + wcd937x->rx_swr_dev->dev_num, + true); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, 0x01, 0x01); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10)); + wcd_enable_irq(&wcd937x->irq_info, WCD937X_IRQ_AUX_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd937x->irq_info, WCD937X_IRQ_AUX_PDM_WD_INT); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10 | 0x1)); + break; + case SND_SOC_DAPM_POST_PMD: + /* Add delay as per hw requirement */ + usleep_range(2000, 2010); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_AUX, + hph_mode); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, 0x01, 0x00); + break; + }; + return ret; +} + +static int wcd937x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd937x->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(wcd937x->rx_swr_dev, + wcd937x->rx_swr_dev->dev_num, + true); + /* + * Enable watchdog interrupt for HPHL or AUX + * depending on mux value + */ + wcd937x->ear_rx_path = + snd_soc_component_read( + component, WCD937X_DIGITAL_CDC_EAR_PATH_CTL); + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, + 0x07, 0x03); + if (!wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_ANA_EAR_COMPANDER_CTL, 0x80, 0x80); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(6000, 6010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + wcd_enable_irq(&wcd937x->irq_info, + WCD937X_IRQ_AUX_PDM_WD_INT); + else + wcd_enable_irq(&wcd937x->irq_info, + WCD937X_IRQ_HPHL_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + wcd_disable_irq(&wcd937x->irq_info, + WCD937X_IRQ_AUX_PDM_WD_INT); + else + wcd_disable_irq(&wcd937x->irq_info, + WCD937X_IRQ_HPHL_PDM_WD_INT); + if (wcd937x->update_wcd_event) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + break; + case SND_SOC_DAPM_POST_PMD: + if (!wcd937x->comp1_enable) + snd_soc_component_update_bits(component, + WCD937X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00); + usleep_range(7000, 7010); + wcd_cls_h_fsm(component, &wcd937x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + hph_mode); + snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, + 0x04, 0x04); + if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL2, + 0x01, 0x00); + else + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_PDM_WD_CTL0, + 0x07, 0x00); + break; + }; + return ret; +} + +static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int mode = wcd937x->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) { + wcd937x_rx_connect_port(component, CLSH, + SND_SOC_DAPM_EVENT_ON(event)); + } + if (SND_SOC_DAPM_EVENT_OFF(event)) + ret = swr_slvdev_datapath_control( + wcd937x->rx_swr_dev, + wcd937x->rx_swr_dev->dev_num, + false); + return ret; +} + +static int wcd937x_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 wcd937x_priv *wcd937x = 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: + wcd937x_rx_connect_port(component, HPH_L, true); + if (wcd937x->comp1_enable) + wcd937x_rx_connect_port(component, COMP_L, true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_rx_connect_port(component, HPH_L, false); + if (wcd937x->comp1_enable) + wcd937x_rx_connect_port(component, COMP_L, false); + wcd937x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + 0x01, 0x00); + break; + }; + return 0; +} + +static int wcd937x_enable_rx2(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = 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: + wcd937x_rx_connect_port(component, HPH_R, true); + if (wcd937x->comp2_enable) + wcd937x_rx_connect_port(component, COMP_R, true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_rx_connect_port(component, HPH_R, false); + if (wcd937x->comp2_enable) + wcd937x_rx_connect_port(component, COMP_R, false); + wcd937x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + 0x02, 0x00); + break; + }; + + return 0; +} + +static int wcd937x_enable_rx3(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_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: + wcd937x_rx_connect_port(component, LO, true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_rx_connect_port(component, LO, false); + usleep_range(6000, 6010); + wcd937x_rx_clk_disable(component); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x00); + break; + } + return 0; + +} + +static int wcd937x_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = 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 = &(wcd937x->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC1_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(wcd937x->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC2_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd937x->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC3_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, + WCD937X_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); + ret = swr_slvdev_datapath_control(wcd937x->tx_swr_dev, + wcd937x->tx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_tx_connect_port(component, DMIC0 + (w->shift), false); + break; + + }; + return 0; +} + +/* + * wcd937x_get_micb_vout_ctl_val: converts micbias from volts to register value + * @micb_mv: micbias in mv + * + * return register value converted + */ +int wcd937x_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < 1000 || micb_mv > 2850) { + pr_err("%s: unsupported micbias voltage\n", __func__); + return -EINVAL; + } + + return (micb_mv - 1000) / 50; +} +EXPORT_SYMBOL(wcd937x_get_micb_vout_ctl_val); + +/* + * wcd937x_mbhc_micb_adjust_voltage: adjust specific micbias voltage + * @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 wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct wcd937x_priv *wcd937x = + 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 = WCD937X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD937X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD937X_ANA_MICB3; + break; + default: + return -EINVAL; + } + mutex_lock(&wcd937x->micb_lock); + + /* + * If requested micbias voltage is same as current micbias + * voltage, then just return. Otherwise, adjust voltage as + * per requested value. If micbias is already enabled, then + * to avoid slow micbias ramp-up or down enable pull-up + * momentarily, change the micbias value and then re-enable + * micbias. + */ + micb_val = snd_soc_component_read(component, micb_reg); + micb_en = (micb_val & 0xC0) >> 6; + cur_vout_ctl = micb_val & 0x3F; + + req_vout_ctl = wcd937x_get_micb_vout_ctl_val(req_volt); + if (req_vout_ctl < 0) { + ret = -EINVAL; + goto exit; + } + if (cur_vout_ctl == req_vout_ctl) { + ret = 0; + goto exit; + } + + dev_dbg(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(&wcd937x->micb_lock); + return ret; +} +EXPORT_SYMBOL(wcd937x_mbhc_micb_adjust_voltage); + +static int wcd937x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + /* Enable BCS for Headset mic */ + if (w->shift == 1 && !(snd_soc_component_read(component, + WCD937X_TX_NEW_TX_CH2_SEL) & 0x80)) { + if (!wcd937x->bcs_dis) { + wcd937x_tx_connect_port( + component, MBHC, true); + set_bit(AMIC2_BCS_ENABLE, + &wcd937x->status_mask); + } + } + wcd937x_tx_connect_port(component, ADC1 + (w->shift), true); + } else { + wcd937x_tx_connect_port(component, DMIC0 + (w->shift), true); + } + break; + case SND_SOC_DAPM_POST_PMD: + ret = swr_slvdev_datapath_control(wcd937x->tx_swr_dev, + wcd937x->tx_swr_dev->dev_num, + false); + break; + }; + + return ret; +} + +static int wcd937x_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event){ + + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd937x_priv *wcd937x = + 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: + mutex_lock(&wcd937x->ana_tx_clk_lock); + wcd937x->ana_clk_count++; + mutex_unlock(&wcd937x->ana_tx_clk_lock); + wcd937x->adc_count++; + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + ret = swr_slvdev_datapath_control(wcd937x->tx_swr_dev, + wcd937x->tx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_tx_connect_port(component, ADC1 + (w->shift), false); + if (w->shift == 1 && + test_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask)) { + wcd937x_tx_connect_port(component, MBHC, false); + clear_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask); + } + + wcd937x->adc_count--; + if (wcd937x->adc_count <= 0) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00); + wcd937x->adc_count = 0; + } + break; + }; + + return ret; +} + +static int wcd937x_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); + struct wcd937x_priv *wcd937x = + 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: + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, 0x40, 0x40); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3_HPF, 0x40, 0x40); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x70, 0x70); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH1, 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, 0x40, 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, 0x80, 0x80); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3, 0x80, 0x80); + break; + case SND_SOC_DAPM_POST_PMD: + if (wcd937x->adc_count == 0) { + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH1, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH2, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00); + } + + mutex_lock(&wcd937x->ana_tx_clk_lock); + wcd937x->ana_clk_count--; + if (wcd937x->ana_clk_count <= 0) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); + wcd937x->ana_clk_count = 0; + } + + mutex_unlock(&wcd937x->ana_tx_clk_lock); + break; + }; + return 0; +} + +int wcd937x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + + struct wcd937x_priv *wcd937x = 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 > WCD937X_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 = WCD937X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD937X_ANA_MICB2; + pre_off_event = WCD_EVENT_PRE_MICBIAS_2_OFF; + post_off_event = WCD_EVENT_POST_MICBIAS_2_OFF; + post_on_event = WCD_EVENT_POST_MICBIAS_2_ON; + post_dapm_on = WCD_EVENT_POST_DAPM_MICBIAS_2_ON; + post_dapm_off = WCD_EVENT_POST_DAPM_MICBIAS_2_OFF; + break; + case MIC_BIAS_3: + micb_reg = WCD937X_ANA_MICB3; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + }; + mutex_lock(&wcd937x->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd937x->pullup_ref[micb_index]++; + if ((wcd937x->pullup_ref[micb_index] == 1) && + (wcd937x->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + if (wcd937x->pullup_ref[micb_index] > 0) + wcd937x->pullup_ref[micb_index]--; + if ((wcd937x->pullup_ref[micb_index] == 0) && + (wcd937x->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + wcd937x->micb_ref[micb_index]++; + mutex_lock(&wcd937x->ana_tx_clk_lock); + wcd937x->ana_clk_count++; + mutex_unlock(&wcd937x->ana_tx_clk_lock); + if (wcd937x->micb_ref[micb_index] == 1) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0xF0, 0xF0); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD937X_MICB1_TEST_CTL_2, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD937X_MICB2_TEST_CTL_2, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD937X_MICB3_TEST_CTL_2, 0x01, 0x01); + snd_soc_component_update_bits(component, + micb_reg, 0xC0, 0x40); + if (post_on_event) + blocking_notifier_call_chain( + &wcd937x->mbhc->notifier, post_on_event, + &wcd937x->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_on && wcd937x->mbhc) + blocking_notifier_call_chain( + &wcd937x->mbhc->notifier, post_dapm_on, + &wcd937x->mbhc->wcd_mbhc); + break; + case MICB_DISABLE: + mutex_lock(&wcd937x->ana_tx_clk_lock); + wcd937x->ana_clk_count--; + mutex_unlock(&wcd937x->ana_tx_clk_lock); + if (wcd937x->micb_ref[micb_index] > 0) + wcd937x->micb_ref[micb_index]--; + if ((wcd937x->micb_ref[micb_index] == 0) && + (wcd937x->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((wcd937x->micb_ref[micb_index] == 0) && + (wcd937x->pullup_ref[micb_index] == 0)) { + if (pre_off_event && wcd937x->mbhc) + blocking_notifier_call_chain( + &wcd937x->mbhc->notifier, pre_off_event, + &wcd937x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + if (post_off_event && wcd937x->mbhc) + blocking_notifier_call_chain( + &wcd937x->mbhc->notifier, + post_off_event, + &wcd937x->mbhc->wcd_mbhc); + } + mutex_lock(&wcd937x->ana_tx_clk_lock); + if (wcd937x->ana_clk_count <= 0) { + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + 0x10, 0x00); + wcd937x->ana_clk_count = 0; + } + mutex_unlock(&wcd937x->ana_tx_clk_lock); + if (is_dapm && post_dapm_off && wcd937x->mbhc) + blocking_notifier_call_chain( + &wcd937x->mbhc->notifier, post_dapm_off, + &wcd937x->mbhc->wcd_mbhc); + break; + }; + + dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, wcd937x->micb_ref[micb_index], + wcd937x->pullup_ref[micb_index]); + mutex_unlock(&wcd937x->micb_lock); + + return 0; +} +EXPORT_SYMBOL(wcd937x_micbias_control); + +void wcd937x_disable_bcs_before_slow_insert(struct snd_soc_component *component, + bool bcs_disable) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (wcd937x->update_wcd_event) { + if (bcs_disable) + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 0); + else + wcd937x->update_wcd_event(wcd937x->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 1); + } +} + +static int wcd937x_get_logical_addr(struct swr_device *swr_dev) +{ + int ret = 0; + uint8_t devnum = 0; + int num_retry = NUM_ATTEMPTS; + + do { + 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); + /* retry after 1ms */ + usleep_range(1000, 1010); + } + } while (ret && --num_retry); + swr_dev->dev_num = devnum; + return 0; +} + +static bool get_usbc_hs_status(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + if (mbhc_cfg->enable_usbc_analog) { + if (!(snd_soc_component_read(component, WCD937X_ANA_MBHC_MECH) + & 0x20)) + return true; + } + return false; +} + +static int wcd937x_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + u16 amic = (val >> 0x10); + u16 mask = 0x40, reg = 0x0; + int ret = 0; + struct wcd937x_priv *wcd937x = dev_get_drvdata((struct device *)data); + struct snd_soc_component *component = wcd937x->component; + struct wcd_mbhc *mbhc; + + switch (event) { + case BOLERO_SLV_EVT_TX_CH_HOLD_CLEAR: + if (amic == 0x1 || amic == 0x2) + reg = WCD937X_ANA_TX_CH2; + else if (amic == 0x3) + reg = WCD937X_ANA_TX_CH3_HPF; + else + return 0; + if (amic == 0x2) + mask = 0x20; + snd_soc_component_update_bits(component, reg, mask, 0x00); + break; + case BOLERO_SLV_EVT_PA_OFF_PRE_SSR: + snd_soc_component_update_bits(component, WCD937X_ANA_HPH, + 0xC0, 0x00); + snd_soc_component_update_bits(component, WCD937X_ANA_EAR, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD937X_AUX_AUXPA, + 0x80, 0x00); + break; + case BOLERO_SLV_EVT_SSR_DOWN: + wcd937x->mbhc->wcd_mbhc.deinit_in_progress = true; + mbhc = &wcd937x->mbhc->wcd_mbhc; + wcd937x->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); + wcd937x_mbhc_ssr_down(wcd937x->mbhc, component); + wcd937x_reset_low(wcd937x->dev); + break; + case BOLERO_SLV_EVT_SSR_UP: + wcd937x_reset(wcd937x->dev); + /* allow reset to take effect */ + usleep_range(10000, 10010); + wcd937x_get_logical_addr(wcd937x->tx_swr_dev); + wcd937x_get_logical_addr(wcd937x->rx_swr_dev); + wcd937x_init_reg(component); + regcache_mark_dirty(wcd937x->regmap); + regcache_sync(wcd937x->regmap); + /* Initialize MBHC module */ + mbhc = &wcd937x->mbhc->wcd_mbhc; + ret = wcd937x_mbhc_post_ssr_init(wcd937x->mbhc, component); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + } else { + wcd937x_mbhc_hs_detect(component, mbhc->mbhc_cfg); + if (wcd937x->usbc_hs_status) + mdelay(500); + } + wcd937x->mbhc->wcd_mbhc.deinit_in_progress = false; + break; + case BOLERO_SLV_EVT_CLK_NOTIFY: + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_TOP_CLK_CFG, 0x06, + ((val >> 0x10) << 0x01)); + break; + default: + dev_err(component->dev, "%s: invalid event %d\n", __func__, + event); + break; + } + return 0; +} + +static int __wcd937x_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 + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_micbias_control(component, micb_num, + MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd937x_micbias_control(component, micb_num, + MICB_DISABLE, true); + break; + }; + + return 0; + +} + +static int wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd937x_codec_enable_micbias(w, event); +} + +static int __wcd937x_codec_enable_micbias_pullup(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, "VA MIC BIAS1", sizeof("VA MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd937x_micbias_control(component, micb_num, + MICB_PULLUP_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: + wcd937x_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + break; + }; + + return 0; + +} + +static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd937x_codec_enable_micbias_pullup(w, event); +} + +static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd937x->hph_mode; + return 0; +} + +static int wcd937x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = 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_warn(component->dev, "%s:Invalid HPH Mode, default to class_AB\n", + __func__); + mode_val = 3; /* enum will be updated later */ + } + wcd937x->hph_mode = mode_val; + return 0; +} + +static int wcd937x_tx_ch_pwr_level_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (strnstr(kcontrol->id.name, "CH1", sizeof(kcontrol->id.name))) + ucontrol->value.integer.value[0] = wcd937x->tx_ch_pwr[0]; + else if (strnstr(kcontrol->id.name, "CH3", sizeof(kcontrol->id.name))) + ucontrol->value.integer.value[0] = wcd937x->tx_ch_pwr[1]; + + return 0; +} + +static int wcd937x_tx_ch_pwr_level_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + u32 pwr_level = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: tx ch pwr_level: %d\n", + __func__, pwr_level); + + if (strnstr(kcontrol->id.name, "CH1", + sizeof(kcontrol->id.name))) { + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH1, 0x60, + pwr_level << 0x5); + wcd937x->tx_ch_pwr[0] = pwr_level; + } else if (strnstr(kcontrol->id.name, "CH3", + sizeof(kcontrol->id.name))) { + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3, 0x60, + pwr_level << 0x5); + wcd937x->tx_ch_pwr[1] = pwr_level; + } + return 0; +} + +static int wcd937x_ear_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ear_pa_gain = snd_soc_component_read(component, + WCD937X_ANA_EAR_COMPANDER_CTL); + + ear_pa_gain = (ear_pa_gain & 0x7C) >> 2; + + ucontrol->value.integer.value[0] = ear_pa_gain; + + dev_dbg(component->dev, "%s: ear_pa_gain = 0x%x\n", __func__, + ear_pa_gain); + + return 0; +} + +static int wcd937x_ear_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + ear_pa_gain = ucontrol->value.integer.value[0] << 2; + + if (!wcd937x->comp1_enable) { + snd_soc_component_update_bits(component, + WCD937X_ANA_EAR_COMPANDER_CTL, + 0x7C, ear_pa_gain); + } + + return 0; +} + +/* wcd937x_codec_get_dev_num - returns swr device number + * @component: Codec instance + * + * Return: swr device number on success or negative error + * code on failure. + */ +int wcd937x_codec_get_dev_num(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x; + + if (!component) + return -EINVAL; + + wcd937x = snd_soc_component_get_drvdata(component); + if (!wcd937x || !wcd937x->rx_swr_dev) { + pr_err("%s: wcd937x component is NULL\n", __func__); + return -EINVAL; + } + + return wcd937x->rx_swr_dev->dev_num; +} +EXPORT_SYMBOL_GPL(wcd937x_codec_get_dev_num); + +static int wcd937x_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = 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 ? wcd937x->comp2_enable : + wcd937x->comp1_enable; + return 0; +} + +static int wcd937x_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = 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) + wcd937x->comp2_enable = value; + else + wcd937x->comp1_enable = value; + + return 0; +} + +static int wcd937x_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + struct wcd937x_pdata *pdata = NULL; + int ret = 0; + + pdata = dev_get_platdata(wcd937x->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: + if (test_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask)) { + dev_dbg(component->dev, + "%s: buck already in enabled state\n", + __func__); + clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + return 0; + } + ret = msm_cdc_enable_ondemand_supply(wcd937x->dev, + wcd937x->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; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + /* + * 200us sleep is required after LDO15 is enabled as per + * HW requirement + */ + usleep_range(200, 250); + break; + case SND_SOC_DAPM_POST_PMD: + set_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + break; + } + 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", +}; + +const char * const tx_master_ch_text[] = { + "ZERO", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", "SWRM_TX1_CH4", + "SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", "SWRM_TX2_CH4", + "SWRM_TX3_CH1", "SWRM_TX3_CH2", "SWRM_TX3_CH3", "SWRM_TX3_CH4", + "SWRM_TX_PCM_IN", +}; + +const struct soc_enum tx_master_ch_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_master_ch_text), + tx_master_ch_text); + +static void wcd937x_tx_get_slave_ch_type_idx(const char *wname, int *ch_idx) +{ + u8 ch_type = 0; + + if (strnstr(wname, "ADC1", sizeof("ADC1"))) + ch_type = ADC1; + else if (strnstr(wname, "ADC2", sizeof("ADC2"))) + ch_type = ADC2; + else if (strnstr(wname, "ADC3", sizeof("ADC3"))) + ch_type = ADC3; + else if (strnstr(wname, "DMIC0", sizeof("DMIC0"))) + ch_type = DMIC0; + else if (strnstr(wname, "DMIC1", sizeof("DMIC1"))) + ch_type = DMIC1; + else if (strnstr(wname, "MBHC", sizeof("MBHC"))) + ch_type = MBHC; + else if (strnstr(wname, "DMIC2", sizeof("DMIC2"))) + ch_type = DMIC2; + else if (strnstr(wname, "DMIC3", sizeof("DMIC3"))) + ch_type = DMIC3; + else if (strnstr(wname, "DMIC4", sizeof("DMIC4"))) + ch_type = DMIC4; + else if (strnstr(wname, "DMIC5", sizeof("DMIC5"))) + ch_type = DMIC5; + else + pr_err("%s: ch name: %s is not listed\n", __func__, wname); + + if (ch_type) + *ch_idx = wcd937x_slave_get_slave_ch_val(ch_type); + else + *ch_idx = -EINVAL; +} + +static int wcd937x_tx_master_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = NULL; + int slave_ch_idx = -EINVAL; + + if (component == NULL) + return -EINVAL; + + wcd937x = snd_soc_component_get_drvdata(component); + if (wcd937x == NULL) + return -EINVAL; + + wcd937x_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + + if (slave_ch_idx < 0 || slave_ch_idx >= WCD937X_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + ucontrol->value.integer.value[0] = + wcd937x_slave_get_master_ch_val( + wcd937x->tx_master_ch_map[slave_ch_idx]); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int wcd937x_tx_master_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x; + int slave_ch_idx = -EINVAL, idx = 0; + + if (component == NULL) + return -EINVAL; + + wcd937x = snd_soc_component_get_drvdata(component); + if (wcd937x == NULL) + return -EINVAL; + + wcd937x_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + + if (slave_ch_idx < 0 || slave_ch_idx >= WCD937X_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + dev_dbg(component->dev, "%s: slave_ch_idx: %d", __func__, slave_ch_idx); + dev_dbg(component->dev, "%s: ucontrol->value.enumerated.item[0] = %ld\n", + __func__, ucontrol->value.enumerated.item[0]); + + idx = ucontrol->value.enumerated.item[0]; + if (idx < 0 || idx >= ARRAY_SIZE(wcd937x_swr_master_ch_map)) + return -EINVAL; + + wcd937x->tx_master_ch_map[slave_ch_idx] = + wcd937x_slave_get_master_ch(idx); + + return 0; +} + +static int wcd937x_bcs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd937x->bcs_dis; + return 0; +} + +static int wcd937x_bcs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + wcd937x->bcs_dis = ucontrol->value.integer.value[0]; + dev_dbg(component->dev, "%s: BCS Disable %d\n", __func__, wcd937x->bcs_dis); + return 0; +} + +static const char * const wcd937x_tx_ch_pwr_level_text[] = { + "L0", "L1", "L2", "L3", +}; + +static const char * const wcd937x_ear_pa_gain_text[] = { + "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", "G_0_DB", + "G_M1P5_DB", "G_M3_DB", "G_M4P5_DB", + "G_M6_DB", "G_7P5_DB", "G_M9_DB", + "G_M10P5_DB", "G_M12_DB", "G_M13P5_DB", + "G_M15_DB", "G_M16P5_DB", "G_M18_DB", +}; + +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 SOC_ENUM_SINGLE_EXT_DECL(wcd937x_ear_pa_gain_enum, + wcd937x_ear_pa_gain_text); + +static SOC_ENUM_SINGLE_EXT_DECL(wcd937x_tx_ch_pwr_level_enum, + wcd937x_tx_ch_pwr_level_text); + +static const struct snd_kcontrol_new wcd937x_snd_controls[] = { + SOC_ENUM_EXT("EAR PA GAIN", wcd937x_ear_pa_gain_enum, + wcd937x_ear_pa_gain_get, wcd937x_ear_pa_gain_put), + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd937x_rx_hph_mode_get, wcd937x_rx_hph_mode_put), + SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0, + wcd937x_get_compander, wcd937x_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0, + wcd937x_get_compander, wcd937x_set_compander), + SOC_SINGLE_EXT("ADC2_BCS Disable", SND_SOC_NOPM, 0, 1, 0, + wcd937x_bcs_get, wcd937x_bcs_put), + + SOC_SINGLE_TLV("HPHL Volume", WCD937X_HPH_L_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD937X_HPH_R_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("ADC1 Volume", WCD937X_ANA_TX_CH1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD937X_ANA_TX_CH2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD937X_ANA_TX_CH3, 0, 20, 0, + analog_gain), + SOC_ENUM_EXT("ADC1 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("ADC2 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("ADC3 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC0 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC1 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("MBHC ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC2 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC3 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC4 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC5 ChMap", tx_master_ch_enum, + wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("TX CH1 PWR", wcd937x_tx_ch_pwr_level_enum, + wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put), + SOC_ENUM_EXT("TX CH3 PWR", wcd937x_tx_ch_pwr_level_enum, + wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put), +}; + +static const struct snd_kcontrol_new adc1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic6_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new ear_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new aux_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphl_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphr_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const char * const adc2_mux_text[] = { + "INP2", "INP3" +}; + +static const char * const rdac3_mux_text[] = { + "RX1", "RX3" +}; + +static const struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD937X_TX_NEW_TX_CH2_SEL, 7, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + + +static const struct soc_enum rdac3_enum = + SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0, + ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); + +static const struct snd_kcontrol_new tx_adc2_mux = + SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); + +static const struct snd_kcontrol_new rx_rdac3_mux = + SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); + +static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { + + /*input widgets*/ + + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_AUX"), + + /* + * These dummy widgets are null connected to WCD937x dapm input and + * output widgets which are not actual path endpoints. This ensures + * dapm doesnt set these dapm input and output widgets as endpoints. + */ + SND_SOC_DAPM_INPUT("WCD_TX_DUMMY"), + SND_SOC_DAPM_OUTPUT("WCD_RX_DUMMY"), + + /*tx widgets*/ + SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, + wcd937x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd937x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd937x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, + &tx_adc2_mux), + + /*tx mixers*/ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, + adc1_switch, ARRAY_SIZE(adc1_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 1, 0, + adc2_switch, ARRAY_SIZE(adc2_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* micbias widgets*/ + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, + wcd937x_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, + wcd937x_enable_clsh, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /*rx widgets*/ + SND_SOC_DAPM_PGA_E("EAR PGA", WCD937X_ANA_EAR, 7, 0, NULL, 0, + wcd937x_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AUX PGA", WCD937X_AUX_AUXPA, 7, 0, NULL, 0, + wcd937x_codec_enable_aux_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", WCD937X_ANA_HPH, 7, 0, NULL, 0, + wcd937x_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", WCD937X_ANA_HPH, 6, 0, NULL, 0, + wcd937x_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_aux_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), + + SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd937x_enable_rx1, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd937x_enable_rx2, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd937x_enable_rx3, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* rx mixer widgets*/ + + SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, + ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), + SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0, + aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, + hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, + hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), + + /*output widgets tx*/ + + SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("WCD_TX_OUTPUT"), + + /*output widgets rx*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("AUX"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + + /* micbias pull up widgets*/ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + +}; + +static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = { + + /*input widgets*/ + SND_SOC_DAPM_INPUT("AMIC4"), + + /*tx widgets*/ + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, + wcd937x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd937x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, + wcd937x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /*tx mixer widgets*/ + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, + 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 1, + 0, dmic2_switch, ARRAY_SIZE(dmic2_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 2, + 0, dmic3_switch, ARRAY_SIZE(dmic3_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 3, + 0, dmic4_switch, ARRAY_SIZE(dmic4_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 4, + 0, dmic5_switch, ARRAY_SIZE(dmic5_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 5, + 0, dmic6_switch, ARRAY_SIZE(dmic6_switch), + wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 2, 0, adc3_switch, + ARRAY_SIZE(adc3_switch), wcd937x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /*output widgets*/ + SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), + +}; + +static const struct snd_soc_dapm_route wcd937x_audio_map[] = { + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, + {"WCD_TX_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1 REQ"}, + {"ADC1 REQ", NULL, "ADC1"}, + {"ADC1", NULL, "AMIC1"}, + + {"WCD_TX_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"}, + + {"IN1_HPHL", NULL, "WCD_RX_DUMMY"}, + {"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, "WCD_RX_DUMMY"}, + {"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, "WCD_RX_DUMMY"}, + {"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 const struct snd_soc_dapm_route wcd9375_audio_map[] = { + + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, + {"WCD_TX_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_MIXER", "Switch", "ADC3 REQ"}, + {"ADC3 REQ", NULL, "ADC3"}, + {"ADC3", NULL, "AMIC4"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_MIXER", "Switch", "DMIC3"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_MIXER", "Switch", "DMIC4"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_MIXER", "Switch", "DMIC5"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_MIXER", "Switch", "DMIC6"}, + +}; + +static ssize_t wcd937x_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct wcd937x_priv *priv; + char buffer[WCD937X_VERSION_ENTRY_SIZE]; + int len = 0; + + priv = (struct wcd937x_priv *) entry->private_data; + if (!priv) { + pr_err("%s: wcd937x priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->version) { + case WCD937X_VERSION_1_0: + len = snprintf(buffer, sizeof(buffer), "WCD937X_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 wcd937x_info_ops = { + .read = wcd937x_version_read, +}; + +static ssize_t wcd937x_variant_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct wcd937x_priv *priv; + char buffer[WCD937X_VARIANT_ENTRY_SIZE]; + int len = 0; + + priv = (struct wcd937x_priv *) entry->private_data; + if (!priv) { + pr_err("%s: wcd937x priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->variant) { + case WCD9370_VARIANT: + len = snprintf(buffer, sizeof(buffer), "WCD9370\n"); + break; + case WCD9375_VARIANT: + len = snprintf(buffer, sizeof(buffer), "WCD9375\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 wcd937x_variant_ops = { + .read = wcd937x_variant_read, +}; + +/* + * wcd937x_get_codec_variant + * @component: component instance + * + * Return: codec variant or -EINVAL in error. + */ +int wcd937x_get_codec_variant(struct snd_soc_component *component) +{ + struct wcd937x_priv *priv = NULL; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) { + dev_err(component->dev, + "%s:wcd937x not probed\n", __func__); + return 0; + } + + return priv->variant; +} +EXPORT_SYMBOL_GPL(wcd937x_get_codec_variant); + +/* + * wcd937x_info_create_codec_entry - creates wcd937x module + * @codec_root: The parent directory + * @component: component instance + * + * Creates wcd937x module, variant and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int wcd937x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct snd_info_entry *variant_entry; + struct wcd937x_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:wcd937x module already created\n", __func__); + return 0; + } + card = component->card; + priv->entry = snd_info_create_module_entry(codec_root->module, + "wcd937x", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create wcd937x entry\n", + __func__); + return -ENOMEM; + } + priv->entry->mode = S_IFDIR | 0555; + if (snd_info_register(priv->entry) < 0) { + snd_info_free_entry(priv->entry); + 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 wcd937x version entry\n", + __func__); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + version_entry->private_data = priv; + version_entry->size = WCD937X_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &wcd937x_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->version_entry = version_entry; + + variant_entry = snd_info_create_card_entry(card->snd_card, + "variant", + priv->entry); + if (!variant_entry) { + dev_dbg(component->dev, + "%s: failed to create wcd937x variant entry\n", + __func__); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + variant_entry->private_data = priv; + variant_entry->size = WCD937X_VARIANT_ENTRY_SIZE; + variant_entry->content = SNDRV_INFO_CONTENT_DATA; + variant_entry->c.ops = &wcd937x_variant_ops; + + if (snd_info_register(variant_entry) < 0) { + snd_info_free_entry(variant_entry); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->variant_entry = variant_entry; + return 0; +} +EXPORT_SYMBOL(wcd937x_info_create_codec_entry); + +static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x, + struct wcd937x_pdata *pdata) +{ + int vout_ctl_1 = 0, vout_ctl_2 = 0, vout_ctl_3 = 0; + int rc = 0; + + if (!pdata) { + dev_err(wcd937x->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl_1 = wcd937x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + vout_ctl_2 = wcd937x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv); + vout_ctl_3 = wcd937x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0) { + rc = -EINVAL; + goto done; + } + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB1, 0x3F, + vout_ctl_1); + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB2, 0x3F, + vout_ctl_2); + regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB3, 0x3F, + vout_ctl_3); + +done: + return rc; +} + +static int wcd937x_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int variant; + int ret = -EINVAL; + + dev_info(component->dev, "%s()\n", __func__); + wcd937x = snd_soc_component_get_drvdata(component); + + if (!wcd937x) + return -EINVAL; + + wcd937x->component = component; + snd_soc_component_init_regmap(component, wcd937x->regmap); + + devm_regmap_qti_debugfs_register(&wcd937x->tx_swr_dev->dev, wcd937x->regmap); + + variant = (snd_soc_component_read( + component, WCD937X_DIGITAL_EFUSE_REG_0) & 0x1E) >> 1; + wcd937x->variant = variant; + + wcd937x->adc_count = 0; + + wcd937x->fw_data = devm_kzalloc(component->dev, + sizeof(*(wcd937x->fw_data)), + GFP_KERNEL); + if (!wcd937x->fw_data) { + dev_err(component->dev, "Failed to allocate fw_data\n"); + ret = -ENOMEM; + goto err; + } + + set_bit(WCD9XXX_MBHC_CAL, wcd937x->fw_data->cal_bit); + ret = wcd_cal_create_hwdep(wcd937x->fw_data, + WCD9XXX_CODEC_HWDEP_NODE, component); + + if (ret < 0) { + dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret); + goto err_hwdep; + } + + ret = wcd937x_mbhc_init(&wcd937x->mbhc, component, wcd937x->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, "IN1_HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "IN2_HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "IN3_AUX"); + snd_soc_dapm_ignore_suspend(dapm, "ADC1_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ADC2_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "AUX"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_DUMMY"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_RX_DUMMY"); + snd_soc_dapm_sync(dapm); + + wcd_cls_h_init(&wcd937x->clsh_info); + wcd937x_init_reg(component); + + if (wcd937x->variant == WCD9375_VARIANT) { + ret = snd_soc_dapm_new_controls(dapm, wcd9375_dapm_widgets, + ARRAY_SIZE(wcd9375_dapm_widgets)); + if (ret < 0) { + dev_err(component->dev, "%s: Failed to add snd_ctls\n", + __func__); + goto err_hwdep; + } + ret = snd_soc_dapm_add_routes(dapm, wcd9375_audio_map, + ARRAY_SIZE(wcd9375_audio_map)); + if (ret < 0) { + dev_err(component->dev, "%s: Failed to add routes\n", + __func__); + goto err_hwdep; + } + snd_soc_dapm_ignore_suspend(dapm, "AMIC4"); + 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, "ADC3_OUTPUT"); + snd_soc_dapm_sync(dapm); + } + wcd937x->version = WCD937X_VERSION_1_0; + /* Register event notifier */ + wcd937x->nblock.notifier_call = wcd937x_event_notify; + if (wcd937x->register_notifier) { + ret = wcd937x->register_notifier(wcd937x->handle, + &wcd937x->nblock, + true); + if (ret) { + dev_err(component->dev, + "%s: Failed to register notifier %d\n", + __func__, ret); + return ret; + } + } + return ret; + +err_hwdep: + wcd937x->fw_data = NULL; + +err: + return ret; +} + +static void wcd937x_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (!wcd937x) + return; + + if (wcd937x->register_notifier) + wcd937x->register_notifier(wcd937x->handle, + &wcd937x->nblock, + false); + return; +} + +static const struct snd_soc_component_driver soc_codec_dev_wcd937x = { + .name = WCD937X_DRV_NAME, + .probe = wcd937x_soc_codec_probe, + .remove = wcd937x_soc_codec_remove, + .controls = wcd937x_snd_controls, + .num_controls = ARRAY_SIZE(wcd937x_snd_controls), + .dapm_widgets = wcd937x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets), + .dapm_routes = wcd937x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd937x_audio_map), +}; + +#ifdef CONFIG_PM_SLEEP +static int wcd937x_suspend(struct device *dev) +{ + struct wcd937x_priv *wcd937x = NULL; + int ret = 0; + struct wcd937x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd937x = dev_get_drvdata(dev); + if (!wcd937x) + return -EINVAL; + + pdata = dev_get_platdata(wcd937x->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask)) { + ret = msm_cdc_disable_ondemand_supply(wcd937x->dev, + wcd937x->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; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + } + return 0; +} + +static int wcd937x_resume(struct device *dev) +{ + return 0; +} +#endif + +static int wcd937x_reset(struct device *dev) +{ + struct wcd937x_priv *wcd937x = NULL; + int rc = 0; + int value = 0; + + if (!dev) + return -ENODEV; + + wcd937x = dev_get_drvdata(dev); + if (!wcd937x) + return -EINVAL; + + if (!wcd937x->rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + value = msm_cdc_pinctrl_get_state(wcd937x->rst_np); + if (value > 0) + return 0; + + rc = msm_cdc_pinctrl_select_sleep_state(wcd937x->rst_np); + if (rc) { + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 20ms sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + + rc = msm_cdc_pinctrl_select_active_state(wcd937x->rst_np); + if (rc) { + dev_err(dev, "%s: wcd active state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 20ms sleep required after pulling the reset gpio to HIGH */ + usleep_range(20, 30); + + return rc; +} + +static int wcd937x_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 wcd937x_dt_parse_micbias_info(struct device *dev, + struct wcd937x_micbias_setting *mb) +{ + u32 prop_val = 0; + int rc = 0; + + /* MB1 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv", + NULL)) { + rc = wcd937x_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 = wcd937x_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 = wcd937x_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 wcd937x_reset_low(struct device *dev) +{ + struct wcd937x_priv *wcd937x = NULL; + int rc = 0; + + if (!dev) + return -ENODEV; + + wcd937x = dev_get_drvdata(dev); + if (!wcd937x) + return -EINVAL; + + if (!wcd937x->rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + rc = msm_cdc_pinctrl_select_sleep_state(wcd937x->rst_np); + if (rc) { + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + return rc; + } + /* 20ms sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + + return rc; +} + +struct wcd937x_pdata *wcd937x_populate_dt_data(struct device *dev) +{ + struct wcd937x_pdata *pdata = NULL; + + pdata = kzalloc(sizeof(struct wcd937x_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-slave", 0); + pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0); + wcd937x_dt_parse_micbias_info(dev, &pdata->micbias); + + return pdata; +} + +static int wcd937x_wakeup(void *handle, bool enable) +{ + struct wcd937x_priv *priv; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + priv = (struct wcd937x_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 irqreturn_t wcd937x_wd_handle_irq(int irq, void *data) +{ + pr_err_ratelimited("%s: Watchdog interrupt for irq =%d triggered\n", + __func__, irq); + return IRQ_HANDLED; +} + +static int wcd937x_bind(struct device *dev) +{ + int ret = 0, i = 0; + struct wcd937x_priv *wcd937x = NULL; + struct wcd937x_pdata *pdata = NULL; + struct wcd_ctrl_platform_data *plat_data = NULL; + + wcd937x = kzalloc(sizeof(struct wcd937x_priv), GFP_KERNEL); + if (!wcd937x) + return -ENOMEM; + + dev_set_drvdata(dev, wcd937x); + + pdata = wcd937x_populate_dt_data(dev); + if (!pdata) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); + ret = -EINVAL; + goto err_pdata; + } + wcd937x->dev = dev; + wcd937x->dev->platform_data = pdata; + wcd937x->rst_np = pdata->rst_np; + ret = msm_cdc_init_supplies(dev, &wcd937x->supplies, + pdata->regulator, pdata->num_supplies); + if (!wcd937x->supplies) { + dev_err(dev, "%s: Cannot init wcd supplies\n", + __func__); + goto err_bind_all; + } + + plat_data = dev_get_platdata(dev->parent); + if (!plat_data) { + dev_err(dev, "%s: platform data from parent is NULL\n", + __func__); + ret = -EINVAL; + goto err_bind_all; + } + wcd937x->handle = (void *)plat_data->handle; + if (!wcd937x->handle) { + dev_err(dev, "%s: handle is NULL\n", __func__); + ret = -EINVAL; + goto err_bind_all; + } + wcd937x->update_wcd_event = plat_data->update_wcd_event; + if (!wcd937x->update_wcd_event) { + dev_err(dev, "%s: update_wcd_event api is null!\n", + __func__); + ret = -EINVAL; + goto err_bind_all; + } + wcd937x->register_notifier = plat_data->register_notifier; + if (!wcd937x->register_notifier) { + dev_err(dev, "%s: register_notifier api is null!\n", + __func__); + ret = -EINVAL; + goto err_bind_all; + } + + ret = msm_cdc_enable_static_supplies(dev, wcd937x->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(dev, "%s: wcd static supply enable failed!\n", + __func__); + goto err_bind_all; + } + + ret = wcd937x_reset(dev); + if (ret == -EPROBE_DEFER) { + dev_err(dev, "%s: wcd reset failed!\n", __func__); + goto err_bind_all; + } + /* + * Add 5msec delay to provide sufficient time for + * soundwire auto enumeration of slave devices as + * as per HW requirement. + */ + usleep_range(5000, 5010); + wcd937x->wakeup = wcd937x_wakeup; + + ret = component_bind_all(dev, wcd937x); + if (ret) { + dev_err(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + goto err_bind_all; + } + + ret = wcd937x_parse_port_mapping(dev, "qcom,rx_swr_ch_map", CODEC_RX); + ret |= wcd937x_parse_port_mapping(dev, "qcom,tx_swr_ch_map", CODEC_TX); + + if (ret) { + dev_err(dev, "Failed to read port mapping\n"); + goto err; + } + ret = wcd937x_parse_port_params(dev, "qcom,swr-tx-port-params", + CODEC_TX); + if (ret) { + dev_err(dev, "Failed to read port params\n"); + goto err; + } + + + wcd937x->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave); + if (!wcd937x->rx_swr_dev) { + dev_err(dev, "%s: Could not find RX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + + wcd937x->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave); + if (!wcd937x->tx_swr_dev) { + dev_err(dev, "%s: Could not find TX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + swr_init_port_params(wcd937x->tx_swr_dev, SWR_NUM_PORTS, + wcd937x->swr_tx_port_params); + + wcd937x->regmap = devm_regmap_init_swr(wcd937x->tx_swr_dev, + &wcd937x_regmap_config); + if (!wcd937x->regmap) { + dev_err(dev, "%s: Regmap init failed\n", + __func__); + goto err; + } + + /* Set all interupts as edge triggered */ + for (i = 0; i < wcd937x_regmap_irq_chip.num_regs; i++) + regmap_write(wcd937x->regmap, + (WCD937X_DIGITAL_INTR_LEVEL_0 + i), 0); + + wcd937x_regmap_irq_chip.irq_drv_data = wcd937x; + wcd937x->irq_info.wcd_regmap_irq_chip = &wcd937x_regmap_irq_chip; + wcd937x->irq_info.codec_name = "WCD937X"; + wcd937x->irq_info.regmap = wcd937x->regmap; + wcd937x->irq_info.dev = dev; + ret = wcd_irq_init(&wcd937x->irq_info, &wcd937x->virq); + + if (ret) { + dev_err(dev, "%s: IRQ init failed: %d\n", + __func__, ret); + goto err; + } + wcd937x->tx_swr_dev->slave_irq = wcd937x->virq; + + ret = wcd937x_set_micbias_data(wcd937x, pdata); + if (ret < 0) { + dev_err(dev, "%s: bad micbias pdata\n", __func__); + goto err_irq; + } + /* default L1 power setting */ + wcd937x->tx_ch_pwr[0] = 1; + wcd937x->tx_ch_pwr[1] = 1; + mutex_init(&wcd937x->micb_lock); + mutex_init(&wcd937x->ana_tx_clk_lock); + /* Request for watchdog interrupt */ + wcd_request_irq(&wcd937x->irq_info, WCD937X_IRQ_HPHR_PDM_WD_INT, + "HPHR PDM WD INT", wcd937x_wd_handle_irq, NULL); + wcd_request_irq(&wcd937x->irq_info, WCD937X_IRQ_HPHL_PDM_WD_INT, + "HPHL PDM WD INT", wcd937x_wd_handle_irq, NULL); + wcd_request_irq(&wcd937x->irq_info, WCD937X_IRQ_AUX_PDM_WD_INT, + "AUX PDM WD INT", wcd937x_wd_handle_irq, NULL); + /* Disable watchdog interrupt for HPH and AUX */ + wcd_disable_irq(&wcd937x->irq_info, WCD937X_IRQ_HPHR_PDM_WD_INT); + wcd_disable_irq(&wcd937x->irq_info, WCD937X_IRQ_HPHL_PDM_WD_INT); + wcd_disable_irq(&wcd937x->irq_info, WCD937X_IRQ_AUX_PDM_WD_INT); + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x, + wcd937x_dai, ARRAY_SIZE(wcd937x_dai)); + if (ret) { + dev_err(dev, "%s: Codec registration failed\n", + __func__); + goto err_irq; + } + + return ret; +err_irq: + wcd_irq_exit(&wcd937x->irq_info, wcd937x->virq); +err: + component_unbind_all(dev, wcd937x); +err_bind_all: + kfree(pdata); +err_pdata: + dev_set_drvdata(dev, NULL); + kfree(wcd937x); + return ret; +} + +static void wcd937x_unbind(struct device *dev) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); + struct wcd937x_pdata *pdata = dev_get_platdata(wcd937x->dev); + + wcd_irq_exit(&wcd937x->irq_info, wcd937x->virq); + snd_soc_unregister_component(dev); + component_unbind_all(dev, wcd937x); + mutex_destroy(&wcd937x->micb_lock); + mutex_destroy(&wcd937x->ana_tx_clk_lock); + dev_set_drvdata(dev, NULL); + kfree(pdata); + kfree(wcd937x); +} + +static const struct of_device_id wcd937x_dt_match[] = { + { .compatible = "qcom,wcd937x-codec" , .data = "wcd937x" }, + {} +}; + +static const struct component_master_ops wcd937x_comp_ops = { + .bind = wcd937x_bind, + .unbind = wcd937x_unbind, +}; + +static int wcd937x_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void wcd937x_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int wcd937x_add_slave_components(struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np, *rx_node, *tx_node; + + np = dev->of_node; + + rx_node = of_parse_phandle(np, "qcom,rx-slave", 0); + if (!rx_node) { + dev_err(dev, "%s: Rx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(rx_node); + component_match_add_release(dev, matchptr, + wcd937x_release_of, + wcd937x_compare_of, + rx_node); + + tx_node = of_parse_phandle(np, "qcom,tx-slave", 0); + if (!tx_node) { + dev_err(dev, "%s: Tx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(tx_node); + component_match_add_release(dev, matchptr, + wcd937x_release_of, + wcd937x_compare_of, + tx_node); + return 0; +} + +static int wcd937x_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + int ret; + + ret = wcd937x_add_slave_components(&pdev->dev, &match); + if (ret) + return ret; + + return component_master_add_with_match(&pdev->dev, + &wcd937x_comp_ops, match); +} + +static int wcd937x_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &wcd937x_comp_ops); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static const struct dev_pm_ops wcd937x_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + wcd937x_suspend, + wcd937x_resume + ) +}; +#endif + +static struct platform_driver wcd937x_codec_driver = { + .probe = wcd937x_probe, + .remove = wcd937x_remove, + .driver = { + .name = "wcd937x_codec", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wcd937x_dt_match), +#ifdef CONFIG_PM_SLEEP + .pm = &wcd937x_dev_pm_ops, +#endif + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd937x_codec_driver); +MODULE_DESCRIPTION("WCD937X Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x.h new file mode 100644 index 0000000000..b7dfda31cb --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _WCD937X_H +#define _WCD937X_H + +#include + +#define WCD937X_MAX_SLAVE_CH_TYPES 10 +#define ZERO 0 + +#define WCD937X_DRV_NAME "wcd937x_codec" + +struct wcd937x_swr_slave_ch_map { + u8 ch_type; + u8 index; +}; + +static const struct wcd937x_swr_slave_ch_map wcd937x_swr_slv_tx_ch_idx[] = { + {ADC1, 0}, + {ADC2, 1}, + {ADC3, 2}, + {DMIC0, 3}, + {DMIC1, 4}, + {MBHC, 5}, + {DMIC2, 6}, + {DMIC3, 7}, + {DMIC4, 8}, + {DMIC5, 9}, +}; + +static int wcd937x_swr_master_ch_map[] = { + ZERO, + SWRM_TX1_CH1, + SWRM_TX1_CH2, + SWRM_TX1_CH3, + SWRM_TX1_CH4, + SWRM_TX2_CH1, + SWRM_TX2_CH2, + SWRM_TX2_CH3, + SWRM_TX2_CH4, + SWRM_TX3_CH1, + SWRM_TX3_CH2, + SWRM_TX3_CH3, + SWRM_TX3_CH4, + SWRM_TX_PCM_IN, +}; + +#ifdef CONFIG_SND_SOC_WCD937X +extern int wcd937x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component); + +extern int wcd937x_get_codec_variant(struct snd_soc_component *component); + +int wcd937x_codec_get_dev_num(struct snd_soc_component *component); + +static inline int wcd937x_slave_get_master_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD937X_MAX_SLAVE_CH_TYPES; i++) + if (ch == wcd937x_swr_master_ch_map[i]) + return i; + return 0; +} + +static inline int wcd937x_slave_get_master_ch(int idx) +{ + return wcd937x_swr_master_ch_map[idx]; +} + +static inline int wcd937x_slave_get_slave_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD937X_MAX_SLAVE_CH_TYPES; i++) + if (ch == wcd937x_swr_slv_tx_ch_idx[i].ch_type) + return wcd937x_swr_slv_tx_ch_idx[i].index; + + return -EINVAL; +} +#else +extern int wcd937x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} +static inline int wcd937x_slave_get_master_ch_val(int ch) +{ + return 0; +} +static inline int wcd937x_slave_get_master_ch(int idx) +{ + return 0; +} +static inline int wcd937x_slave_get_slave_ch_val(int ch) +{ + return 0; +} +static inline int wcd937x_get_codec_variant(struct snd_soc_component *component) +{ + return 0; +} +static int wcd937x_codec_get_dev_num(struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD937X */ + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x_slave.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x_slave.c new file mode 100644 index 0000000000..eb5d92a9f9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/wcd937x_slave.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_DEBUG_FS +#include +#include + +#define SWR_SLV_MAX_REG_ADDR 0x2009 +#define SWR_SLV_START_REG_ADDR 0x40 +#define SWR_SLV_MAX_BUF_LEN 20 +#define BYTES_PER_LINE 12 +#define SWR_SLV_RD_BUF_LEN 8 +#define SWR_SLV_WR_BUF_LEN 32 +#define SWR_SLV_MAX_DEVICES 2 +#endif /* CONFIG_DEBUG_FS */ + +struct wcd937x_slave_priv { + struct swr_device *swr_slave; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_wcd937x_dent; + struct dentry *debugfs_peek; + struct dentry *debugfs_poke; + struct dentry *debugfs_reg_dump; + unsigned int read_data; +#endif +}; + +#ifdef CONFIG_DEBUG_FS +static int codec_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int get_parameters(char *buf, u32 *param1, int num_of_par) +{ + char *token = NULL; + int base = 0, cnt = 0; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +static bool is_swr_slv_reg_readable(int reg) +{ + int ret = true; + + if (((reg > 0x46) && (reg < 0x4A)) || + ((reg > 0x4A) && (reg < 0x50)) || + ((reg > 0x55) && (reg < 0xD0)) || + ((reg > 0xD0) && (reg < 0xE0)) || + ((reg > 0xE0) && (reg < 0xF0)) || + ((reg > 0xF0) && (reg < 0x100)) || + ((reg > 0x105) && (reg < 0x120)) || + ((reg > 0x205) && (reg < 0x220)) || + ((reg > 0x305) && (reg < 0x320)) || + ((reg > 0x405) && (reg < 0x420)) || + ((reg > 0x128) && (reg < 0x130)) || + ((reg > 0x228) && (reg < 0x230)) || + ((reg > 0x328) && (reg < 0x330)) || + ((reg > 0x428) && (reg < 0x430)) || + ((reg > 0x138) && (reg < 0x205)) || + ((reg > 0x238) && (reg < 0x305)) || + ((reg > 0x338) && (reg < 0x405)) || + ((reg > 0x405) && (reg < 0xF00)) || + ((reg > 0xF05) && (reg < 0xF20)) || + ((reg > 0xF25) && (reg < 0xF30)) || + ((reg > 0xF35) && (reg < 0x2000))) + ret = false; + + return ret; +} + +static ssize_t wcd937x_swrslave_reg_show(struct swr_device *pdev, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[SWR_SLV_MAX_BUF_LEN]; + + if (!ubuf || !ppos) + return 0; + + for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR); + i <= SWR_SLV_MAX_REG_ADDR; i++) { + if (!is_swr_slv_reg_readable(i)) + continue; + swr_read(pdev, pdev->dev_num, i, ®_val, 1); + len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, + (reg_val & 0xFF)); + if (((total + len) >= count - 1) || (len < 0)) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + pr_err("%s: fail to copy reg dump\n", __func__); + total = -EFAULT; + goto copy_err; + } + total += len; + *ppos += len; + } + +copy_err: + *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE; + return total; +} + +static ssize_t codec_debug_dump(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct swr_device *pdev; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + return wcd937x_swrslave_reg_show(pdev, ubuf, count, ppos); +} + +static ssize_t codec_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char lbuf[SWR_SLV_RD_BUF_LEN]; + struct swr_device *pdev = NULL; + struct wcd937x_slave_priv *wcd937x_slave = NULL; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd937x_slave = swr_get_dev_data(pdev); + if (!wcd937x_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + snprintf(lbuf, sizeof(lbuf), "0x%x\n", + (wcd937x_slave->read_data & 0xFF)); + + return simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); +} + +static ssize_t codec_debug_peek_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev = NULL; + struct wcd937x_slave_priv *wcd937x_slave = NULL; + + if (!cnt || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd937x_slave = swr_get_dev_data(pdev); + if (!wcd937x_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 1); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))) + return -EINVAL; + swr_read(pdev, pdev->dev_num, param[0], &wcd937x_slave->read_data, 1); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static ssize_t codec_debug_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev; + + if (!file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 2); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && + (param[1] <= 0xFF) && (rc == 0))) + return -EINVAL; + swr_write(pdev, pdev->dev_num, param[0], ¶m[1]); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static const struct file_operations codec_debug_write_ops = { + .open = codec_debug_open, + .write = codec_debug_write, +}; + +static const struct file_operations codec_debug_read_ops = { + .open = codec_debug_open, + .read = codec_debug_read, + .write = codec_debug_peek_write, +}; + +static const struct file_operations codec_debug_dump_ops = { + .open = codec_debug_open, + .read = codec_debug_dump, +}; +#endif + +static int wcd937x_slave_bind(struct device *dev, + struct device *master, void *data) +{ + int ret = 0; + struct wcd937x_slave_priv *wcd937x_slave = NULL; + uint8_t devnum = 0; + struct swr_device *pdev = to_swr_device(dev); + + if (pdev == NULL) { + dev_err(dev, "%s: pdev is NULL\n", __func__); + return -EINVAL; + } + + wcd937x_slave = devm_kzalloc(&pdev->dev, + sizeof(struct wcd937x_slave_priv), GFP_KERNEL); + if (!wcd937x_slave) + return -ENOMEM; + + swr_set_dev_data(pdev, wcd937x_slave); + + wcd937x_slave->swr_slave = pdev; + +#ifdef CONFIG_DEBUG_FS + if (!wcd937x_slave->debugfs_wcd937x_dent) { + wcd937x_slave->debugfs_wcd937x_dent = debugfs_create_dir( + dev_name(&pdev->dev), 0); + if (!IS_ERR(wcd937x_slave->debugfs_wcd937x_dent)) { + wcd937x_slave->debugfs_peek = + debugfs_create_file("swrslave_peek", + S_IFREG | 0444, + wcd937x_slave->debugfs_wcd937x_dent, + (void *) pdev, + &codec_debug_read_ops); + + wcd937x_slave->debugfs_poke = + debugfs_create_file("swrslave_poke", + S_IFREG | 0444, + wcd937x_slave->debugfs_wcd937x_dent, + (void *) pdev, + &codec_debug_write_ops); + + wcd937x_slave->debugfs_reg_dump = + debugfs_create_file( + "swrslave_reg_dump", + S_IFREG | 0444, + wcd937x_slave->debugfs_wcd937x_dent, + (void *) pdev, + &codec_debug_dump_ops); + } + } +#endif + + ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); + if (ret) { + dev_dbg(&pdev->dev, + "%s get devnum %d for dev addr %lx failed\n", + __func__, devnum, pdev->addr); + swr_remove_device(pdev); + return ret; + } + pdev->dev_num = devnum; + + return ret; +} + +static void wcd937x_slave_unbind(struct device *dev, + struct device *master, void *data) +{ + struct wcd937x_slave_priv *wcd937x_slave = NULL; + struct swr_device *pdev = to_swr_device(dev); + + if (pdev == NULL) { + dev_err(dev, "%s: pdev is NULL\n", __func__); + return; + } + + wcd937x_slave = swr_get_dev_data(pdev); + if (!wcd937x_slave) { + dev_err(&pdev->dev, "%s: wcd937x_slave is NULL\n", __func__); + return; + } + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(wcd937x_slave->debugfs_wcd937x_dent); + wcd937x_slave->debugfs_wcd937x_dent = NULL; +#endif + + swr_set_dev_data(pdev, NULL); +} + +static const struct swr_device_id wcd937x_swr_id[] = { + {"wcd937x-slave", 0}, + {} +}; + +static const struct of_device_id wcd937x_swr_dt_match[] = { + { + .compatible = "qcom,wcd937x-slave", + }, + {} +}; + +static const struct component_ops wcd937x_slave_comp_ops = { + .bind = wcd937x_slave_bind, + .unbind = wcd937x_slave_unbind, +}; + +static int wcd937x_swr_up(struct swr_device *pdev) +{ + return 0; +} + +static int wcd937x_swr_down(struct swr_device *pdev) +{ + return 0; +} + +static int wcd937x_swr_reset(struct swr_device *pdev) +{ + return 0; +} + +static int wcd937x_swr_probe(struct swr_device *pdev) +{ + return component_add(&pdev->dev, &wcd937x_slave_comp_ops); +} + +static int wcd937x_swr_remove(struct swr_device *pdev) +{ + component_del(&pdev->dev, &wcd937x_slave_comp_ops); + return 0; +} + +static struct swr_driver wcd937x_slave_driver = { + .driver = { + .name = "wcd937x-slave", + .owner = THIS_MODULE, + .of_match_table = wcd937x_swr_dt_match, + }, + .probe = wcd937x_swr_probe, + .remove = wcd937x_swr_remove, + .id_table = wcd937x_swr_id, + .device_up = wcd937x_swr_up, + .device_down = wcd937x_swr_down, + .reset_device = wcd937x_swr_reset, +}; + +static int __init wcd937x_slave_init(void) +{ + return swr_driver_register(&wcd937x_slave_driver); +} + +static void __exit wcd937x_slave_exit(void) +{ + swr_driver_unregister(&wcd937x_slave_driver); +} + +module_init(wcd937x_slave_init); +module_exit(wcd937x_slave_exit); + +MODULE_DESCRIPTION("WCD937X Swr Slave driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/Kbuild new file mode 100644 index 0000000000..2899d0b269 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/Kbuild @@ -0,0 +1,128 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_KALAMA), y) + include $(AUDIO_ROOT)/config/kalamaauto.conf + INCS += -include $(AUDIO_ROOT)/config/kalamaautoconf.h + endif + ifeq ($(CONFIG_ARCH_PINEAPPLE), y) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.h + endif + ifeq ($(CONFIG_ARCH_HOLI), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.h + endif + ifeq ($(CONFIG_ARCH_BLAIR), y) + include $(AUDIO_ROOT)/config/holiauto.conf + INCS += -include $(AUDIO_ROOT)/config/holiautoconf.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/audio +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 + + +# 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/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/Makefile b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/internal.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/internal.h new file mode 100644 index 0000000000..8c00a7faee --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/internal.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _WCD938X_INTERNAL_H +#define _WCD938X_INTERNAL_H + +#include +#include +#include +#include +#include "wcd938x-mbhc.h" +#include "wcd938x.h" + +#define SWR_SCP_CONTROL 0x44 +#define SWR_SCP_HOST_CLK_DIV2_CTL_BANK 0xE0 +#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 +#define TX_ADC_MAX 4 +#define SWR_NUM_PORTS 4 + +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; + struct mutex wakeup_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; + u32 tx_mode[TX_ADC_MAX]; + s32 adc_count; + bool comp1_enable; + bool comp2_enable; + bool ldoh; + bool bcs_dis; + bool dapm_bias_off; + 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 swr_port_params tx_port_params[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config swr_tx_port_params[SWR_UC_MAX]; + 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); + int (*wakeup)(void *handle, bool enable); + u32 version; + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + struct snd_info_entry *variant_entry; + int flyback_cur_det_disable; + int ear_rx_path; + bool dev_up; + u8 tx_master_ch_map[WCD938X_MAX_SLAVE_CH_TYPES]; + bool usbc_hs_status; + /* wcd to swr dmic notification */ + bool notify_swr_dmic; + struct blocking_notifier_head notifier; +}; + +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 { + /* INTR_CTRL_INT_MASK_0 */ + WCD938X_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD938X_IRQ_MBHC_BUTTON_RELEASE_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 void wcd938x_disable_bcs_before_slow_insert( + struct snd_soc_component *component, + bool bcs_disable); +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); +#endif /* _WCD938X_INTERNAL_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-mbhc.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-mbhc.c new file mode 100644 index 0000000000..d61e6d68fc --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-mbhc.c @@ -0,0 +1,1146 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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_read(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_ratelimited(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) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd938x_priv *wcd938x = dev_get_drvdata(component->dev); + + wcd938x->wakeup((void*)wcd938x, 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_read(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_read(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_ratelimited("%s: NULL component pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(wcd938x_mbhc->fw_data, type); + if (!hwdep_cal) + dev_err_ratelimited(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_read(component, + WCD938X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read(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_read(component, WCD938X_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read(component, WCD938X_MBHC_CTL_CLK); + reg4 = snd_soc_component_read(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read(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); + + /* Disable surge protection before impedance detection. + * This is done to give correct value for high impedance. + */ + regmap_update_bits(wcd938x->regmap, + WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00); + /* 1ms delay needed after disable surge protection */ + usleep_range(1000, 1010); + + /* 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; + } + + /* Enable surge protection again after impedance detection */ + regmap_update_bits(wcd938x->regmap, + WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); +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_read(component, WCD938X_MBHC_NEW_CTL_2) & 0x0C)) + goto done; + + wcd938x_mbhc_moisture_detect_en(mbhc, true); + /* Read moisture comparator status */ + ret = ((snd_soc_component_read(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 void wcd938x_mbhc_bcs_enable(struct wcd_mbhc *mbhc, + bool bcs_enable) +{ + if (bcs_enable) + wcd938x_disable_bcs_before_slow_insert(mbhc->component, false); + else + wcd938x_disable_bcs_before_slow_insert(mbhc->component, true); +} + +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, + .bcs_enable = wcd938x_mbhc_bcs_enable, +}; + +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_ratelimited(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_ratelimited(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_ratelimited("%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + if (!zl || !zr) { + pr_err_ratelimited("%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_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd938x = snd_soc_component_get_drvdata(component); + if (!wcd938x) { + pr_err_ratelimited("%s: wcd938x is NULL\n", __func__); + return -EINVAL; + } + + wcd938x_mbhc = wcd938x->mbhc; + if (!wcd938x_mbhc) { + dev_err_ratelimited(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_ratelimited("%s: component is NULL\n", __func__); + return; + } + + wcd938x = snd_soc_component_get_drvdata(component); + if (!wcd938x) { + pr_err_ratelimited("%s: wcd938x is NULL\n", __func__); + return; + } + + wcd938x_mbhc = wcd938x->mbhc; + if (!wcd938x_mbhc) { + dev_err_ratelimited(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_ssr_down: stop mbhc during + * wcd938x subsystem restart + * mbhc: pointer to wcd937x_mbhc structure + * component: handle to snd_soc_component * + */ +void wcd938x_mbhc_ssr_down(struct wcd938x_mbhc *mbhc, + struct snd_soc_component *component) +{ + struct wcd_mbhc *wcd_mbhc = NULL; + + if (!mbhc || !component) + return; + + wcd_mbhc = &mbhc->wcd_mbhc; + if (!wcd_mbhc) { + dev_err_ratelimited(component->dev, "%s: wcd_mbhc is NULL\n", __func__); + return; + } + + wcd938x_mbhc_hs_detect_exit(component); + wcd_mbhc_deinit(wcd_mbhc); +} +EXPORT_SYMBOL(wcd938x_mbhc_ssr_down); + +/* + * 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; + } + + /* Reset detection type to insertion after SSR recovery */ + snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_MECH, + 0x20, 0x20); + 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; + struct wcd938x_pdata *pdata; + + 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; + + pdata = dev_get_platdata(component->dev); + if (!pdata) { + dev_err(component->dev, "%s: pdata pointer is NULL\n", + __func__); + ret = -EINVAL; + goto err; + } + wcd_mbhc->micb_mv = pdata->micbias.micb2_mv; + + 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/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-mbhc.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-mbhc.h new file mode 100644 index 0000000000..e33a92c20e --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-mbhc.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, 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 void wcd938x_mbhc_ssr_down(struct wcd938x_mbhc *mbhc, + 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 void wcd938x_mbhc_ssr_down(struct wcd938x_mbhc *mbhc, + 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/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-registers.h new file mode 100644 index 0000000000..409c4139fc --- /dev/null +++ b/qcom/opensource/audio-kernel/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/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-regmap.c new file mode 100644 index 0000000000..bfa38b4527 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-regmap.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, 2021, 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; + if ((wcd938x_reg_access[WCD938X_REG(reg)] & RD_REG) + && !(wcd938x_reg_access[WCD938X_REG(reg)] & WR_REG)) + return true; + return false; +} + +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, + .use_single_read = true, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-slave.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-slave.c new file mode 100644 index 0000000000..5b16ab6a0b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-slave.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_DEBUG_FS +#include +#include + +#define SWR_SLV_MAX_REG_ADDR 0x2009 +#define SWR_SLV_START_REG_ADDR 0x40 +#define SWR_SLV_MAX_BUF_LEN 20 +#define BYTES_PER_LINE 12 +#define SWR_SLV_RD_BUF_LEN 8 +#define SWR_SLV_WR_BUF_LEN 32 +#define SWR_SLV_MAX_DEVICES 2 +#endif /* CONFIG_DEBUG_FS */ + +#define SWR_MAX_RETRY 5 + +struct wcd938x_slave_priv { + struct swr_device *swr_slave; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_wcd938x_dent; + struct dentry *debugfs_peek; + struct dentry *debugfs_poke; + struct dentry *debugfs_reg_dump; + unsigned int read_data; +#endif +}; + +#ifdef CONFIG_DEBUG_FS +static int codec_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int get_parameters(char *buf, u32 *param1, int num_of_par) +{ + char *token = NULL; + int base = 0, cnt = 0; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +static bool is_swr_slv_reg_readable(int reg) +{ + int ret = true; + + if (((reg > 0x46) && (reg < 0x4A)) || + ((reg > 0x4A) && (reg < 0x50)) || + ((reg > 0x55) && (reg < 0xD0)) || + ((reg > 0xD0) && (reg < 0xE0)) || + ((reg > 0xE0) && (reg < 0xF0)) || + ((reg > 0xF0) && (reg < 0x100)) || + ((reg > 0x105) && (reg < 0x120)) || + ((reg > 0x205) && (reg < 0x220)) || + ((reg > 0x305) && (reg < 0x320)) || + ((reg > 0x405) && (reg < 0x420)) || + ((reg > 0x128) && (reg < 0x130)) || + ((reg > 0x228) && (reg < 0x230)) || + ((reg > 0x328) && (reg < 0x330)) || + ((reg > 0x428) && (reg < 0x430)) || + ((reg > 0x138) && (reg < 0x205)) || + ((reg > 0x238) && (reg < 0x305)) || + ((reg > 0x338) && (reg < 0x405)) || + ((reg > 0x405) && (reg < 0x2000))) + ret = false; + + return ret; +} + +static ssize_t wcd938x_swrslave_reg_show(struct swr_device *pdev, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[SWR_SLV_MAX_BUF_LEN]; + + if (!ubuf || !ppos) + return 0; + + for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR); + i <= SWR_SLV_MAX_REG_ADDR; i++) { + if (!is_swr_slv_reg_readable(i)) + continue; + swr_read(pdev, pdev->dev_num, i, ®_val, 1); + len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, + (reg_val & 0xFF)); + if (((total + len) >= count - 1) || (len < 0)) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + pr_err_ratelimited("%s: fail to copy reg dump\n", __func__); + total = -EFAULT; + goto copy_err; + } + total += len; + *ppos += len; + } + +copy_err: + *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE; + return total; +} + +static ssize_t codec_debug_dump(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct swr_device *pdev; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + return wcd938x_swrslave_reg_show(pdev, ubuf, count, ppos); +} + +static ssize_t codec_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char lbuf[SWR_SLV_RD_BUF_LEN]; + struct swr_device *pdev = NULL; + struct wcd938x_slave_priv *wcd938x_slave = NULL; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd938x_slave = swr_get_dev_data(pdev); + if (!wcd938x_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + snprintf(lbuf, sizeof(lbuf), "0x%x\n", + (wcd938x_slave->read_data & 0xFF)); + + return simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); +} + +static ssize_t codec_debug_peek_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev = NULL; + struct wcd938x_slave_priv *wcd938x_slave = NULL; + + if (!cnt || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd938x_slave = swr_get_dev_data(pdev); + if (!wcd938x_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 1); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))) + return -EINVAL; + swr_read(pdev, pdev->dev_num, param[0], &wcd938x_slave->read_data, 1); + if (rc == 0) + rc = cnt; + else + pr_err_ratelimited("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static ssize_t codec_debug_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev; + + if (!file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 2); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && + (param[1] <= 0xFF) && (rc == 0))) + return -EINVAL; + swr_write(pdev, pdev->dev_num, param[0], ¶m[1]); + if (rc == 0) + rc = cnt; + else + pr_err_ratelimited("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static const struct file_operations codec_debug_write_ops = { + .open = codec_debug_open, + .write = codec_debug_write, +}; + +static const struct file_operations codec_debug_read_ops = { + .open = codec_debug_open, + .read = codec_debug_read, + .write = codec_debug_peek_write, +}; + +static const struct file_operations codec_debug_dump_ops = { + .open = codec_debug_open, + .read = codec_debug_dump, +}; +#endif + +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); + int retry = SWR_MAX_RETRY; + + if (!pdev) { + pr_err_ratelimited("%s: invalid swr device handle\n", __func__); + return -EINVAL; + } + + do { + /* Add delay for soundwire enumeration */ + usleep_range(100, 110); + ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); + } while (ret && --retry); + + if (ret) { + dev_dbg(&pdev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, devnum, pdev->addr); + ret = -EPROBE_DEFER; + 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_ratelimited(&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; + +#ifdef CONFIG_DEBUG_FS + if (!wcd938x_slave->debugfs_wcd938x_dent) { + wcd938x_slave->debugfs_wcd938x_dent = debugfs_create_dir( + dev_name(&pdev->dev), 0); + if (!IS_ERR(wcd938x_slave->debugfs_wcd938x_dent)) { + wcd938x_slave->debugfs_peek = + debugfs_create_file("swrslave_peek", + S_IFREG | 0444, + wcd938x_slave->debugfs_wcd938x_dent, + (void *) pdev, + &codec_debug_read_ops); + + wcd938x_slave->debugfs_poke = + debugfs_create_file("swrslave_poke", + S_IFREG | 0444, + wcd938x_slave->debugfs_wcd938x_dent, + (void *) pdev, + &codec_debug_write_ops); + + wcd938x_slave->debugfs_reg_dump = + debugfs_create_file( + "swrslave_reg_dump", + S_IFREG | 0444, + wcd938x_slave->debugfs_wcd938x_dent, + (void *) pdev, + &codec_debug_dump_ops); + } + } +#endif + + return component_add(&pdev->dev, &wcd938x_slave_comp_ops); +} + +static int wcd938x_swr_remove(struct swr_device *pdev) +{ +#ifdef CONFIG_DEBUG_FS + struct wcd938x_slave_priv *wcd938x_slave = swr_get_dev_data(pdev); + + if (wcd938x_slave) { + debugfs_remove_recursive(wcd938x_slave->debugfs_wcd938x_dent); + wcd938x_slave->debugfs_wcd938x_dent = NULL; + } +#endif + 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/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x-tables.c new file mode 100644 index 0000000000..d2f7d61b6d --- /dev/null +++ b/qcom/opensource/audio-kernel/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/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x.c new file mode 100644 index 0000000000..f7fb8241b1 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x.c @@ -0,0 +1,4754 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wcd938x-registers.h" +#include "wcd938x.h" +#include "internal.h" +#include "asoc/bolero-slave-internal.h" + +#define NUM_SWRS_DT_PARAMS 5 +#define WCD938X_VARIANT_ENTRY_SIZE 32 + +#define WCD938X_VERSION_1_0 1 +#define WCD938X_VERSION_ENTRY_SIZE 32 +#define EAR_RX_PATH_AUX 1 + +#define ADC_MODE_VAL_HIFI 0x01 +#define ADC_MODE_VAL_LO_HIF 0x02 +#define ADC_MODE_VAL_NORMAL 0x03 +#define ADC_MODE_VAL_LP 0x05 +#define ADC_MODE_VAL_ULP1 0x09 +#define ADC_MODE_VAL_ULP2 0x0B + +#define NUM_ATTEMPTS 20 + +#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone" +#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone" +#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone" +#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone" + +#define WCD938X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD938X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WCD938X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +enum { + CODEC_TX = 0, + CODEC_RX, +}; + +enum { + WCD_ADC1 = 0, + WCD_ADC2, + WCD_ADC3, + WCD_ADC4, + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, + WCD_ADC1_MODE, + WCD_ADC2_MODE, + WCD_ADC3_MODE, + WCD_ADC4_MODE, + WCD_HPHL_EN, + WCD_EAR_EN, +}; + +enum { + ADC_MODE_INVALID = 0, + ADC_MODE_HIFI, + ADC_MODE_LO_HIF, + ADC_MODE_NORMAL, + ADC_MODE_LP, + ADC_MODE_ULP1, + ADC_MODE_ULP2, +}; + +static u8 tx_mode_bit[] = { + [ADC_MODE_INVALID] = 0x00, + [ADC_MODE_HIFI] = 0x01, + [ADC_MODE_LO_HIF] = 0x02, + [ADC_MODE_NORMAL] = 0x04, + [ADC_MODE_LP] = 0x08, + [ADC_MODE_ULP1] = 0x10, + [ADC_MODE_ULP2] = 0x20, +}; + +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 27, 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 int wcd938x_get_adc_mode(int val); + +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, + .runtime_pm = false, + .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_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum) +{ + int ret = 0; + int bank = 0; + + ret = swr_read(dev, devnum, SWR_SCP_CONTROL, &bank, 1); + if (ret) + return -EINVAL; + + return ((bank & 0x40) ? 1: 0); +} + +static int wcd938x_get_clk_rate(int mode) +{ + int rate; + + switch (mode) { + case ADC_MODE_ULP2: + rate = SWR_CLK_RATE_0P6MHZ; + break; + case ADC_MODE_ULP1: + rate = SWR_CLK_RATE_1P2MHZ; + break; + case ADC_MODE_LP: + rate = SWR_CLK_RATE_4P8MHZ; + break; + case ADC_MODE_NORMAL: + case ADC_MODE_LO_HIF: + case ADC_MODE_HIFI: + case ADC_MODE_INVALID: + default: + rate = SWR_CLK_RATE_9P6MHZ; + break; + } + + return rate; +} + +static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component, + int rate, int bank) +{ + u8 mask = (bank ? 0xF0 : 0x0F); + u8 val = 0; + + switch (rate) { + case SWR_CLK_RATE_0P6MHZ: + val = (bank ? 0x60 : 0x06); + break; + case SWR_CLK_RATE_1P2MHZ: + val = (bank ? 0x50 : 0x05); + break; + case SWR_CLK_RATE_2P4MHZ: + val = (bank ? 0x30 : 0x03); + break; + case SWR_CLK_RATE_4P8MHZ: + val = (bank ? 0x10 : 0x01); + break; + case SWR_CLK_RATE_9P6MHZ: + default: + val = 0x00; + break; + } + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_SWR_TX_CLK_RATE, + mask, val); + + return 0; +} + +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_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x00); + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, + 0x1F, 0x15); + snd_soc_component_update_bits(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, + 0x1F, 0x15); + snd_soc_component_update_bits(component, WCD938X_HPH_REFBUFF_UHQA_CTL, + 0xC0, 0x80); + snd_soc_component_update_bits(component, WCD938X_DIGITAL_CDC_DMIC_CTL, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, + 0xFF, 0x14); + snd_soc_component_update_bits(component, + WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, + 0x1F, 0x08); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0xFF, 0x55); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0xFF, 0x44); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0xFF, 0x11); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0xFF, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0xFF, 0x00); + snd_soc_component_update_bits(component, + WCD938X_MICB1_TEST_CTL_1, 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD938X_MICB2_TEST_CTL_1, 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD938X_MICB3_TEST_CTL_1, 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00); + snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x0E, + ((snd_soc_component_read(component, + WCD938X_DIGITAL_EFUSE_REG_30) & 0x07) << 1)); + snd_soc_component_update_bits(component, + WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); + + 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 = 0; + 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; + default: + dev_err_ratelimited(component->dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + for (i = 0; i <= num_ports; i++) { + for (j = 0; j < MAX_CH_PER_PORT; j++) { + if ((*map)[i][j].slave_port_type == slv_prt_type) + goto found; + } + } +found: + if (i > num_ports || j == MAX_CH_PER_PORT) { + dev_err_ratelimited(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; +} + + +/* qcom,swr-tx-port-params = , , , ,*UC0* + , , , , *UC1* + , , , ; *UC2* + , , , ; *UC3 */ +static int wcd938x_parse_port_params(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, max_uc; + int ret = 0; + u32 cnt = 0; + u32 i, j; + struct swr_port_params (*map)[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config (*map_uc)[SWR_UC_MAX]; + struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); + + switch (path) { + case CODEC_TX: + map = &wcd938x->tx_port_params; + map_uc = &wcd938x->swr_tx_port_params; + break; + default: + ret = -EINVAL; + goto err_port_map; + } + + 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; + } + + max_uc = map_size / (SWR_NUM_PORTS * SWR_PORT_PARAMS * sizeof(u32)); + + if (max_uc != SWR_UC_MAX) { + dev_err(dev, "%s: port params not provided for all usecases\n", + __func__); + ret = -EINVAL; + goto err_port_map; + } + 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, + SWR_NUM_PORTS * SWR_PORT_PARAMS * max_uc); + 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 < max_uc; i++) { + for (j = 0; j < SWR_NUM_PORTS; j++) { + cnt = (i * SWR_NUM_PORTS + j) * SWR_PORT_PARAMS; + (*map)[i][j].offset1 = dt_array[cnt]; + (*map)[i][j].lane_ctrl = dt_array[cnt + 1]; + } + (*map_uc)[i].pp = &(*map)[i][0]; + } + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static int wcd938x_parse_port_mapping(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, map_length; + u32 port_num = 0, 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 = NULL; + 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; + default: + dev_err(dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + 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].slave_port_type = slave_port_type; + (*map)[port_num][ch_iter].ch_mask = ch_mask; + (*map)[port_num][ch_iter].master_port_type = master_port_type; + (*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask); + (*map)[port_num][ch_iter++].ch_rate = ch_rate; + old_port_num = port_num; + } + *num_ports = port_num; + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static int wcd938x_tx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, int clk_rate, + u8 enable) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + u8 port_id, num_ch, ch_mask; + u8 ch_type = 0; + u32 ch_rate; + int slave_ch_idx; + u8 num_port = 1; + int ret = 0; + + ret = wcd938x_set_port_params(component, slv_port_type, &port_id, + &num_ch, &ch_mask, &ch_rate, + &ch_type, CODEC_TX); + if (ret) + return ret; + + if (clk_rate) + ch_rate = clk_rate; + + slave_ch_idx = wcd938x_slave_get_slave_ch_val(slv_port_type); + if (slave_ch_idx != -EINVAL) + ch_type = wcd938x->tx_master_ch_map[slave_ch_idx]; + + dev_dbg(component->dev, "%s slv_ch_idx: %d, mstr_ch_type: %d\n", + __func__, slave_ch_idx, ch_type); + + if (enable) + ret = swr_connect_port(wcd938x->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &ch_type); + else + ret = swr_disconnect_port(wcd938x->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_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_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); + snd_soc_component_update_bits(component, + WCD938X_AUX_AUXPA, 0x10, 0x10); + } + 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_ratelimited("%s: Invalid params, NULL component\n", __func__); + return NULL; + } + wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) { + pr_err_ratelimited("%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); + wcd938x->ear_rx_path = + snd_soc_component_read( + component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + snd_soc_component_update_bits(component, + WCD938X_EAR_EAR_DAC_CON, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x01); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x80); + } else { + 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); + if (wcd938x->comp1_enable) + 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); + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_update_bits(component, + WCD938X_FLYBACK_EN, + 0x04, 0x00); + wcd938x->flyback_cur_det_disable++; + 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: + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x00); + } else { + if (!(test_bit(WCD_HPHL_EN, &wcd938x->status_mask))) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x04, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + 0x01, 0x00); + } + if (wcd938x->comp1_enable) + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x00); + } + snd_soc_component_update_bits(component, + WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00); + snd_soc_component_update_bits(component, + WCD938X_EAR_EAR_DAC_CON, 0x80, 0x80); + 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); + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_update_bits(component, + WCD938X_FLYBACK_EN, + 0x04, 0x00); + wcd938x->flyback_cur_det_disable++; + 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: + 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: + if (wcd938x->ldoh) + snd_soc_component_update_bits(component, + WCD938X_LDOH_MODE, + 0x80, 0x80); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + 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); + wcd_clsh_set_hph_mode(component, CLS_H_HIFI); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + snd_soc_component_update_bits(component, + WCD938X_HPH_REFBUFF_LP_CTL, 0x01, 0x01); + } + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x10, 0x10); + wcd_clsh_set_hph_mode(component, hph_mode); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL1, 0x07, 0x03); + 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); + if (hph_mode == CLS_H_LP || + hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_update_bits(component, + WCD938X_HPH_REFBUFF_LP_CTL, 0x01, + 0x00); + 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 || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x02, 0x02); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHR_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHR_PDM_WD_INT); + if (wcd938x->update_wcd_event && wcd938x->comp2_enable) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX2 << 0x10)); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x40, 0x00); + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + WCD_EVENT_PRE_HPHR_PA_OFF, + &wcd938x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 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); + } + 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); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL1, 0x07, 0x00); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + hph_mode); + if (wcd938x->ldoh) + snd_soc_component_update_bits(component, + WCD938X_LDOH_MODE, + 0x80, 0x00); + 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: + if (wcd938x->ldoh) + snd_soc_component_update_bits(component, + WCD938X_LDOH_MODE, + 0x80, 0x80); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x01)); + 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); + wcd_clsh_set_hph_mode(component, CLS_H_HIFI); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + snd_soc_component_update_bits(component, + WCD938X_HPH_REFBUFF_LP_CTL, 0x01, 0x01); + } + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x20, 0x20); + wcd_clsh_set_hph_mode(component, hph_mode); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL0, 0x07, 0x03); + set_bit(WCD_HPHL_EN, &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); + if (hph_mode == CLS_H_LP || + hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_update_bits(component, + WCD938X_HPH_REFBUFF_LP_CTL, + 0x01, 0x00); + 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 || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, 0x02, 0x02); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHL_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + if (!test_bit(WCD_EAR_EN, &wcd938x->status_mask)) { + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHL_PDM_WD_INT); + } + if (wcd938x->update_wcd_event && wcd938x->comp1_enable) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX1 << 0x10)); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd938x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x80, 0x00); + blocking_notifier_call_chain(&wcd938x->mbhc->notifier, + WCD_EVENT_PRE_HPHL_PA_OFF, + &wcd938x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 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(21000, 21100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + 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); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL0, 0x07, 0x00); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + hph_mode); + if (wcd938x->ldoh) + snd_soc_component_update_bits(component, + WCD938X_LDOH_MODE, + 0x80, 0x00); + clear_bit(WCD_HPHL_EN, &wcd938x->status_mask); + 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); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL2, 0x01, 0x01); + 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 || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_AUX_PDM_WD_INT); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_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); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL2, 0x01, 0x00); + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_AUX, + hph_mode); + + wcd938x->flyback_cur_det_disable--; + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_update_bits(component, + WCD938X_FLYBACK_EN, + 0x04, 0x04); + 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); + /* + * Enable watchdog interrupt for HPHL or AUX + * depending on mux value + */ + wcd938x->ear_rx_path = + snd_soc_component_read( + component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL2, + 0x01, 0x01); + else { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL0, + 0x07, 0x03); + set_bit(WCD_EAR_EN, &wcd938x->status_mask); + } + if (!wcd938x->comp1_enable) + snd_soc_component_update_bits(component, + WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x80); + 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 || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + WCD938X_ANA_RX_SUPPLIES, + 0x02, 0x02); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, + WCD938X_IRQ_AUX_PDM_WD_INT); + } else { + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHL_PDM_WD_INT); + } + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_AUX_PDM_WD_INT); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10 | 0x1)); + } else { + if(!test_bit(WCD_HPHL_EN, &wcd938x->status_mask)) { + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHL_PDM_WD_INT); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + } + } + break; + case SND_SOC_DAPM_POST_PMD: + if (!wcd938x->comp1_enable) + snd_soc_component_update_bits(component, + WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00); + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL2, + 0x01, 0x00); + else { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL0, + 0x07, 0x00); + clear_bit(WCD_EAR_EN, &wcd938x->status_mask); + } + wcd_cls_h_fsm(component, &wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + hph_mode); + + wcd938x->flyback_cur_det_disable--; + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_update_bits(component, + WCD938X_FLYBACK_EN, + 0x04, 0x04); + 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: + if (!test_bit(WCD_HPHL_EN, &wcd938x->status_mask) && + !test_bit(WCD_EAR_EN, &wcd938x->status_mask)) { + 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, dmic_clk_en_reg; + s32 *dmic_clk_cnt; + u8 dmic_ctl_shift = 0; + u8 dmic_clk_shift = 0; + u8 dmic_clk_mask = 0; + u16 dmic2_left_en = 0; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (w->shift) { + case 0: + case 1: + dmic_clk_cnt = &(wcd938x->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL; + dmic_clk_mask = 0x0F; + dmic_clk_shift = 0x00; + dmic_ctl_shift = 0x00; + break; + case 2: + dmic2_left_en = WCD938X_DIGITAL_CDC_DMIC2_CTL; + fallthrough; + case 3: + dmic_clk_cnt = &(wcd938x->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL; + dmic_clk_mask = 0xF0; + dmic_clk_shift = 0x04; + dmic_ctl_shift = 0x01; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd938x->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC3_CTL; + dmic_clk_mask = 0x0F; + dmic_clk_shift = 0x00; + dmic_ctl_shift = 0x02; + break; + case 6: + case 7: + dmic_clk_cnt = &(wcd938x->dmic_6_7_clk_cnt); + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC4_CTL; + dmic_clk_mask = 0xF0; + dmic_clk_shift = 0x04; + dmic_ctl_shift = 0x03; + break; + default: + dev_err_ratelimited(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, (w->shift +1), *dmic_clk_cnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_AMIC_CTL, + (0x01 << dmic_ctl_shift), 0x00); + /* 250us sleep as per HW requirement */ + usleep_range(250, 260); + if (dmic2_left_en) + snd_soc_component_update_bits(component, + dmic2_left_en, 0x80, 0x80); + /* Setting DMIC clock rate to 2.4MHz */ + snd_soc_component_update_bits(component, + dmic_clk_reg, dmic_clk_mask, + (0x03 << dmic_clk_shift)); + snd_soc_component_update_bits(component, + dmic_clk_en_reg, 0x08, 0x08); + /* enable clock scaling */ + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DMIC_CTL, 0x06, 0x06); + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_tx_connect_port(component, DMIC0 + (w->shift), 0, + false); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_AMIC_CTL, + (0x01 << dmic_ctl_shift), + (0x01 << dmic_ctl_shift)); + if (dmic2_left_en) + snd_soc_component_update_bits(component, + dmic2_left_en, 0x80, 0x00); + snd_soc_component_update_bits(component, + dmic_clk_en_reg, 0x08, 0x00); + break; + }; + return ret; +} + +/* + * 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_ratelimited("%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_read(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; + int bank = 0; + u8 mode = 0; + int i = 0; + int rate = 0; + + bank = (wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num) ? 0 : 1); + + /* power mode is applicable only to analog mics */ + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + /* Get channel rate */ + rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift - ADC1]); + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Check AMIC2 is connected to ADC2 to take an action on BCS */ + if (w->shift == ADC2 && !(snd_soc_component_read(component, + WCD938X_TX_NEW_AMIC_MUX_CFG) & 0x80)) { + if (!wcd938x->bcs_dis) { + wcd938x_tx_connect_port(component, MBHC, + SWR_CLK_RATE_4P8MHZ, true); + set_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); + } + } + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + set_bit(w->shift - ADC1, &wcd938x->status_mask); + wcd938x_tx_connect_port(component, w->shift, rate, + true); + } else { + wcd938x_tx_connect_port(component, w->shift, + SWR_CLK_RATE_2P4MHZ, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + if (strnstr(w->name, "ADC1", sizeof("ADC1"))) { + clear_bit(WCD_ADC1, &wcd938x->status_mask); + clear_bit(WCD_ADC1_MODE, &wcd938x->status_mask); + } else if (strnstr(w->name, "ADC2", sizeof("ADC2"))) { + clear_bit(WCD_ADC2, &wcd938x->status_mask); + clear_bit(WCD_ADC2_MODE, &wcd938x->status_mask); + } else if (strnstr(w->name, "ADC3", sizeof("ADC3"))) { + clear_bit(WCD_ADC3, &wcd938x->status_mask); + clear_bit(WCD_ADC3_MODE, &wcd938x->status_mask); + } else if (strnstr(w->name, "ADC4", sizeof("ADC4"))) { + clear_bit(WCD_ADC4, &wcd938x->status_mask); + clear_bit(WCD_ADC4_MODE, &wcd938x->status_mask); + } + } + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + if (test_bit(WCD_ADC1, &wcd938x->status_mask) || + test_bit(WCD_ADC1_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd938x->status_mask) || + test_bit(WCD_ADC2_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd938x->status_mask) || + test_bit(WCD_ADC3_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd938x->status_mask) || + test_bit(WCD_ADC4_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + rate = wcd938x_get_clk_rate(i); + if (wcd938x->adc_count) { + rate = (wcd938x->adc_count * rate); + if (rate > SWR_CLK_RATE_9P6MHZ) + rate = SWR_CLK_RATE_9P6MHZ; + } + wcd938x_set_swr_clk_rate(component, rate, bank); + } + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + false); + + if (strnstr(w->name, "ADC", sizeof("ADC"))) + wcd938x_set_swr_clk_rate(component, rate, !bank); + break; + }; + + return ret; +} + +static int wcd938x_get_adc_mode(int val) +{ + int ret = 0; + + switch (val) { + case ADC_MODE_INVALID: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_HIFI: + ret = ADC_MODE_VAL_HIFI; + break; + case ADC_MODE_LO_HIF: + ret = ADC_MODE_VAL_LO_HIF; + break; + case ADC_MODE_NORMAL: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_LP: + ret = ADC_MODE_VAL_LP; + break; + case ADC_MODE_ULP1: + ret = ADC_MODE_VAL_ULP1; + break; + case ADC_MODE_ULP2: + ret = ADC_MODE_VAL_ULP2; + break; + default: + ret = -EINVAL; + pr_err_ratelimited("%s: invalid ADC mode value %d\n", __func__, val); + break; + } + return ret; +} + +int wcd938x_tx_channel_config(struct snd_soc_component *component, + int channel, int mode) +{ + int reg = WCD938X_ANA_TX_CH2, mask = 0, val = 0; + int ret = 0; + + switch (channel) { + case 0: + reg = WCD938X_ANA_TX_CH2; + mask = 0x40; + break; + case 1: + reg = WCD938X_ANA_TX_CH2; + mask = 0x20; + break; + case 2: + reg = WCD938X_ANA_TX_CH4; + mask = 0x40; + break; + case 3: + reg = WCD938X_ANA_TX_CH4; + mask = 0x20; + break; + default: + pr_err_ratelimited("%s: Invalid channel num %d\n", __func__, channel); + ret = -EINVAL; + break; + } + + if (!mode) + val = 0x00; + else + val = mask; + + if (!ret) + snd_soc_component_update_bits(component, reg, mask, val); + + 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); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int clk_rate = 0, ret = 0; + int mode = 0, i = 0, bank = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + bank = (wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num) ? 0 : 1); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x->adc_count++; + if (test_bit(WCD_ADC1, &wcd938x->status_mask) || + test_bit(WCD_ADC1_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd938x->status_mask) || + test_bit(WCD_ADC2_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd938x->status_mask) || + test_bit(WCD_ADC3_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd938x->status_mask) || + test_bit(WCD_ADC4_MODE, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + clk_rate = wcd938x_get_clk_rate(i); + + /* clk_rate depends on number of paths getting enabled */ + clk_rate = (wcd938x->adc_count * clk_rate); + if (clk_rate > SWR_CLK_RATE_9P6MHZ) + clk_rate = SWR_CLK_RATE_9P6MHZ; + wcd938x_set_swr_clk_rate(component, clk_rate, bank); + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + true); + wcd938x_set_swr_clk_rate(component, clk_rate, !bank); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x->adc_count--; + if (wcd938x->adc_count < 0) + wcd938x->adc_count = 0; + + wcd938x_tx_connect_port(component, ADC1 + w->shift, 0, false); + if (w->shift + ADC1 == ADC2 && + test_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask)) { + wcd938x_tx_connect_port(component, MBHC, 0, + false); + clear_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); + } + break; + }; + + return ret; +} + +void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component, + bool bcs_disable) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (wcd938x->update_wcd_event) { + if (bcs_disable) + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 0); + else + wcd938x->update_wcd_event(wcd938x->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 1); + } +} + +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); + struct wcd938x_priv *wcd938x = + snd_soc_component_get_drvdata(component); + int ret = 0; + u8 mode = 0; + + 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_ANA_CLK_CTL, 0x08, 0x08); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + + 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); + + ret = wcd938x_tx_channel_config(component, w->shift, 1); + mode = wcd938x_get_adc_mode(wcd938x->tx_mode[w->shift]); + if (mode < 0) { + dev_info_ratelimited(component->dev, + "%s: invalid mode, setting to normal mode\n", + __func__); + mode = ADC_MODE_VAL_NORMAL; + } + switch (w->shift) { + case 0: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x0F, + mode); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x10); + break; + case 1: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0xF0, + mode << 4); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x20, 0x20); + break; + case 2: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x0F, + mode); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x40, 0x40); + break; + case 3: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0xF0, + mode << 4); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x80); + break; + default: + break; + } + ret |= wcd938x_tx_channel_config(component, w->shift, 0); + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->shift) { + case 0: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00); + break; + case 1: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0xF0, + 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x20, 0x00); + break; + case 2: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x0F, + 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x40, 0x00); + break; + case 3: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0xF0, + 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00); + break; + default: + break; + } + if (wcd938x->adc_count == 0) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00); + } + break; + }; + return ret; +} + +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; + int ret = 0; + + if ((micb_index < 0) || (micb_index > WCD938X_MAX_MICBIAS - 1)) { + dev_err_ratelimited(component->dev, + "%s: Invalid micbias index, micb_ind:%d\n", + __func__, micb_index); + return -EINVAL; + } + + if (NULL == wcd938x) { + dev_err_ratelimited(component->dev, + "%s: wcd938x private data is NULL\n", __func__); + 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_ratelimited(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + }; + mutex_lock(&wcd938x->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + if (!wcd938x->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + 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->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + 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: + if (!wcd938x->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + wcd938x->micb_ref[micb_index]++; + if (wcd938x->micb_ref[micb_index] == 1) { + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xF0, 0xF0); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x01, 0x01); + 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, + WCD938X_MICB4_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->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + 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]); + +done: + mutex_unlock(&wcd938x->micb_lock); + return ret; +} +EXPORT_SYMBOL(wcd938x_micbias_control); + +static int wcd938x_get_logical_addr(struct swr_device *swr_dev) +{ + int ret = 0; + uint8_t devnum = 0; + int num_retry = NUM_ATTEMPTS; + + do { + /* retry after 4ms */ + usleep_range(4000, 4010); + ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum); + } while (ret && --num_retry); + + if (ret) + dev_err_ratelimited(&swr_dev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, devnum, swr_dev->addr); + + swr_dev->dev_num = devnum; + return 0; +} + +static bool get_usbc_hs_status(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + if (mbhc_cfg->enable_usbc_analog) { + if (!(snd_soc_component_read(component, WCD938X_ANA_MBHC_MECH) + & 0x20)) + return true; + } + return false; +} + +int wcd938x_swr_dmic_register_notifier(struct snd_soc_component *component, + struct notifier_block *nblock, + bool enable) +{ + struct wcd938x_priv *wcd938x_priv; + if(NULL == component) { + pr_err_ratelimited("%s: wcd938x component is NULL\n", __func__); + return -EINVAL; + } + + wcd938x_priv = snd_soc_component_get_drvdata(component); + wcd938x_priv->notify_swr_dmic = enable; + if (enable) + return blocking_notifier_chain_register(&wcd938x_priv->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd938x_priv->notifier, nblock); +} +EXPORT_SYMBOL(wcd938x_swr_dmic_register_notifier); + +static int wcd938x_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + 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_SLV_EVT_TX_CH_HOLD_CLEAR: + if (test_bit(WCD_ADC1, &wcd938x->status_mask)) { + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x40, 0x00); + set_bit(WCD_ADC1_MODE, &wcd938x->status_mask); + clear_bit(WCD_ADC1, &wcd938x->status_mask); + } + if (test_bit(WCD_ADC2, &wcd938x->status_mask)) { + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH2, 0x20, 0x00); + set_bit(WCD_ADC2_MODE, &wcd938x->status_mask); + clear_bit(WCD_ADC2, &wcd938x->status_mask); + } + if (test_bit(WCD_ADC3, &wcd938x->status_mask)) { + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH4, 0x40, 0x00); + set_bit(WCD_ADC3_MODE, &wcd938x->status_mask); + clear_bit(WCD_ADC3, &wcd938x->status_mask); + } + if (test_bit(WCD_ADC4, &wcd938x->status_mask)) { + snd_soc_component_update_bits(component, + WCD938X_ANA_TX_CH4, 0x20, 0x00); + set_bit(WCD_ADC4_MODE, &wcd938x->status_mask); + clear_bit(WCD_ADC4, &wcd938x->status_mask); + } + break; + case BOLERO_SLV_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_SLV_EVT_SSR_DOWN: + wcd938x->dev_up = false; + if(wcd938x->notify_swr_dmic) + blocking_notifier_call_chain(&wcd938x->notifier, + WCD938X_EVT_SSR_DOWN, + NULL); + wcd938x->mbhc->wcd_mbhc.deinit_in_progress = true; + mbhc = &wcd938x->mbhc->wcd_mbhc; + wcd938x->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); + wcd938x_mbhc_ssr_down(wcd938x->mbhc, component); + wcd938x_reset_low(wcd938x->dev); + break; + case BOLERO_SLV_EVT_SSR_UP: + wcd938x_reset(wcd938x->dev); + /* allow reset to take effect */ + usleep_range(10000, 10010); + + wcd938x_get_logical_addr(wcd938x->tx_swr_dev); + wcd938x_get_logical_addr(wcd938x->rx_swr_dev); + + wcd938x_init_reg(component); + 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_ratelimited(component->dev, "%s: mbhc initialization failed\n", + __func__); + } else { + wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg); + } + wcd938x->mbhc->wcd_mbhc.deinit_in_progress = false; + wcd938x->dev_up = true; + if(wcd938x->notify_swr_dmic) + blocking_notifier_call_chain(&wcd938x->notifier, + WCD938X_EVT_SSR_UP, + NULL); + if (wcd938x->usbc_hs_status) + mdelay(500); + break; + case BOLERO_SLV_EVT_CLK_NOTIFY: + snd_soc_component_update_bits(component, + 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_codec_enable_micbias_pullup(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, "VA MIC BIAS1", sizeof("VA MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else if (strnstr(w->name, "VA MIC BIAS4", sizeof("VA 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_PULLUP_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_PULLUP_DISABLE, true); + break; + }; + + return 0; + +} + +static int wcd938x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd938x_codec_enable_micbias_pullup(w, event); +} + +static int wcd938x_wakeup(void *handle, bool enable) +{ + struct wcd938x_priv *priv; + int ret = 0; + + if (!handle) { + pr_err_ratelimited("%s: NULL handle\n", __func__); + return -EINVAL; + } + priv = (struct wcd938x_priv *)handle; + if (!priv->tx_swr_dev) { + pr_err_ratelimited("%s: tx swr dev is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&priv->wakeup_lock); + if (enable) + ret = swr_device_wakeup_vote(priv->tx_swr_dev); + else + ret = swr_device_wakeup_unvote(priv->tx_swr_dev); + mutex_unlock(&priv->wakeup_lock); + + return ret; +} + +static int wcd938x_codec_force_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_wakeup(wcd938x, true); + ret = __wcd938x_codec_enable_micbias(w, SND_SOC_DAPM_PRE_PMU); + wcd938x_wakeup(wcd938x, false); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_wakeup(wcd938x, true); + ret = __wcd938x_codec_enable_micbias(w, SND_SOC_DAPM_POST_PMD); + wcd938x_wakeup(wcd938x, false); + break; + } + + return ret; +} + +static int wcd938x_enable_micbias(struct wcd938x_priv *wcd938x, + int micb_num, int req) +{ + int micb_index = micb_num - 1; + u16 micb_reg; + + if (NULL == wcd938x) { + pr_err_ratelimited("%s: wcd938x private data is NULL\n", __func__); + return -EINVAL; + } + + 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: + pr_err_ratelimited("%s: Invalid micbias number: %d\n", __func__, micb_num); + return -EINVAL; + }; + + pr_debug("%s: req: %d micb_num: %d micb_ref: %d pullup_ref: %d\n", + __func__, req, micb_num, wcd938x->micb_ref[micb_index], + wcd938x->pullup_ref[micb_index]); + mutex_lock(&wcd938x->micb_lock); + + switch (req) { + case MICB_ENABLE: + wcd938x->micb_ref[micb_index]++; + if (wcd938x->micb_ref[micb_index] == 1) { + regmap_update_bits(wcd938x->regmap, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xE0, 0xE0); + regmap_update_bits(wcd938x->regmap, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + regmap_update_bits(wcd938x->regmap, + WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x01, 0x01); + regmap_update_bits(wcd938x->regmap, + WCD938X_MICB1_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd938x->regmap, + WCD938X_MICB2_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd938x->regmap, + WCD938X_MICB3_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd938x->regmap, + WCD938X_MICB4_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd938x->regmap, + micb_reg, 0xC0, 0x40); + regmap_update_bits(wcd938x->regmap, micb_reg, 0x3F, 0x10); + } + break; + case MICB_PULLUP_ENABLE: + wcd938x->pullup_ref[micb_index]++; + if ((wcd938x->pullup_ref[micb_index] == 1) && + (wcd938x->micb_ref[micb_index] == 0)) + regmap_update_bits(wcd938x->regmap, 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)) + regmap_update_bits(wcd938x->regmap, micb_reg, + 0xC0, 0x00); + 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)) + regmap_update_bits(wcd938x->regmap, micb_reg, + 0xC0, 0x80); + else if ((wcd938x->micb_ref[micb_index] == 0) && + (wcd938x->pullup_ref[micb_index] == 0)) + regmap_update_bits(wcd938x->regmap, micb_reg, + 0xC0, 0x00); + break; + }; + + mutex_unlock(&wcd938x->micb_lock); + return 0; +} + +int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *component, + int event, int micb_num) +{ + struct wcd938x_priv *wcd938x_priv = NULL; + int ret = 0; + int micb_index = micb_num - 1; + + if(NULL == component) { + pr_err_ratelimited("%s: wcd938x component is NULL\n", __func__); + return -EINVAL; + } + if(event != SND_SOC_DAPM_PRE_PMU && event != SND_SOC_DAPM_POST_PMD) { + pr_err_ratelimited("%s: invalid event: %d\n", __func__, event); + return -EINVAL; + } + if(micb_num < MIC_BIAS_1 || micb_num > MIC_BIAS_4) { + pr_err_ratelimited("%s: invalid mic bias num: %d\n", __func__, micb_num); + return -EINVAL; + } + + wcd938x_priv = snd_soc_component_get_drvdata(component); + + if (!wcd938x_priv->dev_up) { + if ((wcd938x_priv->pullup_ref[micb_index] > 0) && + (event == SND_SOC_DAPM_POST_PMD)) { + wcd938x_priv->pullup_ref[micb_index]--; + ret = -ENODEV; + goto done; + } + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_wakeup(wcd938x_priv, true); + wcd938x_enable_micbias(wcd938x_priv, micb_num, MICB_PULLUP_ENABLE); + wcd938x_wakeup(wcd938x_priv, false); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_wakeup(wcd938x_priv, true); + wcd938x_enable_micbias(wcd938x_priv, micb_num, MICB_PULLUP_DISABLE); + wcd938x_wakeup(wcd938x_priv, false); + break; + } + +done: + return ret; +} +EXPORT_SYMBOL(wcd938x_codec_force_enable_micbias_v2); + +static inline int wcd938x_tx_path_get(const char *wname, + unsigned int *path_num) +{ + int ret = 0; + char *widget_name = NULL; + char *w_name = NULL; + char *path_num_char = NULL; + char *path_name = NULL; + + widget_name = kstrndup(wname, 9, GFP_KERNEL); + if (!widget_name) + return -EINVAL; + + w_name = widget_name; + + path_name = strsep(&widget_name, " "); + if (!path_name) { + pr_err_ratelimited("%s: Invalid widget name = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto err; + } + path_num_char = strpbrk(path_name, "0123"); + if (!path_num_char) { + pr_err_ratelimited("%s: tx path index not found\n", + __func__); + ret = -EINVAL; + goto err; + } + ret = kstrtouint(path_num_char, 10, path_num); + if (ret < 0) + pr_err_ratelimited("%s: Invalid tx path = %s\n", + __func__, w_name); + +err: + kfree(w_name); + return ret; +} + +static int wcd938x_tx_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 = NULL; + int ret = 0; + unsigned int path = 0; + + if (!component) + return -EINVAL; + + wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return -EINVAL; + + ret = wcd938x_tx_path_get(kcontrol->id.name, &path); + if (ret < 0) + return ret; + + ucontrol->value.integer.value[0] = wcd938x->tx_mode[path]; + + return 0; +} + +static int wcd938x_tx_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 = NULL; + u32 mode_val; + unsigned int path = 0; + int ret = 0; + + if (!component) + return -EINVAL; + + wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return -EINVAL; + + ret = wcd938x_tx_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: mode: %d\n", __func__, mode_val); + + wcd938x->tx_mode[path] = mode_val; + + return 0; +} + +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 (wcd938x->variant == WCD9380) { + if (mode_val == CLS_H_HIFI || mode_val == CLS_AB_HIFI) { + dev_info_ratelimited(component->dev, + "%s:Invalid HPH Mode, default to CLS_H_ULP\n", + __func__); + mode_val = CLS_H_ULP; + } + } + if (mode_val == CLS_H_NORMAL) { + dev_info_ratelimited(component->dev, + "%s:Invalid HPH Mode, default to class_AB\n", + __func__); + mode_val = CLS_H_ULP; + } + wcd938x->hph_mode = mode_val; + return 0; +} + +static int wcd938x_ear_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ear_pa_gain = snd_soc_component_read(component, + WCD938X_ANA_EAR_COMPANDER_CTL); + + ear_pa_gain = (ear_pa_gain & 0x7C) >> 2; + + ucontrol->value.integer.value[0] = ear_pa_gain; + + dev_dbg(component->dev, "%s: ear_pa_gain = 0x%x\n", __func__, + ear_pa_gain); + + return 0; +} + +static int wcd938x_ear_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + ear_pa_gain = ucontrol->value.integer.value[0] << 2; + + if (!wcd938x->comp1_enable) { + snd_soc_component_update_bits(component, + WCD938X_ANA_EAR_COMPANDER_CTL, + 0x7C, ear_pa_gain); + } + + return 0; +} + +/* wcd938x_codec_get_dev_num - returns swr device number + * @component: Codec instance + * + * Return: swr device number on success or negative error + * code on failure. + */ +int wcd938x_codec_get_dev_num(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x; + + if (!component) + return -EINVAL; + + wcd938x = snd_soc_component_get_drvdata(component); + if (!wcd938x || !wcd938x->rx_swr_dev) { + pr_err_ratelimited("%s: wcd938x component is NULL\n", __func__); + return -EINVAL; + } + + return wcd938x->rx_swr_dev->dev_num; +} +EXPORT_SYMBOL(wcd938x_codec_get_dev_num); + +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_ratelimited(component->dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (!msm_cdc_is_ondemand_supply(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck")) + return 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (test_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask)) { + dev_dbg(component->dev, + "%s: buck already in enabled state\n", + __func__); + clear_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask); + return 0; + } + ret = msm_cdc_enable_ondemand_supply(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck"); + if (ret == -EINVAL) { + dev_err_ratelimited(component->dev, "%s: vdd buck is not enabled\n", + __func__); + return ret; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask); + /* + * 200us sleep is required after LDO is enabled as per + * HW requirement + */ + usleep_range(200, 250); + break; + case SND_SOC_DAPM_POST_PMD: + set_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask); + break; + } + return 0; +} + + +static int wcd938x_ldoh_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->ldoh; + + return 0; +} + +static int wcd938x_ldoh_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); + + wcd938x->ldoh = ucontrol->value.integer.value[0]; + + return 0; +} + +const char * const tx_master_ch_text[] = { + "ZERO", "SWRM_PCM_OUT", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", + "SWRM_TX1_CH4", "SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", + "SWRM_TX2_CH4", "SWRM_TX3_CH1", "SWRM_TX3_CH2", "SWRM_TX3_CH3", + "SWRM_TX3_CH4", "SWRM_PCM_IN", +}; + +const struct soc_enum tx_master_ch_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_master_ch_text), + tx_master_ch_text); + +static void wcd938x_tx_get_slave_ch_type_idx(const char *wname, int *ch_idx) +{ + u8 ch_type = 0; + + if (strnstr(wname, "ADC1", sizeof("ADC1"))) + ch_type = ADC1; + else if (strnstr(wname, "ADC2", sizeof("ADC2"))) + ch_type = ADC2; + else if (strnstr(wname, "ADC3", sizeof("ADC3"))) + ch_type = ADC3; + else if (strnstr(wname, "ADC4", sizeof("ADC4"))) + ch_type = ADC4; + else if (strnstr(wname, "DMIC0", sizeof("DMIC0"))) + ch_type = DMIC0; + else if (strnstr(wname, "DMIC1", sizeof("DMIC1"))) + ch_type = DMIC1; + else if (strnstr(wname, "MBHC", sizeof("MBHC"))) + ch_type = MBHC; + else if (strnstr(wname, "DMIC2", sizeof("DMIC2"))) + ch_type = DMIC2; + else if (strnstr(wname, "DMIC3", sizeof("DMIC3"))) + ch_type = DMIC3; + else if (strnstr(wname, "DMIC4", sizeof("DMIC4"))) + ch_type = DMIC4; + else if (strnstr(wname, "DMIC5", sizeof("DMIC5"))) + ch_type = DMIC5; + else if (strnstr(wname, "DMIC6", sizeof("DMIC6"))) + ch_type = DMIC6; + else if (strnstr(wname, "DMIC7", sizeof("DMIC7"))) + ch_type = DMIC7; + else + pr_err_ratelimited("%s: port name: %s is not listed\n", __func__, wname); + + if (ch_type) + *ch_idx = wcd938x_slave_get_slave_ch_val(ch_type); + else + *ch_idx = -EINVAL; +} + +static int wcd938x_tx_master_ch_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 = NULL; + int slave_ch_idx = -EINVAL; + + if (component == NULL) + return -EINVAL; + + wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x == NULL) + return -EINVAL; + + wcd938x_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + if (slave_ch_idx < 0 || slave_ch_idx >= WCD938X_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + ucontrol->value.integer.value[0] = wcd938x_slave_get_master_ch_val( + wcd938x->tx_master_ch_map[slave_ch_idx]); + + return 0; +} + +static int wcd938x_tx_master_ch_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 = NULL; + int slave_ch_idx = -EINVAL, idx = 0; + + if (component == NULL) + return -EINVAL; + + wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x == NULL) + return -EINVAL; + + wcd938x_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + + if (slave_ch_idx < 0 || slave_ch_idx >= WCD938X_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + dev_dbg(component->dev, "%s: slave_ch_idx: %d", __func__, slave_ch_idx); + dev_dbg(component->dev, "%s: ucontrol->value.enumerated.item[0] = %ld\n", + __func__, ucontrol->value.enumerated.item[0]); + + idx = ucontrol->value.enumerated.item[0]; + if (idx < 0 || idx >= ARRAY_SIZE(swr_master_ch_map)) + return -EINVAL; + + wcd938x->tx_master_ch_map[slave_ch_idx] = wcd938x_slave_get_master_ch(idx); + return 0; +} + +static int wcd938x_bcs_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->bcs_dis; + + return 0; +} + +static int wcd938x_bcs_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); + + wcd938x->bcs_dis = ucontrol->value.integer.value[0]; + + return 0; +} + +static const char * const tx_mode_mux_text_wcd9380[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", +}; + +static const struct soc_enum tx_mode_mux_enum_wcd9380 = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380); + +static const char * const tx_mode_mux_text[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", + "ADC_ULP1", "ADC_ULP2", +}; + +static const struct soc_enum tx_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const char * const rx_hph_mode_mux_text_wcd9380[] = { + "CLS_H_INVALID", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB", + "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP", + "CLS_AB_LOHIFI", +}; + +static const char * const wcd938x_ear_pa_gain_text[] = { + "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", "G_0_DB", + "G_M1P5_DB", "G_M3_DB", "G_M4P5_DB", + "G_M6_DB", "G_7P5_DB", "G_M9_DB", + "G_M10P5_DB", "G_M12_DB", "G_M13P5_DB", + "G_M15_DB", "G_M16P5_DB", "G_M18_DB", +}; + +static const struct soc_enum rx_hph_mode_mux_enum_wcd9380 = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9380), + rx_hph_mode_mux_text_wcd9380); + +static SOC_ENUM_SINGLE_EXT_DECL(wcd938x_ear_pa_gain_enum, + wcd938x_ear_pa_gain_text); + +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", "CLS_AB_LP", "CLS_AB_LOHIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static const struct snd_kcontrol_new wcd9380_snd_controls[] = { + SOC_ENUM_EXT("EAR PA GAIN", wcd938x_ear_pa_gain_enum, + wcd938x_ear_pa_gain_get, wcd938x_ear_pa_gain_put), + + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9380, + wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), + + SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), +}; + +static const struct snd_kcontrol_new wcd9385_snd_controls[] = { + SOC_ENUM_EXT("EAR PA GAIN", wcd938x_ear_pa_gain_enum, + wcd938x_ear_pa_gain_get, wcd938x_ear_pa_gain_put), + + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), + + SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), +}; + +static const struct snd_kcontrol_new wcd938x_snd_controls[] = { + 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("LDOH Enable", SND_SOC_NOPM, 0, 1, 0, + wcd938x_ldoh_get, wcd938x_ldoh_put), + + SOC_SINGLE_EXT("ADC2_BCS Disable", SND_SOC_NOPM, 0, 1, 0, + wcd938x_bcs_get, wcd938x_bcs_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, 26, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 26, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD938X_ANA_TX_CH3, 0, 26, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD938X_ANA_TX_CH4, 0, 26, 0, + analog_gain), + + SOC_ENUM_EXT("ADC1 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("ADC2 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("ADC3 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("ADC4 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC0 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC1 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("MBHC ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC2 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC3 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC4 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC5 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC6 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC7 ChMap", tx_master_ch_enum, + wcd938x_tx_master_ch_get, wcd938x_tx_master_ch_put), +}; + +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 amic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic6_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic7_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic6_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic7_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 char * const hdr12_mux_text[] = { + "NO_HDR12", "HDR12" +}; + +static const struct soc_enum hdr12_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 4, + ARRAY_SIZE(hdr12_mux_text), hdr12_mux_text); + +static const struct snd_kcontrol_new tx_hdr12_mux = + SOC_DAPM_ENUM("HDR12 MUX Mux", hdr12_enum); + +static const char * const hdr34_mux_text[] = { + "NO_HDR34", "HDR34" +}; + +static const struct soc_enum hdr34_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 3, + ARRAY_SIZE(hdr34_mux_text), hdr34_mux_text); + +static const struct snd_kcontrol_new tx_hdr34_mux = + SOC_DAPM_ENUM("HDR34 MUX Mux", hdr34_enum); + +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("VA AMIC1"), + SND_SOC_DAPM_INPUT("VA AMIC2"), + SND_SOC_DAPM_INPUT("VA AMIC3"), + SND_SOC_DAPM_INPUT("VA AMIC4"), + SND_SOC_DAPM_INPUT("VA AMIC5"), + SND_SOC_DAPM_INPUT("VA AMIC6"), + SND_SOC_DAPM_INPUT("VA AMIC7"), + + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_AUX"), + /* + * These dummy widgets are null connected to WCD938x dapm input and + * output widgets which are not actual path endpoints. This ensures + * dapm doesnt set these dapm input and output widgets as endpoints. + */ + SND_SOC_DAPM_INPUT("WCD_TX_DUMMY"), + SND_SOC_DAPM_OUTPUT("WCD_RX_DUMMY"), + + /*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, 1, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0, + 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, 1, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 6, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 7, 0, + 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, 1, 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, 2, 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, 3, 0, + NULL, 0, wcd938x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC1_MIXER", SND_SOC_NOPM, 0, 0, + amic1_switch, ARRAY_SIZE(amic1_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC2_MIXER", SND_SOC_NOPM, 0, 0, + amic2_switch, ARRAY_SIZE(amic2_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC3_MIXER", SND_SOC_NOPM, 0, 0, + amic3_switch, ARRAY_SIZE(amic3_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC4_MIXER", SND_SOC_NOPM, 0, 0, + amic4_switch, ARRAY_SIZE(amic4_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC5_MIXER", SND_SOC_NOPM, 0, 0, + amic5_switch, ARRAY_SIZE(amic5_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC6_MIXER", SND_SOC_NOPM, 0, 0, + amic6_switch, ARRAY_SIZE(amic6_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC7_MIXER", SND_SOC_NOPM, 0, 0, + amic7_switch, ARRAY_SIZE(amic7_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC1_MIXER", SND_SOC_NOPM, 0, 0, + va_amic1_switch, ARRAY_SIZE(va_amic1_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC2_MIXER", SND_SOC_NOPM, 0, 0, + va_amic2_switch, ARRAY_SIZE(va_amic2_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC3_MIXER", SND_SOC_NOPM, 0, 0, + va_amic3_switch, ARRAY_SIZE(va_amic3_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC4_MIXER", SND_SOC_NOPM, 0, 0, + va_amic4_switch, ARRAY_SIZE(va_amic4_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC5_MIXER", SND_SOC_NOPM, 0, 0, + va_amic5_switch, ARRAY_SIZE(va_amic5_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC6_MIXER", SND_SOC_NOPM, 0, 0, + va_amic6_switch, ARRAY_SIZE(va_amic6_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC7_MIXER", SND_SOC_NOPM, 0, 0, + va_amic7_switch, ARRAY_SIZE(va_amic7_switch), NULL, + 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), + SND_SOC_DAPM_MUX("HDR12 MUX", SND_SOC_NOPM, 0, 0, + &tx_hdr12_mux), + SND_SOC_DAPM_MUX("HDR34 MUX", SND_SOC_NOPM, 0, 0, + &tx_hdr34_mux), + /*tx mixers*/ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, ADC1, 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, ADC2, 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, ADC3, 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, ADC4, 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, DMIC1, + 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, DMIC2, + 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, DMIC3, + 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, DMIC4, + 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, DMIC5, + 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, DMIC6, + 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, DMIC7, + 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, DMIC8, + 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_SUPPLY("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_SUPPLY("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_SUPPLY("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_SUPPLY("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(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd938x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS2_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd938x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS3_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd938x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd938x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_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_PMD | 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_PMD | 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_PMD | 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_PMD | 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("WCD_TX_OUTPUT"), + + /*output widgets rx*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("AUX"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + + /* micbias pull up widgets*/ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route wcd938x_audio_map[] = { + + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, + {"WCD_TX_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1 REQ"}, + {"ADC1 REQ", NULL, "ADC1"}, + {"ADC1", NULL, "AMIC1_MIXER"}, + {"AMIC1_MIXER", "Switch", "AMIC1"}, + {"AMIC1_MIXER", NULL, "VA_AMIC1_MIXER"}, + {"VA_AMIC1_MIXER", "Switch", "VA AMIC1"}, + + {"WCD_TX_OUTPUT", NULL, "ADC2_MIXER"}, + {"ADC2_MIXER", "Switch", "ADC2 REQ"}, + {"ADC2 REQ", NULL, "ADC2"}, + {"ADC2", NULL, "HDR12 MUX"}, + {"HDR12 MUX", "NO_HDR12", "ADC2 MUX"}, + {"HDR12 MUX", "HDR12", "AMIC1_MIXER"}, + {"ADC2 MUX", "INP3", "AMIC3_MIXER"}, + {"AMIC3_MIXER", "Switch", "AMIC3"}, + {"AMIC3_MIXER", NULL, "VA_AMIC3_MIXER"}, + {"VA_AMIC3_MIXER", "Switch", "VA AMIC3"}, + {"ADC2 MUX", "INP2", "AMIC2_MIXER"}, + {"AMIC2_MIXER", "Switch", "AMIC2"}, + {"AMIC2_MIXER", NULL, "VA_AMIC2_MIXER"}, + {"VA_AMIC2_MIXER", "Switch", "VA AMIC2"}, + + {"WCD_TX_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_MIXER", "Switch", "ADC3 REQ"}, + {"ADC3 REQ", NULL, "ADC3"}, + {"ADC3", NULL, "HDR34 MUX"}, + {"HDR34 MUX", "NO_HDR34", "ADC3 MUX"}, + {"HDR34 MUX", "HDR34", "AMIC5_MIXER"}, + {"ADC3 MUX", "INP4", "AMIC4_MIXER"}, + {"AMIC4_MIXER", "Switch", "AMIC4"}, + {"AMIC4_MIXER", NULL, "VA_AMIC4_MIXER"}, + {"VA_AMIC4_MIXER", "Switch", "VA AMIC4"}, + {"ADC3 MUX", "INP6", "AMIC6_MIXER"}, + {"AMIC6_MIXER", "Switch", "AMIC6"}, + {"AMIC6_MIXER", NULL, "VA_AMIC6_MIXER"}, + {"VA_AMIC6_MIXER", "Switch", "VA AMIC6"}, + + {"WCD_TX_OUTPUT", NULL, "ADC4_MIXER"}, + {"ADC4_MIXER", "Switch", "ADC4 REQ"}, + {"ADC4 REQ", NULL, "ADC4"}, + {"ADC4", NULL, "ADC4 MUX"}, + {"ADC4 MUX", "INP5", "AMIC5_MIXER"}, + {"AMIC5_MIXER", "Switch", "AMIC5"}, + {"AMIC5_MIXER", NULL, "VA_AMIC5_MIXER"}, + {"VA_AMIC5_MIXER", "Switch", "VA AMIC5"}, + {"ADC4 MUX", "INP7", "AMIC7_MIXER"}, + {"AMIC7_MIXER", "Switch", "AMIC7"}, + {"AMIC7_MIXER", NULL, "VA_AMIC7_MIXER"}, + {"VA_AMIC7_MIXER", "Switch", "VA AMIC7"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_MIXER", "Switch", "DMIC3"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_MIXER", "Switch", "DMIC4"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_MIXER", "Switch", "DMIC5"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_MIXER", "Switch", "DMIC6"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC7_MIXER"}, + {"DMIC7_MIXER", "Switch", "DMIC7"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC8_MIXER"}, + {"DMIC8_MIXER", "Switch", "DMIC8"}, + + {"IN1_HPHL", NULL, "WCD_RX_DUMMY"}, + {"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, "WCD_RX_DUMMY"}, + {"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, "WCD_RX_DUMMY"}, + {"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_ratelimited("%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, +}; + +static ssize_t wcd938x_variant_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_VARIANT_ENTRY_SIZE]; + int len = 0; + + priv = (struct wcd938x_priv *) entry->private_data; + if (!priv) { + pr_err_ratelimited("%s: wcd938x priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->variant) { + case WCD9380: + len = snprintf(buffer, sizeof(buffer), "WCD9380\n"); + break; + case WCD9385: + len = snprintf(buffer, sizeof(buffer), "WCD9385\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_variant_ops = { + .read = wcd938x_variant_read, +}; + +/* + * wcd938x_get_codec_variant + * @component: component instance + * + * Return: codec variant or -EINVAL in error. + */ +int wcd938x_get_codec_variant(struct snd_soc_component *component) +{ + struct wcd938x_priv *priv = NULL; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) { + dev_err(component->dev, + "%s:wcd938x not probed\n", __func__); + return 0; + } + + return priv->variant; +} +EXPORT_SYMBOL(wcd938x_get_codec_variant); + +/* + * wcd938x_info_create_codec_entry - creates wcd938x module + * @codec_root: The parent directory + * @component: component instance + * + * Creates wcd938x module, variant 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 snd_info_entry *variant_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_module_entry(codec_root->module, + "wcd938x", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create wcd938x entry\n", + __func__); + return -ENOMEM; + } + priv->entry->mode = S_IFDIR | 0555; + if (snd_info_register(priv->entry) < 0) { + snd_info_free_entry(priv->entry); + 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__); + snd_info_free_entry(priv->entry); + 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); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->version_entry = version_entry; + + variant_entry = snd_info_create_card_entry(card->snd_card, + "variant", + priv->entry); + if (!variant_entry) { + dev_dbg(component->dev, "%s: failed to create wcd938x variant entry\n", + __func__); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + variant_entry->private_data = priv; + variant_entry->size = WCD938X_VARIANT_ENTRY_SIZE; + variant_entry->content = SNDRV_INFO_CONTENT_DATA; + variant_entry->c.ops = &wcd938x_variant_ops; + + if (snd_info_register(variant_entry) < 0) { + snd_info_free_entry(variant_entry); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->variant_entry = variant_entry; + + return 0; +} +EXPORT_SYMBOL(wcd938x_info_create_codec_entry); + +static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x, + struct wcd938x_pdata *pdata) +{ + int vout_ctl_1 = 0, vout_ctl_2 = 0, vout_ctl_3 = 0, vout_ctl_4 = 0; + int rc = 0; + + if (!pdata) { + dev_err(wcd938x->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl_1 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + vout_ctl_2 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv); + vout_ctl_3 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv); + vout_ctl_4 = wcd938x_get_micb_vout_ctl_val(pdata->micbias.micb4_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || + vout_ctl_4 < 0) { + rc = -EINVAL; + goto done; + } + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB1, 0x3F, + vout_ctl_1); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB2, 0x3F, + vout_ctl_2); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB3, 0x3F, + vout_ctl_3); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB4, 0x3F, + vout_ctl_4); + +done: + return rc; +} + +static int wcd938x_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(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); + + devm_regmap_qti_debugfs_register(&wcd938x->tx_swr_dev->dev, wcd938x->regmap); + + variant = (snd_soc_component_read(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, "WCD938X_AIF Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WCD938X_AIF Capture"); + 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, "VA AMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC4"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC5"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC6"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC7"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_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_ignore_suspend(dapm, "WCD_TX_DUMMY"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_RX_DUMMY"); + snd_soc_dapm_sync(dapm); + + wcd_cls_h_init(&wcd938x->clsh_info); + wcd938x_init_reg(component); + + if (wcd938x->variant == WCD9380) { + ret = snd_soc_add_component_controls(component, wcd9380_snd_controls, + ARRAY_SIZE(wcd9380_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd938x->variant); + goto err_hwdep; + } + } + if (wcd938x->variant == WCD9385) { + ret = snd_soc_add_component_controls(component, wcd9385_snd_controls, + ARRAY_SIZE(wcd9385_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd938x->variant); + goto err_hwdep; + } + } + 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 int wcd938x_soc_codec_suspend(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return 0; + wcd938x->dapm_bias_off = true; + return 0; +} + +static int wcd938x_soc_codec_resume(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return 0; + wcd938x->dapm_bias_off = false; + return 0; +} + +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), + .suspend = wcd938x_soc_codec_suspend, + .resume = wcd938x_soc_codec_resume, +}; + +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_ratelimited(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_ratelimited(dev, "%s: wcd sleep state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 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_ratelimited(dev, "%s: wcd active state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 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__); + } + + /* MB4 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias4-mv", + NULL)) { + rc = wcd938x_read_of_property_u32(dev, + "qcom,cdc-micbias4-mv", + &prop_val); + if (!rc) + mb->micb4_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias4 DT property not found\n", + __func__); + } +} + +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_ratelimited(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_ratelimited(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_ratelimited(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_ratelimited(dev, "%s: no power supplies defined for codec\n", + __func__); + return NULL; + } + + pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-slave", 0); + pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0); + + wcd938x_dt_parse_micbias_info(dev, &pdata->micbias); + + return pdata; +} + +static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data) +{ + pr_err_ratelimited("%s: Watchdog interrupt for irq =%d triggered\n", + __func__, irq); + return IRQ_HANDLED; +} + +static struct snd_soc_dai_driver wcd938x_dai[] = { + { + .name = "wcd938x_cdc", + .playback = { + .stream_name = "WCD938X_AIF Playback", + .rates = WCD938X_RATES | WCD938X_FRAC_RATES, + .formats = WCD938X_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .capture = { + .stream_name = "WCD938X_AIF Capture", + .rates = WCD938X_RATES | WCD938X_FRAC_RATES, + .formats = WCD938X_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + }, +}; + +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_ratelimited(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_ratelimited(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_ratelimited(dev, "%s: Could not find TX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + swr_init_port_params(wcd938x->tx_swr_dev, SWR_NUM_PORTS, + wcd938x->swr_tx_port_params); + + wcd938x->regmap = devm_regmap_init_swr(wcd938x->tx_swr_dev, + &wcd938x_regmap_config); + if (!wcd938x->regmap) { + dev_err_ratelimited(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_ratelimited(wcd938x->dev, "%s: IRQ init failed: %d\n", + __func__, ret); + goto err; + } + wcd938x->tx_swr_dev->slave_irq = wcd938x->virq; + + ret = wcd938x_set_micbias_data(wcd938x, pdata); + if (ret < 0) { + dev_err_ratelimited(dev, "%s: bad micbias pdata\n", __func__); + goto err_irq; + } + + /* Request for watchdog interrupt */ + wcd_request_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT, + "HPHR PDM WD INT", wcd938x_wd_handle_irq, NULL); + wcd_request_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHL_PDM_WD_INT, + "HPHL PDM WD INT", wcd938x_wd_handle_irq, NULL); + wcd_request_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT, + "AUX PDM WD INT", wcd938x_wd_handle_irq, NULL); + /* Disable watchdog interrupt for HPH and AUX */ + wcd_disable_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT); + wcd_disable_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHL_PDM_WD_INT); + wcd_disable_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT); + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x, + wcd938x_dai, ARRAY_SIZE(wcd938x_dai)); + if (ret) { + dev_err_ratelimited(dev, "%s: Codec registration failed\n", + __func__); + goto err_irq; + } + wcd938x->dev_up = true; + + 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_free_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT, NULL); + wcd_free_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHL_PDM_WD_INT, NULL); + wcd_free_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT, NULL); + 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", .data = "wcd938x"}, + {} +}; + +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-slave", 0); + if (!rx_node) { + dev_err_ratelimited(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-slave", 0); + if (!tx_node) { + dev_err_ratelimited(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; + struct wcd_ctrl_platform_data *plat_data = NULL; + struct device *dev = &pdev->dev; + int ret; + + wcd938x = devm_kzalloc(dev, sizeof(struct wcd938x_priv), + GFP_KERNEL); + if (!wcd938x) + return -ENOMEM; + + dev_set_drvdata(dev, wcd938x); + wcd938x->dev = dev; + + pdata = wcd938x_populate_dt_data(dev); + if (!pdata) { + dev_err(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(dev, &wcd938x->supplies, + pdata->regulator, pdata->num_supplies); + if (!wcd938x->supplies) { + dev_err(dev, "%s: Cannot init wcd supplies\n", + __func__); + return ret; + } + + plat_data = dev_get_platdata(dev->parent); + if (!plat_data) { + dev_err(dev, "%s: platform data from parent is NULL\n", + __func__); + return -EINVAL; + } + wcd938x->handle = (void *)plat_data->handle; + if (!wcd938x->handle) { + dev_err(dev, "%s: handle is NULL\n", __func__); + return -EINVAL; + } + + wcd938x->update_wcd_event = plat_data->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 = plat_data->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(dev, "%s: wcd static supply enable failed!\n", + __func__); + return ret; + } + + ret = wcd938x_parse_port_mapping(dev, "qcom,rx_swr_ch_map", + CODEC_RX); + ret |= wcd938x_parse_port_mapping(dev, "qcom,tx_swr_ch_map", + CODEC_TX); + + if (ret) { + dev_err(dev, "Failed to read port mapping\n"); + goto err; + } + ret = wcd938x_parse_port_params(dev, "qcom,swr-tx-port-params", + CODEC_TX); + if (ret) { + dev_err(dev, "Failed to read port params\n"); + goto err; + } + + mutex_init(&wcd938x->wakeup_lock); + mutex_init(&wcd938x->micb_lock); + ret = wcd938x_add_slave_components(dev, &match); + if (ret) + goto err_lock_init; + + ret = wcd938x_reset(dev); + if (ret == -EPROBE_DEFER) { + dev_err(dev, "%s: wcd reset failed!\n", __func__); + goto err_lock_init; + } + + wcd938x->wakeup = wcd938x_wakeup; + + return component_master_add_with_match(dev, + &wcd938x_comp_ops, match); + +err_lock_init: + mutex_destroy(&wcd938x->micb_lock); + mutex_destroy(&wcd938x->wakeup_lock); +err: + return ret; +} + +static int wcd938x_remove(struct platform_device *pdev) +{ + struct wcd938x_priv *wcd938x = NULL; + + wcd938x = platform_get_drvdata(pdev); + component_master_del(&pdev->dev, &wcd938x_comp_ops); + mutex_destroy(&wcd938x->micb_lock); + mutex_destroy(&wcd938x->wakeup_lock); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int wcd938x_suspend(struct device *dev) +{ + struct wcd938x_priv *wcd938x = NULL; + int ret = 0; + struct wcd938x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd938x = dev_get_drvdata(dev); + if (!wcd938x) + return -EINVAL; + + pdata = dev_get_platdata(wcd938x->dev); + + if (!pdata) { + dev_err_ratelimited(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask)) { + ret = msm_cdc_disable_ondemand_supply(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck"); + if (ret == -EINVAL) { + dev_err_ratelimited(dev, "%s: vdd buck is not disabled\n", + __func__); + return 0; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask); + } + if (wcd938x->dapm_bias_off || + (wcd938x->component && + (snd_soc_component_get_bias_level(wcd938x->component) == + SND_SOC_BIAS_OFF))) { + msm_cdc_set_supplies_lpm_mode(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + true); + set_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask); + } + return 0; +} + +static int wcd938x_resume(struct device *dev) +{ + struct wcd938x_priv *wcd938x = NULL; + struct wcd938x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd938x = dev_get_drvdata(dev); + if (!wcd938x) + return -EINVAL; + + pdata = dev_get_platdata(wcd938x->dev); + + if (!pdata) { + dev_err_ratelimited(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask)) { + msm_cdc_set_supplies_lpm_mode(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + false); + clear_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask); + } + + return 0; +} + +static const struct dev_pm_ops wcd938x_dev_pm_ops = { + .suspend_late = wcd938x_suspend, + .resume_early = 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 + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd938x_codec_driver); +MODULE_DESCRIPTION("WCD938X Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x.h new file mode 100644 index 0000000000..1c0c876b11 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/wcd938x.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _WCD938X_H +#define _WCD938X_H + +#include + +#define WCD938X_MAX_SLAVE_CH_TYPES 13 +#define ZERO 0 +#define WCD938X_DRV_NAME "wcd938x_codec" + +enum { + WCD9380 = 0, + WCD9385 = 5, +}; + +/* from WCD to SWR DMIC events */ +enum { + WCD938X_EVT_SSR_DOWN, + WCD938X_EVT_SSR_UP, +}; + +struct swr_slave_ch_map { + u8 ch_type; + u8 index; +}; + +static const struct swr_slave_ch_map swr_slv_tx_ch_idx[] = { + {ADC1, 0}, + {ADC2, 1}, + {ADC3, 2}, + {ADC4, 3}, + {DMIC0, 4}, + {DMIC1, 5}, + {MBHC, 6}, + {DMIC2, 6}, + {DMIC3, 7}, + {DMIC4, 8}, + {DMIC5, 9}, + {DMIC6, 10}, + {DMIC7, 11}, +}; + +static int swr_master_ch_map[] = { + ZERO, + SWRM_TX_PCM_OUT, + SWRM_TX1_CH1, + SWRM_TX1_CH2, + SWRM_TX1_CH3, + SWRM_TX1_CH4, + SWRM_TX2_CH1, + SWRM_TX2_CH2, + SWRM_TX2_CH3, + SWRM_TX2_CH4, + SWRM_TX3_CH1, + SWRM_TX3_CH2, + SWRM_TX3_CH3, + SWRM_TX3_CH4, + SWRM_TX_PCM_IN, +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD938X) +int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component); + +int wcd938x_get_codec_variant(struct snd_soc_component *component); +int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *wcd938x, + int event, int micb_num); +int wcd938x_swr_dmic_register_notifier(struct snd_soc_component *wcd938x, + struct notifier_block *nblock, + bool enable); +int wcd938x_codec_get_dev_num(struct snd_soc_component *component); + +static inline int wcd938x_slave_get_master_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD938X_MAX_SLAVE_CH_TYPES; i++) + if (ch == swr_master_ch_map[i]) + return i; + return 0; +} + +static inline int wcd938x_slave_get_master_ch(int idx) +{ + return swr_master_ch_map[idx]; +} + +static inline int wcd938x_slave_get_slave_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD938X_MAX_SLAVE_CH_TYPES; i++) + if (ch == swr_slv_tx_ch_idx[i].ch_type) + return swr_slv_tx_ch_idx[i].index; + + return -EINVAL; +} +#else +static inline int wcd938x_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} +static inline int wcd938x_get_codec_variant(struct snd_soc_component *component) +{ + return 0; +} +static inline int wcd938x_codec_force_enable_micbias_v2( + struct snd_soc_component *wcd938x, + int event, int micb_num) +{ + return 0; +} + +static inline int wcd938x_slave_get_master_ch_val(int ch) +{ + return 0; +} +static inline int wcd938x_slave_get_master_ch(int idx) +{ + return 0; +} +static inline int wcd938x_slave_get_slave_ch_val(int ch) +{ + return 0; +} +static int wcd938x_codec_get_dev_num(struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD938X */ +#endif /* _WCD938X_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/Kbuild b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/Kbuild new file mode 100644 index 0000000000..422c343e2b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/Kbuild @@ -0,0 +1,121 @@ +# 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-5.4 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif + ifeq ($(CONFIG_ARCH_WAIPIO), y) + include $(AUDIO_ROOT)/config/waipioauto.conf + INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h + endif + ifeq ($(CONFIG_ARCH_KALAMA), y) + include $(AUDIO_ROOT)/config/kalamaauto.conf + INCS += -include $(AUDIO_ROOT)/config/kalamaautoconf.h + endif + ifeq ($(CONFIG_ARCH_PINEAPPLE), y) + include $(AUDIO_ROOT)/config/pineappleauto.conf + INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.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/audio +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ WCD939X ############ + +# for WCD939X Codec +ifdef CONFIG_SND_SOC_WCD939X + WCD939X_OBJS += wcd939x.o + WCD939X_OBJS += wcd939x-regmap.o + WCD939X_OBJS += wcd939x-tables.o + WCD939X_OBJS += wcd939x-mbhc.o +endif + +ifdef CONFIG_SND_SOC_WCD939X_SLAVE + WCD939X_SLAVE_OBJS += wcd939x-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 + + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_WCD939X) += wcd939x_dlkm.o +wcd939x_dlkm-y := $(WCD939X_OBJS) + +obj-$(CONFIG_SND_SOC_WCD939X_SLAVE) += wcd939x_slave_dlkm.o +wcd939x_slave_dlkm-y := $(WCD939X_SLAVE_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/Makefile b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/Makefile new file mode 100644 index 0000000000..8c87649225 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/Makefile @@ -0,0 +1,6 @@ +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1 +modules_install: + $(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/internal.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/internal.h new file mode 100644 index 0000000000..7d6e260926 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/internal.h @@ -0,0 +1,354 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _WCD939X_INTERNAL_H +#define _WCD939X_INTERNAL_H + +#include +#include +#include +#include +#include "wcd939x-mbhc.h" +#include "wcd939x.h" + +#define SWR_SCP_CONTROL 0x44 +#define SWR_SCP_HOST_CLK_DIV2_CTL_BANK 0xE0 +#define WCD939X_MAX_MICBIAS 4 +#define R_COMMON_GND_BUFFER_SIZE 4 +#define MAX_XTALK_SCALE 31 +#define MIN_XTALK_ALPHA 0 +#define MIN_K_TIMES_100 -90 +#define MAX_K_TIMES_100 10000 +#define MAX_USBCSS_HS_IMPEDANCE_MOHMS 20000 +#define MIN_DIFF_SLOPE_FACTOR 9800 +#define MAX_DIFF_SLOPE_FACTOR 10000 + +/* 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 +#define TX_ADC_MAX 4 +#define SWR_NUM_PORTS 4 + +enum { + RX_CLK_9P6MHZ, + RX_CLK_12P288MHZ, + RX_CLK_11P2896MHZ, +}; + +enum { + WCD939X_HPHL, + WCD939X_HPHR, + WCD939X_HPH_MAX, +}; + +enum { + TX_HDR12 = 0, + TX_HDR34, + TX_HDR_MAX, +}; + +enum xtalk_mode { + XTALK_NONE = 0, + XTALK_DIGITAL = 1, + XTALK_ANALOG = 2 +}; + +extern struct regmap_config wcd939x_regmap_config; + +struct comp_coeff_val { + u8 lsb; + u8 msb; +}; + +struct codec_port_info { + u32 slave_port_type; + u32 master_port_type; + u32 ch_mask; + u32 num_ch; + u32 ch_rate; +}; + +struct wcd939x_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[WCD939X_MAX_MICBIAS]; + s32 pullup_ref[WCD939X_MAX_MICBIAS]; + + struct fw_info *fw_data; + struct device_node *wcd_rst_np; + + struct mutex micb_lock; + struct mutex wakeup_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 wcd939x_mbhc *mbhc; + + /*compander and xtalk*/ + int compander_enabled[WCD939X_HPH_MAX]; + int xtalk_enabled[WCD939X_HPH_MAX]; + u8 hph_pcm_enabled; + + u32 hph_mode; + u32 tx_mode[TX_ADC_MAX]; + s32 adc_count; + bool comp1_enable; + bool comp2_enable; + bool ldoh; + bool bcs_dis; + bool dapm_bias_off; + bool in_2Vpk_mode; + 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 swr_port_params tx_port_params[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config swr_tx_port_params[SWR_UC_MAX]; + 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); + int (*wakeup)(void *handle, bool enable); + u32 version; + /* Entry for version info */ + struct snd_info_entry *entry; + struct snd_info_entry *version_entry; + struct snd_info_entry *variant_entry; + int flyback_cur_det_disable; + int ear_rx_path; + bool dev_up; + u8 tx_master_ch_map[WCD939X_MAX_SLAVE_CH_TYPES]; + bool usbc_hs_status; + u8 rx_clk_config; + /* wcd to swr dmic notification */ + bool notify_swr_dmic; + struct blocking_notifier_head notifier; +}; + +struct wcd939x_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 aud_ch_params { + /* Resistance of audio-side internal FET */ + u32 r_aud_int_fet_mohms; + /* Resistance of audio-side external FET */ + u32 r_aud_ext_fet_mohms; + /* Total right audio-side resistance */ + u32 r_aud_res_tot_mohms; + /* Sum of audio-side parasitics and the left/right side of the load */ + u32 r_load_eff_mohms; + /* DT audio parasitics between HPH_L/R and HPHL/R_FB, in milliohms */ + u32 r1; + /* DT audio-side parasitics between the WCD and external FET, + * in milliohms + */ + u32 r3; + /* Calibrated and adjusted SE zdet measurement value */ + u32 zval; +}; + +struct aud_params { + /* Left-side audio params */ + struct aud_ch_params l; + /* Right-side audio params */ + struct aud_ch_params r; + /* Surge switch resistance */ + u32 r_surge_mohms; + /* Tap out linearizer constant for the audio path, multiplied by 100 from the original + * constants to support decimal values up to the hundredth place + */ + s32 k_aud_times_100; + /* Fixed offset to be applied to audio taps */ + s32 aud_tap_offset; +}; + +struct gnd_sbu_params { + /* Resistance of ground-side internal FET */ + u32 r_gnd_int_fet_mohms; + /* Total ground-side parasitics between the WCD and external FET */ + u32 r_gnd_par_route1_mohms; + /* Total ground-side parasitics between the external FET and connector */ + u32 r_gnd_par_route2_mohms; + /* Total ground-side parasitics between the WCD and connector; sum of route1 and route2 */ + u32 r_gnd_par_tot_mohms; + /* Total ground-side resistance */ + u32 r_gnd_res_tot_mohms; + /* DT ground-side parasitics between the external FET and connector, in milliohms */ + u32 r4; + /* For digital crosstalk with remote sensed analog crosstalk mode, DT ground path parasitic + * resistance between the WCD SBU pin and the external MOSFET, in milliohms + */ + u32 r5; + /* For digital crosstalk with local sensed analog crosstalk mode, DT ground path parasitic + * resistance between the WCD GSBU tap point and the external MOSFET, in milliohms + */ + u32 r6; + /* For digital crosstalk with local sensed analog crosstalk mode, DT ground path parasitic + * resistance between the WCD GSBU tap point and the WCD SBU pin, in milliohms + */ + u32 r7; +}; + +struct r_common_gnd_buffer { + /* Data for elements in buffer */ + u32 data[R_COMMON_GND_BUFFER_SIZE]; + /* Index to write next element in buffer */ + size_t write_index; +}; + +struct gnd_params { + /* SBU1-ground params */ + struct gnd_sbu_params sbu1; + /* SBU2-ground params */ + struct gnd_sbu_params sbu2; + /* FIFO circular buffer for storing previous values of r_common_gnd_mohms */ + struct r_common_gnd_buffer r_cm_gnd_buffer; + /* DT resistance of the ground-side external FET, in milliohms */ + u32 rdson_mohms; + /* DT resistance of the ground-side external FET, Vgs=3.6V, in milliohms */ + u32 rdson_3p6v_mohms; + /* Difference between the ground external FET, Vgs=3.6V and Vgs=6V */ + u32 gnd_ext_fet_delta_mohms; + /* Minimum value used for linearizer audio tap calculations */ + u32 gnd_ext_fet_min_mohms; + /* SW-computed resistance for the ground-side external FET */ + u32 r_gnd_ext_fet_mohms; + /* Total ground-side resistance, with the internal FET and the route1 parasitic removed */ + u32 r_common_gnd_mohms; + /* Ground path offset for testing debug, in milliohms */ + s32 r_common_gnd_offset; + /* Margin to check if the calculated r_common_gnd is in a reasonable range, in milliohms */ + u32 r_common_gnd_margin; +}; + +struct xtalk_params { + /* Computed optimal d-xtalk left-side scale value */ + u8 scale_l; + /* Computed optimal d-xtalk left-side alpha value */ + u8 alpha_l; + /* Computed optimal d-xtalk right-side scale value */ + u8 scale_r; + /* Computed optimal d-xtalk right-side alpha value */ + u8 alpha_r; + /* DT configuration for d-xtalk: + * 0 for digital crosstalk disabled, + * 1 for digital crosstalk with local sensed a-xtalk enabled, and + * 2 for digital crosstalk with remote sensed a-xtalk enabled. + */ + enum xtalk_mode xtalk_config; +}; + +struct wcd939x_usbcss_hs_params { + /* Audio-side USBCSS-HS impedance parameters */ + struct aud_params aud; + /* Ground-side USBCSS-HS impedance parameters */ + struct gnd_params gnd; + /* Xtalk-specific parameters */ + struct xtalk_params xtalk; + /* Calibrated and adjusted differential zdet measurement value */ + u32 zdiffval; + /* Multiplicative scale factor to adjust differential zdet measurement value, times 1000 */ + u32 diff_slope_factor_times_1000; + /* Multiplicative scale factor to adjust single-ended zdet measurement value, times 1000 */ + u32 se_slope_factor_times_1000; +}; + +struct wcd939x_pdata { + struct device_node *rst_np; + struct device_node *rx_slave; + struct device_node *tx_slave; + struct wcd939x_micbias_setting micbias; + struct wcd939x_usbcss_hs_params usbcss_hs; + + 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 { + /* INTR_CTRL_INT_MASK_0 */ + WCD939X_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD939X_IRQ_MBHC_SW_DET, + WCD939X_IRQ_HPHR_OCP_INT, + WCD939X_IRQ_HPHR_CNP_INT, + WCD939X_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD939X_IRQ_HPHL_CNP_INT, + WCD939X_IRQ_EAR_CNP_INT, + WCD939X_IRQ_EAR_SCD_INT, + WCD939X_IRQ_HPHL_PDM_WD_INT, + WCD939X_IRQ_HPHR_PDM_WD_INT, + WCD939X_IRQ_EAR_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD939X_IRQ_MBHC_MOISTURE_INT, + WCD939X_IRQ_HPHL_SURGE_DET_INT, + WCD939X_IRQ_HPHR_SURGE_DET_INT, + WCD939X_NUM_IRQS, +}; + +extern struct wcd939x_mbhc *wcd939x_soc_get_mbhc( + struct snd_soc_component *component); +extern void wcd939x_disable_bcs_before_slow_insert( + struct snd_soc_component *component, + bool bcs_disable); +extern int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int volt, int micb_num); +extern int wcd939x_get_micb_vout_ctl_val(u32 micb_mv); +extern int wcd939x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm); +#endif /* _WCD939X_INTERNAL_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-mbhc.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-mbhc.c new file mode 100644 index 0000000000..baed5dda70 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-mbhc.c @@ -0,0 +1,2393 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd939x-registers.h" +#include "internal.h" +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) +#include +#endif + +#define WCD939X_ZDET_SUPPORTED true +/* Z value defined in milliohm */ +#define WCD939X_ZDET_VAL_32 32000 +#define WCD939X_ZDET_VAL_400 400000 +#define WCD939X_ZDET_VAL_1200 1200000 +#define WCD939X_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define WCD939X_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define WCD939X_ZDET_NUM_MEASUREMENTS 900 +#define WCD939X_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define WCD939X_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false +#define WCD939X_MBHC_ZDET_CONST (1071 * 1024) +#define WCD939X_MBHC_MOISTURE_RREF R_24_KOHM + +#define OHMS_TO_MILLIOHMS 1000 +#define SLOPE_FACTOR_SCALER 10000 +#define FLOAT_TO_FIXED_XTALK (1UL << 16) +#define MAX_XTALK_ALPHA 255 +#define MIN_RL_EFF_MOHMS 1 +#define MAX_RL_EFF_MOHMS 900000 +#define HD2_CODE_BASE_VALUE 0x1D +#define HD2_CODE_INV_RESOLUTION 4201025 +#define FLOAT_TO_FIXED_LINEARIZER (1UL << 12) +#define MIN_TAP_OFFSET -1023 +#define MAX_TAP_OFFSET 1023 +#define MIN_TAP 0 +#define MAX_TAP 1023 +#define RDOWN_TIMER_PERIOD_MSEC 100 + +#define WCD_USBSS_WRITE true +#define WCD_USBSS_READ false +#define ZDET_SE 0 +#define ZDET_DIFF 1 +#define WCD_USBSS_EXT_LIN_EN 0x3D +#define WCD_USBSS_EXT_SW_CTRL_1 0x43 +#define WCD_USBSS_MG1_BIAS 0x25 +#define WCD_USBSS_MG2_BIAS 0x29 + +#define SE_SLOPE_MEAS_BIAS 10000 +#define DIFF_SLOPE_MEAS_BIAS 20000 +#define XTALK_CH_REG_ADDR_DELTA 4 +#define NUM_DIFF_MEAS 2 +#define ZDET_SE_MAX_MOHMS 600000 +#define ZDET_ACC_LMT_MOHMS 100000 +#define R_CONN_PAR_LOAD_POS_MOHMS 7895 +#define LINEARIZER_DEFAULT_TAP 0xE8 +#define GND_EXT_FET_MAX_MOHMS 2000 + +struct zdet_dnl_entry { + u8 base_val_ohms; + s16 se_corr_mohms; + s16 diff_corr_mohms; +}; + +static const struct zdet_dnl_entry zdet_dnl_table[] = { + { 0, 0, 0}, + { 5, 56, 13}, + { 10, 60, 34}, + { 15, 13, -4}, + { 20, 21, 14}, + { 25, -16, -20}, + { 30, 5, 7}, + { 35, -46, -90}, + { 40, -4, -17}, + { 45, -74, -40}, + { 50, -52, 3}, + { 55, -37, -5}, + { 60, 4, -79}, + { 65, -34, -82}, + { 70, -105, -33}, + { 75, -81, -55}, + { 80, -39, 34}, + { 85, -37, 46}, + { 90, -51, 81}, + { 95, 14, 132}, + {100, 101, 197}, + {105, 150, 247}, + {110, 217, 245}, + {115, 232, -189}, + {120, 201, -146}, + {125, -152, -121}, + {130, -157, -69}, + {135, -118, -72}, + {140, -54, -24}, + {145, -55, 51}, +}; + +static struct wcd_mbhc_register + wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN", + WCD939X_MBHC_MECH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + WCD939X_MBHC_MECH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + WCD939X_MBHC_MECH, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + WCD939X_PLUG_DETECT_CTL, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + WCD939X_MBHC_ELECT, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + WCD939X_MECH_DET_CURRENT, 0x1F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + WCD939X_MBHC_MECH, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + WCD939X_MBHC_MECH, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + WCD939X_MBHC_MECH, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + WCD939X_MBHC_MECH, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + WCD939X_MBHC_ELECT, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + WCD939X_MBHC_ELECT, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + WCD939X_PLUG_DETECT_CTL, 0x0F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + WCD939X_CTL_1, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + WCD939X_CTL_2, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + WCD939X_MBHC_RESULT_3, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE", + WCD939X_MBHC_RESULT_3, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + WCD939X_MBHC_RESULT_3, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + WCD939X_MBHC_RESULT_3, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + WCD939X_MBHC_RESULT_3, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + WCD939X_HPH_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + WCD939X_MBHC_RESULT_3, 0x07, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + WCD939X_MBHC_ELECT, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + WCD939X_MBHC_RESULT_3, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + WCD939X_MICB2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + WCD939X_CNP_WG_TIME, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + WCD939X_HPH, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + WCD939X_HPH, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + WCD939X_HPH, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + WCD939X_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", + WCD939X_CTL_BCS, 0x02, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + WCD939X_FSM_STATUS, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + WCD939X_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD939X_FSM_STATUS, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD939X_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD939X_PA_CTL2, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", + WCD939X_L_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN", + WCD939X_R_TEST, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS", + WCD939X_INTR_STATUS_0, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS", + WCD939X_INTR_STATUS_0, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN", + WCD939X_CTL_1, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", WCD939X_FSM_STATUS, + 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", WCD939X_FSM_STATUS, + 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", WCD939X_ADC_RESULT, + 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT", WCD939X_MICB2, 0x3F, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE", + WCD939X_CTL_1, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE", + WCD939X_CTL_1, 0x04, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN", + WCD939X_MBHC_ZDET, 0x02, 1, 0), +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = WCD939X_IRQ_MBHC_SW_DET, + .mbhc_btn_press_intr = WCD939X_IRQ_MBHC_BUTTON_PRESS_DET, + .mbhc_btn_release_intr = WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, + .mbhc_hs_ins_intr = WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + .mbhc_hs_rem_intr = WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, + .hph_left_ocp = WCD939X_IRQ_HPHL_OCP_INT, + .hph_right_ocp = WCD939X_IRQ_HPHR_OCP_INT, +}; + +struct wcd939x_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + +static int wcd939x_mbhc_request_irq(struct snd_soc_component *component, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); + + return wcd_request_irq(&wcd939x->irq_info, irq, name, handler, data); +} + +static void wcd939x_mbhc_irq_control(struct snd_soc_component *component, + int irq, bool enable) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); + + if (enable) + wcd_enable_irq(&wcd939x->irq_info, irq); + else + wcd_disable_irq(&wcd939x->irq_info, irq); +} + +static int wcd939x_mbhc_free_irq(struct snd_soc_component *component, + int irq, void *data) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); + + wcd_free_irq(&wcd939x->irq_info, irq, data); + + return 0; +} + +static void wcd939x_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD939X_CTL_1, + 0x80, 0x80); + else + snd_soc_component_update_bits(component, WCD939X_CTL_1, + 0x80, 0x00); +} + +static int wcd939x_mbhc_btn_to_num(struct snd_soc_component *component) +{ + return snd_soc_component_read(component, WCD939X_MBHC_RESULT_3) & 0x7; +} + +static void wcd939x_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(component, WCD939X_MBHC_ELECT, + 0x01, 0x01); + else + snd_soc_component_update_bits(component, WCD939X_MBHC_ELECT, + 0x01, 0x00); +} + +static void wcd939x_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_ratelimited(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, WCD939X_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 wcd939x_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); + + wcd939x->wakeup((void*)wcd939x, lock); + + return true; +} + +static int wcd939x_mbhc_register_notifier(struct wcd_mbhc *mbhc, + struct notifier_block *nblock, + bool enable) +{ + struct wcd939x_mbhc *wcd939x_mbhc; + + wcd939x_mbhc = container_of(mbhc, struct wcd939x_mbhc, wcd_mbhc); + + if (enable) + return blocking_notifier_chain_register(&wcd939x_mbhc->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd939x_mbhc->notifier, nblock); +} + +static bool wcd939x_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + u8 val = 0; + + if (micb_num == MIC_BIAS_2) { + val = ((snd_soc_component_read(mbhc->component, + WCD939X_MICB2) & 0xC0) + >> 6); + if (val == 0x01) + return true; + } + return false; +} + +static bool wcd939x_mbhc_hph_pa_on_status(struct snd_soc_component *component) +{ + return (snd_soc_component_read(component, WCD939X_HPH) & 0xC0) ? + true : false; +} + +static void wcd939x_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, + WCD939X_MECH_DET_CURRENT, + 0x1F, pull_up_cur); +} + +static int wcd939x_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + int ret = 0; + + ret = wcd939x_micbias_control(component, micb_num, req, false); + + return ret; +} + +static void wcd939x_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP, + 0x1C, 0x0C); + snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP, + 0x80, 0x80); + } else { + snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP, + 0x80, 0x00); + snd_soc_component_update_bits(component, WCD939X_MICB2_RAMP, + 0x1C, 0x00); + } +} + +static struct firmware_cal *wcd939x_get_hwdep_fw_cal(struct wcd_mbhc *mbhc, + enum wcd_cal_type type) +{ + struct wcd939x_mbhc *wcd939x_mbhc; + struct firmware_cal *hwdep_cal; + struct snd_soc_component *component = mbhc->component; + + wcd939x_mbhc = container_of(mbhc, struct wcd939x_mbhc, wcd_mbhc); + + if (!component) { + pr_err_ratelimited("%s: NULL component pointer\n", __func__); + return NULL; + } + hwdep_cal = wcdcal_get_fw_cal(wcd939x_mbhc->fw_data, type); + if (!hwdep_cal) + dev_err_ratelimited(component->dev, "%s: cal not sent by %d\n", + __func__, type); + + return hwdep_cal; +} + +static int wcd939x_mbhc_micb_ctrl_threshold_mic( + struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd939x_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 = wcd939x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + + return rc; +} + +static inline void wcd939x_mbhc_get_result_params(struct wcd939x_priv *wcd939x, + 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 + }; + struct wcd939x_mbhc *wcd939x_mbhc = wcd939x->mbhc; + + regmap_update_bits(wcd939x->regmap, WCD939X_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < WCD939X_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd939x->regmap, WCD939X_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd939x->regmap, WCD939X_MBHC_RESULT_1, &val1); + val |= val1; + wcd939x_mbhc->rdown_prev_iter = val; + regmap_update_bits(wcd939x->regmap, WCD939X_MBHC_ZDET, 0x20, 0x00); + x1 = WCD939X_MBHC_GET_X1(val); + c1 = WCD939X_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(wcd939x->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 = (WCD939X_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = WCD939X_ZDET_FLOATING_IMPEDANCE; + + dev_dbg(wcd939x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + wcd939x_mbhc->rdown_timer_complete = false; + mod_timer(&wcd939x_mbhc->rdown_timer, jiffies + msecs_to_jiffies(RDOWN_TIMER_PERIOD_MSEC)); + while (x1) { + regmap_read(wcd939x->regmap, + WCD939X_MBHC_RESULT_1, &val); + regmap_read(wcd939x->regmap, + WCD939X_MBHC_RESULT_2, &val1); + val = val << 0x08; + val |= val1; + x1 = WCD939X_MBHC_GET_X1(val); + i++; + if (i == WCD939X_ZDET_NUM_MEASUREMENTS) + break; + if (wcd939x_mbhc->rdown_timer_complete && wcd939x_mbhc->rdown_prev_iter == val) + break; + wcd939x_mbhc->rdown_prev_iter = val; + } + del_timer(&wcd939x_mbhc->rdown_timer); +} + +static void wcd939x_mbhc_zdet_ramp(struct snd_soc_component *component, + struct wcd939x_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); + int32_t zdet = 0; + + snd_soc_component_update_bits(component, WCD939X_ZDET_ANA_CTL, 0xF0, + 0x80 | (zdet_param->ldo_ctl << 4)); + snd_soc_component_update_bits(component, WCD939X_MBHC_BTN5, 0xFC, + zdet_param->btn5); + snd_soc_component_update_bits(component, WCD939X_MBHC_BTN6, 0xFC, + zdet_param->btn6); + snd_soc_component_update_bits(component, WCD939X_MBHC_BTN7, 0xFC, + zdet_param->btn7); + snd_soc_component_update_bits(component, WCD939X_ZDET_ANA_CTL, + 0x0F, zdet_param->noff); + snd_soc_component_update_bits(component, WCD939X_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + snd_soc_component_update_bits(component, WCD939X_ZDET_RAMP_CTL, + 0x70, 0x60); /*acc1_min_63 */ + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_ZDET, 0x80, 0x80); + dev_dbg(wcd939x->dev, "%s: ramp for HPH_L, noff = %d\n", + __func__, zdet_param->noff); + wcd939x_mbhc_get_result_params(wcd939x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_ZDET, 0x40, 0x40); + dev_dbg(wcd939x->dev, "%s: ramp for HPH_R, noff = %d\n", + __func__, zdet_param->noff); + wcd939x_mbhc_get_result_params(wcd939x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void wcd939x_wcd_mbhc_qfuse_cal( + struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) +{ + s16 q1; + int q1_cal; + + q1 = snd_soc_component_read(component, + WCD939X_EFUSE_REG_21 + flag_l_r); + if (q1 & 0x80) + q1_cal = (10000 - ((q1 & 0x7F) * 10)); + else + q1_cal = (10000 + (q1 * 10)); + + if (q1_cal > 0) { + if (*z_val < 200 * OHMS_TO_MILLIOHMS) + *z_val = ((*z_val) * 10000) / q1_cal; + else if (*z_val < 2000 * OHMS_TO_MILLIOHMS) + *z_val = ((*z_val) * 1000) / q1_cal * 10; + else if (*z_val < 20000 * OHMS_TO_MILLIOHMS) + *z_val = ((*z_val) * 100) / q1_cal * 100; + } +} + +static void rdown_timer_callback(struct timer_list *timer) +{ + struct wcd939x_mbhc *wcd939x_mbhc = container_of(timer, struct wcd939x_mbhc, rdown_timer); + + wcd939x_mbhc->rdown_timer_complete = true; +} + +static void update_hd2_codes(struct regmap *regmap, u32 r_gnd_res_tot_mohms, u32 r_load_eff_mohms) +{ + u64 hd2_delta = 0; + + if (!regmap) + return; + hd2_delta = (HD2_CODE_INV_RESOLUTION * (u64) r_gnd_res_tot_mohms + + FLOAT_TO_FIXED_XTALK * (u64) ((r_gnd_res_tot_mohms + r_load_eff_mohms) / 2)) / + (FLOAT_TO_FIXED_XTALK * (u64) (r_gnd_res_tot_mohms + r_load_eff_mohms)); + if (hd2_delta >= HD2_CODE_BASE_VALUE) { + regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_L, 0x1F, 0x00); + regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_R, 0x1F, 0x00); + } else { + regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_L, 0x1F, + HD2_CODE_BASE_VALUE - hd2_delta); + regmap_update_bits(regmap, WCD939X_RDAC_HD2_CTL_R, 0x1F, + HD2_CODE_BASE_VALUE - hd2_delta); + } +} + +static u8 get_xtalk_scale(u32 gain) +{ + u8 i; + int target, residue; + + if (gain == 0) + return MAX_XTALK_SCALE; + + target = FLOAT_TO_FIXED_XTALK / ((int) gain); + residue = target; + + for (i = 0; i <= MAX_XTALK_SCALE; i++) { + residue = target - (1 << ((int)((u32) i))); + if (residue < 0) + return i; + } + return MAX_XTALK_SCALE; +} + +static u8 get_xtalk_alpha(u32 gain, u8 scale) +{ + u32 two_exp_scale, round_offset, alpha; + + if (gain == 0) + return MIN_XTALK_ALPHA; + + two_exp_scale = 1 << ((u32) scale); + round_offset = FLOAT_TO_FIXED_XTALK / 2; + alpha = (((gain * two_exp_scale - FLOAT_TO_FIXED_XTALK) * 255) + round_offset) + / FLOAT_TO_FIXED_XTALK; + return (alpha <= MAX_XTALK_ALPHA) ? ((u8) alpha) : MAX_XTALK_ALPHA; +} + +static void update_xtalk_scale_and_alpha(struct wcd939x_priv *wcd939x) +{ + u32 r_gnd_res_tot_mohms = 0, r_gnd_int_fet_mohms = 0, r_gnd_par_route1_mohms = 0; + u32 xtalk_gain_l = 0, xtalk_gain_r = 0, r_load_eff_mohms = 0; + u32 xtalk_gain_denom_l = 0, xtalk_gain_denom_r = 0, r7 = 0; + struct wcd939x_pdata *pdata = dev_get_platdata(wcd939x->dev); + + if (!pdata || pdata->usbcss_hs.xtalk.xtalk_config == XTALK_NONE) + return; + + /* Default xtalk values */ + pdata->usbcss_hs.xtalk.scale_l = MAX_XTALK_SCALE; + pdata->usbcss_hs.xtalk.alpha_l = MIN_XTALK_ALPHA; + pdata->usbcss_hs.xtalk.scale_r = MAX_XTALK_SCALE; + pdata->usbcss_hs.xtalk.alpha_r = MIN_XTALK_ALPHA; + + /* Orientation-dependent ground impedance parameters */ +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU2_ORIENTATION_A) { + r_gnd_res_tot_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_res_tot_mohms; + r_gnd_int_fet_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_int_fet_mohms; + r_gnd_par_route1_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_par_route1_mohms; + r7 = pdata->usbcss_hs.gnd.sbu2.r7; + } else if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU1_ORIENTATION_B) { + r_gnd_res_tot_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_res_tot_mohms; + r_gnd_int_fet_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_int_fet_mohms; + r_gnd_par_route1_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_par_route1_mohms; + r7 = pdata->usbcss_hs.gnd.sbu1.r7; + } else { + dev_dbg(wcd939x->dev, "%s: Using default scale and alpha values\n", __func__); + return; + } +#endif + + r_load_eff_mohms = (pdata->usbcss_hs.aud.l.r_load_eff_mohms + + pdata->usbcss_hs.aud.r.r_load_eff_mohms) / 2; + + if (pdata->usbcss_hs.xtalk.xtalk_config == XTALK_ANALOG) { + /* Update HD2 codes for analog xtalk */ + update_hd2_codes(wcd939x->regmap, r_gnd_res_tot_mohms, r_load_eff_mohms); + } + + /* Left channel */ + xtalk_gain_denom_l = pdata->usbcss_hs.aud.l.zval - r_gnd_int_fet_mohms - + r_gnd_par_route1_mohms + pdata->usbcss_hs.aud.l.r1; + if (xtalk_gain_denom_l == 0) { + dev_dbg(wcd939x->dev, + "%s: Using default scale and alpha values for the left channel\n", + __func__); + } else { + xtalk_gain_l = FLOAT_TO_FIXED_XTALK * pdata->usbcss_hs.gnd.r_common_gnd_mohms / + xtalk_gain_denom_l; + /* Store scale and alpha values */ + pdata->usbcss_hs.xtalk.scale_l = get_xtalk_scale(xtalk_gain_l); + pdata->usbcss_hs.xtalk.alpha_l = get_xtalk_alpha(xtalk_gain_l, + pdata->usbcss_hs.xtalk.scale_l); + } + + /* Right channel */ + xtalk_gain_denom_r = pdata->usbcss_hs.aud.r.zval - r_gnd_int_fet_mohms - + r_gnd_par_route1_mohms + pdata->usbcss_hs.aud.r.r1; + if (xtalk_gain_denom_r == 0) { + dev_dbg(wcd939x->dev, + "%s: Using default scale and alpha values for the right channel\n", + __func__); + } else { + xtalk_gain_r = FLOAT_TO_FIXED_XTALK * pdata->usbcss_hs.gnd.r_common_gnd_mohms / + xtalk_gain_denom_r; + pdata->usbcss_hs.xtalk.scale_r = get_xtalk_scale(xtalk_gain_r); + pdata->usbcss_hs.xtalk.alpha_r = get_xtalk_alpha(xtalk_gain_r, + pdata->usbcss_hs.xtalk.scale_r); + } + + /* Print relevant values */ + dev_dbg(wcd939x->dev, "%s: %s = %dmohms, %s = %dmohms, %s = %dmohms\n", __func__, + "Left SE measurement", pdata->usbcss_hs.aud.l.zval, + "right SE measurment", pdata->usbcss_hs.aud.r.zval, + "differential measurement", pdata->usbcss_hs.zdiffval); + dev_dbg(wcd939x->dev, + "%s: %s = %dmohms, %s = %dmohms, %s = %dmohms, %s = %dmohms, %s = %dmohms\n", + __func__, "R1_L", pdata->usbcss_hs.aud.l.r1, "R1_R", pdata->usbcss_hs.aud.r.r1, + "R7", r7, "r_gnd_int_fet_mohms", r_gnd_int_fet_mohms, "r_common_gnd_mohms", + pdata->usbcss_hs.gnd.r_common_gnd_mohms); + dev_dbg(wcd939x->dev, "%s: %s = %d, %s = %d %s %d\n", __func__, + "Xtalk gain (L->R)", xtalk_gain_l, "xtalk gain (R->L)", xtalk_gain_r, + ". To convert xtalk gain to floating point, divide by", FLOAT_TO_FIXED_XTALK); +} + +static void update_ext_fet_res(struct wcd939x_pdata *pdata, u32 r_aud_ext_fet_mohms, + u32 r_gnd_ext_fet_mohms) +{ + if (!pdata) + return; + + pdata->usbcss_hs.gnd.r_gnd_ext_fet_mohms = (r_gnd_ext_fet_mohms > + MAX_USBCSS_HS_IMPEDANCE_MOHMS) + ? MAX_USBCSS_HS_IMPEDANCE_MOHMS + : r_gnd_ext_fet_mohms; + pdata->usbcss_hs.aud.l.r_aud_ext_fet_mohms = (r_aud_ext_fet_mohms > + MAX_USBCSS_HS_IMPEDANCE_MOHMS) + ? MAX_USBCSS_HS_IMPEDANCE_MOHMS + : r_aud_ext_fet_mohms; + pdata->usbcss_hs.aud.r.r_aud_ext_fet_mohms = pdata->usbcss_hs.aud.l.r_aud_ext_fet_mohms; + pdata->usbcss_hs.gnd.sbu1.r_gnd_res_tot_mohms = get_r_gnd_res_tot_mohms( + pdata->usbcss_hs.gnd.sbu1.r_gnd_int_fet_mohms, + pdata->usbcss_hs.gnd.r_gnd_ext_fet_mohms, + pdata->usbcss_hs.gnd.sbu1.r_gnd_par_tot_mohms); + pdata->usbcss_hs.gnd.sbu2.r_gnd_res_tot_mohms = get_r_gnd_res_tot_mohms( + pdata->usbcss_hs.gnd.sbu2.r_gnd_int_fet_mohms, + pdata->usbcss_hs.gnd.r_gnd_ext_fet_mohms, + pdata->usbcss_hs.gnd.sbu2.r_gnd_par_tot_mohms); + pdata->usbcss_hs.aud.l.r_aud_res_tot_mohms = get_r_aud_res_tot_mohms( + pdata->usbcss_hs.aud.l.r_aud_int_fet_mohms, + pdata->usbcss_hs.aud.l.r_aud_ext_fet_mohms, + pdata->usbcss_hs.aud.l.r_load_eff_mohms); + pdata->usbcss_hs.aud.r.r_aud_res_tot_mohms = get_r_aud_res_tot_mohms( + pdata->usbcss_hs.aud.r.r_aud_int_fet_mohms, + pdata->usbcss_hs.aud.r.r_aud_ext_fet_mohms, + pdata->usbcss_hs.aud.r.r_load_eff_mohms); +} + +static void get_linearizer_taps(struct wcd939x_pdata *pdata, u32 *aud_tap) +{ + u32 r_gnd_int_fet_mohms = 0, r_gnd_par_tot_mohms = 0; + u32 v_aud1 = 0, v_aud2 = 0, aud_denom = 0; + u32 r_load_eff_mohms = 0, r3 = 0, r_aud_ext_fet_mohms = 0, r_aud_int_fet_mohms = 0; +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + u32 r_gnd_res_tot_mohms = 0; +#endif + + if (!pdata) + goto err_data; + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* Orientation-dependent ground impedance parameters */ + if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU2_ORIENTATION_A) { + r_gnd_res_tot_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_res_tot_mohms; + r_gnd_int_fet_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_int_fet_mohms; + } else if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU1_ORIENTATION_B) { + r_gnd_res_tot_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_res_tot_mohms; + r_gnd_int_fet_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_int_fet_mohms; + } else { + goto err_data; + } +#endif + + r_load_eff_mohms = (pdata->usbcss_hs.aud.l.r_load_eff_mohms + + pdata->usbcss_hs.aud.r.r_load_eff_mohms) / 2; + r3 = (pdata->usbcss_hs.aud.l.r3 + pdata->usbcss_hs.aud.r.r3) / 2; + r_aud_ext_fet_mohms = (pdata->usbcss_hs.aud.l.r_aud_ext_fet_mohms + + pdata->usbcss_hs.aud.l.r_aud_ext_fet_mohms) / 2; + r_aud_int_fet_mohms = (pdata->usbcss_hs.aud.l.r_aud_int_fet_mohms + + pdata->usbcss_hs.aud.l.r_aud_int_fet_mohms) / 2; + + aud_denom = (u32) (FLOAT_TO_FIXED_LINEARIZER + + (FLOAT_TO_FIXED_LINEARIZER * pdata->usbcss_hs.aud.k_aud_times_100 / 100)); + + v_aud2 = r_load_eff_mohms - r3 + r_gnd_int_fet_mohms + + pdata->usbcss_hs.gnd.r_gnd_ext_fet_mohms + r_gnd_par_tot_mohms; + v_aud1 = v_aud2 + r_aud_ext_fet_mohms; + v_aud1 = FLOAT_TO_FIXED_LINEARIZER * v_aud1 / (v_aud1 + r_aud_int_fet_mohms); + v_aud2 = FLOAT_TO_FIXED_LINEARIZER * v_aud2 / + (v_aud2 + r_aud_ext_fet_mohms + r_aud_int_fet_mohms); + + *aud_tap = (u32) ((s32) ((1000 * v_aud1 + 10 * pdata->usbcss_hs.aud.k_aud_times_100 * v_aud2 + + aud_denom / 2) / aud_denom) + + pdata->usbcss_hs.aud.aud_tap_offset); + if (*aud_tap > MAX_TAP) + *aud_tap = MAX_TAP; + else if (*aud_tap < MIN_TAP) + *aud_tap = MIN_TAP; + + return; + +err_data: + *aud_tap = LINEARIZER_DEFAULT_TAP; +} + +static void interpolate_zdet_val(uint32_t *z, s64 z_meas_bias_removed, s64 z_val_slope_corrected, + int lb, int flag_se_diff) +{ + s64 lb_to_z = 0, lb_to_ub = 0, z_to_ub = 0, lb_corr = 0, ub_corr = 0, z_interp = 0; + + if (lb < 0) + return; + + /* If lb is the table upper bound, no interpolation needed, just use the lb corr factor */ + if ((lb + 1) >= ARRAY_SIZE(zdet_dnl_table)) { + z_interp = (s64) ((flag_se_diff) ? (zdet_dnl_table[lb].diff_corr_mohms) : + (zdet_dnl_table[lb].se_corr_mohms)); + goto apply_interpolated_bias; + } + + /* Set up interpolation */ + lb_to_ub = OHMS_TO_MILLIOHMS * + (s64) (u64) ((zdet_dnl_table[lb + 1].base_val_ohms - + zdet_dnl_table[lb].base_val_ohms)); + z_to_ub = (OHMS_TO_MILLIOHMS * + ((s64) (u64) (zdet_dnl_table[lb + 1].base_val_ohms))) - z_meas_bias_removed; + lb_to_z = z_meas_bias_removed - (OHMS_TO_MILLIOHMS * + ((s64) (u64) (zdet_dnl_table[lb].base_val_ohms))); + lb_corr = (s64) ((flag_se_diff) ? (zdet_dnl_table[lb].diff_corr_mohms) : + (zdet_dnl_table[lb].se_corr_mohms)); + ub_corr = (s64) ((flag_se_diff) ? (zdet_dnl_table[lb + 1].diff_corr_mohms) : + (zdet_dnl_table[lb + 1].se_corr_mohms)); + /* Linear interpolation */ + z_interp = (lb_corr * z_to_ub + ub_corr * lb_to_z) / lb_to_ub; + +apply_interpolated_bias: + /* Subtract interpolated bias to correct error */ + if (z_interp < z_val_slope_corrected) + *z = (u32) (s32) (z_val_slope_corrected - z_interp); +} + +static int get_lb_zdet_base_val_index(uint32_t z_val) +{ + int i; + + /* Find the lower bound index, whose base value is the smallest value that is still higher + * than the load + */ + for (i = 1; i < ARRAY_SIZE(zdet_dnl_table); i++) { + if (z_val < (OHMS_TO_MILLIOHMS * (u32) zdet_dnl_table[i].base_val_ohms)) + return i - 1; + } + + /* Return the last index if the load is larger than all base values */ + return ARRAY_SIZE(zdet_dnl_table) - 1; +} + +static void apply_zdet_correction(uint32_t *z, int flag_se_diff, u32 se_slope_factor_times_1000, + u32 diff_slope_factor_times_1000) +{ + s64 z_val_slope_corrected = 0, slope_corr = 0; + uint32_t z_meas_bias_removed = 0; + int lb; + + /* Apply slope correction */ + slope_corr = (s64) ((flag_se_diff) ? diff_slope_factor_times_1000 : + se_slope_factor_times_1000); + z_val_slope_corrected = ((s64) (u64) *z) * (FLOAT_TO_FIXED_XTALK) * slope_corr / + SLOPE_FACTOR_SCALER / (FLOAT_TO_FIXED_XTALK); + + /* Interpolate correction term to bias out and apply correction */ + z_meas_bias_removed = (flag_se_diff) ? *z - DIFF_SLOPE_MEAS_BIAS : *z - SE_SLOPE_MEAS_BIAS; + lb = get_lb_zdet_base_val_index(z_meas_bias_removed); + interpolate_zdet_val(z, (s64) (u64) z_meas_bias_removed, z_val_slope_corrected, lb, + flag_se_diff); +} + +static void get_r_common_gnd(struct wcd939x_priv *wcd939x, u32 r_gnd_res_tot_mohms, + u32 r_gnd_int_fet_mohms, u32 r_gnd_par_route1_mohms) +{ + u32 r_common_gnd_mohms = 0, r_accum = 0, r_avg = 0; + size_t i; + struct wcd939x_pdata *pdata = dev_get_platdata(wcd939x->dev); + size_t index = pdata->usbcss_hs.gnd.r_cm_gnd_buffer.write_index; + + r_common_gnd_mohms = r_gnd_res_tot_mohms - r_gnd_int_fet_mohms - r_gnd_par_route1_mohms; + + /* Compute average from r_common_gnd buffer */ + for (i = 0; i < R_COMMON_GND_BUFFER_SIZE; i++) + r_accum += pdata->usbcss_hs.gnd.r_cm_gnd_buffer.data[i]; + r_avg = r_accum / R_COMMON_GND_BUFFER_SIZE; + + /* If r_common_gnd_mohms is OOB, use the average of the buffer values instead */ + if (r_common_gnd_mohms > (r_avg + pdata->usbcss_hs.gnd.r_common_gnd_margin) || + (r_avg >= pdata->usbcss_hs.gnd.r_common_gnd_margin && + r_common_gnd_mohms < (r_avg - pdata->usbcss_hs.gnd.r_common_gnd_margin))) { + dev_dbg(wcd939x->dev, "%s: %s %d %s %d %s\n", __func__, + "The average of the r_common_gnd buffer,", r_avg, + "mohms, is being used instead of the calculated r_common_gnd value of", + r_common_gnd_mohms, "mohms"); + pdata->usbcss_hs.gnd.r_common_gnd_mohms = r_avg; + return; + } + + /* Otherwise, use the computed value and store it in the buffer, updating the write index */ + pdata->usbcss_hs.gnd.r_common_gnd_mohms = r_common_gnd_mohms; + pdata->usbcss_hs.gnd.r_cm_gnd_buffer.data[index] = r_common_gnd_mohms; + pdata->usbcss_hs.gnd.r_cm_gnd_buffer.write_index = (index + 1) % R_COMMON_GND_BUFFER_SIZE; + dev_dbg(wcd939x->dev, "%s: %s %d %s\n", __func__, "The calculated r_common_gnd value,", + r_common_gnd_mohms, "mohms, is being used"); +} + +struct usbcss_hs_attr { + struct wcd939x_priv *priv; + struct kobj_attribute attr; + int index; +}; + +static char *usbcss_sysfs_files[] = { + "rdson_3p6v", + "rdson_6v", + "r1_l", + "r1_r", + "r3_l", + "r3_r", + "r4_sbu1", + "r4_sbu2", + "r5_sbu1", + "r5_sbu2", + "r6_sbu1", + "r6_sbu2", + "r7_sbu1", + "r7_sbu2", + "r_common_gnd_offset", + "rcom_margin", + "se_slope_factor_times_1000", + "diff_slope_factor_times_1000", + "lin_k_aud", + "xtalk_config", +}; + +static ssize_t usbcss_sysfs_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct usbcss_hs_attr *usbc_attr; + struct wcd939x_priv *wcd939x; + struct wcd939x_pdata *pdata; + struct wcd939x_usbcss_hs_params *usbcss_hs; + long val; + int rc; + u32 aud_tap = 0; + bool update_xtalk = false, update_linearizer = false; + + usbc_attr = container_of(attr, struct usbcss_hs_attr, attr); + if (!usbc_attr) + return -EINVAL; + + wcd939x = usbc_attr->priv; + + if (!wcd939x) + return -EINVAL; + + pdata = dev_get_platdata(wcd939x->dev); + if (!pdata) + return -EINVAL; + + usbcss_hs = &pdata->usbcss_hs; + + rc = kstrtol(buf, 0, &val); + if (rc) + return rc; + + if (strcmp(attr->attr.name, "rdson_3p6v") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.rdson_3p6v_mohms = val; + usbcss_hs->gnd.gnd_ext_fet_delta_mohms = (s32) (usbcss_hs->gnd.rdson_3p6v_mohms - + usbcss_hs->gnd.rdson_mohms); + update_linearizer = usbcss_hs->xtalk.xtalk_config == XTALK_ANALOG; + } else if (strcmp(attr->attr.name, "rdson_6v") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.rdson_mohms = val; + update_linearizer = usbcss_hs->xtalk.xtalk_config == XTALK_ANALOG; + } else if (strcmp(attr->attr.name, "r1_l") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->aud.l.r1 = val; + update_xtalk = true; + } else if (strcmp(attr->attr.name, "r1_r") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->aud.r.r1 = val; + update_xtalk = true; + } else if (strcmp(attr->attr.name, "r3_l") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->aud.l.r3 = val; + update_linearizer = true; + } else if (strcmp(attr->attr.name, "r3_r") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->aud.r.r3 = val; + update_linearizer = true; + } else if (strcmp(attr->attr.name, "r4_sbu1") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu1.r4 = val; + update_xtalk = true; + update_linearizer = true; + } else if (strcmp(attr->attr.name, "r4_sbu2") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu2.r4 = val; + update_xtalk = true; + update_linearizer = true; + } else if (strcmp(attr->attr.name, "r5_sbu1") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu1.r5 = val; + + switch (usbcss_hs->xtalk.xtalk_config) { + case XTALK_ANALOG: + update_xtalk = true; + update_linearizer = true; + break; + case XTALK_DIGITAL: + fallthrough; + case XTALK_NONE: + fallthrough; + default: + return count; + } + } else if (strcmp(attr->attr.name, "r5_sbu2") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu2.r5 = val; + + switch (usbcss_hs->xtalk.xtalk_config) { + case XTALK_ANALOG: + update_xtalk = true; + update_linearizer = true; + break; + case XTALK_DIGITAL: + fallthrough; + case XTALK_NONE: + fallthrough; + default: + return count; + } + } else if (strcmp(attr->attr.name, "r6_sbu1") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu1.r6 = val; + + switch (usbcss_hs->xtalk.xtalk_config) { + case XTALK_DIGITAL: + update_xtalk = true; + update_linearizer = true; + break; + case XTALK_ANALOG: + fallthrough; + case XTALK_NONE: + fallthrough; + default: + return count; + } + } else if (strcmp(attr->attr.name, "r6_sbu2") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu2.r6 = val; + + switch (usbcss_hs->xtalk.xtalk_config) { + case XTALK_DIGITAL: + update_xtalk = true; + update_linearizer = true; + break; + case XTALK_ANALOG: + fallthrough; + case XTALK_NONE: + fallthrough; + default: + return count; + } + } else if (strcmp(attr->attr.name, "r7_sbu1") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu1.r7 = val; + + switch (usbcss_hs->xtalk.xtalk_config) { + case XTALK_DIGITAL: + update_xtalk = true; + update_linearizer = true; + break; + case XTALK_ANALOG: + fallthrough; + case XTALK_NONE: + fallthrough; + default: + return count; + } + } else if (strcmp(attr->attr.name, "r7_sbu2") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.sbu2.r7 = val; + + switch (usbcss_hs->xtalk.xtalk_config) { + case XTALK_DIGITAL: + update_xtalk = true; + update_linearizer = true; + break; + case XTALK_ANALOG: + fallthrough; + case XTALK_NONE: + fallthrough; + default: + return count; + } + } else if (strcmp(attr->attr.name, "r_common_gnd_offset") == 0) { + if (val < -MAX_USBCSS_HS_IMPEDANCE_MOHMS || val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of bounds. Min: %d, Max: %d\n", + __func__, val, -MAX_USBCSS_HS_IMPEDANCE_MOHMS, + MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.r_common_gnd_offset = val; + update_xtalk = true; + } else if (strcmp(attr->attr.name, "rcom_margin") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->gnd.r_common_gnd_margin = val; + } else if (strcmp(attr->attr.name, "se_slope_factor_times_1000") == 0) { + if (val > MAX_USBCSS_HS_IMPEDANCE_MOHMS) { + dev_err(wcd939x->dev, "%s: Value %d out of HS impedance range %d\n", + __func__, val, MAX_USBCSS_HS_IMPEDANCE_MOHMS); + return count; + } + usbcss_hs->se_slope_factor_times_1000 = val; + } else if (strcmp(attr->attr.name, "diff_slope_factor_times_1000") == 0) { + if (val > MAX_DIFF_SLOPE_FACTOR || val < MIN_DIFF_SLOPE_FACTOR) { + dev_err(wcd939x->dev, "%s: Value %d out of range of %d to %d\n", + __func__, val, MIN_DIFF_SLOPE_FACTOR, MAX_DIFF_SLOPE_FACTOR); + return count; + } + usbcss_hs->diff_slope_factor_times_1000 = val; + } else if (strcmp(attr->attr.name, "lin_k_aud") == 0) { + if (val < MIN_K_TIMES_100 || val > MAX_K_TIMES_100) { + dev_err(wcd939x->dev, "%s: Value %d out of bounds. Min: %d, Max: %d\n", + __func__, val, MIN_K_TIMES_100, MAX_K_TIMES_100); + return count; + } + usbcss_hs->aud.k_aud_times_100 = val; + update_linearizer = true; + } else if (strcmp(attr->attr.name, "xtalk_config") == 0) { + pdata->usbcss_hs.xtalk.xtalk_config = val; + update_xtalk = true; + + switch (val) { + case XTALK_NONE: + usbcss_hs->xtalk.scale_l = MAX_XTALK_SCALE; + usbcss_hs->xtalk.scale_r = MAX_XTALK_SCALE; + usbcss_hs->xtalk.alpha_l = MIN_XTALK_ALPHA; + usbcss_hs->xtalk.alpha_r = MIN_XTALK_ALPHA; + break; + case XTALK_DIGITAL: + update_linearizer = true; + break; + case XTALK_ANALOG: + update_linearizer = true; + break; + default: + return count; + } + } + + /* Update parastics */ + switch (pdata->usbcss_hs.xtalk.xtalk_config) { + case XTALK_NONE: + fallthrough; + case XTALK_DIGITAL: + usbcss_hs->gnd.sbu1.r_gnd_par_route1_mohms = usbcss_hs->gnd.sbu1.r7; + usbcss_hs->gnd.sbu2.r_gnd_par_route1_mohms = usbcss_hs->gnd.sbu2.r7; + usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms = usbcss_hs->gnd.sbu1.r6 + + usbcss_hs->gnd.sbu1.r4; + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms = usbcss_hs->gnd.sbu2.r6 + + usbcss_hs->gnd.sbu2.r4; + break; + case XTALK_ANALOG: + usbcss_hs->gnd.sbu1.r_gnd_par_route1_mohms = usbcss_hs->gnd.sbu1.r5 + + usbcss_hs->gnd.sbu1.r4; + usbcss_hs->gnd.sbu2.r_gnd_par_route1_mohms = usbcss_hs->gnd.sbu2.r5 + + usbcss_hs->gnd.sbu2.r4; + usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms = 1; + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms = 1; + break; + default: + return count; + } + + /* Update parastics total */ + usbcss_hs->gnd.sbu1.r_gnd_par_tot_mohms = usbcss_hs->gnd.sbu1.r_gnd_par_route1_mohms + + usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms; + usbcss_hs->gnd.sbu2.r_gnd_par_tot_mohms = usbcss_hs->gnd.sbu2.r_gnd_par_route1_mohms + + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms; + + if (update_xtalk) { + /* Apply r_common_gnd offset */ + usbcss_hs->gnd.r_common_gnd_mohms = (usbcss_hs->gnd.r_common_gnd_offset >= 0) ? + usbcss_hs->gnd.r_common_gnd_mohms + + (u32) usbcss_hs->gnd.r_common_gnd_offset : + usbcss_hs->gnd.r_common_gnd_mohms - + (u32) (-1 * usbcss_hs->gnd.r_common_gnd_offset); + /* Compute and store xtalk values */ + update_xtalk_scale_and_alpha(wcd939x); + /* Revert r_common_gnd offset */ + usbcss_hs->gnd.r_common_gnd_mohms = (usbcss_hs->gnd.r_common_gnd_offset >= 0) ? + usbcss_hs->gnd.r_common_gnd_mohms - + (u32) usbcss_hs->gnd.r_common_gnd_offset : + usbcss_hs->gnd.r_common_gnd_mohms + + (u32) (-1 * usbcss_hs->gnd.r_common_gnd_offset); + /* Apply xtalk scale and alpha values */ + regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC0, 0x1F, + pdata->usbcss_hs.xtalk.scale_l); + regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC1, 0xFF, + pdata->usbcss_hs.xtalk.alpha_l); + regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC0 + + XTALK_CH_REG_ADDR_DELTA, 0x1F, + pdata->usbcss_hs.xtalk.scale_r); + regmap_update_bits(wcd939x->regmap, WCD939X_HPHL_RX_PATH_SEC1 + + XTALK_CH_REG_ADDR_DELTA, 0xFF, + pdata->usbcss_hs.xtalk.alpha_r); + dev_err(wcd939x->dev, "%s: Updated xtalk thru sysfs\n", + __func__); + dev_dbg(wcd939x->dev, "%s: Left-channel: Xtalk scale is 0x%x and alpha is 0x%x\n", + __func__, pdata->usbcss_hs.xtalk.scale_l, pdata->usbcss_hs.xtalk.alpha_l); + dev_dbg(wcd939x->dev, "%s: Right-channel: Xtalk scale is 0x%x and alpha is 0x%x\n", + __func__, pdata->usbcss_hs.xtalk.scale_r, pdata->usbcss_hs.xtalk.alpha_r); + } + + if (update_linearizer) { + get_linearizer_taps(pdata, &aud_tap); +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + wcd_usbss_set_linearizer_sw_tap(aud_tap, LINEARIZER_DEFAULT_TAP); +#endif + dev_err(wcd939x->dev, "%s: Updated linearizer thru sysfs\n", + __func__); + dev_dbg(wcd939x->dev, "%s: Linearizer aud_tap is 0x%x\n", + __func__, aud_tap); + } + + return count; +} + +static ssize_t usbcss_sysfs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct usbcss_hs_attr *usbc_attr; + struct wcd939x_priv *wcd939x; + struct wcd939x_pdata *pdata; + + usbc_attr = container_of(attr, struct usbcss_hs_attr, attr); + wcd939x = usbc_attr->priv; + pdata = dev_get_platdata(wcd939x->dev); + + if (strcmp(attr->attr.name, "rdson_3p6v") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.rdson_3p6v_mohms); + else if (strcmp(attr->attr.name, "rdson_6v") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.rdson_mohms); + else if (strcmp(attr->attr.name, "r1_l") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.aud.l.r1); + else if (strcmp(attr->attr.name, "r1_r") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.aud.r.r1); + else if (strcmp(attr->attr.name, "r3_l") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.aud.l.r3); + else if (strcmp(attr->attr.name, "r3_r") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.aud.r.r3); + else if (strcmp(attr->attr.name, "r4_sbu1") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu1.r4); + else if (strcmp(attr->attr.name, "r4_sbu2") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu2.r4); + else if (strcmp(attr->attr.name, "r5_sbu1") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu1.r5); + else if (strcmp(attr->attr.name, "r5_sbu2") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu2.r5); + else if (strcmp(attr->attr.name, "r6_sbu1") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu1.r6); + else if (strcmp(attr->attr.name, "r6_sbu2") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu2.r6); + else if (strcmp(attr->attr.name, "r7_sbu1") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu1.r7); + else if (strcmp(attr->attr.name, "r7_sbu2") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.sbu2.r7); + else if (strcmp(attr->attr.name, "r_common_gnd_offset") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.r_common_gnd_offset); + else if (strcmp(attr->attr.name, "rcom_margin") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.gnd.r_common_gnd_margin); + else if (strcmp(attr->attr.name, "se_slope_factor_times_1000") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.se_slope_factor_times_1000); + else if (strcmp(attr->attr.name, "diff_slope_factor_times_1000") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.diff_slope_factor_times_1000); + else if (strcmp(attr->attr.name, "lin_k_aud") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.aud.k_aud_times_100); + else if (strcmp(attr->attr.name, "xtalk_config") == 0) + return scnprintf(buf, 10, "%d\n", pdata->usbcss_hs.xtalk.xtalk_config); + return 0; +} + +static int create_sysfs_entry_file(struct wcd939x_priv *wcd939x, char *name, int mode, + int index, struct kobject *parent) +{ + struct usbcss_hs_attr *usbc_attr; + char *name_copy; + + usbc_attr = devm_kmalloc(wcd939x->dev, sizeof(*usbc_attr), GFP_KERNEL); + if (!usbc_attr) + return -ENOMEM; + + name_copy = devm_kstrdup(wcd939x->dev, name, GFP_KERNEL); + if (!name_copy) + return -ENOMEM; + + usbc_attr->priv = wcd939x; + usbc_attr->index = index; + usbc_attr->attr.attr.name = name_copy; + usbc_attr->attr.attr.mode = mode; + usbc_attr->attr.show = usbcss_sysfs_show; + usbc_attr->attr.store = usbcss_sysfs_store; + sysfs_attr_init(&usbc_attr->attr.attr); + + return sysfs_create_file(parent, &usbc_attr->attr.attr); +} + +static int usbcss_hs_sysfs_init(struct wcd939x_priv *wcd939x) +{ + int rc = 0; + int i = 0; + struct kobject *kobj = NULL; + + if (!wcd939x || !wcd939x->dev) { + pr_err("%s: Invalid wcd939x private data.\n", __func__); + return -EINVAL; + } + + kobj = kobject_create_and_add("usbcss_hs", kernel_kobj); + if (!kobj) { + dev_err(wcd939x->dev, "%s: Could not create the USBC-SS HS kobj.\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < ARRAY_SIZE(usbcss_sysfs_files); i++) { + rc = create_sysfs_entry_file(wcd939x, usbcss_sysfs_files[i], + 0644, i, kobj); + } + + return 0; +} + +static void wcd939x_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) +{ + struct snd_soc_component *component = mbhc->component; + struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); + struct wcd939x_pdata *pdata = dev_get_platdata(wcd939x->dev); + s16 reg0, reg1, reg2, reg3, reg4; + uint32_t zdiff_val = 0, r_gnd_int_fet_mohms = 0, rl_eff_l_mohms = 0, rl_eff_r_mohms = 0; + uint32_t r_gnd_ext_fet_mohms = 0, r_aud_ext_fet_mohms = 0, r_gnd_res_tot_mohms = 0; + uint32_t r_gnd_par_tot_mohms = 0, r_gnd_par_route1_mohms = 0; + uint32_t aud_tap = LINEARIZER_DEFAULT_TAP, zdiff_counter = 0, zdiff_sum = 0; + uint32_t *zdiff = &zdiff_val; + s32 z_L_R_delta_mohms = 0; + int32_t z1L, z1R, z1Ls, z1Diff; + int zMono, z_diff1, z_diff2; + size_t i; + bool is_fsm_disable = false, calculate_lin_aud_tap = false, gnd_ext_fet_updated = false; + struct wcd939x_mbhc_zdet_param zdet_param = {4, 0, 6, 0x18, 0x60, 0x78}; + struct wcd939x_mbhc_zdet_param *zdet_param_ptr = &zdet_param; + s16 d1[] = {0, 30, 30, 6}; +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + uint32_t cached_regs[4][2] = {{WCD_USBSS_EXT_LIN_EN, 0}, {WCD_USBSS_EXT_SW_CTRL_1, 0}, + {WCD_USBSS_MG1_BIAS, 0}, {WCD_USBSS_MG2_BIAS, 0}}; + uint32_t l_3_6V_regs[4][2] = {{WCD_USBSS_EXT_LIN_EN, 0x00}, {WCD_USBSS_EXT_SW_CTRL_1, 0x00}, + {WCD_USBSS_MG1_BIAS, 0x0E}, {WCD_USBSS_MG2_BIAS, 0x0E}}; + uint32_t diff_regs[2][2] = {{WCD_USBSS_EXT_LIN_EN, 0x00}, {WCD_USBSS_EXT_SW_CTRL_1, 0x00}}; +#endif + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + + /* Turn on RX supplies */ + if (wcd939x->version == WCD939X_VERSION_2_0) { + /* Start up Buck/Flyback, Enable RX bias, Use MBHC RCO for MBHC Zdet, Enable Vneg */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x4E, 0x4E); + /* Wait 100us for settling */ + usleep_range(100, 110); + /* Enable VNEGDAC_LDO */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x10, 0x10); + /* Wait 100us for settling */ + usleep_range(100, 110); + /* Keep PA left/right channels disabled */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x01, 0x01); + /* Enable VPOS */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x20, 0x20); + /* Wait 500us for settling */ + usleep_range(500, 510); + } + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* Cache relevant USB-SS registers */ + wcd_usbss_register_update(cached_regs, WCD_USBSS_READ, ARRAY_SIZE(cached_regs)); + /* Disable 2k pulldown on MG for improved measurement */ + wcd_usbss_register_update(l_3_6V_regs, WCD_USBSS_WRITE, ARRAY_SIZE(l_3_6V_regs)); +#endif + + /* Store register values */ + reg0 = snd_soc_component_read(component, WCD939X_MBHC_BTN5); + reg1 = snd_soc_component_read(component, WCD939X_MBHC_BTN6); + reg2 = snd_soc_component_read(component, WCD939X_MBHC_BTN7); + reg3 = snd_soc_component_read(component, WCD939X_CTL_CLK); + reg4 = snd_soc_component_read(component, WCD939X_ZDET_ANA_CTL); + + /* Disable the detection FSM */ + if (snd_soc_component_read(component, WCD939X_MBHC_ELECT) & 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_MECH, 0x01, 0x00); + + /* Disable surge protection before impedance detection. + * This is done to give correct value for high impedance. + */ + regmap_update_bits(wcd939x->regmap, + WCD939X_HPHLR_SURGE_EN, 0xC0, 0x00); + /* 1ms delay needed after disable surge protection */ + usleep_range(1000, 1010); + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* Disable sense switch and MIC for USB-C analog platforms */ + if (mbhc->mbhc_cfg->enable_usbc_analog) { + wcd_usbss_set_switch_settings_enable(SENSE_SWITCHES, USBSS_SWITCH_DISABLE); + wcd_usbss_set_switch_settings_enable(MIC_SWITCHES, USBSS_SWITCH_DISABLE); + } +#endif + + /* L-channel impedance */ + wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + if ((z1L == WCD939X_ZDET_FLOATING_IMPEDANCE) || (z1L > WCD939X_ZDET_VAL_100K)) { + *zl = WCD939X_ZDET_FLOATING_IMPEDANCE; + } else { + *zl = z1L; + wcd939x_wcd_mbhc_qfuse_cal(component, zl, 0); + dev_dbg(component->dev, "%s: Calibrated left SE measurement is %d(mohms)\n", + __func__, *zl); + apply_zdet_correction(zl, ZDET_SE, pdata->usbcss_hs.se_slope_factor_times_1000, + pdata->usbcss_hs.diff_slope_factor_times_1000); + } + pdata->usbcss_hs.aud.l.zval = *zl; + + if (mbhc->mbhc_cfg->enable_usbc_analog) { + dev_dbg(component->dev, + "%s: Calibrated and adjusted left SE measurement is %d(mohms)\n", __func__, + *zl); + } else { + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(mohms)\n", + __func__, *zl); + } + + /* R-channel impedance */ + wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if ((z1R == WCD939X_ZDET_FLOATING_IMPEDANCE) || (z1R > WCD939X_ZDET_VAL_100K)) { + *zr = WCD939X_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R; + wcd939x_wcd_mbhc_qfuse_cal(component, zr, 4); + dev_dbg(component->dev, "%s: Calibrated right SE measurement is %d(mohms)\n", + __func__, *zr); + apply_zdet_correction(zr, ZDET_SE, pdata->usbcss_hs.se_slope_factor_times_1000, + pdata->usbcss_hs.diff_slope_factor_times_1000); + } + pdata->usbcss_hs.aud.r.zval = *zr; + + + if (mbhc->mbhc_cfg->enable_usbc_analog) { + dev_dbg(component->dev, + "%s: Calibrated and adjusted right SE measurement is %d(mohms)\n", __func__, + *zr); + } else { + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(mohms)\n", + __func__, *zr); + /* Convert from mohms to ohms (rounded) */ + *zl = (*zl + OHMS_TO_MILLIOHMS / 2) / OHMS_TO_MILLIOHMS; + *zr = (*zr + OHMS_TO_MILLIOHMS / 2) / OHMS_TO_MILLIOHMS; + goto mono_stereo_detection; + } + + /* Differential measurement L to R */ +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* Disable AGND switch */ + wcd_usbss_set_switch_settings_enable(AGND_SWITCHES, USBSS_SWITCH_DISABLE); + wcd_usbss_register_update(diff_regs, WCD_USBSS_WRITE, ARRAY_SIZE(diff_regs)); +#endif + /* Enable HPHR NCLAMP */ + regmap_update_bits(wcd939x->regmap, WCD939X_HPHLR_SURGE_MISC1, 0x08, 0x08); + /* Wait 3ms for settling */ + usleep_range(3000, 3010); + /* Differential impedance */ + for (i = 0; i < NUM_DIFF_MEAS; i++) { + wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1Diff, NULL, d1); + if ((z1Diff == WCD939X_ZDET_FLOATING_IMPEDANCE) || + (z1Diff > WCD939X_ZDET_VAL_100K)) { + } else { + *zdiff = z1Diff; + wcd939x_wcd_mbhc_qfuse_cal(component, zdiff, 0); + dev_dbg(component->dev, + "%s: Calibrated differential measurement %d is %d(mohms)\n", + __func__, i + 1, *zdiff); + apply_zdet_correction(zdiff, ZDET_DIFF, + pdata->usbcss_hs.se_slope_factor_times_1000, + pdata->usbcss_hs.diff_slope_factor_times_1000); + zdiff_sum += *zdiff; + zdiff_counter++; + } + dev_dbg(component->dev, + "%s: Calibrated and adjusted differential measurement %d is %d(mohms)\n", + __func__, i + 1, *zdiff); + } + /* Take average of measurements */ + if (zdiff_counter == 0) + *zdiff = WCD939X_ZDET_FLOATING_IMPEDANCE; + else + *zdiff = zdiff_sum / zdiff_counter; + /* Store the average of the measurements */ + pdata->usbcss_hs.zdiffval = *zdiff; + dev_dbg(component->dev, "%s: %s %d(mohms)\n", __func__, + "Average of the calibrated and adjusted differential measurement(s) is", *zdiff); + /* Disable HPHR NCLAMP */ + regmap_update_bits(wcd939x->regmap, WCD939X_HPHLR_SURGE_MISC1, 0x08, 0x00); +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* Enable AGND switch */ + wcd_usbss_set_switch_settings_enable(AGND_SWITCHES, USBSS_SWITCH_ENABLE); + /* Get ground internal resistance based on orientation */ + if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU2_ORIENTATION_A) { + r_gnd_int_fet_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_int_fet_mohms; + r_gnd_par_route1_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_par_route1_mohms; + r_gnd_par_tot_mohms = pdata->usbcss_hs.gnd.sbu2.r_gnd_par_tot_mohms; + } else if (wcd_usbss_get_sbu_switch_orientation() == GND_SBU1_ORIENTATION_B) { + r_gnd_int_fet_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_int_fet_mohms; + r_gnd_par_route1_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_par_route1_mohms; + r_gnd_par_tot_mohms = pdata->usbcss_hs.gnd.sbu1.r_gnd_par_tot_mohms; + } else { + dev_dbg(component->dev, "%s: Invalid SBU switch orientation\n", __func__); + *zl = 0; + *zr = 0; + goto default_vals; + } +#endif + z_L_R_delta_mohms = *zl - *zr; + dev_dbg(component->dev, "%s: %s : %d mohms\n", __func__, + "The difference between the L and R SE measurements (L - R) is", z_L_R_delta_mohms); + + /* Ground path resistance */ + /* Use DTSI params for high zdet SE measurements */ + if (pdata->usbcss_hs.aud.l.zval > ZDET_ACC_LMT_MOHMS || + pdata->usbcss_hs.aud.r.zval > ZDET_ACC_LMT_MOHMS) { + r_gnd_res_tot_mohms = pdata->usbcss_hs.gnd.rdson_mohms + r_gnd_par_tot_mohms + + r_gnd_int_fet_mohms; + pdata->usbcss_hs.gnd.r_common_gnd_mohms = r_gnd_res_tot_mohms - + r_gnd_int_fet_mohms - + r_gnd_par_route1_mohms; + dev_dbg(component->dev, "%s: %s %d %s\n", __func__, + "The r_common_gnd value determined by DTSI parameters,", + pdata->usbcss_hs.gnd.r_common_gnd_mohms, + "mohms, is being used instead of calculating r_common_gnd"); + calculate_lin_aud_tap = false; + } else { + r_gnd_res_tot_mohms = (*zl + *zr - *zdiff + pdata->usbcss_hs.aud.r_surge_mohms) / 2; + /* Offset to account for using 3.6V SE measurements */ + r_gnd_res_tot_mohms = (pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms >= 0) ? + r_gnd_res_tot_mohms - + (u32) (s32) pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms : + r_gnd_res_tot_mohms + + (u32) (s32) (-1 * pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms); + /* Compute r_common_gnd */ + get_r_common_gnd(wcd939x, r_gnd_res_tot_mohms, r_gnd_int_fet_mohms, + r_gnd_par_route1_mohms); + /* Re-calculate ground path resistance based on r_common_gnd */ + r_gnd_res_tot_mohms = pdata->usbcss_hs.gnd.r_common_gnd_mohms + + r_gnd_int_fet_mohms + r_gnd_par_route1_mohms; + calculate_lin_aud_tap = true; + } + dev_dbg(component->dev, "%s: r_gnd_res_tot_mohms is : %d mohms\n", __func__, + r_gnd_res_tot_mohms); + /* Print r_common_gnd buffer */ + for (i = 0; i < R_COMMON_GND_BUFFER_SIZE; i++) { + dev_dbg(component->dev, "%s: Element %d in r_common_gnd_buffer is : %d mohms\n", + __func__, i + 1, pdata->usbcss_hs.gnd.r_cm_gnd_buffer.data[i]); + } + /* Apply r_common_gnd offset */ + pdata->usbcss_hs.gnd.r_common_gnd_mohms = + (pdata->usbcss_hs.gnd.r_common_gnd_offset >= 0) ? + pdata->usbcss_hs.gnd.r_common_gnd_mohms + + (u32) pdata->usbcss_hs.gnd.r_common_gnd_offset : + pdata->usbcss_hs.gnd.r_common_gnd_mohms - + (u32) (-1 * pdata->usbcss_hs.gnd.r_common_gnd_offset); + + /* Ground external FET */ + r_gnd_ext_fet_mohms = r_gnd_res_tot_mohms - r_gnd_par_tot_mohms - r_gnd_int_fet_mohms; + dev_dbg(component->dev, "%s: r_gnd_ext_fet_mohms is : %d mohms\n", __func__, + r_gnd_ext_fet_mohms); + + /* Audio external FET */ + r_aud_ext_fet_mohms = (pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms >= 0) ? + r_gnd_ext_fet_mohms + (u32) (s32) pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms : + r_gnd_ext_fet_mohms - (u32) (s32) (-1 * pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms); + dev_dbg(component->dev, "%s: r_aud_ext_fet_mohms is : %d mohms\n", __func__, + r_aud_ext_fet_mohms); + + /* Compute effective load resistance */ + rl_eff_l_mohms = *zl - pdata->usbcss_hs.aud.l.r_aud_int_fet_mohms - r_aud_ext_fet_mohms - + r_gnd_res_tot_mohms; + rl_eff_r_mohms = *zr - pdata->usbcss_hs.aud.r.r_aud_int_fet_mohms - r_aud_ext_fet_mohms - + r_gnd_res_tot_mohms; + + /* Store z values */ + *zl = (rl_eff_l_mohms - R_CONN_PAR_LOAD_POS_MOHMS - pdata->usbcss_hs.aud.l.r3 + + OHMS_TO_MILLIOHMS / 2) / OHMS_TO_MILLIOHMS; + dev_dbg(component->dev, "%s: rload_l is : %d mohms\n", __func__, + rl_eff_l_mohms - R_CONN_PAR_LOAD_POS_MOHMS - pdata->usbcss_hs.aud.l.r3); + *zr = (rl_eff_r_mohms - R_CONN_PAR_LOAD_POS_MOHMS - pdata->usbcss_hs.aud.r.r3 + + OHMS_TO_MILLIOHMS / 2) / OHMS_TO_MILLIOHMS; + dev_dbg(component->dev, "%s: rload_r is : %d mohms\n", __func__, + rl_eff_r_mohms - R_CONN_PAR_LOAD_POS_MOHMS - pdata->usbcss_hs.aud.r.r3); + + /* Check bounds on effective load values and store the value */ + if (rl_eff_l_mohms > MAX_RL_EFF_MOHMS) + rl_eff_l_mohms = MAX_RL_EFF_MOHMS; + else if (rl_eff_l_mohms < MIN_RL_EFF_MOHMS) + rl_eff_l_mohms = MIN_RL_EFF_MOHMS; + pdata->usbcss_hs.aud.l.r_load_eff_mohms = rl_eff_l_mohms; + if (rl_eff_r_mohms > MAX_RL_EFF_MOHMS) + rl_eff_r_mohms = MAX_RL_EFF_MOHMS; + else if (rl_eff_r_mohms < MIN_RL_EFF_MOHMS) + rl_eff_r_mohms = MIN_RL_EFF_MOHMS; + pdata->usbcss_hs.aud.r.r_load_eff_mohms = rl_eff_r_mohms; + + /* Update FET values and resistances */ + update_ext_fet_res(pdata, r_aud_ext_fet_mohms, r_gnd_ext_fet_mohms); + + /* Update xtalk params */ + /* For SE measurements greater than ZDET_SE_MAX_MOHMS, use default xtalk values */ + if (pdata->usbcss_hs.aud.l.zval > ZDET_SE_MAX_MOHMS || + pdata->usbcss_hs.aud.r.zval > ZDET_SE_MAX_MOHMS) { + pdata->usbcss_hs.xtalk.scale_l = MAX_XTALK_SCALE; + pdata->usbcss_hs.xtalk.scale_r = MAX_XTALK_SCALE; + pdata->usbcss_hs.xtalk.alpha_l = MIN_XTALK_ALPHA; + pdata->usbcss_hs.xtalk.alpha_r = MIN_XTALK_ALPHA; + dev_dbg(component->dev, "%s: %s %d, %s\n", + __func__, "The SE zdet measurement is greater than ZDET_SE_MAX_MOHMS,", + ZDET_SE_MAX_MOHMS, + "so the default xtalk scale and alpha values will be used"); + } else { + update_xtalk_scale_and_alpha(wcd939x); + /* Compute updated linearizer tap */ + if (calculate_lin_aud_tap) { + if (r_gnd_ext_fet_mohms < pdata->usbcss_hs.gnd.gnd_ext_fet_min_mohms) { + r_gnd_ext_fet_mohms = pdata->usbcss_hs.gnd.gnd_ext_fet_min_mohms; + gnd_ext_fet_updated = true; + } + if (r_gnd_ext_fet_mohms > GND_EXT_FET_MAX_MOHMS) { + r_gnd_ext_fet_mohms = GND_EXT_FET_MAX_MOHMS; + gnd_ext_fet_updated = true; + } + if (gnd_ext_fet_updated) { + dev_dbg(component->dev, "%s: %s %d mohms\n", __func__, + "Updated (for linearizer) r_gnd_ext_fet_mohms is :", + r_gnd_ext_fet_mohms); + /* Audio external FET */ + r_aud_ext_fet_mohms = + (pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms >= 0) ? + r_gnd_ext_fet_mohms + + (u32) (s32) pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms : + r_gnd_ext_fet_mohms - + (u32) (s32) (-1 * pdata->usbcss_hs.gnd.gnd_ext_fet_delta_mohms); + dev_dbg(component->dev, "%s: %s %d mohms\n", __func__, + "Updated (for linearizer) r_aud_ext_fet_mohms is :", + r_aud_ext_fet_mohms); + /* Update FET values and resistances */ + update_ext_fet_res(pdata, r_aud_ext_fet_mohms, r_gnd_ext_fet_mohms); + } + get_linearizer_taps(pdata, &aud_tap); + } + } + + /* Print xtalk params */ + dev_dbg(component->dev, "%s: Left-channel: Xtalk scale is 0x%x and alpha is 0x%x\n", + __func__, pdata->usbcss_hs.xtalk.scale_l, pdata->usbcss_hs.xtalk.alpha_l); + dev_dbg(component->dev, "%s: Right-channel: Xtalk scale is 0x%x and alpha is 0x%x\n", + __func__, pdata->usbcss_hs.xtalk.scale_r, pdata->usbcss_hs.xtalk.alpha_r); + + /* Revert r_common_gnd offset */ + pdata->usbcss_hs.gnd.r_common_gnd_mohms = (pdata->usbcss_hs.gnd.r_common_gnd_offset >= 0) ? + pdata->usbcss_hs.gnd.r_common_gnd_mohms - + (u32) pdata->usbcss_hs.gnd.r_common_gnd_offset : + pdata->usbcss_hs.gnd.r_common_gnd_mohms + + (u32) (-1 * pdata->usbcss_hs.gnd.r_common_gnd_offset); + +mono_stereo_detection: + /* Mono/stereo detection */ + if ((*zl == WCD939X_ZDET_FLOATING_IMPEDANCE) && (*zr == WCD939X_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == WCD939X_ZDET_FLOATING_IMPEDANCE) || + (*zr == WCD939X_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, WCD939X_R_ATEST, 0x02, 0x02); + snd_soc_component_update_bits(component, WCD939X_PA_CTL2, 0x40, 0x01); + wcd939x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1Ls, NULL, d1); + snd_soc_component_update_bits(component, WCD939X_PA_CTL2, 0x40, 0x00); + snd_soc_component_update_bits(component, WCD939X_R_ATEST, 0x02, 0x00); + z1Ls /= 1000; + wcd939x_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; + } + goto zdet_complete; +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) +default_vals: + pdata->usbcss_hs.xtalk.scale_l = MAX_XTALK_SCALE; + pdata->usbcss_hs.xtalk.scale_r = MAX_XTALK_SCALE; + pdata->usbcss_hs.xtalk.alpha_l = MIN_XTALK_ALPHA; + pdata->usbcss_hs.xtalk.alpha_r = MIN_XTALK_ALPHA; + /* Print xtalk params */ + dev_dbg(component->dev, + "%s: Left-channel: Xtalk scale is 0x%x and alpha is 0x%x\n", __func__, + pdata->usbcss_hs.xtalk.scale_l, pdata->usbcss_hs.xtalk.alpha_l); + dev_dbg(component->dev, + "%s: Right-channel: Xtalk scale is 0x%x and alpha is 0x%x\n", __func__, + pdata->usbcss_hs.xtalk.scale_r, pdata->usbcss_hs.xtalk.alpha_r); +#endif +zdet_complete: + /* Configure linearizer */ +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + wcd_usbss_set_linearizer_sw_tap(aud_tap, LINEARIZER_DEFAULT_TAP); +#endif + /* Print linearizer values */ + dev_dbg(component->dev, "%s: Linearizer aud_tap is 0x%x\n", + __func__, aud_tap); +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* Enable sense switch and MIC for USB-C analog platforms */ + if (mbhc->mbhc_cfg->enable_usbc_analog) { + wcd_usbss_set_switch_settings_enable(SENSE_SWITCHES, USBSS_SWITCH_ENABLE); + wcd_usbss_set_switch_settings_enable(MIC_SWITCHES, USBSS_SWITCH_ENABLE); + } +#endif + /* Enable surge protection again after impedance detection for platforms other than USB-C + * analog platforms + */ + if (!(mbhc->mbhc_cfg->enable_usbc_analog)) + regmap_update_bits(wcd939x->regmap, WCD939X_HPHLR_SURGE_EN, 0xC0, 0xC0); + + snd_soc_component_write(component, WCD939X_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD939X_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD939X_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (mbhc->hphl_swh) + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD939X_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD939X_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd939x->regmap, + WCD939X_MBHC_ELECT, 0x80, 0x80); + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + wcd_usbss_register_update(cached_regs, WCD_USBSS_WRITE, ARRAY_SIZE(cached_regs)); +#endif + + /* Turn off RX supplies */ + if (wcd939x->version == WCD939X_VERSION_2_0) { + /* Set VPOS to be controlled by RX */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x20, 0x00); + /* Wait 500us for settling */ + usleep_range(500, 510); + /* Set PA Left/Right channels and VNEGDAC_LDO to be controlled by RX */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x11, 0x00); + /* Wait 100us for settling */ + usleep_range(100, 110); + /* Set Vneg mode and enable to be controlled by RX */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x06, 0x00); + /* Wait 100us for settling */ + usleep_range(100, 110); + /* Set RX bias to be controlled by RX and set Buck/Flyback back to SWR Rx clock */ + regmap_update_bits(wcd939x->regmap, WCD939X_ZDET_VNEG_CTL, 0x48, 0x00); + } +} + +static void wcd939x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD939X_MBHC_MECH, + 0x02, 0x02); + snd_soc_component_update_bits(component, WCD939X_MBHC_MECH, + 0x40, 0x40); + } else { + snd_soc_component_update_bits(component, WCD939X_MBHC_MECH, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD939X_MBHC_MECH, + 0x02, 0x00); + } +} + +static void wcd939x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, WCD939X_PA_CTL2, + 0x40, 0x40); + snd_soc_component_update_bits(component, WCD939X_PA_CTL2, + 0x10, 0x10); + } else { + snd_soc_component_update_bits(component, WCD939X_PA_CTL2, + 0x40, 0x00); + snd_soc_component_update_bits(component, WCD939X_PA_CTL2, + 0x10, 0x00); + } +} + +static void wcd939x_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, WCD939X_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, WCD939X_CTL_2, + 0x0C, R_OFF << 2); + return; + } + + snd_soc_component_update_bits(component, WCD939X_CTL_2, + 0x0C, mbhc->moist_rref << 2); +} + +static void wcd939x_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, WCD939X_CTL_2, + 0x0C, mbhc->moist_rref << 2); + else + snd_soc_component_update_bits(component, WCD939X_CTL_2, + 0x0C, R_OFF << 2); +} + +static bool wcd939x_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, WCD939X_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, WCD939X_CTL_2, + 0x0C, R_OFF << 2); + goto done; + } + + /* + * If moisture_en is already enabled, then skip to plug type + * detection. + */ + if ((snd_soc_component_read(component, WCD939X_CTL_2) & 0x0C)) + goto done; + + wcd939x_mbhc_moisture_detect_en(mbhc, true); + /* Read moisture comparator status */ + ret = ((snd_soc_component_read(component, WCD939X_FSM_STATUS) + & 0x20) ? 0 : 1); + +done: + return ret; + +} + +static void wcd939x_mbhc_moisture_polling_ctrl(struct wcd_mbhc *mbhc, + bool enable) +{ + struct snd_soc_component *component = mbhc->component; + + snd_soc_component_update_bits(component, + WCD939X_MOISTURE_DET_POLLING_CTRL, + 0x04, (enable << 2)); +} + +static void wcd939x_mbhc_bcs_enable(struct wcd_mbhc *mbhc, + bool bcs_enable) +{ + if (bcs_enable) + wcd939x_disable_bcs_before_slow_insert(mbhc->component, false); + else + wcd939x_disable_bcs_before_slow_insert(mbhc->component, true); +} + +static void wcd939x_surge_reset_routine(struct wcd_mbhc *mbhc) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(mbhc->component); + + regcache_mark_dirty(wcd939x->regmap); + regcache_sync(wcd939x->regmap); +} + +static void wcd939x_mbhc_zdet_leakage_resistance(struct wcd_mbhc *mbhc, + bool enable) +{ + if (enable) + snd_soc_component_update_bits(mbhc->component, WCD939X_ZDET_BIAS_CTL, + 0x80, 0x80); /* disable 1M pull-up */ + else + snd_soc_component_update_bits(mbhc->component, WCD939X_ZDET_BIAS_CTL, + 0x80, 0x00); /* enable 1M pull-up */ +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .request_irq = wcd939x_mbhc_request_irq, + .irq_control = wcd939x_mbhc_irq_control, + .free_irq = wcd939x_mbhc_free_irq, + .clk_setup = wcd939x_mbhc_clk_setup, + .map_btn_code_to_num = wcd939x_mbhc_btn_to_num, + .mbhc_bias = wcd939x_mbhc_mbhc_bias_control, + .set_btn_thr = wcd939x_mbhc_program_btn_thr, + .lock_sleep = wcd939x_mbhc_lock_sleep, + .register_notifier = wcd939x_mbhc_register_notifier, + .micbias_enable_status = wcd939x_mbhc_micb_en_status, + .hph_pa_on_status = wcd939x_mbhc_hph_pa_on_status, + .hph_pull_up_control_v2 = wcd939x_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = wcd939x_mbhc_request_micbias, + .mbhc_micb_ramp_control = wcd939x_mbhc_micb_ramp_control, + .get_hwdep_fw_cal = wcd939x_get_hwdep_fw_cal, + .mbhc_micb_ctrl_thr_mic = wcd939x_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = wcd939x_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = wcd939x_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = wcd939x_mbhc_hph_pull_down_ctrl, + .mbhc_moisture_config = wcd939x_mbhc_moisture_config, + .mbhc_get_moisture_status = wcd939x_mbhc_get_moisture_status, + .mbhc_moisture_polling_ctrl = wcd939x_mbhc_moisture_polling_ctrl, + .mbhc_moisture_detect_en = wcd939x_mbhc_moisture_detect_en, + .bcs_enable = wcd939x_mbhc_bcs_enable, + .surge_reset_routine = wcd939x_surge_reset_routine, + .zdet_leakage_resistance = wcd939x_mbhc_zdet_leakage_resistance, +}; + +static int wcd939x_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_mbhc *wcd939x_mbhc = wcd939x_soc_get_mbhc(component); + struct wcd_mbhc *mbhc; + + if (!wcd939x_mbhc) { + dev_err_ratelimited(component->dev, "%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + + mbhc = &wcd939x_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 wcd939x_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 wcd939x_mbhc *wcd939x_mbhc = wcd939x_soc_get_mbhc(component); + + if (!wcd939x_mbhc) { + dev_err_ratelimited(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(&wcd939x_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, + wcd939x_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + wcd939x_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + wcd939x_hph_impedance_get, NULL), +}; + +/* + * wcd939x_mbhc_get_impedance: get impedance of headphone + * left and right channels + * @wcd939x_mbhc: handle to struct wcd939x_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 wcd939x_mbhc_get_impedance(struct wcd939x_mbhc *wcd939x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (!wcd939x_mbhc) { + pr_err_ratelimited("%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + if (!zl || !zr) { + pr_err_ratelimited("%s: zl or zr null!\n", __func__); + return -EINVAL; + } + + return wcd_mbhc_get_impedance(&wcd939x_mbhc->wcd_mbhc, zl, zr); +} +EXPORT_SYMBOL(wcd939x_mbhc_get_impedance); + +/* + * wcd939x_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 wcd939x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct wcd939x_priv *wcd939x = NULL; + struct wcd939x_mbhc *wcd939x_mbhc = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd939x = snd_soc_component_get_drvdata(component); + if (!wcd939x) { + pr_err_ratelimited("%s: wcd939x is NULL\n", __func__); + return -EINVAL; + } + + wcd939x_mbhc = wcd939x->mbhc; + if (!wcd939x_mbhc) { + dev_err_ratelimited(component->dev, "%s: mbhc not initialized!\n", __func__); + return -EINVAL; + } + + return wcd_mbhc_start(&wcd939x_mbhc->wcd_mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(wcd939x_mbhc_hs_detect); + +/* + * wcd939x_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality + * @component: handle to snd_soc_component * + */ +void wcd939x_mbhc_hs_detect_exit(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = NULL; + struct wcd939x_mbhc *wcd939x_mbhc = NULL; + + if (!component) { + pr_err_ratelimited("%s: component is NULL\n", __func__); + return; + } + + wcd939x = snd_soc_component_get_drvdata(component); + if (!wcd939x) { + pr_err_ratelimited("%s: wcd939x is NULL\n", __func__); + return; + } + + wcd939x_mbhc = wcd939x->mbhc; + if (!wcd939x_mbhc) { + dev_err_ratelimited(component->dev, "%s: mbhc not initialized!\n", __func__); + return; + } + wcd_mbhc_stop(&wcd939x_mbhc->wcd_mbhc); +} +EXPORT_SYMBOL(wcd939x_mbhc_hs_detect_exit); + +/* + * wcd939x_mbhc_ssr_down: stop mbhc during + * wcd939x subsystem restart + * mbhc: pointer to wcd937x_mbhc structure + * component: handle to snd_soc_component * + */ +void wcd939x_mbhc_ssr_down(struct wcd939x_mbhc *mbhc, + struct snd_soc_component *component) +{ + struct wcd_mbhc *wcd_mbhc = NULL; + + if (!mbhc || !component) + return; + + wcd_mbhc = &mbhc->wcd_mbhc; + if (!wcd_mbhc) { + dev_err_ratelimited(component->dev, "%s: wcd_mbhc is NULL\n", __func__); + return; + } + + wcd939x_mbhc_hs_detect_exit(component); + wcd_mbhc_deinit(wcd_mbhc); +} +EXPORT_SYMBOL(wcd939x_mbhc_ssr_down); + +/* + * wcd939x_mbhc_post_ssr_init: initialize mbhc for + * wcd939x post subsystem restart + * @mbhc: poniter to wcd939x_mbhc structure + * @component: handle to snd_soc_component * + * + * return 0 if mbhc_init is success or error code in case of failure + */ +int wcd939x_mbhc_post_ssr_init(struct wcd939x_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; + } + + /* Reset detection type to insertion after SSR recovery */ + snd_soc_component_update_bits(component, WCD939X_MBHC_MECH, + 0x20, 0x20); + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, WCD939X_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto done; + } + +done: + return ret; +} +EXPORT_SYMBOL(wcd939x_mbhc_post_ssr_init); + +/* + * wcd939x_mbhc_init: initialize mbhc for wcd939x + * @mbhc: poniter to wcd939x_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 wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + struct wcd939x_mbhc *wcd939x_mbhc = NULL; + struct wcd_mbhc *wcd_mbhc = NULL; + int ret = 0; + struct wcd939x_pdata *pdata; + struct wcd939x_priv *wcd939x; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + wcd939x_mbhc = devm_kzalloc(component->dev, sizeof(struct wcd939x_mbhc), + GFP_KERNEL); + if (!wcd939x_mbhc) + return -ENOMEM; + + wcd939x_mbhc->fw_data = fw_data; + BLOCKING_INIT_NOTIFIER_HEAD(&wcd939x_mbhc->notifier); + wcd_mbhc = &wcd939x_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; + + /* Down ramp timer set-up */ + timer_setup(&wcd939x_mbhc->rdown_timer, rdown_timer_callback, 0); + wcd939x_mbhc->rdown_prev_iter = 0; + wcd939x_mbhc->rdown_timer_complete = false; + + pdata = dev_get_platdata(component->dev); + if (!pdata) { + dev_err(component->dev, "%s: pdata pointer is NULL\n", + __func__); + ret = -EINVAL; + goto err; + } + wcd_mbhc->micb_mv = pdata->micbias.micb2_mv; + + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, + &intr_ids, wcd_mbhc_registers, + WCD939X_ZDET_SUPPORTED); + if (ret) { + dev_err(component->dev, "%s: mbhc initialization failed\n", + __func__); + goto err; + } + + (*mbhc) = wcd939x_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)); + + wcd939x = dev_get_drvdata(component->dev); + if (!wcd939x) { + dev_err(component->dev, "%s: wcd939x pointer is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + usbcss_hs_sysfs_init(wcd939x); + + return 0; +err: + if (wcd939x_mbhc) + del_timer(&wcd939x_mbhc->rdown_timer); + devm_kfree(component->dev, wcd939x_mbhc); + return ret; +} +EXPORT_SYMBOL(wcd939x_mbhc_init); + +/* + * wcd939x_mbhc_deinit: deinitialize mbhc for wcd939x + * @codec: handle to snd_soc_component * + */ +void wcd939x_mbhc_deinit(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x; + struct wcd939x_mbhc *wcd939x_mbhc; + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return; + } + + wcd939x = snd_soc_component_get_drvdata(component); + if (!wcd939x) { + pr_err("%s: wcd939x is NULL\n", __func__); + return; + } + + wcd939x_mbhc = wcd939x->mbhc; + if (wcd939x_mbhc) { + del_timer(&wcd939x_mbhc->rdown_timer); + wcd_mbhc_deinit(&wcd939x_mbhc->wcd_mbhc); + devm_kfree(component->dev, wcd939x_mbhc); + } +} +EXPORT_SYMBOL(wcd939x_mbhc_deinit); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-mbhc.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-mbhc.h new file mode 100644 index 0000000000..0cf53d5d8f --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-mbhc.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef __WCD939X_MBHC_H__ +#define __WCD939X_MBHC_H__ +#include + +struct wcd939x_mbhc { + struct wcd_mbhc wcd_mbhc; + struct blocking_notifier_head notifier; + struct fw_info *fw_data; + struct timer_list rdown_timer; + int rdown_prev_iter; + bool rdown_timer_complete; +}; + +static inline u32 get_r_gnd_res_tot_mohms(u32 r_gnd_int_fet_mohms, u32 r_gnd_ext_fet_mohms, + u32 r_gnd_par_tot_mohms) +{ + return r_gnd_int_fet_mohms + r_gnd_ext_fet_mohms + r_gnd_par_tot_mohms; +} + +static inline u32 get_r_aud_res_tot_mohms(u32 r_aud_int_fet_mohms, u32 r_aud_ext_fet_mohms, + u32 r_load_eff_mohms) +{ + return r_aud_int_fet_mohms + r_aud_ext_fet_mohms + r_load_eff_mohms; +} + +#if IS_ENABLED(CONFIG_SND_SOC_WCD939X) +extern int wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data); +extern void wcd939x_mbhc_hs_detect_exit(struct snd_soc_component *component); +extern int wcd939x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg); +extern void wcd939x_mbhc_deinit(struct snd_soc_component *component); +extern void wcd939x_mbhc_ssr_down(struct wcd939x_mbhc *mbhc, + struct snd_soc_component *component); +extern int wcd939x_mbhc_post_ssr_init(struct wcd939x_mbhc *mbhc, + struct snd_soc_component *component); +extern int wcd939x_mbhc_get_impedance(struct wcd939x_mbhc *wcd939x_mbhc, + uint32_t *zl, uint32_t *zr); +#else +static inline int wcd939x_mbhc_init(struct wcd939x_mbhc **mbhc, + struct snd_soc_component *component, + struct fw_info *fw_data) +{ + return 0; +} +static inline void wcd939x_mbhc_hs_detect_exit( + struct snd_soc_component *component) +{ +} +static inline int wcd939x_mbhc_hs_detect(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + return 0; +} +static inline void wcd939x_mbhc_deinit(struct snd_soc_component *component) +{ +} +static inline void wcd939x_mbhc_ssr_down(struct wcd939x_mbhc *mbhc, + struct snd_soc_component *component) +{ +} +static inline int wcd939x_mbhc_post_ssr_init(struct wcd939x_mbhc *mbhc, + struct snd_soc_component *component) +{ + return 0; +} + +static inline int wcd939x_mbhc_get_impedance(struct wcd939x_mbhc *wcd939x_mbhc, + uint32_t *zl, uint32_t *zr) +{ + if (zl) + *zl = 0; + if (zr) + *zr = 0; + return -EINVAL; +} +#endif + +#endif /* __WCD939X_MBHC_H__ */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-reg-masks.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-reg-masks.h new file mode 100644 index 0000000000..b8b24135cf --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-reg-masks.h @@ -0,0 +1,2673 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef WCD939X_REG_MASKS_H +#define WCD939X_REG_MASKS_H +#include +#include +#include "wcd939x-registers.h" + +/* Use in conjunction with wcd939x-reg-shifts.c for field values. */ +/* field_value = (register_value & field_mask) >> field_shift */ + +#define FIELD_MASK(register_name, field_name) \ +WCD939X_##register_name##_##field_name##_MASK + +/* WCD939X_ANA_PAGE Fields: */ +#define WCD939X_ANA_PAGE_VALUE_MASK 0xff + +/* WCD939X_BIAS Fields: */ +#define WCD939X_BIAS_ANALOG_BIAS_EN_MASK 0x80 +#define WCD939X_BIAS_PRECHRG_EN_MASK 0x40 +#define WCD939X_BIAS_PRECHRG_CTL_MODE_MASK 0x20 + +/* WCD939X_RX_SUPPLIES Fields: */ +#define WCD939X_RX_SUPPLIES_VPOS_EN_MASK 0x80 +#define WCD939X_RX_SUPPLIES_VNEG_EN_MASK 0x40 +#define WCD939X_RX_SUPPLIES_VPOS_PWR_LVL_MASK 0x08 +#define WCD939X_RX_SUPPLIES_VNEG_PWR_LVL_MASK 0x04 +#define WCD939X_RX_SUPPLIES_REGULATOR_MODE_MASK 0x02 +#define WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE_MASK 0x01 + +/* WCD939X_HPH Fields: */ +#define WCD939X_HPH_HPHL_ENABLE_MASK 0x80 +#define WCD939X_HPH_HPHR_ENABLE_MASK 0x40 +#define WCD939X_HPH_HPHL_REF_ENABLE_MASK 0x20 +#define WCD939X_HPH_HPHR_REF_ENABLE_MASK 0x10 +#define WCD939X_HPH_PWR_LEVEL_MASK 0x0c + +/* WCD939X_EAR Fields: */ +#define WCD939X_EAR_ENABLE_MASK 0x80 +#define WCD939X_EAR_SHORT_PROT_EN_MASK 0x40 +#define WCD939X_EAR_OUT_IMPEDANCE_MASK 0x20 + +/* WCD939X_EAR_COMPANDER_CTL Fields: */ +#define WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG_MASK 0x80 +#define WCD939X_EAR_COMPANDER_CTL_EAR_GAIN_MASK 0x7c +#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_BYP_MASK 0x02 +#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_CLK_EDGE_MASK 0x01 + +/* WCD939X_TX_CH1 Fields: */ +#define WCD939X_TX_CH1_ENABLE_MASK 0x80 +#define WCD939X_TX_CH1_PWR_LEVEL_MASK 0x60 +#define WCD939X_TX_CH1_GAIN_MASK 0x1f + +/* WCD939X_TX_CH2 Fields: */ +#define WCD939X_TX_CH2_ENABLE_MASK 0x80 +#define WCD939X_TX_CH2_HPF1_INIT_MASK 0x40 +#define WCD939X_TX_CH2_HPF2_INIT_MASK 0x20 +#define WCD939X_TX_CH2_GAIN_MASK 0x1f + +/* WCD939X_TX_CH3 Fields: */ +#define WCD939X_TX_CH3_ENABLE_MASK 0x80 +#define WCD939X_TX_CH3_PWR_LEVEL_MASK 0x60 +#define WCD939X_TX_CH3_GAIN_MASK 0x1f + +/* WCD939X_TX_CH4 Fields: */ +#define WCD939X_TX_CH4_ENABLE_MASK 0x80 +#define WCD939X_TX_CH4_HPF3_INIT_MASK 0x40 +#define WCD939X_TX_CH4_HPF4_INIT_MASK 0x20 +#define WCD939X_TX_CH4_GAIN_MASK 0x1f + +/* WCD939X_MICB1_MICB2_DSP_EN_LOGIC Fields: */ +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB1_DSP_OVERRIDE_MASK 0x80 +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB1_DSP_CTRL_MASK 0x60 +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB2_DSP_OVERRIDE_MASK 0x10 +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB2_DSP_CTRL_MASK 0x0c + +/* WCD939X_MICB3_DSP_EN_LOGIC Fields: */ +#define WCD939X_MICB3_DSP_EN_LOGIC_MICB3_DSP_OVERRIDE_MASK 0x80 +#define WCD939X_MICB3_DSP_EN_LOGIC_MICB3_DSP_CTRL_MASK 0x60 + +/* WCD939X_MBHC_MECH Fields: */ +#define WCD939X_MBHC_MECH_L_DET_EN_MASK 0x80 +#define WCD939X_MBHC_MECH_GND_DET_EN_MASK 0x40 +#define WCD939X_MBHC_MECH_MECH_DETECT_TYPE_MASK 0x20 +#define WCD939X_MBHC_MECH_HPHL_PLUG_TYPE_MASK 0x10 +#define WCD939X_MBHC_MECH_GND_PLUG_TYPE_MASK 0x08 +#define WCD939X_MBHC_MECH_MECH_HS_L_PULLUP_COMP_EN_MASK 0x04 +#define WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN_MASK 0x02 +#define WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND_MASK 0x01 + +/* WCD939X_MBHC_ELECT Fields: */ +#define WCD939X_MBHC_ELECT_FSM_EN_MASK 0x80 +#define WCD939X_MBHC_ELECT_BTNDET_ISRC_CTL_MASK 0x70 +#define WCD939X_MBHC_ELECT_ELECT_DET_TYPE_MASK 0x08 +#define WCD939X_MBHC_ELECT_ELECT_SCHMT_ISRC_CTL_MASK 0x06 +#define WCD939X_MBHC_ELECT_BIAS_EN_MASK 0x01 + +/* WCD939X_MBHC_ZDET Fields: */ +#define WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN_MASK 0x80 +#define WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN_MASK 0x40 +#define WCD939X_MBHC_ZDET_ZDET_CHG_EN_MASK 0x20 +#define WCD939X_MBHC_ZDET_ZDET_ILEAK_COMP_EN_MASK 0x10 +#define WCD939X_MBHC_ZDET_ELECT_ISRC_EN_MASK 0x02 + +/* WCD939X_MBHC_RESULT_1 Fields: */ +#define WCD939X_MBHC_RESULT_1_Z_RESULT_LSB_MASK 0xff + +/* WCD939X_MBHC_RESULT_2 Fields: */ +#define WCD939X_MBHC_RESULT_2_Z_RESULT_MSB_MASK 0xff + +/* WCD939X_MBHC_RESULT_3 Fields: */ +#define WCD939X_MBHC_RESULT_3_MIC_SCHMT_RESULT_MASK 0x20 +#define WCD939X_MBHC_RESULT_3_IN2P_CLAMP_STATE_MASK 0x10 +#define WCD939X_MBHC_RESULT_3_BTN_RESULT_MASK 0x07 + +/* WCD939X_MBHC_BTN0 Fields: */ +#define WCD939X_MBHC_BTN0_VTH_MASK 0xfc + +/* WCD939X_MBHC_BTN1 Fields: */ +#define WCD939X_MBHC_BTN1_VTH_MASK 0xfc + +/* WCD939X_MBHC_BTN2 Fields: */ +#define WCD939X_MBHC_BTN2_VTH_MASK 0xfc + +/* WCD939X_MBHC_BTN3 Fields: */ +#define WCD939X_MBHC_BTN3_VTH_MASK 0xfc + +/* WCD939X_MBHC_BTN4 Fields: */ +#define WCD939X_MBHC_BTN4_VTH_MASK 0xfc + +/* WCD939X_MBHC_BTN5 Fields: */ +#define WCD939X_MBHC_BTN5_VTH_MASK 0xfc + +/* WCD939X_MBHC_BTN6 Fields: */ +#define WCD939X_MBHC_BTN6_VTH_MASK 0xfc + +/* WCD939X_MBHC_BTN7 Fields: */ +#define WCD939X_MBHC_BTN7_VTH_MASK 0xfc + +/* WCD939X_MICB1 Fields: */ +#define WCD939X_MICB1_ENABLE_MASK 0xc0 +#define WCD939X_MICB1_VOUT_CTL_MASK 0x3f + +/* WCD939X_MICB2 Fields: */ +#define WCD939X_MICB2_ENABLE_MASK 0xc0 +#define WCD939X_MICB2_VOUT_CTL_MASK 0x3f + +/* WCD939X_MICB2_RAMP Fields: */ +#define WCD939X_MICB2_RAMP_RAMP_ENABLE_MASK 0x80 +#define WCD939X_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE_MASK 0x40 +#define WCD939X_MICB2_RAMP_ALLSW_OVRD_ENABLE_MASK 0x20 +#define WCD939X_MICB2_RAMP_SHIFT_CTL_MASK 0x1c +#define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP_MASK 0x03 + +/* WCD939X_MICB3 Fields: */ +#define WCD939X_MICB3_ENABLE_MASK 0xc0 + +/* WCD939X_MICB4 Fields: */ +#define WCD939X_MICB4_ENABLE_MASK 0xc0 + + +/* WCD939X_CTL Fields: */ +#define WCD939X_CTL_BG_FAST_MODE_EN_MASK 0x80 +#define WCD939X_CTL_TX_SCBIAS_REF_SEL_MASK 0x40 +#define WCD939X_CTL_DC_START_UP_EN_MASK 0x20 +#define WCD939X_CTL_TRAN_START_UP_EN_MASK 0x10 +#define WCD939X_CTL_OTA_BIAS_CTL_MASK 0x08 +#define WCD939X_CTL_ATEST_CTL_MASK 0x04 +#define WCD939X_CTL_EFUSE_EN_MASK 0x02 + +/* WCD939X_VBG_FINE_ADJ Fields: */ +#define WCD939X_VBG_FINE_ADJ_VBG_FINE_ADJ_MASK 0xf0 +#define WCD939X_VBG_FINE_ADJ_EN_DTEST_BG_STATUS_MASK 0x08 +#define WCD939X_VBG_FINE_ADJ_PRECHARGE_TIMER_COUNT_MASK 0x07 + + +/* WCD939X_VDDCX_ADJUST Fields: */ +#define WCD939X_VDDCX_ADJUST_RC_ZERO_FREQ_TUNE_MASK 0x0c +#define WCD939X_VDDCX_ADJUST_VDDCX_ADJUST_MASK 0x03 + +/* WCD939X_DISABLE_LDOL Fields: */ +#define WCD939X_DISABLE_LDOL_DISABLE_LDOL_MASK 0x01 + + +/* WCD939X_CTL_CLK Fields: */ +#define WCD939X_CTL_CLK_CLK_SEL_MASK 0x40 +#define WCD939X_CTL_CLK_COMP_CLK_CTL_MASK 0x30 +#define WCD939X_CTL_CLK_COMP_AZ_CTL_MASK 0x0c +#define WCD939X_CTL_CLK_TEST_CLK_EN_MASK 0x02 +#define WCD939X_CTL_CLK_COMP_AVG_BYP_EN_MASK 0x01 + +/* WCD939X_CTL_ANA Fields: */ +#define WCD939X_CTL_ANA_BIAS_SEL_MASK 0x80 + +/* WCD939X_ZDET_VNEG_CTL Fields: */ +#define WCD939X_ZDET_VNEG_CTL_SPARE_BITS_7_6_MASK 0xc0 +#define WCD939X_ZDET_VNEG_CTL_VPOS_EN_MASK 0x20 +#define WCD939X_ZDET_VNEG_CTL_VNEGDAC_LDO_EN_MASK 0x10 +#define WCD939X_ZDET_VNEG_CTL_RXBIAS_EN_MASK 0x08 +#define WCD939X_ZDET_VNEG_CTL_VNEG_MODE_MASK 0x04 +#define WCD939X_ZDET_VNEG_CTL_VNEG_EN_MASK 0x02 +#define WCD939X_ZDET_VNEG_CTL_HPH_DISABLE_MASK 0x01 + +/* WCD939X_ZDET_BIAS_CTL Fields: */ +#define WCD939X_ZDET_BIAS_CTL_ZDET_ILEAK_EN_OVR_MASK 0x80 +#define WCD939X_ZDET_BIAS_CTL_ZDET_ILEAK_COMP_CTL_MASK 0x70 +#define WCD939X_ZDET_BIAS_CTL_ZDET_LDO_IREF_MASK 0x0c +#define WCD939X_ZDET_BIAS_CTL_ZDET_COMP_IREF_MASK 0x03 + +/* WCD939X_CTL_BCS Fields: */ +#define WCD939X_CTL_BCS_FAST_INT_OVRD_EN_MASK 0x80 +#define WCD939X_CTL_BCS_ELECT_REM_FAST_REG_OVRD_MASK 0x40 +#define WCD939X_CTL_BCS_BTN_RELEASE_FAST_REG_OVRD_MASK 0x20 +#define WCD939X_CTL_BCS_BTN_PRESS_FAST_REG_OVRD_MASK 0x10 +#define WCD939X_CTL_BCS_ANC_DET_EN_MASK 0x02 +#define WCD939X_CTL_BCS_DEBUG_1_MASK 0x01 + +/* WCD939X_MOISTURE_DET_FSM_STATUS Fields: */ +#define WCD939X_MOISTURE_DET_FSM_STATUS_ELECT_IN2P_COMP_MASK 0x80 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MECH_HS_G_COMP_MASK 0x40 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MECH_HS_M_COMP_MASK 0x20 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MECH_HS_L_COMP_MASK 0x10 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MOISTURE_INTR_MASK 0x08 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MOISTURE_GTPOLLING_STATUS_MASK 0x04 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MOISTURE_DET_STATUS_MASK 0x02 +#define WCD939X_MOISTURE_DET_FSM_STATUS_ZDET_TIMER_MASK 0x01 + +/* WCD939X_TEST_CTL Fields: */ +#define WCD939X_TEST_CTL_FAST_DBNC_TIMER_MASK 0x30 +#define WCD939X_TEST_CTL_ATEST_MASK 0x0f + + +/* WCD939X_MODE Fields: */ +#define WCD939X_MODE_LDOH_EN_MASK 0x80 +#define WCD939X_MODE_PWRDN_STATE_MASK 0x40 +#define WCD939X_MODE_SLOWRAMP_EN_MASK 0x20 +#define WCD939X_MODE_VOUT_ADJUST_MASK 0x18 +#define WCD939X_MODE_VOUT_COARSE_ADJ_MASK 0x07 + +/* WCD939X_LDOH_BIAS Fields: */ +#define WCD939X_LDOH_BIAS_IBIAS_REF_MASK 0xe0 +#define WCD939X_LDOH_BIAS_IBIAS_ERR_AMP_MASK 0x18 +#define WCD939X_LDOH_BIAS_IBIAS_NATIVE_DEVICE_MASK 0x04 +#define WCD939X_LDOH_BIAS_IBIAS_BUFFER_BLEED_MASK 0x02 +#define WCD939X_LDOH_BIAS_INRUSH_CURRENT_FIX_DIS_MASK 0x01 + +/* WCD939X_STB_LOADS Fields: */ +#define WCD939X_STB_LOADS_STB_LOADS_1_UA_MASK 0xf0 +#define WCD939X_STB_LOADS_STB_LOAD_10_UA_MASK 0x08 +#define WCD939X_STB_LOADS_FORCE_EN_60K_MASK 0x04 +#define WCD939X_STB_LOADS_CLK_GATE_MASK 0x02 + +/* WCD939X_SLOWRAMP Fields: */ +#define WCD939X_SLOWRAMP_SLOWRAMP_IBIAS_MASK 0xc0 +#define WCD939X_SLOWRAMP_SLOWRAMP_RESET_TIME_MASK 0x30 + + +/* WCD939X_TEST_CTL_1 Fields: */ +#define WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL_MASK 0xe0 +#define WCD939X_TEST_CTL_1_EN_VREFGEN_MASK 0x10 +#define WCD939X_TEST_CTL_1_EN_LDO_MASK 0x08 +#define WCD939X_TEST_CTL_1_LDO_BLEEDER_I_CTRL_MASK 0x07 + +/* WCD939X_TEST_CTL_2 Fields: */ +#define WCD939X_TEST_CTL_2_IBIAS_VREFGEN_MASK 0xc0 +#define WCD939X_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_MASK 0x20 +#define WCD939X_TEST_CTL_2_SPAREBIT_MASK 0x18 +#define WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK 0x07 + +/* WCD939X_TEST_CTL_3 Fields: */ +#define WCD939X_TEST_CTL_3_CFILT_REF_EN_MASK 0x80 +#define WCD939X_TEST_CTL_3_RZ_LDO_VAL_MASK 0x70 +#define WCD939X_TEST_CTL_3_IBIAS_LDO_STG3_MASK 0x0c +#define WCD939X_TEST_CTL_3_ATEST_CTRL_MASK 0x03 + + +/* WCD939X_MICB2_TEST_CTL_1 Fields: */ +#define WCD939X_MICB2_TEST_CTL_1_NOISE_FILT_RES_VAL_MASK 0xe0 +#define WCD939X_MICB2_TEST_CTL_1_EN_VREFGEN_MASK 0x10 +#define WCD939X_MICB2_TEST_CTL_1_EN_LDO_MASK 0x08 +#define WCD939X_MICB2_TEST_CTL_1_LDO_BLEEDER_I_CTRL_MASK 0x07 + +/* WCD939X_MICB2_TEST_CTL_2 Fields: */ +#define WCD939X_MICB2_TEST_CTL_2_IBIAS_VREFGEN_MASK 0xc0 +#define WCD939X_MICB2_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_MASK 0x20 +#define WCD939X_MICB2_TEST_CTL_2_SPAREBIT_MASK 0x18 +#define WCD939X_MICB2_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK 0x07 + +/* WCD939X_MICB2_TEST_CTL_3 Fields: */ +#define WCD939X_MICB2_TEST_CTL_3_CFILT_REF_EN_MASK 0x80 +#define WCD939X_MICB2_TEST_CTL_3_RZ_LDO_VAL_MASK 0x70 +#define WCD939X_MICB2_TEST_CTL_3_IBIAS_LDO_STG3_MASK 0x0c +#define WCD939X_MICB2_TEST_CTL_3_ATEST_CTRL_MASK 0x03 + + +/* WCD939X_MICB3_TEST_CTL_1 Fields: */ +#define WCD939X_MICB3_TEST_CTL_1_NOISE_FILT_RES_VAL_MASK 0xe0 +#define WCD939X_MICB3_TEST_CTL_1_EN_VREFGEN_MASK 0x10 +#define WCD939X_MICB3_TEST_CTL_1_EN_LDO_MASK 0x08 +#define WCD939X_MICB3_TEST_CTL_1_LDO_BLEEDER_I_CTRL_MASK 0x07 + +/* WCD939X_MICB3_TEST_CTL_2 Fields: */ +#define WCD939X_MICB3_TEST_CTL_2_IBIAS_VREFGEN_MASK 0xc0 +#define WCD939X_MICB3_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_MASK 0x20 +#define WCD939X_MICB3_TEST_CTL_2_SPAREBIT_MASK 0x18 +#define WCD939X_MICB3_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK 0x07 + +/* WCD939X_MICB3_TEST_CTL_3 Fields: */ +#define WCD939X_MICB3_TEST_CTL_3_CFILT_REF_EN_MASK 0x80 +#define WCD939X_MICB3_TEST_CTL_3_RZ_LDO_VAL_MASK 0x70 +#define WCD939X_MICB3_TEST_CTL_3_IBIAS_LDO_STG3_MASK 0x0c +#define WCD939X_MICB3_TEST_CTL_3_ATEST_CTRL_MASK 0x03 + + +/* WCD939X_MICB4_TEST_CTL_1 Fields: */ +#define WCD939X_MICB4_TEST_CTL_1_NOISE_FILT_RES_VAL_MASK 0xe0 +#define WCD939X_MICB4_TEST_CTL_1_EN_VREFGEN_MASK 0x10 +#define WCD939X_MICB4_TEST_CTL_1_EN_LDO_MASK 0x08 +#define WCD939X_MICB4_TEST_CTL_1_LDO_BLEEDER_I_CTRL_MASK 0x07 + +/* WCD939X_MICB4_TEST_CTL_2 Fields: */ +#define WCD939X_MICB4_TEST_CTL_2_IBIAS_VREFGEN_MASK 0xc0 +#define WCD939X_MICB4_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_MASK 0x20 +#define WCD939X_MICB4_TEST_CTL_2_SPAREBIT_MASK 0x18 +#define WCD939X_MICB4_TEST_CTL_2_IBIAS_LDO_DRIVER_MASK 0x07 + +/* WCD939X_MICB4_TEST_CTL_3 Fields: */ +#define WCD939X_MICB4_TEST_CTL_3_CFILT_REF_EN_MASK 0x80 +#define WCD939X_MICB4_TEST_CTL_3_RZ_LDO_VAL_MASK 0x70 +#define WCD939X_MICB4_TEST_CTL_3_IBIAS_LDO_STG3_MASK 0x0c +#define WCD939X_MICB4_TEST_CTL_3_ATEST_CTRL_MASK 0x03 + + +/* WCD939X_ADC_VCM Fields: */ +#define WCD939X_ADC_VCM_FLL_ATEST_EN_MASK 0x40 +#define WCD939X_ADC_VCM_VCM_L2_12P288_MASK 0x30 +#define WCD939X_ADC_VCM_VCM_L2_9P6_MASK 0x0c +#define WCD939X_ADC_VCM_VCM_DEFAULT_MASK 0x03 + +/* WCD939X_BIAS_ATEST Fields: */ +#define WCD939X_BIAS_ATEST_TX_CURR_EN_MASK 0x80 +#define WCD939X_BIAS_ATEST_SC_BIAS_EN_MASK 0x40 +#define WCD939X_BIAS_ATEST_SC_BIAS_VREF_SEL_MASK 0x20 +#define WCD939X_BIAS_ATEST_ATEST4_EN_MASK 0x08 +#define WCD939X_BIAS_ATEST_ATEST3_EN_MASK 0x04 +#define WCD939X_BIAS_ATEST_ATEST2_EN_MASK 0x02 +#define WCD939X_BIAS_ATEST_ATEST1_EN_MASK 0x01 + +/* WCD939X_SPARE1 Fields: */ +#define WCD939X_SPARE1_SPARE_BITS_7_0_MASK 0xff + +/* WCD939X_SPARE2 Fields: */ +#define WCD939X_SPARE2_SPARE_BITS_7_0_MASK 0xff + +/* WCD939X_TXFE_DIV_CTL Fields: */ +#define WCD939X_TXFE_DIV_CTL_FB_SW_DRIVE_MASK 0x20 +#define WCD939X_TXFE_DIV_CTL_EN_CKGEN_INIT_MASK 0x10 +#define WCD939X_TXFE_DIV_CTL_N_PAUSE_MASK 0x03 + +/* WCD939X_TXFE_DIV_START Fields: */ +#define WCD939X_TXFE_DIV_START_DIV_MASK 0xff + +/* WCD939X_SPARE3 Fields: */ +#define WCD939X_SPARE3_SPARE_BITS_7_0_MASK 0xff + +/* WCD939X_SPARE4 Fields: */ +#define WCD939X_SPARE4_SPARE_BITS_7_0_MASK 0xff + + +/* WCD939X_TEST_EN Fields: */ +#define WCD939X_TEST_EN_TXFE1_EN_MASK 0x80 +#define WCD939X_TEST_EN_ADC1_EN_MASK 0x40 +#define WCD939X_TEST_EN_TXFE1_BYPASS_MASK 0x20 +#define WCD939X_TEST_EN_TXFE1_CLK_MODE_MASK 0x10 +#define WCD939X_TEST_EN_TXFE2_EN_MASK 0x08 +#define WCD939X_TEST_EN_ADC2_EN_MASK 0x04 +#define WCD939X_TEST_EN_TXFE2_BYPASS_MASK 0x02 +#define WCD939X_TEST_EN_TXFE2_CLK_MODE_MASK 0x01 + +/* WCD939X_ADC_IB Fields: */ +#define WCD939X_ADC_IB_ADC2_DEM_MODE_MASK 0xc0 +#define WCD939X_ADC_IB_ADC2_DEM_OPERATION_MASK 0x30 +#define WCD939X_ADC_IB_L2_DAC_DLY_MASK 0x0c +#define WCD939X_ADC_IB_DEFAULT_DAC_DLY_MASK 0x03 + +/* WCD939X_ATEST_REFCTL Fields: */ +#define WCD939X_ATEST_REFCTL_ATEST_CTL_MASK 0xf0 +#define WCD939X_ATEST_REFCTL_TXFE_INCM_REF_MASK 0x0c +#define WCD939X_ATEST_REFCTL_TXFE_HP_GAIN_MODE_MASK 0x02 +#define WCD939X_ATEST_REFCTL_ADCREF_ULPRES_EN_MASK 0x01 + +/* WCD939X_TX_1_2_TEST_CTL Fields: */ +#define WCD939X_TX_1_2_TEST_CTL_TXFE_HP_GAIN_MASK 0x80 +#define WCD939X_TX_1_2_TEST_CTL_REF_CAP_MASK 0x40 +#define WCD939X_TX_1_2_TEST_CTL_ADC1_DEM_MODE_MASK 0x30 +#define WCD939X_TX_1_2_TEST_CTL_ADC1_DEM_OPERATION_MASK 0x0c +#define WCD939X_TX_1_2_TEST_CTL_SAR_ERR_DET_EN_MASK 0x02 +#define WCD939X_TX_1_2_TEST_CTL_SAR_EXT_DELAY_EN_MASK 0x01 + +/* WCD939X_TEST_BLK_EN1 Fields: */ +#define WCD939X_TEST_BLK_EN1_ADC1_INT1_EN_MASK 0x80 +#define WCD939X_TEST_BLK_EN1_ADC1_INT2_EN_MASK 0x40 +#define WCD939X_TEST_BLK_EN1_ADC1_SAR_EN_MASK 0x20 +#define WCD939X_TEST_BLK_EN1_ADC1_CMGEN_EN_MASK 0x10 +#define WCD939X_TEST_BLK_EN1_ADC1_CLKGEN_EN_MASK 0x08 +#define WCD939X_TEST_BLK_EN1_REF_EN_MASK 0x04 +#define WCD939X_TEST_BLK_EN1_TXFE1_CLKDIV_EN_MASK 0x02 +#define WCD939X_TEST_BLK_EN1_TXFE2_CLKDIV_EN_MASK 0x01 + +/* WCD939X_TXFE1_CLKDIV Fields: */ +#define WCD939X_TXFE1_CLKDIV_DIV_MASK 0xff + +/* WCD939X_SAR2_ERR Fields: */ +#define WCD939X_SAR2_ERR_SAR_ERR_COUNT_MASK 0xff + +/* WCD939X_SAR1_ERR Fields: */ +#define WCD939X_SAR1_ERR_SAR_ERR_COUNT_MASK 0xff + + +/* WCD939X_TX_3_4_TEST_EN Fields: */ +#define WCD939X_TX_3_4_TEST_EN_TXFE3_EN_MASK 0x80 +#define WCD939X_TX_3_4_TEST_EN_ADC3_EN_MASK 0x40 +#define WCD939X_TX_3_4_TEST_EN_TXFE3_BYPASS_MASK 0x20 +#define WCD939X_TX_3_4_TEST_EN_TXFE3_CLK_MODE_MASK 0x10 +#define WCD939X_TX_3_4_TEST_EN_TXFE4_EN_MASK 0x08 +#define WCD939X_TX_3_4_TEST_EN_ADC4_EN_MASK 0x04 +#define WCD939X_TX_3_4_TEST_EN_TXFE4_BYPASS_MASK 0x02 +#define WCD939X_TX_3_4_TEST_EN_TXFE4_CLK_MODE_MASK 0x01 + +/* WCD939X_TX_3_4_ADC_IB Fields: */ +#define WCD939X_TX_3_4_ADC_IB_ADC4_DEM_MODE_MASK 0xc0 +#define WCD939X_TX_3_4_ADC_IB_ADC4_DEM_OPERATION_MASK 0x30 +#define WCD939X_TX_3_4_ADC_IB_L2_DAC_DLY_MASK 0x0c +#define WCD939X_TX_3_4_ADC_IB_DEFAULT_DAC_DLY_MASK 0x03 + +/* WCD939X_TX_3_4_ATEST_REFCTL Fields: */ +#define WCD939X_TX_3_4_ATEST_REFCTL_ATEST_CTL_MASK 0xf0 +#define WCD939X_TX_3_4_ATEST_REFCTL_TXFE_INCM_REF_MASK 0x0c +#define WCD939X_TX_3_4_ATEST_REFCTL_TXFE_HP_GAIN_MODE_MASK 0x02 +#define WCD939X_TX_3_4_ATEST_REFCTL_ADCREF_ULPRES_EN_MASK 0x01 + +/* WCD939X_TX_3_4_TEST_CTL Fields: */ +#define WCD939X_TX_3_4_TEST_CTL_TXFE_HP_GAIN_MASK 0x80 +#define WCD939X_TX_3_4_TEST_CTL_REF_CAP_MASK 0x40 +#define WCD939X_TX_3_4_TEST_CTL_ADC3_DEM_MODE_MASK 0x30 +#define WCD939X_TX_3_4_TEST_CTL_ADC3_DEM_OPERATION_MASK 0x0c +#define WCD939X_TX_3_4_TEST_CTL_SAR_ERR_DET_EN_MASK 0x02 +#define WCD939X_TX_3_4_TEST_CTL_SAR_EXT_DELAY_EN_MASK 0x01 + +/* WCD939X_TEST_BLK_EN3 Fields: */ +#define WCD939X_TEST_BLK_EN3_ADC3_INT1_EN_MASK 0x80 +#define WCD939X_TEST_BLK_EN3_ADC3_INT2_EN_MASK 0x40 +#define WCD939X_TEST_BLK_EN3_ADC3_SAR_EN_MASK 0x20 +#define WCD939X_TEST_BLK_EN3_ADC3_CMGEN_EN_MASK 0x10 +#define WCD939X_TEST_BLK_EN3_ADC3_CLKGEN_EN_MASK 0x08 +#define WCD939X_TEST_BLK_EN3_REF_EN_MASK 0x04 +#define WCD939X_TEST_BLK_EN3_TXFE3_CLKDIV_EN_MASK 0x02 +#define WCD939X_TEST_BLK_EN3_TXFE4_CLKDIV_EN_MASK 0x01 + +/* WCD939X_TXFE3_CLKDIV Fields: */ +#define WCD939X_TXFE3_CLKDIV_DIV_MASK 0xff + +/* WCD939X_SAR4_ERR Fields: */ +#define WCD939X_SAR4_ERR_SAR_ERR_COUNT_MASK 0xff + +/* WCD939X_SAR3_ERR Fields: */ +#define WCD939X_SAR3_ERR_SAR_ERR_COUNT_MASK 0xff + +/* WCD939X_TEST_BLK_EN2 Fields: */ +#define WCD939X_TEST_BLK_EN2_ADC2_INT1_EN_MASK 0x80 +#define WCD939X_TEST_BLK_EN2_ADC2_INT2_EN_MASK 0x40 +#define WCD939X_TEST_BLK_EN2_ADC2_SAR_EN_MASK 0x20 +#define WCD939X_TEST_BLK_EN2_ADC2_CMGEN_EN_MASK 0x10 +#define WCD939X_TEST_BLK_EN2_ADC2_CLKGEN_EN_MASK 0x08 +#define WCD939X_TEST_BLK_EN2_ADC12_VREF_NONL2_MASK 0x06 +#define WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN_MASK 0x01 + +/* WCD939X_TXFE2_CLKDIV Fields: */ +#define WCD939X_TXFE2_CLKDIV_DIV_MASK 0xff + +/* WCD939X_TX_3_4_SPARE1 Fields: */ +#define WCD939X_TX_3_4_SPARE1_SPARE_BITS_7_0_MASK 0xff + +/* WCD939X_TEST_BLK_EN4 Fields: */ +#define WCD939X_TEST_BLK_EN4_ADC4_INT1_EN_MASK 0x80 +#define WCD939X_TEST_BLK_EN4_ADC4_INT2_EN_MASK 0x40 +#define WCD939X_TEST_BLK_EN4_ADC4_SAR_EN_MASK 0x20 +#define WCD939X_TEST_BLK_EN4_ADC4_CMGEN_EN_MASK 0x10 +#define WCD939X_TEST_BLK_EN4_ADC4_CLKGEN_EN_MASK 0x08 +#define WCD939X_TEST_BLK_EN4_ADC34_VREF_NONL2_MASK 0x06 +#define WCD939X_TEST_BLK_EN4_SPARE_BITS_0_0_MASK 0x01 + +/* WCD939X_TXFE4_CLKDIV Fields: */ +#define WCD939X_TXFE4_CLKDIV_DIV_MASK 0xff + +/* WCD939X_TX_3_4_SPARE2 Fields: */ +#define WCD939X_TX_3_4_SPARE2_SPARE_BITS_7_0_MASK 0xff + + +/* WCD939X_MODE_1 Fields: */ +#define WCD939X_MODE_1_BUCK_EN_DELAY_SEL_MASK 0x60 +#define WCD939X_MODE_1_BUCK_EN_RESET_BY_EXT_MASK 0x10 + +/* WCD939X_MODE_2 Fields: */ +#define WCD939X_MODE_2_VREF_I2C_MASK 0xff + +/* WCD939X_MODE_3 Fields: */ +#define WCD939X_MODE_3_DELTA_IPEAK_2VPK_MASK 0xf0 +#define WCD939X_MODE_3_DELTA_IPEAK_OVERRIDE_MASK 0x04 +#define WCD939X_MODE_3_CTRL_VREF_BY_MASK 0x02 +#define WCD939X_MODE_3_MANUAL_PWR_OPT_HPH_MASK 0x01 + +/* WCD939X_CTRL_VCL_1 Fields: */ +#define WCD939X_CTRL_VCL_1_DELTA_V_SEL_MASK 0xf0 +#define WCD939X_CTRL_VCL_1_VDD_BUCK_FILT_2VPK_MASK 0x0c +#define WCD939X_CTRL_VCL_1_VREF_DELTA_GEN_GAIN_SEL_MASK 0x03 + +/* WCD939X_CTRL_VCL_2 Fields: */ +#define WCD939X_CTRL_VCL_2_VDD_BUCK_FILT_MASK 0xc0 +#define WCD939X_CTRL_VCL_2_VREF_FILT_1_MASK 0x30 +#define WCD939X_CTRL_VCL_2_VREF_FILT_2_MASK 0x0e + +/* WCD939X_CTRL_CCL_1 Fields: */ +#define WCD939X_CTRL_CCL_1_DELTA_IPEAK_MASK 0xf0 +#define WCD939X_CTRL_CCL_1_DELTA_IVALLEY_MASK 0x0f + +/* WCD939X_CTRL_CCL_2 Fields: */ +#define WCD939X_CTRL_CCL_2_CHOOSE_I_LIM_MASK 0xfc +#define WCD939X_CTRL_CCL_2_BUCK_BYPASS_OVERRIDE_MASK 0x02 +#define WCD939X_CTRL_CCL_2_BUCK_BYPASS_EN_MASK 0x01 + +/* WCD939X_CTRL_CCL_3 Fields: */ +#define WCD939X_CTRL_CCL_3_MIN_PON_MASK 0xc0 +#define WCD939X_CTRL_CCL_3_MIN_NON_MASK 0x30 + +/* WCD939X_CTRL_CCL_4 Fields: */ +#define WCD939X_CTRL_CCL_4_P_BLNK_INV1_LOAD_MASK 0x80 +#define WCD939X_CTRL_CCL_4_P_BLNK_INV2_LOAD_MASK 0x40 +#define WCD939X_CTRL_CCL_4_N_BLNK_INV1_LOAD_MASK 0x20 +#define WCD939X_CTRL_CCL_4_N_BLNK_INV2_LOAD_MASK 0x10 +#define WCD939X_CTRL_CCL_4_RST_PW_INV_LOAD_MASK 0x02 +#define WCD939X_CTRL_CCL_4_INZ_RST_SW_CTRL_MASK 0x01 + +/* WCD939X_CTRL_CCL_5 Fields: */ +#define WCD939X_CTRL_CCL_5_IPK_FRC_RST_MASK 0xe0 + +/* WCD939X_BUCK_TMUX_A_D Fields: */ +#define WCD939X_BUCK_TMUX_A_D_ATEST_SEL_MASK 0x80 +#define WCD939X_BUCK_TMUX_A_D_DTEST_MUX_EN_MASK 0x08 +#define WCD939X_BUCK_TMUX_A_D_DTEST_BRK_4_BRK_3_BRK_2_BRK_1_MASK 0x07 + +/* WCD939X_BUCK_SW_DRV_CNTL Fields: */ +#define WCD939X_BUCK_SW_DRV_CNTL_PSW_DRV_CNTL_MASK 0xf0 +#define WCD939X_BUCK_SW_DRV_CNTL_NSW_DRV_CNTL_MASK 0x0f + +/* WCD939X_SPARE Fields: */ +#define WCD939X_SPARE_CHOOSE_I_LIM_2VPK_MASK 0xfc + + +/* WCD939X_EN Fields: */ +#define WCD939X_EN_FLYBACK_EN_DELAY_SEL_MASK 0x60 +#define WCD939X_EN_FLYBACK_EN_RESET_BY_EXT_MASK 0x10 +#define WCD939X_EN_EN_PWSV_MASK 0x08 +#define WCD939X_EN_EN_CUR_DET_MASK 0x04 +#define WCD939X_EN_EN_BLEEDER_MASK 0x02 +#define WCD939X_EN_VREF_PWR_DAC_SEL_OVERRIDE_MASK 0x01 + +/* WCD939X_VNEG_CTRL_1 Fields: */ +#define WCD939X_VNEG_CTRL_1_VREF_DELTA_GEN_LP_MASK 0xe0 +#define WCD939X_VNEG_CTRL_1_VREF_DELTA_GEN_UHQA_MASK 0x1c +#define WCD939X_VNEG_CTRL_1_DRV_PSW_LC_MASK 0x02 +#define WCD939X_VNEG_CTRL_1_DRV_PSW_HC_MASK 0x01 + +/* WCD939X_VNEG_CTRL_2 Fields: */ +#define WCD939X_VNEG_CTRL_2_MIN_PON_MASK 0xc0 +#define WCD939X_VNEG_CTRL_2_MIN_NON_MASK 0x20 +#define WCD939X_VNEG_CTRL_2_RST_PW_MASK 0x10 +#define WCD939X_VNEG_CTRL_2_P_BLNK_MASK 0x0c +#define WCD939X_VNEG_CTRL_2_N_BLNK_MASK 0x03 + +/* WCD939X_VNEG_CTRL_3 Fields: */ +#define WCD939X_VNEG_CTRL_3_EN_IVLY_FRC_RST_MASK 0x10 +#define WCD939X_VNEG_CTRL_3_IVLY_FRC_RST_MASK 0x0c +#define WCD939X_VNEG_CTRL_3_INZ_RDY_CTL_MASK 0x02 +#define WCD939X_VNEG_CTRL_3_INIT_MINPON_CTL_MASK 0x01 + +/* WCD939X_VNEG_CTRL_4 Fields: */ +#define WCD939X_VNEG_CTRL_4_ILIM_SEL_MASK 0xf0 +#define WCD939X_VNEG_CTRL_4_PW_BUF_POS_MASK 0x0c +#define WCD939X_VNEG_CTRL_4_PW_BUF_NEG_MASK 0x03 + +/* WCD939X_VNEG_CTRL_5 Fields: */ +#define WCD939X_VNEG_CTRL_5_IPK_DELTA_VNEG_LP_MASK 0xf0 +#define WCD939X_VNEG_CTRL_5_IPK_DELTA_VNEG_UHQA_MASK 0x0f + +/* WCD939X_VNEG_CTRL_6 Fields: */ +#define WCD939X_VNEG_CTRL_6_VREF_THIGH_POS_MASK 0xf0 +#define WCD939X_VNEG_CTRL_6_VREF_TLOW_POS_MASK 0x0f + +/* WCD939X_VNEG_CTRL_7 Fields: */ +#define WCD939X_VNEG_CTRL_7_VREF_THIGH_NEG_MASK 0xf0 +#define WCD939X_VNEG_CTRL_7_VREF_TLOW_NEG_MASK 0x0f + +/* WCD939X_VNEG_CTRL_8 Fields: */ +#define WCD939X_VNEG_CTRL_8_SW_POS_EN_DLY_MASK 0xc0 +#define WCD939X_VNEG_CTRL_8_SW_NEG_EN_DLY_MASK 0x30 +#define WCD939X_VNEG_CTRL_8_VNEG_EN_DLY_MASK 0x0e +#define WCD939X_VNEG_CTRL_8_EN_IVLYCMP_STATIC_MASK 0x01 + +/* WCD939X_VNEG_CTRL_9 Fields: */ +#define WCD939X_VNEG_CTRL_9_CUR_DET_TH_MASK 0xc0 +#define WCD939X_VNEG_CTRL_9_MAXPON_SEL_MASK 0x38 +#define WCD939X_VNEG_CTRL_9_EN_MAXPON_FRC_MASK 0x04 +#define WCD939X_VNEG_CTRL_9_VREF_PWR_DAC_SEL_MASK 0x02 + +/* WCD939X_VNEGDAC_CTRL_1 Fields: */ +#define WCD939X_VNEGDAC_CTRL_1_VREF_DAC_DELTA_GEN_LP_MASK 0xe0 +#define WCD939X_VNEGDAC_CTRL_1_VREF_DAC_DELTA_GEN_UHQA_MASK 0x1c +#define WCD939X_VNEGDAC_CTRL_1_N_BLNK_DAC_MASK 0x03 + +/* WCD939X_VNEGDAC_CTRL_2 Fields: */ +#define WCD939X_VNEGDAC_CTRL_2_VREF_DAC_SEL_MASK 0xe0 +#define WCD939X_VNEGDAC_CTRL_2_VNEGDAC_1P8REF_EN_DLY_MASK 0x18 +#define WCD939X_VNEGDAC_CTRL_2_VREF_BLEEDER_MASK 0x06 +#define WCD939X_VNEGDAC_CTRL_2_N_ICHRG_BLNK_DAC_MASK 0x01 + +/* WCD939X_VNEGDAC_CTRL_3 Fields: */ +#define WCD939X_VNEGDAC_CTRL_3_IPK_DELTA_VNEGDAC_LP_MASK 0xf0 +#define WCD939X_VNEGDAC_CTRL_3_IPK_DELTA_VNEGDAC_UHQA_MASK 0x0f + +/* WCD939X_CTRL_1 Fields: */ +#define WCD939X_CTRL_1_ICHRG_VREF_MASK 0xc0 +#define WCD939X_CTRL_1_EN_INZCMP_CTL_1_MASK 0x20 +#define WCD939X_CTRL_1_EN_INZCMP_CTL_2_MASK 0x10 +#define WCD939X_CTRL_1_DELTAV_STEP_CTL_MASK 0x08 +#define WCD939X_CTRL_1_EN_MAXNON_FRC_MASK 0x04 +#define WCD939X_CTRL_1_MAXNON_SEL_MASK 0x03 + +/* WCD939X_FLYBACK_TEST_CTL Fields: */ +#define WCD939X_FLYBACK_TEST_CTL_DTEST_MUX_SEL_MASK 0x80 +#define WCD939X_FLYBACK_TEST_CTL_ILIM_SEL_2VPK_MASK 0x0f + + +/* WCD939X_AUX_SW_CTL Fields: */ +#define WCD939X_AUX_SW_CTL_AUXL_SW_EN_MASK 0x80 +#define WCD939X_AUX_SW_CTL_AUXR_SW_EN_MASK 0x40 +#define WCD939X_AUX_SW_CTL_AUXL2R_SW_EN_MASK 0x20 + +/* WCD939X_PA_AUX_IN_CONN Fields: */ +#define WCD939X_PA_AUX_IN_CONN_HPHL_AUX_IN_MASK 0x80 +#define WCD939X_PA_AUX_IN_CONN_HPHR_AUX_IN_MASK 0x40 +#define WCD939X_PA_AUX_IN_CONN_EAR_AUX_IN_MASK 0x20 +#define WCD939X_PA_AUX_IN_CONN_SPARE_BITS0_MASK 0x10 +#define WCD939X_PA_AUX_IN_CONN_SPARE_BITS1_MASK 0x0e +#define WCD939X_PA_AUX_IN_CONN_RX_CLK_PHASE_INV_MASK 0x01 + +/* WCD939X_TIMER_DIV Fields: */ +#define WCD939X_TIMER_DIV_RX_CLK_DIVIDER_OVWT_MASK 0x80 +#define WCD939X_TIMER_DIV_RX_CLK_DIVIDER_MASK 0x7f + +/* WCD939X_OCP_CTL Fields: */ +#define WCD939X_OCP_CTL_SPARE_BITS_MASK 0xf0 +#define WCD939X_OCP_CTL_N_CONNECTION_ATTEMPTS_MASK 0x0f + +/* WCD939X_OCP_COUNT Fields: */ +#define WCD939X_OCP_COUNT_RUN_N_CYCLES_MASK 0xf0 +#define WCD939X_OCP_COUNT_WAIT_N_CYCLES_MASK 0x0f + +/* WCD939X_BIAS_EAR_DAC Fields: */ +#define WCD939X_BIAS_EAR_DAC_EAR_DAC_5_UA_MASK 0xf0 +#define WCD939X_BIAS_EAR_DAC_ATEST_RX_BIAS_MASK 0x0f + +/* WCD939X_BIAS_EAR_AMP Fields: */ +#define WCD939X_BIAS_EAR_AMP_EAR_AMP_10_UA_MASK 0xf0 +#define WCD939X_BIAS_EAR_AMP_EAR_AMP_5_UA_MASK 0x0f + +/* WCD939X_BIAS_HPH_LDO Fields: */ +#define WCD939X_BIAS_HPH_LDO_HPH_NVLDO2_5_UA_MASK 0xf0 +#define WCD939X_BIAS_HPH_LDO_HPH_NVLDO1_4P5_UA_MASK 0x0f + +/* WCD939X_BIAS_HPH_PA Fields: */ +#define WCD939X_BIAS_HPH_PA_HPH_CONSTOP_5_UA_MASK 0xf0 +#define WCD939X_BIAS_HPH_PA_HPH_AMP_5_UA_MASK 0x0f + +/* WCD939X_BIAS_HPH_RDACBUFF_CNP2 Fields: */ +#define WCD939X_BIAS_HPH_RDACBUFF_CNP2_RDAC_BUF_3_UA_MASK 0xf0 +#define WCD939X_BIAS_HPH_RDACBUFF_CNP2_HPH_CNP_10_UA_MASK 0x0f + +/* WCD939X_BIAS_HPH_RDAC_LDO Fields: */ +#define WCD939X_BIAS_HPH_RDAC_LDO_RDAC_LDO_1P65_4_UA_MASK 0xf0 +#define WCD939X_BIAS_HPH_RDAC_LDO_RDAC_LDO_N1P65_4_UA_MASK 0x0f + +/* WCD939X_BIAS_HPH_CNP1 Fields: */ +#define WCD939X_BIAS_HPH_CNP1_HPH_CNP_4_UA_MASK 0xf0 +#define WCD939X_BIAS_HPH_CNP1_HPH_CNP_3_UA_MASK 0x0f + +/* WCD939X_BIAS_HPH_LOWPOWER Fields: */ +#define WCD939X_BIAS_HPH_LOWPOWER_HPH_AMP_LP_1P5_UA_MASK 0xf0 +#define WCD939X_BIAS_HPH_LOWPOWER_RDAC_BUF_LP_0P25_UA_MASK 0x0f + +/* WCD939X_BIAS_AUX_DAC Fields: */ +#define WCD939X_BIAS_AUX_DAC_SPARE_BITS0_MASK 0xf0 +#define WCD939X_BIAS_AUX_DAC_SPARE_BITS1_MASK 0x0f + +/* WCD939X_BIAS_AUX_AMP Fields: */ +#define WCD939X_BIAS_AUX_AMP_SPARE_BITS0_MASK 0xf0 +#define WCD939X_BIAS_AUX_AMP_SPARE_BITS1_MASK 0x0f + +/* WCD939X_BIAS_VNEGDAC_BLEEDER Fields: */ +#define WCD939X_BIAS_VNEGDAC_BLEEDER_BLEEDER_CTRL_MASK 0xf0 + +/* WCD939X_BIAS_MISC Fields: */ +#define WCD939X_BIAS_MISC_SPARE_BITS_MASK 0xff + +/* WCD939X_BIAS_BUCK_RST Fields: */ +#define WCD939X_BIAS_BUCK_RST_BUCK_RST_2_UA_MASK 0x0f + +/* WCD939X_BIAS_BUCK_VREF_ERRAMP Fields: */ +#define WCD939X_BIAS_BUCK_VREF_ERRAMP_BUCK_VREF_1_UA_MASK 0xf0 +#define WCD939X_BIAS_BUCK_VREF_ERRAMP_BUCK_ERRAMP_1_UA_MASK 0x0f + +/* WCD939X_BIAS_FLYB_ERRAMP Fields: */ +#define WCD939X_BIAS_FLYB_ERRAMP_FLYB_ERRAMP_1_UA_MASK 0xf0 + +/* WCD939X_BIAS_FLYB_BUFF Fields: */ +#define WCD939X_BIAS_FLYB_BUFF_FLYB_VNEG_5_UA_MASK 0xf0 +#define WCD939X_BIAS_FLYB_BUFF_FLYB_VPOS_5_UA_MASK 0x0f + +/* WCD939X_BIAS_FLYB_MID_RST Fields: */ +#define WCD939X_BIAS_FLYB_MID_RST_FLYB_MID_1_UA_MASK 0xf0 +#define WCD939X_BIAS_FLYB_MID_RST_FLYB_RST_1_UA_MASK 0x0f + + +/* WCD939X_L_STATUS Fields: */ +#define WCD939X_L_STATUS_CMPDR_GAIN_MASK 0xf8 +#define WCD939X_L_STATUS_OCP_COMP_DETECT_MASK 0x04 +#define WCD939X_L_STATUS_OCP_LIMIT_MASK 0x02 +#define WCD939X_L_STATUS_PA_READY_MASK 0x01 + +/* WCD939X_R_STATUS Fields: */ +#define WCD939X_R_STATUS_CMPDR_GAIN_MASK 0xf8 +#define WCD939X_R_STATUS_OCP_COMP_DETECT_MASK 0x04 +#define WCD939X_R_STATUS_OCP_LIMIT_MASK 0x02 +#define WCD939X_R_STATUS_PA_READY_MASK 0x01 + +/* WCD939X_CNP_EN Fields: */ +#define WCD939X_CNP_EN_FSM_CLK_EN_MASK 0x80 +#define WCD939X_CNP_EN_FSM_RESET_MASK 0x40 +#define WCD939X_CNP_EN_CNP_IREF_SEL_MASK 0x20 +#define WCD939X_CNP_EN_FSM_OVERRIDE_EN_MASK 0x08 +#define WCD939X_CNP_EN_WG_LR_SEL_MASK 0x04 +#define WCD939X_CNP_EN_DBG_CURR_DIRECTION_R_MASK 0x02 +#define WCD939X_CNP_EN_DBG_VREF_EN_MASK 0x01 + +/* WCD939X_CNP_WG_CTL Fields: */ +#define WCD939X_CNP_WG_CTL_GM3_BOOST_EN_MASK 0x80 +#define WCD939X_CNP_WG_CTL_NO_PD_SEQU_MASK 0x40 +#define WCD939X_CNP_WG_CTL_VREF_TIMER_MASK 0x38 +#define WCD939X_CNP_WG_CTL_CURR_LDIV_CTL_MASK 0x07 + +/* WCD939X_CNP_WG_TIME Fields: */ +#define WCD939X_CNP_WG_TIME_WG_FINE_TIMER_MASK 0xff + +/* WCD939X_HPH_OCP_CTL Fields: */ +#define WCD939X_HPH_OCP_CTL_OCP_CURR_LIMIT_MASK 0xe0 +#define WCD939X_HPH_OCP_CTL_OCP_FSM_EN_MASK 0x10 +#define WCD939X_HPH_OCP_CTL_SPARE_BITS_MASK 0x08 +#define WCD939X_HPH_OCP_CTL_SCD_OP_EN_MASK 0x02 + +/* WCD939X_AUTO_CHOP Fields: */ +#define WCD939X_AUTO_CHOP_GM3_CASCODE_CTL_2VPK_MASK 0xc0 +#define WCD939X_AUTO_CHOP_AUTO_CHOPPER_MODE_MASK 0x20 +#define WCD939X_AUTO_CHOP_GAIN_THRESHOLD_MASK 0x1f + +/* WCD939X_CHOP_CTL Fields: */ +#define WCD939X_CHOP_CTL_CHOPPER_EN_MASK 0x80 +#define WCD939X_CHOP_CTL_CLK_INV_MASK 0x40 +#define WCD939X_CHOP_CTL_SPARE_BITS_MASK 0x38 +#define WCD939X_CHOP_CTL_DIV2_DIV_BY_2_MASK 0x04 +#define WCD939X_CHOP_CTL_DIV2_DIV_BY_2_4_6_8_MASK 0x03 + +/* WCD939X_PA_CTL1 Fields: */ +#define WCD939X_PA_CTL1_GM3_IBIAS_CTL_MASK 0xf0 +#define WCD939X_PA_CTL1_GM3_IB_SCALE_MASK 0x0e +#define WCD939X_PA_CTL1_SPARE_BITS_MASK 0x01 + +/* WCD939X_PA_CTL2 Fields: */ +#define WCD939X_PA_CTL2_SPARE_BITS0_MASK 0x80 +#define WCD939X_PA_CTL2_HPHPA_GND_R_MASK 0x40 +#define WCD939X_PA_CTL2_SPARE_BITS1_MASK 0x20 +#define WCD939X_PA_CTL2_HPHPA_GND_L_MASK 0x10 +#define WCD939X_PA_CTL2_SPARE_BITS2_MASK 0x0c +#define WCD939X_PA_CTL2_GM3_CASCODE_CTL_NORMAL_MASK 0x03 + +/* WCD939X_L_EN Fields: */ +#define WCD939X_L_EN_CONST_SEL_L_MASK 0xc0 +#define WCD939X_L_EN_GAIN_SOURCE_SEL_MASK 0x20 +#define WCD939X_L_EN_SPARE_BITS_MASK 0x1f + +/* WCD939X_L_TEST Fields: */ +#define WCD939X_L_TEST_PDN_EN_MASK 0x80 +#define WCD939X_L_TEST_PDN_AMP2_EN_MASK 0x40 +#define WCD939X_L_TEST_PDN_AMP_EN_MASK 0x20 +#define WCD939X_L_TEST_PA_CNP_SW_CONN_MASK 0x10 +#define WCD939X_L_TEST_PA_CNP_SW_OFF_MASK 0x08 +#define WCD939X_L_TEST_PA_CNP_SW_ON_MASK 0x04 +#define WCD939X_L_TEST_SPARE_BITS_MASK 0x02 +#define WCD939X_L_TEST_OCP_DET_EN_MASK 0x01 + +/* WCD939X_L_ATEST Fields: */ +#define WCD939X_L_ATEST_DACL_REF_ATEST1_CONN_MASK 0x80 +#define WCD939X_L_ATEST_LDO1_L_ATEST2_CONN_MASK 0x40 +#define WCD939X_L_ATEST_LDO_L_ATEST2_CAL_MASK 0x20 +#define WCD939X_L_ATEST_LDO2_L_ATEST2_CONN_MASK 0x10 +#define WCD939X_L_ATEST_HPHPA_GND_OVR_MASK 0x08 +#define WCD939X_L_ATEST_SPARE_BITS_MASK 0x04 +#define WCD939X_L_ATEST_CNP_EXD2_MASK 0x02 +#define WCD939X_L_ATEST_CNP_EXD1_MASK 0x01 + +/* WCD939X_R_EN Fields: */ +#define WCD939X_R_EN_CONST_SEL_R_MASK 0xc0 +#define WCD939X_R_EN_GAIN_SOURCE_SEL_MASK 0x20 +#define WCD939X_R_EN_SPARE_BITS_MASK 0x1f + +/* WCD939X_R_TEST Fields: */ +#define WCD939X_R_TEST_PDN_EN_MASK 0x80 +#define WCD939X_R_TEST_PDN_AMP2_EN_MASK 0x40 +#define WCD939X_R_TEST_PDN_AMP_EN_MASK 0x20 +#define WCD939X_R_TEST_PA_CNP_SW_CONN_MASK 0x10 +#define WCD939X_R_TEST_PA_CNP_SW_OFF_MASK 0x08 +#define WCD939X_R_TEST_PA_CNP_SW_ON_MASK 0x04 +#define WCD939X_R_TEST_SPARE_BITS_MASK 0x02 +#define WCD939X_R_TEST_OCP_DET_EN_MASK 0x01 + +/* WCD939X_R_ATEST Fields: */ +#define WCD939X_R_ATEST_DACR_REF_ATEST1_CONN_MASK 0x80 +#define WCD939X_R_ATEST_LDO1_R_ATEST2_CONN_MASK 0x40 +#define WCD939X_R_ATEST_LDO_R_ATEST2_CAL_MASK 0x20 +#define WCD939X_R_ATEST_LDO2_R_ATEST2_CONN_MASK 0x10 +#define WCD939X_R_ATEST_LDO_1P65V_ATEST1_CONN_MASK 0x08 +#define WCD939X_R_ATEST_SPARE_BITS0_MASK 0x04 +#define WCD939X_R_ATEST_HPH_GND_OVR_MASK 0x02 +#define WCD939X_R_ATEST_SPARE_BITS1_MASK 0x01 + +/* WCD939X_RDAC_CLK_CTL1 Fields: */ +#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN_MASK 0x80 +#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_DIV_CTRL_MASK 0x70 +#define WCD939X_RDAC_CLK_CTL1_SPARE_BITS_MASK 0x0f + +/* WCD939X_RDAC_CLK_CTL2 Fields: */ +#define WCD939X_RDAC_CLK_CTL2_SPARE_BITS_MASK 0xf0 +#define WCD939X_RDAC_CLK_CTL2_PREREF_SC_CLK_EN_MASK 0x08 +#define WCD939X_RDAC_CLK_CTL2_PREREF_SC_CLK_DIVIDER_CTRL_MASK 0x07 + +/* WCD939X_RDAC_LDO_CTL Fields: */ +#define WCD939X_RDAC_LDO_CTL_LDO_1P65_BYPASS_MASK 0x80 +#define WCD939X_RDAC_LDO_CTL_LDO_1P65_OUTCTL_MASK 0x70 +#define WCD939X_RDAC_LDO_CTL_N1P65V_LDO_BYPASS_MASK 0x08 +#define WCD939X_RDAC_LDO_CTL_N1P65_LDO_OUTCTL_MASK 0x07 + +/* WCD939X_RDAC_CHOP_CLK_LP_CTL Fields: */ +#define WCD939X_RDAC_CHOP_CLK_LP_CTL_OPAMP_CHOP_CLK_EN_LP_MASK 0x80 +#define WCD939X_RDAC_CHOP_CLK_LP_CTL_SPARE_BITS_MASK 0x7f + +/* WCD939X_REFBUFF_UHQA_CTL Fields: */ +#define WCD939X_REFBUFF_UHQA_CTL_SPARE_BITS_MASK 0xc0 +#define WCD939X_REFBUFF_UHQA_CTL_HPH_VNEGREG2_COMP_CTL_OV_MASK 0x20 +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_RBIAS_ADJUST_MASK 0x10 +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFP_IOUT_CTL_MASK 0x0c +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_IOUT_CTL_MASK 0x03 + +/* WCD939X_REFBUFF_LP_CTL Fields: */ +#define WCD939X_REFBUFF_LP_CTL_HPH_VNEGREG2_CURR_COMP_MASK 0xc0 +#define WCD939X_REFBUFF_LP_CTL_SPARE_BITS_MASK 0x30 +#define WCD939X_REFBUFF_LP_CTL_EN_PREREF_FILT_STARTUP_CLKDIV_MASK 0x08 +#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_STARTUP_CLKDIV_CTL_MASK 0x06 +#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS_MASK 0x01 + +/* WCD939X_L_DAC_CTL Fields: */ +#define WCD939X_L_DAC_CTL_SPARE_BITS_MASK 0x80 +#define WCD939X_L_DAC_CTL_DAC_REF_EN_MASK 0x40 +#define WCD939X_L_DAC_CTL_DAC_SAMPLE_EDGE_SELECT_MASK 0x20 +#define WCD939X_L_DAC_CTL_DATA_RESET_MASK 0x10 +#define WCD939X_L_DAC_CTL_INV_DATA_MASK 0x08 +#define WCD939X_L_DAC_CTL_DAC_L_EN_OV_MASK 0x04 +#define WCD939X_L_DAC_CTL_DAC_LDO_UHQA_OV_MASK 0x02 +#define WCD939X_L_DAC_CTL_DAC_LDO_POWERMODE_MASK 0x01 + +/* WCD939X_R_DAC_CTL Fields: */ +#define WCD939X_R_DAC_CTL_SPARE_BITS_MASK 0x80 +#define WCD939X_R_DAC_CTL_DAC_REF_EN_MASK 0x40 +#define WCD939X_R_DAC_CTL_DAC_SAMPLE_EDGE_SELECT_MASK 0x20 +#define WCD939X_R_DAC_CTL_DATA_RESET_MASK 0x10 +#define WCD939X_R_DAC_CTL_INV_DATA_MASK 0x08 +#define WCD939X_R_DAC_CTL_DAC_R_EN_OV_MASK 0x04 +#define WCD939X_R_DAC_CTL_DAC_PREREF_UHQA_OV_MASK 0x02 +#define WCD939X_R_DAC_CTL_DAC_PREREF_POWERMODE_MASK 0x01 + + +/* WCD939X_HPHLR_SURGE_COMP_SEL Fields: */ +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHL_PSURGE_MASK 0xc0 +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHL_NSURGE_MASK 0x30 +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHR_PSURGE_MASK 0x0c +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHR_NSURGE_MASK 0x03 + +/* WCD939X_HPHLR_SURGE_EN Fields: */ +#define WCD939X_HPHLR_SURGE_EN_EN_SURGE_PROTECTION_HPHL_MASK 0x80 +#define WCD939X_HPHLR_SURGE_EN_EN_SURGE_PROTECTION_HPHR_MASK 0x40 +#define WCD939X_HPHLR_SURGE_EN_SEL_SURGE_COMP_IQ_MASK 0x30 +#define WCD939X_HPHLR_SURGE_EN_SURGE_VOLT_MODE_SHUTOFF_EN_MASK 0x08 +#define WCD939X_HPHLR_SURGE_EN_LATCH_INTR_OP_STG_HIZ_EN_MASK 0x04 +#define WCD939X_HPHLR_SURGE_EN_SURGE_LATCH_REG_RESET_MASK 0x02 +#define WCD939X_HPHLR_SURGE_EN_SWTICH_VN_VNDAC_NSURGE_EN_MASK 0x01 + +/* WCD939X_HPHLR_SURGE_MISC1 Fields: */ +#define WCD939X_HPHLR_SURGE_MISC1_EN_VNEG_PULLDN_MASK 0x80 +#define WCD939X_HPHLR_SURGE_MISC1_EN_OFFSET_36MV_NSURGE_RESLADDER_MASK 0x40 +#define WCD939X_HPHLR_SURGE_MISC1_EN_NMOS_LAMP_MASK 0x20 +#define WCD939X_HPHLR_SURGE_MISC1_EN_NCLAMP_REG_HPHL_MASK 0x10 +#define WCD939X_HPHLR_SURGE_MISC1_EN_NCLAMP_REG_HPHR_MASK 0x08 +#define WCD939X_HPHLR_SURGE_MISC1_SPARE_BITS_MASK 0x07 + +/* WCD939X_HPHLR_SURGE_STATUS Fields: */ +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_CLAMP_SW_STATUS_MASK 0x80 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_CLAMP_SW_STATUS_MASK 0x40 +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_PSURGE_COMP_STATUS_MASK 0x20 +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_NSURGE_COMP_STATUS_MASK 0x10 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_PSURGE_COMP_STATUS_MASK 0x08 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_NSURGE_COMP_STATUS_MASK 0x04 +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_SURGE_DET_INTR_EN_MASK 0x02 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_SURGE_DET_INTR_EN_MASK 0x01 + + +/* WCD939X_EAR_EN_REG Fields: */ +#define WCD939X_EAR_EN_REG_EAR_DAC_DATA_RESET_MASK 0x80 +#define WCD939X_EAR_EN_REG_EAR_DAC_DATA_EN_MASK 0x40 +#define WCD939X_EAR_EN_REG_EAR_DAC_REF_EN_MASK 0x20 +#define WCD939X_EAR_EN_REG_EAR_VCM_EN_MASK 0x10 +#define WCD939X_EAR_EN_REG_EAR_AMP_EN_MASK 0x08 +#define WCD939X_EAR_EN_REG_EAR_BIAS_EN_MASK 0x04 +#define WCD939X_EAR_EN_REG_EAR_CNP_FSM_EN_MASK 0x02 +#define WCD939X_EAR_EN_REG_EAR_OUTPUT_SHORT_MASK 0x01 + +/* WCD939X_EAR_PA_CON Fields: */ +#define WCD939X_EAR_PA_CON_EAR_ANA_AUX_EN_MASK 0x80 +#define WCD939X_EAR_PA_CON_EAR_CMFB_SF_BYPASS_MASK 0x40 +#define WCD939X_EAR_PA_CON_EAR_SF_CURR_MASK 0x20 +#define WCD939X_EAR_PA_CON_EAR_BTI_CTL_MASK 0x10 +#define WCD939X_EAR_PA_CON_EAR_GM3_IBIAS_CTL_MASK 0x0f + +/* WCD939X_EAR_SP_CON Fields: */ +#define WCD939X_EAR_SP_CON_EAR_SP_INT_EN_MASK 0x80 +#define WCD939X_EAR_SP_CON_EAR_SP_AUTO_SHT_DWN_MASK 0x40 +#define WCD939X_EAR_SP_CON_SP_LIMIT_CURR_NMOS_MASK 0x38 +#define WCD939X_EAR_SP_CON_SP_LIMIT_CURR_PMOS_MASK 0x07 + +/* WCD939X_EAR_DAC_CON Fields: */ +#define WCD939X_EAR_DAC_CON_DAC_SAMPLE_EDGE_SEL_MASK 0x80 +#define WCD939X_EAR_DAC_CON_REF_DBG_EN_MASK 0x40 +#define WCD939X_EAR_DAC_CON_REF_DBG_GAIN_MASK 0x38 +#define WCD939X_EAR_DAC_CON_GAIN_DAC_MASK 0x06 +#define WCD939X_EAR_DAC_CON_INV_DATA_MASK 0x01 + +/* WCD939X_EAR_CNP_FSM_CON Fields: */ +#define WCD939X_EAR_CNP_FSM_CON_CNP_FSM_CLK_DIV1_MASK 0xf0 +#define WCD939X_EAR_CNP_FSM_CON_CNP_FSM_CLK_DIV2_MASK 0x0c +#define WCD939X_EAR_CNP_FSM_CON_SCD_FSM_DEGLITCH_SEL_MASK 0x03 + +/* WCD939X_EAR_TEST_CTL Fields: */ +#define WCD939X_EAR_TEST_CTL_DTEST_EN_MASK 0x80 +#define WCD939X_EAR_TEST_CTL_DTEST_SEL_2_MASK 0x40 +#define WCD939X_EAR_TEST_CTL_EAR_RDAC_ATEST_EN_MASK 0x20 +#define WCD939X_EAR_TEST_CTL_EAR_PA_ATEST_SEL_MASK 0x1f + +/* WCD939X_STATUS_REG_1 Fields: */ +#define WCD939X_STATUS_REG_1_SP_INT_MASK 0x80 +#define WCD939X_STATUS_REG_1_SP_ALL_OUT_MASK 0x40 +#define WCD939X_STATUS_REG_1_SP_NMOS_OUT_MASK 0x20 +#define WCD939X_STATUS_REG_1_SP_PMOS_OUT_MASK 0x10 +#define WCD939X_STATUS_REG_1_PA_READY_MASK 0x08 +#define WCD939X_STATUS_REG_1_CNP_FSM_STATUS_MASK 0x04 + +/* WCD939X_STATUS_REG_2 Fields: */ +#define WCD939X_STATUS_REG_2_PA_EN_MASK 0x80 +#define WCD939X_STATUS_REG_2_BIAS_EN_MASK 0x40 +#define WCD939X_STATUS_REG_2_DAC_EN_MASK 0x20 +#define WCD939X_STATUS_REG_2_VCM_EN_MASK 0x10 +#define WCD939X_STATUS_REG_2_CLK_EN_MASK 0x08 +#define WCD939X_STATUS_REG_2_SCD_EN_MASK 0x04 +#define WCD939X_STATUS_REG_2_SHORT_EN_MASK 0x02 +#define WCD939X_STATUS_REG_2_DAC_RESET_MASK 0x01 + + +/* WCD939X_ANA_NEW_PAGE Fields: */ +#define WCD939X_ANA_NEW_PAGE_VALUE_MASK 0xff + + +/* WCD939X_ANA_HPH2 Fields: */ +#define WCD939X_ANA_HPH2_HIFI_2VPK_PA_GAIN_CTL_MASK 0x80 +#define WCD939X_ANA_HPH2_ULP_VREF_CTL_MASK 0x40 +#define WCD939X_ANA_HPH2_SPARE_BITS_MASK 0x3f + +/* WCD939X_ANA_HPH3 Fields: */ +#define WCD939X_ANA_HPH3_SPARE_BITS_MASK 0xff + + +/* WCD939X_SLEEP_CTL Fields: */ +#define WCD939X_SLEEP_CTL_SPARE_BITS_MASK 0x80 +#define WCD939X_SLEEP_CTL_LDOL_BG_SEL_MASK 0x10 +#define WCD939X_SLEEP_CTL_BG_CTL_MASK 0x0e +#define WCD939X_SLEEP_CTL_DTEST_EN_MASK 0x01 + +/* WCD939X_WATCHDOG_CTL Fields: */ +#define WCD939X_WATCHDOG_CTL_EN_WATCHDOG_MASK 0x80 +#define WCD939X_WATCHDOG_CTL_EN_WATCHDOG_VREFGEN_MASK 0x40 +#define WCD939X_WATCHDOG_CTL_BYPASS_WATCHDOG_MASK 0x20 +#define WCD939X_WATCHDOG_CTL_ATEST_CTL_MASK 0x1c + + +/* WCD939X_ELECT_REM_CLAMP_CTL Fields: */ +#define WCD939X_ELECT_REM_CLAMP_CTL_FSM_ELECT_CLAMP_EN_MASK 0x80 +#define WCD939X_ELECT_REM_CLAMP_CTL_SLNQ_ELECT_CLAMP_EN_MASK 0x40 +#define WCD939X_ELECT_REM_CLAMP_CTL_SLNQ_FAIL_CLAMP_EN_MASK 0x20 +#define WCD939X_ELECT_REM_CLAMP_CTL_SLNQ_ELECT_REM_RST_MASK 0x10 + +/* WCD939X_CTL_1 Fields: */ +#define WCD939X_CTL_1_RCO_EN_MASK 0x80 +#define WCD939X_CTL_1_ADC_MODE_MASK 0x10 +#define WCD939X_CTL_1_ADC_ENABLE_MASK 0x08 +#define WCD939X_CTL_1_DETECTION_DONE_MASK 0x04 +#define WCD939X_CTL_1_BTN_DBNC_CTL_MASK 0x03 + +/* WCD939X_CTL_2 Fields: */ +#define WCD939X_CTL_2_MUX_CTL_MASK 0x70 +#define WCD939X_CTL_2_M_RTH_CTL_MASK 0x0c +#define WCD939X_CTL_2_HS_VREF_CTL_MASK 0x03 + +/* WCD939X_PLUG_DETECT_CTL Fields: */ +#define WCD939X_PLUG_DETECT_CTL_SPARE_BITS_7_6_MASK 0xc0 +#define WCD939X_PLUG_DETECT_CTL_MIC_CLAMP_CTL_MASK 0x30 +#define WCD939X_PLUG_DETECT_CTL_INSREM_DBNC_CTL_MASK 0x0f + +/* WCD939X_ZDET_ANA_CTL Fields: */ +#define WCD939X_ZDET_ANA_CTL_AVERAGING_EN_MASK 0x80 +#define WCD939X_ZDET_ANA_CTL_ZDET_MAXV_CTL_MASK 0x70 +#define WCD939X_ZDET_ANA_CTL_ZDET_RANGE_CTL_MASK 0x0f + +/* WCD939X_ZDET_RAMP_CTL Fields: */ +#define WCD939X_ZDET_RAMP_CTL_ZDET_ACC1_MIN_CTL_MASK 0x70 +#define WCD939X_ZDET_RAMP_CTL_ZDET_RAMP_TIME_CTL_MASK 0x0f + +/* WCD939X_FSM_STATUS Fields: */ +#define WCD939X_FSM_STATUS_ADC_TIMEOUT_MASK 0x80 +#define WCD939X_FSM_STATUS_ADC_COMPLETE_MASK 0x40 +#define WCD939X_FSM_STATUS_HS_M_COMP_STATUS_MASK 0x20 +#define WCD939X_FSM_STATUS_FAST_PRESS_FLAG_STATUS_MASK 0x10 +#define WCD939X_FSM_STATUS_FAST_REMOVAL_FLAG_STATUS_MASK 0x08 +#define WCD939X_FSM_STATUS_REMOVAL_FLAG_STATUS_MASK 0x04 +#define WCD939X_FSM_STATUS_ELECT_REM_RT_STATUS_MASK 0x02 +#define WCD939X_FSM_STATUS_BTN_STATUS_MASK 0x01 + +/* WCD939X_ADC_RESULT Fields: */ +#define WCD939X_ADC_RESULT_ADC_RESULT_MASK 0xff + + +/* WCD939X_TX_CH12_MUX Fields: */ +#define WCD939X_TX_CH12_MUX_SPARE_BITS_MASK 0xc0 +#define WCD939X_TX_CH12_MUX_CH2_SEL_MASK 0x38 +#define WCD939X_TX_CH12_MUX_CH1_SEL_MASK 0x07 + +/* WCD939X_TX_CH34_MUX Fields: */ +#define WCD939X_TX_CH34_MUX_SPARE_BITS_MASK 0xc0 +#define WCD939X_TX_CH34_MUX_CH4_SEL_MASK 0x38 +#define WCD939X_TX_CH34_MUX_CH3_SEL_MASK 0x07 + + +/* WCD939X_DIE_CRK_DET_EN Fields: */ +#define WCD939X_DIE_CRK_DET_EN_DIE_CRK_DET_EN_MASK 0x80 +#define WCD939X_DIE_CRK_DET_EN_SEL_CURR_INJCT_PT_MRING_MASK 0x40 + +/* WCD939X_DIE_CRK_DET_OUT Fields: */ +#define WCD939X_DIE_CRK_DET_OUT_DIE_CRK_DET_OUT_MASK 0x80 + + +/* WCD939X_RDAC_GAIN_CTL Fields: */ +#define WCD939X_RDAC_GAIN_CTL_SPARE_BITS_MASK 0xff + +/* WCD939X_PA_GAIN_CTL_L Fields: */ +#define WCD939X_PA_GAIN_CTL_L_EN_HPHPA_2VPK_MASK 0x80 +#define WCD939X_PA_GAIN_CTL_L_RX_SUPPLY_LEVEL_MASK 0x40 +#define WCD939X_PA_GAIN_CTL_L_DAC_DR_BOOST_MASK 0x20 +#define WCD939X_PA_GAIN_CTL_L_PA_GAIN_L_MASK 0x1f + +/* WCD939X_RDAC_VREF_CTL Fields: */ +#define WCD939X_RDAC_VREF_CTL_DAC_REF_EFUSE_TUNE_EN_MASK 0x80 +#define WCD939X_RDAC_VREF_CTL_DAC_VREFN_TUNE_MASK 0x70 +#define WCD939X_RDAC_VREF_CTL_REFCURRENT_2UA_MASK 0x08 +#define WCD939X_RDAC_VREF_CTL_DAC_VREFP_TUNE_MASK 0x07 + +/* WCD939X_RDAC_OVERRIDE_CTL Fields: */ +#define WCD939X_RDAC_OVERRIDE_CTL_VDDRX_LDO_LIFT_BYPASS_MASK 0x80 +#define WCD939X_RDAC_OVERRIDE_CTL_REFBUF_IREF_OVRIDE_MASK 0x40 +#define WCD939X_RDAC_OVERRIDE_CTL_SPARE_BITS1_MASK 0x30 +#define WCD939X_RDAC_OVERRIDE_CTL_RDAC_IDLE_DETECT_OVERRIDE_MASK 0x08 +#define WCD939X_RDAC_OVERRIDE_CTL_SPARE_BITS2_MASK 0x07 + +/* WCD939X_PA_GAIN_CTL_R Fields: */ +#define WCD939X_PA_GAIN_CTL_R_D_RCO_CLK_EN_MASK 0x80 +#define WCD939X_PA_GAIN_CTL_R_SPARE_BITS_MASK 0x60 +#define WCD939X_PA_GAIN_CTL_R_PA_GAIN_R_MASK 0x1f + +/* WCD939X_PA_MISC1 Fields: */ +#define WCD939X_PA_MISC1_EN_AUTO_CMPDR_DETECTION_MASK 0x80 +#define WCD939X_PA_MISC1_EN_PA_IDLE_DETECT_OVERRIDE_MASK 0x40 +#define WCD939X_PA_MISC1_D_PZ_INF_EN_MASK 0x20 +#define WCD939X_PA_MISC1_HPHPA_BW_PROG_MASK 0x18 +#define WCD939X_PA_MISC1_PA_CHOP_EN_OVERRIDE_MASK 0x04 +#define WCD939X_PA_MISC1_OCP_FSM_LOCK_EN_MASK 0x02 +#define WCD939X_PA_MISC1_AUTOCHOP_PDN_SEQ_OVERRIDE_MASK 0x01 + +/* WCD939X_PA_MISC2 Fields: */ +#define WCD939X_PA_MISC2_HPHPA_HI_Z_MASK 0x80 +#define WCD939X_PA_MISC2_HPH_PSRR_ENH_MASK 0x40 +#define WCD939X_PA_MISC2_FORCE_IQCTRL_MASK 0x20 +#define WCD939X_PA_MISC2_FORCE_PSRREH_MASK 0x10 +#define WCD939X_PA_MISC2_CHOP_CLKLAP_SEL_MASK 0x08 +#define WCD939X_PA_MISC2_SPARE_BITS_MASK 0x04 +#define WCD939X_PA_MISC2_IDLE_DETECT_L_DTEST_ENABLE_MASK 0x02 +#define WCD939X_PA_MISC2_IDLE_DETECT_R_DTEST_ENABLE_MASK 0x01 + +/* WCD939X_PA_RDAC_MISC Fields: */ +#define WCD939X_PA_RDAC_MISC_CNP_WG_FINE_TIME_LSB_CTL_MASK 0xf0 +#define WCD939X_PA_RDAC_MISC_RDAC_NSW_REG_CTL_MASK 0x08 +#define WCD939X_PA_RDAC_MISC_RDAC_PSW_NSW_CTL_OVERRIDE_MASK 0x04 +#define WCD939X_PA_RDAC_MISC_RDAC_PSW_NSW_REG_CTL_MASK 0x03 + +/* WCD939X_HPH_TIMER1 Fields: */ +#define WCD939X_HPH_TIMER1_CURR_IDIV_CTL_CMPDR_OFF_MASK 0xe0 +#define WCD939X_HPH_TIMER1_CURR_IDIV_CTL_AUTOCHOP_MASK 0x1c +#define WCD939X_HPH_TIMER1_AUTOCHOP_TIMER_CTL_EN_MASK 0x02 +#define WCD939X_HPH_TIMER1_SPARE_BITS_MASK 0x01 + +/* WCD939X_HPH_TIMER2 Fields: */ +#define WCD939X_HPH_TIMER2_VREF_TIMER_IDLESTATE_MASK 0xe0 +#define WCD939X_HPH_TIMER2_CNP_WG_FINE_TIME_LSB_CTL_IDLE_MASK 0x1e +#define WCD939X_HPH_TIMER2_SPARE_BITS_MASK 0x01 + +/* WCD939X_HPH_TIMER3 Fields: */ +#define WCD939X_HPH_TIMER3_WG_FINE_TIMER_CMPDR_OFF_MASK 0xff + +/* WCD939X_HPH_TIMER4 Fields: */ +#define WCD939X_HPH_TIMER4_WG_FINE_TIMER_AUTOCHOP_MASK 0xff + +/* WCD939X_PA_RDAC_MISC2 Fields: */ +#define WCD939X_PA_RDAC_MISC2_SPARE_BITS_MASK 0xe0 +#define WCD939X_PA_RDAC_MISC2_RDAC_DNW_RES_FORCE_BYPASS_MASK 0x10 +#define WCD939X_PA_RDAC_MISC2_SCLPF_BYPASS_TIMER_STG1_MASK 0x0c +#define WCD939X_PA_RDAC_MISC2_SCLPF_BYPASS_TIMER_STG2_MASK 0x03 + +/* WCD939X_PA_RDAC_MISC3 Fields: */ +#define WCD939X_PA_RDAC_MISC3_SPARE_BITS_MASK 0xff + +/* WCD939X_RDAC_HD2_CTL_L Fields: */ +#define WCD939X_RDAC_HD2_CTL_L_EN_HD2_RES_DIV_L_MASK 0x80 +#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_PULLGND_L_MASK 0x40 +#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L_MASK 0x3f + +/* WCD939X_RDAC_HD2_CTL_R Fields: */ +#define WCD939X_RDAC_HD2_CTL_R_EN_HD2_RES_DIV_R_MASK 0x80 +#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_PULLGND_L_MASK 0x40 +#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R_MASK 0x3f + + +/* WCD939X_HPH_RDAC_BIAS_LOHIFI Fields: */ +#define WCD939X_HPH_RDAC_BIAS_LOHIFI_HPHPA_BIAS_LOHIFI_MASK 0xf0 +#define WCD939X_HPH_RDAC_BIAS_LOHIFI_HPHRDAC_BIAS_LOHIFI_MASK 0x0f + +/* WCD939X_HPH_RDAC_BIAS_ULP Fields: */ +#define WCD939X_HPH_RDAC_BIAS_ULP_SLEEPBG_PWR_SEL_MASK 0x80 +#define WCD939X_HPH_RDAC_BIAS_ULP_SLEEPBG_PWR_SEL_OVERRIDE_MASK 0x40 +#define WCD939X_HPH_RDAC_BIAS_ULP_CDC_3P5MM_LEGACY_IN_MASK 0x20 +#define WCD939X_HPH_RDAC_BIAS_ULP_SPARE_BITS1_MASK 0x10 +#define WCD939X_HPH_RDAC_BIAS_ULP_HPHRDAC_BIAS_ULP_MASK 0x0f + +/* WCD939X_HPH_RDAC_LDO_LP Fields: */ +#define WCD939X_HPH_RDAC_LDO_LP_HPHRDAC_1P6VLDO_BIAS_LP_MASK 0xf0 +#define WCD939X_HPH_RDAC_LDO_LP_HPHRDAC_N1P6VLDO_BIAS_LP_MASK 0x0f + + +/* WCD939X_MOISTURE_DET_DC_CTRL Fields: */ +#define WCD939X_MOISTURE_DET_DC_CTRL_ONCOUNT_MASK 0x60 +#define WCD939X_MOISTURE_DET_DC_CTRL_OFFCOUNT_MASK 0x1f + +/* WCD939X_MOISTURE_DET_POLLING_CTRL Fields: */ +#define WCD939X_MOISTURE_DET_POLLING_CTRL_HPHL_PA_EN_MASK 0x40 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_DTEST_EN_MASK 0x30 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOISTURE_OVRD_POLLING_MASK 0x08 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOISTURE_EN_POLLING_MASK 0x04 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOISTURE_DBNC_TIME_MASK 0x03 + +/* WCD939X_MECH_DET_CURRENT Fields: */ +#define WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL_MASK 0x1f + +/* WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW Fields: */ +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_SPARE_BITS_7_MASK 0x80 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_ZDET_CLK_SEL_MASK 0x40 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_ZDET_SUBSEL_OV_MASK 0x20 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_ZDET_CLK_EN_CTL_MASK 0x10 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_MOIS_CURRENT_CTL_SEL_MASK 0x08 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_MOIS_CURRENT_ADD_MASK 0x04 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_MECH_REF_SEL_MASK 0x03 + + +/* WCD939X_EAR_CHOPPER_CON Fields: */ +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_EN_MASK 0x80 +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_DIV_MASK 0x78 +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_INV_MASK 0x04 +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_OVERLAP_MASK 0x02 +#define WCD939X_EAR_CHOPPER_CON_SCD_SHTDWN_FAST_PATH_DIS_MASK 0x01 + +/* WCD939X_CNP_VCM_CON1 Fields: */ +#define WCD939X_CNP_VCM_CON1_SCD_EN_TIME_SEL_MASK 0x80 +#define WCD939X_CNP_VCM_CON1_NO_DYN_BIAS_DURING_STARTUP_MASK 0x40 +#define WCD939X_CNP_VCM_CON1_CNP_VCM_GEN_START_MASK 0x3f + +/* WCD939X_CNP_VCM_CON2 Fields: */ +#define WCD939X_CNP_VCM_CON2_DTEST_SEL_MASK 0xc0 +#define WCD939X_CNP_VCM_CON2_CNP_VCM_GEN_STOP_MASK 0x3f + +/* WCD939X_EAR_DYNAMIC_BIAS Fields: */ +#define WCD939X_EAR_DYNAMIC_BIAS_EAR_DYN_BIAS_SEL_MASK 0xe0 +#define WCD939X_EAR_DYNAMIC_BIAS_EAR_BIAS_CURR_MASK 0x1f + + +/* WCD939X_WATCHDOG_CTL_1 Fields: */ +#define WCD939X_WATCHDOG_CTL_1_VREF_HI_CTL_MASK 0x1f + +/* WCD939X_WATCHDOG_CTL_2 Fields: */ +#define WCD939X_WATCHDOG_CTL_2_VREF_LO_CTL_MASK 0x1f + + +/* WCD939X_DIE_CRK_DET_INT1 Fields: */ +#define WCD939X_DIE_CRK_DET_INT1_SEL_EDGE_DET_MASK 0xc0 +#define WCD939X_DIE_CRK_DET_INT1_EN_RINGM_ATEST_MASK 0x20 +#define WCD939X_DIE_CRK_DET_INT1_EN_RINGP_ATEST_MASK 0x10 +#define WCD939X_DIE_CRK_DET_INT1_RING_CURR_SEL_MASK 0x0e +#define WCD939X_DIE_CRK_DET_INT1_EN_VREF_ATEST_MASK 0x01 + +/* WCD939X_DIE_CRK_DET_INT2 Fields: */ +#define WCD939X_DIE_CRK_DET_INT2_REF_CURR_SEL_MASK 0xe0 +#define WCD939X_DIE_CRK_DET_INT2_COMP_STG1_IBIAS_MASK 0x18 +#define WCD939X_DIE_CRK_DET_INT2_COMP_STG2_IBIAS_MASK 0x06 +#define WCD939X_DIE_CRK_DET_INT2_EN_ATEST_MASK 0x01 + + +/* WCD939X_TXFE_DIVSTOP_L2 Fields: */ +#define WCD939X_TXFE_DIVSTOP_L2_DIV_L2_MASK 0xff + +/* WCD939X_TXFE_DIVSTOP_L1 Fields: */ +#define WCD939X_TXFE_DIVSTOP_L1_DIV_L1_MASK 0xff + +/* WCD939X_TXFE_DIVSTOP_L0 Fields: */ +#define WCD939X_TXFE_DIVSTOP_L0_DIV_L0_MASK 0xff + +/* WCD939X_TXFE_DIVSTOP_ULP1P2M Fields: */ +#define WCD939X_TXFE_DIVSTOP_ULP1P2M_DIV_ULP1P2M_MASK 0xff + +/* WCD939X_TXFE_DIVSTOP_ULP0P6M Fields: */ +#define WCD939X_TXFE_DIVSTOP_ULP0P6M_DIV_ULP0P6M_MASK 0xff + +/* WCD939X_TXFE_ICTRL_STG1_L2L1 Fields: */ +#define WCD939X_TXFE_ICTRL_STG1_L2L1_NINIT_L2_MASK 0xc0 +#define WCD939X_TXFE_ICTRL_STG1_L2L1_ICTRL_STG1_L2L1_MASK 0x1f + +/* WCD939X_TXFE_ICTRL_STG1_L0 Fields: */ +#define WCD939X_TXFE_ICTRL_STG1_L0_NINIT_L1_MASK 0xc0 +#define WCD939X_TXFE_ICTRL_STG1_L0_ICTRL_STG1_L0_MASK 0x1f + +/* WCD939X_TXFE_ICTRL_STG1_ULP Fields: */ +#define WCD939X_TXFE_ICTRL_STG1_ULP_NINIT_L0_MASK 0xc0 +#define WCD939X_TXFE_ICTRL_STG1_ULP_ICTRL_STG1_ULP_MASK 0x1f + +/* WCD939X_TXFE_ICTRL_STG2MAIN_L2L1 Fields: */ +#define WCD939X_TXFE_ICTRL_STG2MAIN_L2L1_NINIT_ULP1P2M_MASK 0xc0 +#define WCD939X_TXFE_ICTRL_STG2MAIN_L2L1_ICTRL_STG2MAIN_L2L1_MASK 0x1f + +/* WCD939X_TXFE_ICTRL_STG2MAIN_L0 Fields: */ +#define WCD939X_TXFE_ICTRL_STG2MAIN_L0_NINIT_ULP0P6M_MASK 0xc0 +#define WCD939X_TXFE_ICTRL_STG2MAIN_L0_ADCREF_ULPIBIAS_EN_MASK 0x20 +#define WCD939X_TXFE_ICTRL_STG2MAIN_L0_ICTRL_STG2MAIN_L0_MASK 0x1f + +/* WCD939X_TXFE_ICTRL_STG2MAIN_ULP Fields: */ +#define WCD939X_TXFE_ICTRL_STG2MAIN_ULP_ICTRL_STG2MAIN_ULP_MASK 0x1f + +/* WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0 Fields: */ +#define WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0_ICTRL_STG2CASC_L2L1_MASK 0xf0 +#define WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0_ICTRL_STG2CASC_L0_MASK 0x0f + +/* WCD939X_TXFE_ICTRL_STG2CASC_ULP Fields: */ +#define WCD939X_TXFE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M_MASK 0xf0 +#define WCD939X_TXFE_ICTRL_STG2CASC_ULP_ICTRL_STG2CASC_ULP_MASK 0x0f + +/* WCD939X_TXADC_SCBIAS_L2L1 Fields: */ +#define WCD939X_TXADC_SCBIAS_L2L1_ICTRL_SCBIAS_L2_MASK 0xf0 +#define WCD939X_TXADC_SCBIAS_L2L1_ICTRL_SCBIAS_L1_MASK 0x0f + +/* WCD939X_TXADC_SCBIAS_L0ULP Fields: */ +#define WCD939X_TXADC_SCBIAS_L0ULP_ICTRL_SCBIAS_L0_MASK 0xf0 +#define WCD939X_TXADC_SCBIAS_L0ULP_ICTRL_SCBIAS_ULP1P2M_MASK 0x0f + +/* WCD939X_TXADC_INT_L2 Fields: */ +#define WCD939X_TXADC_INT_L2_INT1_L2_MASK 0xf0 +#define WCD939X_TXADC_INT_L2_INT2_L2_MASK 0x0f + +/* WCD939X_TXADC_INT_L1 Fields: */ +#define WCD939X_TXADC_INT_L1_INT1_L1_MASK 0xf0 +#define WCD939X_TXADC_INT_L1_INT2_L1_MASK 0x0f + +/* WCD939X_TXADC_INT_L0 Fields: */ +#define WCD939X_TXADC_INT_L0_INT1_L0_MASK 0xf0 +#define WCD939X_TXADC_INT_L0_INT2_L0_MASK 0x0f + +/* WCD939X_TXADC_INT_ULP Fields: */ +#define WCD939X_TXADC_INT_ULP_INT1_ULP_MASK 0xf0 +#define WCD939X_TXADC_INT_ULP_INT2_ULP_MASK 0x0f + + +/* WCD939X_DIGITAL_PAGE Fields: */ +#define WCD939X_DIGITAL_PAGE_PAG_REG_MASK 0xff + +/* WCD939X_CHIP_ID0 Fields: */ +#define WCD939X_CHIP_ID0_BYTE_0_MASK 0xff + +/* WCD939X_CHIP_ID1 Fields: */ +#define WCD939X_CHIP_ID1_BYTE_1_MASK 0xff + +/* WCD939X_CHIP_ID2 Fields: */ +#define WCD939X_CHIP_ID2_BYTE_2_MASK 0xff + +/* WCD939X_CHIP_ID3 Fields: */ +#define WCD939X_CHIP_ID3_BYTE_3_MASK 0xff + +/* WCD939X_SWR_TX_CLK_RATE Fields: */ +#define WCD939X_SWR_TX_CLK_RATE_CLK_RATE_BK_1_MASK 0xf0 +#define WCD939X_SWR_TX_CLK_RATE_CLK_RATE_BK_0_MASK 0x0f + +/* WCD939X_CDC_RST_CTL Fields: */ +#define WCD939X_CDC_RST_CTL_ANA_SW_RST_N_MASK 0x02 +#define WCD939X_CDC_RST_CTL_DIG_SW_RST_N_MASK 0x01 + +/* WCD939X_TOP_CLK_CFG Fields: */ +#define WCD939X_TOP_CLK_CFG_RX_CLK_CFG_MASK 0x06 +#define WCD939X_TOP_CLK_CFG_TX_CLK_CFG_MASK 0x01 + +/* WCD939X_CDC_ANA_CLK_CTL Fields: */ +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV4_CLK_EN_MASK 0x20 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN_MASK 0x10 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN_MASK 0x08 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN_MASK 0x04 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN_MASK 0x02 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN_MASK 0x01 + +/* WCD939X_CDC_DIG_CLK_CTL Fields: */ +#define WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN_MASK 0x80 +#define WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN_MASK 0x40 +#define WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN_MASK 0x20 +#define WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN_MASK 0x10 +#define WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN_MASK 0x04 +#define WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN_MASK 0x02 +#define WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN_MASK 0x01 + +/* WCD939X_SWR_RST_EN Fields: */ +#define WCD939X_SWR_RST_EN_RX_RESET_SYNC_LOST_EN_MASK 0x20 +#define WCD939X_SWR_RST_EN_RX_RESET_SWR_BUS_EN_MASK 0x10 +#define WCD939X_SWR_RST_EN_RX_RESET_SWR_REG_EN_MASK 0x08 +#define WCD939X_SWR_RST_EN_TX_RESET_SYNC_LOST_EN_MASK 0x04 +#define WCD939X_SWR_RST_EN_TX_RESET_SWR_BUS_EN_MASK 0x02 +#define WCD939X_SWR_RST_EN_TX_RESET_SWR_REG_EN_MASK 0x01 + +/* WCD939X_CDC_PATH_MODE Fields: */ +#define WCD939X_CDC_PATH_MODE_EAR_MODE_MASK 0x40 +#define WCD939X_CDC_PATH_MODE_TXD2_MODE_MASK 0x30 +#define WCD939X_CDC_PATH_MODE_TXD1_MODE_MASK 0x0c +#define WCD939X_CDC_PATH_MODE_TXD0_MODE_MASK 0x03 + +/* WCD939X_CDC_RX_RST Fields: */ +#define WCD939X_CDC_RX_RST_RX2_SOFT_RST_MASK 0x04 +#define WCD939X_CDC_RX_RST_RX1_SOFT_RST_MASK 0x02 +#define WCD939X_CDC_RX_RST_RX0_SOFT_RST_MASK 0x01 + +/* WCD939X_CDC_RX0_CTL Fields: */ +#define WCD939X_CDC_RX0_CTL_DSM_DITHER_ENABLE_MASK 0x80 +#define WCD939X_CDC_RX0_CTL_DEM_DITHER_ENABLE_MASK 0x40 +#define WCD939X_CDC_RX0_CTL_DEM_MID_ENABLE_MASK 0x20 +#define WCD939X_CDC_RX0_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_MASK 0x10 +#define WCD939X_CDC_RX0_CTL_DEM_SWITCHING_BLOCK_ENABLE_MASK 0x08 +#define WCD939X_CDC_RX0_CTL_DEM_SEGMENTING_BLOCK_ENABLE_MASK 0x04 +#define WCD939X_CDC_RX0_CTL_DEM_BYPASS_MASK 0x02 + +/* WCD939X_CDC_RX1_CTL Fields: */ +#define WCD939X_CDC_RX1_CTL_DSM_DITHER_ENABLE_MASK 0x80 +#define WCD939X_CDC_RX1_CTL_DEM_DITHER_ENABLE_MASK 0x40 +#define WCD939X_CDC_RX1_CTL_DEM_MID_ENABLE_MASK 0x20 +#define WCD939X_CDC_RX1_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_MASK 0x10 +#define WCD939X_CDC_RX1_CTL_DEM_SWITCHING_BLOCK_ENABLE_MASK 0x08 +#define WCD939X_CDC_RX1_CTL_DEM_SEGMENTING_BLOCK_ENABLE_MASK 0x04 +#define WCD939X_CDC_RX1_CTL_DEM_BYPASS_MASK 0x02 + +/* WCD939X_CDC_RX2_CTL Fields: */ +#define WCD939X_CDC_RX2_CTL_DSM_DITHER_ENABLE_MASK 0x80 +#define WCD939X_CDC_RX2_CTL_DEM_DITHER_ENABLE_MASK 0x40 +#define WCD939X_CDC_RX2_CTL_DEM_MID_ENABLE_MASK 0x20 +#define WCD939X_CDC_RX2_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_MASK 0x10 +#define WCD939X_CDC_RX2_CTL_DEM_SWITCHING_BLOCK_ENABLE_MASK 0x08 +#define WCD939X_CDC_RX2_CTL_DEM_SEGMENTING_BLOCK_ENABLE_MASK 0x04 +#define WCD939X_CDC_RX2_CTL_DEM_BYPASS_MASK 0x02 + +/* WCD939X_CDC_TX_ANA_MODE_0_1 Fields: */ +#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE_MASK 0xf0 +#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE_MASK 0x0f + +/* WCD939X_CDC_TX_ANA_MODE_2_3 Fields: */ +#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE_MASK 0xf0 +#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE_MASK 0x0f + +/* WCD939X_CDC_COMP_CTL_0 Fields: */ +#define WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN_MASK 0x02 +#define WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN_MASK 0x01 + +/* WCD939X_CDC_ANA_TX_CLK_CTL Fields: */ +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_MBHC_1P2M_CLK_EN_MASK 0x20 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX3_ADC_CLK_EN_MASK 0x10 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX2_ADC_CLK_EN_MASK 0x08 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX1_ADC_CLK_EN_MASK 0x04 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX0_ADC_CLK_EN_MASK 0x02 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN_MASK 0x01 + +/* WCD939X_CDC_HPH_DSM_A1_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A1_0_COEF_A1_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_A1_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A1_1_COEF_A1_MASK 0x01 + +/* WCD939X_CDC_HPH_DSM_A2_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A2_0_COEF_A2_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_A2_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A2_1_COEF_A2_MASK 0x0f + +/* WCD939X_CDC_HPH_DSM_A3_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A3_0_COEF_A3_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_A3_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A3_1_COEF_A3_MASK 0x07 + +/* WCD939X_CDC_HPH_DSM_A4_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A4_0_COEF_A4_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_A4_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A4_1_COEF_A4_MASK 0x03 + +/* WCD939X_CDC_HPH_DSM_A5_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A5_0_COEF_A5_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_A5_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A5_1_COEF_A5_MASK 0x03 + +/* WCD939X_CDC_HPH_DSM_A6_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A6_0_COEF_A6_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_A7_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A7_0_COEF_A7_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_C_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_0_COEF_C3_MASK 0xf0 +#define WCD939X_CDC_HPH_DSM_C_0_COEF_C2_MASK 0x0f + +/* WCD939X_CDC_HPH_DSM_C_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_1_COEF_C5_MASK 0xf0 +#define WCD939X_CDC_HPH_DSM_C_1_COEF_C4_MASK 0x0f + +/* WCD939X_CDC_HPH_DSM_C_2 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_2_COEF_C7_MASK 0xf0 +#define WCD939X_CDC_HPH_DSM_C_2_COEF_C6_MASK 0x0f + +/* WCD939X_CDC_HPH_DSM_C_3 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_3_COEF_C7_MASK 0x3f + +/* WCD939X_CDC_HPH_DSM_R1 Fields: */ +#define WCD939X_CDC_HPH_DSM_R1_SAT_LIMIT_R1_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_R2 Fields: */ +#define WCD939X_CDC_HPH_DSM_R2_SAT_LIMIT_R2_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_R3 Fields: */ +#define WCD939X_CDC_HPH_DSM_R3_SAT_LIMIT_R3_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_R4 Fields: */ +#define WCD939X_CDC_HPH_DSM_R4_SAT_LIMIT_R4_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_R5 Fields: */ +#define WCD939X_CDC_HPH_DSM_R5_SAT_LIMIT_R5_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_R6 Fields: */ +#define WCD939X_CDC_HPH_DSM_R6_SAT_LIMIT_R6_MASK 0xff + +/* WCD939X_CDC_HPH_DSM_R7 Fields: */ +#define WCD939X_CDC_HPH_DSM_R7_SAT_LIMIT_R7_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_A1_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A1_0_COEF_A1_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_A1_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A1_1_COEF_A1_MASK 0x01 + +/* WCD939X_CDC_EAR_DSM_A2_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A2_0_COEF_A2_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_A2_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A2_1_COEF_A2_MASK 0x0f + +/* WCD939X_CDC_EAR_DSM_A3_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A3_0_COEF_A3_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_A3_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A3_1_COEF_A3_MASK 0x07 + +/* WCD939X_CDC_EAR_DSM_A4_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A4_0_COEF_A4_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_A4_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A4_1_COEF_A4_MASK 0x03 + +/* WCD939X_CDC_EAR_DSM_A5_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A5_0_COEF_A5_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_A5_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A5_1_COEF_A5_MASK 0x03 + +/* WCD939X_CDC_EAR_DSM_A6_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A6_0_COEF_A6_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_A7_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A7_0_COEF_A7_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_C_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_0_COEF_C3_MASK 0xf0 +#define WCD939X_CDC_EAR_DSM_C_0_COEF_C2_MASK 0x0f + +/* WCD939X_CDC_EAR_DSM_C_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_1_COEF_C5_MASK 0xf0 +#define WCD939X_CDC_EAR_DSM_C_1_COEF_C4_MASK 0x0f + +/* WCD939X_CDC_EAR_DSM_C_2 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_2_COEF_C7_MASK 0xf0 +#define WCD939X_CDC_EAR_DSM_C_2_COEF_C6_MASK 0x0f + +/* WCD939X_CDC_EAR_DSM_C_3 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_3_COEF_C7_MASK 0x3f + +/* WCD939X_CDC_EAR_DSM_R1 Fields: */ +#define WCD939X_CDC_EAR_DSM_R1_SAT_LIMIT_R1_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_R2 Fields: */ +#define WCD939X_CDC_EAR_DSM_R2_SAT_LIMIT_R2_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_R3 Fields: */ +#define WCD939X_CDC_EAR_DSM_R3_SAT_LIMIT_R3_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_R4 Fields: */ +#define WCD939X_CDC_EAR_DSM_R4_SAT_LIMIT_R4_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_R5 Fields: */ +#define WCD939X_CDC_EAR_DSM_R5_SAT_LIMIT_R5_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_R6 Fields: */ +#define WCD939X_CDC_EAR_DSM_R6_SAT_LIMIT_R6_MASK 0xff + +/* WCD939X_CDC_EAR_DSM_R7 Fields: */ +#define WCD939X_CDC_EAR_DSM_R7_SAT_LIMIT_R7_MASK 0xff + +/* WCD939X_CDC_HPH_GAIN_RX_0 Fields: */ +#define WCD939X_CDC_HPH_GAIN_RX_0_GAIN_RX_MASK 0xff + +/* WCD939X_CDC_HPH_GAIN_RX_1 Fields: */ +#define WCD939X_CDC_HPH_GAIN_RX_1_GAIN_RX_MASK 0xff + +/* WCD939X_CDC_HPH_GAIN_DSD_0 Fields: */ +#define WCD939X_CDC_HPH_GAIN_DSD_0_GAIN_DSD_MASK 0xff + +/* WCD939X_CDC_HPH_GAIN_DSD_1 Fields: */ +#define WCD939X_CDC_HPH_GAIN_DSD_1_GAIN_DSD_MASK 0xff + +/* WCD939X_CDC_HPH_GAIN_DSD_2 Fields: */ +#define WCD939X_CDC_HPH_GAIN_DSD_2_GAIN_LATCH_MASK 0x02 +#define WCD939X_CDC_HPH_GAIN_DSD_2_GAIN_DSD_MASK 0x01 + +/* WCD939X_CDC_EAR_GAIN_DSD_0 Fields: */ +#define WCD939X_CDC_EAR_GAIN_DSD_0_GAIN_DSD_MASK 0xff + +/* WCD939X_CDC_EAR_GAIN_DSD_1 Fields: */ +#define WCD939X_CDC_EAR_GAIN_DSD_1_GAIN_DSD_MASK 0xff + +/* WCD939X_CDC_EAR_GAIN_DSD_2 Fields: */ +#define WCD939X_CDC_EAR_GAIN_DSD_2_GAIN_LATCH_MASK 0x02 +#define WCD939X_CDC_EAR_GAIN_DSD_2_GAIN_DSD_MASK 0x01 + +/* WCD939X_CDC_HPH_GAIN_CTL Fields: */ +#define WCD939X_CDC_HPH_GAIN_CTL_HPH_STEREO_EN_MASK 0x10 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN_MASK 0x08 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN_MASK 0x04 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_DSD_EN_MASK 0x02 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_DSD_EN_MASK 0x01 + +/* WCD939X_CDC_EAR_GAIN_CTL Fields: */ +#define WCD939X_CDC_EAR_GAIN_CTL_EAR_EN_MASK 0x01 + +/* WCD939X_CDC_EAR_PATH_CTL Fields: */ +#define WCD939X_CDC_EAR_PATH_CTL_EAR_GAIN_CTL_MASK 0x3e +#define WCD939X_CDC_EAR_PATH_CTL_EAR_MUX_SEL_MASK 0x01 + +/* WCD939X_CDC_SWR_CLH Fields: */ +#define WCD939X_CDC_SWR_CLH_CLH_CTL_MASK 0xff + +/* WCD939X_SWR_CLH_BYP Fields: */ +#define WCD939X_SWR_CLH_BYP_SWR_CLH_BYP_MASK 0x01 + +/* WCD939X_CDC_TX0_CTL Fields: */ +#define WCD939X_CDC_TX0_CTL_REQ_FB_SEL_MASK 0x40 +#define WCD939X_CDC_TX0_CTL_TX_DITHER_EN_MASK 0x20 +#define WCD939X_CDC_TX0_CTL_RANDOM_REGION_MASK 0x1f + +/* WCD939X_CDC_TX1_CTL Fields: */ +#define WCD939X_CDC_TX1_CTL_REQ_FB_SEL_MASK 0x40 +#define WCD939X_CDC_TX1_CTL_TX_DITHER_EN_MASK 0x20 +#define WCD939X_CDC_TX1_CTL_RANDOM_REGION_MASK 0x1f + +/* WCD939X_CDC_TX2_CTL Fields: */ +#define WCD939X_CDC_TX2_CTL_REQ_FB_SEL_MASK 0x40 +#define WCD939X_CDC_TX2_CTL_TX_DITHER_EN_MASK 0x20 +#define WCD939X_CDC_TX2_CTL_RANDOM_REGION_MASK 0x1f + +/* WCD939X_CDC_TX_RST Fields: */ +#define WCD939X_CDC_TX_RST_TX3_SOFT_RST_MASK 0x08 +#define WCD939X_CDC_TX_RST_TX2_SOFT_RST_MASK 0x04 +#define WCD939X_CDC_TX_RST_TX1_SOFT_RST_MASK 0x02 +#define WCD939X_CDC_TX_RST_TX0_SOFT_RST_MASK 0x01 + +/* WCD939X_CDC_REQ_CTL Fields: */ +#define WCD939X_CDC_REQ_CTL_TX3_WIDE_BAND_MASK 0x20 +#define WCD939X_CDC_REQ_CTL_TX2_WIDE_BAND_MASK 0x10 +#define WCD939X_CDC_REQ_CTL_TX1_WIDE_BAND_MASK 0x08 +#define WCD939X_CDC_REQ_CTL_TX0_WIDE_BAND_MASK 0x04 +#define WCD939X_CDC_REQ_CTL_FS_RATE_4P8_MASK 0x02 +#define WCD939X_CDC_REQ_CTL_NO_NOTCH_MASK 0x01 + +/* WCD939X_CDC_RST Fields: */ +#define WCD939X_CDC_RST_TX_SOFT_RST_MASK 0x02 +#define WCD939X_CDC_RST_RX_SOFT_RST_MASK 0x01 + +/* WCD939X_CDC_AMIC_CTL Fields: */ +#define WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL_MASK 0x08 +#define WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL_MASK 0x04 +#define WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL_MASK 0x02 +#define WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL_MASK 0x01 + +/* WCD939X_CDC_DMIC_CTL Fields: */ +#define WCD939X_CDC_DMIC_CTL_DMIC_LEGACY_SW_MODE_MASK 0x08 +#define WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN_MASK 0x04 +#define WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN_MASK 0x02 +#define WCD939X_CDC_DMIC_CTL_SOFT_RESET_MASK 0x01 + +/* WCD939X_CDC_DMIC1_CTL Fields: */ +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SCALE_SEL_MASK 0x70 +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN_MASK 0x08 +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SEL_MASK 0x07 + +/* WCD939X_CDC_DMIC2_CTL Fields: */ +#define WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN_MASK 0x80 +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SCALE_SEL_MASK 0x70 +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN_MASK 0x08 +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SEL_MASK 0x07 + +/* WCD939X_CDC_DMIC3_CTL Fields: */ +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SCALE_SEL_MASK 0x70 +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN_MASK 0x08 +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SEL_MASK 0x07 + +/* WCD939X_CDC_DMIC4_CTL Fields: */ +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SCALE_SEL_MASK 0x70 +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN_MASK 0x08 +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SEL_MASK 0x07 + +/* WCD939X_EFUSE_PRG_CTL Fields: */ +#define WCD939X_EFUSE_PRG_CTL_PRG_ADDR_MASK 0xff + +/* WCD939X_EFUSE_CTL Fields: */ +#define WCD939X_EFUSE_CTL_EFUSE_ST_CNT_MASK 0x3c +#define WCD939X_EFUSE_CTL_EFUSE_SOFT_RST_N_MASK 0x02 +#define WCD939X_EFUSE_CTL_EFUSE_EN_MASK 0x01 + +/* WCD939X_CDC_DMIC_RATE_1_2 Fields: */ +#define WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE_MASK 0xf0 +#define WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE_MASK 0x0f + +/* WCD939X_CDC_DMIC_RATE_3_4 Fields: */ +#define WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE_MASK 0xf0 +#define WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE_MASK 0x0f + +/* WCD939X_PDM_WD_CTL0 Fields: */ +#define WCD939X_PDM_WD_CTL0_HOLD_OFF_MASK 0x10 +#define WCD939X_PDM_WD_CTL0_TIME_OUT_SEL_MASK 0x08 +#define WCD939X_PDM_WD_CTL0_PDM_WD_EN_MASK 0x07 + +/* WCD939X_PDM_WD_CTL1 Fields: */ +#define WCD939X_PDM_WD_CTL1_HOLD_OFF_MASK 0x10 +#define WCD939X_PDM_WD_CTL1_TIME_OUT_SEL_MASK 0x08 +#define WCD939X_PDM_WD_CTL1_PDM_WD_EN_MASK 0x07 + +/* WCD939X_PDM_WD_CTL2 Fields: */ +#define WCD939X_PDM_WD_CTL2_HOLD_OFF_MASK 0x04 +#define WCD939X_PDM_WD_CTL2_TIME_OUT_SEL_MASK 0x02 +#define WCD939X_PDM_WD_CTL2_PDM_WD_EN_MASK 0x01 + +/* WCD939X_INTR_MODE Fields: */ +#define WCD939X_INTR_MODE_SWR_PULSE_CLR_MASK 0x20 +#define WCD939X_INTR_MODE_SWR_RX_INT_OUT_EN_MASK 0x10 +#define WCD939X_INTR_MODE_SWR_INTR_LEVEL_MASK 0x02 +#define WCD939X_INTR_MODE_INT_POLARITY_MASK 0x01 + +/* WCD939X_INTR_MASK_0 Fields: */ +#define WCD939X_INTR_MASK_0_HPHL_OCP_INT_MASK 0x80 +#define WCD939X_INTR_MASK_0_HPHR_CNP_INT_MASK 0x40 +#define WCD939X_INTR_MASK_0_HPHR_OCP_INT_MASK 0x20 +#define WCD939X_INTR_MASK_0_MBHC_SW_INT_MASK 0x10 +#define WCD939X_INTR_MASK_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD939X_INTR_MASK_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD939X_INTR_MASK_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD939X_INTR_MASK_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD939X_INTR_MASK_1 Fields: */ +#define WCD939X_INTR_MASK_1_EAR_PDM_WD_INT_MASK 0x80 +#define WCD939X_INTR_MASK_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD939X_INTR_MASK_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD939X_INTR_MASK_1_EAR_SCD_INT_MASK 0x04 +#define WCD939X_INTR_MASK_1_EAR_CNP_INT_MASK 0x02 +#define WCD939X_INTR_MASK_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD939X_INTR_MASK_2 Fields: */ +#define WCD939X_INTR_MASK_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD939X_INTR_MASK_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD939X_INTR_MASK_2_MBHC_MOISTRUE_INT_MASK 0x02 + +/* WCD939X_INTR_STATUS_0 Fields: */ +#define WCD939X_INTR_STATUS_0_HPHL_OCP_INT_MASK 0x80 +#define WCD939X_INTR_STATUS_0_HPHR_CNP_INT_MASK 0x40 +#define WCD939X_INTR_STATUS_0_HPHR_OCP_INT_MASK 0x20 +#define WCD939X_INTR_STATUS_0_MBHC_SW_INT_MASK 0x10 +#define WCD939X_INTR_STATUS_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD939X_INTR_STATUS_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD939X_INTR_STATUS_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD939X_INTR_STATUS_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD939X_INTR_STATUS_1 Fields: */ +#define WCD939X_INTR_STATUS_1_EAR_PDM_WD_INT_MASK 0x80 +#define WCD939X_INTR_STATUS_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD939X_INTR_STATUS_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD939X_INTR_STATUS_1_EAR_SCD_INT_MASK 0x04 +#define WCD939X_INTR_STATUS_1_EAR_CNP_INT_MASK 0x02 +#define WCD939X_INTR_STATUS_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD939X_INTR_STATUS_2 Fields: */ +#define WCD939X_INTR_STATUS_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD939X_INTR_STATUS_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD939X_INTR_STATUS_2_MBHC_MOISTRUE_INT_MASK 0x02 + +/* WCD939X_INTR_CLEAR_0 Fields: */ +#define WCD939X_INTR_CLEAR_0_HPHL_OCP_INT_MASK 0x80 +#define WCD939X_INTR_CLEAR_0_HPHR_CNP_INT_MASK 0x40 +#define WCD939X_INTR_CLEAR_0_HPHR_OCP_INT_MASK 0x20 +#define WCD939X_INTR_CLEAR_0_MBHC_SW_INT_MASK 0x10 +#define WCD939X_INTR_CLEAR_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD939X_INTR_CLEAR_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD939X_INTR_CLEAR_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD939X_INTR_CLEAR_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD939X_INTR_CLEAR_1 Fields: */ +#define WCD939X_INTR_CLEAR_1_EAR_PDM_WD_INT_MASK 0x80 +#define WCD939X_INTR_CLEAR_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD939X_INTR_CLEAR_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD939X_INTR_CLEAR_1_EAR_SCD_INT_MASK 0x04 +#define WCD939X_INTR_CLEAR_1_EAR_CNP_INT_MASK 0x02 +#define WCD939X_INTR_CLEAR_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD939X_INTR_CLEAR_2 Fields: */ +#define WCD939X_INTR_CLEAR_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD939X_INTR_CLEAR_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD939X_INTR_CLEAR_2_MBHC_MOISTRUE_INT_MASK 0x02 + +/* WCD939X_INTR_LEVEL_0 Fields: */ +#define WCD939X_INTR_LEVEL_0_HPHL_OCP_INT_MASK 0x80 +#define WCD939X_INTR_LEVEL_0_HPHR_CNP_INT_MASK 0x40 +#define WCD939X_INTR_LEVEL_0_HPHR_OCP_INT_MASK 0x20 +#define WCD939X_INTR_LEVEL_0_MBHC_SW_INT_MASK 0x10 +#define WCD939X_INTR_LEVEL_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD939X_INTR_LEVEL_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD939X_INTR_LEVEL_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD939X_INTR_LEVEL_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD939X_INTR_LEVEL_1 Fields: */ +#define WCD939X_INTR_LEVEL_1_EAR_PDM_WD_INT_MASK 0x80 +#define WCD939X_INTR_LEVEL_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD939X_INTR_LEVEL_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD939X_INTR_LEVEL_1_EAR_SCD_INT_MASK 0x04 +#define WCD939X_INTR_LEVEL_1_EAR_CNP_INT_MASK 0x02 +#define WCD939X_INTR_LEVEL_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD939X_INTR_LEVEL_2 Fields: */ +#define WCD939X_INTR_LEVEL_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD939X_INTR_LEVEL_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD939X_INTR_LEVEL_2_MBHC_MOISTRUE_INT_MASK 0x02 + +/* WCD939X_INTR_SET_0 Fields: */ +#define WCD939X_INTR_SET_0_HPHL_OCP_INT_MASK 0x80 +#define WCD939X_INTR_SET_0_HPHR_CNP_INT_MASK 0x40 +#define WCD939X_INTR_SET_0_HPHR_OCP_INT_MASK 0x20 +#define WCD939X_INTR_SET_0_MBHC_SW_INT_MASK 0x10 +#define WCD939X_INTR_SET_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD939X_INTR_SET_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD939X_INTR_SET_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD939X_INTR_SET_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD939X_INTR_SET_1 Fields: */ +#define WCD939X_INTR_SET_1_EAR_PDM_WD_INT_MASK 0x80 +#define WCD939X_INTR_SET_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD939X_INTR_SET_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD939X_INTR_SET_1_EAR_SCD_INT_MASK 0x04 +#define WCD939X_INTR_SET_1_EAR_CNP_INT_MASK 0x02 +#define WCD939X_INTR_SET_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD939X_INTR_SET_2 Fields: */ +#define WCD939X_INTR_SET_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD939X_INTR_SET_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD939X_INTR_SET_2_MBHC_MOISTRUE_INT_MASK 0x02 + +/* WCD939X_INTR_TEST_0 Fields: */ +#define WCD939X_INTR_TEST_0_HPHL_OCP_INT_MASK 0x80 +#define WCD939X_INTR_TEST_0_HPHR_CNP_INT_MASK 0x40 +#define WCD939X_INTR_TEST_0_HPHR_OCP_INT_MASK 0x20 +#define WCD939X_INTR_TEST_0_MBHC_SW_INT_MASK 0x10 +#define WCD939X_INTR_TEST_0_MBHC_ELECT_INS_REM_LEG_INT_MASK 0x08 +#define WCD939X_INTR_TEST_0_MBHC_ELECT_INS_REM_INT_MASK 0x04 +#define WCD939X_INTR_TEST_0_MBHC_BTN_RELEASE_INT_MASK 0x02 +#define WCD939X_INTR_TEST_0_MBHC_BTN_PRESS_INT_MASK 0x01 + +/* WCD939X_INTR_TEST_1 Fields: */ +#define WCD939X_INTR_TEST_1_EAR_PDM_WD_INT_MASK 0x80 +#define WCD939X_INTR_TEST_1_HPHR_PDM_WD_INT_MASK 0x40 +#define WCD939X_INTR_TEST_1_HPHL_PDM_WD_INT_MASK 0x20 +#define WCD939X_INTR_TEST_1_EAR_SCD_INT_MASK 0x04 +#define WCD939X_INTR_TEST_1_EAR_CNP_INT_MASK 0x02 +#define WCD939X_INTR_TEST_1_HPHL_CNP_INT_MASK 0x01 + +/* WCD939X_INTR_TEST_2 Fields: */ +#define WCD939X_INTR_TEST_2_HPHL_SURGE_DET_INT_MASK 0x08 +#define WCD939X_INTR_TEST_2_HPHR_SURGE_DET_INT_MASK 0x04 +#define WCD939X_INTR_TEST_2_MBHC_MOISTRUE_INT_MASK 0x02 + +/* WCD939X_TX_MODE_DBG_EN Fields: */ +#define WCD939X_TX_MODE_DBG_EN_TXD3_MODE_DBG_EN_MASK 0x08 +#define WCD939X_TX_MODE_DBG_EN_TXD2_MODE_DBG_EN_MASK 0x04 +#define WCD939X_TX_MODE_DBG_EN_TXD1_MODE_DBG_EN_MASK 0x02 +#define WCD939X_TX_MODE_DBG_EN_TXD0_MODE_DBG_EN_MASK 0x01 + +/* WCD939X_TX_MODE_DBG_0_1 Fields: */ +#define WCD939X_TX_MODE_DBG_0_1_TXD1_MODE_DBG_MASK 0xf0 +#define WCD939X_TX_MODE_DBG_0_1_TXD0_MODE_DBG_MASK 0x0f + +/* WCD939X_TX_MODE_DBG_2_3 Fields: */ +#define WCD939X_TX_MODE_DBG_2_3_TXD3_MODE_DBG_MASK 0xf0 +#define WCD939X_TX_MODE_DBG_2_3_TXD2_MODE_DBG_MASK 0x0f + +/* WCD939X_LB_IN_SEL_CTL Fields: */ +#define WCD939X_LB_IN_SEL_CTL_EAR_LB_IN_SEL_MASK 0x0c +#define WCD939X_LB_IN_SEL_CTL_HPH_LB_IN_SEL_MASK 0x03 + +/* WCD939X_LOOP_BACK_MODE Fields: */ +#define WCD939X_LOOP_BACK_MODE_TX_DATA_EDGE_MASK 0x10 +#define WCD939X_LOOP_BACK_MODE_RX_DATA_EDGE_MASK 0x08 +#define WCD939X_LOOP_BACK_MODE_LOOPBACK_MODE_MASK 0x07 + +/* WCD939X_SWR_DAC_TEST Fields: */ +#define WCD939X_SWR_DAC_TEST_SWR_DAC_TEST_MASK 0x01 + +/* WCD939X_SWR_HM_TEST_RX_0 Fields: */ +#define WCD939X_SWR_HM_TEST_RX_0_ALT_MODE_MASK 0x80 +#define WCD939X_SWR_HM_TEST_RX_0_IO_MODE_MASK 0x40 +#define WCD939X_SWR_HM_TEST_RX_0_LN2_T_DATA_OE_MASK 0x20 +#define WCD939X_SWR_HM_TEST_RX_0_LN2_T_DATA_OUT_MASK 0x10 +#define WCD939X_SWR_HM_TEST_RX_0_LN2_T_KEEPER_EN_MASK 0x08 +#define WCD939X_SWR_HM_TEST_RX_0_LN1_T_DATA_OE_MASK 0x04 +#define WCD939X_SWR_HM_TEST_RX_0_LN1_T_DATA_OUT_MASK 0x02 +#define WCD939X_SWR_HM_TEST_RX_0_LN1_T_KEEPER_EN_MASK 0x01 + +/* WCD939X_SWR_HM_TEST_TX_0 Fields: */ +#define WCD939X_SWR_HM_TEST_TX_0_ALT_MODE_MASK 0x80 +#define WCD939X_SWR_HM_TEST_TX_0_IO_MODE_MASK 0x40 +#define WCD939X_SWR_HM_TEST_TX_0_LN2_T_DATA_OE_MASK 0x20 +#define WCD939X_SWR_HM_TEST_TX_0_LN2_T_DATA_OUT_MASK 0x10 +#define WCD939X_SWR_HM_TEST_TX_0_LN2_T_KEEPER_EN_MASK 0x08 +#define WCD939X_SWR_HM_TEST_TX_0_LN1_T_DATA_OE_MASK 0x04 +#define WCD939X_SWR_HM_TEST_TX_0_LN1_T_DATA_OUT_MASK 0x02 +#define WCD939X_SWR_HM_TEST_TX_0_LN1_T_KEEPER_EN_MASK 0x01 + +/* WCD939X_SWR_HM_TEST_RX_1 Fields: */ +#define WCD939X_SWR_HM_TEST_RX_1_DTEST_SEL_MASK 0x1c +#define WCD939X_SWR_HM_TEST_RX_1_LN2_DLY_CELL_TEST_EN_MASK 0x02 +#define WCD939X_SWR_HM_TEST_RX_1_LN1_DLY_CELL_TEST_EN_MASK 0x01 + +/* WCD939X_SWR_HM_TEST_TX_1 Fields: */ +#define WCD939X_SWR_HM_TEST_TX_1_DTEST_SEL_MASK 0x78 +#define WCD939X_SWR_HM_TEST_TX_1_LN3_DLY_CELL_TEST_EN_MASK 0x04 +#define WCD939X_SWR_HM_TEST_TX_1_LN2_DLY_CELL_TEST_EN_MASK 0x02 +#define WCD939X_SWR_HM_TEST_TX_1_LN1_DLY_CELL_TEST_EN_MASK 0x01 + +/* WCD939X_SWR_HM_TEST_TX_2 Fields: */ +#define WCD939X_SWR_HM_TEST_TX_2_LN3_T_DATA_OE_MASK 0x04 +#define WCD939X_SWR_HM_TEST_TX_2_LN3_T_DATA_OUT_MASK 0x02 +#define WCD939X_SWR_HM_TEST_TX_2_LN3_T_KEEPER_EN_MASK 0x01 + +/* WCD939X_SWR_HM_TEST_0 Fields: */ +#define WCD939X_SWR_HM_TEST_0_TX_LN2_T_DATA_IN_MASK 0x80 +#define WCD939X_SWR_HM_TEST_0_TX_LN2_T_CLK_IN_MASK 0x40 +#define WCD939X_SWR_HM_TEST_0_TX_LN1_T_DATA_IN_MASK 0x20 +#define WCD939X_SWR_HM_TEST_0_TX_LN1_T_CLK_IN_MASK 0x10 +#define WCD939X_SWR_HM_TEST_0_RX_LN2_T_DATA_IN_MASK 0x08 +#define WCD939X_SWR_HM_TEST_0_RX_LN2_T_CLK_IN_MASK 0x04 +#define WCD939X_SWR_HM_TEST_0_RX_LN1_T_DATA_IN_MASK 0x02 +#define WCD939X_SWR_HM_TEST_0_RX_LN1_T_CLK_IN_MASK 0x01 + +/* WCD939X_SWR_HM_TEST_1 Fields: */ +#define WCD939X_SWR_HM_TEST_1_TX_LN3_T_DATA_IN_MASK 0x02 +#define WCD939X_SWR_HM_TEST_1_TX_LN3_T_CLK_IN_MASK 0x01 + +/* WCD939X_PAD_CTL_SWR_0 Fields: */ +#define WCD939X_PAD_CTL_SWR_0_SWR_SLEW_PRG_MASK 0xf0 +#define WCD939X_PAD_CTL_SWR_0_SWR_DRIVE_PRG_MASK 0x0f + +/* WCD939X_PAD_CTL_SWR_1 Fields: */ +#define WCD939X_PAD_CTL_SWR_1_SWR_TDZ_PRG_MASK 0x0f + +/* WCD939X_I2C_CTL Fields: */ +#define WCD939X_I2C_CTL_ACTIVE_MODE_MASK 0x01 + +/* WCD939X_CDC_TX_TANGGU_SW_MODE Fields: */ +#define WCD939X_CDC_TX_TANGGU_SW_MODE_LEGACY_SW_MODE_MASK 0x01 + +/* WCD939X_EFUSE_TEST_CTL_0 Fields: */ +#define WCD939X_EFUSE_TEST_CTL_0_EFUSE_TEST_CTL_LSB_MASK 0xff + +/* WCD939X_EFUSE_TEST_CTL_1 Fields: */ +#define WCD939X_EFUSE_TEST_CTL_1_EFUSE_TEST_CTL_MSB_MASK 0xff + +/* WCD939X_EFUSE_T_DATA_0 Fields: */ +#define WCD939X_EFUSE_T_DATA_0_EFUSE_DATA_MASK 0xff + +/* WCD939X_EFUSE_T_DATA_1 Fields: */ +#define WCD939X_EFUSE_T_DATA_1_EFUSE_DATA_MASK 0xff + +/* WCD939X_PAD_CTL_PDM_RX0 Fields: */ +#define WCD939X_PAD_CTL_PDM_RX0_PDM_SLEW_PRG_MASK 0xf0 +#define WCD939X_PAD_CTL_PDM_RX0_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD939X_PAD_CTL_PDM_RX1 Fields: */ +#define WCD939X_PAD_CTL_PDM_RX1_PDM_SLEW_PRG_MASK 0xf0 +#define WCD939X_PAD_CTL_PDM_RX1_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD939X_PAD_CTL_PDM_TX0 Fields: */ +#define WCD939X_PAD_CTL_PDM_TX0_PDM_SLEW_PRG_MASK 0xf0 +#define WCD939X_PAD_CTL_PDM_TX0_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD939X_PAD_CTL_PDM_TX1 Fields: */ +#define WCD939X_PAD_CTL_PDM_TX1_PDM_SLEW_PRG_MASK 0xf0 +#define WCD939X_PAD_CTL_PDM_TX1_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD939X_PAD_CTL_PDM_TX2 Fields: */ +#define WCD939X_PAD_CTL_PDM_TX2_PDM_SLEW_PRG_MASK 0xf0 +#define WCD939X_PAD_CTL_PDM_TX2_PDM_DRIVE_PRG_MASK 0x0f + +/* WCD939X_PAD_INP_DIS_0 Fields: */ +#define WCD939X_PAD_INP_DIS_0_DMIC3_CLK_MASK 0x20 +#define WCD939X_PAD_INP_DIS_0_DMIC3_DATA_MASK 0x10 +#define WCD939X_PAD_INP_DIS_0_DMIC2_CLK_MASK 0x08 +#define WCD939X_PAD_INP_DIS_0_DMIC2_DATA_MASK 0x04 +#define WCD939X_PAD_INP_DIS_0_DMIC1_CLK_MASK 0x02 +#define WCD939X_PAD_INP_DIS_0_DMIC1_DATA_MASK 0x01 + +/* WCD939X_PAD_INP_DIS_1 Fields: */ +#define WCD939X_PAD_INP_DIS_1_DMIC4_CLK_MASK 0x10 +#define WCD939X_PAD_INP_DIS_1_DMIC4_DATA_MASK 0x08 + +/* WCD939X_DRIVE_STRENGTH_0 Fields: */ +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC2_CLK_MASK 0xc0 +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC2_DATA_MASK 0x30 +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC1_CLK_MASK 0x0c +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC1_DATA_MASK 0x03 + +/* WCD939X_DRIVE_STRENGTH_1 Fields: */ +#define WCD939X_DRIVE_STRENGTH_1_DS_DMIC3_CLK_MASK 0x0c +#define WCD939X_DRIVE_STRENGTH_1_DS_DMIC3_DATA_MASK 0x03 + +/* WCD939X_DRIVE_STRENGTH_2 Fields: */ +#define WCD939X_DRIVE_STRENGTH_2_DS_DMIC4_CLK_MASK 0xc0 +#define WCD939X_DRIVE_STRENGTH_2_DS_DMIC4_DATA_MASK 0x30 + +/* WCD939X_RX_DATA_EDGE_CTL Fields: */ +#define WCD939X_RX_DATA_EDGE_CTL_HPH_CLH_EDGE_MASK 0x20 +#define WCD939X_RX_DATA_EDGE_CTL_EAR_DOUT_EDGE_MASK 0x10 +#define WCD939X_RX_DATA_EDGE_CTL_HPHR_DOUT_EDGE_MASK 0x08 +#define WCD939X_RX_DATA_EDGE_CTL_HPHL_DOUT_EDGE_MASK 0x04 +#define WCD939X_RX_DATA_EDGE_CTL_HPHR_GAIN_EDGE_MASK 0x02 +#define WCD939X_RX_DATA_EDGE_CTL_HPHL_GAIN_EDGE_MASK 0x01 + +/* WCD939X_TX_DATA_EDGE_CTL Fields: */ +#define WCD939X_TX_DATA_EDGE_CTL_TX_WE_DLY_MASK 0xc0 +#define WCD939X_TX_DATA_EDGE_CTL_TX3_DIN_EDGE_MASK 0x08 +#define WCD939X_TX_DATA_EDGE_CTL_TX2_DIN_EDGE_MASK 0x04 +#define WCD939X_TX_DATA_EDGE_CTL_TX1_DIN_EDGE_MASK 0x02 +#define WCD939X_TX_DATA_EDGE_CTL_TX0_DIN_EDGE_MASK 0x01 + +/* WCD939X_GPIO_MODE Fields: */ +#define WCD939X_GPIO_MODE_GPIO_3_EN_MASK 0x04 +#define WCD939X_GPIO_MODE_GPIO_2_EN_MASK 0x02 +#define WCD939X_GPIO_MODE_TEST_MODE_MASK 0x01 + +/* WCD939X_PIN_CTL_OE Fields: */ +#define WCD939X_PIN_CTL_OE_TEST_PIN_CTL_OE_MASK 0x10 +#define WCD939X_PIN_CTL_OE_GPIO_3_PIN_CTL_OE_MASK 0x08 +#define WCD939X_PIN_CTL_OE_GPIO_2_PIN_CTL_OE_MASK 0x04 + +/* WCD939X_PIN_CTL_DATA_0 Fields: */ +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC3_CLK_MASK 0x20 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC3_DATA_MASK 0x10 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC2_CLK_MASK 0x08 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC2_DATA_MASK 0x04 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC1_CLK_MASK 0x02 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC1_DATA_MASK 0x01 + +/* WCD939X_PIN_CTL_DATA_1 Fields: */ +#define WCD939X_PIN_CTL_DATA_1_PAD_DMIC4_CLK_MASK 0x08 +#define WCD939X_PIN_CTL_DATA_1_PAD_DMIC4_DATA_MASK 0x04 + +/* WCD939X_PIN_STATUS_0 Fields: */ +#define WCD939X_PIN_STATUS_0_PAD_DMIC3_CLK_MASK 0x20 +#define WCD939X_PIN_STATUS_0_PAD_DMIC3_DATA_MASK 0x10 +#define WCD939X_PIN_STATUS_0_PAD_DMIC2_CLK_MASK 0x08 +#define WCD939X_PIN_STATUS_0_PAD_DMIC2_DATA_MASK 0x04 +#define WCD939X_PIN_STATUS_0_PAD_DMIC1_CLK_MASK 0x02 +#define WCD939X_PIN_STATUS_0_PAD_DMIC1_DATA_MASK 0x01 + +/* WCD939X_PIN_STATUS_1 Fields: */ +#define WCD939X_PIN_STATUS_1_PAD_DMIC4_CLK_MASK 0x08 +#define WCD939X_PIN_STATUS_1_PAD_DMIC4_DATA_MASK 0x04 + +/* WCD939X_DIG_DEBUG_CTL Fields: */ +#define WCD939X_DIG_DEBUG_CTL_DIG_DEBUG_CTL_MASK 0x7f + +/* WCD939X_DIG_DEBUG_EN Fields: */ +#define WCD939X_DIG_DEBUG_EN_TX_DBG_MODE_MASK 0x04 +#define WCD939X_DIG_DEBUG_EN_RX_DBG_MODE_1_MASK 0x02 +#define WCD939X_DIG_DEBUG_EN_RX_DBG_MODE_0_MASK 0x01 + +/* WCD939X_ANA_CSR_DBG_ADD Fields: */ +#define WCD939X_ANA_CSR_DBG_ADD_ADD_MASK 0xff + +/* WCD939X_ANA_CSR_DBG_CTL Fields: */ +#define WCD939X_ANA_CSR_DBG_CTL_WR_VALUE_MASK 0xc0 +#define WCD939X_ANA_CSR_DBG_CTL_RD_VALUE_MASK 0x38 +#define WCD939X_ANA_CSR_DBG_CTL_DBG_PAGE_SEL_MASK 0x06 +#define WCD939X_ANA_CSR_DBG_CTL_DBG_EN_MASK 0x01 + +/* WCD939X_SSP_DBG Fields: */ +#define WCD939X_SSP_DBG_RX_SSP_DBG_MASK 0x02 +#define WCD939X_SSP_DBG_TX_SSP_DBG_MASK 0x01 + +/* WCD939X_MODE_STATUS_0 Fields: */ +#define WCD939X_MODE_STATUS_0_ATE_7_MASK 0x80 +#define WCD939X_MODE_STATUS_0_ATE_6_MASK 0x40 +#define WCD939X_MODE_STATUS_0_ATE_5_MASK 0x20 +#define WCD939X_MODE_STATUS_0_ATE_4_MASK 0x10 +#define WCD939X_MODE_STATUS_0_ATE_3_MASK 0x08 +#define WCD939X_MODE_STATUS_0_ATE_2_MASK 0x04 +#define WCD939X_MODE_STATUS_0_ATE_1_MASK 0x02 +#define WCD939X_MODE_STATUS_0_SWR_TEST_MASK 0x01 + +/* WCD939X_MODE_STATUS_1 Fields: */ +#define WCD939X_MODE_STATUS_1_SWR_PAD_TEST_MASK 0x02 +#define WCD939X_MODE_STATUS_1_EFUSE_MODE_MASK 0x01 + +/* WCD939X_SPARE_0 Fields: */ +#define WCD939X_SPARE_0_SPARE_REG_0_MASK 0xff + +/* WCD939X_SPARE_1 Fields: */ +#define WCD939X_SPARE_1_SPARE_REG_1_MASK 0xff + +/* WCD939X_SPARE_2 Fields: */ +#define WCD939X_SPARE_2_SPARE_REG_2_MASK 0xff + +/* WCD939X_EFUSE_REG_0 Fields: */ +#define WCD939X_EFUSE_REG_0_SPARE_BITS_MASK 0xe0 +#define WCD939X_EFUSE_REG_0_WCD939X_ID_MASK 0x1e +#define WCD939X_EFUSE_REG_0_EFUSE_BLOWN_MASK 0x01 + +/* WCD939X_EFUSE_REG_1 Fields: */ +#define WCD939X_EFUSE_REG_1_LOT_ID_0_MASK 0xff + +/* WCD939X_EFUSE_REG_2 Fields: */ +#define WCD939X_EFUSE_REG_2_LOT_ID_1_MASK 0xff + +/* WCD939X_EFUSE_REG_3 Fields: */ +#define WCD939X_EFUSE_REG_3_LOT_ID_2_MASK 0xff + +/* WCD939X_EFUSE_REG_4 Fields: */ +#define WCD939X_EFUSE_REG_4_LOT_ID_3_MASK 0xff + +/* WCD939X_EFUSE_REG_5 Fields: */ +#define WCD939X_EFUSE_REG_5_LOT_ID_4_MASK 0xff + +/* WCD939X_EFUSE_REG_6 Fields: */ +#define WCD939X_EFUSE_REG_6_LOT_ID_5_MASK 0xff + +/* WCD939X_EFUSE_REG_7 Fields: */ +#define WCD939X_EFUSE_REG_7_LOT_ID_6_MASK 0xff + +/* WCD939X_EFUSE_REG_8 Fields: */ +#define WCD939X_EFUSE_REG_8_LOT_ID_7_MASK 0xff + +/* WCD939X_EFUSE_REG_9 Fields: */ +#define WCD939X_EFUSE_REG_9_LOT_ID_8_MASK 0xff + +/* WCD939X_EFUSE_REG_10 Fields: */ +#define WCD939X_EFUSE_REG_10_LOT_ID_9_MASK 0xff + +/* WCD939X_EFUSE_REG_11 Fields: */ +#define WCD939X_EFUSE_REG_11_LOT_ID_10_MASK 0xff + +/* WCD939X_EFUSE_REG_12 Fields: */ +#define WCD939X_EFUSE_REG_12_LOT_ID_11_MASK 0xff + +/* WCD939X_EFUSE_REG_13 Fields: */ +#define WCD939X_EFUSE_REG_13_WAFER_ID_MASK 0xff + +/* WCD939X_EFUSE_REG_14 Fields: */ +#define WCD939X_EFUSE_REG_14_X_DIE_LOCATION_MASK 0xff + +/* WCD939X_EFUSE_REG_15 Fields: */ +#define WCD939X_EFUSE_REG_15_Y_DIE_LOCATION_MASK 0xff + +/* WCD939X_EFUSE_REG_16 Fields: */ +#define WCD939X_EFUSE_REG_16_FAB_ID_MASK 0xff + +/* WCD939X_EFUSE_REG_17 Fields: */ +#define WCD939X_EFUSE_REG_17_TEST_PROGRAM_REV_MASK 0xff + +/* WCD939X_EFUSE_REG_18 Fields: */ +#define WCD939X_EFUSE_REG_18_DIE_REVISION_MASK 0xff + +/* WCD939X_EFUSE_REG_19 Fields: */ +#define WCD939X_EFUSE_REG_19_MFG_ID_SPARE_MASK 0xff + +/* WCD939X_EFUSE_REG_20 Fields: */ +#define WCD939X_EFUSE_REG_20_I2C_SLV_ID_BLOWN_MASK 0x80 +#define WCD939X_EFUSE_REG_20_I2C_SLAVE_ID_MASK 0x7f + +/* WCD939X_EFUSE_REG_21 Fields: */ +#define WCD939X_EFUSE_REG_21_MBHC_IMP_DET_0_MASK 0xff + +/* WCD939X_EFUSE_REG_22 Fields: */ +#define WCD939X_EFUSE_REG_22_MBHC_IMP_DET_1_MASK 0xff + +/* WCD939X_EFUSE_REG_23 Fields: */ +#define WCD939X_EFUSE_REG_23_SWR_PAD_DRIVE_PRG_1P2V_MASK 0xf0 +#define WCD939X_EFUSE_REG_23_SWR_SLEW_PRG_1P2V_MASK 0x0f + +/* WCD939X_EFUSE_REG_24 Fields: */ +#define WCD939X_EFUSE_REG_24_SPARE_BITS_MASK 0xe0 +#define WCD939X_EFUSE_REG_24_SWR_PAD_BLOWN_MASK 0x10 +#define WCD939X_EFUSE_REG_24_SWR_TDZ_DELAY_PRG_1P2V_MASK 0x0f + +/* WCD939X_EFUSE_REG_25 Fields: */ +#define WCD939X_EFUSE_REG_25_MBHC_IMP_DET_2_MASK 0xff + +/* WCD939X_EFUSE_REG_26 Fields: */ +#define WCD939X_EFUSE_REG_26_MBHC_IMP_DET_3_MASK 0xff + +/* WCD939X_EFUSE_REG_27 Fields: */ +#define WCD939X_EFUSE_REG_27_HPH_DSD_DIS_MASK 0x80 +#define WCD939X_EFUSE_REG_27_BG_TUNE_BLOWN_MASK 0x40 +#define WCD939X_EFUSE_REG_27_BG_TUNE_MASK 0x30 +#define WCD939X_EFUSE_REG_27_EFUSE_HPH_MASK 0x0f + +/* WCD939X_EFUSE_REG_28 Fields: */ +#define WCD939X_EFUSE_REG_28_HPH_CLH_DIS_MASK 0x80 +#define WCD939X_EFUSE_REG_28_HPH_LOHIFI_DIS_MASK 0x40 +#define WCD939X_EFUSE_REG_28_HPH_HIFI_DIS_MASK 0x20 +#define WCD939X_EFUSE_REG_28_EAR_CLH_DIS_MASK 0x10 +#define WCD939X_EFUSE_REG_28_DMIC_DIS_MASK 0x08 +#define WCD939X_EFUSE_REG_28_TX_LP_DIS_MASK 0x04 +#define WCD939X_EFUSE_REG_28_TX_HP_DIS_MASK 0x02 +#define WCD939X_EFUSE_REG_28_SPARE_BITS_MASK 0x01 + +/* WCD939X_EFUSE_REG_29 Fields: */ +#define WCD939X_EFUSE_REG_29_TX_ULP1_DIS_MASK 0x80 +#define WCD939X_EFUSE_REG_29_TX_ULP2_DIS_MASK 0x40 +#define WCD939X_EFUSE_REG_29_SPARE_BITS_MASK 0x30 +#define WCD939X_EFUSE_REG_29_SWR_PAD_DRIVE_PRG_1P8V_MASK 0x0f + +/* WCD939X_EFUSE_REG_30 Fields: */ +#define WCD939X_EFUSE_REG_30_SWR_SLEW_PRG_1P8V_MASK 0xf0 +#define WCD939X_EFUSE_REG_30_SWR_TDZ_DELAY_PRG_1P8V_MASK 0x0f + +/* WCD939X_EFUSE_REG_31 Fields: */ +#define WCD939X_EFUSE_REG_31_SPARE_EFUSE_ANA_MASK 0xff + +/* WCD939X_TX_REQ_FB_CTL_0 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_0_ULP2_FB_T2_MASK 0xf0 +#define WCD939X_TX_REQ_FB_CTL_0_ULP2_FB_T1_MASK 0x0f + +/* WCD939X_TX_REQ_FB_CTL_1 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_1_ULP1_FB_T2_MASK 0xf0 +#define WCD939X_TX_REQ_FB_CTL_1_ULP1_FB_T1_MASK 0x0f + +/* WCD939X_TX_REQ_FB_CTL_2 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_2_L0_FB_T2_MASK 0xf0 +#define WCD939X_TX_REQ_FB_CTL_2_L0_FB_T1_MASK 0x0f + +/* WCD939X_TX_REQ_FB_CTL_3 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_3_L1_FB_T2_MASK 0xf0 +#define WCD939X_TX_REQ_FB_CTL_3_L1_FB_T1_MASK 0x0f + +/* WCD939X_TX_REQ_FB_CTL_4 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_4_L2_FB_T2_MASK 0xf0 +#define WCD939X_TX_REQ_FB_CTL_4_L2_FB_T1_MASK 0x0f + +/* WCD939X_DEM_BYPASS_DATA0 Fields: */ +#define WCD939X_DEM_BYPASS_DATA0_DEM_BYPASS_DATA0_MASK 0xff + +/* WCD939X_DEM_BYPASS_DATA1 Fields: */ +#define WCD939X_DEM_BYPASS_DATA1_DEM_BYPASS_DATA1_MASK 0xff + +/* WCD939X_DEM_BYPASS_DATA2 Fields: */ +#define WCD939X_DEM_BYPASS_DATA2_DEM_BYPASS_DATA2_MASK 0xff + +/* WCD939X_DEM_BYPASS_DATA3 Fields: */ +#define WCD939X_DEM_BYPASS_DATA3_DEM_BYPASS_DATA3_MASK 0x0f + +/* WCD939X_DEM_SECOND_ORDER Fields: */ +#define WCD939X_DEM_SECOND_ORDER_DEM_1_2ND_ORDER_EN_MASK 0x02 +#define WCD939X_DEM_SECOND_ORDER_DEM_0_2ND_ORDER_EN_MASK 0x01 + +/* WCD939X_DSM_CTRL Fields: */ +#define WCD939X_DSM_CTRL_DSM_1_STATIC_EN_MASK 0x02 +#define WCD939X_DSM_CTRL_DSM_0_STATIC_EN_MASK 0x01 + +/* WCD939X_DSM_0_STATIC_DATA_0 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_0_DSM_0_STATIC_DATA0_MASK 0xff + +/* WCD939X_DSM_0_STATIC_DATA_1 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_1_DSM_0_STATIC_DATA1_MASK 0xff + +/* WCD939X_DSM_0_STATIC_DATA_2 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_2_DSM_0_STATIC_DATA2_MASK 0xff + +/* WCD939X_DSM_0_STATIC_DATA_3 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_3_DSM_0_STATIC_DATA3_MASK 0x07 + +/* WCD939X_DSM_1_STATIC_DATA_0 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_0_DSM_1_STATIC_DATA0_MASK 0xff + +/* WCD939X_DSM_1_STATIC_DATA_1 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_1_DSM_1_STATIC_DATA1_MASK 0xff + +/* WCD939X_DSM_1_STATIC_DATA_2 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_2_DSM_1_STATIC_DATA2_MASK 0xff + +/* WCD939X_DSM_1_STATIC_DATA_3 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_3_DSM_1_STATIC_DATA3_MASK 0x07 + + +/* WCD939X_RX_PAGE Fields: */ +#define WCD939X_RX_PAGE_PAG_REG_MASK 0xff + +/* WCD939X_TOP_CFG0 Fields: */ +#define WCD939X_TOP_CFG0_HPH_DAC_RATE_SEL_MASK 0x02 +#define WCD939X_TOP_CFG0_PGA_UPDATE_MASK 0x01 + +/* WCD939X_HPHL_COMP_WR_LSB Fields: */ +#define WCD939X_HPHL_COMP_WR_LSB_COEFF_MASK 0xff + +/* WCD939X_HPHL_COMP_WR_MSB Fields: */ +#define WCD939X_HPHL_COMP_WR_MSB_COEFF_MASK 0x1f + +/* WCD939X_HPHL_COMP_LUT Fields: */ +#define WCD939X_HPHL_COMP_LUT_BYPASS_MASK 0x80 +#define WCD939X_HPHL_COMP_LUT_MANUAL_RD_MASK 0x40 +#define WCD939X_HPHL_COMP_LUT_MANUAL_WR_MASK 0x20 +#define WCD939X_HPHL_COMP_LUT_ADDR_MASK 0x1f + +/* WCD939X_HPHL_COMP_RD_LSB Fields: */ +#define WCD939X_HPHL_COMP_RD_LSB_COEFF_MASK 0xff + +/* WCD939X_HPHL_COMP_RD_MSB Fields: */ +#define WCD939X_HPHL_COMP_RD_MSB_COEFF_MASK 0x1f + +/* WCD939X_HPHR_COMP_WR_LSB Fields: */ +#define WCD939X_HPHR_COMP_WR_LSB_COEFF_MASK 0xff + +/* WCD939X_HPHR_COMP_WR_MSB Fields: */ +#define WCD939X_HPHR_COMP_WR_MSB_COEFF_MASK 0x1f + +/* WCD939X_HPHR_COMP_LUT Fields: */ +#define WCD939X_HPHR_COMP_LUT_BYPASS_MASK 0x80 +#define WCD939X_HPHR_COMP_LUT_MANUAL_RD_MASK 0x40 +#define WCD939X_HPHR_COMP_LUT_MANUAL_WR_MASK 0x20 +#define WCD939X_HPHR_COMP_LUT_ADDR_MASK 0x1f + +/* WCD939X_HPHR_COMP_RD_LSB Fields: */ +#define WCD939X_HPHR_COMP_RD_LSB_COEFF_MASK 0xff + +/* WCD939X_HPHR_COMP_RD_MSB Fields: */ +#define WCD939X_HPHR_COMP_RD_MSB_COEFF_MASK 0x1f + +/* WCD939X_DSD0_DEBUG_CFG1 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG1_DSD_UNPACKING_ORDER_MASK 0x08 +#define WCD939X_DSD0_DEBUG_CFG1_DSD_DC_DET_EN_MASK 0x04 +#define WCD939X_DSD0_DEBUG_CFG1_DSD_MUTE_DET_EN_MASK 0x01 + +/* WCD939X_DSD0_DEBUG_CFG2 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG2_MUTE_INI_VAL_MASK 0x10 +#define WCD939X_DSD0_DEBUG_CFG2_DC_INTR_THRESHOLD_MASK 0x0c +#define WCD939X_DSD0_DEBUG_CFG2_DC_DET_THRESHOLD_MASK 0x03 + +/* WCD939X_DSD0_DEBUG_CFG3 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG3_DSD_POST_GAIN_MASK 0x38 +#define WCD939X_DSD0_DEBUG_CFG3_DSD_GAIN_ADJ_MASK 0x07 + +/* WCD939X_DSD0_DEBUG_CFG4 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG4_DSD_INPUT_ZOH_MASK 0x03 + +/* WCD939X_DSD0_DEBUG_CFG5 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG5_DSD_DC_DET_MASK 0x80 +#define WCD939X_DSD0_DEBUG_CFG5_DSD_PGA_GAIN_UPD_STATUS_MASK 0x40 +#define WCD939X_DSD0_DEBUG_CFG5_DSD_DC_SAMPLE_NUM_MSB_MASK 0x03 + +/* WCD939X_DSD0_DEBUG_CFG6 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG6_DSD_DC_SAMPLE_NUM_LSB_MASK 0xff + +/* WCD939X_DSD1_DEBUG_CFG1 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG1_DSD_UNPACKING_ORDER_MASK 0x04 +#define WCD939X_DSD1_DEBUG_CFG1_DSD_DC_DET_EN_MASK 0x02 +#define WCD939X_DSD1_DEBUG_CFG1_DSD_MUTE_DET_EN_MASK 0x01 + +/* WCD939X_DSD1_DEBUG_CFG2 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG2_MUTE_INI_VAL_MASK 0x10 +#define WCD939X_DSD1_DEBUG_CFG2_DC_INTR_THRESHOLD_MASK 0x0c +#define WCD939X_DSD1_DEBUG_CFG2_DC_DET_THRESHOLD_MASK 0x03 + +/* WCD939X_DSD1_DEBUG_CFG3 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG3_DSD_POST_GAIN_MASK 0x38 +#define WCD939X_DSD1_DEBUG_CFG3_DSD_GAIN_ADJ_MASK 0x07 + +/* WCD939X_DSD1_DEBUG_CFG4 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG4_DSD_INPUT_ZOH_MASK 0x03 + +/* WCD939X_DSD1_DEBUG_CFG5 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG5_DSD_DC_DET_MASK 0x80 +#define WCD939X_DSD1_DEBUG_CFG5_DSD_PGA_GAIN_UPD_STATUS_MASK 0x40 +#define WCD939X_DSD1_DEBUG_CFG5_DSD_DC_SAMPLE_NUM_MSB_MASK 0x03 + +/* WCD939X_DSD1_DEBUG_CFG6 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG6_DSD_DC_SAMPLE_NUM_LSB_MASK 0xff + +/* WCD939X_HPHL_RX_PATH_CFG0 Fields: */ +#define WCD939X_HPHL_RX_PATH_CFG0_INT_EN_MASK 0x02 +#define WCD939X_HPHL_RX_PATH_CFG0_DLY_ZN_EN_MASK 0x01 + +/* WCD939X_HPHL_RX_PATH_CFG1 Fields: */ +#define WCD939X_HPHL_RX_PATH_CFG1_DSM_SOFT_RST_MASK 0x20 +#define WCD939X_HPHL_RX_PATH_CFG1_INT_SOFT_RST_MASK 0x10 +#define WCD939X_HPHL_RX_PATH_CFG1_FMT_CONV_MASK 0x08 +#define WCD939X_HPHL_RX_PATH_CFG1_IDLE_OVRD_EN_MASK 0x04 +#define WCD939X_HPHL_RX_PATH_CFG1_RX_DC_DROOP_COEFF_SEL_MASK 0x03 + +/* WCD939X_HPHR_RX_PATH_CFG0 Fields: */ +#define WCD939X_HPHR_RX_PATH_CFG0_INT_EN_MASK 0x04 +#define WCD939X_HPHR_RX_PATH_CFG0_DLY_ZN_EN_MASK 0x02 + +/* WCD939X_HPHR_RX_PATH_CFG1 Fields: */ +#define WCD939X_HPHR_RX_PATH_CFG1_DSM_SOFT_RST_MASK 0x20 +#define WCD939X_HPHR_RX_PATH_CFG1_INT_SOFT_RST_MASK 0x10 +#define WCD939X_HPHR_RX_PATH_CFG1_FMT_CONV_MASK 0x08 +#define WCD939X_HPHR_RX_PATH_CFG1_IDLE_OVRD_EN_MASK 0x04 +#define WCD939X_HPHR_RX_PATH_CFG1_RX_DC_DROOP_COEFF_SEL_MASK 0x03 + +/* WCD939X_RX_PATH_CFG2 Fields: */ +#define WCD939X_RX_PATH_CFG2_COMP_XTALK_EN_MASK 0x08 +#define WCD939X_RX_PATH_CFG2_XTALK_NLIN_EN_MASK 0x04 +#define WCD939X_RX_PATH_CFG2_XTALK_LIN_EN_MASK 0x02 +#define WCD939X_RX_PATH_CFG2_XTALK_EN_MASK 0x01 + +/* WCD939X_HPHL_RX_PATH_SEC0 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC0_LIN_XTALK_POLARITY_MASK 0x20 +#define WCD939X_HPHL_RX_PATH_SEC0_LIN_XTALK_SCALE_MASK 0x1f + +/* WCD939X_HPHL_RX_PATH_SEC1 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC1_LIN_XTALK_ALPHA_MASK 0xff + +/* WCD939X_HPHL_RX_PATH_SEC2 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC2_NLIN_XTALK_POLARITY_MASK 0x40 +#define WCD939X_HPHL_RX_PATH_SEC2_NLIN_XTALK_BYPASS_MASK 0x20 +#define WCD939X_HPHL_RX_PATH_SEC2_NLIN_XTALK_SCALE_MASK 0x1f + +/* WCD939X_HPHL_RX_PATH_SEC3 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC3_NLIN_XTALK_ALPHA_MASK 0xff + +/* WCD939X_HPHR_RX_PATH_SEC0 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC0_LIN_XTALK_POLARITY_MASK 0x20 +#define WCD939X_HPHR_RX_PATH_SEC0_LIN_XTALK_SCALE_MASK 0x1f + +/* WCD939X_HPHR_RX_PATH_SEC1 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC1_LIN_XTALK_ALPHA_MASK 0xff + +/* WCD939X_HPHR_RX_PATH_SEC2 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC2_NLIN_XTALK_POLARITY_MASK 0x40 +#define WCD939X_HPHR_RX_PATH_SEC2_NLIN_XTALK_BYPASS_MASK 0x20 +#define WCD939X_HPHR_RX_PATH_SEC2_NLIN_XTALK_SCALE_MASK 0x1f + +/* WCD939X_HPHR_RX_PATH_SEC3 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC3_NLIN_XTALK_ALPHA_MASK 0xff + +/* WCD939X_RX_PATH_SEC4 Fields: */ +#define WCD939X_RX_PATH_SEC4_NLIN_CMB_POLARITY_MASK 0x20 +#define WCD939X_RX_PATH_SEC4_NLIN_CMB_SCALE_MASK 0x1f + +/* WCD939X_RX_PATH_SEC5 Fields: */ +#define WCD939X_RX_PATH_SEC5_NLIN_CMB_ALPHA_MASK 0xff + + +/* WCD939X_CTL0 Fields: */ +#define WCD939X_CTL0_SHUTDWN_TOUT_MASK 0x70 +#define WCD939X_CTL0_DROPOUT_EN_MASK 0x08 +#define WCD939X_CTL0_COMP_HALT_MASK 0x04 +#define WCD939X_CTL0_SOFT_RST_MASK 0x02 +#define WCD939X_CTL0_CLK_EN_MASK 0x01 + +/* WCD939X_CTL1 Fields: */ +#define WCD939X_CTL1_LEVEL_METER_DIV_FACTOR_MASK 0xf0 +#define WCD939X_CTL1_PEAK_METER_TOUT_MASK 0x0f + +/* WCD939X_CTL2 Fields: */ +#define WCD939X_CTL2_LEVEL_METER_RESAMPLE_RATE_MASK 0xff + +/* WCD939X_CTL3 Fields: */ +#define WCD939X_CTL3_STATIC_GAIN_OFFSET_MASK 0x80 +#define WCD939X_CTL3_ZONE_SELECT_SHIFT_MASK 0x70 +#define WCD939X_CTL3_ZONE_SELECT_ENTRY_MASK 0x0f + +/* WCD939X_CTL4 Fields: */ +#define WCD939X_CTL4_DET_WINDOW_MASK 0xff + +/* WCD939X_CTL5 Fields: */ +#define WCD939X_CTL5_GAIN_MAX_THOLD_MASK 0x18 +#define WCD939X_CTL5_DET_WINDOW_MASK 0x07 + +/* WCD939X_CTL6 Fields: */ +#define WCD939X_CTL6_STATUS_MASK 0x01 + +/* WCD939X_CTL7 Fields: */ +#define WCD939X_CTL7_DIS_SCD_MASK 0x40 +#define WCD939X_CTL7_AGAIN_DELAY_MASK 0x1e + +/* WCD939X_CTL8 Fields: */ +#define WCD939X_CTL8_PEAK_TO_FLAG_DIS_MASK 0x02 +#define WCD939X_CTL8_GAIN_STEP_SELECT_MASK 0x01 + +/* WCD939X_CTL9 Fields: */ +#define WCD939X_CTL9_ZONE0_RMS_MASK 0x7f + +/* WCD939X_CTL10 Fields: */ +#define WCD939X_CTL10_ZONE1_RMS_MASK 0x7f + +/* WCD939X_CTL11 Fields: */ +#define WCD939X_CTL11_ZONE2_RMS_MASK 0x7f + +/* WCD939X_CTL12 Fields: */ +#define WCD939X_CTL12_ZONE3_RMS_MASK 0x7f + +/* WCD939X_CTL13 Fields: */ +#define WCD939X_CTL13_ZONE4_RMS_MASK 0x7f + +/* WCD939X_CTL14 Fields: */ +#define WCD939X_CTL14_ZONE5_RMS_MASK 0x7f + +/* WCD939X_CTL15 Fields: */ +#define WCD939X_CTL15_ZONE6_RMS_MASK 0x7f + +/* WCD939X_CTL16 Fields: */ +#define WCD939X_CTL16_MAX_ATTN_MASK 0xff + +/* WCD939X_CTL17 Fields: */ +#define WCD939X_CTL17_PATH_GAIN_MASK 0x3f + +/* WCD939X_CTL18 Fields: */ +#define WCD939X_CTL18_ANA_ADDR_MAP_MASK 0x3f + +/* WCD939X_CTL19 Fields: */ +#define WCD939X_CTL19_RMS_TOUT_MASK 0x3e +#define WCD939X_CTL19_RMS_TOUT_OVERRIDE_MASK 0x01 + + +/* WCD939X_R_CTL0 Fields: */ +#define WCD939X_R_CTL0_SHUTDWN_TOUT_MASK 0x70 +#define WCD939X_R_CTL0_DROPOUT_EN_MASK 0x08 +#define WCD939X_R_CTL0_COMP_HALT_MASK 0x04 +#define WCD939X_R_CTL0_SOFT_RST_MASK 0x02 +#define WCD939X_R_CTL0_CLK_EN_MASK 0x01 + +/* WCD939X_R_CTL1 Fields: */ +#define WCD939X_R_CTL1_LEVEL_METER_DIV_FACTOR_MASK 0xf0 +#define WCD939X_R_CTL1_PEAK_METER_TOUT_MASK 0x0f + +/* WCD939X_R_CTL2 Fields: */ +#define WCD939X_R_CTL2_LEVEL_METER_RESAMPLE_RATE_MASK 0xff + +/* WCD939X_R_CTL3 Fields: */ +#define WCD939X_R_CTL3_STATIC_GAIN_OFFSET_MASK 0x80 +#define WCD939X_R_CTL3_ZONE_SELECT_SHIFT_MASK 0x70 +#define WCD939X_R_CTL3_ZONE_SELECT_ENTRY_MASK 0x0f + +/* WCD939X_R_CTL4 Fields: */ +#define WCD939X_R_CTL4_DET_WINDOW_MASK 0xff + +/* WCD939X_R_CTL5 Fields: */ +#define WCD939X_R_CTL5_GAIN_MAX_THOLD_MASK 0x18 +#define WCD939X_R_CTL5_DET_WINDOW_MASK 0x07 + +/* WCD939X_R_CTL6 Fields: */ +#define WCD939X_R_CTL6_STATUS_MASK 0x01 + +/* WCD939X_R_CTL7 Fields: */ +#define WCD939X_R_CTL7_DIS_SCD_MASK 0x40 +#define WCD939X_R_CTL7_AGAIN_DELAY_MASK 0x1e + +/* WCD939X_R_CTL8 Fields: */ +#define WCD939X_R_CTL8_PEAK_TO_FLAG_DIS_MASK 0x02 +#define WCD939X_R_CTL8_GAIN_STEP_SELECT_MASK 0x01 + +/* WCD939X_R_CTL9 Fields: */ +#define WCD939X_R_CTL9_ZONE0_RMS_MASK 0x7f + +/* WCD939X_R_CTL10 Fields: */ +#define WCD939X_R_CTL10_ZONE1_RMS_MASK 0x7f + +/* WCD939X_R_CTL11 Fields: */ +#define WCD939X_R_CTL11_ZONE2_RMS_MASK 0x7f + +/* WCD939X_R_CTL12 Fields: */ +#define WCD939X_R_CTL12_ZONE3_RMS_MASK 0x7f + +/* WCD939X_R_CTL13 Fields: */ +#define WCD939X_R_CTL13_ZONE4_RMS_MASK 0x7f + +/* WCD939X_R_CTL14 Fields: */ +#define WCD939X_R_CTL14_ZONE5_RMS_MASK 0x7f + +/* WCD939X_R_CTL15 Fields: */ +#define WCD939X_R_CTL15_ZONE6_RMS_MASK 0x7f + +/* WCD939X_R_CTL16 Fields: */ +#define WCD939X_R_CTL16_MAX_ATTN_MASK 0xff + +/* WCD939X_R_CTL17 Fields: */ +#define WCD939X_R_CTL17_PATH_GAIN_MASK 0x3f + +/* WCD939X_R_CTL18 Fields: */ +#define WCD939X_R_CTL18_ANA_ADDR_MAP_MASK 0x3f + +/* WCD939X_R_CTL19 Fields: */ +#define WCD939X_R_CTL19_RMS_TOUT_MASK 0x3e +#define WCD939X_R_CTL19_RMS_TOUT_OVERRIDE_MASK 0x01 + + +/* WCD939X_PATH_CTL Fields: */ +#define WCD939X_PATH_CTL_RESET_RIGHT_MASK 0x08 +#define WCD939X_PATH_CTL_RESET_LEFT_MASK 0x04 +#define WCD939X_PATH_CTL_CLK_EN_RIGHT_MASK 0x02 +#define WCD939X_PATH_CTL_CLK_EN_LEFT_MASK 0x01 + +/* WCD939X_CFG0 Fields: */ +#define WCD939X_CFG0_AUTO_DISABLE_ANC_MASK 0x04 +#define WCD939X_CFG0_AUTO_DISABLE_DSD_MASK 0x02 +#define WCD939X_CFG0_IDLE_STEREO_MASK 0x01 + +/* WCD939X_CFG1 Fields: */ +#define WCD939X_CFG1_IDLE_N_HOLDOFF_LSB_MASK 0xff + +/* WCD939X_CFG2 Fields: */ +#define WCD939X_CFG2_IDLE_N_HOLDOFF_MSB_MASK 0x0f + +/* WCD939X_CFG3 Fields: */ +#define WCD939X_CFG3_IDLE_THRESHOLD_MASK 0xff + + +/* WCD939X_DSD_HPHL_PATH_CTL Fields: */ +#define WCD939X_DSD_HPHL_PATH_CTL_RESET_MASK 0x02 +#define WCD939X_DSD_HPHL_PATH_CTL_CLK_EN_MASK 0x01 + +/* WCD939X_DSD_HPHL_CFG0 Fields: */ +#define WCD939X_DSD_HPHL_CFG0_INP_SEL_MASK 0x01 + +/* WCD939X_DSD_HPHL_CFG1 Fields: */ +#define WCD939X_DSD_HPHL_CFG1_PGA_GAIN_MASK 0xff + +/* WCD939X_DSD_HPHL_CFG2 Fields: */ +#define WCD939X_DSD_HPHL_CFG2_PGA_TIMER_MSB_EXT_MASK 0x78 +#define WCD939X_DSD_HPHL_CFG2_PGA_MUTE_EN_MASK 0x04 +#define WCD939X_DSD_HPHL_CFG2_PGA_MODE_MASK 0x02 +#define WCD939X_DSD_HPHL_CFG2_PGA_HALF_DB_MASK 0x01 + +/* WCD939X_DSD_HPHL_CFG3 Fields: */ +#define WCD939X_DSD_HPHL_CFG3_PGA_TIMER_MASK 0xff + +/* WCD939X_CFG4 Fields: */ +#define WCD939X_CFG4_TOGGLE_THRESHOLD_MASK 0x18 +#define WCD939X_CFG4_MUTE_THRESHOLD_MASK 0x07 + +/* WCD939X_CFG5 Fields: */ +#define WCD939X_CFG5_DATA_BIT_POLARITY_MASK 0x02 +#define WCD939X_CFG5_INP_BIT_POLARITY_MASK 0x01 + + +/* WCD939X_DSD_HPHR_PATH_CTL Fields: */ +#define WCD939X_DSD_HPHR_PATH_CTL_RESET_MASK 0x02 +#define WCD939X_DSD_HPHR_PATH_CTL_CLK_EN_MASK 0x01 + +/* WCD939X_DSD_HPHR_CFG0 Fields: */ +#define WCD939X_DSD_HPHR_CFG0_INP_SEL_MASK 0x01 + +/* WCD939X_DSD_HPHR_CFG1 Fields: */ +#define WCD939X_DSD_HPHR_CFG1_PGA_GAIN_MASK 0xff + +/* WCD939X_DSD_HPHR_CFG2 Fields: */ +#define WCD939X_DSD_HPHR_CFG2_PGA_TIMER_MSB_EXT_MASK 0x78 +#define WCD939X_DSD_HPHR_CFG2_PGA_MUTE_EN_MASK 0x04 +#define WCD939X_DSD_HPHR_CFG2_PGA_MODE_MASK 0x02 +#define WCD939X_DSD_HPHR_CFG2_PGA_HALF_DB_MASK 0x01 + +/* WCD939X_DSD_HPHR_CFG3 Fields: */ +#define WCD939X_DSD_HPHR_CFG3_PGA_TIMER_MASK 0xff + +/* WCD939X_DSD_HPHR_CFG4 Fields: */ +#define WCD939X_DSD_HPHR_CFG4_TOGGLE_THRESHOLD_MASK 0x18 +#define WCD939X_DSD_HPHR_CFG4_MUTE_THRESHOLD_MASK 0x07 + +/* WCD939X_DSD_HPHR_CFG5 Fields: */ +#define WCD939X_DSD_HPHR_CFG5_DATA_BIT_POLARITY_MASK 0x02 +#define WCD939X_DSD_HPHR_CFG5_INP_BIT_POLARITY_MASK 0x01 + + +#endif /* WCD939X_REG_MASKS_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-reg-shifts.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-reg-shifts.h new file mode 100644 index 0000000000..8c17425479 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-reg-shifts.h @@ -0,0 +1,2673 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef WCD939X_REG_SHIFTS_H +#define WCD939X_REG_SHIFTS_H +#include +#include +#include "wcd939x-registers.h" + +/* Use in conjunction with wcd939x-reg-masks.c for field values. */ +/* field_value = (register_value & field_mask) >> field_shift */ + +#define FIELD_SHIFT(register_name, field_name) \ +WCD939X_##register_name##_##field_name##_SHIFT + +/* WCD939X_ANA_PAGE Fields: */ +#define WCD939X_ANA_PAGE_VALUE_SHIFT 0x00 + +/* WCD939X_BIAS Fields: */ +#define WCD939X_BIAS_ANALOG_BIAS_EN_SHIFT 0x07 +#define WCD939X_BIAS_PRECHRG_EN_SHIFT 0x06 +#define WCD939X_BIAS_PRECHRG_CTL_MODE_SHIFT 0x05 + +/* WCD939X_RX_SUPPLIES Fields: */ +#define WCD939X_RX_SUPPLIES_VPOS_EN_SHIFT 0x07 +#define WCD939X_RX_SUPPLIES_VNEG_EN_SHIFT 0x06 +#define WCD939X_RX_SUPPLIES_VPOS_PWR_LVL_SHIFT 0x03 +#define WCD939X_RX_SUPPLIES_VNEG_PWR_LVL_SHIFT 0x02 +#define WCD939X_RX_SUPPLIES_REGULATOR_MODE_SHIFT 0x01 +#define WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE_SHIFT 0x00 + +/* WCD939X_HPH Fields: */ +#define WCD939X_HPH_HPHL_ENABLE_SHIFT 0x07 +#define WCD939X_HPH_HPHR_ENABLE_SHIFT 0x06 +#define WCD939X_HPH_HPHL_REF_ENABLE_SHIFT 0x05 +#define WCD939X_HPH_HPHR_REF_ENABLE_SHIFT 0x04 +#define WCD939X_HPH_PWR_LEVEL_SHIFT 0x02 + +/* WCD939X_EAR Fields: */ +#define WCD939X_EAR_ENABLE_SHIFT 0x07 +#define WCD939X_EAR_SHORT_PROT_EN_SHIFT 0x06 +#define WCD939X_EAR_OUT_IMPEDANCE_SHIFT 0x05 + +/* WCD939X_EAR_COMPANDER_CTL Fields: */ +#define WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG_SHIFT 0x07 +#define WCD939X_EAR_COMPANDER_CTL_EAR_GAIN_SHIFT 0x02 +#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_BYP_SHIFT 0x01 +#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_CLK_EDGE_SHIFT 0x00 + +/* WCD939X_TX_CH1 Fields: */ +#define WCD939X_TX_CH1_ENABLE_SHIFT 0x07 +#define WCD939X_TX_CH1_PWR_LEVEL_SHIFT 0x05 +#define WCD939X_TX_CH1_GAIN_SHIFT 0x00 + +/* WCD939X_TX_CH2 Fields: */ +#define WCD939X_TX_CH2_ENABLE_SHIFT 0x07 +#define WCD939X_TX_CH2_HPF1_INIT_SHIFT 0x06 +#define WCD939X_TX_CH2_HPF2_INIT_SHIFT 0x05 +#define WCD939X_TX_CH2_GAIN_SHIFT 0x00 + +/* WCD939X_TX_CH3 Fields: */ +#define WCD939X_TX_CH3_ENABLE_SHIFT 0x07 +#define WCD939X_TX_CH3_PWR_LEVEL_SHIFT 0x05 +#define WCD939X_TX_CH3_GAIN_SHIFT 0x00 + +/* WCD939X_TX_CH4 Fields: */ +#define WCD939X_TX_CH4_ENABLE_SHIFT 0x07 +#define WCD939X_TX_CH4_HPF3_INIT_SHIFT 0x06 +#define WCD939X_TX_CH4_HPF4_INIT_SHIFT 0x05 +#define WCD939X_TX_CH4_GAIN_SHIFT 0x00 + +/* WCD939X_MICB1_MICB2_DSP_EN_LOGIC Fields: */ +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB1_DSP_OVERRIDE_SHIFT 0x07 +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB1_DSP_CTRL_SHIFT 0x05 +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB2_DSP_OVERRIDE_SHIFT 0x04 +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC_MICB2_DSP_CTRL_SHIFT 0x02 + +/* WCD939X_MICB3_DSP_EN_LOGIC Fields: */ +#define WCD939X_MICB3_DSP_EN_LOGIC_MICB3_DSP_OVERRIDE_SHIFT 0x07 +#define WCD939X_MICB3_DSP_EN_LOGIC_MICB3_DSP_CTRL_SHIFT 0x05 + +/* WCD939X_MBHC_MECH Fields: */ +#define WCD939X_MBHC_MECH_L_DET_EN_SHIFT 0x07 +#define WCD939X_MBHC_MECH_GND_DET_EN_SHIFT 0x06 +#define WCD939X_MBHC_MECH_MECH_DETECT_TYPE_SHIFT 0x05 +#define WCD939X_MBHC_MECH_HPHL_PLUG_TYPE_SHIFT 0x04 +#define WCD939X_MBHC_MECH_GND_PLUG_TYPE_SHIFT 0x03 +#define WCD939X_MBHC_MECH_MECH_HS_L_PULLUP_COMP_EN_SHIFT 0x02 +#define WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN_SHIFT 0x01 +#define WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND_SHIFT 0x00 + +/* WCD939X_MBHC_ELECT Fields: */ +#define WCD939X_MBHC_ELECT_FSM_EN_SHIFT 0x07 +#define WCD939X_MBHC_ELECT_BTNDET_ISRC_CTL_SHIFT 0x04 +#define WCD939X_MBHC_ELECT_ELECT_DET_TYPE_SHIFT 0x03 +#define WCD939X_MBHC_ELECT_ELECT_SCHMT_ISRC_CTL_SHIFT 0x01 +#define WCD939X_MBHC_ELECT_BIAS_EN_SHIFT 0x00 + +/* WCD939X_MBHC_ZDET Fields: */ +#define WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN_SHIFT 0x07 +#define WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN_SHIFT 0x06 +#define WCD939X_MBHC_ZDET_ZDET_CHG_EN_SHIFT 0x05 +#define WCD939X_MBHC_ZDET_ZDET_ILEAK_COMP_EN_SHIFT 0x04 +#define WCD939X_MBHC_ZDET_ELECT_ISRC_EN_SHIFT 0x01 + +/* WCD939X_MBHC_RESULT_1 Fields: */ +#define WCD939X_MBHC_RESULT_1_Z_RESULT_LSB_SHIFT 0x00 + +/* WCD939X_MBHC_RESULT_2 Fields: */ +#define WCD939X_MBHC_RESULT_2_Z_RESULT_MSB_SHIFT 0x00 + +/* WCD939X_MBHC_RESULT_3 Fields: */ +#define WCD939X_MBHC_RESULT_3_MIC_SCHMT_RESULT_SHIFT 0x05 +#define WCD939X_MBHC_RESULT_3_IN2P_CLAMP_STATE_SHIFT 0x04 +#define WCD939X_MBHC_RESULT_3_BTN_RESULT_SHIFT 0x00 + +/* WCD939X_MBHC_BTN0 Fields: */ +#define WCD939X_MBHC_BTN0_VTH_SHIFT 0x02 + +/* WCD939X_MBHC_BTN1 Fields: */ +#define WCD939X_MBHC_BTN1_VTH_SHIFT 0x02 + +/* WCD939X_MBHC_BTN2 Fields: */ +#define WCD939X_MBHC_BTN2_VTH_SHIFT 0x02 + +/* WCD939X_MBHC_BTN3 Fields: */ +#define WCD939X_MBHC_BTN3_VTH_SHIFT 0x02 + +/* WCD939X_MBHC_BTN4 Fields: */ +#define WCD939X_MBHC_BTN4_VTH_SHIFT 0x02 + +/* WCD939X_MBHC_BTN5 Fields: */ +#define WCD939X_MBHC_BTN5_VTH_SHIFT 0x02 + +/* WCD939X_MBHC_BTN6 Fields: */ +#define WCD939X_MBHC_BTN6_VTH_SHIFT 0x02 + +/* WCD939X_MBHC_BTN7 Fields: */ +#define WCD939X_MBHC_BTN7_VTH_SHIFT 0x02 + +/* WCD939X_MICB1 Fields: */ +#define WCD939X_MICB1_ENABLE_SHIFT 0x06 +#define WCD939X_MICB1_VOUT_CTL_SHIFT 0x00 + +/* WCD939X_MICB2 Fields: */ +#define WCD939X_MICB2_ENABLE_SHIFT 0x06 +#define WCD939X_MICB2_VOUT_CTL_SHIFT 0x00 + +/* WCD939X_MICB2_RAMP Fields: */ +#define WCD939X_MICB2_RAMP_RAMP_ENABLE_SHIFT 0x07 +#define WCD939X_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE_SHIFT 0x06 +#define WCD939X_MICB2_RAMP_ALLSW_OVRD_ENABLE_SHIFT 0x05 +#define WCD939X_MICB2_RAMP_SHIFT_CTL_SHIFT 0x02 +#define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP_SHIFT 0x00 + +/* WCD939X_MICB3 Fields: */ +#define WCD939X_MICB3_ENABLE_SHIFT 0x06 + +/* WCD939X_MICB4 Fields: */ +#define WCD939X_MICB4_ENABLE_SHIFT 0x06 + + +/* WCD939X_CTL Fields: */ +#define WCD939X_CTL_BG_FAST_MODE_EN_SHIFT 0x07 +#define WCD939X_CTL_TX_SCBIAS_REF_SEL_SHIFT 0x06 +#define WCD939X_CTL_DC_START_UP_EN_SHIFT 0x05 +#define WCD939X_CTL_TRAN_START_UP_EN_SHIFT 0x04 +#define WCD939X_CTL_OTA_BIAS_CTL_SHIFT 0x03 +#define WCD939X_CTL_ATEST_CTL_SHIFT 0x02 +#define WCD939X_CTL_EFUSE_EN_SHIFT 0x01 + +/* WCD939X_VBG_FINE_ADJ Fields: */ +#define WCD939X_VBG_FINE_ADJ_VBG_FINE_ADJ_SHIFT 0x04 +#define WCD939X_VBG_FINE_ADJ_EN_DTEST_BG_STATUS_SHIFT 0x03 +#define WCD939X_VBG_FINE_ADJ_PRECHARGE_TIMER_COUNT_SHIFT 0x00 + + +/* WCD939X_VDDCX_ADJUST Fields: */ +#define WCD939X_VDDCX_ADJUST_RC_ZERO_FREQ_TUNE_SHIFT 0x02 +#define WCD939X_VDDCX_ADJUST_VDDCX_ADJUST_SHIFT 0x00 + +/* WCD939X_DISABLE_LDOL Fields: */ +#define WCD939X_DISABLE_LDOL_DISABLE_LDOL_SHIFT 0x00 + + +/* WCD939X_CTL_CLK Fields: */ +#define WCD939X_CTL_CLK_CLK_SEL_SHIFT 0x06 +#define WCD939X_CTL_CLK_COMP_CLK_CTL_SHIFT 0x04 +#define WCD939X_CTL_CLK_COMP_AZ_CTL_SHIFT 0x02 +#define WCD939X_CTL_CLK_TEST_CLK_EN_SHIFT 0x01 +#define WCD939X_CTL_CLK_COMP_AVG_BYP_EN_SHIFT 0x00 + +/* WCD939X_CTL_ANA Fields: */ +#define WCD939X_CTL_ANA_BIAS_SEL_SHIFT 0x07 + +/* WCD939X_ZDET_VNEG_CTL Fields: */ +#define WCD939X_ZDET_VNEG_CTL_SPARE_BITS_7_6_SHIFT 0x06 +#define WCD939X_ZDET_VNEG_CTL_VPOS_EN_SHIFT 0x05 +#define WCD939X_ZDET_VNEG_CTL_VNEGDAC_LDO_EN_SHIFT 0x04 +#define WCD939X_ZDET_VNEG_CTL_RXBIAS_EN_SHIFT 0x03 +#define WCD939X_ZDET_VNEG_CTL_VNEG_MODE_SHIFT 0x02 +#define WCD939X_ZDET_VNEG_CTL_VNEG_EN_SHIFT 0x01 +#define WCD939X_ZDET_VNEG_CTL_HPH_DISABLE_SHIFT 0x00 + +/* WCD939X_ZDET_BIAS_CTL Fields: */ +#define WCD939X_ZDET_BIAS_CTL_ZDET_ILEAK_EN_OVR_SHIFT 0x07 +#define WCD939X_ZDET_BIAS_CTL_ZDET_ILEAK_COMP_CTL_SHIFT 0x04 +#define WCD939X_ZDET_BIAS_CTL_ZDET_LDO_IREF_SHIFT 0x02 +#define WCD939X_ZDET_BIAS_CTL_ZDET_COMP_IREF_SHIFT 0x00 + +/* WCD939X_CTL_BCS Fields: */ +#define WCD939X_CTL_BCS_FAST_INT_OVRD_EN_SHIFT 0x07 +#define WCD939X_CTL_BCS_ELECT_REM_FAST_REG_OVRD_SHIFT 0x06 +#define WCD939X_CTL_BCS_BTN_RELEASE_FAST_REG_OVRD_SHIFT 0x05 +#define WCD939X_CTL_BCS_BTN_PRESS_FAST_REG_OVRD_SHIFT 0x04 +#define WCD939X_CTL_BCS_ANC_DET_EN_SHIFT 0x01 +#define WCD939X_CTL_BCS_DEBUG_1_SHIFT 0x00 + +/* WCD939X_MOISTURE_DET_FSM_STATUS Fields: */ +#define WCD939X_MOISTURE_DET_FSM_STATUS_ELECT_IN2P_COMP_SHIFT 0x07 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MECH_HS_G_COMP_SHIFT 0x06 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MECH_HS_M_COMP_SHIFT 0x05 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MECH_HS_L_COMP_SHIFT 0x04 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MOISTURE_INTR_SHIFT 0x03 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MOISTURE_GTPOLLING_STATUS_SHIFT 0x02 +#define WCD939X_MOISTURE_DET_FSM_STATUS_MOISTURE_DET_STATUS_SHIFT 0x01 +#define WCD939X_MOISTURE_DET_FSM_STATUS_ZDET_TIMER_SHIFT 0x00 + +/* WCD939X_TEST_CTL Fields: */ +#define WCD939X_TEST_CTL_FAST_DBNC_TIMER_SHIFT 0x04 +#define WCD939X_TEST_CTL_ATEST_SHIFT 0x00 + + +/* WCD939X_MODE Fields: */ +#define WCD939X_MODE_LDOH_EN_SHIFT 0x07 +#define WCD939X_MODE_PWRDN_STATE_SHIFT 0x06 +#define WCD939X_MODE_SLOWRAMP_EN_SHIFT 0x05 +#define WCD939X_MODE_VOUT_ADJUST_SHIFT 0x03 +#define WCD939X_MODE_VOUT_COARSE_ADJ_SHIFT 0x00 + +/* WCD939X_LDOH_BIAS Fields: */ +#define WCD939X_LDOH_BIAS_IBIAS_REF_SHIFT 0x05 +#define WCD939X_LDOH_BIAS_IBIAS_ERR_AMP_SHIFT 0x03 +#define WCD939X_LDOH_BIAS_IBIAS_NATIVE_DEVICE_SHIFT 0x02 +#define WCD939X_LDOH_BIAS_IBIAS_BUFFER_BLEED_SHIFT 0x01 +#define WCD939X_LDOH_BIAS_INRUSH_CURRENT_FIX_DIS_SHIFT 0x00 + +/* WCD939X_STB_LOADS Fields: */ +#define WCD939X_STB_LOADS_STB_LOADS_1_UA_SHIFT 0x04 +#define WCD939X_STB_LOADS_STB_LOAD_10_UA_SHIFT 0x03 +#define WCD939X_STB_LOADS_FORCE_EN_60K_SHIFT 0x02 +#define WCD939X_STB_LOADS_CLK_GATE_SHIFT 0x01 + +/* WCD939X_SLOWRAMP Fields: */ +#define WCD939X_SLOWRAMP_SLOWRAMP_IBIAS_SHIFT 0x06 +#define WCD939X_SLOWRAMP_SLOWRAMP_RESET_TIME_SHIFT 0x04 + + +/* WCD939X_TEST_CTL_1 Fields: */ +#define WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL_SHIFT 0x05 +#define WCD939X_TEST_CTL_1_EN_VREFGEN_SHIFT 0x04 +#define WCD939X_TEST_CTL_1_EN_LDO_SHIFT 0x03 +#define WCD939X_TEST_CTL_1_LDO_BLEEDER_I_CTRL_SHIFT 0x00 + +/* WCD939X_TEST_CTL_2 Fields: */ +#define WCD939X_TEST_CTL_2_IBIAS_VREFGEN_SHIFT 0x06 +#define WCD939X_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_SHIFT 0x05 +#define WCD939X_TEST_CTL_2_SPAREBIT_SHIFT 0x03 +#define WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER_SHIFT 0x00 + +/* WCD939X_TEST_CTL_3 Fields: */ +#define WCD939X_TEST_CTL_3_CFILT_REF_EN_SHIFT 0x07 +#define WCD939X_TEST_CTL_3_RZ_LDO_VAL_SHIFT 0x04 +#define WCD939X_TEST_CTL_3_IBIAS_LDO_STG3_SHIFT 0x02 +#define WCD939X_TEST_CTL_3_ATEST_CTRL_SHIFT 0x00 + + +/* WCD939X_MICB2_TEST_CTL_1 Fields: */ +#define WCD939X_MICB2_TEST_CTL_1_NOISE_FILT_RES_VAL_SHIFT 0x05 +#define WCD939X_MICB2_TEST_CTL_1_EN_VREFGEN_SHIFT 0x04 +#define WCD939X_MICB2_TEST_CTL_1_EN_LDO_SHIFT 0x03 +#define WCD939X_MICB2_TEST_CTL_1_LDO_BLEEDER_I_CTRL_SHIFT 0x00 + +/* WCD939X_MICB2_TEST_CTL_2 Fields: */ +#define WCD939X_MICB2_TEST_CTL_2_IBIAS_VREFGEN_SHIFT 0x06 +#define WCD939X_MICB2_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_SHIFT 0x05 +#define WCD939X_MICB2_TEST_CTL_2_SPAREBIT_SHIFT 0x03 +#define WCD939X_MICB2_TEST_CTL_2_IBIAS_LDO_DRIVER_SHIFT 0x00 + +/* WCD939X_MICB2_TEST_CTL_3 Fields: */ +#define WCD939X_MICB2_TEST_CTL_3_CFILT_REF_EN_SHIFT 0x07 +#define WCD939X_MICB2_TEST_CTL_3_RZ_LDO_VAL_SHIFT 0x04 +#define WCD939X_MICB2_TEST_CTL_3_IBIAS_LDO_STG3_SHIFT 0x02 +#define WCD939X_MICB2_TEST_CTL_3_ATEST_CTRL_SHIFT 0x00 + + +/* WCD939X_MICB3_TEST_CTL_1 Fields: */ +#define WCD939X_MICB3_TEST_CTL_1_NOISE_FILT_RES_VAL_SHIFT 0x05 +#define WCD939X_MICB3_TEST_CTL_1_EN_VREFGEN_SHIFT 0x04 +#define WCD939X_MICB3_TEST_CTL_1_EN_LDO_SHIFT 0x03 +#define WCD939X_MICB3_TEST_CTL_1_LDO_BLEEDER_I_CTRL_SHIFT 0x00 + +/* WCD939X_MICB3_TEST_CTL_2 Fields: */ +#define WCD939X_MICB3_TEST_CTL_2_IBIAS_VREFGEN_SHIFT 0x06 +#define WCD939X_MICB3_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_SHIFT 0x05 +#define WCD939X_MICB3_TEST_CTL_2_SPAREBIT_SHIFT 0x03 +#define WCD939X_MICB3_TEST_CTL_2_IBIAS_LDO_DRIVER_SHIFT 0x00 + +/* WCD939X_MICB3_TEST_CTL_3 Fields: */ +#define WCD939X_MICB3_TEST_CTL_3_CFILT_REF_EN_SHIFT 0x07 +#define WCD939X_MICB3_TEST_CTL_3_RZ_LDO_VAL_SHIFT 0x04 +#define WCD939X_MICB3_TEST_CTL_3_IBIAS_LDO_STG3_SHIFT 0x02 +#define WCD939X_MICB3_TEST_CTL_3_ATEST_CTRL_SHIFT 0x00 + + +/* WCD939X_MICB4_TEST_CTL_1 Fields: */ +#define WCD939X_MICB4_TEST_CTL_1_NOISE_FILT_RES_VAL_SHIFT 0x05 +#define WCD939X_MICB4_TEST_CTL_1_EN_VREFGEN_SHIFT 0x04 +#define WCD939X_MICB4_TEST_CTL_1_EN_LDO_SHIFT 0x03 +#define WCD939X_MICB4_TEST_CTL_1_LDO_BLEEDER_I_CTRL_SHIFT 0x00 + +/* WCD939X_MICB4_TEST_CTL_2 Fields: */ +#define WCD939X_MICB4_TEST_CTL_2_IBIAS_VREFGEN_SHIFT 0x06 +#define WCD939X_MICB4_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS_SHIFT 0x05 +#define WCD939X_MICB4_TEST_CTL_2_SPAREBIT_SHIFT 0x03 +#define WCD939X_MICB4_TEST_CTL_2_IBIAS_LDO_DRIVER_SHIFT 0x00 + +/* WCD939X_MICB4_TEST_CTL_3 Fields: */ +#define WCD939X_MICB4_TEST_CTL_3_CFILT_REF_EN_SHIFT 0x07 +#define WCD939X_MICB4_TEST_CTL_3_RZ_LDO_VAL_SHIFT 0x04 +#define WCD939X_MICB4_TEST_CTL_3_IBIAS_LDO_STG3_SHIFT 0x02 +#define WCD939X_MICB4_TEST_CTL_3_ATEST_CTRL_SHIFT 0x00 + + +/* WCD939X_ADC_VCM Fields: */ +#define WCD939X_ADC_VCM_FLL_ATEST_EN_SHIFT 0x06 +#define WCD939X_ADC_VCM_VCM_L2_12P288_SHIFT 0x04 +#define WCD939X_ADC_VCM_VCM_L2_9P6_SHIFT 0x02 +#define WCD939X_ADC_VCM_VCM_DEFAULT_SHIFT 0x00 + +/* WCD939X_BIAS_ATEST Fields: */ +#define WCD939X_BIAS_ATEST_TX_CURR_EN_SHIFT 0x07 +#define WCD939X_BIAS_ATEST_SC_BIAS_EN_SHIFT 0x06 +#define WCD939X_BIAS_ATEST_SC_BIAS_VREF_SEL_SHIFT 0x05 +#define WCD939X_BIAS_ATEST_ATEST4_EN_SHIFT 0x03 +#define WCD939X_BIAS_ATEST_ATEST3_EN_SHIFT 0x02 +#define WCD939X_BIAS_ATEST_ATEST2_EN_SHIFT 0x01 +#define WCD939X_BIAS_ATEST_ATEST1_EN_SHIFT 0x00 + +/* WCD939X_SPARE1 Fields: */ +#define WCD939X_SPARE1_SPARE_BITS_7_0_SHIFT 0x00 + +/* WCD939X_SPARE2 Fields: */ +#define WCD939X_SPARE2_SPARE_BITS_7_0_SHIFT 0x00 + +/* WCD939X_TXFE_DIV_CTL Fields: */ +#define WCD939X_TXFE_DIV_CTL_FB_SW_DRIVE_SHIFT 0x05 +#define WCD939X_TXFE_DIV_CTL_EN_CKGEN_INIT_SHIFT 0x04 +#define WCD939X_TXFE_DIV_CTL_N_PAUSE_SHIFT 0x00 + +/* WCD939X_TXFE_DIV_START Fields: */ +#define WCD939X_TXFE_DIV_START_DIV_SHIFT 0x00 + +/* WCD939X_SPARE3 Fields: */ +#define WCD939X_SPARE3_SPARE_BITS_7_0_SHIFT 0x00 + +/* WCD939X_SPARE4 Fields: */ +#define WCD939X_SPARE4_SPARE_BITS_7_0_SHIFT 0x00 + + +/* WCD939X_TEST_EN Fields: */ +#define WCD939X_TEST_EN_TXFE1_EN_SHIFT 0x07 +#define WCD939X_TEST_EN_ADC1_EN_SHIFT 0x06 +#define WCD939X_TEST_EN_TXFE1_BYPASS_SHIFT 0x05 +#define WCD939X_TEST_EN_TXFE1_CLK_MODE_SHIFT 0x04 +#define WCD939X_TEST_EN_TXFE2_EN_SHIFT 0x03 +#define WCD939X_TEST_EN_ADC2_EN_SHIFT 0x02 +#define WCD939X_TEST_EN_TXFE2_BYPASS_SHIFT 0x01 +#define WCD939X_TEST_EN_TXFE2_CLK_MODE_SHIFT 0x00 + +/* WCD939X_ADC_IB Fields: */ +#define WCD939X_ADC_IB_ADC2_DEM_MODE_SHIFT 0x06 +#define WCD939X_ADC_IB_ADC2_DEM_OPERATION_SHIFT 0x04 +#define WCD939X_ADC_IB_L2_DAC_DLY_SHIFT 0x02 +#define WCD939X_ADC_IB_DEFAULT_DAC_DLY_SHIFT 0x00 + +/* WCD939X_ATEST_REFCTL Fields: */ +#define WCD939X_ATEST_REFCTL_ATEST_CTL_SHIFT 0x04 +#define WCD939X_ATEST_REFCTL_TXFE_INCM_REF_SHIFT 0x02 +#define WCD939X_ATEST_REFCTL_TXFE_HP_GAIN_MODE_SHIFT 0x01 +#define WCD939X_ATEST_REFCTL_ADCREF_ULPRES_EN_SHIFT 0x00 + +/* WCD939X_TX_1_2_TEST_CTL Fields: */ +#define WCD939X_TX_1_2_TEST_CTL_TXFE_HP_GAIN_SHIFT 0x07 +#define WCD939X_TX_1_2_TEST_CTL_REF_CAP_SHIFT 0x06 +#define WCD939X_TX_1_2_TEST_CTL_ADC1_DEM_MODE_SHIFT 0x04 +#define WCD939X_TX_1_2_TEST_CTL_ADC1_DEM_OPERATION_SHIFT 0x02 +#define WCD939X_TX_1_2_TEST_CTL_SAR_ERR_DET_EN_SHIFT 0x01 +#define WCD939X_TX_1_2_TEST_CTL_SAR_EXT_DELAY_EN_SHIFT 0x00 + +/* WCD939X_TEST_BLK_EN1 Fields: */ +#define WCD939X_TEST_BLK_EN1_ADC1_INT1_EN_SHIFT 0x07 +#define WCD939X_TEST_BLK_EN1_ADC1_INT2_EN_SHIFT 0x06 +#define WCD939X_TEST_BLK_EN1_ADC1_SAR_EN_SHIFT 0x05 +#define WCD939X_TEST_BLK_EN1_ADC1_CMGEN_EN_SHIFT 0x04 +#define WCD939X_TEST_BLK_EN1_ADC1_CLKGEN_EN_SHIFT 0x03 +#define WCD939X_TEST_BLK_EN1_REF_EN_SHIFT 0x02 +#define WCD939X_TEST_BLK_EN1_TXFE1_CLKDIV_EN_SHIFT 0x01 +#define WCD939X_TEST_BLK_EN1_TXFE2_CLKDIV_EN_SHIFT 0x00 + +/* WCD939X_TXFE1_CLKDIV Fields: */ +#define WCD939X_TXFE1_CLKDIV_DIV_SHIFT 0x00 + +/* WCD939X_SAR2_ERR Fields: */ +#define WCD939X_SAR2_ERR_SAR_ERR_COUNT_SHIFT 0x00 + +/* WCD939X_SAR1_ERR Fields: */ +#define WCD939X_SAR1_ERR_SAR_ERR_COUNT_SHIFT 0x00 + + +/* WCD939X_TX_3_4_TEST_EN Fields: */ +#define WCD939X_TX_3_4_TEST_EN_TXFE3_EN_SHIFT 0x07 +#define WCD939X_TX_3_4_TEST_EN_ADC3_EN_SHIFT 0x06 +#define WCD939X_TX_3_4_TEST_EN_TXFE3_BYPASS_SHIFT 0x05 +#define WCD939X_TX_3_4_TEST_EN_TXFE3_CLK_MODE_SHIFT 0x04 +#define WCD939X_TX_3_4_TEST_EN_TXFE4_EN_SHIFT 0x03 +#define WCD939X_TX_3_4_TEST_EN_ADC4_EN_SHIFT 0x02 +#define WCD939X_TX_3_4_TEST_EN_TXFE4_BYPASS_SHIFT 0x01 +#define WCD939X_TX_3_4_TEST_EN_TXFE4_CLK_MODE_SHIFT 0x00 + +/* WCD939X_TX_3_4_ADC_IB Fields: */ +#define WCD939X_TX_3_4_ADC_IB_ADC4_DEM_MODE_SHIFT 0x06 +#define WCD939X_TX_3_4_ADC_IB_ADC4_DEM_OPERATION_SHIFT 0x04 +#define WCD939X_TX_3_4_ADC_IB_L2_DAC_DLY_SHIFT 0x02 +#define WCD939X_TX_3_4_ADC_IB_DEFAULT_DAC_DLY_SHIFT 0x00 + +/* WCD939X_TX_3_4_ATEST_REFCTL Fields: */ +#define WCD939X_TX_3_4_ATEST_REFCTL_ATEST_CTL_SHIFT 0x04 +#define WCD939X_TX_3_4_ATEST_REFCTL_TXFE_INCM_REF_SHIFT 0x02 +#define WCD939X_TX_3_4_ATEST_REFCTL_TXFE_HP_GAIN_MODE_SHIFT 0x01 +#define WCD939X_TX_3_4_ATEST_REFCTL_ADCREF_ULPRES_EN_SHIFT 0x00 + +/* WCD939X_TX_3_4_TEST_CTL Fields: */ +#define WCD939X_TX_3_4_TEST_CTL_TXFE_HP_GAIN_SHIFT 0x07 +#define WCD939X_TX_3_4_TEST_CTL_REF_CAP_SHIFT 0x06 +#define WCD939X_TX_3_4_TEST_CTL_ADC3_DEM_MODE_SHIFT 0x04 +#define WCD939X_TX_3_4_TEST_CTL_ADC3_DEM_OPERATION_SHIFT 0x02 +#define WCD939X_TX_3_4_TEST_CTL_SAR_ERR_DET_EN_SHIFT 0x01 +#define WCD939X_TX_3_4_TEST_CTL_SAR_EXT_DELAY_EN_SHIFT 0x00 + +/* WCD939X_TEST_BLK_EN3 Fields: */ +#define WCD939X_TEST_BLK_EN3_ADC3_INT1_EN_SHIFT 0x07 +#define WCD939X_TEST_BLK_EN3_ADC3_INT2_EN_SHIFT 0x06 +#define WCD939X_TEST_BLK_EN3_ADC3_SAR_EN_SHIFT 0x05 +#define WCD939X_TEST_BLK_EN3_ADC3_CMGEN_EN_SHIFT 0x04 +#define WCD939X_TEST_BLK_EN3_ADC3_CLKGEN_EN_SHIFT 0x03 +#define WCD939X_TEST_BLK_EN3_REF_EN_SHIFT 0x02 +#define WCD939X_TEST_BLK_EN3_TXFE3_CLKDIV_EN_SHIFT 0x01 +#define WCD939X_TEST_BLK_EN3_TXFE4_CLKDIV_EN_SHIFT 0x00 + +/* WCD939X_TXFE3_CLKDIV Fields: */ +#define WCD939X_TXFE3_CLKDIV_DIV_SHIFT 0x00 + +/* WCD939X_SAR4_ERR Fields: */ +#define WCD939X_SAR4_ERR_SAR_ERR_COUNT_SHIFT 0x00 + +/* WCD939X_SAR3_ERR Fields: */ +#define WCD939X_SAR3_ERR_SAR_ERR_COUNT_SHIFT 0x00 + +/* WCD939X_TEST_BLK_EN2 Fields: */ +#define WCD939X_TEST_BLK_EN2_ADC2_INT1_EN_SHIFT 0x07 +#define WCD939X_TEST_BLK_EN2_ADC2_INT2_EN_SHIFT 0x06 +#define WCD939X_TEST_BLK_EN2_ADC2_SAR_EN_SHIFT 0x05 +#define WCD939X_TEST_BLK_EN2_ADC2_CMGEN_EN_SHIFT 0x04 +#define WCD939X_TEST_BLK_EN2_ADC2_CLKGEN_EN_SHIFT 0x03 +#define WCD939X_TEST_BLK_EN2_ADC12_VREF_NONL2_SHIFT 0x01 +#define WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN_SHIFT 0x00 + +/* WCD939X_TXFE2_CLKDIV Fields: */ +#define WCD939X_TXFE2_CLKDIV_DIV_SHIFT 0x00 + +/* WCD939X_TX_3_4_SPARE1 Fields: */ +#define WCD939X_TX_3_4_SPARE1_SPARE_BITS_7_0_SHIFT 0x00 + +/* WCD939X_TEST_BLK_EN4 Fields: */ +#define WCD939X_TEST_BLK_EN4_ADC4_INT1_EN_SHIFT 0x07 +#define WCD939X_TEST_BLK_EN4_ADC4_INT2_EN_SHIFT 0x06 +#define WCD939X_TEST_BLK_EN4_ADC4_SAR_EN_SHIFT 0x05 +#define WCD939X_TEST_BLK_EN4_ADC4_CMGEN_EN_SHIFT 0x04 +#define WCD939X_TEST_BLK_EN4_ADC4_CLKGEN_EN_SHIFT 0x03 +#define WCD939X_TEST_BLK_EN4_ADC34_VREF_NONL2_SHIFT 0x01 +#define WCD939X_TEST_BLK_EN4_SPARE_BITS_0_0_SHIFT 0x00 + +/* WCD939X_TXFE4_CLKDIV Fields: */ +#define WCD939X_TXFE4_CLKDIV_DIV_SHIFT 0x00 + +/* WCD939X_TX_3_4_SPARE2 Fields: */ +#define WCD939X_TX_3_4_SPARE2_SPARE_BITS_7_0_SHIFT 0x00 + + +/* WCD939X_MODE_1 Fields: */ +#define WCD939X_MODE_1_BUCK_EN_DELAY_SEL_SHIFT 0x05 +#define WCD939X_MODE_1_BUCK_EN_RESET_BY_EXT_SHIFT 0x04 + +/* WCD939X_MODE_2 Fields: */ +#define WCD939X_MODE_2_VREF_I2C_SHIFT 0x00 + +/* WCD939X_MODE_3 Fields: */ +#define WCD939X_MODE_3_DELTA_IPEAK_2VPK_SHIFT 0x04 +#define WCD939X_MODE_3_DELTA_IPEAK_OVERRIDE_SHIFT 0x02 +#define WCD939X_MODE_3_CTRL_VREF_BY_SHIFT 0x01 +#define WCD939X_MODE_3_MANUAL_PWR_OPT_HPH_SHIFT 0x00 + +/* WCD939X_CTRL_VCL_1 Fields: */ +#define WCD939X_CTRL_VCL_1_DELTA_V_SEL_SHIFT 0x04 +#define WCD939X_CTRL_VCL_1_VDD_BUCK_FILT_2VPK_SHIFT 0x02 +#define WCD939X_CTRL_VCL_1_VREF_DELTA_GEN_GAIN_SEL_SHIFT 0x00 + +/* WCD939X_CTRL_VCL_2 Fields: */ +#define WCD939X_CTRL_VCL_2_VDD_BUCK_FILT_SHIFT 0x06 +#define WCD939X_CTRL_VCL_2_VREF_FILT_1_SHIFT 0x04 +#define WCD939X_CTRL_VCL_2_VREF_FILT_2_SHIFT 0x01 + +/* WCD939X_CTRL_CCL_1 Fields: */ +#define WCD939X_CTRL_CCL_1_DELTA_IPEAK_SHIFT 0x04 +#define WCD939X_CTRL_CCL_1_DELTA_IVALLEY_SHIFT 0x00 + +/* WCD939X_CTRL_CCL_2 Fields: */ +#define WCD939X_CTRL_CCL_2_CHOOSE_I_LIM_SHIFT 0x02 +#define WCD939X_CTRL_CCL_2_BUCK_BYPASS_OVERRIDE_SHIFT 0x01 +#define WCD939X_CTRL_CCL_2_BUCK_BYPASS_EN_SHIFT 0x00 + +/* WCD939X_CTRL_CCL_3 Fields: */ +#define WCD939X_CTRL_CCL_3_MIN_PON_SHIFT 0x06 +#define WCD939X_CTRL_CCL_3_MIN_NON_SHIFT 0x04 + +/* WCD939X_CTRL_CCL_4 Fields: */ +#define WCD939X_CTRL_CCL_4_P_BLNK_INV1_LOAD_SHIFT 0x07 +#define WCD939X_CTRL_CCL_4_P_BLNK_INV2_LOAD_SHIFT 0x06 +#define WCD939X_CTRL_CCL_4_N_BLNK_INV1_LOAD_SHIFT 0x05 +#define WCD939X_CTRL_CCL_4_N_BLNK_INV2_LOAD_SHIFT 0x04 +#define WCD939X_CTRL_CCL_4_RST_PW_INV_LOAD_SHIFT 0x01 +#define WCD939X_CTRL_CCL_4_INZ_RST_SW_CTRL_SHIFT 0x00 + +/* WCD939X_CTRL_CCL_5 Fields: */ +#define WCD939X_CTRL_CCL_5_IPK_FRC_RST_SHIFT 0x05 + +/* WCD939X_BUCK_TMUX_A_D Fields: */ +#define WCD939X_BUCK_TMUX_A_D_ATEST_SEL_SHIFT 0x07 +#define WCD939X_BUCK_TMUX_A_D_DTEST_MUX_EN_SHIFT 0x03 +#define WCD939X_BUCK_TMUX_A_D_DTEST_BRK_4_BRK_3_BRK_2_BRK_1_SHIFT 0x00 + +/* WCD939X_BUCK_SW_DRV_CNTL Fields: */ +#define WCD939X_BUCK_SW_DRV_CNTL_PSW_DRV_CNTL_SHIFT 0x04 +#define WCD939X_BUCK_SW_DRV_CNTL_NSW_DRV_CNTL_SHIFT 0x00 + +/* WCD939X_SPARE Fields: */ +#define WCD939X_SPARE_CHOOSE_I_LIM_2VPK_SHIFT 0x02 + + +/* WCD939X_EN Fields: */ +#define WCD939X_EN_FLYBACK_EN_DELAY_SEL_SHIFT 0x05 +#define WCD939X_EN_FLYBACK_EN_RESET_BY_EXT_SHIFT 0x04 +#define WCD939X_EN_EN_PWSV_SHIFT 0x03 +#define WCD939X_EN_EN_CUR_DET_SHIFT 0x02 +#define WCD939X_EN_EN_BLEEDER_SHIFT 0x01 +#define WCD939X_EN_VREF_PWR_DAC_SEL_OVERRIDE_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_1 Fields: */ +#define WCD939X_VNEG_CTRL_1_VREF_DELTA_GEN_LP_SHIFT 0x05 +#define WCD939X_VNEG_CTRL_1_VREF_DELTA_GEN_UHQA_SHIFT 0x02 +#define WCD939X_VNEG_CTRL_1_DRV_PSW_LC_SHIFT 0x01 +#define WCD939X_VNEG_CTRL_1_DRV_PSW_HC_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_2 Fields: */ +#define WCD939X_VNEG_CTRL_2_MIN_PON_SHIFT 0x06 +#define WCD939X_VNEG_CTRL_2_MIN_NON_SHIFT 0x05 +#define WCD939X_VNEG_CTRL_2_RST_PW_SHIFT 0x04 +#define WCD939X_VNEG_CTRL_2_P_BLNK_SHIFT 0x02 +#define WCD939X_VNEG_CTRL_2_N_BLNK_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_3 Fields: */ +#define WCD939X_VNEG_CTRL_3_EN_IVLY_FRC_RST_SHIFT 0x04 +#define WCD939X_VNEG_CTRL_3_IVLY_FRC_RST_SHIFT 0x02 +#define WCD939X_VNEG_CTRL_3_INZ_RDY_CTL_SHIFT 0x01 +#define WCD939X_VNEG_CTRL_3_INIT_MINPON_CTL_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_4 Fields: */ +#define WCD939X_VNEG_CTRL_4_ILIM_SEL_SHIFT 0x04 +#define WCD939X_VNEG_CTRL_4_PW_BUF_POS_SHIFT 0x02 +#define WCD939X_VNEG_CTRL_4_PW_BUF_NEG_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_5 Fields: */ +#define WCD939X_VNEG_CTRL_5_IPK_DELTA_VNEG_LP_SHIFT 0x04 +#define WCD939X_VNEG_CTRL_5_IPK_DELTA_VNEG_UHQA_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_6 Fields: */ +#define WCD939X_VNEG_CTRL_6_VREF_THIGH_POS_SHIFT 0x04 +#define WCD939X_VNEG_CTRL_6_VREF_TLOW_POS_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_7 Fields: */ +#define WCD939X_VNEG_CTRL_7_VREF_THIGH_NEG_SHIFT 0x04 +#define WCD939X_VNEG_CTRL_7_VREF_TLOW_NEG_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_8 Fields: */ +#define WCD939X_VNEG_CTRL_8_SW_POS_EN_DLY_SHIFT 0x06 +#define WCD939X_VNEG_CTRL_8_SW_NEG_EN_DLY_SHIFT 0x04 +#define WCD939X_VNEG_CTRL_8_VNEG_EN_DLY_SHIFT 0x01 +#define WCD939X_VNEG_CTRL_8_EN_IVLYCMP_STATIC_SHIFT 0x00 + +/* WCD939X_VNEG_CTRL_9 Fields: */ +#define WCD939X_VNEG_CTRL_9_CUR_DET_TH_SHIFT 0x06 +#define WCD939X_VNEG_CTRL_9_MAXPON_SEL_SHIFT 0x03 +#define WCD939X_VNEG_CTRL_9_EN_MAXPON_FRC_SHIFT 0x02 +#define WCD939X_VNEG_CTRL_9_VREF_PWR_DAC_SEL_SHIFT 0x01 + +/* WCD939X_VNEGDAC_CTRL_1 Fields: */ +#define WCD939X_VNEGDAC_CTRL_1_VREF_DAC_DELTA_GEN_LP_SHIFT 0x05 +#define WCD939X_VNEGDAC_CTRL_1_VREF_DAC_DELTA_GEN_UHQA_SHIFT 0x02 +#define WCD939X_VNEGDAC_CTRL_1_N_BLNK_DAC_SHIFT 0x00 + +/* WCD939X_VNEGDAC_CTRL_2 Fields: */ +#define WCD939X_VNEGDAC_CTRL_2_VREF_DAC_SEL_SHIFT 0x05 +#define WCD939X_VNEGDAC_CTRL_2_VNEGDAC_1P8REF_EN_DLY_SHIFT 0x03 +#define WCD939X_VNEGDAC_CTRL_2_VREF_BLEEDER_SHIFT 0x01 +#define WCD939X_VNEGDAC_CTRL_2_N_ICHRG_BLNK_DAC_SHIFT 0x00 + +/* WCD939X_VNEGDAC_CTRL_3 Fields: */ +#define WCD939X_VNEGDAC_CTRL_3_IPK_DELTA_VNEGDAC_LP_SHIFT 0x04 +#define WCD939X_VNEGDAC_CTRL_3_IPK_DELTA_VNEGDAC_UHQA_SHIFT 0x00 + +/* WCD939X_CTRL_1 Fields: */ +#define WCD939X_CTRL_1_ICHRG_VREF_SHIFT 0x06 +#define WCD939X_CTRL_1_EN_INZCMP_CTL_1_SHIFT 0x05 +#define WCD939X_CTRL_1_EN_INZCMP_CTL_2_SHIFT 0x04 +#define WCD939X_CTRL_1_DELTAV_STEP_CTL_SHIFT 0x03 +#define WCD939X_CTRL_1_EN_MAXNON_FRC_SHIFT 0x02 +#define WCD939X_CTRL_1_MAXNON_SEL_SHIFT 0x00 + +/* WCD939X_FLYBACK_TEST_CTL Fields: */ +#define WCD939X_FLYBACK_TEST_CTL_DTEST_MUX_SEL_SHIFT 0x07 +#define WCD939X_FLYBACK_TEST_CTL_ILIM_SEL_2VPK_SHIFT 0x00 + + +/* WCD939X_AUX_SW_CTL Fields: */ +#define WCD939X_AUX_SW_CTL_AUXL_SW_EN_SHIFT 0x07 +#define WCD939X_AUX_SW_CTL_AUXR_SW_EN_SHIFT 0x06 +#define WCD939X_AUX_SW_CTL_AUXL2R_SW_EN_SHIFT 0x05 + +/* WCD939X_PA_AUX_IN_CONN Fields: */ +#define WCD939X_PA_AUX_IN_CONN_HPHL_AUX_IN_SHIFT 0x07 +#define WCD939X_PA_AUX_IN_CONN_HPHR_AUX_IN_SHIFT 0x06 +#define WCD939X_PA_AUX_IN_CONN_EAR_AUX_IN_SHIFT 0x05 +#define WCD939X_PA_AUX_IN_CONN_SPARE_BITS0_SHIFT 0x04 +#define WCD939X_PA_AUX_IN_CONN_SPARE_BITS1_SHIFT 0x01 +#define WCD939X_PA_AUX_IN_CONN_RX_CLK_PHASE_INV_SHIFT 0x00 + +/* WCD939X_TIMER_DIV Fields: */ +#define WCD939X_TIMER_DIV_RX_CLK_DIVIDER_OVWT_SHIFT 0x07 +#define WCD939X_TIMER_DIV_RX_CLK_DIVIDER_SHIFT 0x00 + +/* WCD939X_OCP_CTL Fields: */ +#define WCD939X_OCP_CTL_SPARE_BITS_SHIFT 0x04 +#define WCD939X_OCP_CTL_N_CONNECTION_ATTEMPTS_SHIFT 0x00 + +/* WCD939X_OCP_COUNT Fields: */ +#define WCD939X_OCP_COUNT_RUN_N_CYCLES_SHIFT 0x04 +#define WCD939X_OCP_COUNT_WAIT_N_CYCLES_SHIFT 0x00 + +/* WCD939X_BIAS_EAR_DAC Fields: */ +#define WCD939X_BIAS_EAR_DAC_EAR_DAC_5_UA_SHIFT 0x04 +#define WCD939X_BIAS_EAR_DAC_ATEST_RX_BIAS_SHIFT 0x00 + +/* WCD939X_BIAS_EAR_AMP Fields: */ +#define WCD939X_BIAS_EAR_AMP_EAR_AMP_10_UA_SHIFT 0x04 +#define WCD939X_BIAS_EAR_AMP_EAR_AMP_5_UA_SHIFT 0x00 + +/* WCD939X_BIAS_HPH_LDO Fields: */ +#define WCD939X_BIAS_HPH_LDO_HPH_NVLDO2_5_UA_SHIFT 0x04 +#define WCD939X_BIAS_HPH_LDO_HPH_NVLDO1_4P5_UA_SHIFT 0x00 + +/* WCD939X_BIAS_HPH_PA Fields: */ +#define WCD939X_BIAS_HPH_PA_HPH_CONSTOP_5_UA_SHIFT 0x04 +#define WCD939X_BIAS_HPH_PA_HPH_AMP_5_UA_SHIFT 0x00 + +/* WCD939X_BIAS_HPH_RDACBUFF_CNP2 Fields: */ +#define WCD939X_BIAS_HPH_RDACBUFF_CNP2_RDAC_BUF_3_UA_SHIFT 0x04 +#define WCD939X_BIAS_HPH_RDACBUFF_CNP2_HPH_CNP_10_UA_SHIFT 0x00 + +/* WCD939X_BIAS_HPH_RDAC_LDO Fields: */ +#define WCD939X_BIAS_HPH_RDAC_LDO_RDAC_LDO_1P65_4_UA_SHIFT 0x04 +#define WCD939X_BIAS_HPH_RDAC_LDO_RDAC_LDO_N1P65_4_UA_SHIFT 0x00 + +/* WCD939X_BIAS_HPH_CNP1 Fields: */ +#define WCD939X_BIAS_HPH_CNP1_HPH_CNP_4_UA_SHIFT 0x04 +#define WCD939X_BIAS_HPH_CNP1_HPH_CNP_3_UA_SHIFT 0x00 + +/* WCD939X_BIAS_HPH_LOWPOWER Fields: */ +#define WCD939X_BIAS_HPH_LOWPOWER_HPH_AMP_LP_1P5_UA_SHIFT 0x04 +#define WCD939X_BIAS_HPH_LOWPOWER_RDAC_BUF_LP_0P25_UA_SHIFT 0x00 + +/* WCD939X_BIAS_AUX_DAC Fields: */ +#define WCD939X_BIAS_AUX_DAC_SPARE_BITS0_SHIFT 0x04 +#define WCD939X_BIAS_AUX_DAC_SPARE_BITS1_SHIFT 0x00 + +/* WCD939X_BIAS_AUX_AMP Fields: */ +#define WCD939X_BIAS_AUX_AMP_SPARE_BITS0_SHIFT 0x04 +#define WCD939X_BIAS_AUX_AMP_SPARE_BITS1_SHIFT 0x00 + +/* WCD939X_BIAS_VNEGDAC_BLEEDER Fields: */ +#define WCD939X_BIAS_VNEGDAC_BLEEDER_BLEEDER_CTRL_SHIFT 0x04 + +/* WCD939X_BIAS_MISC Fields: */ +#define WCD939X_BIAS_MISC_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_BIAS_BUCK_RST Fields: */ +#define WCD939X_BIAS_BUCK_RST_BUCK_RST_2_UA_SHIFT 0x00 + +/* WCD939X_BIAS_BUCK_VREF_ERRAMP Fields: */ +#define WCD939X_BIAS_BUCK_VREF_ERRAMP_BUCK_VREF_1_UA_SHIFT 0x04 +#define WCD939X_BIAS_BUCK_VREF_ERRAMP_BUCK_ERRAMP_1_UA_SHIFT 0x00 + +/* WCD939X_BIAS_FLYB_ERRAMP Fields: */ +#define WCD939X_BIAS_FLYB_ERRAMP_FLYB_ERRAMP_1_UA_SHIFT 0x04 + +/* WCD939X_BIAS_FLYB_BUFF Fields: */ +#define WCD939X_BIAS_FLYB_BUFF_FLYB_VNEG_5_UA_SHIFT 0x04 +#define WCD939X_BIAS_FLYB_BUFF_FLYB_VPOS_5_UA_SHIFT 0x00 + +/* WCD939X_BIAS_FLYB_MID_RST Fields: */ +#define WCD939X_BIAS_FLYB_MID_RST_FLYB_MID_1_UA_SHIFT 0x04 +#define WCD939X_BIAS_FLYB_MID_RST_FLYB_RST_1_UA_SHIFT 0x00 + + +/* WCD939X_L_STATUS Fields: */ +#define WCD939X_L_STATUS_CMPDR_GAIN_SHIFT 0x03 +#define WCD939X_L_STATUS_OCP_COMP_DETECT_SHIFT 0x02 +#define WCD939X_L_STATUS_OCP_LIMIT_SHIFT 0x01 +#define WCD939X_L_STATUS_PA_READY_SHIFT 0x00 + +/* WCD939X_R_STATUS Fields: */ +#define WCD939X_R_STATUS_CMPDR_GAIN_SHIFT 0x03 +#define WCD939X_R_STATUS_OCP_COMP_DETECT_SHIFT 0x02 +#define WCD939X_R_STATUS_OCP_LIMIT_SHIFT 0x01 +#define WCD939X_R_STATUS_PA_READY_SHIFT 0x00 + +/* WCD939X_CNP_EN Fields: */ +#define WCD939X_CNP_EN_FSM_CLK_EN_SHIFT 0x07 +#define WCD939X_CNP_EN_FSM_RESET_SHIFT 0x06 +#define WCD939X_CNP_EN_CNP_IREF_SEL_SHIFT 0x05 +#define WCD939X_CNP_EN_FSM_OVERRIDE_EN_SHIFT 0x03 +#define WCD939X_CNP_EN_WG_LR_SEL_SHIFT 0x02 +#define WCD939X_CNP_EN_DBG_CURR_DIRECTION_R_SHIFT 0x01 +#define WCD939X_CNP_EN_DBG_VREF_EN_SHIFT 0x00 + +/* WCD939X_CNP_WG_CTL Fields: */ +#define WCD939X_CNP_WG_CTL_GM3_BOOST_EN_SHIFT 0x07 +#define WCD939X_CNP_WG_CTL_NO_PD_SEQU_SHIFT 0x06 +#define WCD939X_CNP_WG_CTL_VREF_TIMER_SHIFT 0x03 +#define WCD939X_CNP_WG_CTL_CURR_LDIV_CTL_SHIFT 0x00 + +/* WCD939X_CNP_WG_TIME Fields: */ +#define WCD939X_CNP_WG_TIME_WG_FINE_TIMER_SHIFT 0x00 + +/* WCD939X_HPH_OCP_CTL Fields: */ +#define WCD939X_HPH_OCP_CTL_OCP_CURR_LIMIT_SHIFT 0x05 +#define WCD939X_HPH_OCP_CTL_OCP_FSM_EN_SHIFT 0x04 +#define WCD939X_HPH_OCP_CTL_SPARE_BITS_SHIFT 0x03 +#define WCD939X_HPH_OCP_CTL_SCD_OP_EN_SHIFT 0x01 + +/* WCD939X_AUTO_CHOP Fields: */ +#define WCD939X_AUTO_CHOP_GM3_CASCODE_CTL_2VPK_SHIFT 0x06 +#define WCD939X_AUTO_CHOP_AUTO_CHOPPER_MODE_SHIFT 0x05 +#define WCD939X_AUTO_CHOP_GAIN_THRESHOLD_SHIFT 0x00 + +/* WCD939X_CHOP_CTL Fields: */ +#define WCD939X_CHOP_CTL_CHOPPER_EN_SHIFT 0x07 +#define WCD939X_CHOP_CTL_CLK_INV_SHIFT 0x06 +#define WCD939X_CHOP_CTL_SPARE_BITS_SHIFT 0x03 +#define WCD939X_CHOP_CTL_DIV2_DIV_BY_2_SHIFT 0x02 +#define WCD939X_CHOP_CTL_DIV2_DIV_BY_2_4_6_8_SHIFT 0x00 + +/* WCD939X_PA_CTL1 Fields: */ +#define WCD939X_PA_CTL1_GM3_IBIAS_CTL_SHIFT 0x04 +#define WCD939X_PA_CTL1_GM3_IB_SCALE_SHIFT 0x01 +#define WCD939X_PA_CTL1_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_PA_CTL2 Fields: */ +#define WCD939X_PA_CTL2_SPARE_BITS0_SHIFT 0x07 +#define WCD939X_PA_CTL2_HPHPA_GND_R_SHIFT 0x06 +#define WCD939X_PA_CTL2_SPARE_BITS1_SHIFT 0x05 +#define WCD939X_PA_CTL2_HPHPA_GND_L_SHIFT 0x04 +#define WCD939X_PA_CTL2_SPARE_BITS2_SHIFT 0x02 +#define WCD939X_PA_CTL2_GM3_CASCODE_CTL_NORMAL_SHIFT 0x00 + +/* WCD939X_L_EN Fields: */ +#define WCD939X_L_EN_CONST_SEL_L_SHIFT 0x06 +#define WCD939X_L_EN_GAIN_SOURCE_SEL_SHIFT 0x05 +#define WCD939X_L_EN_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_L_TEST Fields: */ +#define WCD939X_L_TEST_PDN_EN_SHIFT 0x07 +#define WCD939X_L_TEST_PDN_AMP2_EN_SHIFT 0x06 +#define WCD939X_L_TEST_PDN_AMP_EN_SHIFT 0x05 +#define WCD939X_L_TEST_PA_CNP_SW_CONN_SHIFT 0x04 +#define WCD939X_L_TEST_PA_CNP_SW_OFF_SHIFT 0x03 +#define WCD939X_L_TEST_PA_CNP_SW_ON_SHIFT 0x02 +#define WCD939X_L_TEST_SPARE_BITS_SHIFT 0x01 +#define WCD939X_L_TEST_OCP_DET_EN_SHIFT 0x00 + +/* WCD939X_L_ATEST Fields: */ +#define WCD939X_L_ATEST_DACL_REF_ATEST1_CONN_SHIFT 0x07 +#define WCD939X_L_ATEST_LDO1_L_ATEST2_CONN_SHIFT 0x06 +#define WCD939X_L_ATEST_LDO_L_ATEST2_CAL_SHIFT 0x05 +#define WCD939X_L_ATEST_LDO2_L_ATEST2_CONN_SHIFT 0x04 +#define WCD939X_L_ATEST_HPHPA_GND_OVR_SHIFT 0x03 +#define WCD939X_L_ATEST_SPARE_BITS_SHIFT 0x02 +#define WCD939X_L_ATEST_CNP_EXD2_SHIFT 0x01 +#define WCD939X_L_ATEST_CNP_EXD1_SHIFT 0x00 + +/* WCD939X_R_EN Fields: */ +#define WCD939X_R_EN_CONST_SEL_R_SHIFT 0x06 +#define WCD939X_R_EN_GAIN_SOURCE_SEL_SHIFT 0x05 +#define WCD939X_R_EN_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_R_TEST Fields: */ +#define WCD939X_R_TEST_PDN_EN_SHIFT 0x07 +#define WCD939X_R_TEST_PDN_AMP2_EN_SHIFT 0x06 +#define WCD939X_R_TEST_PDN_AMP_EN_SHIFT 0x05 +#define WCD939X_R_TEST_PA_CNP_SW_CONN_SHIFT 0x04 +#define WCD939X_R_TEST_PA_CNP_SW_OFF_SHIFT 0x03 +#define WCD939X_R_TEST_PA_CNP_SW_ON_SHIFT 0x02 +#define WCD939X_R_TEST_SPARE_BITS_SHIFT 0x01 +#define WCD939X_R_TEST_OCP_DET_EN_SHIFT 0x00 + +/* WCD939X_R_ATEST Fields: */ +#define WCD939X_R_ATEST_DACR_REF_ATEST1_CONN_SHIFT 0x07 +#define WCD939X_R_ATEST_LDO1_R_ATEST2_CONN_SHIFT 0x06 +#define WCD939X_R_ATEST_LDO_R_ATEST2_CAL_SHIFT 0x05 +#define WCD939X_R_ATEST_LDO2_R_ATEST2_CONN_SHIFT 0x04 +#define WCD939X_R_ATEST_LDO_1P65V_ATEST1_CONN_SHIFT 0x03 +#define WCD939X_R_ATEST_SPARE_BITS0_SHIFT 0x02 +#define WCD939X_R_ATEST_HPH_GND_OVR_SHIFT 0x01 +#define WCD939X_R_ATEST_SPARE_BITS1_SHIFT 0x00 + +/* WCD939X_RDAC_CLK_CTL1 Fields: */ +#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN_SHIFT 0x07 +#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_DIV_CTRL_SHIFT 0x04 +#define WCD939X_RDAC_CLK_CTL1_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_RDAC_CLK_CTL2 Fields: */ +#define WCD939X_RDAC_CLK_CTL2_SPARE_BITS_SHIFT 0x04 +#define WCD939X_RDAC_CLK_CTL2_PREREF_SC_CLK_EN_SHIFT 0x03 +#define WCD939X_RDAC_CLK_CTL2_PREREF_SC_CLK_DIVIDER_CTRL_SHIFT 0x00 + +/* WCD939X_RDAC_LDO_CTL Fields: */ +#define WCD939X_RDAC_LDO_CTL_LDO_1P65_BYPASS_SHIFT 0x07 +#define WCD939X_RDAC_LDO_CTL_LDO_1P65_OUTCTL_SHIFT 0x04 +#define WCD939X_RDAC_LDO_CTL_N1P65V_LDO_BYPASS_SHIFT 0x03 +#define WCD939X_RDAC_LDO_CTL_N1P65_LDO_OUTCTL_SHIFT 0x00 + +/* WCD939X_RDAC_CHOP_CLK_LP_CTL Fields: */ +#define WCD939X_RDAC_CHOP_CLK_LP_CTL_OPAMP_CHOP_CLK_EN_LP_SHIFT 0x07 +#define WCD939X_RDAC_CHOP_CLK_LP_CTL_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_REFBUFF_UHQA_CTL Fields: */ +#define WCD939X_REFBUFF_UHQA_CTL_SPARE_BITS_SHIFT 0x06 +#define WCD939X_REFBUFF_UHQA_CTL_HPH_VNEGREG2_COMP_CTL_OV_SHIFT 0x05 +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_RBIAS_ADJUST_SHIFT 0x04 +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFP_IOUT_CTL_SHIFT 0x02 +#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_IOUT_CTL_SHIFT 0x00 + +/* WCD939X_REFBUFF_LP_CTL Fields: */ +#define WCD939X_REFBUFF_LP_CTL_HPH_VNEGREG2_CURR_COMP_SHIFT 0x06 +#define WCD939X_REFBUFF_LP_CTL_SPARE_BITS_SHIFT 0x04 +#define WCD939X_REFBUFF_LP_CTL_EN_PREREF_FILT_STARTUP_CLKDIV_SHIFT 0x03 +#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_STARTUP_CLKDIV_CTL_SHIFT 0x01 +#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS_SHIFT 0x00 + +/* WCD939X_L_DAC_CTL Fields: */ +#define WCD939X_L_DAC_CTL_SPARE_BITS_SHIFT 0x07 +#define WCD939X_L_DAC_CTL_DAC_REF_EN_SHIFT 0x06 +#define WCD939X_L_DAC_CTL_DAC_SAMPLE_EDGE_SELECT_SHIFT 0x05 +#define WCD939X_L_DAC_CTL_DATA_RESET_SHIFT 0x04 +#define WCD939X_L_DAC_CTL_INV_DATA_SHIFT 0x03 +#define WCD939X_L_DAC_CTL_DAC_L_EN_OV_SHIFT 0x02 +#define WCD939X_L_DAC_CTL_DAC_LDO_UHQA_OV_SHIFT 0x01 +#define WCD939X_L_DAC_CTL_DAC_LDO_POWERMODE_SHIFT 0x00 + +/* WCD939X_R_DAC_CTL Fields: */ +#define WCD939X_R_DAC_CTL_SPARE_BITS_SHIFT 0x07 +#define WCD939X_R_DAC_CTL_DAC_REF_EN_SHIFT 0x06 +#define WCD939X_R_DAC_CTL_DAC_SAMPLE_EDGE_SELECT_SHIFT 0x05 +#define WCD939X_R_DAC_CTL_DATA_RESET_SHIFT 0x04 +#define WCD939X_R_DAC_CTL_INV_DATA_SHIFT 0x03 +#define WCD939X_R_DAC_CTL_DAC_R_EN_OV_SHIFT 0x02 +#define WCD939X_R_DAC_CTL_DAC_PREREF_UHQA_OV_SHIFT 0x01 +#define WCD939X_R_DAC_CTL_DAC_PREREF_POWERMODE_SHIFT 0x00 + + +/* WCD939X_HPHLR_SURGE_COMP_SEL Fields: */ +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHL_PSURGE_SHIFT 0x06 +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHL_NSURGE_SHIFT 0x04 +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHR_PSURGE_SHIFT 0x02 +#define WCD939X_HPHLR_SURGE_COMP_SEL_COMP_REF_SEL_HPHR_NSURGE_SHIFT 0x00 + +/* WCD939X_HPHLR_SURGE_EN Fields: */ +#define WCD939X_HPHLR_SURGE_EN_EN_SURGE_PROTECTION_HPHL_SHIFT 0x07 +#define WCD939X_HPHLR_SURGE_EN_EN_SURGE_PROTECTION_HPHR_SHIFT 0x06 +#define WCD939X_HPHLR_SURGE_EN_SEL_SURGE_COMP_IQ_SHIFT 0x04 +#define WCD939X_HPHLR_SURGE_EN_SURGE_VOLT_MODE_SHUTOFF_EN_SHIFT 0x03 +#define WCD939X_HPHLR_SURGE_EN_LATCH_INTR_OP_STG_HIZ_EN_SHIFT 0x02 +#define WCD939X_HPHLR_SURGE_EN_SURGE_LATCH_REG_RESET_SHIFT 0x01 +#define WCD939X_HPHLR_SURGE_EN_SWTICH_VN_VNDAC_NSURGE_EN_SHIFT 0x00 + +/* WCD939X_HPHLR_SURGE_MISC1 Fields: */ +#define WCD939X_HPHLR_SURGE_MISC1_EN_VNEG_PULLDN_SHIFT 0x07 +#define WCD939X_HPHLR_SURGE_MISC1_EN_OFFSET_36MV_NSURGE_RESLADDER_SHIFT 0x06 +#define WCD939X_HPHLR_SURGE_MISC1_EN_NMOS_LAMP_SHIFT 0x05 +#define WCD939X_HPHLR_SURGE_MISC1_EN_NCLAMP_REG_HPHL_SHIFT 0x04 +#define WCD939X_HPHLR_SURGE_MISC1_EN_NCLAMP_REG_HPHR_SHIFT 0x03 +#define WCD939X_HPHLR_SURGE_MISC1_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_HPHLR_SURGE_STATUS Fields: */ +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_CLAMP_SW_STATUS_SHIFT 0x07 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_CLAMP_SW_STATUS_SHIFT 0x06 +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_PSURGE_COMP_STATUS_SHIFT 0x05 +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_NSURGE_COMP_STATUS_SHIFT 0x04 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_PSURGE_COMP_STATUS_SHIFT 0x03 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_NSURGE_COMP_STATUS_SHIFT 0x02 +#define WCD939X_HPHLR_SURGE_STATUS_HPHL_SURGE_DET_INTR_EN_SHIFT 0x01 +#define WCD939X_HPHLR_SURGE_STATUS_HPHR_SURGE_DET_INTR_EN_SHIFT 0x00 + + +/* WCD939X_EAR_EN_REG Fields: */ +#define WCD939X_EAR_EN_REG_EAR_DAC_DATA_RESET_SHIFT 0x07 +#define WCD939X_EAR_EN_REG_EAR_DAC_DATA_EN_SHIFT 0x06 +#define WCD939X_EAR_EN_REG_EAR_DAC_REF_EN_SHIFT 0x05 +#define WCD939X_EAR_EN_REG_EAR_VCM_EN_SHIFT 0x04 +#define WCD939X_EAR_EN_REG_EAR_AMP_EN_SHIFT 0x03 +#define WCD939X_EAR_EN_REG_EAR_BIAS_EN_SHIFT 0x02 +#define WCD939X_EAR_EN_REG_EAR_CNP_FSM_EN_SHIFT 0x01 +#define WCD939X_EAR_EN_REG_EAR_OUTPUT_SHORT_SHIFT 0x00 + +/* WCD939X_EAR_PA_CON Fields: */ +#define WCD939X_EAR_PA_CON_EAR_ANA_AUX_EN_SHIFT 0x07 +#define WCD939X_EAR_PA_CON_EAR_CMFB_SF_BYPASS_SHIFT 0x06 +#define WCD939X_EAR_PA_CON_EAR_SF_CURR_SHIFT 0x05 +#define WCD939X_EAR_PA_CON_EAR_BTI_CTL_SHIFT 0x04 +#define WCD939X_EAR_PA_CON_EAR_GM3_IBIAS_CTL_SHIFT 0x00 + +/* WCD939X_EAR_SP_CON Fields: */ +#define WCD939X_EAR_SP_CON_EAR_SP_INT_EN_SHIFT 0x07 +#define WCD939X_EAR_SP_CON_EAR_SP_AUTO_SHT_DWN_SHIFT 0x06 +#define WCD939X_EAR_SP_CON_SP_LIMIT_CURR_NMOS_SHIFT 0x03 +#define WCD939X_EAR_SP_CON_SP_LIMIT_CURR_PMOS_SHIFT 0x00 + +/* WCD939X_EAR_DAC_CON Fields: */ +#define WCD939X_EAR_DAC_CON_DAC_SAMPLE_EDGE_SEL_SHIFT 0x07 +#define WCD939X_EAR_DAC_CON_REF_DBG_EN_SHIFT 0x06 +#define WCD939X_EAR_DAC_CON_REF_DBG_GAIN_SHIFT 0x03 +#define WCD939X_EAR_DAC_CON_GAIN_DAC_SHIFT 0x01 +#define WCD939X_EAR_DAC_CON_INV_DATA_SHIFT 0x00 + +/* WCD939X_EAR_CNP_FSM_CON Fields: */ +#define WCD939X_EAR_CNP_FSM_CON_CNP_FSM_CLK_DIV1_SHIFT 0x04 +#define WCD939X_EAR_CNP_FSM_CON_CNP_FSM_CLK_DIV2_SHIFT 0x02 +#define WCD939X_EAR_CNP_FSM_CON_SCD_FSM_DEGLITCH_SEL_SHIFT 0x00 + +/* WCD939X_EAR_TEST_CTL Fields: */ +#define WCD939X_EAR_TEST_CTL_DTEST_EN_SHIFT 0x07 +#define WCD939X_EAR_TEST_CTL_DTEST_SEL_2_SHIFT 0x06 +#define WCD939X_EAR_TEST_CTL_EAR_RDAC_ATEST_EN_SHIFT 0x05 +#define WCD939X_EAR_TEST_CTL_EAR_PA_ATEST_SEL_SHIFT 0x00 + +/* WCD939X_STATUS_REG_1 Fields: */ +#define WCD939X_STATUS_REG_1_SP_INT_SHIFT 0x07 +#define WCD939X_STATUS_REG_1_SP_ALL_OUT_SHIFT 0x06 +#define WCD939X_STATUS_REG_1_SP_NMOS_OUT_SHIFT 0x05 +#define WCD939X_STATUS_REG_1_SP_PMOS_OUT_SHIFT 0x04 +#define WCD939X_STATUS_REG_1_PA_READY_SHIFT 0x03 +#define WCD939X_STATUS_REG_1_CNP_FSM_STATUS_SHIFT 0x02 + +/* WCD939X_STATUS_REG_2 Fields: */ +#define WCD939X_STATUS_REG_2_PA_EN_SHIFT 0x07 +#define WCD939X_STATUS_REG_2_BIAS_EN_SHIFT 0x06 +#define WCD939X_STATUS_REG_2_DAC_EN_SHIFT 0x05 +#define WCD939X_STATUS_REG_2_VCM_EN_SHIFT 0x04 +#define WCD939X_STATUS_REG_2_CLK_EN_SHIFT 0x03 +#define WCD939X_STATUS_REG_2_SCD_EN_SHIFT 0x02 +#define WCD939X_STATUS_REG_2_SHORT_EN_SHIFT 0x01 +#define WCD939X_STATUS_REG_2_DAC_RESET_SHIFT 0x00 + + +/* WCD939X_ANA_NEW_PAGE Fields: */ +#define WCD939X_ANA_NEW_PAGE_VALUE_SHIFT 0x00 + + +/* WCD939X_ANA_HPH2 Fields: */ +#define WCD939X_ANA_HPH2_HIFI_2VPK_PA_GAIN_CTL_SHIFT 0x07 +#define WCD939X_ANA_HPH2_ULP_VREF_CTL_SHIFT 0x06 +#define WCD939X_ANA_HPH2_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_ANA_HPH3 Fields: */ +#define WCD939X_ANA_HPH3_SPARE_BITS_SHIFT 0x00 + + +/* WCD939X_SLEEP_CTL Fields: */ +#define WCD939X_SLEEP_CTL_SPARE_BITS_SHIFT 0x07 +#define WCD939X_SLEEP_CTL_LDOL_BG_SEL_SHIFT 0x04 +#define WCD939X_SLEEP_CTL_BG_CTL_SHIFT 0x01 +#define WCD939X_SLEEP_CTL_DTEST_EN_SHIFT 0x00 + +/* WCD939X_WATCHDOG_CTL Fields: */ +#define WCD939X_WATCHDOG_CTL_EN_WATCHDOG_SHIFT 0x07 +#define WCD939X_WATCHDOG_CTL_EN_WATCHDOG_VREFGEN_SHIFT 0x06 +#define WCD939X_WATCHDOG_CTL_BYPASS_WATCHDOG_SHIFT 0x05 +#define WCD939X_WATCHDOG_CTL_ATEST_CTL_SHIFT 0x02 + + +/* WCD939X_ELECT_REM_CLAMP_CTL Fields: */ +#define WCD939X_ELECT_REM_CLAMP_CTL_FSM_ELECT_CLAMP_EN_SHIFT 0x07 +#define WCD939X_ELECT_REM_CLAMP_CTL_SLNQ_ELECT_CLAMP_EN_SHIFT 0x06 +#define WCD939X_ELECT_REM_CLAMP_CTL_SLNQ_FAIL_CLAMP_EN_SHIFT 0x05 +#define WCD939X_ELECT_REM_CLAMP_CTL_SLNQ_ELECT_REM_RST_SHIFT 0x04 + +/* WCD939X_CTL_1 Fields: */ +#define WCD939X_CTL_1_RCO_EN_SHIFT 0x07 +#define WCD939X_CTL_1_ADC_MODE_SHIFT 0x04 +#define WCD939X_CTL_1_ADC_ENABLE_SHIFT 0x03 +#define WCD939X_CTL_1_DETECTION_DONE_SHIFT 0x02 +#define WCD939X_CTL_1_BTN_DBNC_CTL_SHIFT 0x00 + +/* WCD939X_CTL_2 Fields: */ +#define WCD939X_CTL_2_MUX_CTL_SHIFT 0x04 +#define WCD939X_CTL_2_M_RTH_CTL_SHIFT 0x02 +#define WCD939X_CTL_2_HS_VREF_CTL_SHIFT 0x00 + +/* WCD939X_PLUG_DETECT_CTL Fields: */ +#define WCD939X_PLUG_DETECT_CTL_SPARE_BITS_7_6_SHIFT 0x06 +#define WCD939X_PLUG_DETECT_CTL_MIC_CLAMP_CTL_SHIFT 0x04 +#define WCD939X_PLUG_DETECT_CTL_INSREM_DBNC_CTL_SHIFT 0x00 + +/* WCD939X_ZDET_ANA_CTL Fields: */ +#define WCD939X_ZDET_ANA_CTL_AVERAGING_EN_SHIFT 0x07 +#define WCD939X_ZDET_ANA_CTL_ZDET_MAXV_CTL_SHIFT 0x04 +#define WCD939X_ZDET_ANA_CTL_ZDET_RANGE_CTL_SHIFT 0x00 + +/* WCD939X_ZDET_RAMP_CTL Fields: */ +#define WCD939X_ZDET_RAMP_CTL_ZDET_ACC1_MIN_CTL_SHIFT 0x04 +#define WCD939X_ZDET_RAMP_CTL_ZDET_RAMP_TIME_CTL_SHIFT 0x00 + +/* WCD939X_FSM_STATUS Fields: */ +#define WCD939X_FSM_STATUS_ADC_TIMEOUT_SHIFT 0x07 +#define WCD939X_FSM_STATUS_ADC_COMPLETE_SHIFT 0x06 +#define WCD939X_FSM_STATUS_HS_M_COMP_STATUS_SHIFT 0x05 +#define WCD939X_FSM_STATUS_FAST_PRESS_FLAG_STATUS_SHIFT 0x04 +#define WCD939X_FSM_STATUS_FAST_REMOVAL_FLAG_STATUS_SHIFT 0x03 +#define WCD939X_FSM_STATUS_REMOVAL_FLAG_STATUS_SHIFT 0x02 +#define WCD939X_FSM_STATUS_ELECT_REM_RT_STATUS_SHIFT 0x01 +#define WCD939X_FSM_STATUS_BTN_STATUS_SHIFT 0x00 + +/* WCD939X_ADC_RESULT Fields: */ +#define WCD939X_ADC_RESULT_ADC_RESULT_SHIFT 0x00 + + +/* WCD939X_TX_CH12_MUX Fields: */ +#define WCD939X_TX_CH12_MUX_SPARE_BITS_SHIFT 0x06 +#define WCD939X_TX_CH12_MUX_CH2_SEL_SHIFT 0x03 +#define WCD939X_TX_CH12_MUX_CH1_SEL_SHIFT 0x00 + +/* WCD939X_TX_CH34_MUX Fields: */ +#define WCD939X_TX_CH34_MUX_SPARE_BITS_SHIFT 0x06 +#define WCD939X_TX_CH34_MUX_CH4_SEL_SHIFT 0x03 +#define WCD939X_TX_CH34_MUX_CH3_SEL_SHIFT 0x00 + + +/* WCD939X_DIE_CRK_DET_EN Fields: */ +#define WCD939X_DIE_CRK_DET_EN_DIE_CRK_DET_EN_SHIFT 0x07 +#define WCD939X_DIE_CRK_DET_EN_SEL_CURR_INJCT_PT_MRING_SHIFT 0x06 + +/* WCD939X_DIE_CRK_DET_OUT Fields: */ +#define WCD939X_DIE_CRK_DET_OUT_DIE_CRK_DET_OUT_SHIFT 0x07 + + +/* WCD939X_RDAC_GAIN_CTL Fields: */ +#define WCD939X_RDAC_GAIN_CTL_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_PA_GAIN_CTL_L Fields: */ +#define WCD939X_PA_GAIN_CTL_L_EN_HPHPA_2VPK_SHIFT 0x07 +#define WCD939X_PA_GAIN_CTL_L_RX_SUPPLY_LEVEL_SHIFT 0x06 +#define WCD939X_PA_GAIN_CTL_L_DAC_DR_BOOST_SHIFT 0x05 +#define WCD939X_PA_GAIN_CTL_L_PA_GAIN_L_SHIFT 0x00 + +/* WCD939X_RDAC_VREF_CTL Fields: */ +#define WCD939X_RDAC_VREF_CTL_DAC_REF_EFUSE_TUNE_EN_SHIFT 0x07 +#define WCD939X_RDAC_VREF_CTL_DAC_VREFN_TUNE_SHIFT 0x04 +#define WCD939X_RDAC_VREF_CTL_REFCURRENT_2UA_SHIFT 0x03 +#define WCD939X_RDAC_VREF_CTL_DAC_VREFP_TUNE_SHIFT 0x00 + +/* WCD939X_RDAC_OVERRIDE_CTL Fields: */ +#define WCD939X_RDAC_OVERRIDE_CTL_VDDRX_LDO_LIFT_BYPASS_SHIFT 0x07 +#define WCD939X_RDAC_OVERRIDE_CTL_REFBUF_IREF_OVRIDE_SHIFT 0x06 +#define WCD939X_RDAC_OVERRIDE_CTL_SPARE_BITS1_SHIFT 0x04 +#define WCD939X_RDAC_OVERRIDE_CTL_RDAC_IDLE_DETECT_OVERRIDE_SHIFT 0x03 +#define WCD939X_RDAC_OVERRIDE_CTL_SPARE_BITS2_SHIFT 0x00 + +/* WCD939X_PA_GAIN_CTL_R Fields: */ +#define WCD939X_PA_GAIN_CTL_R_D_RCO_CLK_EN_SHIFT 0x07 +#define WCD939X_PA_GAIN_CTL_R_SPARE_BITS_SHIFT 0x05 +#define WCD939X_PA_GAIN_CTL_R_PA_GAIN_R_SHIFT 0x00 + +/* WCD939X_PA_MISC1 Fields: */ +#define WCD939X_PA_MISC1_EN_AUTO_CMPDR_DETECTION_SHIFT 0x07 +#define WCD939X_PA_MISC1_EN_PA_IDLE_DETECT_OVERRIDE_SHIFT 0x06 +#define WCD939X_PA_MISC1_D_PZ_INF_EN_SHIFT 0x05 +#define WCD939X_PA_MISC1_HPHPA_BW_PROG_SHIFT 0x03 +#define WCD939X_PA_MISC1_PA_CHOP_EN_OVERRIDE_SHIFT 0x02 +#define WCD939X_PA_MISC1_OCP_FSM_LOCK_EN_SHIFT 0x01 +#define WCD939X_PA_MISC1_AUTOCHOP_PDN_SEQ_OVERRIDE_SHIFT 0x00 + +/* WCD939X_PA_MISC2 Fields: */ +#define WCD939X_PA_MISC2_HPHPA_HI_Z_SHIFT 0x07 +#define WCD939X_PA_MISC2_HPH_PSRR_ENH_SHIFT 0x06 +#define WCD939X_PA_MISC2_FORCE_IQCTRL_SHIFT 0x05 +#define WCD939X_PA_MISC2_FORCE_PSRREH_SHIFT 0x04 +#define WCD939X_PA_MISC2_CHOP_CLKLAP_SEL_SHIFT 0x03 +#define WCD939X_PA_MISC2_SPARE_BITS_SHIFT 0x02 +#define WCD939X_PA_MISC2_IDLE_DETECT_L_DTEST_ENABLE_SHIFT 0x01 +#define WCD939X_PA_MISC2_IDLE_DETECT_R_DTEST_ENABLE_SHIFT 0x00 + +/* WCD939X_PA_RDAC_MISC Fields: */ +#define WCD939X_PA_RDAC_MISC_CNP_WG_FINE_TIME_LSB_CTL_SHIFT 0x04 +#define WCD939X_PA_RDAC_MISC_RDAC_NSW_REG_CTL_SHIFT 0x03 +#define WCD939X_PA_RDAC_MISC_RDAC_PSW_NSW_CTL_OVERRIDE_SHIFT 0x02 +#define WCD939X_PA_RDAC_MISC_RDAC_PSW_NSW_REG_CTL_SHIFT 0x00 + +/* WCD939X_HPH_TIMER1 Fields: */ +#define WCD939X_HPH_TIMER1_CURR_IDIV_CTL_CMPDR_OFF_SHIFT 0x05 +#define WCD939X_HPH_TIMER1_CURR_IDIV_CTL_AUTOCHOP_SHIFT 0x02 +#define WCD939X_HPH_TIMER1_AUTOCHOP_TIMER_CTL_EN_SHIFT 0x01 +#define WCD939X_HPH_TIMER1_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_HPH_TIMER2 Fields: */ +#define WCD939X_HPH_TIMER2_VREF_TIMER_IDLESTATE_SHIFT 0x05 +#define WCD939X_HPH_TIMER2_CNP_WG_FINE_TIME_LSB_CTL_IDLE_SHIFT 0x01 +#define WCD939X_HPH_TIMER2_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_HPH_TIMER3 Fields: */ +#define WCD939X_HPH_TIMER3_WG_FINE_TIMER_CMPDR_OFF_SHIFT 0x00 + +/* WCD939X_HPH_TIMER4 Fields: */ +#define WCD939X_HPH_TIMER4_WG_FINE_TIMER_AUTOCHOP_SHIFT 0x00 + +/* WCD939X_PA_RDAC_MISC2 Fields: */ +#define WCD939X_PA_RDAC_MISC2_SPARE_BITS_SHIFT 0x05 +#define WCD939X_PA_RDAC_MISC2_RDAC_DNW_RES_FORCE_BYPASS_SHIFT 0x04 +#define WCD939X_PA_RDAC_MISC2_SCLPF_BYPASS_TIMER_STG1_SHIFT 0x02 +#define WCD939X_PA_RDAC_MISC2_SCLPF_BYPASS_TIMER_STG2_SHIFT 0x00 + +/* WCD939X_PA_RDAC_MISC3 Fields: */ +#define WCD939X_PA_RDAC_MISC3_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_RDAC_HD2_CTL_L Fields: */ +#define WCD939X_RDAC_HD2_CTL_L_EN_HD2_RES_DIV_L_SHIFT 0x07 +#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_PULLGND_L_SHIFT 0x06 +#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L_SHIFT 0x00 + +/* WCD939X_RDAC_HD2_CTL_R Fields: */ +#define WCD939X_RDAC_HD2_CTL_R_EN_HD2_RES_DIV_R_SHIFT 0x07 +#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_PULLGND_L_SHIFT 0x06 +#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R_SHIFT 0x00 + + +/* WCD939X_HPH_RDAC_BIAS_LOHIFI Fields: */ +#define WCD939X_HPH_RDAC_BIAS_LOHIFI_HPHPA_BIAS_LOHIFI_SHIFT 0x04 +#define WCD939X_HPH_RDAC_BIAS_LOHIFI_HPHRDAC_BIAS_LOHIFI_SHIFT 0x00 + +/* WCD939X_HPH_RDAC_BIAS_ULP Fields: */ +#define WCD939X_HPH_RDAC_BIAS_ULP_SLEEPBG_PWR_SEL_SHIFT 0x07 +#define WCD939X_HPH_RDAC_BIAS_ULP_SLEEPBG_PWR_SEL_OVERRIDE_SHIFT 0x06 +#define WCD939X_HPH_RDAC_BIAS_ULP_CDC_3P5MM_LEGACY_IN_SHIFT 0x05 +#define WCD939X_HPH_RDAC_BIAS_ULP_SPARE_BITS1_SHIFT 0x04 +#define WCD939X_HPH_RDAC_BIAS_ULP_HPHRDAC_BIAS_ULP_SHIFT 0x00 + +/* WCD939X_HPH_RDAC_LDO_LP Fields: */ +#define WCD939X_HPH_RDAC_LDO_LP_HPHRDAC_1P6VLDO_BIAS_LP_SHIFT 0x04 +#define WCD939X_HPH_RDAC_LDO_LP_HPHRDAC_N1P6VLDO_BIAS_LP_SHIFT 0x00 + + +/* WCD939X_MOISTURE_DET_DC_CTRL Fields: */ +#define WCD939X_MOISTURE_DET_DC_CTRL_ONCOUNT_SHIFT 0x05 +#define WCD939X_MOISTURE_DET_DC_CTRL_OFFCOUNT_SHIFT 0x00 + +/* WCD939X_MOISTURE_DET_POLLING_CTRL Fields: */ +#define WCD939X_MOISTURE_DET_POLLING_CTRL_HPHL_PA_EN_SHIFT 0x06 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_DTEST_EN_SHIFT 0x04 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOISTURE_OVRD_POLLING_SHIFT 0x03 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOISTURE_EN_POLLING_SHIFT 0x02 +#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOISTURE_DBNC_TIME_SHIFT 0x00 + +/* WCD939X_MECH_DET_CURRENT Fields: */ +#define WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL_SHIFT 0x00 + +/* WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW Fields: */ +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_SPARE_BITS_7_SHIFT 0x07 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_ZDET_CLK_SEL_SHIFT 0x06 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_ZDET_SUBSEL_OV_SHIFT 0x05 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_ZDET_CLK_EN_CTL_SHIFT 0x04 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_MOIS_CURRENT_CTL_SEL_SHIFT 0x03 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_MOIS_CURRENT_ADD_SHIFT 0x02 +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW_MECH_REF_SEL_SHIFT 0x00 + + +/* WCD939X_EAR_CHOPPER_CON Fields: */ +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_EN_SHIFT 0x07 +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_DIV_SHIFT 0x03 +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_INV_SHIFT 0x02 +#define WCD939X_EAR_CHOPPER_CON_EAR_CHOPPER_CLK_OVERLAP_SHIFT 0x01 +#define WCD939X_EAR_CHOPPER_CON_SCD_SHTDWN_FAST_PATH_DIS_SHIFT 0x00 + +/* WCD939X_CNP_VCM_CON1 Fields: */ +#define WCD939X_CNP_VCM_CON1_SCD_EN_TIME_SEL_SHIFT 0x07 +#define WCD939X_CNP_VCM_CON1_NO_DYN_BIAS_DURING_STARTUP_SHIFT 0x06 +#define WCD939X_CNP_VCM_CON1_CNP_VCM_GEN_START_SHIFT 0x00 + +/* WCD939X_CNP_VCM_CON2 Fields: */ +#define WCD939X_CNP_VCM_CON2_DTEST_SEL_SHIFT 0x06 +#define WCD939X_CNP_VCM_CON2_CNP_VCM_GEN_STOP_SHIFT 0x00 + +/* WCD939X_EAR_DYNAMIC_BIAS Fields: */ +#define WCD939X_EAR_DYNAMIC_BIAS_EAR_DYN_BIAS_SEL_SHIFT 0x05 +#define WCD939X_EAR_DYNAMIC_BIAS_EAR_BIAS_CURR_SHIFT 0x00 + + +/* WCD939X_WATCHDOG_CTL_1 Fields: */ +#define WCD939X_WATCHDOG_CTL_1_VREF_HI_CTL_SHIFT 0x00 + +/* WCD939X_WATCHDOG_CTL_2 Fields: */ +#define WCD939X_WATCHDOG_CTL_2_VREF_LO_CTL_SHIFT 0x00 + + +/* WCD939X_DIE_CRK_DET_INT1 Fields: */ +#define WCD939X_DIE_CRK_DET_INT1_SEL_EDGE_DET_SHIFT 0x06 +#define WCD939X_DIE_CRK_DET_INT1_EN_RINGM_ATEST_SHIFT 0x05 +#define WCD939X_DIE_CRK_DET_INT1_EN_RINGP_ATEST_SHIFT 0x04 +#define WCD939X_DIE_CRK_DET_INT1_RING_CURR_SEL_SHIFT 0x01 +#define WCD939X_DIE_CRK_DET_INT1_EN_VREF_ATEST_SHIFT 0x00 + +/* WCD939X_DIE_CRK_DET_INT2 Fields: */ +#define WCD939X_DIE_CRK_DET_INT2_REF_CURR_SEL_SHIFT 0x05 +#define WCD939X_DIE_CRK_DET_INT2_COMP_STG1_IBIAS_SHIFT 0x03 +#define WCD939X_DIE_CRK_DET_INT2_COMP_STG2_IBIAS_SHIFT 0x01 +#define WCD939X_DIE_CRK_DET_INT2_EN_ATEST_SHIFT 0x00 + + +/* WCD939X_TXFE_DIVSTOP_L2 Fields: */ +#define WCD939X_TXFE_DIVSTOP_L2_DIV_L2_SHIFT 0x00 + +/* WCD939X_TXFE_DIVSTOP_L1 Fields: */ +#define WCD939X_TXFE_DIVSTOP_L1_DIV_L1_SHIFT 0x00 + +/* WCD939X_TXFE_DIVSTOP_L0 Fields: */ +#define WCD939X_TXFE_DIVSTOP_L0_DIV_L0_SHIFT 0x00 + +/* WCD939X_TXFE_DIVSTOP_ULP1P2M Fields: */ +#define WCD939X_TXFE_DIVSTOP_ULP1P2M_DIV_ULP1P2M_SHIFT 0x00 + +/* WCD939X_TXFE_DIVSTOP_ULP0P6M Fields: */ +#define WCD939X_TXFE_DIVSTOP_ULP0P6M_DIV_ULP0P6M_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG1_L2L1 Fields: */ +#define WCD939X_TXFE_ICTRL_STG1_L2L1_NINIT_L2_SHIFT 0x06 +#define WCD939X_TXFE_ICTRL_STG1_L2L1_ICTRL_STG1_L2L1_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG1_L0 Fields: */ +#define WCD939X_TXFE_ICTRL_STG1_L0_NINIT_L1_SHIFT 0x06 +#define WCD939X_TXFE_ICTRL_STG1_L0_ICTRL_STG1_L0_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG1_ULP Fields: */ +#define WCD939X_TXFE_ICTRL_STG1_ULP_NINIT_L0_SHIFT 0x06 +#define WCD939X_TXFE_ICTRL_STG1_ULP_ICTRL_STG1_ULP_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG2MAIN_L2L1 Fields: */ +#define WCD939X_TXFE_ICTRL_STG2MAIN_L2L1_NINIT_ULP1P2M_SHIFT 0x06 +#define WCD939X_TXFE_ICTRL_STG2MAIN_L2L1_ICTRL_STG2MAIN_L2L1_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG2MAIN_L0 Fields: */ +#define WCD939X_TXFE_ICTRL_STG2MAIN_L0_NINIT_ULP0P6M_SHIFT 0x06 +#define WCD939X_TXFE_ICTRL_STG2MAIN_L0_ADCREF_ULPIBIAS_EN_SHIFT 0x05 +#define WCD939X_TXFE_ICTRL_STG2MAIN_L0_ICTRL_STG2MAIN_L0_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG2MAIN_ULP Fields: */ +#define WCD939X_TXFE_ICTRL_STG2MAIN_ULP_ICTRL_STG2MAIN_ULP_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0 Fields: */ +#define WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0_ICTRL_STG2CASC_L2L1_SHIFT 0x04 +#define WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0_ICTRL_STG2CASC_L0_SHIFT 0x00 + +/* WCD939X_TXFE_ICTRL_STG2CASC_ULP Fields: */ +#define WCD939X_TXFE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M_SHIFT 0x04 +#define WCD939X_TXFE_ICTRL_STG2CASC_ULP_ICTRL_STG2CASC_ULP_SHIFT 0x00 + +/* WCD939X_TXADC_SCBIAS_L2L1 Fields: */ +#define WCD939X_TXADC_SCBIAS_L2L1_ICTRL_SCBIAS_L2_SHIFT 0x04 +#define WCD939X_TXADC_SCBIAS_L2L1_ICTRL_SCBIAS_L1_SHIFT 0x00 + +/* WCD939X_TXADC_SCBIAS_L0ULP Fields: */ +#define WCD939X_TXADC_SCBIAS_L0ULP_ICTRL_SCBIAS_L0_SHIFT 0x04 +#define WCD939X_TXADC_SCBIAS_L0ULP_ICTRL_SCBIAS_ULP1P2M_SHIFT 0x00 + +/* WCD939X_TXADC_INT_L2 Fields: */ +#define WCD939X_TXADC_INT_L2_INT1_L2_SHIFT 0x04 +#define WCD939X_TXADC_INT_L2_INT2_L2_SHIFT 0x00 + +/* WCD939X_TXADC_INT_L1 Fields: */ +#define WCD939X_TXADC_INT_L1_INT1_L1_SHIFT 0x04 +#define WCD939X_TXADC_INT_L1_INT2_L1_SHIFT 0x00 + +/* WCD939X_TXADC_INT_L0 Fields: */ +#define WCD939X_TXADC_INT_L0_INT1_L0_SHIFT 0x04 +#define WCD939X_TXADC_INT_L0_INT2_L0_SHIFT 0x00 + +/* WCD939X_TXADC_INT_ULP Fields: */ +#define WCD939X_TXADC_INT_ULP_INT1_ULP_SHIFT 0x04 +#define WCD939X_TXADC_INT_ULP_INT2_ULP_SHIFT 0x00 + + +/* WCD939X_DIGITAL_PAGE Fields: */ +#define WCD939X_DIGITAL_PAGE_PAG_REG_SHIFT 0x00 + +/* WCD939X_CHIP_ID0 Fields: */ +#define WCD939X_CHIP_ID0_BYTE_0_SHIFT 0x00 + +/* WCD939X_CHIP_ID1 Fields: */ +#define WCD939X_CHIP_ID1_BYTE_1_SHIFT 0x00 + +/* WCD939X_CHIP_ID2 Fields: */ +#define WCD939X_CHIP_ID2_BYTE_2_SHIFT 0x00 + +/* WCD939X_CHIP_ID3 Fields: */ +#define WCD939X_CHIP_ID3_BYTE_3_SHIFT 0x00 + +/* WCD939X_SWR_TX_CLK_RATE Fields: */ +#define WCD939X_SWR_TX_CLK_RATE_CLK_RATE_BK_1_SHIFT 0x04 +#define WCD939X_SWR_TX_CLK_RATE_CLK_RATE_BK_0_SHIFT 0x00 + +/* WCD939X_CDC_RST_CTL Fields: */ +#define WCD939X_CDC_RST_CTL_ANA_SW_RST_N_SHIFT 0x01 +#define WCD939X_CDC_RST_CTL_DIG_SW_RST_N_SHIFT 0x00 + +/* WCD939X_TOP_CLK_CFG Fields: */ +#define WCD939X_TOP_CLK_CFG_RX_CLK_CFG_SHIFT 0x01 +#define WCD939X_TOP_CLK_CFG_TX_CLK_CFG_SHIFT 0x00 + +/* WCD939X_CDC_ANA_CLK_CTL Fields: */ +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV4_CLK_EN_SHIFT 0x05 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN_SHIFT 0x04 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN_SHIFT 0x03 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN_SHIFT 0x02 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN_SHIFT 0x01 +#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN_SHIFT 0x00 + +/* WCD939X_CDC_DIG_CLK_CTL Fields: */ +#define WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN_SHIFT 0x07 +#define WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN_SHIFT 0x06 +#define WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN_SHIFT 0x05 +#define WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN_SHIFT 0x04 +#define WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN_SHIFT 0x02 +#define WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN_SHIFT 0x01 +#define WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN_SHIFT 0x00 + +/* WCD939X_SWR_RST_EN Fields: */ +#define WCD939X_SWR_RST_EN_RX_RESET_SYNC_LOST_EN_SHIFT 0x05 +#define WCD939X_SWR_RST_EN_RX_RESET_SWR_BUS_EN_SHIFT 0x04 +#define WCD939X_SWR_RST_EN_RX_RESET_SWR_REG_EN_SHIFT 0x03 +#define WCD939X_SWR_RST_EN_TX_RESET_SYNC_LOST_EN_SHIFT 0x02 +#define WCD939X_SWR_RST_EN_TX_RESET_SWR_BUS_EN_SHIFT 0x01 +#define WCD939X_SWR_RST_EN_TX_RESET_SWR_REG_EN_SHIFT 0x00 + +/* WCD939X_CDC_PATH_MODE Fields: */ +#define WCD939X_CDC_PATH_MODE_EAR_MODE_SHIFT 0x06 +#define WCD939X_CDC_PATH_MODE_TXD2_MODE_SHIFT 0x04 +#define WCD939X_CDC_PATH_MODE_TXD1_MODE_SHIFT 0x02 +#define WCD939X_CDC_PATH_MODE_TXD0_MODE_SHIFT 0x00 + +/* WCD939X_CDC_RX_RST Fields: */ +#define WCD939X_CDC_RX_RST_RX2_SOFT_RST_SHIFT 0x02 +#define WCD939X_CDC_RX_RST_RX1_SOFT_RST_SHIFT 0x01 +#define WCD939X_CDC_RX_RST_RX0_SOFT_RST_SHIFT 0x00 + +/* WCD939X_CDC_RX0_CTL Fields: */ +#define WCD939X_CDC_RX0_CTL_DSM_DITHER_ENABLE_SHIFT 0x07 +#define WCD939X_CDC_RX0_CTL_DEM_DITHER_ENABLE_SHIFT 0x06 +#define WCD939X_CDC_RX0_CTL_DEM_MID_ENABLE_SHIFT 0x05 +#define WCD939X_CDC_RX0_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_SHIFT 0x04 +#define WCD939X_CDC_RX0_CTL_DEM_SWITCHING_BLOCK_ENABLE_SHIFT 0x03 +#define WCD939X_CDC_RX0_CTL_DEM_SEGMENTING_BLOCK_ENABLE_SHIFT 0x02 +#define WCD939X_CDC_RX0_CTL_DEM_BYPASS_SHIFT 0x01 + +/* WCD939X_CDC_RX1_CTL Fields: */ +#define WCD939X_CDC_RX1_CTL_DSM_DITHER_ENABLE_SHIFT 0x07 +#define WCD939X_CDC_RX1_CTL_DEM_DITHER_ENABLE_SHIFT 0x06 +#define WCD939X_CDC_RX1_CTL_DEM_MID_ENABLE_SHIFT 0x05 +#define WCD939X_CDC_RX1_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_SHIFT 0x04 +#define WCD939X_CDC_RX1_CTL_DEM_SWITCHING_BLOCK_ENABLE_SHIFT 0x03 +#define WCD939X_CDC_RX1_CTL_DEM_SEGMENTING_BLOCK_ENABLE_SHIFT 0x02 +#define WCD939X_CDC_RX1_CTL_DEM_BYPASS_SHIFT 0x01 + +/* WCD939X_CDC_RX2_CTL Fields: */ +#define WCD939X_CDC_RX2_CTL_DSM_DITHER_ENABLE_SHIFT 0x07 +#define WCD939X_CDC_RX2_CTL_DEM_DITHER_ENABLE_SHIFT 0x06 +#define WCD939X_CDC_RX2_CTL_DEM_MID_ENABLE_SHIFT 0x05 +#define WCD939X_CDC_RX2_CTL_DEM_MOD_SWITCHING_BLOCK_ENABLE_SHIFT 0x04 +#define WCD939X_CDC_RX2_CTL_DEM_SWITCHING_BLOCK_ENABLE_SHIFT 0x03 +#define WCD939X_CDC_RX2_CTL_DEM_SEGMENTING_BLOCK_ENABLE_SHIFT 0x02 +#define WCD939X_CDC_RX2_CTL_DEM_BYPASS_SHIFT 0x01 + +/* WCD939X_CDC_TX_ANA_MODE_0_1 Fields: */ +#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE_SHIFT 0x04 +#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE_SHIFT 0x00 + +/* WCD939X_CDC_TX_ANA_MODE_2_3 Fields: */ +#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE_SHIFT 0x04 +#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE_SHIFT 0x00 + +/* WCD939X_CDC_COMP_CTL_0 Fields: */ +#define WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN_SHIFT 0x01 +#define WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN_SHIFT 0x00 + +/* WCD939X_CDC_ANA_TX_CLK_CTL Fields: */ +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_MBHC_1P2M_CLK_EN_SHIFT 0x05 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX3_ADC_CLK_EN_SHIFT 0x04 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX2_ADC_CLK_EN_SHIFT 0x03 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX1_ADC_CLK_EN_SHIFT 0x02 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX0_ADC_CLK_EN_SHIFT 0x01 +#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A1_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A1_0_COEF_A1_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A1_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A1_1_COEF_A1_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A2_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A2_0_COEF_A2_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A2_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A2_1_COEF_A2_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A3_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A3_0_COEF_A3_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A3_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A3_1_COEF_A3_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A4_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A4_0_COEF_A4_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A4_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A4_1_COEF_A4_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A5_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A5_0_COEF_A5_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A5_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_A5_1_COEF_A5_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A6_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A6_0_COEF_A6_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_A7_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_A7_0_COEF_A7_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_C_0 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_0_COEF_C3_SHIFT 0x04 +#define WCD939X_CDC_HPH_DSM_C_0_COEF_C2_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_C_1 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_1_COEF_C5_SHIFT 0x04 +#define WCD939X_CDC_HPH_DSM_C_1_COEF_C4_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_C_2 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_2_COEF_C7_SHIFT 0x04 +#define WCD939X_CDC_HPH_DSM_C_2_COEF_C6_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_C_3 Fields: */ +#define WCD939X_CDC_HPH_DSM_C_3_COEF_C7_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_R1 Fields: */ +#define WCD939X_CDC_HPH_DSM_R1_SAT_LIMIT_R1_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_R2 Fields: */ +#define WCD939X_CDC_HPH_DSM_R2_SAT_LIMIT_R2_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_R3 Fields: */ +#define WCD939X_CDC_HPH_DSM_R3_SAT_LIMIT_R3_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_R4 Fields: */ +#define WCD939X_CDC_HPH_DSM_R4_SAT_LIMIT_R4_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_R5 Fields: */ +#define WCD939X_CDC_HPH_DSM_R5_SAT_LIMIT_R5_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_R6 Fields: */ +#define WCD939X_CDC_HPH_DSM_R6_SAT_LIMIT_R6_SHIFT 0x00 + +/* WCD939X_CDC_HPH_DSM_R7 Fields: */ +#define WCD939X_CDC_HPH_DSM_R7_SAT_LIMIT_R7_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A1_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A1_0_COEF_A1_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A1_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A1_1_COEF_A1_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A2_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A2_0_COEF_A2_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A2_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A2_1_COEF_A2_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A3_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A3_0_COEF_A3_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A3_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A3_1_COEF_A3_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A4_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A4_0_COEF_A4_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A4_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A4_1_COEF_A4_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A5_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A5_0_COEF_A5_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A5_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_A5_1_COEF_A5_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A6_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A6_0_COEF_A6_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_A7_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_A7_0_COEF_A7_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_C_0 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_0_COEF_C3_SHIFT 0x04 +#define WCD939X_CDC_EAR_DSM_C_0_COEF_C2_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_C_1 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_1_COEF_C5_SHIFT 0x04 +#define WCD939X_CDC_EAR_DSM_C_1_COEF_C4_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_C_2 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_2_COEF_C7_SHIFT 0x04 +#define WCD939X_CDC_EAR_DSM_C_2_COEF_C6_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_C_3 Fields: */ +#define WCD939X_CDC_EAR_DSM_C_3_COEF_C7_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_R1 Fields: */ +#define WCD939X_CDC_EAR_DSM_R1_SAT_LIMIT_R1_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_R2 Fields: */ +#define WCD939X_CDC_EAR_DSM_R2_SAT_LIMIT_R2_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_R3 Fields: */ +#define WCD939X_CDC_EAR_DSM_R3_SAT_LIMIT_R3_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_R4 Fields: */ +#define WCD939X_CDC_EAR_DSM_R4_SAT_LIMIT_R4_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_R5 Fields: */ +#define WCD939X_CDC_EAR_DSM_R5_SAT_LIMIT_R5_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_R6 Fields: */ +#define WCD939X_CDC_EAR_DSM_R6_SAT_LIMIT_R6_SHIFT 0x00 + +/* WCD939X_CDC_EAR_DSM_R7 Fields: */ +#define WCD939X_CDC_EAR_DSM_R7_SAT_LIMIT_R7_SHIFT 0x00 + +/* WCD939X_CDC_HPH_GAIN_RX_0 Fields: */ +#define WCD939X_CDC_HPH_GAIN_RX_0_GAIN_RX_SHIFT 0x00 + +/* WCD939X_CDC_HPH_GAIN_RX_1 Fields: */ +#define WCD939X_CDC_HPH_GAIN_RX_1_GAIN_RX_SHIFT 0x00 + +/* WCD939X_CDC_HPH_GAIN_DSD_0 Fields: */ +#define WCD939X_CDC_HPH_GAIN_DSD_0_GAIN_DSD_SHIFT 0x00 + +/* WCD939X_CDC_HPH_GAIN_DSD_1 Fields: */ +#define WCD939X_CDC_HPH_GAIN_DSD_1_GAIN_DSD_SHIFT 0x00 + +/* WCD939X_CDC_HPH_GAIN_DSD_2 Fields: */ +#define WCD939X_CDC_HPH_GAIN_DSD_2_GAIN_LATCH_SHIFT 0x01 +#define WCD939X_CDC_HPH_GAIN_DSD_2_GAIN_DSD_SHIFT 0x00 + +/* WCD939X_CDC_EAR_GAIN_DSD_0 Fields: */ +#define WCD939X_CDC_EAR_GAIN_DSD_0_GAIN_DSD_SHIFT 0x00 + +/* WCD939X_CDC_EAR_GAIN_DSD_1 Fields: */ +#define WCD939X_CDC_EAR_GAIN_DSD_1_GAIN_DSD_SHIFT 0x00 + +/* WCD939X_CDC_EAR_GAIN_DSD_2 Fields: */ +#define WCD939X_CDC_EAR_GAIN_DSD_2_GAIN_LATCH_SHIFT 0x01 +#define WCD939X_CDC_EAR_GAIN_DSD_2_GAIN_DSD_SHIFT 0x00 + +/* WCD939X_CDC_HPH_GAIN_CTL Fields: */ +#define WCD939X_CDC_HPH_GAIN_CTL_HPH_STEREO_EN_SHIFT 0x04 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN_SHIFT 0x03 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN_SHIFT 0x02 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_DSD_EN_SHIFT 0x01 +#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_DSD_EN_SHIFT 0x00 + +/* WCD939X_CDC_EAR_GAIN_CTL Fields: */ +#define WCD939X_CDC_EAR_GAIN_CTL_EAR_EN_SHIFT 0x00 + +/* WCD939X_CDC_EAR_PATH_CTL Fields: */ +#define WCD939X_CDC_EAR_PATH_CTL_EAR_GAIN_CTL_SHIFT 0x01 +#define WCD939X_CDC_EAR_PATH_CTL_EAR_MUX_SEL_SHIFT 0x00 + +/* WCD939X_CDC_SWR_CLH Fields: */ +#define WCD939X_CDC_SWR_CLH_CLH_CTL_SHIFT 0x00 + +/* WCD939X_SWR_CLH_BYP Fields: */ +#define WCD939X_SWR_CLH_BYP_SWR_CLH_BYP_SHIFT 0x00 + +/* WCD939X_CDC_TX0_CTL Fields: */ +#define WCD939X_CDC_TX0_CTL_REQ_FB_SEL_SHIFT 0x06 +#define WCD939X_CDC_TX0_CTL_TX_DITHER_EN_SHIFT 0x05 +#define WCD939X_CDC_TX0_CTL_RANDOM_REGION_SHIFT 0x00 + +/* WCD939X_CDC_TX1_CTL Fields: */ +#define WCD939X_CDC_TX1_CTL_REQ_FB_SEL_SHIFT 0x06 +#define WCD939X_CDC_TX1_CTL_TX_DITHER_EN_SHIFT 0x05 +#define WCD939X_CDC_TX1_CTL_RANDOM_REGION_SHIFT 0x00 + +/* WCD939X_CDC_TX2_CTL Fields: */ +#define WCD939X_CDC_TX2_CTL_REQ_FB_SEL_SHIFT 0x06 +#define WCD939X_CDC_TX2_CTL_TX_DITHER_EN_SHIFT 0x05 +#define WCD939X_CDC_TX2_CTL_RANDOM_REGION_SHIFT 0x00 + +/* WCD939X_CDC_TX_RST Fields: */ +#define WCD939X_CDC_TX_RST_TX3_SOFT_RST_SHIFT 0x03 +#define WCD939X_CDC_TX_RST_TX2_SOFT_RST_SHIFT 0x02 +#define WCD939X_CDC_TX_RST_TX1_SOFT_RST_SHIFT 0x01 +#define WCD939X_CDC_TX_RST_TX0_SOFT_RST_SHIFT 0x00 + +/* WCD939X_CDC_REQ_CTL Fields: */ +#define WCD939X_CDC_REQ_CTL_TX3_WIDE_BAND_SHIFT 0x05 +#define WCD939X_CDC_REQ_CTL_TX2_WIDE_BAND_SHIFT 0x04 +#define WCD939X_CDC_REQ_CTL_TX1_WIDE_BAND_SHIFT 0x03 +#define WCD939X_CDC_REQ_CTL_TX0_WIDE_BAND_SHIFT 0x02 +#define WCD939X_CDC_REQ_CTL_FS_RATE_4P8_SHIFT 0x01 +#define WCD939X_CDC_REQ_CTL_NO_NOTCH_SHIFT 0x00 + +/* WCD939X_CDC_RST Fields: */ +#define WCD939X_CDC_RST_TX_SOFT_RST_SHIFT 0x01 +#define WCD939X_CDC_RST_RX_SOFT_RST_SHIFT 0x00 + +/* WCD939X_CDC_AMIC_CTL Fields: */ +#define WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL_SHIFT 0x03 +#define WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL_SHIFT 0x02 +#define WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL_SHIFT 0x01 +#define WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL_SHIFT 0x00 + +/* WCD939X_CDC_DMIC_CTL Fields: */ +#define WCD939X_CDC_DMIC_CTL_DMIC_LEGACY_SW_MODE_SHIFT 0x03 +#define WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN_SHIFT 0x02 +#define WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN_SHIFT 0x01 +#define WCD939X_CDC_DMIC_CTL_SOFT_RESET_SHIFT 0x00 + +/* WCD939X_CDC_DMIC1_CTL Fields: */ +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SCALE_SEL_SHIFT 0x04 +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN_SHIFT 0x03 +#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SEL_SHIFT 0x00 + +/* WCD939X_CDC_DMIC2_CTL Fields: */ +#define WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN_SHIFT 0x07 +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SCALE_SEL_SHIFT 0x04 +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN_SHIFT 0x03 +#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SEL_SHIFT 0x00 + +/* WCD939X_CDC_DMIC3_CTL Fields: */ +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SCALE_SEL_SHIFT 0x04 +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN_SHIFT 0x03 +#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SEL_SHIFT 0x00 + +/* WCD939X_CDC_DMIC4_CTL Fields: */ +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SCALE_SEL_SHIFT 0x04 +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN_SHIFT 0x03 +#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SEL_SHIFT 0x00 + +/* WCD939X_EFUSE_PRG_CTL Fields: */ +#define WCD939X_EFUSE_PRG_CTL_PRG_ADDR_SHIFT 0x00 + +/* WCD939X_EFUSE_CTL Fields: */ +#define WCD939X_EFUSE_CTL_EFUSE_ST_CNT_SHIFT 0x02 +#define WCD939X_EFUSE_CTL_EFUSE_SOFT_RST_N_SHIFT 0x01 +#define WCD939X_EFUSE_CTL_EFUSE_EN_SHIFT 0x00 + +/* WCD939X_CDC_DMIC_RATE_1_2 Fields: */ +#define WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE_SHIFT 0x04 +#define WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE_SHIFT 0x00 + +/* WCD939X_CDC_DMIC_RATE_3_4 Fields: */ +#define WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE_SHIFT 0x04 +#define WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE_SHIFT 0x00 + +/* WCD939X_PDM_WD_CTL0 Fields: */ +#define WCD939X_PDM_WD_CTL0_HOLD_OFF_SHIFT 0x04 +#define WCD939X_PDM_WD_CTL0_TIME_OUT_SEL_SHIFT 0x03 +#define WCD939X_PDM_WD_CTL0_PDM_WD_EN_SHIFT 0x00 + +/* WCD939X_PDM_WD_CTL1 Fields: */ +#define WCD939X_PDM_WD_CTL1_HOLD_OFF_SHIFT 0x04 +#define WCD939X_PDM_WD_CTL1_TIME_OUT_SEL_SHIFT 0x03 +#define WCD939X_PDM_WD_CTL1_PDM_WD_EN_SHIFT 0x00 + +/* WCD939X_PDM_WD_CTL2 Fields: */ +#define WCD939X_PDM_WD_CTL2_HOLD_OFF_SHIFT 0x02 +#define WCD939X_PDM_WD_CTL2_TIME_OUT_SEL_SHIFT 0x01 +#define WCD939X_PDM_WD_CTL2_PDM_WD_EN_SHIFT 0x00 + +/* WCD939X_INTR_MODE Fields: */ +#define WCD939X_INTR_MODE_SWR_PULSE_CLR_SHIFT 0x05 +#define WCD939X_INTR_MODE_SWR_RX_INT_OUT_EN_SHIFT 0x04 +#define WCD939X_INTR_MODE_SWR_INTR_LEVEL_SHIFT 0x01 +#define WCD939X_INTR_MODE_INT_POLARITY_SHIFT 0x00 + +/* WCD939X_INTR_MASK_0 Fields: */ +#define WCD939X_INTR_MASK_0_HPHL_OCP_INT_SHIFT 0x07 +#define WCD939X_INTR_MASK_0_HPHR_CNP_INT_SHIFT 0x06 +#define WCD939X_INTR_MASK_0_HPHR_OCP_INT_SHIFT 0x05 +#define WCD939X_INTR_MASK_0_MBHC_SW_INT_SHIFT 0x04 +#define WCD939X_INTR_MASK_0_MBHC_ELECT_INS_REM_LEG_INT_SHIFT 0x03 +#define WCD939X_INTR_MASK_0_MBHC_ELECT_INS_REM_INT_SHIFT 0x02 +#define WCD939X_INTR_MASK_0_MBHC_BTN_RELEASE_INT_SHIFT 0x01 +#define WCD939X_INTR_MASK_0_MBHC_BTN_PRESS_INT_SHIFT 0x00 + +/* WCD939X_INTR_MASK_1 Fields: */ +#define WCD939X_INTR_MASK_1_EAR_PDM_WD_INT_SHIFT 0x07 +#define WCD939X_INTR_MASK_1_HPHR_PDM_WD_INT_SHIFT 0x06 +#define WCD939X_INTR_MASK_1_HPHL_PDM_WD_INT_SHIFT 0x05 +#define WCD939X_INTR_MASK_1_EAR_SCD_INT_SHIFT 0x02 +#define WCD939X_INTR_MASK_1_EAR_CNP_INT_SHIFT 0x01 +#define WCD939X_INTR_MASK_1_HPHL_CNP_INT_SHIFT 0x00 + +/* WCD939X_INTR_MASK_2 Fields: */ +#define WCD939X_INTR_MASK_2_HPHL_SURGE_DET_INT_SHIFT 0x03 +#define WCD939X_INTR_MASK_2_HPHR_SURGE_DET_INT_SHIFT 0x02 +#define WCD939X_INTR_MASK_2_MBHC_MOISTRUE_INT_SHIFT 0x01 + +/* WCD939X_INTR_STATUS_0 Fields: */ +#define WCD939X_INTR_STATUS_0_HPHL_OCP_INT_SHIFT 0x07 +#define WCD939X_INTR_STATUS_0_HPHR_CNP_INT_SHIFT 0x06 +#define WCD939X_INTR_STATUS_0_HPHR_OCP_INT_SHIFT 0x05 +#define WCD939X_INTR_STATUS_0_MBHC_SW_INT_SHIFT 0x04 +#define WCD939X_INTR_STATUS_0_MBHC_ELECT_INS_REM_LEG_INT_SHIFT 0x03 +#define WCD939X_INTR_STATUS_0_MBHC_ELECT_INS_REM_INT_SHIFT 0x02 +#define WCD939X_INTR_STATUS_0_MBHC_BTN_RELEASE_INT_SHIFT 0x01 +#define WCD939X_INTR_STATUS_0_MBHC_BTN_PRESS_INT_SHIFT 0x00 + +/* WCD939X_INTR_STATUS_1 Fields: */ +#define WCD939X_INTR_STATUS_1_EAR_PDM_WD_INT_SHIFT 0x07 +#define WCD939X_INTR_STATUS_1_HPHR_PDM_WD_INT_SHIFT 0x06 +#define WCD939X_INTR_STATUS_1_HPHL_PDM_WD_INT_SHIFT 0x05 +#define WCD939X_INTR_STATUS_1_EAR_SCD_INT_SHIFT 0x02 +#define WCD939X_INTR_STATUS_1_EAR_CNP_INT_SHIFT 0x01 +#define WCD939X_INTR_STATUS_1_HPHL_CNP_INT_SHIFT 0x00 + +/* WCD939X_INTR_STATUS_2 Fields: */ +#define WCD939X_INTR_STATUS_2_HPHL_SURGE_DET_INT_SHIFT 0x03 +#define WCD939X_INTR_STATUS_2_HPHR_SURGE_DET_INT_SHIFT 0x02 +#define WCD939X_INTR_STATUS_2_MBHC_MOISTRUE_INT_SHIFT 0x01 + +/* WCD939X_INTR_CLEAR_0 Fields: */ +#define WCD939X_INTR_CLEAR_0_HPHL_OCP_INT_SHIFT 0x07 +#define WCD939X_INTR_CLEAR_0_HPHR_CNP_INT_SHIFT 0x06 +#define WCD939X_INTR_CLEAR_0_HPHR_OCP_INT_SHIFT 0x05 +#define WCD939X_INTR_CLEAR_0_MBHC_SW_INT_SHIFT 0x04 +#define WCD939X_INTR_CLEAR_0_MBHC_ELECT_INS_REM_LEG_INT_SHIFT 0x03 +#define WCD939X_INTR_CLEAR_0_MBHC_ELECT_INS_REM_INT_SHIFT 0x02 +#define WCD939X_INTR_CLEAR_0_MBHC_BTN_RELEASE_INT_SHIFT 0x01 +#define WCD939X_INTR_CLEAR_0_MBHC_BTN_PRESS_INT_SHIFT 0x00 + +/* WCD939X_INTR_CLEAR_1 Fields: */ +#define WCD939X_INTR_CLEAR_1_EAR_PDM_WD_INT_SHIFT 0x07 +#define WCD939X_INTR_CLEAR_1_HPHR_PDM_WD_INT_SHIFT 0x06 +#define WCD939X_INTR_CLEAR_1_HPHL_PDM_WD_INT_SHIFT 0x05 +#define WCD939X_INTR_CLEAR_1_EAR_SCD_INT_SHIFT 0x02 +#define WCD939X_INTR_CLEAR_1_EAR_CNP_INT_SHIFT 0x01 +#define WCD939X_INTR_CLEAR_1_HPHL_CNP_INT_SHIFT 0x00 + +/* WCD939X_INTR_CLEAR_2 Fields: */ +#define WCD939X_INTR_CLEAR_2_HPHL_SURGE_DET_INT_SHIFT 0x03 +#define WCD939X_INTR_CLEAR_2_HPHR_SURGE_DET_INT_SHIFT 0x02 +#define WCD939X_INTR_CLEAR_2_MBHC_MOISTRUE_INT_SHIFT 0x01 + +/* WCD939X_INTR_LEVEL_0 Fields: */ +#define WCD939X_INTR_LEVEL_0_HPHL_OCP_INT_SHIFT 0x07 +#define WCD939X_INTR_LEVEL_0_HPHR_CNP_INT_SHIFT 0x06 +#define WCD939X_INTR_LEVEL_0_HPHR_OCP_INT_SHIFT 0x05 +#define WCD939X_INTR_LEVEL_0_MBHC_SW_INT_SHIFT 0x04 +#define WCD939X_INTR_LEVEL_0_MBHC_ELECT_INS_REM_LEG_INT_SHIFT 0x03 +#define WCD939X_INTR_LEVEL_0_MBHC_ELECT_INS_REM_INT_SHIFT 0x02 +#define WCD939X_INTR_LEVEL_0_MBHC_BTN_RELEASE_INT_SHIFT 0x01 +#define WCD939X_INTR_LEVEL_0_MBHC_BTN_PRESS_INT_SHIFT 0x00 + +/* WCD939X_INTR_LEVEL_1 Fields: */ +#define WCD939X_INTR_LEVEL_1_EAR_PDM_WD_INT_SHIFT 0x07 +#define WCD939X_INTR_LEVEL_1_HPHR_PDM_WD_INT_SHIFT 0x06 +#define WCD939X_INTR_LEVEL_1_HPHL_PDM_WD_INT_SHIFT 0x05 +#define WCD939X_INTR_LEVEL_1_EAR_SCD_INT_SHIFT 0x02 +#define WCD939X_INTR_LEVEL_1_EAR_CNP_INT_SHIFT 0x01 +#define WCD939X_INTR_LEVEL_1_HPHL_CNP_INT_SHIFT 0x00 + +/* WCD939X_INTR_LEVEL_2 Fields: */ +#define WCD939X_INTR_LEVEL_2_HPHL_SURGE_DET_INT_SHIFT 0x03 +#define WCD939X_INTR_LEVEL_2_HPHR_SURGE_DET_INT_SHIFT 0x02 +#define WCD939X_INTR_LEVEL_2_MBHC_MOISTRUE_INT_SHIFT 0x01 + +/* WCD939X_INTR_SET_0 Fields: */ +#define WCD939X_INTR_SET_0_HPHL_OCP_INT_SHIFT 0x07 +#define WCD939X_INTR_SET_0_HPHR_CNP_INT_SHIFT 0x06 +#define WCD939X_INTR_SET_0_HPHR_OCP_INT_SHIFT 0x05 +#define WCD939X_INTR_SET_0_MBHC_SW_INT_SHIFT 0x04 +#define WCD939X_INTR_SET_0_MBHC_ELECT_INS_REM_LEG_INT_SHIFT 0x03 +#define WCD939X_INTR_SET_0_MBHC_ELECT_INS_REM_INT_SHIFT 0x02 +#define WCD939X_INTR_SET_0_MBHC_BTN_RELEASE_INT_SHIFT 0x01 +#define WCD939X_INTR_SET_0_MBHC_BTN_PRESS_INT_SHIFT 0x00 + +/* WCD939X_INTR_SET_1 Fields: */ +#define WCD939X_INTR_SET_1_EAR_PDM_WD_INT_SHIFT 0x07 +#define WCD939X_INTR_SET_1_HPHR_PDM_WD_INT_SHIFT 0x06 +#define WCD939X_INTR_SET_1_HPHL_PDM_WD_INT_SHIFT 0x05 +#define WCD939X_INTR_SET_1_EAR_SCD_INT_SHIFT 0x02 +#define WCD939X_INTR_SET_1_EAR_CNP_INT_SHIFT 0x01 +#define WCD939X_INTR_SET_1_HPHL_CNP_INT_SHIFT 0x00 + +/* WCD939X_INTR_SET_2 Fields: */ +#define WCD939X_INTR_SET_2_HPHL_SURGE_DET_INT_SHIFT 0x03 +#define WCD939X_INTR_SET_2_HPHR_SURGE_DET_INT_SHIFT 0x02 +#define WCD939X_INTR_SET_2_MBHC_MOISTRUE_INT_SHIFT 0x01 + +/* WCD939X_INTR_TEST_0 Fields: */ +#define WCD939X_INTR_TEST_0_HPHL_OCP_INT_SHIFT 0x07 +#define WCD939X_INTR_TEST_0_HPHR_CNP_INT_SHIFT 0x06 +#define WCD939X_INTR_TEST_0_HPHR_OCP_INT_SHIFT 0x05 +#define WCD939X_INTR_TEST_0_MBHC_SW_INT_SHIFT 0x04 +#define WCD939X_INTR_TEST_0_MBHC_ELECT_INS_REM_LEG_INT_SHIFT 0x03 +#define WCD939X_INTR_TEST_0_MBHC_ELECT_INS_REM_INT_SHIFT 0x02 +#define WCD939X_INTR_TEST_0_MBHC_BTN_RELEASE_INT_SHIFT 0x01 +#define WCD939X_INTR_TEST_0_MBHC_BTN_PRESS_INT_SHIFT 0x00 + +/* WCD939X_INTR_TEST_1 Fields: */ +#define WCD939X_INTR_TEST_1_EAR_PDM_WD_INT_SHIFT 0x07 +#define WCD939X_INTR_TEST_1_HPHR_PDM_WD_INT_SHIFT 0x06 +#define WCD939X_INTR_TEST_1_HPHL_PDM_WD_INT_SHIFT 0x05 +#define WCD939X_INTR_TEST_1_EAR_SCD_INT_SHIFT 0x02 +#define WCD939X_INTR_TEST_1_EAR_CNP_INT_SHIFT 0x01 +#define WCD939X_INTR_TEST_1_HPHL_CNP_INT_SHIFT 0x00 + +/* WCD939X_INTR_TEST_2 Fields: */ +#define WCD939X_INTR_TEST_2_HPHL_SURGE_DET_INT_SHIFT 0x03 +#define WCD939X_INTR_TEST_2_HPHR_SURGE_DET_INT_SHIFT 0x02 +#define WCD939X_INTR_TEST_2_MBHC_MOISTRUE_INT_SHIFT 0x01 + +/* WCD939X_TX_MODE_DBG_EN Fields: */ +#define WCD939X_TX_MODE_DBG_EN_TXD3_MODE_DBG_EN_SHIFT 0x03 +#define WCD939X_TX_MODE_DBG_EN_TXD2_MODE_DBG_EN_SHIFT 0x02 +#define WCD939X_TX_MODE_DBG_EN_TXD1_MODE_DBG_EN_SHIFT 0x01 +#define WCD939X_TX_MODE_DBG_EN_TXD0_MODE_DBG_EN_SHIFT 0x00 + +/* WCD939X_TX_MODE_DBG_0_1 Fields: */ +#define WCD939X_TX_MODE_DBG_0_1_TXD1_MODE_DBG_SHIFT 0x04 +#define WCD939X_TX_MODE_DBG_0_1_TXD0_MODE_DBG_SHIFT 0x00 + +/* WCD939X_TX_MODE_DBG_2_3 Fields: */ +#define WCD939X_TX_MODE_DBG_2_3_TXD3_MODE_DBG_SHIFT 0x04 +#define WCD939X_TX_MODE_DBG_2_3_TXD2_MODE_DBG_SHIFT 0x00 + +/* WCD939X_LB_IN_SEL_CTL Fields: */ +#define WCD939X_LB_IN_SEL_CTL_EAR_LB_IN_SEL_SHIFT 0x02 +#define WCD939X_LB_IN_SEL_CTL_HPH_LB_IN_SEL_SHIFT 0x00 + +/* WCD939X_LOOP_BACK_MODE Fields: */ +#define WCD939X_LOOP_BACK_MODE_TX_DATA_EDGE_SHIFT 0x04 +#define WCD939X_LOOP_BACK_MODE_RX_DATA_EDGE_SHIFT 0x03 +#define WCD939X_LOOP_BACK_MODE_LOOPBACK_MODE_SHIFT 0x00 + +/* WCD939X_SWR_DAC_TEST Fields: */ +#define WCD939X_SWR_DAC_TEST_SWR_DAC_TEST_SHIFT 0x00 + +/* WCD939X_SWR_HM_TEST_RX_0 Fields: */ +#define WCD939X_SWR_HM_TEST_RX_0_ALT_MODE_SHIFT 0x07 +#define WCD939X_SWR_HM_TEST_RX_0_IO_MODE_SHIFT 0x06 +#define WCD939X_SWR_HM_TEST_RX_0_LN2_T_DATA_OE_SHIFT 0x05 +#define WCD939X_SWR_HM_TEST_RX_0_LN2_T_DATA_OUT_SHIFT 0x04 +#define WCD939X_SWR_HM_TEST_RX_0_LN2_T_KEEPER_EN_SHIFT 0x03 +#define WCD939X_SWR_HM_TEST_RX_0_LN1_T_DATA_OE_SHIFT 0x02 +#define WCD939X_SWR_HM_TEST_RX_0_LN1_T_DATA_OUT_SHIFT 0x01 +#define WCD939X_SWR_HM_TEST_RX_0_LN1_T_KEEPER_EN_SHIFT 0x00 + +/* WCD939X_SWR_HM_TEST_TX_0 Fields: */ +#define WCD939X_SWR_HM_TEST_TX_0_ALT_MODE_SHIFT 0x07 +#define WCD939X_SWR_HM_TEST_TX_0_IO_MODE_SHIFT 0x06 +#define WCD939X_SWR_HM_TEST_TX_0_LN2_T_DATA_OE_SHIFT 0x05 +#define WCD939X_SWR_HM_TEST_TX_0_LN2_T_DATA_OUT_SHIFT 0x04 +#define WCD939X_SWR_HM_TEST_TX_0_LN2_T_KEEPER_EN_SHIFT 0x03 +#define WCD939X_SWR_HM_TEST_TX_0_LN1_T_DATA_OE_SHIFT 0x02 +#define WCD939X_SWR_HM_TEST_TX_0_LN1_T_DATA_OUT_SHIFT 0x01 +#define WCD939X_SWR_HM_TEST_TX_0_LN1_T_KEEPER_EN_SHIFT 0x00 + +/* WCD939X_SWR_HM_TEST_RX_1 Fields: */ +#define WCD939X_SWR_HM_TEST_RX_1_DTEST_SEL_SHIFT 0x02 +#define WCD939X_SWR_HM_TEST_RX_1_LN2_DLY_CELL_TEST_EN_SHIFT 0x01 +#define WCD939X_SWR_HM_TEST_RX_1_LN1_DLY_CELL_TEST_EN_SHIFT 0x00 + +/* WCD939X_SWR_HM_TEST_TX_1 Fields: */ +#define WCD939X_SWR_HM_TEST_TX_1_DTEST_SEL_SHIFT 0x03 +#define WCD939X_SWR_HM_TEST_TX_1_LN3_DLY_CELL_TEST_EN_SHIFT 0x02 +#define WCD939X_SWR_HM_TEST_TX_1_LN2_DLY_CELL_TEST_EN_SHIFT 0x01 +#define WCD939X_SWR_HM_TEST_TX_1_LN1_DLY_CELL_TEST_EN_SHIFT 0x00 + +/* WCD939X_SWR_HM_TEST_TX_2 Fields: */ +#define WCD939X_SWR_HM_TEST_TX_2_LN3_T_DATA_OE_SHIFT 0x02 +#define WCD939X_SWR_HM_TEST_TX_2_LN3_T_DATA_OUT_SHIFT 0x01 +#define WCD939X_SWR_HM_TEST_TX_2_LN3_T_KEEPER_EN_SHIFT 0x00 + +/* WCD939X_SWR_HM_TEST_0 Fields: */ +#define WCD939X_SWR_HM_TEST_0_TX_LN2_T_DATA_IN_SHIFT 0x07 +#define WCD939X_SWR_HM_TEST_0_TX_LN2_T_CLK_IN_SHIFT 0x06 +#define WCD939X_SWR_HM_TEST_0_TX_LN1_T_DATA_IN_SHIFT 0x05 +#define WCD939X_SWR_HM_TEST_0_TX_LN1_T_CLK_IN_SHIFT 0x04 +#define WCD939X_SWR_HM_TEST_0_RX_LN2_T_DATA_IN_SHIFT 0x03 +#define WCD939X_SWR_HM_TEST_0_RX_LN2_T_CLK_IN_SHIFT 0x02 +#define WCD939X_SWR_HM_TEST_0_RX_LN1_T_DATA_IN_SHIFT 0x01 +#define WCD939X_SWR_HM_TEST_0_RX_LN1_T_CLK_IN_SHIFT 0x00 + +/* WCD939X_SWR_HM_TEST_1 Fields: */ +#define WCD939X_SWR_HM_TEST_1_TX_LN3_T_DATA_IN_SHIFT 0x01 +#define WCD939X_SWR_HM_TEST_1_TX_LN3_T_CLK_IN_SHIFT 0x00 + +/* WCD939X_PAD_CTL_SWR_0 Fields: */ +#define WCD939X_PAD_CTL_SWR_0_SWR_SLEW_PRG_SHIFT 0x04 +#define WCD939X_PAD_CTL_SWR_0_SWR_DRIVE_PRG_SHIFT 0x00 + +/* WCD939X_PAD_CTL_SWR_1 Fields: */ +#define WCD939X_PAD_CTL_SWR_1_SWR_TDZ_PRG_SHIFT 0x00 + +/* WCD939X_I2C_CTL Fields: */ +#define WCD939X_I2C_CTL_ACTIVE_MODE_SHIFT 0x00 + +/* WCD939X_CDC_TX_TANGGU_SW_MODE Fields: */ +#define WCD939X_CDC_TX_TANGGU_SW_MODE_LEGACY_SW_MODE_SHIFT 0x00 + +/* WCD939X_EFUSE_TEST_CTL_0 Fields: */ +#define WCD939X_EFUSE_TEST_CTL_0_EFUSE_TEST_CTL_LSB_SHIFT 0x00 + +/* WCD939X_EFUSE_TEST_CTL_1 Fields: */ +#define WCD939X_EFUSE_TEST_CTL_1_EFUSE_TEST_CTL_MSB_SHIFT 0x00 + +/* WCD939X_EFUSE_T_DATA_0 Fields: */ +#define WCD939X_EFUSE_T_DATA_0_EFUSE_DATA_SHIFT 0x00 + +/* WCD939X_EFUSE_T_DATA_1 Fields: */ +#define WCD939X_EFUSE_T_DATA_1_EFUSE_DATA_SHIFT 0x00 + +/* WCD939X_PAD_CTL_PDM_RX0 Fields: */ +#define WCD939X_PAD_CTL_PDM_RX0_PDM_SLEW_PRG_SHIFT 0x04 +#define WCD939X_PAD_CTL_PDM_RX0_PDM_DRIVE_PRG_SHIFT 0x00 + +/* WCD939X_PAD_CTL_PDM_RX1 Fields: */ +#define WCD939X_PAD_CTL_PDM_RX1_PDM_SLEW_PRG_SHIFT 0x04 +#define WCD939X_PAD_CTL_PDM_RX1_PDM_DRIVE_PRG_SHIFT 0x00 + +/* WCD939X_PAD_CTL_PDM_TX0 Fields: */ +#define WCD939X_PAD_CTL_PDM_TX0_PDM_SLEW_PRG_SHIFT 0x04 +#define WCD939X_PAD_CTL_PDM_TX0_PDM_DRIVE_PRG_SHIFT 0x00 + +/* WCD939X_PAD_CTL_PDM_TX1 Fields: */ +#define WCD939X_PAD_CTL_PDM_TX1_PDM_SLEW_PRG_SHIFT 0x04 +#define WCD939X_PAD_CTL_PDM_TX1_PDM_DRIVE_PRG_SHIFT 0x00 + +/* WCD939X_PAD_CTL_PDM_TX2 Fields: */ +#define WCD939X_PAD_CTL_PDM_TX2_PDM_SLEW_PRG_SHIFT 0x04 +#define WCD939X_PAD_CTL_PDM_TX2_PDM_DRIVE_PRG_SHIFT 0x00 + +/* WCD939X_PAD_INP_DIS_0 Fields: */ +#define WCD939X_PAD_INP_DIS_0_DMIC3_CLK_SHIFT 0x05 +#define WCD939X_PAD_INP_DIS_0_DMIC3_DATA_SHIFT 0x04 +#define WCD939X_PAD_INP_DIS_0_DMIC2_CLK_SHIFT 0x03 +#define WCD939X_PAD_INP_DIS_0_DMIC2_DATA_SHIFT 0x02 +#define WCD939X_PAD_INP_DIS_0_DMIC1_CLK_SHIFT 0x01 +#define WCD939X_PAD_INP_DIS_0_DMIC1_DATA_SHIFT 0x00 + +/* WCD939X_PAD_INP_DIS_1 Fields: */ +#define WCD939X_PAD_INP_DIS_1_DMIC4_CLK_SHIFT 0x04 +#define WCD939X_PAD_INP_DIS_1_DMIC4_DATA_SHIFT 0x03 + +/* WCD939X_DRIVE_STRENGTH_0 Fields: */ +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC2_CLK_SHIFT 0x06 +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC2_DATA_SHIFT 0x04 +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC1_CLK_SHIFT 0x02 +#define WCD939X_DRIVE_STRENGTH_0_DS_DMIC1_DATA_SHIFT 0x00 + +/* WCD939X_DRIVE_STRENGTH_1 Fields: */ +#define WCD939X_DRIVE_STRENGTH_1_DS_DMIC3_CLK_SHIFT 0x02 +#define WCD939X_DRIVE_STRENGTH_1_DS_DMIC3_DATA_SHIFT 0x00 + +/* WCD939X_DRIVE_STRENGTH_2 Fields: */ +#define WCD939X_DRIVE_STRENGTH_2_DS_DMIC4_CLK_SHIFT 0x06 +#define WCD939X_DRIVE_STRENGTH_2_DS_DMIC4_DATA_SHIFT 0x04 + +/* WCD939X_RX_DATA_EDGE_CTL Fields: */ +#define WCD939X_RX_DATA_EDGE_CTL_HPH_CLH_EDGE_SHIFT 0x05 +#define WCD939X_RX_DATA_EDGE_CTL_EAR_DOUT_EDGE_SHIFT 0x04 +#define WCD939X_RX_DATA_EDGE_CTL_HPHR_DOUT_EDGE_SHIFT 0x03 +#define WCD939X_RX_DATA_EDGE_CTL_HPHL_DOUT_EDGE_SHIFT 0x02 +#define WCD939X_RX_DATA_EDGE_CTL_HPHR_GAIN_EDGE_SHIFT 0x01 +#define WCD939X_RX_DATA_EDGE_CTL_HPHL_GAIN_EDGE_SHIFT 0x00 + +/* WCD939X_TX_DATA_EDGE_CTL Fields: */ +#define WCD939X_TX_DATA_EDGE_CTL_TX_WE_DLY_SHIFT 0x06 +#define WCD939X_TX_DATA_EDGE_CTL_TX3_DIN_EDGE_SHIFT 0x03 +#define WCD939X_TX_DATA_EDGE_CTL_TX2_DIN_EDGE_SHIFT 0x02 +#define WCD939X_TX_DATA_EDGE_CTL_TX1_DIN_EDGE_SHIFT 0x01 +#define WCD939X_TX_DATA_EDGE_CTL_TX0_DIN_EDGE_SHIFT 0x00 + +/* WCD939X_GPIO_MODE Fields: */ +#define WCD939X_GPIO_MODE_GPIO_3_EN_SHIFT 0x02 +#define WCD939X_GPIO_MODE_GPIO_2_EN_SHIFT 0x01 +#define WCD939X_GPIO_MODE_TEST_MODE_SHIFT 0x00 + +/* WCD939X_PIN_CTL_OE Fields: */ +#define WCD939X_PIN_CTL_OE_TEST_PIN_CTL_OE_SHIFT 0x04 +#define WCD939X_PIN_CTL_OE_GPIO_3_PIN_CTL_OE_SHIFT 0x03 +#define WCD939X_PIN_CTL_OE_GPIO_2_PIN_CTL_OE_SHIFT 0x02 + +/* WCD939X_PIN_CTL_DATA_0 Fields: */ +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC3_CLK_SHIFT 0x05 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC3_DATA_SHIFT 0x04 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC2_CLK_SHIFT 0x03 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC2_DATA_SHIFT 0x02 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC1_CLK_SHIFT 0x01 +#define WCD939X_PIN_CTL_DATA_0_PAD_DMIC1_DATA_SHIFT 0x00 + +/* WCD939X_PIN_CTL_DATA_1 Fields: */ +#define WCD939X_PIN_CTL_DATA_1_PAD_DMIC4_CLK_SHIFT 0x03 +#define WCD939X_PIN_CTL_DATA_1_PAD_DMIC4_DATA_SHIFT 0x02 + +/* WCD939X_PIN_STATUS_0 Fields: */ +#define WCD939X_PIN_STATUS_0_PAD_DMIC3_CLK_SHIFT 0x05 +#define WCD939X_PIN_STATUS_0_PAD_DMIC3_DATA_SHIFT 0x04 +#define WCD939X_PIN_STATUS_0_PAD_DMIC2_CLK_SHIFT 0x03 +#define WCD939X_PIN_STATUS_0_PAD_DMIC2_DATA_SHIFT 0x02 +#define WCD939X_PIN_STATUS_0_PAD_DMIC1_CLK_SHIFT 0x01 +#define WCD939X_PIN_STATUS_0_PAD_DMIC1_DATA_SHIFT 0x00 + +/* WCD939X_PIN_STATUS_1 Fields: */ +#define WCD939X_PIN_STATUS_1_PAD_DMIC4_CLK_SHIFT 0x03 +#define WCD939X_PIN_STATUS_1_PAD_DMIC4_DATA_SHIFT 0x02 + +/* WCD939X_DIG_DEBUG_CTL Fields: */ +#define WCD939X_DIG_DEBUG_CTL_DIG_DEBUG_CTL_SHIFT 0x00 + +/* WCD939X_DIG_DEBUG_EN Fields: */ +#define WCD939X_DIG_DEBUG_EN_TX_DBG_MODE_SHIFT 0x02 +#define WCD939X_DIG_DEBUG_EN_RX_DBG_MODE_1_SHIFT 0x01 +#define WCD939X_DIG_DEBUG_EN_RX_DBG_MODE_0_SHIFT 0x00 + +/* WCD939X_ANA_CSR_DBG_ADD Fields: */ +#define WCD939X_ANA_CSR_DBG_ADD_ADD_SHIFT 0x00 + +/* WCD939X_ANA_CSR_DBG_CTL Fields: */ +#define WCD939X_ANA_CSR_DBG_CTL_WR_VALUE_SHIFT 0x06 +#define WCD939X_ANA_CSR_DBG_CTL_RD_VALUE_SHIFT 0x03 +#define WCD939X_ANA_CSR_DBG_CTL_DBG_PAGE_SEL_SHIFT 0x01 +#define WCD939X_ANA_CSR_DBG_CTL_DBG_EN_SHIFT 0x00 + +/* WCD939X_SSP_DBG Fields: */ +#define WCD939X_SSP_DBG_RX_SSP_DBG_SHIFT 0x01 +#define WCD939X_SSP_DBG_TX_SSP_DBG_SHIFT 0x00 + +/* WCD939X_MODE_STATUS_0 Fields: */ +#define WCD939X_MODE_STATUS_0_ATE_7_SHIFT 0x07 +#define WCD939X_MODE_STATUS_0_ATE_6_SHIFT 0x06 +#define WCD939X_MODE_STATUS_0_ATE_5_SHIFT 0x05 +#define WCD939X_MODE_STATUS_0_ATE_4_SHIFT 0x04 +#define WCD939X_MODE_STATUS_0_ATE_3_SHIFT 0x03 +#define WCD939X_MODE_STATUS_0_ATE_2_SHIFT 0x02 +#define WCD939X_MODE_STATUS_0_ATE_1_SHIFT 0x01 +#define WCD939X_MODE_STATUS_0_SWR_TEST_SHIFT 0x00 + +/* WCD939X_MODE_STATUS_1 Fields: */ +#define WCD939X_MODE_STATUS_1_SWR_PAD_TEST_SHIFT 0x01 +#define WCD939X_MODE_STATUS_1_EFUSE_MODE_SHIFT 0x00 + +/* WCD939X_SPARE_0 Fields: */ +#define WCD939X_SPARE_0_SPARE_REG_0_SHIFT 0x00 + +/* WCD939X_SPARE_1 Fields: */ +#define WCD939X_SPARE_1_SPARE_REG_1_SHIFT 0x00 + +/* WCD939X_SPARE_2 Fields: */ +#define WCD939X_SPARE_2_SPARE_REG_2_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_0 Fields: */ +#define WCD939X_EFUSE_REG_0_SPARE_BITS_SHIFT 0x05 +#define WCD939X_EFUSE_REG_0_WCD939X_ID_SHIFT 0x01 +#define WCD939X_EFUSE_REG_0_EFUSE_BLOWN_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_1 Fields: */ +#define WCD939X_EFUSE_REG_1_LOT_ID_0_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_2 Fields: */ +#define WCD939X_EFUSE_REG_2_LOT_ID_1_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_3 Fields: */ +#define WCD939X_EFUSE_REG_3_LOT_ID_2_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_4 Fields: */ +#define WCD939X_EFUSE_REG_4_LOT_ID_3_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_5 Fields: */ +#define WCD939X_EFUSE_REG_5_LOT_ID_4_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_6 Fields: */ +#define WCD939X_EFUSE_REG_6_LOT_ID_5_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_7 Fields: */ +#define WCD939X_EFUSE_REG_7_LOT_ID_6_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_8 Fields: */ +#define WCD939X_EFUSE_REG_8_LOT_ID_7_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_9 Fields: */ +#define WCD939X_EFUSE_REG_9_LOT_ID_8_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_10 Fields: */ +#define WCD939X_EFUSE_REG_10_LOT_ID_9_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_11 Fields: */ +#define WCD939X_EFUSE_REG_11_LOT_ID_10_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_12 Fields: */ +#define WCD939X_EFUSE_REG_12_LOT_ID_11_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_13 Fields: */ +#define WCD939X_EFUSE_REG_13_WAFER_ID_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_14 Fields: */ +#define WCD939X_EFUSE_REG_14_X_DIE_LOCATION_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_15 Fields: */ +#define WCD939X_EFUSE_REG_15_Y_DIE_LOCATION_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_16 Fields: */ +#define WCD939X_EFUSE_REG_16_FAB_ID_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_17 Fields: */ +#define WCD939X_EFUSE_REG_17_TEST_PROGRAM_REV_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_18 Fields: */ +#define WCD939X_EFUSE_REG_18_DIE_REVISION_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_19 Fields: */ +#define WCD939X_EFUSE_REG_19_MFG_ID_SPARE_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_20 Fields: */ +#define WCD939X_EFUSE_REG_20_I2C_SLV_ID_BLOWN_SHIFT 0x07 +#define WCD939X_EFUSE_REG_20_I2C_SLAVE_ID_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_21 Fields: */ +#define WCD939X_EFUSE_REG_21_MBHC_IMP_DET_0_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_22 Fields: */ +#define WCD939X_EFUSE_REG_22_MBHC_IMP_DET_1_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_23 Fields: */ +#define WCD939X_EFUSE_REG_23_SWR_PAD_DRIVE_PRG_1P2V_SHIFT 0x04 +#define WCD939X_EFUSE_REG_23_SWR_SLEW_PRG_1P2V_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_24 Fields: */ +#define WCD939X_EFUSE_REG_24_SPARE_BITS_SHIFT 0x05 +#define WCD939X_EFUSE_REG_24_SWR_PAD_BLOWN_SHIFT 0x04 +#define WCD939X_EFUSE_REG_24_SWR_TDZ_DELAY_PRG_1P2V_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_25 Fields: */ +#define WCD939X_EFUSE_REG_25_MBHC_IMP_DET_2_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_26 Fields: */ +#define WCD939X_EFUSE_REG_26_MBHC_IMP_DET_3_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_27 Fields: */ +#define WCD939X_EFUSE_REG_27_HPH_DSD_DIS_SHIFT 0x07 +#define WCD939X_EFUSE_REG_27_BG_TUNE_BLOWN_SHIFT 0x06 +#define WCD939X_EFUSE_REG_27_BG_TUNE_SHIFT 0x04 +#define WCD939X_EFUSE_REG_27_EFUSE_HPH_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_28 Fields: */ +#define WCD939X_EFUSE_REG_28_HPH_CLH_DIS_SHIFT 0x07 +#define WCD939X_EFUSE_REG_28_HPH_LOHIFI_DIS_SHIFT 0x06 +#define WCD939X_EFUSE_REG_28_HPH_HIFI_DIS_SHIFT 0x05 +#define WCD939X_EFUSE_REG_28_EAR_CLH_DIS_SHIFT 0x04 +#define WCD939X_EFUSE_REG_28_DMIC_DIS_SHIFT 0x03 +#define WCD939X_EFUSE_REG_28_TX_LP_DIS_SHIFT 0x02 +#define WCD939X_EFUSE_REG_28_TX_HP_DIS_SHIFT 0x01 +#define WCD939X_EFUSE_REG_28_SPARE_BITS_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_29 Fields: */ +#define WCD939X_EFUSE_REG_29_TX_ULP1_DIS_SHIFT 0x07 +#define WCD939X_EFUSE_REG_29_TX_ULP2_DIS_SHIFT 0x06 +#define WCD939X_EFUSE_REG_29_SPARE_BITS_SHIFT 0x04 +#define WCD939X_EFUSE_REG_29_SWR_PAD_DRIVE_PRG_1P8V_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_30 Fields: */ +#define WCD939X_EFUSE_REG_30_SWR_SLEW_PRG_1P8V_SHIFT 0x04 +#define WCD939X_EFUSE_REG_30_SWR_TDZ_DELAY_PRG_1P8V_SHIFT 0x00 + +/* WCD939X_EFUSE_REG_31 Fields: */ +#define WCD939X_EFUSE_REG_31_SPARE_EFUSE_ANA_SHIFT 0x00 + +/* WCD939X_TX_REQ_FB_CTL_0 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_0_ULP2_FB_T2_SHIFT 0x04 +#define WCD939X_TX_REQ_FB_CTL_0_ULP2_FB_T1_SHIFT 0x00 + +/* WCD939X_TX_REQ_FB_CTL_1 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_1_ULP1_FB_T2_SHIFT 0x04 +#define WCD939X_TX_REQ_FB_CTL_1_ULP1_FB_T1_SHIFT 0x00 + +/* WCD939X_TX_REQ_FB_CTL_2 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_2_L0_FB_T2_SHIFT 0x04 +#define WCD939X_TX_REQ_FB_CTL_2_L0_FB_T1_SHIFT 0x00 + +/* WCD939X_TX_REQ_FB_CTL_3 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_3_L1_FB_T2_SHIFT 0x04 +#define WCD939X_TX_REQ_FB_CTL_3_L1_FB_T1_SHIFT 0x00 + +/* WCD939X_TX_REQ_FB_CTL_4 Fields: */ +#define WCD939X_TX_REQ_FB_CTL_4_L2_FB_T2_SHIFT 0x04 +#define WCD939X_TX_REQ_FB_CTL_4_L2_FB_T1_SHIFT 0x00 + +/* WCD939X_DEM_BYPASS_DATA0 Fields: */ +#define WCD939X_DEM_BYPASS_DATA0_DEM_BYPASS_DATA0_SHIFT 0x00 + +/* WCD939X_DEM_BYPASS_DATA1 Fields: */ +#define WCD939X_DEM_BYPASS_DATA1_DEM_BYPASS_DATA1_SHIFT 0x00 + +/* WCD939X_DEM_BYPASS_DATA2 Fields: */ +#define WCD939X_DEM_BYPASS_DATA2_DEM_BYPASS_DATA2_SHIFT 0x00 + +/* WCD939X_DEM_BYPASS_DATA3 Fields: */ +#define WCD939X_DEM_BYPASS_DATA3_DEM_BYPASS_DATA3_SHIFT 0x00 + +/* WCD939X_DEM_SECOND_ORDER Fields: */ +#define WCD939X_DEM_SECOND_ORDER_DEM_1_2ND_ORDER_EN_SHIFT 0x01 +#define WCD939X_DEM_SECOND_ORDER_DEM_0_2ND_ORDER_EN_SHIFT 0x00 + +/* WCD939X_DSM_CTRL Fields: */ +#define WCD939X_DSM_CTRL_DSM_1_STATIC_EN_SHIFT 0x01 +#define WCD939X_DSM_CTRL_DSM_0_STATIC_EN_SHIFT 0x00 + +/* WCD939X_DSM_0_STATIC_DATA_0 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_0_DSM_0_STATIC_DATA0_SHIFT 0x00 + +/* WCD939X_DSM_0_STATIC_DATA_1 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_1_DSM_0_STATIC_DATA1_SHIFT 0x00 + +/* WCD939X_DSM_0_STATIC_DATA_2 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_2_DSM_0_STATIC_DATA2_SHIFT 0x00 + +/* WCD939X_DSM_0_STATIC_DATA_3 Fields: */ +#define WCD939X_DSM_0_STATIC_DATA_3_DSM_0_STATIC_DATA3_SHIFT 0x00 + +/* WCD939X_DSM_1_STATIC_DATA_0 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_0_DSM_1_STATIC_DATA0_SHIFT 0x00 + +/* WCD939X_DSM_1_STATIC_DATA_1 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_1_DSM_1_STATIC_DATA1_SHIFT 0x00 + +/* WCD939X_DSM_1_STATIC_DATA_2 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_2_DSM_1_STATIC_DATA2_SHIFT 0x00 + +/* WCD939X_DSM_1_STATIC_DATA_3 Fields: */ +#define WCD939X_DSM_1_STATIC_DATA_3_DSM_1_STATIC_DATA3_SHIFT 0x00 + + +/* WCD939X_RX_PAGE Fields: */ +#define WCD939X_RX_PAGE_PAG_REG_SHIFT 0x00 + +/* WCD939X_TOP_CFG0 Fields: */ +#define WCD939X_TOP_CFG0_HPH_DAC_RATE_SEL_SHIFT 0x01 +#define WCD939X_TOP_CFG0_PGA_UPDATE_SHIFT 0x00 + +/* WCD939X_HPHL_COMP_WR_LSB Fields: */ +#define WCD939X_HPHL_COMP_WR_LSB_COEFF_SHIFT 0x00 + +/* WCD939X_HPHL_COMP_WR_MSB Fields: */ +#define WCD939X_HPHL_COMP_WR_MSB_COEFF_SHIFT 0x00 + +/* WCD939X_HPHL_COMP_LUT Fields: */ +#define WCD939X_HPHL_COMP_LUT_BYPASS_SHIFT 0x07 +#define WCD939X_HPHL_COMP_LUT_MANUAL_RD_SHIFT 0x06 +#define WCD939X_HPHL_COMP_LUT_MANUAL_WR_SHIFT 0x05 +#define WCD939X_HPHL_COMP_LUT_ADDR_SHIFT 0x00 + +/* WCD939X_HPHL_COMP_RD_LSB Fields: */ +#define WCD939X_HPHL_COMP_RD_LSB_COEFF_SHIFT 0x00 + +/* WCD939X_HPHL_COMP_RD_MSB Fields: */ +#define WCD939X_HPHL_COMP_RD_MSB_COEFF_SHIFT 0x00 + +/* WCD939X_HPHR_COMP_WR_LSB Fields: */ +#define WCD939X_HPHR_COMP_WR_LSB_COEFF_SHIFT 0x00 + +/* WCD939X_HPHR_COMP_WR_MSB Fields: */ +#define WCD939X_HPHR_COMP_WR_MSB_COEFF_SHIFT 0x00 + +/* WCD939X_HPHR_COMP_LUT Fields: */ +#define WCD939X_HPHR_COMP_LUT_BYPASS_SHIFT 0x07 +#define WCD939X_HPHR_COMP_LUT_MANUAL_RD_SHIFT 0x06 +#define WCD939X_HPHR_COMP_LUT_MANUAL_WR_SHIFT 0x05 +#define WCD939X_HPHR_COMP_LUT_ADDR_SHIFT 0x00 + +/* WCD939X_HPHR_COMP_RD_LSB Fields: */ +#define WCD939X_HPHR_COMP_RD_LSB_COEFF_SHIFT 0x00 + +/* WCD939X_HPHR_COMP_RD_MSB Fields: */ +#define WCD939X_HPHR_COMP_RD_MSB_COEFF_SHIFT 0x00 + +/* WCD939X_DSD0_DEBUG_CFG1 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG1_DSD_UNPACKING_ORDER_SHIFT 0x03 +#define WCD939X_DSD0_DEBUG_CFG1_DSD_DC_DET_EN_SHIFT 0x02 +#define WCD939X_DSD0_DEBUG_CFG1_DSD_MUTE_DET_EN_SHIFT 0x00 + +/* WCD939X_DSD0_DEBUG_CFG2 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG2_MUTE_INI_VAL_SHIFT 0x04 +#define WCD939X_DSD0_DEBUG_CFG2_DC_INTR_THRESHOLD_SHIFT 0x02 +#define WCD939X_DSD0_DEBUG_CFG2_DC_DET_THRESHOLD_SHIFT 0x00 + +/* WCD939X_DSD0_DEBUG_CFG3 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG3_DSD_POST_GAIN_SHIFT 0x03 +#define WCD939X_DSD0_DEBUG_CFG3_DSD_GAIN_ADJ_SHIFT 0x00 + +/* WCD939X_DSD0_DEBUG_CFG4 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG4_DSD_INPUT_ZOH_SHIFT 0x00 + +/* WCD939X_DSD0_DEBUG_CFG5 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG5_DSD_DC_DET_SHIFT 0x07 +#define WCD939X_DSD0_DEBUG_CFG5_DSD_PGA_GAIN_UPD_STATUS_SHIFT 0x06 +#define WCD939X_DSD0_DEBUG_CFG5_DSD_DC_SAMPLE_NUM_MSB_SHIFT 0x00 + +/* WCD939X_DSD0_DEBUG_CFG6 Fields: */ +#define WCD939X_DSD0_DEBUG_CFG6_DSD_DC_SAMPLE_NUM_LSB_SHIFT 0x00 + +/* WCD939X_DSD1_DEBUG_CFG1 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG1_DSD_UNPACKING_ORDER_SHIFT 0x02 +#define WCD939X_DSD1_DEBUG_CFG1_DSD_DC_DET_EN_SHIFT 0x01 +#define WCD939X_DSD1_DEBUG_CFG1_DSD_MUTE_DET_EN_SHIFT 0x00 + +/* WCD939X_DSD1_DEBUG_CFG2 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG2_MUTE_INI_VAL_SHIFT 0x04 +#define WCD939X_DSD1_DEBUG_CFG2_DC_INTR_THRESHOLD_SHIFT 0x02 +#define WCD939X_DSD1_DEBUG_CFG2_DC_DET_THRESHOLD_SHIFT 0x00 + +/* WCD939X_DSD1_DEBUG_CFG3 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG3_DSD_POST_GAIN_SHIFT 0x03 +#define WCD939X_DSD1_DEBUG_CFG3_DSD_GAIN_ADJ_SHIFT 0x00 + +/* WCD939X_DSD1_DEBUG_CFG4 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG4_DSD_INPUT_ZOH_SHIFT 0x00 + +/* WCD939X_DSD1_DEBUG_CFG5 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG5_DSD_DC_DET_SHIFT 0x07 +#define WCD939X_DSD1_DEBUG_CFG5_DSD_PGA_GAIN_UPD_STATUS_SHIFT 0x06 +#define WCD939X_DSD1_DEBUG_CFG5_DSD_DC_SAMPLE_NUM_MSB_SHIFT 0x00 + +/* WCD939X_DSD1_DEBUG_CFG6 Fields: */ +#define WCD939X_DSD1_DEBUG_CFG6_DSD_DC_SAMPLE_NUM_LSB_SHIFT 0x00 + +/* WCD939X_HPHL_RX_PATH_CFG0 Fields: */ +#define WCD939X_HPHL_RX_PATH_CFG0_INT_EN_SHIFT 0x01 +#define WCD939X_HPHL_RX_PATH_CFG0_DLY_ZN_EN_SHIFT 0x00 + +/* WCD939X_HPHL_RX_PATH_CFG1 Fields: */ +#define WCD939X_HPHL_RX_PATH_CFG1_DSM_SOFT_RST_SHIFT 0x05 +#define WCD939X_HPHL_RX_PATH_CFG1_INT_SOFT_RST_SHIFT 0x04 +#define WCD939X_HPHL_RX_PATH_CFG1_FMT_CONV_SHIFT 0x03 +#define WCD939X_HPHL_RX_PATH_CFG1_IDLE_OVRD_EN_SHIFT 0x02 +#define WCD939X_HPHL_RX_PATH_CFG1_RX_DC_DROOP_COEFF_SEL_SHIFT 0x00 + +/* WCD939X_HPHR_RX_PATH_CFG0 Fields: */ +#define WCD939X_HPHR_RX_PATH_CFG0_INT_EN_SHIFT 0x02 +#define WCD939X_HPHR_RX_PATH_CFG0_DLY_ZN_EN_SHIFT 0x01 + +/* WCD939X_HPHR_RX_PATH_CFG1 Fields: */ +#define WCD939X_HPHR_RX_PATH_CFG1_DSM_SOFT_RST_SHIFT 0x05 +#define WCD939X_HPHR_RX_PATH_CFG1_INT_SOFT_RST_SHIFT 0x04 +#define WCD939X_HPHR_RX_PATH_CFG1_FMT_CONV_SHIFT 0x03 +#define WCD939X_HPHR_RX_PATH_CFG1_IDLE_OVRD_EN_SHIFT 0x02 +#define WCD939X_HPHR_RX_PATH_CFG1_RX_DC_DROOP_COEFF_SEL_SHIFT 0x00 + +/* WCD939X_RX_PATH_CFG2 Fields: */ +#define WCD939X_RX_PATH_CFG2_COMP_XTALK_EN_SHIFT 0x03 +#define WCD939X_RX_PATH_CFG2_XTALK_NLIN_EN_SHIFT 0x02 +#define WCD939X_RX_PATH_CFG2_XTALK_LIN_EN_SHIFT 0x01 +#define WCD939X_RX_PATH_CFG2_XTALK_EN_SHIFT 0x00 + +/* WCD939X_HPHL_RX_PATH_SEC0 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC0_LIN_XTALK_POLARITY_SHIFT 0x05 +#define WCD939X_HPHL_RX_PATH_SEC0_LIN_XTALK_SCALE_SHIFT 0x00 + +/* WCD939X_HPHL_RX_PATH_SEC1 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC1_LIN_XTALK_ALPHA_SHIFT 0x00 + +/* WCD939X_HPHL_RX_PATH_SEC2 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC2_NLIN_XTALK_POLARITY_SHIFT 0x06 +#define WCD939X_HPHL_RX_PATH_SEC2_NLIN_XTALK_BYPASS_SHIFT 0x05 +#define WCD939X_HPHL_RX_PATH_SEC2_NLIN_XTALK_SCALE_SHIFT 0x00 + +/* WCD939X_HPHL_RX_PATH_SEC3 Fields: */ +#define WCD939X_HPHL_RX_PATH_SEC3_NLIN_XTALK_ALPHA_SHIFT 0x00 + +/* WCD939X_HPHR_RX_PATH_SEC0 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC0_LIN_XTALK_POLARITY_SHIFT 0x05 +#define WCD939X_HPHR_RX_PATH_SEC0_LIN_XTALK_SCALE_SHIFT 0x00 + +/* WCD939X_HPHR_RX_PATH_SEC1 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC1_LIN_XTALK_ALPHA_SHIFT 0x00 + +/* WCD939X_HPHR_RX_PATH_SEC2 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC2_NLIN_XTALK_POLARITY_SHIFT 0x06 +#define WCD939X_HPHR_RX_PATH_SEC2_NLIN_XTALK_BYPASS_SHIFT 0x05 +#define WCD939X_HPHR_RX_PATH_SEC2_NLIN_XTALK_SCALE_SHIFT 0x00 + +/* WCD939X_HPHR_RX_PATH_SEC3 Fields: */ +#define WCD939X_HPHR_RX_PATH_SEC3_NLIN_XTALK_ALPHA_SHIFT 0x00 + +/* WCD939X_RX_PATH_SEC4 Fields: */ +#define WCD939X_RX_PATH_SEC4_NLIN_CMB_POLARITY_SHIFT 0x05 +#define WCD939X_RX_PATH_SEC4_NLIN_CMB_SCALE_SHIFT 0x00 + +/* WCD939X_RX_PATH_SEC5 Fields: */ +#define WCD939X_RX_PATH_SEC5_NLIN_CMB_ALPHA_SHIFT 0x00 + + +/* WCD939X_CTL0 Fields: */ +#define WCD939X_CTL0_SHUTDWN_TOUT_SHIFT 0x04 +#define WCD939X_CTL0_DROPOUT_EN_SHIFT 0x03 +#define WCD939X_CTL0_COMP_HALT_SHIFT 0x02 +#define WCD939X_CTL0_SOFT_RST_SHIFT 0x01 +#define WCD939X_CTL0_CLK_EN_SHIFT 0x00 + +/* WCD939X_CTL1 Fields: */ +#define WCD939X_CTL1_LEVEL_METER_DIV_FACTOR_SHIFT 0x04 +#define WCD939X_CTL1_PEAK_METER_TOUT_SHIFT 0x00 + +/* WCD939X_CTL2 Fields: */ +#define WCD939X_CTL2_LEVEL_METER_RESAMPLE_RATE_SHIFT 0x00 + +/* WCD939X_CTL3 Fields: */ +#define WCD939X_CTL3_STATIC_GAIN_OFFSET_SHIFT 0x07 +#define WCD939X_CTL3_ZONE_SELECT_SHIFT_SHIFT 0x04 +#define WCD939X_CTL3_ZONE_SELECT_ENTRY_SHIFT 0x00 + +/* WCD939X_CTL4 Fields: */ +#define WCD939X_CTL4_DET_WINDOW_SHIFT 0x00 + +/* WCD939X_CTL5 Fields: */ +#define WCD939X_CTL5_GAIN_MAX_THOLD_SHIFT 0x03 +#define WCD939X_CTL5_DET_WINDOW_SHIFT 0x00 + +/* WCD939X_CTL6 Fields: */ +#define WCD939X_CTL6_STATUS_SHIFT 0x00 + +/* WCD939X_CTL7 Fields: */ +#define WCD939X_CTL7_DIS_SCD_SHIFT 0x06 +#define WCD939X_CTL7_AGAIN_DELAY_SHIFT 0x01 + +/* WCD939X_CTL8 Fields: */ +#define WCD939X_CTL8_PEAK_TO_FLAG_DIS_SHIFT 0x01 +#define WCD939X_CTL8_GAIN_STEP_SELECT_SHIFT 0x00 + +/* WCD939X_CTL9 Fields: */ +#define WCD939X_CTL9_ZONE0_RMS_SHIFT 0x00 + +/* WCD939X_CTL10 Fields: */ +#define WCD939X_CTL10_ZONE1_RMS_SHIFT 0x00 + +/* WCD939X_CTL11 Fields: */ +#define WCD939X_CTL11_ZONE2_RMS_SHIFT 0x00 + +/* WCD939X_CTL12 Fields: */ +#define WCD939X_CTL12_ZONE3_RMS_SHIFT 0x00 + +/* WCD939X_CTL13 Fields: */ +#define WCD939X_CTL13_ZONE4_RMS_SHIFT 0x00 + +/* WCD939X_CTL14 Fields: */ +#define WCD939X_CTL14_ZONE5_RMS_SHIFT 0x00 + +/* WCD939X_CTL15 Fields: */ +#define WCD939X_CTL15_ZONE6_RMS_SHIFT 0x00 + +/* WCD939X_CTL16 Fields: */ +#define WCD939X_CTL16_MAX_ATTN_SHIFT 0x00 + +/* WCD939X_CTL17 Fields: */ +#define WCD939X_CTL17_PATH_GAIN_SHIFT 0x00 + +/* WCD939X_CTL18 Fields: */ +#define WCD939X_CTL18_ANA_ADDR_MAP_SHIFT 0x00 + +/* WCD939X_CTL19 Fields: */ +#define WCD939X_CTL19_RMS_TOUT_SHIFT 0x01 +#define WCD939X_CTL19_RMS_TOUT_OVERRIDE_SHIFT 0x00 + + +/* WCD939X_R_CTL0 Fields: */ +#define WCD939X_R_CTL0_SHUTDWN_TOUT_SHIFT 0x04 +#define WCD939X_R_CTL0_DROPOUT_EN_SHIFT 0x03 +#define WCD939X_R_CTL0_COMP_HALT_SHIFT 0x02 +#define WCD939X_R_CTL0_SOFT_RST_SHIFT 0x01 +#define WCD939X_R_CTL0_CLK_EN_SHIFT 0x00 + +/* WCD939X_R_CTL1 Fields: */ +#define WCD939X_R_CTL1_LEVEL_METER_DIV_FACTOR_SHIFT 0x04 +#define WCD939X_R_CTL1_PEAK_METER_TOUT_SHIFT 0x00 + +/* WCD939X_R_CTL2 Fields: */ +#define WCD939X_R_CTL2_LEVEL_METER_RESAMPLE_RATE_SHIFT 0x00 + +/* WCD939X_R_CTL3 Fields: */ +#define WCD939X_R_CTL3_STATIC_GAIN_OFFSET_SHIFT 0x07 +#define WCD939X_R_CTL3_ZONE_SELECT_SHIFT_SHIFT 0x04 +#define WCD939X_R_CTL3_ZONE_SELECT_ENTRY_SHIFT 0x00 + +/* WCD939X_R_CTL4 Fields: */ +#define WCD939X_R_CTL4_DET_WINDOW_SHIFT 0x00 + +/* WCD939X_R_CTL5 Fields: */ +#define WCD939X_R_CTL5_GAIN_MAX_THOLD_SHIFT 0x03 +#define WCD939X_R_CTL5_DET_WINDOW_SHIFT 0x00 + +/* WCD939X_R_CTL6 Fields: */ +#define WCD939X_R_CTL6_STATUS_SHIFT 0x00 + +/* WCD939X_R_CTL7 Fields: */ +#define WCD939X_R_CTL7_DIS_SCD_SHIFT 0x06 +#define WCD939X_R_CTL7_AGAIN_DELAY_SHIFT 0x01 + +/* WCD939X_R_CTL8 Fields: */ +#define WCD939X_R_CTL8_PEAK_TO_FLAG_DIS_SHIFT 0x01 +#define WCD939X_R_CTL8_GAIN_STEP_SELECT_SHIFT 0x00 + +/* WCD939X_R_CTL9 Fields: */ +#define WCD939X_R_CTL9_ZONE0_RMS_SHIFT 0x00 + +/* WCD939X_R_CTL10 Fields: */ +#define WCD939X_R_CTL10_ZONE1_RMS_SHIFT 0x00 + +/* WCD939X_R_CTL11 Fields: */ +#define WCD939X_R_CTL11_ZONE2_RMS_SHIFT 0x00 + +/* WCD939X_R_CTL12 Fields: */ +#define WCD939X_R_CTL12_ZONE3_RMS_SHIFT 0x00 + +/* WCD939X_R_CTL13 Fields: */ +#define WCD939X_R_CTL13_ZONE4_RMS_SHIFT 0x00 + +/* WCD939X_R_CTL14 Fields: */ +#define WCD939X_R_CTL14_ZONE5_RMS_SHIFT 0x00 + +/* WCD939X_R_CTL15 Fields: */ +#define WCD939X_R_CTL15_ZONE6_RMS_SHIFT 0x00 + +/* WCD939X_R_CTL16 Fields: */ +#define WCD939X_R_CTL16_MAX_ATTN_SHIFT 0x00 + +/* WCD939X_R_CTL17 Fields: */ +#define WCD939X_R_CTL17_PATH_GAIN_SHIFT 0x00 + +/* WCD939X_R_CTL18 Fields: */ +#define WCD939X_R_CTL18_ANA_ADDR_MAP_SHIFT 0x00 + +/* WCD939X_R_CTL19 Fields: */ +#define WCD939X_R_CTL19_RMS_TOUT_SHIFT 0x01 +#define WCD939X_R_CTL19_RMS_TOUT_OVERRIDE_SHIFT 0x00 + + +/* WCD939X_PATH_CTL Fields: */ +#define WCD939X_PATH_CTL_RESET_RIGHT_SHIFT 0x03 +#define WCD939X_PATH_CTL_RESET_LEFT_SHIFT 0x02 +#define WCD939X_PATH_CTL_CLK_EN_RIGHT_SHIFT 0x01 +#define WCD939X_PATH_CTL_CLK_EN_LEFT_SHIFT 0x00 + +/* WCD939X_CFG0 Fields: */ +#define WCD939X_CFG0_AUTO_DISABLE_ANC_SHIFT 0x02 +#define WCD939X_CFG0_AUTO_DISABLE_DSD_SHIFT 0x01 +#define WCD939X_CFG0_IDLE_STEREO_SHIFT 0x00 + +/* WCD939X_CFG1 Fields: */ +#define WCD939X_CFG1_IDLE_N_HOLDOFF_LSB_SHIFT 0x00 + +/* WCD939X_CFG2 Fields: */ +#define WCD939X_CFG2_IDLE_N_HOLDOFF_MSB_SHIFT 0x00 + +/* WCD939X_CFG3 Fields: */ +#define WCD939X_CFG3_IDLE_THRESHOLD_SHIFT 0x00 + + +/* WCD939X_DSD_HPHL_PATH_CTL Fields: */ +#define WCD939X_DSD_HPHL_PATH_CTL_RESET_SHIFT 0x01 +#define WCD939X_DSD_HPHL_PATH_CTL_CLK_EN_SHIFT 0x00 + +/* WCD939X_DSD_HPHL_CFG0 Fields: */ +#define WCD939X_DSD_HPHL_CFG0_INP_SEL_SHIFT 0x00 + +/* WCD939X_DSD_HPHL_CFG1 Fields: */ +#define WCD939X_DSD_HPHL_CFG1_PGA_GAIN_SHIFT 0x00 + +/* WCD939X_DSD_HPHL_CFG2 Fields: */ +#define WCD939X_DSD_HPHL_CFG2_PGA_TIMER_MSB_EXT_SHIFT 0x03 +#define WCD939X_DSD_HPHL_CFG2_PGA_MUTE_EN_SHIFT 0x02 +#define WCD939X_DSD_HPHL_CFG2_PGA_MODE_SHIFT 0x01 +#define WCD939X_DSD_HPHL_CFG2_PGA_HALF_DB_SHIFT 0x00 + +/* WCD939X_DSD_HPHL_CFG3 Fields: */ +#define WCD939X_DSD_HPHL_CFG3_PGA_TIMER_SHIFT 0x00 + +/* WCD939X_CFG4 Fields: */ +#define WCD939X_CFG4_TOGGLE_THRESHOLD_SHIFT 0x03 +#define WCD939X_CFG4_MUTE_THRESHOLD_SHIFT 0x00 + +/* WCD939X_CFG5 Fields: */ +#define WCD939X_CFG5_DATA_BIT_POLARITY_SHIFT 0x01 +#define WCD939X_CFG5_INP_BIT_POLARITY_SHIFT 0x00 + + +/* WCD939X_DSD_HPHR_PATH_CTL Fields: */ +#define WCD939X_DSD_HPHR_PATH_CTL_RESET_SHIFT 0x01 +#define WCD939X_DSD_HPHR_PATH_CTL_CLK_EN_SHIFT 0x00 + +/* WCD939X_DSD_HPHR_CFG0 Fields: */ +#define WCD939X_DSD_HPHR_CFG0_INP_SEL_SHIFT 0x00 + +/* WCD939X_DSD_HPHR_CFG1 Fields: */ +#define WCD939X_DSD_HPHR_CFG1_PGA_GAIN_SHIFT 0x00 + +/* WCD939X_DSD_HPHR_CFG2 Fields: */ +#define WCD939X_DSD_HPHR_CFG2_PGA_TIMER_MSB_EXT_SHIFT 0x03 +#define WCD939X_DSD_HPHR_CFG2_PGA_MUTE_EN_SHIFT 0x02 +#define WCD939X_DSD_HPHR_CFG2_PGA_MODE_SHIFT 0x01 +#define WCD939X_DSD_HPHR_CFG2_PGA_HALF_DB_SHIFT 0x00 + +/* WCD939X_DSD_HPHR_CFG3 Fields: */ +#define WCD939X_DSD_HPHR_CFG3_PGA_TIMER_SHIFT 0x00 + +/* WCD939X_DSD_HPHR_CFG4 Fields: */ +#define WCD939X_DSD_HPHR_CFG4_TOGGLE_THRESHOLD_SHIFT 0x03 +#define WCD939X_DSD_HPHR_CFG4_MUTE_THRESHOLD_SHIFT 0x00 + +/* WCD939X_DSD_HPHR_CFG5 Fields: */ +#define WCD939X_DSD_HPHR_CFG5_DATA_BIT_POLARITY_SHIFT 0x01 +#define WCD939X_DSD_HPHR_CFG5_INP_BIT_POLARITY_SHIFT 0x00 + + +#endif /* WCD939X_REG_SHIFTS_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-registers.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-registers.h new file mode 100644 index 0000000000..86a854dba2 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-registers.h @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef WCD939X_REGISTERS_H +#define WCD939X_REGISTERS_H + +#define WCD939X_BASE 0x2fff +#define WCD939X_REG(reg) (reg - WCD939X_BASE - 1) + +enum { + REG_NO_ACCESS, + RD_REG, + WR_REG, + RD_WR_REG +}; + +enum { + WCD939X_VERSION_1_0, + WCD939X_VERSION_1_1, + WCD939X_VERSION_2_0, +}; + +#define WCD939X_ANA_BASE (WCD939X_BASE+0x01) +#define WCD939X_ANA_PAGE (WCD939X_ANA_BASE+0x00) +#define WCD939X_BIAS (WCD939X_ANA_BASE+0x01) +#define WCD939X_RX_SUPPLIES (WCD939X_ANA_BASE+0x08) +#define WCD939X_HPH (WCD939X_ANA_BASE+0x09) +#define WCD939X_EAR (WCD939X_ANA_BASE+0x0a) +#define WCD939X_EAR_COMPANDER_CTL (WCD939X_ANA_BASE+0x0b) +#define WCD939X_TX_CH1 (WCD939X_ANA_BASE+0x0e) +#define WCD939X_TX_CH2 (WCD939X_ANA_BASE+0x0f) +#define WCD939X_TX_CH3 (WCD939X_ANA_BASE+0x10) +#define WCD939X_TX_CH4 (WCD939X_ANA_BASE+0x11) +#define WCD939X_MICB1_MICB2_DSP_EN_LOGIC (WCD939X_ANA_BASE+0x12) +#define WCD939X_MICB3_DSP_EN_LOGIC (WCD939X_ANA_BASE+0x13) +#define WCD939X_MBHC_MECH (WCD939X_ANA_BASE+0x14) +#define WCD939X_MBHC_ELECT (WCD939X_ANA_BASE+0x15) +#define WCD939X_MBHC_ZDET (WCD939X_ANA_BASE+0x16) +#define WCD939X_MBHC_RESULT_1 (WCD939X_ANA_BASE+0x17) +#define WCD939X_MBHC_RESULT_2 (WCD939X_ANA_BASE+0x18) +#define WCD939X_MBHC_RESULT_3 (WCD939X_ANA_BASE+0x19) +#define WCD939X_MBHC_BTN0 (WCD939X_ANA_BASE+0x1a) +#define WCD939X_MBHC_BTN1 (WCD939X_ANA_BASE+0x1b) +#define WCD939X_MBHC_BTN2 (WCD939X_ANA_BASE+0x1c) +#define WCD939X_MBHC_BTN3 (WCD939X_ANA_BASE+0x1d) +#define WCD939X_MBHC_BTN4 (WCD939X_ANA_BASE+0x1e) +#define WCD939X_MBHC_BTN5 (WCD939X_ANA_BASE+0x1f) +#define WCD939X_MBHC_BTN6 (WCD939X_ANA_BASE+0x20) +#define WCD939X_MBHC_BTN7 (WCD939X_ANA_BASE+0x21) +#define WCD939X_MICB1 (WCD939X_ANA_BASE+0x22) +#define WCD939X_MICB2 (WCD939X_ANA_BASE+0x23) +#define WCD939X_MICB2_RAMP (WCD939X_ANA_BASE+0x24) +#define WCD939X_MICB3 (WCD939X_ANA_BASE+0x25) +#define WCD939X_MICB4 (WCD939X_ANA_BASE+0x26) + +#define WCD939X_BIAS_BASE (WCD939X_BASE+0x29) +#define WCD939X_CTL (WCD939X_BIAS_BASE+0x00) +#define WCD939X_VBG_FINE_ADJ (WCD939X_BIAS_BASE+0x01) + +#define WCD939X_LDOL_BASE (WCD939X_BASE+0x41) +#define WCD939X_VDDCX_ADJUST (WCD939X_LDOL_BASE+0x00) +#define WCD939X_DISABLE_LDOL (WCD939X_LDOL_BASE+0x01) + +#define WCD939X_MBHC_BASE (WCD939X_BASE+0x57) +#define WCD939X_CTL_CLK (WCD939X_MBHC_BASE+0x00) +#define WCD939X_CTL_ANA (WCD939X_MBHC_BASE+0x01) +#define WCD939X_ZDET_VNEG_CTL (WCD939X_MBHC_BASE+0x02) +#define WCD939X_ZDET_BIAS_CTL (WCD939X_MBHC_BASE+0x03) +#define WCD939X_CTL_BCS (WCD939X_MBHC_BASE+0x04) +#define WCD939X_MOISTURE_DET_FSM_STATUS (WCD939X_MBHC_BASE+0x05) +#define WCD939X_TEST_CTL (WCD939X_MBHC_BASE+0x06) + +#define WCD939X_LDOH_BASE (WCD939X_BASE+0x68) +#define WCD939X_MODE (WCD939X_LDOH_BASE+0x00) +#define WCD939X_LDOH_BIAS (WCD939X_LDOH_BASE+0x01) +#define WCD939X_STB_LOADS (WCD939X_LDOH_BASE+0x02) +#define WCD939X_SLOWRAMP (WCD939X_LDOH_BASE+0x03) + +#define WCD939X_MICB1_BASE (WCD939X_BASE+0x6c) +#define WCD939X_TEST_CTL_1 (WCD939X_MICB1_BASE+0x00) +#define WCD939X_TEST_CTL_2 (WCD939X_MICB1_BASE+0x01) +#define WCD939X_TEST_CTL_3 (WCD939X_MICB1_BASE+0x02) + +#define WCD939X_MICB2_BASE (WCD939X_BASE+0x6f) +#define WCD939X_MICB2_TEST_CTL_1 (WCD939X_MICB2_BASE+0x00) +#define WCD939X_MICB2_TEST_CTL_2 (WCD939X_MICB2_BASE+0x01) +#define WCD939X_MICB2_TEST_CTL_3 (WCD939X_MICB2_BASE+0x02) + +#define WCD939X_MICB3_BASE (WCD939X_BASE+0x72) +#define WCD939X_MICB3_TEST_CTL_1 (WCD939X_MICB3_BASE+0x00) +#define WCD939X_MICB3_TEST_CTL_2 (WCD939X_MICB3_BASE+0x01) +#define WCD939X_MICB3_TEST_CTL_3 (WCD939X_MICB3_BASE+0x02) + +#define WCD939X_MICB4_BASE (WCD939X_BASE+0x75) +#define WCD939X_MICB4_TEST_CTL_1 (WCD939X_MICB4_BASE+0x00) +#define WCD939X_MICB4_TEST_CTL_2 (WCD939X_MICB4_BASE+0x01) +#define WCD939X_MICB4_TEST_CTL_3 (WCD939X_MICB4_BASE+0x02) + +#define WCD939X_TX_COM_BASE (WCD939X_BASE+0x78) +#define WCD939X_ADC_VCM (WCD939X_TX_COM_BASE+0x00) +#define WCD939X_BIAS_ATEST (WCD939X_TX_COM_BASE+0x01) +#define WCD939X_SPARE1 (WCD939X_TX_COM_BASE+0x02) +#define WCD939X_SPARE2 (WCD939X_TX_COM_BASE+0x03) +#define WCD939X_TXFE_DIV_CTL (WCD939X_TX_COM_BASE+0x04) +#define WCD939X_TXFE_DIV_START (WCD939X_TX_COM_BASE+0x05) +#define WCD939X_SPARE3 (WCD939X_TX_COM_BASE+0x06) +#define WCD939X_SPARE4 (WCD939X_TX_COM_BASE+0x07) + +#define WCD939X_TX_1_2_BASE (WCD939X_BASE+0x80) +#define WCD939X_TEST_EN (WCD939X_TX_1_2_BASE+0x00) +#define WCD939X_ADC_IB (WCD939X_TX_1_2_BASE+0x01) +#define WCD939X_ATEST_REFCTL (WCD939X_TX_1_2_BASE+0x02) +#define WCD939X_TX_1_2_TEST_CTL (WCD939X_TX_1_2_BASE+0x03) +#define WCD939X_TEST_BLK_EN1 (WCD939X_TX_1_2_BASE+0x04) +#define WCD939X_TXFE1_CLKDIV (WCD939X_TX_1_2_BASE+0x05) +#define WCD939X_SAR2_ERR (WCD939X_TX_1_2_BASE+0x06) +#define WCD939X_SAR1_ERR (WCD939X_TX_1_2_BASE+0x07) + +#define WCD939X_TX_3_4_BASE (WCD939X_BASE+0x88) +#define WCD939X_TX_3_4_TEST_EN (WCD939X_TX_3_4_BASE+0x00) +#define WCD939X_TX_3_4_ADC_IB (WCD939X_TX_3_4_BASE+0x01) +#define WCD939X_TX_3_4_ATEST_REFCTL (WCD939X_TX_3_4_BASE+0x02) +#define WCD939X_TX_3_4_TEST_CTL (WCD939X_TX_3_4_BASE+0x03) +#define WCD939X_TEST_BLK_EN3 (WCD939X_TX_3_4_BASE+0x04) +#define WCD939X_TXFE3_CLKDIV (WCD939X_TX_3_4_BASE+0x05) +#define WCD939X_SAR4_ERR (WCD939X_TX_3_4_BASE+0x06) +#define WCD939X_SAR3_ERR (WCD939X_TX_3_4_BASE+0x07) +#define WCD939X_TEST_BLK_EN2 (WCD939X_TX_3_4_BASE+0x08) +#define WCD939X_TXFE2_CLKDIV (WCD939X_TX_3_4_BASE+0x09) +#define WCD939X_TX_3_4_SPARE1 (WCD939X_TX_3_4_BASE+0x0a) +#define WCD939X_TEST_BLK_EN4 (WCD939X_TX_3_4_BASE+0x0b) +#define WCD939X_TXFE4_CLKDIV (WCD939X_TX_3_4_BASE+0x0c) +#define WCD939X_TX_3_4_SPARE2 (WCD939X_TX_3_4_BASE+0x0d) + +#define WCD939X_CLASSH_BASE (WCD939X_BASE+0x98) +#define WCD939X_MODE_1 (WCD939X_CLASSH_BASE+0x00) +#define WCD939X_MODE_2 (WCD939X_CLASSH_BASE+0x01) +#define WCD939X_MODE_3 (WCD939X_CLASSH_BASE+0x02) +#define WCD939X_CTRL_VCL_1 (WCD939X_CLASSH_BASE+0x03) +#define WCD939X_CTRL_VCL_2 (WCD939X_CLASSH_BASE+0x04) +#define WCD939X_CTRL_CCL_1 (WCD939X_CLASSH_BASE+0x05) +#define WCD939X_CTRL_CCL_2 (WCD939X_CLASSH_BASE+0x06) +#define WCD939X_CTRL_CCL_3 (WCD939X_CLASSH_BASE+0x07) +#define WCD939X_CTRL_CCL_4 (WCD939X_CLASSH_BASE+0x08) +#define WCD939X_CTRL_CCL_5 (WCD939X_CLASSH_BASE+0x09) +#define WCD939X_BUCK_TMUX_A_D (WCD939X_CLASSH_BASE+0x0a) +#define WCD939X_BUCK_SW_DRV_CNTL (WCD939X_CLASSH_BASE+0x0b) +#define WCD939X_SPARE (WCD939X_CLASSH_BASE+0x0c) + +#define WCD939X_FLYBACK_BASE (WCD939X_BASE+0xa5) +#define WCD939X_EN (WCD939X_FLYBACK_BASE+0x00) +#define WCD939X_VNEG_CTRL_1 (WCD939X_FLYBACK_BASE+0x01) +#define WCD939X_VNEG_CTRL_2 (WCD939X_FLYBACK_BASE+0x02) +#define WCD939X_VNEG_CTRL_3 (WCD939X_FLYBACK_BASE+0x03) +#define WCD939X_VNEG_CTRL_4 (WCD939X_FLYBACK_BASE+0x04) +#define WCD939X_VNEG_CTRL_5 (WCD939X_FLYBACK_BASE+0x05) +#define WCD939X_VNEG_CTRL_6 (WCD939X_FLYBACK_BASE+0x06) +#define WCD939X_VNEG_CTRL_7 (WCD939X_FLYBACK_BASE+0x07) +#define WCD939X_VNEG_CTRL_8 (WCD939X_FLYBACK_BASE+0x08) +#define WCD939X_VNEG_CTRL_9 (WCD939X_FLYBACK_BASE+0x09) +#define WCD939X_VNEGDAC_CTRL_1 (WCD939X_FLYBACK_BASE+0x0a) +#define WCD939X_VNEGDAC_CTRL_2 (WCD939X_FLYBACK_BASE+0x0b) +#define WCD939X_VNEGDAC_CTRL_3 (WCD939X_FLYBACK_BASE+0x0c) +#define WCD939X_CTRL_1 (WCD939X_FLYBACK_BASE+0x0d) +#define WCD939X_FLYBACK_TEST_CTL (WCD939X_FLYBACK_BASE+0x0e) + +#define WCD939X_RX_BASE (WCD939X_BASE+0xb4) +#define WCD939X_AUX_SW_CTL (WCD939X_RX_BASE+0x00) +#define WCD939X_PA_AUX_IN_CONN (WCD939X_RX_BASE+0x01) +#define WCD939X_TIMER_DIV (WCD939X_RX_BASE+0x02) +#define WCD939X_OCP_CTL (WCD939X_RX_BASE+0x03) +#define WCD939X_OCP_COUNT (WCD939X_RX_BASE+0x04) +#define WCD939X_BIAS_EAR_DAC (WCD939X_RX_BASE+0x05) +#define WCD939X_BIAS_EAR_AMP (WCD939X_RX_BASE+0x06) +#define WCD939X_BIAS_HPH_LDO (WCD939X_RX_BASE+0x07) +#define WCD939X_BIAS_HPH_PA (WCD939X_RX_BASE+0x08) +#define WCD939X_BIAS_HPH_RDACBUFF_CNP2 (WCD939X_RX_BASE+0x09) +#define WCD939X_BIAS_HPH_RDAC_LDO (WCD939X_RX_BASE+0x0a) +#define WCD939X_BIAS_HPH_CNP1 (WCD939X_RX_BASE+0x0b) +#define WCD939X_BIAS_HPH_LOWPOWER (WCD939X_RX_BASE+0x0c) +#define WCD939X_BIAS_AUX_DAC (WCD939X_RX_BASE+0x0d) +#define WCD939X_BIAS_AUX_AMP (WCD939X_RX_BASE+0x0e) +#define WCD939X_BIAS_VNEGDAC_BLEEDER (WCD939X_RX_BASE+0x0f) +#define WCD939X_BIAS_MISC (WCD939X_RX_BASE+0x10) +#define WCD939X_BIAS_BUCK_RST (WCD939X_RX_BASE+0x11) +#define WCD939X_BIAS_BUCK_VREF_ERRAMP (WCD939X_RX_BASE+0x12) +#define WCD939X_BIAS_FLYB_ERRAMP (WCD939X_RX_BASE+0x13) +#define WCD939X_BIAS_FLYB_BUFF (WCD939X_RX_BASE+0x14) +#define WCD939X_BIAS_FLYB_MID_RST (WCD939X_RX_BASE+0x15) + +#define WCD939X_HPH_BASE (WCD939X_BASE+0xca) +#define WCD939X_L_STATUS (WCD939X_HPH_BASE+0x00) +#define WCD939X_R_STATUS (WCD939X_HPH_BASE+0x01) +#define WCD939X_CNP_EN (WCD939X_HPH_BASE+0x02) +#define WCD939X_CNP_WG_CTL (WCD939X_HPH_BASE+0x03) +#define WCD939X_CNP_WG_TIME (WCD939X_HPH_BASE+0x04) +#define WCD939X_HPH_OCP_CTL (WCD939X_HPH_BASE+0x05) +#define WCD939X_AUTO_CHOP (WCD939X_HPH_BASE+0x06) +#define WCD939X_CHOP_CTL (WCD939X_HPH_BASE+0x07) +#define WCD939X_PA_CTL1 (WCD939X_HPH_BASE+0x08) +#define WCD939X_PA_CTL2 (WCD939X_HPH_BASE+0x09) +#define WCD939X_L_EN (WCD939X_HPH_BASE+0x0a) +#define WCD939X_L_TEST (WCD939X_HPH_BASE+0x0b) +#define WCD939X_L_ATEST (WCD939X_HPH_BASE+0x0c) +#define WCD939X_R_EN (WCD939X_HPH_BASE+0x0d) +#define WCD939X_R_TEST (WCD939X_HPH_BASE+0x0e) +#define WCD939X_R_ATEST (WCD939X_HPH_BASE+0x0f) +#define WCD939X_RDAC_CLK_CTL1 (WCD939X_HPH_BASE+0x10) +#define WCD939X_RDAC_CLK_CTL2 (WCD939X_HPH_BASE+0x11) +#define WCD939X_RDAC_LDO_CTL (WCD939X_HPH_BASE+0x12) +#define WCD939X_RDAC_CHOP_CLK_LP_CTL (WCD939X_HPH_BASE+0x13) +#define WCD939X_REFBUFF_UHQA_CTL (WCD939X_HPH_BASE+0x14) +#define WCD939X_REFBUFF_LP_CTL (WCD939X_HPH_BASE+0x15) +#define WCD939X_L_DAC_CTL (WCD939X_HPH_BASE+0x16) +#define WCD939X_R_DAC_CTL (WCD939X_HPH_BASE+0x17) + +#define WCD939X_HPH_SURGE_BASE (WCD939X_BASE+0xe2) +#define WCD939X_HPHLR_SURGE_COMP_SEL (WCD939X_HPH_SURGE_BASE+0x00) +#define WCD939X_HPHLR_SURGE_EN (WCD939X_HPH_SURGE_BASE+0x01) +#define WCD939X_HPHLR_SURGE_MISC1 (WCD939X_HPH_SURGE_BASE+0x02) +#define WCD939X_HPHLR_SURGE_STATUS (WCD939X_HPH_SURGE_BASE+0x03) + +#define WCD939X_EAR_BASE (WCD939X_BASE+0xea) +#define WCD939X_EAR_EN_REG (WCD939X_EAR_BASE+0x00) +#define WCD939X_EAR_PA_CON (WCD939X_EAR_BASE+0x01) +#define WCD939X_EAR_SP_CON (WCD939X_EAR_BASE+0x02) +#define WCD939X_EAR_DAC_CON (WCD939X_EAR_BASE+0x03) +#define WCD939X_EAR_CNP_FSM_CON (WCD939X_EAR_BASE+0x04) +#define WCD939X_EAR_TEST_CTL (WCD939X_EAR_BASE+0x05) +#define WCD939X_STATUS_REG_1 (WCD939X_EAR_BASE+0x06) +#define WCD939X_STATUS_REG_2 (WCD939X_EAR_BASE+0x07) + +#define WCD939X_FLYBACK_NEW_BASE (WCD939X_BASE+0xf7) +#define WCD939X_FLYBACK_NEW_CTRL_2 (WCD939X_FLYBACK_NEW_BASE+0x00) +#define WCD939X_FLYBACK_NEW_CTRL_3 (WCD939X_FLYBACK_NEW_BASE+0x01) +#define WCD939X_FLYBACK_NEW_CTRL_4 (WCD939X_FLYBACK_NEW_BASE+0x02) + +#define WCD939X_ANA_NEW_BASE (WCD939X_BASE+0x101) +#define WCD939X_ANA_NEW_PAGE (WCD939X_ANA_NEW_BASE+0x00) + +#define WCD939X_HPH_NEW_BASE (WCD939X_BASE+0x102) +#define WCD939X_ANA_HPH2 (WCD939X_HPH_NEW_BASE+0x00) +#define WCD939X_ANA_HPH3 (WCD939X_HPH_NEW_BASE+0x01) + +#define WCD939X_SLEEP_BASE (WCD939X_BASE+0x104) +#define WCD939X_SLEEP_CTL (WCD939X_SLEEP_BASE+0x00) +#define WCD939X_WATCHDOG_CTL (WCD939X_SLEEP_BASE+0x01) + +#define WCD939X_MBHC_NEW_BASE (WCD939X_BASE+0x120) +#define WCD939X_ELECT_REM_CLAMP_CTL (WCD939X_MBHC_NEW_BASE+0x00) +#define WCD939X_CTL_1 (WCD939X_MBHC_NEW_BASE+0x01) +#define WCD939X_CTL_2 (WCD939X_MBHC_NEW_BASE+0x02) +#define WCD939X_PLUG_DETECT_CTL (WCD939X_MBHC_NEW_BASE+0x03) +#define WCD939X_ZDET_ANA_CTL (WCD939X_MBHC_NEW_BASE+0x04) +#define WCD939X_ZDET_RAMP_CTL (WCD939X_MBHC_NEW_BASE+0x05) +#define WCD939X_FSM_STATUS (WCD939X_MBHC_NEW_BASE+0x06) +#define WCD939X_ADC_RESULT (WCD939X_MBHC_NEW_BASE+0x07) + +#define WCD939X_TX_NEW_BASE (WCD939X_BASE+0x128) +#define WCD939X_TX_CH12_MUX (WCD939X_TX_NEW_BASE+0x00) +#define WCD939X_TX_CH34_MUX (WCD939X_TX_NEW_BASE+0x01) + +#define WCD939X_DIE_CRACK_BASE (WCD939X_BASE+0x12d) +#define WCD939X_DIE_CRK_DET_EN (WCD939X_DIE_CRACK_BASE+0x00) +#define WCD939X_DIE_CRK_DET_OUT (WCD939X_DIE_CRACK_BASE+0x01) + +#define WCD939X_HPH_NEW_INT_BASE (WCD939X_BASE+0x133) +#define WCD939X_RDAC_GAIN_CTL (WCD939X_HPH_NEW_INT_BASE+0x00) +#define WCD939X_PA_GAIN_CTL_L (WCD939X_HPH_NEW_INT_BASE+0x01) +#define WCD939X_RDAC_VREF_CTL (WCD939X_HPH_NEW_INT_BASE+0x02) +#define WCD939X_RDAC_OVERRIDE_CTL (WCD939X_HPH_NEW_INT_BASE+0x03) +#define WCD939X_PA_GAIN_CTL_R (WCD939X_HPH_NEW_INT_BASE+0x04) +#define WCD939X_PA_MISC1 (WCD939X_HPH_NEW_INT_BASE+0x05) +#define WCD939X_PA_MISC2 (WCD939X_HPH_NEW_INT_BASE+0x06) +#define WCD939X_PA_RDAC_MISC (WCD939X_HPH_NEW_INT_BASE+0x07) +#define WCD939X_HPH_TIMER1 (WCD939X_HPH_NEW_INT_BASE+0x08) +#define WCD939X_HPH_TIMER2 (WCD939X_HPH_NEW_INT_BASE+0x09) +#define WCD939X_HPH_TIMER3 (WCD939X_HPH_NEW_INT_BASE+0x0a) +#define WCD939X_HPH_TIMER4 (WCD939X_HPH_NEW_INT_BASE+0x0b) +#define WCD939X_PA_RDAC_MISC2 (WCD939X_HPH_NEW_INT_BASE+0x0c) +#define WCD939X_PA_RDAC_MISC3 (WCD939X_HPH_NEW_INT_BASE+0x0d) +#define WCD939X_RDAC_HD2_CTL_L (WCD939X_HPH_NEW_INT_BASE+0x0e) +#define WCD939X_RDAC_HD2_CTL_R (WCD939X_HPH_NEW_INT_BASE+0x0f) + +#define WCD939X_RX_NEW_INT_BASE (WCD939X_BASE+0x146) +#define WCD939X_HPH_RDAC_BIAS_LOHIFI (WCD939X_RX_NEW_INT_BASE+0x00) +#define WCD939X_HPH_RDAC_BIAS_ULP (WCD939X_RX_NEW_INT_BASE+0x01) +#define WCD939X_HPH_RDAC_LDO_LP (WCD939X_RX_NEW_INT_BASE+0x02) + +#define WCD939X_MBHC_NEW_INT_BASE (WCD939X_BASE+0x1b0) +#define WCD939X_MOISTURE_DET_DC_CTRL (WCD939X_MBHC_NEW_INT_BASE+0x00) +#define WCD939X_MOISTURE_DET_POLLING_CTRL (WCD939X_MBHC_NEW_INT_BASE+0x01) +#define WCD939X_MECH_DET_CURRENT (WCD939X_MBHC_NEW_INT_BASE+0x02) +#define WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW (WCD939X_MBHC_NEW_INT_BASE+0x03) + +#define WCD939X_EAR_INT_NEW_BASE (WCD939X_BASE+0x1b8) +#define WCD939X_EAR_CHOPPER_CON (WCD939X_EAR_INT_NEW_BASE+0x00) +#define WCD939X_CNP_VCM_CON1 (WCD939X_EAR_INT_NEW_BASE+0x01) +#define WCD939X_CNP_VCM_CON2 (WCD939X_EAR_INT_NEW_BASE+0x02) +#define WCD939X_EAR_DYNAMIC_BIAS (WCD939X_EAR_INT_NEW_BASE+0x03) + +#define WCD939X_SLEEP_INT_BASE (WCD939X_BASE+0x1d1) +#define WCD939X_WATCHDOG_CTL_1 (WCD939X_SLEEP_INT_BASE+0x00) +#define WCD939X_WATCHDOG_CTL_2 (WCD939X_SLEEP_INT_BASE+0x01) + +#define WCD939X_DIE_CRACK_INT_BASE (WCD939X_BASE+0x1d4) +#define WCD939X_DIE_CRK_DET_INT1 (WCD939X_DIE_CRACK_INT_BASE+0x00) +#define WCD939X_DIE_CRK_DET_INT2 (WCD939X_DIE_CRACK_INT_BASE+0x01) + +#define WCD939X_TX_COM_NEW_INT_BASE (WCD939X_BASE+0x1d6) +#define WCD939X_TXFE_DIVSTOP_L2 (WCD939X_TX_COM_NEW_INT_BASE+0x00) +#define WCD939X_TXFE_DIVSTOP_L1 (WCD939X_TX_COM_NEW_INT_BASE+0x01) +#define WCD939X_TXFE_DIVSTOP_L0 (WCD939X_TX_COM_NEW_INT_BASE+0x02) +#define WCD939X_TXFE_DIVSTOP_ULP1P2M (WCD939X_TX_COM_NEW_INT_BASE+0x03) +#define WCD939X_TXFE_DIVSTOP_ULP0P6M (WCD939X_TX_COM_NEW_INT_BASE+0x04) +#define WCD939X_TXFE_ICTRL_STG1_L2L1 (WCD939X_TX_COM_NEW_INT_BASE+0x05) +#define WCD939X_TXFE_ICTRL_STG1_L0 (WCD939X_TX_COM_NEW_INT_BASE+0x06) +#define WCD939X_TXFE_ICTRL_STG1_ULP (WCD939X_TX_COM_NEW_INT_BASE+0x07) +#define WCD939X_TXFE_ICTRL_STG2MAIN_L2L1 (WCD939X_TX_COM_NEW_INT_BASE+0x08) +#define WCD939X_TXFE_ICTRL_STG2MAIN_L0 (WCD939X_TX_COM_NEW_INT_BASE+0x09) +#define WCD939X_TXFE_ICTRL_STG2MAIN_ULP (WCD939X_TX_COM_NEW_INT_BASE+0x0a) +#define WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0 (WCD939X_TX_COM_NEW_INT_BASE+0x0b) +#define WCD939X_TXFE_ICTRL_STG2CASC_ULP (WCD939X_TX_COM_NEW_INT_BASE+0x0c) +#define WCD939X_TXADC_SCBIAS_L2L1 (WCD939X_TX_COM_NEW_INT_BASE+0x0d) +#define WCD939X_TXADC_SCBIAS_L0ULP (WCD939X_TX_COM_NEW_INT_BASE+0x0e) +#define WCD939X_TXADC_INT_L2 (WCD939X_TX_COM_NEW_INT_BASE+0x0f) +#define WCD939X_TXADC_INT_L1 (WCD939X_TX_COM_NEW_INT_BASE+0x10) +#define WCD939X_TXADC_INT_L0 (WCD939X_TX_COM_NEW_INT_BASE+0x11) +#define WCD939X_TXADC_INT_ULP (WCD939X_TX_COM_NEW_INT_BASE+0x12) + +#define WCD939X_DIGITAL_BASE (WCD939X_BASE+0x401) +#define WCD939X_DIGITAL_PAGE (WCD939X_DIGITAL_BASE+0x00) +#define WCD939X_CHIP_ID0 (WCD939X_DIGITAL_BASE+0x01) +#define WCD939X_CHIP_ID1 (WCD939X_DIGITAL_BASE+0x02) +#define WCD939X_CHIP_ID2 (WCD939X_DIGITAL_BASE+0x03) +#define WCD939X_CHIP_ID3 (WCD939X_DIGITAL_BASE+0x04) +#define WCD939X_SWR_TX_CLK_RATE (WCD939X_DIGITAL_BASE+0x05) +#define WCD939X_CDC_RST_CTL (WCD939X_DIGITAL_BASE+0x06) +#define WCD939X_TOP_CLK_CFG (WCD939X_DIGITAL_BASE+0x07) +#define WCD939X_CDC_ANA_CLK_CTL (WCD939X_DIGITAL_BASE+0x08) +#define WCD939X_CDC_DIG_CLK_CTL (WCD939X_DIGITAL_BASE+0x09) +#define WCD939X_SWR_RST_EN (WCD939X_DIGITAL_BASE+0x0a) +#define WCD939X_CDC_PATH_MODE (WCD939X_DIGITAL_BASE+0x0b) +#define WCD939X_CDC_RX_RST (WCD939X_DIGITAL_BASE+0x0c) +#define WCD939X_CDC_RX0_CTL (WCD939X_DIGITAL_BASE+0x0d) +#define WCD939X_CDC_RX1_CTL (WCD939X_DIGITAL_BASE+0x0e) +#define WCD939X_CDC_RX2_CTL (WCD939X_DIGITAL_BASE+0x0f) +#define WCD939X_CDC_TX_ANA_MODE_0_1 (WCD939X_DIGITAL_BASE+0x10) +#define WCD939X_CDC_TX_ANA_MODE_2_3 (WCD939X_DIGITAL_BASE+0x11) +#define WCD939X_CDC_COMP_CTL_0 (WCD939X_DIGITAL_BASE+0x14) +#define WCD939X_CDC_ANA_TX_CLK_CTL (WCD939X_DIGITAL_BASE+0x17) +#define WCD939X_CDC_HPH_DSM_A1_0 (WCD939X_DIGITAL_BASE+0x18) +#define WCD939X_CDC_HPH_DSM_A1_1 (WCD939X_DIGITAL_BASE+0x19) +#define WCD939X_CDC_HPH_DSM_A2_0 (WCD939X_DIGITAL_BASE+0x1a) +#define WCD939X_CDC_HPH_DSM_A2_1 (WCD939X_DIGITAL_BASE+0x1b) +#define WCD939X_CDC_HPH_DSM_A3_0 (WCD939X_DIGITAL_BASE+0x1c) +#define WCD939X_CDC_HPH_DSM_A3_1 (WCD939X_DIGITAL_BASE+0x1d) +#define WCD939X_CDC_HPH_DSM_A4_0 (WCD939X_DIGITAL_BASE+0x1e) +#define WCD939X_CDC_HPH_DSM_A4_1 (WCD939X_DIGITAL_BASE+0x1f) +#define WCD939X_CDC_HPH_DSM_A5_0 (WCD939X_DIGITAL_BASE+0x20) +#define WCD939X_CDC_HPH_DSM_A5_1 (WCD939X_DIGITAL_BASE+0x21) +#define WCD939X_CDC_HPH_DSM_A6_0 (WCD939X_DIGITAL_BASE+0x22) +#define WCD939X_CDC_HPH_DSM_A7_0 (WCD939X_DIGITAL_BASE+0x23) +#define WCD939X_CDC_HPH_DSM_C_0 (WCD939X_DIGITAL_BASE+0x24) +#define WCD939X_CDC_HPH_DSM_C_1 (WCD939X_DIGITAL_BASE+0x25) +#define WCD939X_CDC_HPH_DSM_C_2 (WCD939X_DIGITAL_BASE+0x26) +#define WCD939X_CDC_HPH_DSM_C_3 (WCD939X_DIGITAL_BASE+0x27) +#define WCD939X_CDC_HPH_DSM_R1 (WCD939X_DIGITAL_BASE+0x28) +#define WCD939X_CDC_HPH_DSM_R2 (WCD939X_DIGITAL_BASE+0x29) +#define WCD939X_CDC_HPH_DSM_R3 (WCD939X_DIGITAL_BASE+0x2a) +#define WCD939X_CDC_HPH_DSM_R4 (WCD939X_DIGITAL_BASE+0x2b) +#define WCD939X_CDC_HPH_DSM_R5 (WCD939X_DIGITAL_BASE+0x2c) +#define WCD939X_CDC_HPH_DSM_R6 (WCD939X_DIGITAL_BASE+0x2d) +#define WCD939X_CDC_HPH_DSM_R7 (WCD939X_DIGITAL_BASE+0x2e) +#define WCD939X_CDC_EAR_DSM_A1_0 (WCD939X_DIGITAL_BASE+0x2f) +#define WCD939X_CDC_EAR_DSM_A1_1 (WCD939X_DIGITAL_BASE+0x30) +#define WCD939X_CDC_EAR_DSM_A2_0 (WCD939X_DIGITAL_BASE+0x31) +#define WCD939X_CDC_EAR_DSM_A2_1 (WCD939X_DIGITAL_BASE+0x32) +#define WCD939X_CDC_EAR_DSM_A3_0 (WCD939X_DIGITAL_BASE+0x33) +#define WCD939X_CDC_EAR_DSM_A3_1 (WCD939X_DIGITAL_BASE+0x34) +#define WCD939X_CDC_EAR_DSM_A4_0 (WCD939X_DIGITAL_BASE+0x35) +#define WCD939X_CDC_EAR_DSM_A4_1 (WCD939X_DIGITAL_BASE+0x36) +#define WCD939X_CDC_EAR_DSM_A5_0 (WCD939X_DIGITAL_BASE+0x37) +#define WCD939X_CDC_EAR_DSM_A5_1 (WCD939X_DIGITAL_BASE+0x38) +#define WCD939X_CDC_EAR_DSM_A6_0 (WCD939X_DIGITAL_BASE+0x39) +#define WCD939X_CDC_EAR_DSM_A7_0 (WCD939X_DIGITAL_BASE+0x3a) +#define WCD939X_CDC_EAR_DSM_C_0 (WCD939X_DIGITAL_BASE+0x3b) +#define WCD939X_CDC_EAR_DSM_C_1 (WCD939X_DIGITAL_BASE+0x3c) +#define WCD939X_CDC_EAR_DSM_C_2 (WCD939X_DIGITAL_BASE+0x3d) +#define WCD939X_CDC_EAR_DSM_C_3 (WCD939X_DIGITAL_BASE+0x3e) +#define WCD939X_CDC_EAR_DSM_R1 (WCD939X_DIGITAL_BASE+0x3f) +#define WCD939X_CDC_EAR_DSM_R2 (WCD939X_DIGITAL_BASE+0x40) +#define WCD939X_CDC_EAR_DSM_R3 (WCD939X_DIGITAL_BASE+0x41) +#define WCD939X_CDC_EAR_DSM_R4 (WCD939X_DIGITAL_BASE+0x42) +#define WCD939X_CDC_EAR_DSM_R5 (WCD939X_DIGITAL_BASE+0x43) +#define WCD939X_CDC_EAR_DSM_R6 (WCD939X_DIGITAL_BASE+0x44) +#define WCD939X_CDC_EAR_DSM_R7 (WCD939X_DIGITAL_BASE+0x45) +#define WCD939X_CDC_HPH_GAIN_RX_0 (WCD939X_DIGITAL_BASE+0x46) +#define WCD939X_CDC_HPH_GAIN_RX_1 (WCD939X_DIGITAL_BASE+0x47) +#define WCD939X_CDC_HPH_GAIN_DSD_0 (WCD939X_DIGITAL_BASE+0x48) +#define WCD939X_CDC_HPH_GAIN_DSD_1 (WCD939X_DIGITAL_BASE+0x49) +#define WCD939X_CDC_HPH_GAIN_DSD_2 (WCD939X_DIGITAL_BASE+0x4a) +#define WCD939X_CDC_EAR_GAIN_DSD_0 (WCD939X_DIGITAL_BASE+0x4b) +#define WCD939X_CDC_EAR_GAIN_DSD_1 (WCD939X_DIGITAL_BASE+0x4c) +#define WCD939X_CDC_EAR_GAIN_DSD_2 (WCD939X_DIGITAL_BASE+0x4d) +#define WCD939X_CDC_HPH_GAIN_CTL (WCD939X_DIGITAL_BASE+0x4e) +#define WCD939X_CDC_EAR_GAIN_CTL (WCD939X_DIGITAL_BASE+0x4f) +#define WCD939X_CDC_EAR_PATH_CTL (WCD939X_DIGITAL_BASE+0x50) +#define WCD939X_CDC_SWR_CLH (WCD939X_DIGITAL_BASE+0x51) +#define WCD939X_SWR_CLH_BYP (WCD939X_DIGITAL_BASE+0x52) +#define WCD939X_CDC_TX0_CTL (WCD939X_DIGITAL_BASE+0x53) +#define WCD939X_CDC_TX1_CTL (WCD939X_DIGITAL_BASE+0x54) +#define WCD939X_CDC_TX2_CTL (WCD939X_DIGITAL_BASE+0x55) +#define WCD939X_CDC_TX_RST (WCD939X_DIGITAL_BASE+0x56) +#define WCD939X_CDC_REQ_CTL (WCD939X_DIGITAL_BASE+0x57) +#define WCD939X_CDC_RST (WCD939X_DIGITAL_BASE+0x58) +#define WCD939X_CDC_AMIC_CTL (WCD939X_DIGITAL_BASE+0x5a) +#define WCD939X_CDC_DMIC_CTL (WCD939X_DIGITAL_BASE+0x5b) +#define WCD939X_CDC_DMIC1_CTL (WCD939X_DIGITAL_BASE+0x5c) +#define WCD939X_CDC_DMIC2_CTL (WCD939X_DIGITAL_BASE+0x5d) +#define WCD939X_CDC_DMIC3_CTL (WCD939X_DIGITAL_BASE+0x5e) +#define WCD939X_CDC_DMIC4_CTL (WCD939X_DIGITAL_BASE+0x5f) +#define WCD939X_EFUSE_PRG_CTL (WCD939X_DIGITAL_BASE+0x60) +#define WCD939X_EFUSE_CTL (WCD939X_DIGITAL_BASE+0x61) +#define WCD939X_CDC_DMIC_RATE_1_2 (WCD939X_DIGITAL_BASE+0x62) +#define WCD939X_CDC_DMIC_RATE_3_4 (WCD939X_DIGITAL_BASE+0x63) +#define WCD939X_PDM_WD_CTL0 (WCD939X_DIGITAL_BASE+0x65) +#define WCD939X_PDM_WD_CTL1 (WCD939X_DIGITAL_BASE+0x66) +#define WCD939X_PDM_WD_CTL2 (WCD939X_DIGITAL_BASE+0x67) +#define WCD939X_INTR_MODE (WCD939X_DIGITAL_BASE+0x6a) +#define WCD939X_INTR_MASK_0 (WCD939X_DIGITAL_BASE+0x6b) +#define WCD939X_INTR_MASK_1 (WCD939X_DIGITAL_BASE+0x6c) +#define WCD939X_INTR_MASK_2 (WCD939X_DIGITAL_BASE+0x6d) +#define WCD939X_INTR_STATUS_0 (WCD939X_DIGITAL_BASE+0x6e) +#define WCD939X_INTR_STATUS_1 (WCD939X_DIGITAL_BASE+0x6f) +#define WCD939X_INTR_STATUS_2 (WCD939X_DIGITAL_BASE+0x70) +#define WCD939X_INTR_CLEAR_0 (WCD939X_DIGITAL_BASE+0x71) +#define WCD939X_INTR_CLEAR_1 (WCD939X_DIGITAL_BASE+0x72) +#define WCD939X_INTR_CLEAR_2 (WCD939X_DIGITAL_BASE+0x73) +#define WCD939X_INTR_LEVEL_0 (WCD939X_DIGITAL_BASE+0x74) +#define WCD939X_INTR_LEVEL_1 (WCD939X_DIGITAL_BASE+0x75) +#define WCD939X_INTR_LEVEL_2 (WCD939X_DIGITAL_BASE+0x76) +#define WCD939X_INTR_SET_0 (WCD939X_DIGITAL_BASE+0x77) +#define WCD939X_INTR_SET_1 (WCD939X_DIGITAL_BASE+0x78) +#define WCD939X_INTR_SET_2 (WCD939X_DIGITAL_BASE+0x79) +#define WCD939X_INTR_TEST_0 (WCD939X_DIGITAL_BASE+0x7a) +#define WCD939X_INTR_TEST_1 (WCD939X_DIGITAL_BASE+0x7b) +#define WCD939X_INTR_TEST_2 (WCD939X_DIGITAL_BASE+0x7c) +#define WCD939X_TX_MODE_DBG_EN (WCD939X_DIGITAL_BASE+0x7f) +#define WCD939X_TX_MODE_DBG_0_1 (WCD939X_DIGITAL_BASE+0x80) +#define WCD939X_TX_MODE_DBG_2_3 (WCD939X_DIGITAL_BASE+0x81) +#define WCD939X_LB_IN_SEL_CTL (WCD939X_DIGITAL_BASE+0x82) +#define WCD939X_LOOP_BACK_MODE (WCD939X_DIGITAL_BASE+0x83) +#define WCD939X_SWR_DAC_TEST (WCD939X_DIGITAL_BASE+0x84) +#define WCD939X_SWR_HM_TEST_RX_0 (WCD939X_DIGITAL_BASE+0x85) +#define WCD939X_SWR_HM_TEST_TX_0 (WCD939X_DIGITAL_BASE+0x86) +#define WCD939X_SWR_HM_TEST_RX_1 (WCD939X_DIGITAL_BASE+0x87) +#define WCD939X_SWR_HM_TEST_TX_1 (WCD939X_DIGITAL_BASE+0x88) +#define WCD939X_SWR_HM_TEST_TX_2 (WCD939X_DIGITAL_BASE+0x89) +#define WCD939X_SWR_HM_TEST_0 (WCD939X_DIGITAL_BASE+0x8a) +#define WCD939X_SWR_HM_TEST_1 (WCD939X_DIGITAL_BASE+0x8b) +#define WCD939X_PAD_CTL_SWR_0 (WCD939X_DIGITAL_BASE+0x8c) +#define WCD939X_PAD_CTL_SWR_1 (WCD939X_DIGITAL_BASE+0x8d) +#define WCD939X_I2C_CTL (WCD939X_DIGITAL_BASE+0x8e) +#define WCD939X_CDC_TX_TANGGU_SW_MODE (WCD939X_DIGITAL_BASE+0x8f) +#define WCD939X_EFUSE_TEST_CTL_0 (WCD939X_DIGITAL_BASE+0x90) +#define WCD939X_EFUSE_TEST_CTL_1 (WCD939X_DIGITAL_BASE+0x91) +#define WCD939X_EFUSE_T_DATA_0 (WCD939X_DIGITAL_BASE+0x92) +#define WCD939X_EFUSE_T_DATA_1 (WCD939X_DIGITAL_BASE+0x93) +#define WCD939X_PAD_CTL_PDM_RX0 (WCD939X_DIGITAL_BASE+0x94) +#define WCD939X_PAD_CTL_PDM_RX1 (WCD939X_DIGITAL_BASE+0x95) +#define WCD939X_PAD_CTL_PDM_TX0 (WCD939X_DIGITAL_BASE+0x96) +#define WCD939X_PAD_CTL_PDM_TX1 (WCD939X_DIGITAL_BASE+0x97) +#define WCD939X_PAD_CTL_PDM_TX2 (WCD939X_DIGITAL_BASE+0x98) +#define WCD939X_PAD_INP_DIS_0 (WCD939X_DIGITAL_BASE+0x99) +#define WCD939X_PAD_INP_DIS_1 (WCD939X_DIGITAL_BASE+0x9a) +#define WCD939X_DRIVE_STRENGTH_0 (WCD939X_DIGITAL_BASE+0x9b) +#define WCD939X_DRIVE_STRENGTH_1 (WCD939X_DIGITAL_BASE+0x9c) +#define WCD939X_DRIVE_STRENGTH_2 (WCD939X_DIGITAL_BASE+0x9d) +#define WCD939X_RX_DATA_EDGE_CTL (WCD939X_DIGITAL_BASE+0x9e) +#define WCD939X_TX_DATA_EDGE_CTL (WCD939X_DIGITAL_BASE+0x9f) +#define WCD939X_GPIO_MODE (WCD939X_DIGITAL_BASE+0xa0) +#define WCD939X_PIN_CTL_OE (WCD939X_DIGITAL_BASE+0xa1) +#define WCD939X_PIN_CTL_DATA_0 (WCD939X_DIGITAL_BASE+0xa2) +#define WCD939X_PIN_CTL_DATA_1 (WCD939X_DIGITAL_BASE+0xa3) +#define WCD939X_PIN_STATUS_0 (WCD939X_DIGITAL_BASE+0xa4) +#define WCD939X_PIN_STATUS_1 (WCD939X_DIGITAL_BASE+0xa5) +#define WCD939X_DIG_DEBUG_CTL (WCD939X_DIGITAL_BASE+0xa6) +#define WCD939X_DIG_DEBUG_EN (WCD939X_DIGITAL_BASE+0xa7) +#define WCD939X_ANA_CSR_DBG_ADD (WCD939X_DIGITAL_BASE+0xa8) +#define WCD939X_ANA_CSR_DBG_CTL (WCD939X_DIGITAL_BASE+0xa9) +#define WCD939X_SSP_DBG (WCD939X_DIGITAL_BASE+0xaa) +#define WCD939X_MODE_STATUS_0 (WCD939X_DIGITAL_BASE+0xab) +#define WCD939X_MODE_STATUS_1 (WCD939X_DIGITAL_BASE+0xac) +#define WCD939X_SPARE_0 (WCD939X_DIGITAL_BASE+0xad) +#define WCD939X_SPARE_1 (WCD939X_DIGITAL_BASE+0xae) +#define WCD939X_SPARE_2 (WCD939X_DIGITAL_BASE+0xaf) +#define WCD939X_EFUSE_REG_0 (WCD939X_DIGITAL_BASE+0xb0) +#define WCD939X_EFUSE_REG_1 (WCD939X_DIGITAL_BASE+0xb1) +#define WCD939X_EFUSE_REG_2 (WCD939X_DIGITAL_BASE+0xb2) +#define WCD939X_EFUSE_REG_3 (WCD939X_DIGITAL_BASE+0xb3) +#define WCD939X_EFUSE_REG_4 (WCD939X_DIGITAL_BASE+0xb4) +#define WCD939X_EFUSE_REG_5 (WCD939X_DIGITAL_BASE+0xb5) +#define WCD939X_EFUSE_REG_6 (WCD939X_DIGITAL_BASE+0xb6) +#define WCD939X_EFUSE_REG_7 (WCD939X_DIGITAL_BASE+0xb7) +#define WCD939X_EFUSE_REG_8 (WCD939X_DIGITAL_BASE+0xb8) +#define WCD939X_EFUSE_REG_9 (WCD939X_DIGITAL_BASE+0xb9) +#define WCD939X_EFUSE_REG_10 (WCD939X_DIGITAL_BASE+0xba) +#define WCD939X_EFUSE_REG_11 (WCD939X_DIGITAL_BASE+0xbb) +#define WCD939X_EFUSE_REG_12 (WCD939X_DIGITAL_BASE+0xbc) +#define WCD939X_EFUSE_REG_13 (WCD939X_DIGITAL_BASE+0xbd) +#define WCD939X_EFUSE_REG_14 (WCD939X_DIGITAL_BASE+0xbe) +#define WCD939X_EFUSE_REG_15 (WCD939X_DIGITAL_BASE+0xbf) +#define WCD939X_EFUSE_REG_16 (WCD939X_DIGITAL_BASE+0xc0) +#define WCD939X_EFUSE_REG_17 (WCD939X_DIGITAL_BASE+0xc1) +#define WCD939X_EFUSE_REG_18 (WCD939X_DIGITAL_BASE+0xc2) +#define WCD939X_EFUSE_REG_19 (WCD939X_DIGITAL_BASE+0xc3) +#define WCD939X_EFUSE_REG_20 (WCD939X_DIGITAL_BASE+0xc4) +#define WCD939X_EFUSE_REG_21 (WCD939X_DIGITAL_BASE+0xc5) +#define WCD939X_EFUSE_REG_22 (WCD939X_DIGITAL_BASE+0xc6) +#define WCD939X_EFUSE_REG_23 (WCD939X_DIGITAL_BASE+0xc7) +#define WCD939X_EFUSE_REG_24 (WCD939X_DIGITAL_BASE+0xc8) +#define WCD939X_EFUSE_REG_25 (WCD939X_DIGITAL_BASE+0xc9) +#define WCD939X_EFUSE_REG_26 (WCD939X_DIGITAL_BASE+0xca) +#define WCD939X_EFUSE_REG_27 (WCD939X_DIGITAL_BASE+0xcb) +#define WCD939X_EFUSE_REG_28 (WCD939X_DIGITAL_BASE+0xcc) +#define WCD939X_EFUSE_REG_29 (WCD939X_DIGITAL_BASE+0xcd) +#define WCD939X_EFUSE_REG_30 (WCD939X_DIGITAL_BASE+0xce) +#define WCD939X_EFUSE_REG_31 (WCD939X_DIGITAL_BASE+0xcf) +#define WCD939X_TX_REQ_FB_CTL_0 (WCD939X_DIGITAL_BASE+0xd0) +#define WCD939X_TX_REQ_FB_CTL_1 (WCD939X_DIGITAL_BASE+0xd1) +#define WCD939X_TX_REQ_FB_CTL_2 (WCD939X_DIGITAL_BASE+0xd2) +#define WCD939X_TX_REQ_FB_CTL_3 (WCD939X_DIGITAL_BASE+0xd3) +#define WCD939X_TX_REQ_FB_CTL_4 (WCD939X_DIGITAL_BASE+0xd4) +#define WCD939X_DEM_BYPASS_DATA0 (WCD939X_DIGITAL_BASE+0xd5) +#define WCD939X_DEM_BYPASS_DATA1 (WCD939X_DIGITAL_BASE+0xd6) +#define WCD939X_DEM_BYPASS_DATA2 (WCD939X_DIGITAL_BASE+0xd7) +#define WCD939X_DEM_BYPASS_DATA3 (WCD939X_DIGITAL_BASE+0xd8) +#define WCD939X_DEM_SECOND_ORDER (WCD939X_DIGITAL_BASE+0xd9) +#define WCD939X_DSM_CTRL (WCD939X_DIGITAL_BASE+0xda) +#define WCD939X_DSM_0_STATIC_DATA_0 (WCD939X_DIGITAL_BASE+0xdb) +#define WCD939X_DSM_0_STATIC_DATA_1 (WCD939X_DIGITAL_BASE+0xdc) +#define WCD939X_DSM_0_STATIC_DATA_2 (WCD939X_DIGITAL_BASE+0xdd) +#define WCD939X_DSM_0_STATIC_DATA_3 (WCD939X_DIGITAL_BASE+0xde) +#define WCD939X_DSM_1_STATIC_DATA_0 (WCD939X_DIGITAL_BASE+0xdf) +#define WCD939X_DSM_1_STATIC_DATA_1 (WCD939X_DIGITAL_BASE+0xe0) +#define WCD939X_DSM_1_STATIC_DATA_2 (WCD939X_DIGITAL_BASE+0xe1) +#define WCD939X_DSM_1_STATIC_DATA_3 (WCD939X_DIGITAL_BASE+0xe2) + +#define WCD939X_RX_TOP_PAGE (WCD939X_BASE+0x501) +#define WCD939X_TOP_CFG0 (WCD939X_RX_TOP_PAGE+0x01) +#define WCD939X_HPHL_COMP_WR_LSB (WCD939X_RX_TOP_PAGE+0x02) +#define WCD939X_HPHL_COMP_WR_MSB (WCD939X_RX_TOP_PAGE+0x03) +#define WCD939X_HPHL_COMP_LUT (WCD939X_RX_TOP_PAGE+0x04) +#define WCD939X_HPHL_COMP_RD_LSB (WCD939X_RX_TOP_PAGE+0x05) +#define WCD939X_HPHL_COMP_RD_MSB (WCD939X_RX_TOP_PAGE+0x06) +#define WCD939X_HPHR_COMP_WR_LSB (WCD939X_RX_TOP_PAGE+0x07) +#define WCD939X_HPHR_COMP_WR_MSB (WCD939X_RX_TOP_PAGE+0x08) +#define WCD939X_HPHR_COMP_LUT (WCD939X_RX_TOP_PAGE+0x09) +#define WCD939X_HPHR_COMP_RD_LSB (WCD939X_RX_TOP_PAGE+0x0a) +#define WCD939X_HPHR_COMP_RD_MSB (WCD939X_RX_TOP_PAGE+0x0b) +#define WCD939X_DSD0_DEBUG_CFG1 (WCD939X_RX_TOP_PAGE+0x0c) +#define WCD939X_DSD0_DEBUG_CFG2 (WCD939X_RX_TOP_PAGE+0x0d) +#define WCD939X_DSD0_DEBUG_CFG3 (WCD939X_RX_TOP_PAGE+0x0e) +#define WCD939X_DSD0_DEBUG_CFG4 (WCD939X_RX_TOP_PAGE+0x0f) +#define WCD939X_DSD0_DEBUG_CFG5 (WCD939X_RX_TOP_PAGE+0x10) +#define WCD939X_DSD0_DEBUG_CFG6 (WCD939X_RX_TOP_PAGE+0x11) +#define WCD939X_DSD1_DEBUG_CFG1 (WCD939X_RX_TOP_PAGE+0x12) +#define WCD939X_DSD1_DEBUG_CFG2 (WCD939X_RX_TOP_PAGE+0x13) +#define WCD939X_DSD1_DEBUG_CFG3 (WCD939X_RX_TOP_PAGE+0x14) +#define WCD939X_DSD1_DEBUG_CFG4 (WCD939X_RX_TOP_PAGE+0x15) +#define WCD939X_DSD1_DEBUG_CFG5 (WCD939X_RX_TOP_PAGE+0x16) +#define WCD939X_DSD1_DEBUG_CFG6 (WCD939X_RX_TOP_PAGE+0x17) +#define WCD939X_HPHL_RX_PATH_CFG0 (WCD939X_RX_TOP_PAGE+0x1c) +#define WCD939X_HPHL_RX_PATH_CFG1 (WCD939X_RX_TOP_PAGE+0x1d) +#define WCD939X_HPHR_RX_PATH_CFG0 (WCD939X_RX_TOP_PAGE+0x1e) +#define WCD939X_HPHR_RX_PATH_CFG1 (WCD939X_RX_TOP_PAGE+0x1f) +#define WCD939X_RX_PATH_CFG2 (WCD939X_RX_TOP_PAGE+0x20) +#define WCD939X_HPHL_RX_PATH_SEC0 (WCD939X_RX_TOP_PAGE+0x21) +#define WCD939X_HPHL_RX_PATH_SEC1 (WCD939X_RX_TOP_PAGE+0x22) +#define WCD939X_HPHL_RX_PATH_SEC2 (WCD939X_RX_TOP_PAGE+0x23) +#define WCD939X_HPHL_RX_PATH_SEC3 (WCD939X_RX_TOP_PAGE+0x24) +#define WCD939X_HPHR_RX_PATH_SEC0 (WCD939X_RX_TOP_PAGE+0x25) +#define WCD939X_HPHR_RX_PATH_SEC1 (WCD939X_RX_TOP_PAGE+0x26) +#define WCD939X_HPHR_RX_PATH_SEC2 (WCD939X_RX_TOP_PAGE+0x27) +#define WCD939X_HPHR_RX_PATH_SEC3 (WCD939X_RX_TOP_PAGE+0x28) +#define WCD939X_RX_PATH_SEC4 (WCD939X_RX_TOP_PAGE+0x29) +#define WCD939X_RX_PATH_SEC5 (WCD939X_RX_TOP_PAGE+0x2a) + +#define WCD939X_COMPANDER_HPHL_BASE (WCD939X_BASE+0x541) +#define WCD939X_CTL0 (WCD939X_COMPANDER_HPHL_BASE+0x00) +#define WCD939X_CTL1 (WCD939X_COMPANDER_HPHL_BASE+0x01) +#define WCD939X_CTL2 (WCD939X_COMPANDER_HPHL_BASE+0x02) +#define WCD939X_CTL3 (WCD939X_COMPANDER_HPHL_BASE+0x03) +#define WCD939X_CTL4 (WCD939X_COMPANDER_HPHL_BASE+0x04) +#define WCD939X_CTL5 (WCD939X_COMPANDER_HPHL_BASE+0x05) +#define WCD939X_CTL6 (WCD939X_COMPANDER_HPHL_BASE+0x06) +#define WCD939X_CTL7 (WCD939X_COMPANDER_HPHL_BASE+0x07) +#define WCD939X_CTL8 (WCD939X_COMPANDER_HPHL_BASE+0x08) +#define WCD939X_CTL9 (WCD939X_COMPANDER_HPHL_BASE+0x09) +#define WCD939X_CTL10 (WCD939X_COMPANDER_HPHL_BASE+0x0a) +#define WCD939X_CTL11 (WCD939X_COMPANDER_HPHL_BASE+0x0b) +#define WCD939X_CTL12 (WCD939X_COMPANDER_HPHL_BASE+0x0c) +#define WCD939X_CTL13 (WCD939X_COMPANDER_HPHL_BASE+0x0d) +#define WCD939X_CTL14 (WCD939X_COMPANDER_HPHL_BASE+0x0e) +#define WCD939X_CTL15 (WCD939X_COMPANDER_HPHL_BASE+0x0f) +#define WCD939X_CTL16 (WCD939X_COMPANDER_HPHL_BASE+0x10) +#define WCD939X_CTL17 (WCD939X_COMPANDER_HPHL_BASE+0x11) +#define WCD939X_CTL18 (WCD939X_COMPANDER_HPHL_BASE+0x12) +#define WCD939X_CTL19 (WCD939X_COMPANDER_HPHL_BASE+0x13) + +#define WCD939X_R_BASE (WCD939X_BASE+0x561) +#define WCD939X_R_CTL0 (WCD939X_R_BASE+0x00) +#define WCD939X_R_CTL1 (WCD939X_R_BASE+0x01) +#define WCD939X_R_CTL2 (WCD939X_R_BASE+0x02) +#define WCD939X_R_CTL3 (WCD939X_R_BASE+0x03) +#define WCD939X_R_CTL4 (WCD939X_R_BASE+0x04) +#define WCD939X_R_CTL5 (WCD939X_R_BASE+0x05) +#define WCD939X_R_CTL6 (WCD939X_R_BASE+0x06) +#define WCD939X_R_CTL7 (WCD939X_R_BASE+0x07) +#define WCD939X_R_CTL8 (WCD939X_R_BASE+0x08) +#define WCD939X_R_CTL9 (WCD939X_R_BASE+0x09) +#define WCD939X_R_CTL10 (WCD939X_R_BASE+0x0a) +#define WCD939X_R_CTL11 (WCD939X_R_BASE+0x0b) +#define WCD939X_R_CTL12 (WCD939X_R_BASE+0x0c) +#define WCD939X_R_CTL13 (WCD939X_R_BASE+0x0d) +#define WCD939X_R_CTL14 (WCD939X_R_BASE+0x0e) +#define WCD939X_R_CTL15 (WCD939X_R_BASE+0x0f) +#define WCD939X_R_CTL16 (WCD939X_R_BASE+0x10) +#define WCD939X_R_CTL17 (WCD939X_R_BASE+0x11) +#define WCD939X_R_CTL18 (WCD939X_R_BASE+0x12) +#define WCD939X_R_CTL19 (WCD939X_R_BASE+0x13) + +#define WCD939X_E_BASE (WCD939X_BASE+0x581) +#define WCD939X_PATH_CTL (WCD939X_E_BASE+0x00) +#define WCD939X_CFG0 (WCD939X_E_BASE+0x01) +#define WCD939X_CFG1 (WCD939X_E_BASE+0x02) +#define WCD939X_CFG2 (WCD939X_E_BASE+0x03) +#define WCD939X_CFG3 (WCD939X_E_BASE+0x04) + +#define WCD939X_DSD_HPHL_BASE (WCD939X_BASE+0x591) +#define WCD939X_DSD_HPHL_PATH_CTL (WCD939X_DSD_HPHL_BASE+0x00) +#define WCD939X_DSD_HPHL_CFG0 (WCD939X_DSD_HPHL_BASE+0x01) +#define WCD939X_DSD_HPHL_CFG1 (WCD939X_DSD_HPHL_BASE+0x02) +#define WCD939X_DSD_HPHL_CFG2 (WCD939X_DSD_HPHL_BASE+0x03) +#define WCD939X_DSD_HPHL_CFG3 (WCD939X_DSD_HPHL_BASE+0x04) +#define WCD939X_CFG4 (WCD939X_DSD_HPHL_BASE+0x05) +#define WCD939X_CFG5 (WCD939X_DSD_HPHL_BASE+0x06) + +#define WCD939X_DSD_HPHR_BASE (WCD939X_BASE+0x5a1) +#define WCD939X_DSD_HPHR_PATH_CTL (WCD939X_DSD_HPHR_BASE+0x00) +#define WCD939X_DSD_HPHR_CFG0 (WCD939X_DSD_HPHR_BASE+0x01) +#define WCD939X_DSD_HPHR_CFG1 (WCD939X_DSD_HPHR_BASE+0x02) +#define WCD939X_DSD_HPHR_CFG2 (WCD939X_DSD_HPHR_BASE+0x03) +#define WCD939X_DSD_HPHR_CFG3 (WCD939X_DSD_HPHR_BASE+0x04) +#define WCD939X_DSD_HPHR_CFG4 (WCD939X_DSD_HPHR_BASE+0x05) +#define WCD939X_DSD_HPHR_CFG5 (WCD939X_DSD_HPHR_BASE+0x06) + +#define WCD939X_MAX_REGISTER (WCD939X_DSD_HPHR_CFG5) +#define WCD939X_NUM_REGISTERS (WCD939X_REG(WCD939X_MAX_REGISTER+1)) + +#endif /* WCD939X_REGISTERS_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-regmap.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-regmap.c new file mode 100644 index 0000000000..95b9c83d66 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-regmap.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include "wcd939x-registers.h" + +extern const u8 wcd939x_reg_access[WCD939X_NUM_REGISTERS]; + +static struct reg_default wcd939x_defaults[] = { + {WCD939X_ANA_PAGE, 0x00}, + {WCD939X_BIAS, 0x00}, + {WCD939X_RX_SUPPLIES, 0x00}, + {WCD939X_HPH, 0x0c}, + {WCD939X_EAR, 0x00}, + {WCD939X_EAR_COMPANDER_CTL, 0x02}, + {WCD939X_TX_CH1, 0x20}, + {WCD939X_TX_CH2, 0x00}, + {WCD939X_TX_CH3, 0x20}, + {WCD939X_TX_CH4, 0x00}, + {WCD939X_MICB1_MICB2_DSP_EN_LOGIC, 0x00}, + {WCD939X_MICB3_DSP_EN_LOGIC, 0x00}, + {WCD939X_MBHC_MECH, 0x39}, + {WCD939X_MBHC_ELECT, 0x08}, + {WCD939X_MBHC_ZDET, 0x00}, + {WCD939X_MBHC_RESULT_1, 0x00}, + {WCD939X_MBHC_RESULT_2, 0x00}, + {WCD939X_MBHC_RESULT_3, 0x00}, + {WCD939X_MBHC_BTN0, 0x00}, + {WCD939X_MBHC_BTN1, 0x10}, + {WCD939X_MBHC_BTN2, 0x20}, + {WCD939X_MBHC_BTN3, 0x30}, + {WCD939X_MBHC_BTN4, 0x40}, + {WCD939X_MBHC_BTN5, 0x50}, + {WCD939X_MBHC_BTN6, 0x60}, + {WCD939X_MBHC_BTN7, 0x70}, + {WCD939X_MICB1, 0x10}, + {WCD939X_MICB2, 0x10}, + {WCD939X_MICB2_RAMP, 0x00}, + {WCD939X_MICB3, 0x00}, + {WCD939X_MICB4, 0x00}, + {WCD939X_CTL, 0x2a}, + {WCD939X_VBG_FINE_ADJ, 0x55}, + {WCD939X_VDDCX_ADJUST, 0x01}, + {WCD939X_DISABLE_LDOL, 0x00}, + {WCD939X_CTL_CLK, 0x00}, + {WCD939X_CTL_ANA, 0x00}, + {WCD939X_ZDET_VNEG_CTL, 0x00}, + {WCD939X_ZDET_BIAS_CTL, 0x46}, + {WCD939X_CTL_BCS, 0x00}, + {WCD939X_MOISTURE_DET_FSM_STATUS, 0x00}, + {WCD939X_TEST_CTL, 0x00}, + {WCD939X_MODE, 0x2b}, + {WCD939X_LDOH_BIAS, 0x68}, + {WCD939X_STB_LOADS, 0x00}, + {WCD939X_SLOWRAMP, 0x50}, + {WCD939X_TEST_CTL_1, 0x1a}, + {WCD939X_TEST_CTL_2, 0x00}, + {WCD939X_TEST_CTL_3, 0xa4}, + {WCD939X_MICB2_TEST_CTL_1, 0x1a}, + {WCD939X_MICB2_TEST_CTL_2, 0x00}, + {WCD939X_MICB2_TEST_CTL_3, 0x24}, + {WCD939X_MICB3_TEST_CTL_1, 0x9a}, + {WCD939X_MICB3_TEST_CTL_2, 0x80}, + {WCD939X_MICB3_TEST_CTL_3, 0x24}, + {WCD939X_MICB4_TEST_CTL_1, 0x1a}, + {WCD939X_MICB4_TEST_CTL_2, 0x80}, + {WCD939X_MICB4_TEST_CTL_3, 0x24}, + {WCD939X_ADC_VCM, 0x39}, + {WCD939X_BIAS_ATEST, 0xe0}, + {WCD939X_SPARE1, 0x00}, + {WCD939X_SPARE2, 0x00}, + {WCD939X_TXFE_DIV_CTL, 0x22}, + {WCD939X_TXFE_DIV_START, 0x00}, + {WCD939X_SPARE3, 0x00}, + {WCD939X_SPARE4, 0x00}, + {WCD939X_TEST_EN, 0xcc}, + {WCD939X_ADC_IB, 0xe9}, + {WCD939X_ATEST_REFCTL, 0x0b}, + {WCD939X_TX_1_2_TEST_CTL, 0x38}, + {WCD939X_TEST_BLK_EN1, 0xff}, + {WCD939X_TXFE1_CLKDIV, 0x00}, + {WCD939X_SAR2_ERR, 0x00}, + {WCD939X_SAR1_ERR, 0x00}, + {WCD939X_TX_3_4_TEST_EN, 0xcc}, + {WCD939X_TX_3_4_ADC_IB, 0xe9}, + {WCD939X_TX_3_4_ATEST_REFCTL, 0x0b}, + {WCD939X_TX_3_4_TEST_CTL, 0x38}, + {WCD939X_TEST_BLK_EN3, 0xff}, + {WCD939X_TXFE3_CLKDIV, 0x00}, + {WCD939X_SAR4_ERR, 0x00}, + {WCD939X_SAR3_ERR, 0x00}, + {WCD939X_TEST_BLK_EN2, 0xfb}, + {WCD939X_TXFE2_CLKDIV, 0x00}, + {WCD939X_TX_3_4_SPARE1, 0x00}, + {WCD939X_TEST_BLK_EN4, 0xfb}, + {WCD939X_TXFE4_CLKDIV, 0x00}, + {WCD939X_TX_3_4_SPARE2, 0x00}, + {WCD939X_MODE_1, 0x40}, + {WCD939X_MODE_2, 0x3a}, + {WCD939X_MODE_3, 0xf0}, + {WCD939X_CTRL_VCL_1, 0x7c}, + {WCD939X_CTRL_VCL_2, 0x82}, + {WCD939X_CTRL_CCL_1, 0x31}, + {WCD939X_CTRL_CCL_2, 0x80}, + {WCD939X_CTRL_CCL_3, 0x80}, + {WCD939X_CTRL_CCL_4, 0x51}, + {WCD939X_CTRL_CCL_5, 0x00}, + {WCD939X_BUCK_TMUX_A_D, 0x00}, + {WCD939X_BUCK_SW_DRV_CNTL, 0x77}, + {WCD939X_SPARE, 0x80}, + {WCD939X_EN, 0x4e}, + {WCD939X_VNEG_CTRL_1, 0x0b}, + {WCD939X_VNEG_CTRL_2, 0x45}, + {WCD939X_VNEG_CTRL_3, 0x14}, + {WCD939X_VNEG_CTRL_4, 0xdb}, + {WCD939X_VNEG_CTRL_5, 0x83}, + {WCD939X_VNEG_CTRL_6, 0x98}, + {WCD939X_VNEG_CTRL_7, 0xa9}, + {WCD939X_VNEG_CTRL_8, 0x68}, + {WCD939X_VNEG_CTRL_9, 0x66}, + {WCD939X_VNEGDAC_CTRL_1, 0xed}, + {WCD939X_VNEGDAC_CTRL_2, 0xf8}, + {WCD939X_VNEGDAC_CTRL_3, 0xa6}, + {WCD939X_CTRL_1, 0x65}, + {WCD939X_FLYBACK_TEST_CTL, 0x02}, + {WCD939X_AUX_SW_CTL, 0x00}, + {WCD939X_PA_AUX_IN_CONN, 0x01}, + {WCD939X_TIMER_DIV, 0x32}, + {WCD939X_OCP_CTL, 0x1f}, + {WCD939X_OCP_COUNT, 0x77}, + {WCD939X_BIAS_EAR_DAC, 0xa0}, + {WCD939X_BIAS_EAR_AMP, 0xaa}, + {WCD939X_BIAS_HPH_LDO, 0xa9}, + {WCD939X_BIAS_HPH_PA, 0xaa}, + {WCD939X_BIAS_HPH_RDACBUFF_CNP2, 0xca}, + {WCD939X_BIAS_HPH_RDAC_LDO, 0x88}, + {WCD939X_BIAS_HPH_CNP1, 0x82}, + {WCD939X_BIAS_HPH_LOWPOWER, 0x82}, + {WCD939X_BIAS_AUX_DAC, 0xa0}, + {WCD939X_BIAS_AUX_AMP, 0xaa}, + {WCD939X_BIAS_VNEGDAC_BLEEDER, 0x50}, + {WCD939X_BIAS_MISC, 0x00}, + {WCD939X_BIAS_BUCK_RST, 0x08}, + {WCD939X_BIAS_BUCK_VREF_ERRAMP, 0x44}, + {WCD939X_BIAS_FLYB_ERRAMP, 0x40}, + {WCD939X_BIAS_FLYB_BUFF, 0xaa}, + {WCD939X_BIAS_FLYB_MID_RST, 0x14}, + {WCD939X_L_STATUS, 0x04}, + {WCD939X_R_STATUS, 0x04}, + {WCD939X_CNP_EN, 0x80}, + {WCD939X_CNP_WG_CTL, 0x9a}, + {WCD939X_CNP_WG_TIME, 0x14}, + {WCD939X_HPH_OCP_CTL, 0x28}, + {WCD939X_AUTO_CHOP, 0x56}, + {WCD939X_CHOP_CTL, 0x83}, + {WCD939X_PA_CTL1, 0x46}, + {WCD939X_PA_CTL2, 0x50}, + {WCD939X_L_EN, 0x80}, + {WCD939X_L_TEST, 0xe0}, + {WCD939X_L_ATEST, 0x50}, + {WCD939X_R_EN, 0x80}, + {WCD939X_R_TEST, 0xe0}, + {WCD939X_R_ATEST, 0x50}, + {WCD939X_RDAC_CLK_CTL1, 0x80}, + {WCD939X_RDAC_CLK_CTL2, 0x0b}, + {WCD939X_RDAC_LDO_CTL, 0x33}, + {WCD939X_RDAC_CHOP_CLK_LP_CTL, 0x00}, + {WCD939X_REFBUFF_UHQA_CTL, 0x00}, + {WCD939X_REFBUFF_LP_CTL, 0x8e}, + {WCD939X_L_DAC_CTL, 0x20}, + {WCD939X_R_DAC_CTL, 0x20}, + {WCD939X_HPHLR_SURGE_COMP_SEL, 0x55}, + {WCD939X_HPHLR_SURGE_EN, 0x19}, + {WCD939X_HPHLR_SURGE_MISC1, 0xa0}, + {WCD939X_HPHLR_SURGE_STATUS, 0x00}, + {WCD939X_EAR_EN_REG, 0x22}, + {WCD939X_EAR_PA_CON, 0x44}, + {WCD939X_EAR_SP_CON, 0xdb}, + {WCD939X_EAR_DAC_CON, 0x80}, + {WCD939X_EAR_CNP_FSM_CON, 0xb2}, + {WCD939X_EAR_TEST_CTL, 0x00}, + {WCD939X_STATUS_REG_1, 0x00}, + {WCD939X_STATUS_REG_2, 0x08}, + {WCD939X_FLYBACK_NEW_CTRL_2, 0x00}, + {WCD939X_FLYBACK_NEW_CTRL_3, 0x00}, + {WCD939X_FLYBACK_NEW_CTRL_4, 0x44}, + {WCD939X_ANA_NEW_PAGE, 0x00}, + {WCD939X_ANA_HPH2, 0x00}, + {WCD939X_ANA_HPH3, 0x00}, + {WCD939X_SLEEP_CTL, 0x18}, + {WCD939X_WATCHDOG_CTL, 0x00}, + {WCD939X_ELECT_REM_CLAMP_CTL, 0x00}, + {WCD939X_CTL_1, 0x02}, + {WCD939X_CTL_2, 0x05}, + {WCD939X_PLUG_DETECT_CTL, 0xe9}, + {WCD939X_ZDET_ANA_CTL, 0x0f}, + {WCD939X_ZDET_RAMP_CTL, 0x00}, + {WCD939X_FSM_STATUS, 0x00}, + {WCD939X_ADC_RESULT, 0x00}, + {WCD939X_TX_CH12_MUX, 0x11}, + {WCD939X_TX_CH34_MUX, 0x23}, + {WCD939X_DIE_CRK_DET_EN, 0x00}, + {WCD939X_DIE_CRK_DET_OUT, 0x00}, + {WCD939X_RDAC_GAIN_CTL, 0x00}, + {WCD939X_PA_GAIN_CTL_L, 0x00}, + {WCD939X_RDAC_VREF_CTL, 0x08}, + {WCD939X_RDAC_OVERRIDE_CTL, 0x00}, + {WCD939X_PA_GAIN_CTL_R, 0x00}, + {WCD939X_PA_MISC1, 0x32}, + {WCD939X_PA_MISC2, 0x00}, + {WCD939X_PA_RDAC_MISC, 0x00}, + {WCD939X_HPH_TIMER1, 0xfe}, + {WCD939X_HPH_TIMER2, 0x02}, + {WCD939X_HPH_TIMER3, 0x4e}, + {WCD939X_HPH_TIMER4, 0x54}, + {WCD939X_PA_RDAC_MISC2, 0x0b}, + {WCD939X_PA_RDAC_MISC3, 0x00}, + {WCD939X_RDAC_HD2_CTL_L, 0xa0}, + {WCD939X_RDAC_HD2_CTL_R, 0xa0}, + {WCD939X_HPH_RDAC_BIAS_LOHIFI, 0x64}, + {WCD939X_HPH_RDAC_BIAS_ULP, 0x01}, + {WCD939X_HPH_RDAC_LDO_LP, 0x11}, + {WCD939X_MOISTURE_DET_DC_CTRL, 0x57}, + {WCD939X_MOISTURE_DET_POLLING_CTRL, 0x01}, + {WCD939X_MECH_DET_CURRENT, 0x00}, + {WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW, 0x47}, + {WCD939X_EAR_CHOPPER_CON, 0xa8}, + {WCD939X_CNP_VCM_CON1, 0x42}, + {WCD939X_CNP_VCM_CON2, 0x22}, + {WCD939X_EAR_DYNAMIC_BIAS, 0x00}, + {WCD939X_WATCHDOG_CTL_1, 0x0a}, + {WCD939X_WATCHDOG_CTL_2, 0x0a}, + {WCD939X_DIE_CRK_DET_INT1, 0x02}, + {WCD939X_DIE_CRK_DET_INT2, 0x60}, + {WCD939X_TXFE_DIVSTOP_L2, 0xff}, + {WCD939X_TXFE_DIVSTOP_L1, 0x7f}, + {WCD939X_TXFE_DIVSTOP_L0, 0x3f}, + {WCD939X_TXFE_DIVSTOP_ULP1P2M, 0x1f}, + {WCD939X_TXFE_DIVSTOP_ULP0P6M, 0x0f}, + {WCD939X_TXFE_ICTRL_STG1_L2L1, 0xd7}, + {WCD939X_TXFE_ICTRL_STG1_L0, 0xc8}, + {WCD939X_TXFE_ICTRL_STG1_ULP, 0xc6}, + {WCD939X_TXFE_ICTRL_STG2MAIN_L2L1, 0x95}, + {WCD939X_TXFE_ICTRL_STG2MAIN_L0, 0x6a}, + {WCD939X_TXFE_ICTRL_STG2MAIN_ULP, 0x05}, + {WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0, 0xa5}, + {WCD939X_TXFE_ICTRL_STG2CASC_ULP, 0x13}, + {WCD939X_TXADC_SCBIAS_L2L1, 0x88}, + {WCD939X_TXADC_SCBIAS_L0ULP, 0x42}, + {WCD939X_TXADC_INT_L2, 0xff}, + {WCD939X_TXADC_INT_L1, 0x64}, + {WCD939X_TXADC_INT_L0, 0x64}, + {WCD939X_TXADC_INT_ULP, 0x77}, + {WCD939X_DIGITAL_PAGE, 0x00}, + {WCD939X_CHIP_ID0, 0x00}, + {WCD939X_CHIP_ID1, 0x00}, + {WCD939X_CHIP_ID2, 0x0e}, + {WCD939X_CHIP_ID3, 0x01}, + {WCD939X_SWR_TX_CLK_RATE, 0x00}, + {WCD939X_CDC_RST_CTL, 0x03}, + {WCD939X_TOP_CLK_CFG, 0x00}, + {WCD939X_CDC_ANA_CLK_CTL, 0x00}, + {WCD939X_CDC_DIG_CLK_CTL, 0xf0}, + {WCD939X_SWR_RST_EN, 0x00}, + {WCD939X_CDC_PATH_MODE, 0x55}, + {WCD939X_CDC_RX_RST, 0x00}, + {WCD939X_CDC_RX0_CTL, 0xfc}, + {WCD939X_CDC_RX1_CTL, 0xfc}, + {WCD939X_CDC_RX2_CTL, 0xfc}, + {WCD939X_CDC_TX_ANA_MODE_0_1, 0x00}, + {WCD939X_CDC_TX_ANA_MODE_2_3, 0x00}, + {WCD939X_CDC_COMP_CTL_0, 0x00}, + {WCD939X_CDC_ANA_TX_CLK_CTL, 0x1e}, + {WCD939X_CDC_HPH_DSM_A1_0, 0x00}, + {WCD939X_CDC_HPH_DSM_A1_1, 0x01}, + {WCD939X_CDC_HPH_DSM_A2_0, 0x63}, + {WCD939X_CDC_HPH_DSM_A2_1, 0x04}, + {WCD939X_CDC_HPH_DSM_A3_0, 0xac}, + {WCD939X_CDC_HPH_DSM_A3_1, 0x04}, + {WCD939X_CDC_HPH_DSM_A4_0, 0x1a}, + {WCD939X_CDC_HPH_DSM_A4_1, 0x03}, + {WCD939X_CDC_HPH_DSM_A5_0, 0xbc}, + {WCD939X_CDC_HPH_DSM_A5_1, 0x02}, + {WCD939X_CDC_HPH_DSM_A6_0, 0xc7}, + {WCD939X_CDC_HPH_DSM_A7_0, 0xf8}, + {WCD939X_CDC_HPH_DSM_C_0, 0x47}, + {WCD939X_CDC_HPH_DSM_C_1, 0x43}, + {WCD939X_CDC_HPH_DSM_C_2, 0xb1}, + {WCD939X_CDC_HPH_DSM_C_3, 0x17}, + {WCD939X_CDC_HPH_DSM_R1, 0x4d}, + {WCD939X_CDC_HPH_DSM_R2, 0x29}, + {WCD939X_CDC_HPH_DSM_R3, 0x34}, + {WCD939X_CDC_HPH_DSM_R4, 0x59}, + {WCD939X_CDC_HPH_DSM_R5, 0x66}, + {WCD939X_CDC_HPH_DSM_R6, 0x87}, + {WCD939X_CDC_HPH_DSM_R7, 0x64}, + {WCD939X_CDC_EAR_DSM_A1_0, 0x00}, + {WCD939X_CDC_EAR_DSM_A1_1, 0x01}, + {WCD939X_CDC_EAR_DSM_A2_0, 0x96}, + {WCD939X_CDC_EAR_DSM_A2_1, 0x09}, + {WCD939X_CDC_EAR_DSM_A3_0, 0xab}, + {WCD939X_CDC_EAR_DSM_A3_1, 0x05}, + {WCD939X_CDC_EAR_DSM_A4_0, 0x1c}, + {WCD939X_CDC_EAR_DSM_A4_1, 0x02}, + {WCD939X_CDC_EAR_DSM_A5_0, 0x17}, + {WCD939X_CDC_EAR_DSM_A5_1, 0x02}, + {WCD939X_CDC_EAR_DSM_A6_0, 0xaa}, + {WCD939X_CDC_EAR_DSM_A7_0, 0xe3}, + {WCD939X_CDC_EAR_DSM_C_0, 0x69}, + {WCD939X_CDC_EAR_DSM_C_1, 0x54}, + {WCD939X_CDC_EAR_DSM_C_2, 0x02}, + {WCD939X_CDC_EAR_DSM_C_3, 0x15}, + {WCD939X_CDC_EAR_DSM_R1, 0xa4}, + {WCD939X_CDC_EAR_DSM_R2, 0xb5}, + {WCD939X_CDC_EAR_DSM_R3, 0x86}, + {WCD939X_CDC_EAR_DSM_R4, 0x85}, + {WCD939X_CDC_EAR_DSM_R5, 0xaa}, + {WCD939X_CDC_EAR_DSM_R6, 0xe2}, + {WCD939X_CDC_EAR_DSM_R7, 0x62}, + {WCD939X_CDC_HPH_GAIN_RX_0, 0x55}, + {WCD939X_CDC_HPH_GAIN_RX_1, 0xa9}, + {WCD939X_CDC_HPH_GAIN_DSD_0, 0x3d}, + {WCD939X_CDC_HPH_GAIN_DSD_1, 0x2e}, + {WCD939X_CDC_HPH_GAIN_DSD_2, 0x01}, + {WCD939X_CDC_EAR_GAIN_DSD_0, 0x00}, + {WCD939X_CDC_EAR_GAIN_DSD_1, 0xfc}, + {WCD939X_CDC_EAR_GAIN_DSD_2, 0x01}, + {WCD939X_CDC_HPH_GAIN_CTL, 0x00}, + {WCD939X_CDC_EAR_GAIN_CTL, 0x00}, + {WCD939X_CDC_EAR_PATH_CTL, 0x00}, + {WCD939X_CDC_SWR_CLH, 0x00}, + {WCD939X_SWR_CLH_BYP, 0x00}, + {WCD939X_CDC_TX0_CTL, 0x68}, + {WCD939X_CDC_TX1_CTL, 0x68}, + {WCD939X_CDC_TX2_CTL, 0x68}, + {WCD939X_CDC_TX_RST, 0x00}, + {WCD939X_CDC_REQ_CTL, 0x01}, + {WCD939X_CDC_RST, 0x00}, + {WCD939X_CDC_AMIC_CTL, 0x0f}, + {WCD939X_CDC_DMIC_CTL, 0x04}, + {WCD939X_CDC_DMIC1_CTL, 0x01}, + {WCD939X_CDC_DMIC2_CTL, 0x01}, + {WCD939X_CDC_DMIC3_CTL, 0x01}, + {WCD939X_CDC_DMIC4_CTL, 0x01}, + {WCD939X_EFUSE_PRG_CTL, 0x00}, + {WCD939X_EFUSE_CTL, 0x2b}, + {WCD939X_CDC_DMIC_RATE_1_2, 0x11}, + {WCD939X_CDC_DMIC_RATE_3_4, 0x11}, + {WCD939X_PDM_WD_CTL0, 0x00}, + {WCD939X_PDM_WD_CTL1, 0x00}, + {WCD939X_PDM_WD_CTL2, 0x00}, + {WCD939X_INTR_MODE, 0x00}, + {WCD939X_INTR_MASK_0, 0xff}, + {WCD939X_INTR_MASK_1, 0xe7}, + {WCD939X_INTR_MASK_2, 0x0e}, + {WCD939X_INTR_STATUS_0, 0x00}, + {WCD939X_INTR_STATUS_1, 0x00}, + {WCD939X_INTR_STATUS_2, 0x00}, + {WCD939X_INTR_CLEAR_0, 0x00}, + {WCD939X_INTR_CLEAR_1, 0x00}, + {WCD939X_INTR_CLEAR_2, 0x00}, + {WCD939X_INTR_LEVEL_0, 0x00}, + {WCD939X_INTR_LEVEL_1, 0x00}, + {WCD939X_INTR_LEVEL_2, 0x00}, + {WCD939X_INTR_SET_0, 0x00}, + {WCD939X_INTR_SET_1, 0x00}, + {WCD939X_INTR_SET_2, 0x00}, + {WCD939X_INTR_TEST_0, 0x00}, + {WCD939X_INTR_TEST_1, 0x00}, + {WCD939X_INTR_TEST_2, 0x00}, + {WCD939X_TX_MODE_DBG_EN, 0x00}, + {WCD939X_TX_MODE_DBG_0_1, 0x00}, + {WCD939X_TX_MODE_DBG_2_3, 0x00}, + {WCD939X_LB_IN_SEL_CTL, 0x00}, + {WCD939X_LOOP_BACK_MODE, 0x00}, + {WCD939X_SWR_DAC_TEST, 0x00}, + {WCD939X_SWR_HM_TEST_RX_0, 0x40}, + {WCD939X_SWR_HM_TEST_TX_0, 0x40}, + {WCD939X_SWR_HM_TEST_RX_1, 0x00}, + {WCD939X_SWR_HM_TEST_TX_1, 0x00}, + {WCD939X_SWR_HM_TEST_TX_2, 0x00}, + {WCD939X_SWR_HM_TEST_0, 0x00}, + {WCD939X_SWR_HM_TEST_1, 0x00}, + {WCD939X_PAD_CTL_SWR_0, 0x8f}, + {WCD939X_PAD_CTL_SWR_1, 0x06}, + {WCD939X_I2C_CTL, 0x00}, + {WCD939X_CDC_TX_TANGGU_SW_MODE, 0x00}, + {WCD939X_EFUSE_TEST_CTL_0, 0x00}, + {WCD939X_EFUSE_TEST_CTL_1, 0x00}, + {WCD939X_EFUSE_T_DATA_0, 0x00}, + {WCD939X_EFUSE_T_DATA_1, 0x00}, + {WCD939X_PAD_CTL_PDM_RX0, 0xf1}, + {WCD939X_PAD_CTL_PDM_RX1, 0xf1}, + {WCD939X_PAD_CTL_PDM_TX0, 0xf1}, + {WCD939X_PAD_CTL_PDM_TX1, 0xf1}, + {WCD939X_PAD_CTL_PDM_TX2, 0xf1}, + {WCD939X_PAD_INP_DIS_0, 0x00}, + {WCD939X_PAD_INP_DIS_1, 0x00}, + {WCD939X_DRIVE_STRENGTH_0, 0x00}, + {WCD939X_DRIVE_STRENGTH_1, 0x00}, + {WCD939X_DRIVE_STRENGTH_2, 0x00}, + {WCD939X_RX_DATA_EDGE_CTL, 0x1f}, + {WCD939X_TX_DATA_EDGE_CTL, 0x80}, + {WCD939X_GPIO_MODE, 0x00}, + {WCD939X_PIN_CTL_OE, 0x00}, + {WCD939X_PIN_CTL_DATA_0, 0x00}, + {WCD939X_PIN_CTL_DATA_1, 0x00}, + {WCD939X_PIN_STATUS_0, 0x00}, + {WCD939X_PIN_STATUS_1, 0x00}, + {WCD939X_DIG_DEBUG_CTL, 0x00}, + {WCD939X_DIG_DEBUG_EN, 0x00}, + {WCD939X_ANA_CSR_DBG_ADD, 0x00}, + {WCD939X_ANA_CSR_DBG_CTL, 0x48}, + {WCD939X_SSP_DBG, 0x00}, + {WCD939X_MODE_STATUS_0, 0x00}, + {WCD939X_MODE_STATUS_1, 0x00}, + {WCD939X_SPARE_0, 0x00}, + {WCD939X_SPARE_1, 0x00}, + {WCD939X_SPARE_2, 0x00}, + {WCD939X_EFUSE_REG_0, 0x00}, + {WCD939X_EFUSE_REG_1, 0xff}, + {WCD939X_EFUSE_REG_2, 0xff}, + {WCD939X_EFUSE_REG_3, 0xff}, + {WCD939X_EFUSE_REG_4, 0xff}, + {WCD939X_EFUSE_REG_5, 0xff}, + {WCD939X_EFUSE_REG_6, 0xff}, + {WCD939X_EFUSE_REG_7, 0xff}, + {WCD939X_EFUSE_REG_8, 0xff}, + {WCD939X_EFUSE_REG_9, 0xff}, + {WCD939X_EFUSE_REG_10, 0xff}, + {WCD939X_EFUSE_REG_11, 0xff}, + {WCD939X_EFUSE_REG_12, 0xff}, + {WCD939X_EFUSE_REG_13, 0xff}, + {WCD939X_EFUSE_REG_14, 0xff}, + {WCD939X_EFUSE_REG_15, 0xff}, + {WCD939X_EFUSE_REG_16, 0xff}, + {WCD939X_EFUSE_REG_17, 0xff}, + {WCD939X_EFUSE_REG_18, 0xff}, + {WCD939X_EFUSE_REG_19, 0xff}, + {WCD939X_EFUSE_REG_20, 0x0e}, + {WCD939X_EFUSE_REG_21, 0x00}, + {WCD939X_EFUSE_REG_22, 0x00}, + {WCD939X_EFUSE_REG_23, 0xf6}, + {WCD939X_EFUSE_REG_24, 0x18}, + {WCD939X_EFUSE_REG_25, 0x00}, + {WCD939X_EFUSE_REG_26, 0x00}, + {WCD939X_EFUSE_REG_27, 0x00}, + {WCD939X_EFUSE_REG_28, 0x00}, + {WCD939X_EFUSE_REG_29, 0x0f}, + {WCD939X_EFUSE_REG_30, 0x49}, + {WCD939X_EFUSE_REG_31, 0x00}, + {WCD939X_TX_REQ_FB_CTL_0, 0x88}, + {WCD939X_TX_REQ_FB_CTL_1, 0x88}, + {WCD939X_TX_REQ_FB_CTL_2, 0x88}, + {WCD939X_TX_REQ_FB_CTL_3, 0x88}, + {WCD939X_TX_REQ_FB_CTL_4, 0x88}, + {WCD939X_DEM_BYPASS_DATA0, 0x55}, + {WCD939X_DEM_BYPASS_DATA1, 0x55}, + {WCD939X_DEM_BYPASS_DATA2, 0x55}, + {WCD939X_DEM_BYPASS_DATA3, 0x01}, + {WCD939X_DEM_SECOND_ORDER, 0x03}, + {WCD939X_DSM_CTRL, 0x00}, + {WCD939X_DSM_0_STATIC_DATA_0, 0x00}, + {WCD939X_DSM_0_STATIC_DATA_1, 0x00}, + {WCD939X_DSM_0_STATIC_DATA_2, 0x00}, + {WCD939X_DSM_0_STATIC_DATA_3, 0x00}, + {WCD939X_DSM_1_STATIC_DATA_0, 0x00}, + {WCD939X_DSM_1_STATIC_DATA_1, 0x00}, + {WCD939X_DSM_1_STATIC_DATA_2, 0x00}, + {WCD939X_DSM_1_STATIC_DATA_3, 0x00}, + {WCD939X_RX_TOP_PAGE, 0x00}, + {WCD939X_TOP_CFG0, 0x00}, + {WCD939X_HPHL_COMP_WR_LSB, 0x00}, + {WCD939X_HPHL_COMP_WR_MSB, 0x00}, + {WCD939X_HPHL_COMP_LUT, 0x00}, + {WCD939X_HPHL_COMP_RD_LSB, 0x00}, + {WCD939X_HPHL_COMP_RD_MSB, 0x00}, + {WCD939X_HPHR_COMP_WR_LSB, 0x00}, + {WCD939X_HPHR_COMP_WR_MSB, 0x00}, + {WCD939X_HPHR_COMP_LUT, 0x00}, + {WCD939X_HPHR_COMP_RD_LSB, 0x00}, + {WCD939X_HPHR_COMP_RD_MSB, 0x00}, + {WCD939X_DSD0_DEBUG_CFG1, 0x05}, + {WCD939X_DSD0_DEBUG_CFG2, 0x08}, + {WCD939X_DSD0_DEBUG_CFG3, 0x00}, + {WCD939X_DSD0_DEBUG_CFG4, 0x00}, + {WCD939X_DSD0_DEBUG_CFG5, 0x00}, + {WCD939X_DSD0_DEBUG_CFG6, 0x00}, + {WCD939X_DSD1_DEBUG_CFG1, 0x03}, + {WCD939X_DSD1_DEBUG_CFG2, 0x08}, + {WCD939X_DSD1_DEBUG_CFG3, 0x00}, + {WCD939X_DSD1_DEBUG_CFG4, 0x00}, + {WCD939X_DSD1_DEBUG_CFG5, 0x00}, + {WCD939X_DSD1_DEBUG_CFG6, 0x00}, + {WCD939X_HPHL_RX_PATH_CFG0, 0x00}, + {WCD939X_HPHL_RX_PATH_CFG1, 0x00}, + {WCD939X_HPHR_RX_PATH_CFG0, 0x00}, + {WCD939X_HPHR_RX_PATH_CFG1, 0x00}, + {WCD939X_RX_PATH_CFG2, 0x00}, + {WCD939X_HPHL_RX_PATH_SEC0, 0x00}, + {WCD939X_HPHL_RX_PATH_SEC1, 0x00}, + {WCD939X_HPHL_RX_PATH_SEC2, 0x00}, + {WCD939X_HPHL_RX_PATH_SEC3, 0x00}, + {WCD939X_HPHR_RX_PATH_SEC0, 0x00}, + {WCD939X_HPHR_RX_PATH_SEC1, 0x00}, + {WCD939X_HPHR_RX_PATH_SEC2, 0x00}, + {WCD939X_HPHR_RX_PATH_SEC3, 0x00}, + {WCD939X_RX_PATH_SEC4, 0x00}, + {WCD939X_RX_PATH_SEC5, 0x00}, + {WCD939X_CTL0, 0x60}, + {WCD939X_CTL1, 0xdb}, + {WCD939X_CTL2, 0xff}, + {WCD939X_CTL3, 0x35}, + {WCD939X_CTL4, 0xff}, + {WCD939X_CTL5, 0x00}, + {WCD939X_CTL6, 0x01}, + {WCD939X_CTL7, 0x08}, + {WCD939X_CTL8, 0x00}, + {WCD939X_CTL9, 0x00}, + {WCD939X_CTL10, 0x06}, + {WCD939X_CTL11, 0x12}, + {WCD939X_CTL12, 0x1e}, + {WCD939X_CTL13, 0x2a}, + {WCD939X_CTL14, 0x36}, + {WCD939X_CTL15, 0x3c}, + {WCD939X_CTL16, 0xc4}, + {WCD939X_CTL17, 0x00}, + {WCD939X_CTL18, 0x0c}, + {WCD939X_CTL19, 0x16}, + {WCD939X_R_CTL0, 0x60}, + {WCD939X_R_CTL1, 0xdb}, + {WCD939X_R_CTL2, 0xff}, + {WCD939X_R_CTL3, 0x35}, + {WCD939X_R_CTL4, 0xff}, + {WCD939X_R_CTL5, 0x00}, + {WCD939X_R_CTL6, 0x01}, + {WCD939X_R_CTL7, 0x08}, + {WCD939X_R_CTL8, 0x00}, + {WCD939X_R_CTL9, 0x00}, + {WCD939X_R_CTL10, 0x06}, + {WCD939X_R_CTL11, 0x12}, + {WCD939X_R_CTL12, 0x1e}, + {WCD939X_R_CTL13, 0x2a}, + {WCD939X_R_CTL14, 0x36}, + {WCD939X_R_CTL15, 0x3c}, + {WCD939X_R_CTL16, 0xc4}, + {WCD939X_R_CTL17, 0x00}, + {WCD939X_R_CTL18, 0x0c}, + {WCD939X_R_CTL19, 0x16}, + {WCD939X_PATH_CTL, 0x00}, + {WCD939X_CFG0, 0x07}, + {WCD939X_CFG1, 0x3c}, + {WCD939X_CFG2, 0x00}, + {WCD939X_CFG3, 0x00}, + {WCD939X_DSD_HPHL_PATH_CTL, 0x00}, + {WCD939X_DSD_HPHL_CFG0, 0x00}, + {WCD939X_DSD_HPHL_CFG1, 0x00}, + {WCD939X_DSD_HPHL_CFG2, 0x22}, + {WCD939X_DSD_HPHL_CFG3, 0x00}, + {WCD939X_CFG4, 0x1a}, + {WCD939X_CFG5, 0x00}, + {WCD939X_DSD_HPHR_PATH_CTL, 0x00}, + {WCD939X_DSD_HPHR_CFG0, 0x00}, + {WCD939X_DSD_HPHR_CFG1, 0x00}, + {WCD939X_DSD_HPHR_CFG2, 0x22}, + {WCD939X_DSD_HPHR_CFG3, 0x00}, + {WCD939X_DSD_HPHR_CFG4, 0x1a}, + {WCD939X_DSD_HPHR_CFG5, 0x00}, +}; + +static bool wcd939x_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg <= WCD939X_BASE + 1) + return 0; + + return wcd939x_reg_access[WCD939X_REG(reg)] & WR_REG; +} + +static bool wcd939x_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg <= WCD939X_BASE + 1) + return 0; + + return ((wcd939x_reg_access[WCD939X_REG(reg)] & RD_REG) && + !(wcd939x_reg_access[WCD939X_REG(reg)] & WR_REG)); +} + +struct regmap_config wcd939x_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd939x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd939x_defaults), + .max_register = WCD939X_MAX_REGISTER, + .volatile_reg = wcd939x_volatile_register, + .writeable_reg = wcd939x_writeable_register, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .can_multi_write = true, + .use_single_read = true, +}; diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-slave.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-slave.c new file mode 100644 index 0000000000..2fd78d0015 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-slave.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_DEBUG_FS +#include +#include + +#define SWR_SLV_MAX_REG_ADDR 0x2009 +#define SWR_SLV_START_REG_ADDR 0x40 +#define SWR_SLV_MAX_BUF_LEN 20 +#define BYTES_PER_LINE 12 +#define SWR_SLV_RD_BUF_LEN 8 +#define SWR_SLV_WR_BUF_LEN 32 +#define SWR_SLV_MAX_DEVICES 2 +#endif /* CONFIG_DEBUG_FS */ + +#define SWR_MAX_RETRY 5 + +struct wcd939x_slave_priv { + struct swr_device *swr_slave; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_wcd939x_dent; + struct dentry *debugfs_peek; + struct dentry *debugfs_poke; + struct dentry *debugfs_reg_dump; + unsigned int read_data; +#endif +}; + +#ifdef CONFIG_DEBUG_FS +static int codec_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int get_parameters(char *buf, u32 *param1, int num_of_par) +{ + char *token = NULL; + int base = 0, cnt = 0; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +static bool is_swr_slv_reg_readable(int reg) +{ + int ret = true; + + if (((reg > 0x46) && (reg < 0x4A)) || + ((reg > 0x4A) && (reg < 0x50)) || + ((reg > 0x55) && (reg < 0xD0)) || + ((reg > 0xD0) && (reg < 0xE0)) || + ((reg > 0xE0) && (reg < 0xF0)) || + ((reg > 0xF0) && (reg < 0x100)) || + ((reg > 0x105) && (reg < 0x120)) || + ((reg > 0x205) && (reg < 0x220)) || + ((reg > 0x305) && (reg < 0x320)) || + ((reg > 0x405) && (reg < 0x420)) || + ((reg > 0x128) && (reg < 0x130)) || + ((reg > 0x228) && (reg < 0x230)) || + ((reg > 0x328) && (reg < 0x330)) || + ((reg > 0x428) && (reg < 0x430)) || + ((reg > 0x138) && (reg < 0x205)) || + ((reg > 0x238) && (reg < 0x305)) || + ((reg > 0x338) && (reg < 0x405)) || + ((reg > 0x438) && (reg < 0x2000))) + ret = false; + + return ret; +} + +static ssize_t wcd939x_swrslave_reg_show(struct swr_device *pdev, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[SWR_SLV_MAX_BUF_LEN]; + + if (!ubuf || !ppos) + return 0; + + for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR); + i <= SWR_SLV_MAX_REG_ADDR; i++) { + if (!is_swr_slv_reg_readable(i)) + continue; + swr_read(pdev, pdev->dev_num, i, ®_val, 1); + len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, + (reg_val & 0xFF)); + if (((total + len) >= count - 1) || (len < 0)) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + pr_err_ratelimited("%s: fail to copy reg dump\n", __func__); + total = -EFAULT; + goto copy_err; + } + total += len; + *ppos += len; + } + +copy_err: + *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE; + return total; +} + +static ssize_t codec_debug_dump(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct swr_device *pdev; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + return wcd939x_swrslave_reg_show(pdev, ubuf, count, ppos); +} + +static ssize_t codec_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char lbuf[SWR_SLV_RD_BUF_LEN]; + struct swr_device *pdev = NULL; + struct wcd939x_slave_priv *wcd939x_slave = NULL; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd939x_slave = swr_get_dev_data(pdev); + if (!wcd939x_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + snprintf(lbuf, sizeof(lbuf), "0x%x\n", + (wcd939x_slave->read_data & 0xFF)); + + return simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); +} + +static ssize_t codec_debug_peek_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev = NULL; + struct wcd939x_slave_priv *wcd939x_slave = NULL; + + if (!cnt || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wcd939x_slave = swr_get_dev_data(pdev); + if (!wcd939x_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 1); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))) + return -EINVAL; + swr_read(pdev, pdev->dev_num, param[0], &wcd939x_slave->read_data, 1); + if (rc == 0) + rc = cnt; + else + pr_err_ratelimited("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static ssize_t codec_debug_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev; + + if (!file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 2); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && + (param[1] <= 0xFF) && (rc == 0))) + return -EINVAL; + swr_write(pdev, pdev->dev_num, param[0], ¶m[1]); + if (rc == 0) + rc = cnt; + else + pr_err_ratelimited("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static const struct file_operations codec_debug_write_ops = { + .open = codec_debug_open, + .write = codec_debug_write, +}; + +static const struct file_operations codec_debug_read_ops = { + .open = codec_debug_open, + .read = codec_debug_read, + .write = codec_debug_peek_write, +}; + +static const struct file_operations codec_debug_dump_ops = { + .open = codec_debug_open, + .read = codec_debug_dump, +}; +#endif + +static int wcd939x_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); + int retry = SWR_MAX_RETRY; + + if (!pdev) { + pr_err_ratelimited("%s: invalid swr device handle\n", __func__); + return -EINVAL; + } + + do { + /* Add delay for soundwire enumeration */ + usleep_range(100, 110); + ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); + } while (ret && --retry); + + if (ret) { + dev_dbg(&pdev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, devnum, pdev->addr); + ret = -EPROBE_DEFER; + return ret; + } + pdev->dev_num = devnum; + + return ret; +} + +static void wcd939x_slave_unbind(struct device *dev, + struct device *master, void *data) +{ + struct wcd939x_slave_priv *wcd939x_slave = NULL; + struct swr_device *pdev = to_swr_device(dev); + + wcd939x_slave = swr_get_dev_data(pdev); + if (!wcd939x_slave) { + dev_err_ratelimited(&pdev->dev, "%s: wcd939x_slave is NULL\n", __func__); + return; + } +} + +static const struct swr_device_id wcd939x_swr_id[] = { + {"wcd939x-slave", 0}, + {} +}; + +static const struct of_device_id wcd939x_swr_dt_match[] = { + { + .compatible = "qcom,wcd939x-slave", + }, + {} +}; + +static const struct component_ops wcd939x_slave_comp_ops = { + .bind = wcd939x_slave_bind, + .unbind = wcd939x_slave_unbind, +}; + +static int wcd939x_swr_probe(struct swr_device *pdev) +{ + struct wcd939x_slave_priv *wcd939x_slave = NULL; + + wcd939x_slave = devm_kzalloc(&pdev->dev, + sizeof(struct wcd939x_slave_priv), GFP_KERNEL); + if (!wcd939x_slave) + return -ENOMEM; + + swr_set_dev_data(pdev, wcd939x_slave); + + wcd939x_slave->swr_slave = pdev; + +#ifdef CONFIG_DEBUG_FS + if (!wcd939x_slave->debugfs_wcd939x_dent) { + wcd939x_slave->debugfs_wcd939x_dent = debugfs_create_dir( + dev_name(&pdev->dev), 0); + if (!IS_ERR(wcd939x_slave->debugfs_wcd939x_dent)) { + wcd939x_slave->debugfs_peek = + debugfs_create_file("swrslave_peek", + S_IFREG | 0444, + wcd939x_slave->debugfs_wcd939x_dent, + (void *) pdev, + &codec_debug_read_ops); + + wcd939x_slave->debugfs_poke = + debugfs_create_file("swrslave_poke", + S_IFREG | 0444, + wcd939x_slave->debugfs_wcd939x_dent, + (void *) pdev, + &codec_debug_write_ops); + + wcd939x_slave->debugfs_reg_dump = + debugfs_create_file( + "swrslave_reg_dump", + S_IFREG | 0444, + wcd939x_slave->debugfs_wcd939x_dent, + (void *) pdev, + &codec_debug_dump_ops); + } + } +#endif + + return component_add(&pdev->dev, &wcd939x_slave_comp_ops); +} + +static int wcd939x_swr_remove(struct swr_device *pdev) +{ +#ifdef CONFIG_DEBUG_FS + struct wcd939x_slave_priv *wcd939x_slave = swr_get_dev_data(pdev); + + if (wcd939x_slave) { + debugfs_remove_recursive(wcd939x_slave->debugfs_wcd939x_dent); + wcd939x_slave->debugfs_wcd939x_dent = NULL; + } +#endif + component_del(&pdev->dev, &wcd939x_slave_comp_ops); + swr_set_dev_data(pdev, NULL); + swr_remove_device(pdev); + + return 0; +} + +static struct swr_driver wcd939x_slave_driver = { + .driver = { + .name = "wcd939x-slave", + .owner = THIS_MODULE, + .of_match_table = wcd939x_swr_dt_match, + }, + .probe = wcd939x_swr_probe, + .remove = wcd939x_swr_remove, + .id_table = wcd939x_swr_id, +}; + +static int __init wcd939x_slave_init(void) +{ + return swr_driver_register(&wcd939x_slave_driver); +} + +static void __exit wcd939x_slave_exit(void) +{ + swr_driver_unregister(&wcd939x_slave_driver); +} + +module_init(wcd939x_slave_init); +module_exit(wcd939x_slave_exit); + +MODULE_DESCRIPTION("WCD939X Swr Slave driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-tables.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-tables.c new file mode 100644 index 0000000000..cf40cd45ea --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x-tables.c @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include "wcd939x-registers.h" + +const u8 wcd939x_reg_access[WCD939X_NUM_REGISTERS] = { + [WCD939X_REG(WCD939X_ANA_PAGE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RX_SUPPLIES)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_COMPANDER_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_CH1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_CH2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_CH3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_CH4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB1_MICB2_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB3_DSP_EN_LOGIC)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_MECH)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_ELECT)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_ZDET)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_RESULT_1)] = RD_REG, + [WCD939X_REG(WCD939X_MBHC_RESULT_2)] = RD_REG, + [WCD939X_REG(WCD939X_MBHC_RESULT_3)] = RD_REG, + [WCD939X_REG(WCD939X_MBHC_BTN0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_BTN1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_BTN2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_BTN3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_BTN4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_BTN5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_BTN6)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MBHC_BTN7)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB2_RAMP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VBG_FINE_ADJ)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VDDCX_ADJUST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DISABLE_LDOL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL_CLK)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL_ANA)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ZDET_VNEG_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ZDET_BIAS_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL_BCS)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MOISTURE_DET_FSM_STATUS)] = RD_REG, + [WCD939X_REG(WCD939X_TEST_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MODE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_LDOH_BIAS)] = RD_WR_REG, + [WCD939X_REG(WCD939X_STB_LOADS)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SLOWRAMP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TEST_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TEST_CTL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TEST_CTL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB2_TEST_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB2_TEST_CTL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB2_TEST_CTL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB3_TEST_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB3_TEST_CTL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB3_TEST_CTL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB4_TEST_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB4_TEST_CTL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MICB4_TEST_CTL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ADC_VCM)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_ATEST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SPARE1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SPARE2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_DIV_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_DIV_START)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SPARE3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SPARE4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TEST_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ADC_IB)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ATEST_REFCTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_1_2_TEST_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TEST_BLK_EN1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE1_CLKDIV)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SAR2_ERR)] = RD_REG, + [WCD939X_REG(WCD939X_SAR1_ERR)] = RD_REG, + [WCD939X_REG(WCD939X_TX_3_4_TEST_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_3_4_ADC_IB)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_3_4_ATEST_REFCTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_3_4_TEST_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TEST_BLK_EN3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE3_CLKDIV)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SAR4_ERR)] = RD_REG, + [WCD939X_REG(WCD939X_SAR3_ERR)] = RD_REG, + [WCD939X_REG(WCD939X_TEST_BLK_EN2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE2_CLKDIV)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_3_4_SPARE1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TEST_BLK_EN4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE4_CLKDIV)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_3_4_SPARE2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MODE_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MODE_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MODE_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_VCL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_VCL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_CCL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_CCL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_CCL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_CCL_4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_CCL_5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BUCK_TMUX_A_D)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BUCK_SW_DRV_CNTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SPARE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_6)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_7)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_8)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEG_CTRL_9)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEGDAC_CTRL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEGDAC_CTRL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_VNEGDAC_CTRL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTRL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_FLYBACK_TEST_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_AUX_SW_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_AUX_IN_CONN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TIMER_DIV)] = RD_WR_REG, + [WCD939X_REG(WCD939X_OCP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_OCP_COUNT)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_EAR_DAC)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_EAR_AMP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_HPH_LDO)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_HPH_PA)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_HPH_RDACBUFF_CNP2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_HPH_RDAC_LDO)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_HPH_CNP1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_HPH_LOWPOWER)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_AUX_DAC)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_AUX_AMP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_VNEGDAC_BLEEDER)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_MISC)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_BUCK_RST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_BUCK_VREF_ERRAMP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_FLYB_ERRAMP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_FLYB_BUFF)] = RD_WR_REG, + [WCD939X_REG(WCD939X_BIAS_FLYB_MID_RST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_L_STATUS)] = RD_REG, + [WCD939X_REG(WCD939X_R_STATUS)] = RD_REG, + [WCD939X_REG(WCD939X_CNP_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CNP_WG_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CNP_WG_TIME)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_OCP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_AUTO_CHOP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CHOP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_CTL1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_CTL2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_L_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_L_TEST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_L_ATEST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_TEST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_ATEST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_CLK_CTL1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_CLK_CTL2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_LDO_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_CHOP_CLK_LP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_REFBUFF_UHQA_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_REFBUFF_LP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_L_DAC_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_DAC_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHLR_SURGE_COMP_SEL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHLR_SURGE_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHLR_SURGE_MISC1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHLR_SURGE_STATUS)] = RD_REG, + [WCD939X_REG(WCD939X_EAR_EN_REG)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_PA_CON)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_SP_CON)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_DAC_CON)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_CNP_FSM_CON)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_TEST_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_STATUS_REG_1)] = RD_REG, + [WCD939X_REG(WCD939X_STATUS_REG_2)] = RD_REG, + [WCD939X_REG(WCD939X_FLYBACK_NEW_CTRL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_FLYBACK_NEW_CTRL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_FLYBACK_NEW_CTRL_4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ANA_NEW_PAGE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ANA_HPH2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ANA_HPH3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SLEEP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_WATCHDOG_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ELECT_REM_CLAMP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PLUG_DETECT_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ZDET_ANA_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ZDET_RAMP_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_FSM_STATUS)] = RD_REG, + [WCD939X_REG(WCD939X_ADC_RESULT)] = RD_REG, + [WCD939X_REG(WCD939X_TX_CH12_MUX)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_CH34_MUX)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DIE_CRK_DET_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DIE_CRK_DET_OUT)] = RD_REG, + [WCD939X_REG(WCD939X_RDAC_GAIN_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_GAIN_CTL_L)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_VREF_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_OVERRIDE_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_GAIN_CTL_R)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_MISC1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_MISC2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_RDAC_MISC)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_TIMER1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_TIMER2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_TIMER3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_TIMER4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_RDAC_MISC2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PA_RDAC_MISC3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_HD2_CTL_L)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RDAC_HD2_CTL_R)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_RDAC_BIAS_LOHIFI)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_RDAC_BIAS_ULP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPH_RDAC_LDO_LP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MOISTURE_DET_DC_CTRL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MOISTURE_DET_POLLING_CTRL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MECH_DET_CURRENT)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ZDET_CLK_AND_MOISTURE_CTL_NEW)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_CHOPPER_CON)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CNP_VCM_CON1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CNP_VCM_CON2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EAR_DYNAMIC_BIAS)] = RD_WR_REG, + [WCD939X_REG(WCD939X_WATCHDOG_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_WATCHDOG_CTL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DIE_CRK_DET_INT1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DIE_CRK_DET_INT2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_DIVSTOP_L2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_DIVSTOP_L1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_DIVSTOP_L0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_DIVSTOP_ULP1P2M)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_DIVSTOP_ULP0P6M)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG1_L2L1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG1_L0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG1_ULP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG2MAIN_L2L1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG2MAIN_L0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG2MAIN_ULP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG2CASC_L2L1L0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXFE_ICTRL_STG2CASC_ULP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXADC_SCBIAS_L2L1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXADC_SCBIAS_L0ULP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXADC_INT_L2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXADC_INT_L1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXADC_INT_L0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TXADC_INT_ULP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DIGITAL_PAGE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CHIP_ID0)] = RD_REG, + [WCD939X_REG(WCD939X_CHIP_ID1)] = RD_REG, + [WCD939X_REG(WCD939X_CHIP_ID2)] = RD_REG, + [WCD939X_REG(WCD939X_CHIP_ID3)] = RD_REG, + [WCD939X_REG(WCD939X_SWR_TX_CLK_RATE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_RST_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TOP_CLK_CFG)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_ANA_CLK_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DIG_CLK_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_RST_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_PATH_MODE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_RX_RST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_RX0_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_RX1_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_RX2_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_TX_ANA_MODE_0_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_TX_ANA_MODE_2_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_COMP_CTL_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_ANA_TX_CLK_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A1_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A1_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A2_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A2_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A3_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A3_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A4_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A4_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A5_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A5_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A6_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_A7_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_C_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_C_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_C_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_C_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_R1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_R2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_R3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_R4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_R5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_R6)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_DSM_R7)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A1_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A1_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A2_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A2_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A3_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A3_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A4_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A4_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A5_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A5_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A6_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_A7_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_C_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_C_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_C_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_C_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_R1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_R2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_R3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_R4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_R5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_R6)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_DSM_R7)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_GAIN_RX_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_GAIN_RX_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_GAIN_DSD_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_GAIN_DSD_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_GAIN_DSD_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_GAIN_DSD_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_GAIN_DSD_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_GAIN_DSD_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_HPH_GAIN_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_GAIN_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_EAR_PATH_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_SWR_CLH)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_CLH_BYP)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_TX0_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_TX1_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_TX2_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_TX_RST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_REQ_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_RST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_AMIC_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DMIC_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DMIC1_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DMIC2_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DMIC3_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DMIC4_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EFUSE_PRG_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EFUSE_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DMIC_RATE_1_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_DMIC_RATE_3_4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PDM_WD_CTL0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PDM_WD_CTL1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PDM_WD_CTL2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_MODE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_MASK_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_MASK_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_MASK_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_STATUS_0)] = RD_REG, + [WCD939X_REG(WCD939X_INTR_STATUS_1)] = RD_REG, + [WCD939X_REG(WCD939X_INTR_STATUS_2)] = RD_REG, + [WCD939X_REG(WCD939X_INTR_CLEAR_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_CLEAR_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_CLEAR_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_LEVEL_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_LEVEL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_LEVEL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_SET_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_SET_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_SET_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_TEST_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_TEST_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_INTR_TEST_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_MODE_DBG_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_MODE_DBG_0_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_MODE_DBG_2_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_LB_IN_SEL_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_LOOP_BACK_MODE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_DAC_TEST)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_HM_TEST_RX_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_HM_TEST_TX_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_HM_TEST_RX_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_HM_TEST_TX_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_HM_TEST_TX_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SWR_HM_TEST_0)] = RD_REG, + [WCD939X_REG(WCD939X_SWR_HM_TEST_1)] = RD_REG, + [WCD939X_REG(WCD939X_PAD_CTL_SWR_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PAD_CTL_SWR_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_I2C_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CDC_TX_TANGGU_SW_MODE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EFUSE_TEST_CTL_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EFUSE_TEST_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EFUSE_T_DATA_0)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_T_DATA_1)] = RD_REG, + [WCD939X_REG(WCD939X_PAD_CTL_PDM_RX0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PAD_CTL_PDM_RX1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PAD_CTL_PDM_TX0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PAD_CTL_PDM_TX1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PAD_CTL_PDM_TX2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PAD_INP_DIS_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PAD_INP_DIS_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DRIVE_STRENGTH_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DRIVE_STRENGTH_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DRIVE_STRENGTH_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_DATA_EDGE_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_GPIO_MODE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PIN_CTL_OE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PIN_CTL_DATA_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PIN_CTL_DATA_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PIN_STATUS_0)] = RD_REG, + [WCD939X_REG(WCD939X_PIN_STATUS_1)] = RD_REG, + [WCD939X_REG(WCD939X_DIG_DEBUG_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DIG_DEBUG_EN)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ANA_CSR_DBG_ADD)] = RD_WR_REG, + [WCD939X_REG(WCD939X_ANA_CSR_DBG_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SSP_DBG)] = RD_WR_REG, + [WCD939X_REG(WCD939X_MODE_STATUS_0)] = RD_REG, + [WCD939X_REG(WCD939X_MODE_STATUS_1)] = RD_REG, + [WCD939X_REG(WCD939X_SPARE_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SPARE_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_SPARE_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_0)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_1)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_2)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_3)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_4)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_5)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_6)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_7)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_8)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_9)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_10)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_11)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_12)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_13)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_14)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_15)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_16)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_17)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_18)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_19)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_20)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_21)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_22)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_23)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_24)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_25)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_26)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_27)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_28)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_29)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_30)] = RD_REG, + [WCD939X_REG(WCD939X_EFUSE_REG_31)] = RD_REG, + [WCD939X_REG(WCD939X_TX_REQ_FB_CTL_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_REQ_FB_CTL_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_REQ_FB_CTL_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_REQ_FB_CTL_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TX_REQ_FB_CTL_4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DEM_BYPASS_DATA0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DEM_BYPASS_DATA1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DEM_BYPASS_DATA2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DEM_BYPASS_DATA3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DEM_SECOND_ORDER)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_CTRL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_0_STATIC_DATA_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_0_STATIC_DATA_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_0_STATIC_DATA_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_0_STATIC_DATA_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_1_STATIC_DATA_0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_1_STATIC_DATA_1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_1_STATIC_DATA_2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSM_1_STATIC_DATA_3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RX_TOP_PAGE)] = RD_WR_REG, + [WCD939X_REG(WCD939X_TOP_CFG0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_COMP_WR_LSB)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_COMP_WR_MSB)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_COMP_LUT)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_COMP_RD_LSB)] = RD_REG, + [WCD939X_REG(WCD939X_HPHL_COMP_RD_MSB)] = RD_REG, + [WCD939X_REG(WCD939X_HPHR_COMP_WR_LSB)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_COMP_WR_MSB)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_COMP_LUT)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_COMP_RD_LSB)] = RD_REG, + [WCD939X_REG(WCD939X_HPHR_COMP_RD_MSB)] = RD_REG, + [WCD939X_REG(WCD939X_DSD0_DEBUG_CFG1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD0_DEBUG_CFG2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD0_DEBUG_CFG3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD0_DEBUG_CFG4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD0_DEBUG_CFG5)] = RD_REG, + [WCD939X_REG(WCD939X_DSD0_DEBUG_CFG6)] = RD_REG, + [WCD939X_REG(WCD939X_DSD1_DEBUG_CFG1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD1_DEBUG_CFG2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD1_DEBUG_CFG3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD1_DEBUG_CFG4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD1_DEBUG_CFG5)] = RD_REG, + [WCD939X_REG(WCD939X_DSD1_DEBUG_CFG6)] = RD_REG, + [WCD939X_REG(WCD939X_HPHL_RX_PATH_CFG0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_RX_PATH_CFG1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_RX_PATH_CFG0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_RX_PATH_CFG1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RX_PATH_CFG2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_RX_PATH_SEC0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_RX_PATH_SEC1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_RX_PATH_SEC2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHL_RX_PATH_SEC3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_RX_PATH_SEC0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_RX_PATH_SEC1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_RX_PATH_SEC2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_HPHR_RX_PATH_SEC3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RX_PATH_SEC4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_RX_PATH_SEC5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL6)] = RD_REG, + [WCD939X_REG(WCD939X_CTL7)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL8)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL9)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL10)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL11)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL12)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL13)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL14)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL15)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL16)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL17)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL18)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CTL19)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL6)] = RD_REG, + [WCD939X_REG(WCD939X_R_CTL7)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL8)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL9)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL10)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL11)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL12)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL13)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL14)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL15)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL16)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL17)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL18)] = RD_WR_REG, + [WCD939X_REG(WCD939X_R_CTL19)] = RD_WR_REG, + [WCD939X_REG(WCD939X_PATH_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CFG0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CFG1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CFG2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CFG3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHL_PATH_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHL_CFG0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHL_CFG1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHL_CFG2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHL_CFG3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CFG4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_CFG5)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHR_PATH_CTL)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHR_CFG0)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHR_CFG1)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHR_CFG2)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHR_CFG3)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHR_CFG4)] = RD_WR_REG, + [WCD939X_REG(WCD939X_DSD_HPHR_CFG5)] = RD_WR_REG, +}; + diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x.c new file mode 100644 index 0000000000..b31d10ba62 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x.c @@ -0,0 +1,5665 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd939x-registers.h" +#include "wcd939x.h" +#include "internal.h" +#include "asoc/bolero-slave-internal.h" +#include "wcd939x-reg-masks.h" +#include "wcd939x-reg-shifts.h" +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) +#include +#endif + + +#define NUM_SWRS_DT_PARAMS 5 +#define WCD939X_VARIANT_ENTRY_SIZE 32 + +#define WCD939X_VERSION_ENTRY_SIZE 32 + +#define ADC_MODE_VAL_HIFI 0x01 +#define ADC_MODE_VAL_LO_HIF 0x02 +#define ADC_MODE_VAL_NORMAL 0x03 +#define ADC_MODE_VAL_LP 0x05 +#define ADC_MODE_VAL_ULP1 0x09 +#define ADC_MODE_VAL_ULP2 0x0B + +#define HPH_IMPEDANCE_2VPK_MODE_OHMS 260 +#define XTALK_L_CH_NUM 0 +#define XTALK_R_CH_NUM 1 +#define GND_EXT_FET_MARGIN_MOHMS 200 + +#define NUM_ATTEMPTS 5 +#define COMP_MAX_COEFF 25 +#define HPH_MODE_MAX 4 + +#define WCD_USBSS_WRITE true +#define WCD_USBSS_READ false +#define WCD_USBSS_DP_EN 0x1E +#define WCD_USBSS_DN_EN 0x21 +#define P_THRESH_SEL_MASK 0x0E +#define P_THRESH_SEL_SHIFT 0x01 +#define VTH_4P0 0x04 +#define VTH_4P2 0x06 + +#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone" +#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone" +#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone" +#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone" + +#define WCD939X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD939X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WCD939X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define REG_FIELD_VALUE(register_name, field_name, value) \ +WCD939X_##register_name, FIELD_MASK(register_name, field_name), \ +value << FIELD_SHIFT(register_name, field_name) + +#define WCD939X_COMP_OFFSET \ + (WCD939X_R_BASE - WCD939X_COMPANDER_HPHL_BASE) + +#define WCD939X_XTALK_OFFSET \ + (WCD939X_HPHR_RX_PATH_SEC0 - WCD939X_HPHL_RX_PATH_SEC0) + +enum { + CODEC_TX = 0, + CODEC_RX, +}; + +enum { + WCD_ADC1 = 0, + WCD_ADC2, + WCD_ADC3, + WCD_ADC4, + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, + WCD_ADC1_MODE, + WCD_ADC2_MODE, + WCD_ADC3_MODE, + WCD_ADC4_MODE, +}; + +enum { + ADC_MODE_INVALID = 0, + ADC_MODE_HIFI, + ADC_MODE_LO_HIF, + ADC_MODE_NORMAL, + ADC_MODE_LP, + ADC_MODE_ULP1, + ADC_MODE_ULP2, +}; + +enum { + SUPPLY_LEVEL_2VPK, + REGULATOR_MODE_2VPK, + SET_HPH_GAIN_2VPK, +}; + +static u8 tx_mode_bit[] = { + [ADC_MODE_INVALID] = 0x00, + [ADC_MODE_HIFI] = 0x01, + [ADC_MODE_LO_HIF] = 0x02, + [ADC_MODE_NORMAL] = 0x04, + [ADC_MODE_LP] = 0x08, + [ADC_MODE_ULP1] = 0x10, + [ADC_MODE_ULP2] = 0x20, +}; + +extern const u8 wcd939x_reg_access[WCD939X_NUM_REGISTERS]; +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(hph_analog_gain, 600, -3000); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +/* Will be set by reading the registers during bind()*/ +static int wcd939x_version = WCD939X_VERSION_2_0; + +static int wcd939x_handle_post_irq(void *data); +static int wcd939x_reset(struct device *dev); +static int wcd939x_reset_low(struct device *dev); +static int wcd939x_get_adc_mode(int val); +static void wcd939x_config_2Vpk_mode(struct snd_soc_component *component, + struct wcd939x_priv *wcd939x, int mode_2vpk); + +static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(WCD939X_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(WCD939X_IRQ_EAR_SCD_INT, 1, 0x04), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(WCD939X_IRQ_EAR_PDM_WD_INT, 1, 0x80), + REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), +}; + +static struct regmap_irq_chip wcd939x_regmap_irq_chip = { + .name = "wcd939x", + .irqs = wcd939x_irqs, + .num_irqs = ARRAY_SIZE(wcd939x_irqs), + .num_regs = 3, + .status_base = WCD939X_INTR_STATUS_0, + .mask_base = WCD939X_INTR_MASK_0, + .type_base = WCD939X_INTR_LEVEL_0, + .ack_base = WCD939X_INTR_CLEAR_0, + .use_ack = 1, + .runtime_pm = false, + .handle_post_irq = wcd939x_handle_post_irq, + .irq_drv_data = NULL, +}; + +static bool wcd939x_readable_register(struct device *dev, unsigned int reg) +{ + if (reg <= WCD939X_BASE + 1) + return 0; + + if (reg >= WCD939X_FLYBACK_NEW_CTRL_2 && reg <= WCD939X_FLYBACK_NEW_CTRL_4) { + if (wcd939x_version == WCD939X_VERSION_1_0) + return 0; + } + return wcd939x_reg_access[WCD939X_REG(reg)] & RD_REG; +} + +static int wcd939x_handle_post_irq(void *data) +{ + struct wcd939x_priv *wcd939x = data; + u32 sts1 = 0, sts2 = 0, sts3 = 0; + + regmap_read(wcd939x->regmap, WCD939X_INTR_STATUS_0, &sts1); + regmap_read(wcd939x->regmap, WCD939X_INTR_STATUS_1, &sts2); + regmap_read(wcd939x->regmap, WCD939X_INTR_STATUS_2, &sts3); + + wcd939x->tx_swr_dev->slave_irq_pending = + ((sts1 || sts2 || sts3) ? true : false); + + return IRQ_HANDLED; +} + +static int wcd939x_hph_compander_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + int compander = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = wcd939x->compander_enabled[compander]; + return 0; +} + + +static int wcd939x_hph_compander_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + int compander = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + int value = ucontrol->value.integer.value[0]; + + if (value < WCD939X_HPH_MAX && value >= 0) + wcd939x->compander_enabled[compander] = value; + else { + dev_err(component->dev, "%s: Invalid comp value = %d\n", __func__, value); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: Compander %d value %d\n", + __func__, wcd939x->compander_enabled[compander], value); + return 0; +} + +static int wcd939x_hph_xtalk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + int xtalk = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + int value = ucontrol->value.integer.value[0]; + + if (value < WCD939X_HPH_MAX && value >= 0) + wcd939x->xtalk_enabled[xtalk] = value; + else { + dev_err(component->dev, "%s: Invalid xtalk value = %d\n", __func__, value); + return -EINVAL; + } + + dev_dbg(component->dev, "%s: xtalk %d value %d\n", + __func__, wcd939x->xtalk_enabled[xtalk], value); + + return 0; + +} + +static int wcd939x_hph_xtalk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + int xtalk = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = wcd939x->xtalk_enabled[xtalk]; + + return 0; +} + +static int wcd939x_hph_pcm_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + wcd939x->hph_pcm_enabled = ucontrol->value.integer.value[0]; + dev_dbg(component->dev, "%s: pcm enabled %d \n", + __func__, wcd939x->hph_pcm_enabled); + return 0; + +} + +static int wcd939x_hph_pcm_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd939x->hph_pcm_enabled; + + return 0; +} + +static int wcd939x_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum) +{ + int ret = 0; + int bank = 0; + + ret = swr_read(dev, devnum, SWR_SCP_CONTROL, &bank, 1); + if (ret) + return -EINVAL; + + return ((bank & 0x40) ? 1: 0); +} + +static int wcd939x_get_clk_rate(int mode) +{ + int rate; + + switch (mode) { + case ADC_MODE_ULP2: + rate = SWR_CLK_RATE_0P6MHZ; + break; + case ADC_MODE_ULP1: + rate = SWR_CLK_RATE_1P2MHZ; + break; + case ADC_MODE_LP: + rate = SWR_CLK_RATE_4P8MHZ; + break; + case ADC_MODE_NORMAL: + case ADC_MODE_LO_HIF: + case ADC_MODE_HIFI: + case ADC_MODE_INVALID: + default: + rate = SWR_CLK_RATE_9P6MHZ; + break; + } + + return rate; +} + +static int wcd939x_set_swr_clk_rate(struct snd_soc_component *component, + int rate, int bank) +{ + u8 mask = (bank ? 0xF0 : 0x0F); + u8 val = 0; + + switch (rate) { + case SWR_CLK_RATE_0P6MHZ: + val = (bank ? 0x60 : 0x06); + break; + case SWR_CLK_RATE_1P2MHZ: + val = (bank ? 0x50 : 0x05); + break; + case SWR_CLK_RATE_2P4MHZ: + val = (bank ? 0x30 : 0x03); + break; + case SWR_CLK_RATE_4P8MHZ: + val = (bank ? 0x10 : 0x01); + break; + case SWR_CLK_RATE_9P6MHZ: + default: + val = 0x00; + break; + } + snd_soc_component_update_bits(component, + WCD939X_SWR_TX_CLK_RATE, + mask, val); + + return 0; +} + +static int wcd939x_init_reg(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(BIAS, ANALOG_BIAS_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(BIAS, PRECHRG_EN, 0x01)); + + /* 10 msec delay as per HW requirement */ + usleep_range(10000, 10010); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(BIAS, PRECHRG_EN, 0x00)); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_HD2_CTL_L, HD2_RES_DIV_CTL_L, 0x15)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_HD2_CTL_R, HD2_RES_DIV_CTL_R, 0x15)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DMIC_CTL, CLK_SCALE_EN, 0x01)); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TXFE_ICTRL_STG2CASC_ULP, ICTRL_SCBIAS_ULP0P6M, 0x1)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TXFE_ICTRL_STG2CASC_ULP, ICTRL_STG2CASC_ULP, 0x4)); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TXFE_ICTRL_STG2MAIN_ULP, ICTRL_STG2MAIN_ULP, 0x08)); + + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TEST_CTL_1, NOISE_FILT_RES_VAL, 0x07)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MICB2_TEST_CTL_1, NOISE_FILT_RES_VAL, 0x07)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MICB3_TEST_CTL_1, NOISE_FILT_RES_VAL, 0x07)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MICB4_TEST_CTL_1, NOISE_FILT_RES_VAL, 0x07)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TEST_BLK_EN2, TXFE2_MBHC_CLKRST_EN, 0x00)); + + if (of_find_property(component->card->dev->of_node, "qcom,wcd-disable-legacy-surge", NULL)) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHLR_SURGE_EN, EN_SURGE_PROTECTION_HPHL, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHLR_SURGE_EN, EN_SURGE_PROTECTION_HPHR, 0x00)); + } + else { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHLR_SURGE_EN, EN_SURGE_PROTECTION_HPHL, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHLR_SURGE_EN, EN_SURGE_PROTECTION_HPHR, 0x01)); + } + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH_OCP_CTL, OCP_FSM_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH_OCP_CTL, SCD_OP_EN, 0x01)); + + if (wcd939x->version != WCD939X_VERSION_2_0) + snd_soc_component_write(component, WCD939X_CFG0, 0x05); + + /* + * Disable 1M pull-up by default during boot by writing 0b1 to bit[7]. + * This gets re-enabled when headset is inserted. + */ + snd_soc_component_update_bits(component, WCD939X_ZDET_BIAS_CTL, 0x80, 0x80); + return 0; +} + +static int wcd939x_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 = 0; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT]; + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + switch (path) { + case CODEC_RX: + map = &wcd939x->rx_port_mapping; + num_ports = wcd939x->num_rx_ports; + break; + case CODEC_TX: + map = &wcd939x->tx_port_mapping; + num_ports = wcd939x->num_tx_ports; + break; + default: + dev_err_ratelimited(component->dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + for (i = 0; i <= num_ports; i++) { + for (j = 0; j < MAX_CH_PER_PORT; j++) { + if ((*map)[i][j].slave_port_type == slv_prt_type) + goto found; + } + } +found: + if (i > num_ports || j == MAX_CH_PER_PORT) { + dev_err_ratelimited(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; +} + + +/* qcom,swr-tx-port-params = , , , ,*UC0* + , , , , *UC1* + , , , ; *UC2* + , , , ; *UC3 */ +static int wcd939x_parse_port_params(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, max_uc; + int ret = 0; + u32 cnt = 0; + u32 i, j; + struct swr_port_params (*map)[SWR_UC_MAX][SWR_NUM_PORTS]; + struct swr_dev_frame_config (*map_uc)[SWR_UC_MAX]; + struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); + + switch (path) { + case CODEC_TX: + map = &wcd939x->tx_port_params; + map_uc = &wcd939x->swr_tx_port_params; + break; + default: + ret = -EINVAL; + goto err_port_map; + } + + 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; + } + + max_uc = map_size / (SWR_NUM_PORTS * SWR_PORT_PARAMS * sizeof(u32)); + + if (max_uc != SWR_UC_MAX) { + dev_err(dev, "%s: port params not provided for all usecases\n", + __func__); + ret = -EINVAL; + goto err_port_map; + } + 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, + SWR_NUM_PORTS * SWR_PORT_PARAMS * max_uc); + 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 < max_uc; i++) { + for (j = 0; j < SWR_NUM_PORTS; j++) { + cnt = (i * SWR_NUM_PORTS + j) * SWR_PORT_PARAMS; + (*map)[i][j].offset1 = dt_array[cnt]; + (*map)[i][j].lane_ctrl = dt_array[cnt + 1]; + } + (*map_uc)[i].pp = &(*map)[i][0]; + } + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static int wcd939x_parse_port_mapping(struct device *dev, + char *prop, u8 path) +{ + u32 *dt_array, map_size, map_length; + u32 port_num = 0, 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 = NULL; + struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT]; + struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); + + switch (path) { + case CODEC_RX: + map = &wcd939x->rx_port_mapping; + num_ports = &wcd939x->num_rx_ports; + break; + case CODEC_TX: + map = &wcd939x->tx_port_mapping; + num_ports = &wcd939x->num_tx_ports; + break; + default: + dev_err(dev, "%s Invalid path selected %u\n", + __func__, path); + return -EINVAL; + } + + 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].slave_port_type = slave_port_type; + (*map)[port_num][ch_iter].ch_mask = ch_mask; + (*map)[port_num][ch_iter].master_port_type = master_port_type; + (*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask); + (*map)[port_num][ch_iter++].ch_rate = ch_rate; + old_port_num = port_num; + } + *num_ports = port_num; + kfree(dt_array); + return 0; + +err_pdata_fail: + kfree(dt_array); +err_alloc: +err_port_map: + return ret; +} + +static int wcd939x_tx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, int clk_rate, + u8 enable) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + u8 port_id, num_ch, ch_mask; + u8 ch_type = 0; + u32 ch_rate; + int slave_ch_idx; + u8 num_port = 1; + int ret = 0; + + ret = wcd939x_set_port_params(component, slv_port_type, &port_id, + &num_ch, &ch_mask, &ch_rate, + &ch_type, CODEC_TX); + if (ret) + return ret; + + if (clk_rate) + ch_rate = clk_rate; + + slave_ch_idx = wcd939x_slave_get_slave_ch_val(slv_port_type); + if (slave_ch_idx != -EINVAL) + ch_type = wcd939x->tx_master_ch_map[slave_ch_idx]; + + dev_dbg(component->dev, "%s slv_ch_idx: %d, mstr_ch_type: %d\n", + __func__, slave_ch_idx, ch_type); + + if (enable) + ret = swr_connect_port(wcd939x->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &ch_type); + else + ret = swr_disconnect_port(wcd939x->tx_swr_dev, &port_id, + num_port, &ch_mask, &ch_type); + return ret; + +} +static int wcd939x_rx_connect_port(struct snd_soc_component *component, + u8 slv_port_type, u8 enable) +{ + struct wcd939x_priv *wcd939x = 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 = wcd939x_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(wcd939x->rx_swr_dev, &port_id, + num_port, &ch_mask, &ch_rate, + &num_ch, &port_type); + else + ret = swr_disconnect_port(wcd939x->rx_swr_dev, &port_id, + num_port, &ch_mask, &port_type); + return ret; +} + +static int wcd939x_rx_clk_enable(struct snd_soc_component *component, int rx_num) +{ + + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s rx_clk_cnt: %d\n", __func__, wcd939x->rx_clk_cnt); + + if (wcd939x->rx_clk_cnt == 0) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, RX_BIAS_ENABLE, 0x01)); + + /*Analog path clock controls*/ + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_RX_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_RX_DIV2_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_RX_DIV4_CLK_EN, 0x01)); + + /*Digital path clock controls*/ + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, RXD0_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, RXD1_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, RXD2_CLK_EN, 0x01)); + + } + wcd939x->rx_clk_cnt++; + + return 0; +} + +static int wcd939x_rx_clk_disable(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s rx_clk_cnt: %d\n", __func__, wcd939x->rx_clk_cnt); + + if (wcd939x->rx_clk_cnt == 0) + return 0; + + wcd939x->rx_clk_cnt--; + if (wcd939x->rx_clk_cnt == 0) { + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, VNEG_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, VPOS_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, RXD2_CLK_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, RXD1_CLK_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, RXD0_CLK_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_RX_DIV4_CLK_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_RX_DIV2_CLK_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_RX_CLK_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, RX_BIAS_ENABLE, 0x00)); + + } + return 0; +} + +/* + * wcd939x_soc_get_mbhc: get wcd939x_mbhc handle of corresponding component + * @component: handle to snd_soc_component * + * + * return wcd939x_mbhc handle or error code in case of failure + */ +struct wcd939x_mbhc *wcd939x_soc_get_mbhc(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x; + + if (!component) { + pr_err_ratelimited("%s: Invalid params, NULL component\n", __func__); + return NULL; + } + wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x) { + pr_err_ratelimited("%s: wcd939x is NULL\n", __func__); + return NULL; + } + + return wcd939x->mbhc; +} +EXPORT_SYMBOL(wcd939x_soc_get_mbhc); + +static int wcd939x_config_power_mode(struct snd_soc_component *component, + int event, int index, int mode) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (mode == CLS_H_ULP) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_UHQA_CTL, REFBUFP_IOUT_CTL, 0x1)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_UHQA_CTL, REFBUFN_IOUT_CTL, 0x1)); + + if (wcd939x->compander_enabled[index]) { + if (index == WCD939X_HPHL) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL12, ZONE3_RMS, 0x21)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL13, ZONE4_RMS, 0x30)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL14, ZONE5_RMS, 0x3F)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL15, ZONE6_RMS, 0x48)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL17, PATH_GAIN, 0x0C)); + } else if (index == WCD939X_HPHR) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL12, ZONE3_RMS, 0x21)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL13, ZONE4_RMS, 0x30)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL14, ZONE5_RMS, 0x3F)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL15, ZONE6_RMS, 0x48)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL17, PATH_GAIN, 0x0C)); + } + } + } else { + if (wcd939x->compander_enabled[index]) { + if (index == WCD939X_HPHL) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL12, ZONE3_RMS, 0x1E)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL13, ZONE4_RMS, 0x2A)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL14, ZONE5_RMS, 0x36)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL15, ZONE6_RMS, 0x3C)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CTL17, PATH_GAIN, 0x00)); + } else if (index == WCD939X_HPHR) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL12, ZONE3_RMS, 0x1E)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL13, ZONE4_RMS, 0x2A)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL14, ZONE5_RMS, 0x36)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL15, ZONE6_RMS, 0x3C)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_CTL17, PATH_GAIN, 0x00)); + } + } + } + break; + case SND_SOC_DAPM_POST_PMD: + if (mode == CLS_H_ULP) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_UHQA_CTL, REFBUFN_IOUT_CTL, 0x0)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_UHQA_CTL, REFBUFP_IOUT_CTL, 0x0)); + } + break; + } + return 0; +} + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) +static int wcd939x_get_usbss_hph_power_mode(int hph_mode) +{ + switch (hph_mode) { + case CLS_H_HIFI: + case CLS_H_LOHIFI: + return 0x4; + default: + /* set default mode to ULP */ + return 0x2; + } +} +#endif + +static int wcd939x_enable_hph_pcm_index(struct snd_soc_component *component, + int event, int hph) +{ + struct wcd939x_priv *wcd939x = NULL; + + if (!component) { + pr_err_ratelimited("%s: Invalid params, NULL component\n", __func__); + return -EINVAL; + } + + wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x->hph_pcm_enabled) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (hph == WCD939X_HPHL) { + if (wcd939x->rx_clk_config == RX_CLK_11P2896MHZ) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHL_RX_PATH_CFG1, + RX_DC_DROOP_COEFF_SEL, 0x2)); + else if (wcd939x->rx_clk_config == RX_CLK_9P6MHZ) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHL_RX_PATH_CFG1, + RX_DC_DROOP_COEFF_SEL, 0x3)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHL_RX_PATH_CFG0, + DLY_ZN_EN, 0x1)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHL_RX_PATH_CFG0, + INT_EN, 0x3)); + } else if (hph == WCD939X_HPHR) { + if (wcd939x->rx_clk_config == RX_CLK_11P2896MHZ) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHR_RX_PATH_CFG1, + RX_DC_DROOP_COEFF_SEL, 0x2)); + else if (wcd939x->rx_clk_config == RX_CLK_9P6MHZ) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHR_RX_PATH_CFG1, + RX_DC_DROOP_COEFF_SEL, 0x3)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHR_RX_PATH_CFG0, + DLY_ZN_EN, 0x1)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPHR_RX_PATH_CFG0, + INT_EN, 0x3)); + } + break; + case SND_SOC_DAPM_POST_PMD: + break; + } + + return 0; +} + +static int wcd939x_config_compander(struct snd_soc_component *component, + int event, int compander_indx) +{ + u16 comp_ctl7_reg = 0, comp_ctl0_reg = 0; + u16 comp_en_mask_val = 0, gain_source_sel = 0; + struct wcd939x_priv *wcd939x; + + if (compander_indx >= WCD939X_HPH_MAX || compander_indx < 0) { + pr_err_ratelimited("%s: Invalid compander value: %d\n", + __func__, compander_indx); + return -EINVAL; + } + + if (!component) { + pr_err_ratelimited("%s: Invalid params, NULL component\n", __func__); + return -EINVAL; + } + wcd939x = snd_soc_component_get_drvdata(component); + if (!wcd939x->hph_pcm_enabled) + return 0; + + dev_dbg(component->dev, "%s compander_index = %d\n", __func__, compander_indx); + + if (!wcd939x->compander_enabled[compander_indx]) { + if (SND_SOC_DAPM_EVENT_ON(event)) + gain_source_sel = 0x01; + else + gain_source_sel = 0x00; + + if (compander_indx == WCD939X_HPHL) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(L_EN, GAIN_SOURCE_SEL, gain_source_sel)); + } else if (compander_indx == WCD939X_HPHR) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_EN, GAIN_SOURCE_SEL, gain_source_sel)); + } + wcd939x_config_2Vpk_mode(component, wcd939x, SET_HPH_GAIN_2VPK); + return 0; + } + + if (compander_indx == WCD939X_HPHL) + comp_en_mask_val = 1 << 1; + else if (compander_indx == WCD939X_HPHR) + comp_en_mask_val = 1 << 0; + else + return 0; + + comp_ctl0_reg = WCD939X_CTL0 + (compander_indx * WCD939X_COMP_OFFSET); + comp_ctl7_reg = WCD939X_CTL7 + (compander_indx * WCD939X_COMP_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + + snd_soc_component_update_bits(component, + comp_ctl7_reg, 0x1E, 0x00); + /* Enable compander clock*/ + snd_soc_component_update_bits(component, + comp_ctl0_reg , 0x01, 0x01); + + /* 250us sleep required as per HW Sequence */ + usleep_range(250, 260); + snd_soc_component_update_bits(component, + comp_ctl0_reg, 0x02, 0x02); + snd_soc_component_update_bits(component, + comp_ctl0_reg, 0x02, 0x00); + + /* Enable compander*/ + snd_soc_component_update_bits(component, + WCD939X_CDC_COMP_CTL_0, comp_en_mask_val, comp_en_mask_val); + + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + WCD939X_CDC_COMP_CTL_0, comp_en_mask_val, 0x00); + snd_soc_component_update_bits(component, + comp_ctl0_reg , 0x01, 0x00); + if (compander_indx == WCD939X_HPHL) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(L_EN, GAIN_SOURCE_SEL, 0x0)); + if (compander_indx == WCD939X_HPHR) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_EN, GAIN_SOURCE_SEL, 0x0)); + } + + return 0; +} + +static int wcd939x_config_xtalk(struct snd_soc_component *component, + int event, int xtalk_indx) +{ + u16 xtalk_sec0 = 0, xtalk_sec1 = 0, xtalk_sec2 = 0, xtalk_sec3 = 0; + struct wcd939x_priv *wcd939x = NULL; + struct wcd939x_pdata *pdata = NULL; + if (!component) { + pr_err_ratelimited("%s: Invalid params, NULL component\n", __func__); + return -EINVAL; + } + + wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x->xtalk_enabled[xtalk_indx]) + return 0; + + pdata = dev_get_platdata(wcd939x->dev); + + dev_dbg(component->dev, "%s xtalk_indx = %d event = %d\n", + __func__, xtalk_indx, event); + + switch(event) { + + case SND_SOC_DAPM_PRE_PMU: + xtalk_sec0 = WCD939X_HPHL_RX_PATH_SEC0 + (xtalk_indx * WCD939X_XTALK_OFFSET); + xtalk_sec1 = WCD939X_HPHL_RX_PATH_SEC1 + (xtalk_indx * WCD939X_XTALK_OFFSET); + xtalk_sec2 = WCD939X_HPHL_RX_PATH_SEC2 + (xtalk_indx * WCD939X_XTALK_OFFSET); + xtalk_sec3 = WCD939X_HPHL_RX_PATH_SEC3 + (xtalk_indx * WCD939X_XTALK_OFFSET); + + /* Write scale and alpha based on channel */ + if (xtalk_indx == XTALK_L_CH_NUM) { + snd_soc_component_update_bits(component, xtalk_sec1, 0xFF, + pdata->usbcss_hs.xtalk.alpha_l); + snd_soc_component_update_bits(component, xtalk_sec0, 0x1F, + pdata->usbcss_hs.xtalk.scale_l); + } else if (xtalk_indx == XTALK_R_CH_NUM) { + snd_soc_component_update_bits(component, xtalk_sec1, 0xFF, + pdata->usbcss_hs.xtalk.alpha_r); + snd_soc_component_update_bits(component, xtalk_sec0, 0x1F, + pdata->usbcss_hs.xtalk.scale_r); + } else { + snd_soc_component_update_bits(component, xtalk_sec1, 0xFF, MIN_XTALK_ALPHA); + snd_soc_component_update_bits(component, xtalk_sec0, 0x1F, MAX_XTALK_SCALE); + } + + dev_dbg(component->dev, "%s Scale = 0x%x, Alpha = 0x%x\n", __func__, + snd_soc_component_read(component, xtalk_sec0), + snd_soc_component_read(component, xtalk_sec1)); + + snd_soc_component_update_bits(component, xtalk_sec3, 0xFF, 0x4F); + snd_soc_component_update_bits(component, xtalk_sec2, 0x1F, 0x11); + + break; + case SND_SOC_DAPM_POST_PMU: + /* enable xtalk for L and R channels*/ + snd_soc_component_update_bits(component, WCD939X_RX_PATH_CFG2, + 0x0F, 0x0F); + break; + case SND_SOC_DAPM_POST_PMD: + /* Disable Xtalk for L and R channels*/ + snd_soc_component_update_bits(component, WCD939X_RX_PATH_CFG2, + 0x00, 0x00); + break; + } + return 0; +} + +static int wcd939x_rx3_mux(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 event: %d wshift: %d wname: %s\n", + __func__, event, w->shift, w->name); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x_rx_clk_enable(component, w->shift); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_rx_clk_disable(component); + break; + } + + return 0; +} + +static int wcd939x_rx_mux(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + + int hph_mode = 0; + struct wcd939x_priv *wcd939x = NULL; + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + wcd939x = snd_soc_component_get_drvdata(component); + hph_mode = wcd939x->hph_mode; + + dev_dbg(component->dev, "%s event: %d wshift: %d wname: %s\n", + __func__, event, w->shift, w->name); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x_rx_clk_enable(component, w->shift); + if (wcd939x->hph_pcm_enabled) + wcd939x_config_power_mode(component, event, w->shift, hph_mode); + wcd939x_config_compander(component, event, w->shift); + wcd939x_config_xtalk(component, event, w->shift); + break; + case SND_SOC_DAPM_POST_PMU: + wcd939x_config_xtalk(component, event, w->shift); + /*TBD: need to revisit , for both L & R we are updating, but in QCRG only once*/ + if (wcd939x->hph_pcm_enabled) { + if (hph_mode == CLS_H_HIFI || hph_mode == CLS_AB_HIFI) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TOP_CFG0, HPH_DAC_RATE_SEL, 0x1)); + else + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TOP_CFG0, HPH_DAC_RATE_SEL, 0x0)); + } + wcd939x_enable_hph_pcm_index(component, event, w->shift); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_config_xtalk(component, event, w->shift); + wcd939x_config_compander(component, event, w->shift); + if (wcd939x->hph_pcm_enabled) + wcd939x_config_power_mode(component, event, w->shift, hph_mode); + wcd939x_rx_clk_disable(component); + break; + + } + + return 0; +} + +static void wcd939x_config_2Vpk_mode(struct snd_soc_component *component, + struct wcd939x_priv *wcd939x, int mode_2vpk) +{ + uint32_t zl = 0, zr = 0; + int rc; + + if (!wcd939x->in_2Vpk_mode) + return; + + rc = wcd_mbhc_get_impedance(&wcd939x->mbhc->wcd_mbhc, &zl, &zr); + if (rc) { + dev_err_ratelimited(component->dev, "%s: Unable to get impedance for 2Vpk mode", __func__); + return; + } + + switch (mode_2vpk) { + case SUPPLY_LEVEL_2VPK: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PA_GAIN_CTL_L, RX_SUPPLY_LEVEL, 0x01)); + + if (zl < HPH_IMPEDANCE_2VPK_MODE_OHMS) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PA_GAIN_CTL_L, EN_HPHPA_2VPK, 0x00)); + else + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PA_GAIN_CTL_L, EN_HPHPA_2VPK, 0x01)); + break; + case REGULATOR_MODE_2VPK: + if (zl >= HPH_IMPEDANCE_2VPK_MODE_OHMS) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, REGULATOR_MODE, 0x01)); + snd_soc_component_update_bits(component, WCD939X_FLYBACK_TEST_CTL, + 0x0F, 0x02); + } else { + snd_soc_component_update_bits(component, WCD939X_FLYBACK_TEST_CTL, + 0x0F, 0x0D); + } + break; + case SET_HPH_GAIN_2VPK: + if (zl >= HPH_IMPEDANCE_2VPK_MODE_OHMS) { + snd_soc_component_update_bits(component, WCD939X_PA_GAIN_CTL_L, 0x1F, 0x02); + snd_soc_component_update_bits(component, WCD939X_PA_GAIN_CTL_R, 0x1F, 0x02); + } + + break; + } +} + +static int wcd939x_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 wcd939x_priv *wcd939x = 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: + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_CLK_CTL1, OPAMP_CHOP_CLK_EN, 0x00)); + wcd939x_config_2Vpk_mode(component, wcd939x, SUPPLY_LEVEL_2VPK); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_HPH_GAIN_CTL, HPHL_RX_EN, 0x01)); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_HD2_CTL_L, HD2_RES_DIV_CTL_L, 0x1D)); + if (!wcd939x->hph_pcm_enabled) { + if (wcd939x->comp1_enable) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_COMP_CTL_0, HPHL_COMP_EN, 0x01)); + /* 5msec compander delay as per HW requirement */ + if (!wcd939x->comp2_enable || + (snd_soc_component_read(component, + WCD939X_CDC_COMP_CTL_0) & 0x01)) + usleep_range(5000, 5010); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH_TIMER1, AUTOCHOP_TIMER_CTL_EN, 0x00)); + } else { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_COMP_CTL_0, HPHL_COMP_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(L_EN, GAIN_SOURCE_SEL, 0x01)); + } + } + if (wcd939x->hph_pcm_enabled) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH_TIMER1, AUTOCHOP_TIMER_CTL_EN, 0x00)); + snd_soc_component_write(component, WCD939X_VNEG_CTRL_1, 0xEB); + if (wcd939x->hph_mode == CLS_H_LOHIFI) + snd_soc_component_write(component, + WCD939X_HPH_RDAC_BIAS_LOHIFI, 0x52); + else + snd_soc_component_write(component, + WCD939X_HPH_RDAC_BIAS_LOHIFI, 0x64); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_HD2_CTL_L, HD2_RES_DIV_CTL_L, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_HPH_GAIN_CTL, HPHL_RX_EN, 0x00)); + break; + } + + return 0; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = 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: + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_CLK_CTL1, OPAMP_CHOP_CLK_EN, 0x00)); + wcd939x_config_2Vpk_mode(component, wcd939x, SUPPLY_LEVEL_2VPK); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_HPH_GAIN_CTL, HPHR_RX_EN, 0x01)); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_HD2_CTL_R, HD2_RES_DIV_CTL_R, 0x1D)); + if (!wcd939x->hph_pcm_enabled) { + if (wcd939x->comp1_enable) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_COMP_CTL_0, HPHR_COMP_EN, 0x01)); + /* 5msec compander delay as per HW requirement */ + if (!wcd939x->comp2_enable || + (snd_soc_component_read(component, + WCD939X_CDC_COMP_CTL_0) & 0x02)) + usleep_range(5000, 5010); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH_TIMER1, AUTOCHOP_TIMER_CTL_EN, 0x00)); + } else { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_COMP_CTL_0, HPHR_COMP_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(R_EN, GAIN_SOURCE_SEL, 0x01)); + } + } + if (wcd939x->hph_pcm_enabled) { + snd_soc_component_write(component, WCD939X_VNEG_CTRL_1, 0xEB); + if (wcd939x->hph_mode == CLS_H_LOHIFI) + snd_soc_component_write(component, + WCD939X_HPH_RDAC_BIAS_LOHIFI, 0x52); + else + snd_soc_component_write(component, + WCD939X_HPH_RDAC_BIAS_LOHIFI, 0x64); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RDAC_HD2_CTL_R, HD2_RES_DIV_CTL_R, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_HPH_GAIN_CTL, HPHR_RX_EN, 0x00)); + break; + } + + return 0; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = 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: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_EAR_GAIN_CTL, EAR_EN, 0x01)); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(EAR_DAC_CON, DAC_SAMPLE_EDGE_SEL, 0x00)); + /* 5 msec delay as per HW requirement */ + usleep_range(5000, 5010); + wcd_cls_h_fsm(component, &wcd939x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + CLS_AB_HIFI); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(VNEG_CTRL_4, ILIM_SEL, 0xD)); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(EAR_DAC_CON, DAC_SAMPLE_EDGE_SEL, 0x01)); + break; + }; + return 0; + +} + +static int wcd939x_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int ret = 0; + int hph_mode = wcd939x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd939x->ldoh) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MODE, LDOH_EN, 0x01)); + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + ret = swr_slvdev_datapath_control(wcd939x->rx_swr_dev, + wcd939x->rx_swr_dev->dev_num, + true); + wcd_cls_h_fsm(component, &wcd939x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + hph_mode); + wcd939x_config_2Vpk_mode(component, wcd939x, REGULATOR_MODE_2VPK); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_LP_CTL, PREREF_FILT_BYPASS, 0x01)); + } + /* update Mode for LOHIFI */ + if (hph_mode == CLS_H_LOHIFI) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, PWR_LEVEL, 0x00)); + } +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* update USBSS power mode for AATC */ + if (wcd939x->mbhc->wcd_mbhc.mbhc_cfg->enable_usbc_analog) + wcd_usbss_audio_config(NULL, WCD_USBSS_CONFIG_TYPE_POWER_MODE, + wcd939x_get_usbss_hph_power_mode(hph_mode)); +#endif + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(VNEG_CTRL_4, ILIM_SEL, 0xD)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHR_REF_ENABLE, 0x01)); + if ((snd_soc_component_read(component, WCD939X_HPH) & 0x30) == 0x30) + usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PDM_WD_CTL1, PDM_WD_EN, 0x03)); + 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, &wcd939x->status_mask)) { + if (!wcd939x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + if (hph_mode == CLS_H_LP || + hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_LP_CTL, PREREF_FILT_BYPASS, 0x00)); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH_TIMER1, AUTOCHOP_TIMER_CTL_EN, 0x01)); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, REGULATOR_MODE, 0x01)); + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10)); + /*Enable PDM INT for PDM data path only*/ + if (!wcd939x->hph_pcm_enabled) + wcd_enable_irq(&wcd939x->irq_info, + WCD939X_IRQ_HPHR_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + wcd_disable_irq(&wcd939x->irq_info, + WCD939X_IRQ_HPHR_PDM_WD_INT); + if (wcd939x->update_wcd_event && wcd939x->comp2_enable) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX2 << 0x10)); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd939x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHR_ENABLE, 0x00)); + + blocking_notifier_call_chain(&wcd939x->mbhc->notifier, + WCD_EVENT_PRE_HPHR_PA_OFF, + &wcd939x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 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, &wcd939x->status_mask)) { + if (!wcd939x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + blocking_notifier_call_chain(&wcd939x->mbhc->notifier, + WCD_EVENT_POST_HPHR_PA_OFF, + &wcd939x->mbhc->wcd_mbhc); + + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHR_REF_ENABLE, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PDM_WD_CTL1, PDM_WD_EN, 0x00)); +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (wcd939x->mbhc->wcd_mbhc.mbhc_cfg->enable_usbc_analog && + !(snd_soc_component_read(component, WCD939X_HPH) & 0XC0)) + wcd_usbss_audio_config(NULL, WCD_USBSS_CONFIG_TYPE_POWER_MODE, 1); +#endif + wcd_cls_h_fsm(component, &wcd939x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + hph_mode); + if (wcd939x->ldoh) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MODE, LDOH_EN, 0x00)); + break; + }; + return ret; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int ret = 0; + int hph_mode = wcd939x->hph_mode; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd939x->ldoh) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MODE, LDOH_EN, 0x01)); + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x01)); + ret = swr_slvdev_datapath_control(wcd939x->rx_swr_dev, + wcd939x->rx_swr_dev->dev_num, + true); + wcd_cls_h_fsm(component, &wcd939x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + hph_mode); + wcd939x_config_2Vpk_mode(component, wcd939x, REGULATOR_MODE_2VPK); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_LP_CTL, PREREF_FILT_BYPASS, 0x01)); + } + /* update Mode for LOHIFI */ + if (hph_mode == CLS_H_LOHIFI) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, PWR_LEVEL, 0x00)); + } +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* update USBSS power mode for AATC */ + if (wcd939x->mbhc->wcd_mbhc.mbhc_cfg->enable_usbc_analog) + wcd_usbss_audio_config(NULL, WCD_USBSS_CONFIG_TYPE_POWER_MODE, + wcd939x_get_usbss_hph_power_mode(hph_mode)); +#endif + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(VNEG_CTRL_4, ILIM_SEL, 0xD)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHL_REF_ENABLE, 0x01)); + if ((snd_soc_component_read(component, WCD939X_HPH) & 0x30) == 0x30) + usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PDM_WD_CTL0, PDM_WD_EN, 0x03)); + 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, &wcd939x->status_mask)) { + if (!wcd939x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + if (hph_mode == CLS_H_LP || + hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + if (!wcd939x->hph_pcm_enabled) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(REFBUFF_LP_CTL, PREREF_FILT_BYPASS, 0x00)); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH_TIMER1, AUTOCHOP_TIMER_CTL_EN, 0x01)); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, REGULATOR_MODE, 0x01)); + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10)); + /*Enable PDM INT for PDM data path only*/ + if (!wcd939x->hph_pcm_enabled) + wcd_enable_irq(&wcd939x->irq_info, + WCD939X_IRQ_HPHL_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + wcd_disable_irq(&wcd939x->irq_info, + WCD939X_IRQ_HPHL_PDM_WD_INT); + if (wcd939x->update_wcd_event && wcd939x->comp1_enable) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX1 << 0x10)); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd939x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHL_ENABLE, 0x00)); + blocking_notifier_call_chain(&wcd939x->mbhc->notifier, + WCD_EVENT_PRE_HPHL_PA_OFF, + &wcd939x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd939x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 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, &wcd939x->status_mask)) { + if (!wcd939x->comp1_enable) + usleep_range(21000, 21100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); + } + blocking_notifier_call_chain(&wcd939x->mbhc->notifier, + WCD_EVENT_POST_HPHL_PA_OFF, + &wcd939x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHL_REF_ENABLE, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PDM_WD_CTL0, PDM_WD_EN, 0x00)); +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + if (wcd939x->mbhc->wcd_mbhc.mbhc_cfg->enable_usbc_analog && + !(snd_soc_component_read(component, WCD939X_HPH) & 0XC0)) + wcd_usbss_audio_config(NULL, WCD_USBSS_CONFIG_TYPE_POWER_MODE, 1); +#endif + wcd_cls_h_fsm(component, &wcd939x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + hph_mode); + if (wcd939x->ldoh) + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MODE, LDOH_EN, 0x00)); + + break; + }; + return ret; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = 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: + ret = swr_slvdev_datapath_control(wcd939x->rx_swr_dev, + wcd939x->rx_swr_dev->dev_num, + true); + /* + * Enable watchdog interrupt for HPHL + */ + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PDM_WD_CTL0, PDM_WD_EN, 0x03)); + /* For EAR, use CLASS_AB regulator mode */ + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(RX_SUPPLIES, REGULATOR_MODE, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(EAR_COMPANDER_CTL, GAIN_OVRD_REG, 0x01)); + break; + case SND_SOC_DAPM_POST_PMU: + /* 6 msec delay as per HW requirement */ + usleep_range(6000, 6010); + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10)); + wcd_enable_irq(&wcd939x->irq_info, WCD939X_IRQ_EAR_PDM_WD_INT); + break; + case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd939x->irq_info, + WCD939X_IRQ_EAR_PDM_WD_INT); + if (wcd939x->update_wcd_event) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_RX_MUTE, + (WCD_RX3 << 0x10 | 0x1)); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(EAR_COMPANDER_CTL, GAIN_OVRD_REG, 0x00)); + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(PDM_WD_CTL0, PDM_WD_EN, 0x00)); + wcd_cls_h_fsm(component, &wcd939x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + CLS_AB_HIFI); + break; + }; + return ret; +} + +static int wcd939x_clsh_dummy(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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + if (SND_SOC_DAPM_EVENT_OFF(event)) + ret = swr_slvdev_datapath_control( + wcd939x->rx_swr_dev, + wcd939x->rx_swr_dev->dev_num, + false); + return ret; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int mode = wcd939x->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) { + wcd939x_rx_connect_port(component, CLSH, + SND_SOC_DAPM_EVENT_ON(event)); + } + if (SND_SOC_DAPM_EVENT_OFF(event)) + ret = swr_slvdev_datapath_control( + wcd939x->rx_swr_dev, + wcd939x->rx_swr_dev->dev_num, + false); + return ret; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = 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: + if (wcd939x->hph_pcm_enabled) + wcd939x_rx_connect_port(component, HIFI_PCM_L, true); + else { + wcd939x_rx_connect_port(component, HPH_L, true); + if (wcd939x->comp1_enable) + wcd939x_rx_connect_port(component, COMP_L, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (wcd939x->hph_pcm_enabled) + wcd939x_rx_connect_port(component, HIFI_PCM_L, false); + else { + wcd939x_rx_connect_port(component, HPH_L, false); + if (wcd939x->comp1_enable) + wcd939x_rx_connect_port(component, COMP_L, false); + } + break; + }; + + return 0; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = 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: + if (wcd939x->hph_pcm_enabled) + wcd939x_rx_connect_port(component, HIFI_PCM_R, true); + else { + wcd939x_rx_connect_port(component, HPH_R, true); + if (wcd939x->comp2_enable) + wcd939x_rx_connect_port(component, COMP_R, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (wcd939x->hph_pcm_enabled) + wcd939x_rx_connect_port(component, HIFI_PCM_R, false); + else { + wcd939x_rx_connect_port(component, HPH_R, false); + if (wcd939x->comp2_enable) + wcd939x_rx_connect_port(component, COMP_R, false); + } + break; + }; + + return 0; +} + +static int wcd939x_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: + wcd939x_rx_connect_port(component, LO, true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_rx_connect_port(component, LO, false); + /* 6 msec delay as per HW requirement */ + usleep_range(6000, 6010); + break; + } + + return 0; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + u16 dmic_clk_reg, dmic_clk_en_reg; + s32 *dmic_clk_cnt; + u8 dmic_ctl_shift = 0; + u8 dmic_clk_shift = 0; + u8 dmic_clk_mask = 0; + u16 dmic2_left_en = 0; + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (w->shift) { + case 0: + case 1: + dmic_clk_cnt = &(wcd939x->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD939X_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD939X_CDC_DMIC1_CTL; + dmic_clk_mask = 0x0F; + dmic_clk_shift = 0x00; + dmic_ctl_shift = 0x00; + break; + case 2: + dmic2_left_en = WCD939X_CDC_DMIC2_CTL; + fallthrough; + case 3: + dmic_clk_cnt = &(wcd939x->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD939X_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD939X_CDC_DMIC2_CTL; + dmic_clk_mask = 0xF0; + dmic_clk_shift = 0x04; + dmic_ctl_shift = 0x01; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd939x->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD939X_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD939X_CDC_DMIC3_CTL; + dmic_clk_mask = 0x0F; + dmic_clk_shift = 0x00; + dmic_ctl_shift = 0x02; + break; + case 6: + case 7: + dmic_clk_cnt = &(wcd939x->dmic_6_7_clk_cnt); + dmic_clk_reg = WCD939X_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD939X_CDC_DMIC4_CTL; + dmic_clk_mask = 0xF0; + dmic_clk_shift = 0x04; + dmic_ctl_shift = 0x03; + break; + default: + dev_err_ratelimited(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, (w->shift +1), *dmic_clk_cnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD939X_CDC_AMIC_CTL, + (0x01 << dmic_ctl_shift), 0x00); + /* 250us sleep as per HW requirement */ + usleep_range(250, 260); + if (dmic2_left_en) + snd_soc_component_update_bits(component, + dmic2_left_en, 0x80, 0x80); + /* Setting DMIC clock rate to 2.4MHz */ + snd_soc_component_update_bits(component, + dmic_clk_reg, dmic_clk_mask, + (0x03 << dmic_clk_shift)); + snd_soc_component_update_bits(component, + dmic_clk_en_reg, 0x08, 0x08); + /* enable clock scaling */ + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DMIC_CTL, CLK_SCALE_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DMIC_CTL, DMIC_DIV_BAK_EN, 0x01)); + ret = swr_slvdev_datapath_control(wcd939x->tx_swr_dev, + wcd939x->tx_swr_dev->dev_num, + true); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_tx_connect_port(component, DMIC0 + (w->shift), 0, + false); + snd_soc_component_update_bits(component, + WCD939X_CDC_AMIC_CTL, + (0x01 << dmic_ctl_shift), + (0x01 << dmic_ctl_shift)); + if (dmic2_left_en) + snd_soc_component_update_bits(component, + dmic2_left_en, 0x80, 0x00); + snd_soc_component_update_bits(component, + dmic_clk_en_reg, 0x08, 0x00); + break; + }; + return ret; +} + +/* + * wcd939x_get_micb_vout_ctl_val: converts micbias from volts to register value + * @micb_mv: micbias in mv + * + * return register value converted + */ +int wcd939x_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_ratelimited("%s: unsupported micbias voltage\n", __func__); + return -EINVAL; + } + + return (micb_mv - 1000) / 50; +} +EXPORT_SYMBOL(wcd939x_get_micb_vout_ctl_val); + +/* + * wcd939x_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 wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct wcd939x_priv *wcd939x = 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 = WCD939X_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD939X_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD939X_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD939X_MICB4; + break; + default: + return -EINVAL; + } + mutex_lock(&wcd939x->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_read(component, micb_reg); + micb_en = (micb_val & 0xC0) >> 6; + cur_vout_ctl = micb_val & 0x3F; + + req_vout_ctl = wcd939x_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(&wcd939x->micb_lock); + return ret; +} +EXPORT_SYMBOL(wcd939x_mbhc_micb_adjust_voltage); + +static int wcd939x_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int ret = 0; + int bank = 0; + u8 mode = 0; + int i = 0; + int rate = 0; + + bank = (wcd939x_swr_slv_get_current_bank(wcd939x->tx_swr_dev, + wcd939x->tx_swr_dev->dev_num) ? 0 : 1); + + /* power mode is applicable only to analog mics */ + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + /* Get channel rate */ + rate = wcd939x_get_clk_rate(wcd939x->tx_mode[w->shift - ADC1]); + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Check AMIC2 is connected to ADC2 to take an action on BCS */ + if (w->shift == ADC2 && + (((snd_soc_component_read(component, WCD939X_TX_CH12_MUX) & + 0x38) >> 3) == 0x2)) { + if (!wcd939x->bcs_dis) { + wcd939x_tx_connect_port(component, MBHC, + SWR_CLK_RATE_4P8MHZ, true); + set_bit(AMIC2_BCS_ENABLE, &wcd939x->status_mask); + } + } + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + set_bit(w->shift - ADC1, &wcd939x->status_mask); + wcd939x_tx_connect_port(component, w->shift, rate, + true); + } else { + wcd939x_tx_connect_port(component, w->shift, + SWR_CLK_RATE_2P4MHZ, true); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + if (strnstr(w->name, "ADC1", sizeof("ADC1"))) { + clear_bit(WCD_ADC1, &wcd939x->status_mask); + clear_bit(WCD_ADC1_MODE, &wcd939x->status_mask); + } else if (strnstr(w->name, "ADC2", sizeof("ADC2"))) { + clear_bit(WCD_ADC2, &wcd939x->status_mask); + clear_bit(WCD_ADC2_MODE, &wcd939x->status_mask); + } else if (strnstr(w->name, "ADC3", sizeof("ADC3"))) { + clear_bit(WCD_ADC3, &wcd939x->status_mask); + clear_bit(WCD_ADC3_MODE, &wcd939x->status_mask); + } else if (strnstr(w->name, "ADC4", sizeof("ADC4"))) { + clear_bit(WCD_ADC4, &wcd939x->status_mask); + clear_bit(WCD_ADC4_MODE, &wcd939x->status_mask); + } + } + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + if (test_bit(WCD_ADC1, &wcd939x->status_mask) || + test_bit(WCD_ADC1_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd939x->status_mask) || + test_bit(WCD_ADC2_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd939x->status_mask) || + test_bit(WCD_ADC3_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd939x->status_mask) || + test_bit(WCD_ADC4_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + rate = wcd939x_get_clk_rate(i); + if (wcd939x->adc_count) { + rate = (wcd939x->adc_count * rate); + if (rate > SWR_CLK_RATE_9P6MHZ) + rate = SWR_CLK_RATE_9P6MHZ; + } + wcd939x_set_swr_clk_rate(component, rate, bank); + } + ret = swr_slvdev_datapath_control(wcd939x->tx_swr_dev, + wcd939x->tx_swr_dev->dev_num, + false); + + if (strnstr(w->name, "ADC", sizeof("ADC"))) + wcd939x_set_swr_clk_rate(component, rate, !bank); + break; + }; + + return ret; +} + +static int wcd939x_get_adc_mode(int val) +{ + int ret = 0; + + switch (val) { + case ADC_MODE_INVALID: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_HIFI: + ret = ADC_MODE_VAL_HIFI; + break; + case ADC_MODE_LO_HIF: + ret = ADC_MODE_VAL_LO_HIF; + break; + case ADC_MODE_NORMAL: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_LP: + ret = ADC_MODE_VAL_LP; + break; + case ADC_MODE_ULP1: + ret = ADC_MODE_VAL_ULP1; + break; + case ADC_MODE_ULP2: + ret = ADC_MODE_VAL_ULP2; + break; + default: + ret = -EINVAL; + pr_err_ratelimited("%s: invalid ADC mode value %d\n", __func__, val); + break; + } + return ret; +} + +int wcd939x_tx_channel_config(struct snd_soc_component *component, + int channel, int mode) +{ + int reg = WCD939X_TX_CH2, mask = 0, val = 0; + int ret = 0; + + switch (channel) { + case 0: + reg = WCD939X_TX_CH2; + mask = 0x40; + break; + case 1: + reg = WCD939X_TX_CH2; + mask = 0x20; + break; + case 2: + reg = WCD939X_TX_CH4; + mask = 0x40; + break; + case 3: + reg = WCD939X_TX_CH4; + mask = 0x20; + break; + default: + pr_err_ratelimited("%s: Invalid channel num %d\n", __func__, channel); + ret = -EINVAL; + break; + } + + if (!mode) + val = 0x00; + else + val = mask; + + if (!ret) + snd_soc_component_update_bits(component, reg, mask, val); + + return ret; +} + +static int wcd939x_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); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + int clk_rate = 0, ret = 0; + int mode = 0, i = 0, bank = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + bank = (wcd939x_swr_slv_get_current_bank(wcd939x->tx_swr_dev, + wcd939x->tx_swr_dev->dev_num) ? 0 : 1); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x->adc_count++; + if (test_bit(WCD_ADC1, &wcd939x->status_mask) || + test_bit(WCD_ADC1_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd939x->status_mask) || + test_bit(WCD_ADC2_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd939x->status_mask) || + test_bit(WCD_ADC3_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd939x->status_mask) || + test_bit(WCD_ADC4_MODE, &wcd939x->status_mask)) + mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + clk_rate = wcd939x_get_clk_rate(i); + + /* clk_rate depends on number of paths getting enabled */ + clk_rate = (wcd939x->adc_count * clk_rate); + if (clk_rate > SWR_CLK_RATE_9P6MHZ) + clk_rate = SWR_CLK_RATE_9P6MHZ; + wcd939x_set_swr_clk_rate(component, clk_rate, bank); + ret = swr_slvdev_datapath_control(wcd939x->tx_swr_dev, + wcd939x->tx_swr_dev->dev_num, + true); + wcd939x_set_swr_clk_rate(component, clk_rate, !bank); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x->adc_count--; + if (wcd939x->adc_count < 0) + wcd939x->adc_count = 0; + + wcd939x_tx_connect_port(component, ADC1 + w->shift, 0, false); + if (w->shift + ADC1 == ADC2 && + test_bit(AMIC2_BCS_ENABLE, &wcd939x->status_mask)) { + wcd939x_tx_connect_port(component, MBHC, 0, + false); + clear_bit(AMIC2_BCS_ENABLE, &wcd939x->status_mask); + } + break; + }; + + return ret; +} + +void wcd939x_disable_bcs_before_slow_insert(struct snd_soc_component *component, + bool bcs_disable) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (wcd939x->update_wcd_event) { + if (bcs_disable) + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 0); + else + wcd939x->update_wcd_event(wcd939x->handle, + SLV_BOLERO_EVT_BCS_CLK_OFF, 1); + } +} + +static int wcd939x_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); + struct wcd939x_priv *wcd939x = + snd_soc_component_get_drvdata(component); + int ret = 0; + u8 mode = 0; + + 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, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_TX_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_TX_DIV2_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_REQ_CTL, FS_RATE_4P8, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_REQ_CTL, NO_NOTCH, 0x00)); + + ret = wcd939x_tx_channel_config(component, w->shift, 1); + mode = wcd939x_get_adc_mode(wcd939x->tx_mode[w->shift]); + if (mode < 0) { + dev_info_ratelimited(component->dev, + "%s: invalid mode, setting to normal mode\n", + __func__); + mode = ADC_MODE_VAL_NORMAL; + } + switch (w->shift) { + case 0: + snd_soc_component_update_bits(component, + WCD939X_CDC_TX_ANA_MODE_0_1, 0x0F, + mode); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD0_CLK_EN, 0x01)); + break; + case 1: + snd_soc_component_update_bits(component, + WCD939X_CDC_TX_ANA_MODE_0_1, 0xF0, + mode << 4); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD1_CLK_EN, 0x01)); + break; + case 2: + snd_soc_component_update_bits(component, + WCD939X_CDC_TX_ANA_MODE_2_3, 0x0F, + mode); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD2_CLK_EN, 0x01)); + break; + case 3: + snd_soc_component_update_bits(component, + WCD939X_CDC_TX_ANA_MODE_2_3, 0xF0, + mode << 4); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD3_CLK_EN, 0x01)); + break; + default: + break; + } + ret |= wcd939x_tx_channel_config(component, w->shift, 0); + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->shift) { + case 0: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_TX_ANA_MODE_0_1, TXD0_MODE, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD0_CLK_EN, 0x00)); + break; + case 1: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_TX_ANA_MODE_0_1, TXD1_MODE, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD1_CLK_EN, 0x00)); + break; + case 2: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_TX_ANA_MODE_2_3, TXD2_MODE, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD2_CLK_EN, 0x00)); + break; + case 3: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_TX_ANA_MODE_2_3, TXD3_MODE, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL, TXD3_CLK_EN, 0x00)); + break; + default: + break; + } + if (wcd939x->adc_count == 0) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_TX_DIV2_CLK_EN, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_TX_CLK_EN, 0x00)); + } + break; + }; + return ret; +} + +int wcd939x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + + struct wcd939x_priv *wcd939x = 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; + int ret = 0; + + if ((micb_index < 0) || (micb_index > WCD939X_MAX_MICBIAS - 1)) { + dev_err_ratelimited(component->dev, + "%s: Invalid micbias index, micb_ind:%d\n", + __func__, micb_index); + return -EINVAL; + } + + if (NULL == wcd939x) { + dev_err_ratelimited(component->dev, + "%s: wcd939x private data is NULL\n", __func__); + return -EINVAL; + } + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD939X_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD939X_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 = WCD939X_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD939X_MICB4; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + }; + mutex_lock(&wcd939x->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + if (!wcd939x->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + wcd939x->pullup_ref[micb_index]++; + if ((wcd939x->pullup_ref[micb_index] == 1) && + (wcd939x->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + if (wcd939x->pullup_ref[micb_index] > 0) + wcd939x->pullup_ref[micb_index]--; + if (!wcd939x->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + if ((wcd939x->pullup_ref[micb_index] == 0) && + (wcd939x->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + if (!wcd939x->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + wcd939x->micb_ref[micb_index]++; + if (wcd939x->micb_ref[micb_index] == 1) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL,TXD3_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL,TXD2_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL,TXD1_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_DIG_CLK_CTL,TXD0_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_CLK_CTL, ANA_TX_DIV2_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(CDC_ANA_TX_CLK_CTL, ANA_TXSCBIAS_CLK_EN, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TEST_CTL_2, IBIAS_LDO_DRIVER, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MICB2_TEST_CTL_2, IBIAS_LDO_DRIVER, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MICB3_TEST_CTL_2, IBIAS_LDO_DRIVER, 0x01)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(MICB4_TEST_CTL_2, IBIAS_LDO_DRIVER, 0x01)); + snd_soc_component_update_bits(component, + micb_reg, 0xC0, 0x40); + if (post_on_event) + blocking_notifier_call_chain( + &wcd939x->mbhc->notifier, + post_on_event, + &wcd939x->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_on && wcd939x->mbhc) + blocking_notifier_call_chain(&wcd939x->mbhc->notifier, + post_dapm_on, + &wcd939x->mbhc->wcd_mbhc); + break; + case MICB_DISABLE: + if (wcd939x->micb_ref[micb_index] > 0) + wcd939x->micb_ref[micb_index]--; + if (!wcd939x->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } + if ((wcd939x->micb_ref[micb_index] == 0) && + (wcd939x->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((wcd939x->micb_ref[micb_index] == 0) && + (wcd939x->pullup_ref[micb_index] == 0)) { + if (pre_off_event && wcd939x->mbhc) + blocking_notifier_call_chain( + &wcd939x->mbhc->notifier, + pre_off_event, + &wcd939x->mbhc->wcd_mbhc); + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + if (post_off_event && wcd939x->mbhc) + blocking_notifier_call_chain( + &wcd939x->mbhc->notifier, + post_off_event, + &wcd939x->mbhc->wcd_mbhc); + } + if (is_dapm && post_dapm_off && wcd939x->mbhc) + blocking_notifier_call_chain(&wcd939x->mbhc->notifier, + post_dapm_off, + &wcd939x->mbhc->wcd_mbhc); + break; + }; + + dev_dbg(component->dev, + "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", + __func__, micb_num, wcd939x->micb_ref[micb_index], + wcd939x->pullup_ref[micb_index]); + +done: + mutex_unlock(&wcd939x->micb_lock); + return ret; +} +EXPORT_SYMBOL(wcd939x_micbias_control); + +static int wcd939x_get_logical_addr(struct swr_device *swr_dev) +{ + int ret = 0; + uint8_t devnum = 0; + int num_retry = NUM_ATTEMPTS; + + do { + /* retry after 1ms */ + usleep_range(1000, 1010); + ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum); + } while (ret && --num_retry); + + if (ret) + dev_err_ratelimited(&swr_dev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, devnum, swr_dev->addr); + + swr_dev->dev_num = devnum; + return 0; +} + +static bool get_usbc_hs_status(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + if (mbhc_cfg->enable_usbc_analog) { + if (!(snd_soc_component_read(component, WCD939X_MBHC_MECH) + & 0x20)) + return true; + } + return false; +} + +int wcd939x_swr_dmic_register_notifier(struct snd_soc_component *component, + struct notifier_block *nblock, + bool enable) +{ + struct wcd939x_priv *wcd939x_priv; + if(NULL == component) { + pr_err_ratelimited("%s: wcd939x component is NULL\n", __func__); + return -EINVAL; + } + + wcd939x_priv = snd_soc_component_get_drvdata(component); + wcd939x_priv->notify_swr_dmic = enable; + if (enable) + return blocking_notifier_chain_register(&wcd939x_priv->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd939x_priv->notifier, nblock); +} +EXPORT_SYMBOL(wcd939x_swr_dmic_register_notifier); + +static int wcd939x_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + int ret = 0; + int rx_clk_type; + struct wcd939x_priv *wcd939x = dev_get_drvdata((struct device *)data); + struct snd_soc_component *component = wcd939x->component; + struct wcd_mbhc *mbhc; + + switch (event) { + case BOLERO_SLV_EVT_TX_CH_HOLD_CLEAR: + if (test_bit(WCD_ADC1, &wcd939x->status_mask)) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TX_CH2, HPF1_INIT, 0x00)); + set_bit(WCD_ADC1_MODE, &wcd939x->status_mask); + clear_bit(WCD_ADC1, &wcd939x->status_mask); + } + if (test_bit(WCD_ADC2, &wcd939x->status_mask)) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TX_CH2, HPF2_INIT, 0x00)); + set_bit(WCD_ADC2_MODE, &wcd939x->status_mask); + clear_bit(WCD_ADC2, &wcd939x->status_mask); + } + if (test_bit(WCD_ADC3, &wcd939x->status_mask)) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TX_CH4, HPF3_INIT, 0x00)); + set_bit(WCD_ADC3_MODE, &wcd939x->status_mask); + clear_bit(WCD_ADC3, &wcd939x->status_mask); + } + if (test_bit(WCD_ADC4, &wcd939x->status_mask)) { + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(TX_CH4, HPF4_INIT, 0x00)); + set_bit(WCD_ADC4_MODE, &wcd939x->status_mask); + clear_bit(WCD_ADC4, &wcd939x->status_mask); + } + break; + case BOLERO_SLV_EVT_PA_OFF_PRE_SSR: + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHL_ENABLE, 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(HPH, HPHR_ENABLE , 0x00)); + snd_soc_component_update_bits(component, + REG_FIELD_VALUE(EAR, ENABLE, 0x00)); + break; + case BOLERO_SLV_EVT_SSR_DOWN: + wcd939x->dev_up = false; + if(wcd939x->notify_swr_dmic) + blocking_notifier_call_chain(&wcd939x->notifier, + WCD939X_EVT_SSR_DOWN, + NULL); + wcd939x->mbhc->wcd_mbhc.deinit_in_progress = true; + mbhc = &wcd939x->mbhc->wcd_mbhc; + wcd939x->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); + wcd939x_mbhc_ssr_down(wcd939x->mbhc, component); + wcd939x_reset_low(wcd939x->dev); + break; + case BOLERO_SLV_EVT_SSR_UP: + wcd939x_reset(wcd939x->dev); + /* allow reset to take effect */ + usleep_range(10000, 10010); + + wcd939x_get_logical_addr(wcd939x->tx_swr_dev); + wcd939x_get_logical_addr(wcd939x->rx_swr_dev); + + wcd939x_init_reg(component); + regcache_mark_dirty(wcd939x->regmap); + regcache_sync(wcd939x->regmap); + /* Initialize MBHC module */ + mbhc = &wcd939x->mbhc->wcd_mbhc; + ret = wcd939x_mbhc_post_ssr_init(wcd939x->mbhc, component); + if (ret) { + dev_err_ratelimited(component->dev, "%s: mbhc initialization failed\n", + __func__); + } else { + wcd939x_mbhc_hs_detect(component, mbhc->mbhc_cfg); + } + wcd939x->mbhc->wcd_mbhc.deinit_in_progress = false; + wcd939x->dev_up = true; + if(wcd939x->notify_swr_dmic) + blocking_notifier_call_chain(&wcd939x->notifier, + WCD939X_EVT_SSR_UP, + NULL); + if (wcd939x->usbc_hs_status) + mdelay(500); + break; + case BOLERO_SLV_EVT_CLK_NOTIFY: + snd_soc_component_update_bits(component, + WCD939X_TOP_CLK_CFG, 0x06, + ((val >> 0x10) << 0x01)); + + rx_clk_type = (val >> 0x10); + + switch(rx_clk_type) { + case RX_CLK_12P288MHZ: + wcd939x->rx_clk_config = RX_CLK_12P288MHZ; + break; + case RX_CLK_11P2896MHZ: + wcd939x->rx_clk_config = RX_CLK_11P2896MHZ; + break; + default: + wcd939x->rx_clk_config = RX_CLK_9P6MHZ; + break; + } + dev_dbg(component->dev, "%s: rx clk config %d\n", __func__, wcd939x->rx_clk_config); + break; + default: + dev_dbg(component->dev, "%s: invalid event %d\n", __func__, event); + break; + } + return 0; +} + +static int __wcd939x_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: + wcd939x_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: + wcd939x_micbias_control(component, micb_num, + MICB_DISABLE, true); + break; + }; + + return 0; + +} + +static int wcd939x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd939x_codec_enable_micbias(w, event); +} + +static int __wcd939x_codec_enable_micbias_pullup(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, "VA MIC BIAS1", sizeof("VA MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else if (strnstr(w->name, "VA MIC BIAS4", sizeof("VA MIC BIAS4"))) + micb_num = MIC_BIAS_4; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x_micbias_control(component, micb_num, + MICB_PULLUP_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: + wcd939x_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + break; + }; + + return 0; + +} + +static int wcd939x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + return __wcd939x_codec_enable_micbias_pullup(w, event); +} + +static int wcd939x_wakeup(void *handle, bool enable) +{ + struct wcd939x_priv *priv; + int ret = 0; + + if (!handle) { + pr_err_ratelimited("%s: NULL handle\n", __func__); + return -EINVAL; + } + priv = (struct wcd939x_priv *)handle; + if (!priv->tx_swr_dev) { + pr_err_ratelimited("%s: tx swr dev is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&priv->wakeup_lock); + if (enable) + ret = swr_device_wakeup_vote(priv->tx_swr_dev); + else + ret = swr_device_wakeup_unvote(priv->tx_swr_dev); + mutex_unlock(&priv->wakeup_lock); + + return ret; +} + +static int wcd939x_codec_force_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x_wakeup(wcd939x, true); + ret = __wcd939x_codec_enable_micbias(w, SND_SOC_DAPM_PRE_PMU); + wcd939x_wakeup(wcd939x, false); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_wakeup(wcd939x, true); + ret = __wcd939x_codec_enable_micbias(w, SND_SOC_DAPM_POST_PMD); + wcd939x_wakeup(wcd939x, false); + break; + } + + return ret; +} + +static int wcd939x_enable_micbias(struct wcd939x_priv *wcd939x, + int micb_num, int req) +{ + int micb_index = micb_num - 1; + u16 micb_reg; + + if (NULL == wcd939x) { + pr_err_ratelimited("%s: wcd939x private data is NULL\n", __func__); + return -EINVAL; + } + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD939X_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD939X_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD939X_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD939X_MICB4; + break; + default: + pr_err_ratelimited("%s: Invalid micbias number: %d\n", __func__, micb_num); + return -EINVAL; + }; + + pr_debug("%s: req: %d micb_num: %d micb_ref: %d pullup_ref: %d\n", + __func__, req, micb_num, wcd939x->micb_ref[micb_index], + wcd939x->pullup_ref[micb_index]); + mutex_lock(&wcd939x->micb_lock); + + switch (req) { + case MICB_ENABLE: + wcd939x->micb_ref[micb_index]++; + if (wcd939x->micb_ref[micb_index] == 1) { + regmap_update_bits(wcd939x->regmap, + WCD939X_CDC_DIG_CLK_CTL, 0xE0, 0xE0); + regmap_update_bits(wcd939x->regmap, + WCD939X_CDC_ANA_CLK_CTL, 0x10, 0x10); + regmap_update_bits(wcd939x->regmap, + WCD939X_CDC_ANA_TX_CLK_CTL, 0x01, 0x01); + regmap_update_bits(wcd939x->regmap, + WCD939X_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd939x->regmap, + WCD939X_MICB2_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd939x->regmap, + WCD939X_MICB3_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd939x->regmap, + WCD939X_MICB4_TEST_CTL_2, 0x01, 0x01); + regmap_update_bits(wcd939x->regmap, + micb_reg, 0xC0, 0x40); + regmap_update_bits(wcd939x->regmap, micb_reg, 0x3F, 0x10); + } + break; + case MICB_PULLUP_ENABLE: + wcd939x->pullup_ref[micb_index]++; + if ((wcd939x->pullup_ref[micb_index] == 1) && + (wcd939x->micb_ref[micb_index] == 0)) + regmap_update_bits(wcd939x->regmap, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + if (wcd939x->pullup_ref[micb_index] > 0) + wcd939x->pullup_ref[micb_index]--; + + if ((wcd939x->pullup_ref[micb_index] == 0) && + (wcd939x->micb_ref[micb_index] == 0)) + regmap_update_bits(wcd939x->regmap, micb_reg, + 0xC0, 0x00); + break; + case MICB_DISABLE: + if (wcd939x->micb_ref[micb_index] > 0) + wcd939x->micb_ref[micb_index]--; + + if ((wcd939x->micb_ref[micb_index] == 0) && + (wcd939x->pullup_ref[micb_index] > 0)) + regmap_update_bits(wcd939x->regmap, micb_reg, + 0xC0, 0x80); + else if ((wcd939x->micb_ref[micb_index] == 0) && + (wcd939x->pullup_ref[micb_index] == 0)) + regmap_update_bits(wcd939x->regmap, micb_reg, + 0xC0, 0x00); + break; + }; + + mutex_unlock(&wcd939x->micb_lock); + return 0; +} + +int wcd939x_codec_force_enable_micbias_v2(struct snd_soc_component *component, + int event, int micb_num) +{ + struct wcd939x_priv *wcd939x_priv = NULL; + int ret = 0; + int micb_index = micb_num - 1; + + if(NULL == component) { + pr_err_ratelimited("%s: wcd939x component is NULL\n", __func__); + return -EINVAL; + } + if(event != SND_SOC_DAPM_PRE_PMU && event != SND_SOC_DAPM_POST_PMD) { + pr_err_ratelimited("%s: invalid event: %d\n", __func__, event); + return -EINVAL; + } + if(micb_num < MIC_BIAS_1 || micb_num > MIC_BIAS_4) { + pr_err_ratelimited("%s: invalid mic bias num: %d\n", __func__, micb_num); + return -EINVAL; + } + + wcd939x_priv = snd_soc_component_get_drvdata(component); + + if (!wcd939x_priv->dev_up) { + if ((wcd939x_priv->pullup_ref[micb_index] > 0) && + (event == SND_SOC_DAPM_POST_PMD)) { + wcd939x_priv->pullup_ref[micb_index]--; + ret = -ENODEV; + goto done; + } + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd939x_wakeup(wcd939x_priv, true); + wcd939x_enable_micbias(wcd939x_priv, micb_num, MICB_PULLUP_ENABLE); + wcd939x_wakeup(wcd939x_priv, false); + break; + case SND_SOC_DAPM_POST_PMD: + wcd939x_wakeup(wcd939x_priv, true); + wcd939x_enable_micbias(wcd939x_priv, micb_num, MICB_PULLUP_DISABLE); + wcd939x_wakeup(wcd939x_priv, false); + break; + } + +done: + return ret; +} +EXPORT_SYMBOL(wcd939x_codec_force_enable_micbias_v2); + +static inline int wcd939x_tx_path_get(const char *wname, + unsigned int *path_num) +{ + int ret = 0; + char *widget_name = NULL; + char *w_name = NULL; + char *path_num_char = NULL; + char *path_name = NULL; + + widget_name = kstrndup(wname, 9, GFP_KERNEL); + if (!widget_name) + return -EINVAL; + + w_name = widget_name; + + path_name = strsep(&widget_name, " "); + if (!path_name) { + pr_err_ratelimited("%s: Invalid widget name = %s\n", + __func__, widget_name); + ret = -EINVAL; + goto err; + } + path_num_char = strpbrk(path_name, "0123"); + if (!path_num_char) { + pr_err_ratelimited("%s: tx path index not found\n", + __func__); + ret = -EINVAL; + goto err; + } + ret = kstrtouint(path_num_char, 10, path_num); + if (ret < 0) + pr_err_ratelimited("%s: Invalid tx path = %s\n", + __func__, w_name); + +err: + kfree(w_name); + return ret; +} + +static int wcd939x_tx_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = NULL; + int ret = 0; + unsigned int path = 0; + + if (!component) + return -EINVAL; + + wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x) + return -EINVAL; + + ret = wcd939x_tx_path_get(kcontrol->id.name, &path); + if (ret < 0) + return ret; + + ucontrol->value.integer.value[0] = wcd939x->tx_mode[path]; + + return 0; +} + +static int wcd939x_tx_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = NULL; + u32 mode_val; + unsigned int path = 0; + int ret = 0; + + if (!component) + return -EINVAL; + + wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x) + return -EINVAL; + + ret = wcd939x_tx_path_get(kcontrol->id.name, &path); + if (ret) + return ret; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: mode: %d\n", __func__, mode_val); + + wcd939x->tx_mode[path] = mode_val; + + return 0; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd939x->hph_mode; + return 0; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = 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 (wcd939x->variant == WCD9390) { + if (mode_val == CLS_H_HIFI || mode_val == CLS_AB_HIFI) { + dev_info_ratelimited(component->dev, + "%s:Invalid HPH Mode, default to CLS_H_ULP\n", + __func__); + mode_val = CLS_H_ULP; + } + } + if (mode_val == CLS_H_NORMAL) { + dev_info_ratelimited(component->dev, + "%s:Invalid HPH Mode, default to class_AB\n", + __func__); + mode_val = CLS_H_ULP; + } + wcd939x->hph_mode = mode_val; + + return 0; +} + +static int wcd939x_ear_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + ear_pa_gain = snd_soc_component_read(component, + WCD939X_EAR_COMPANDER_CTL); + + ear_pa_gain = (ear_pa_gain & 0x7C) >> 2; + + ucontrol->value.integer.value[0] = ear_pa_gain; + + dev_dbg(component->dev, "%s: ear_pa_gain = 0x%x\n", __func__, + ear_pa_gain); + + return 0; +} + +static int wcd939x_ear_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain = 0; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + ear_pa_gain = ucontrol->value.integer.value[0] << 2; + + snd_soc_component_update_bits(component, + WCD939X_EAR_COMPANDER_CTL, + 0x7C, ear_pa_gain); + + return 0; +} + +/* wcd939x_codec_get_dev_num - returns swr device number + * @component: Codec instance + * + * Return: swr device number on success or negative error + * code on failure. + */ +int wcd939x_codec_get_dev_num(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x; + + if (!component) + return -EINVAL; + + wcd939x = snd_soc_component_get_drvdata(component); + if (!wcd939x || !wcd939x->rx_swr_dev) { + pr_err_ratelimited("%s: wcd939x component is NULL\n", __func__); + return -EINVAL; + } + + return wcd939x->rx_swr_dev->dev_num; +} +EXPORT_SYMBOL(wcd939x_codec_get_dev_num); + +static int wcd939x_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = 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 ? wcd939x->comp2_enable : + wcd939x->comp1_enable; + return 0; +} + +static int wcd939x_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = 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) + wcd939x->comp2_enable = value; + else + wcd939x->comp1_enable = value; + + return 0; +} + +static int wcd939x_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + struct wcd939x_pdata *pdata = NULL; + int ret = 0; + + pdata = dev_get_platdata(wcd939x->dev); + + if (!pdata) { + dev_err_ratelimited(component->dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (!msm_cdc_is_ondemand_supply(wcd939x->dev, + wcd939x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck")) + return 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (test_bit(ALLOW_BUCK_DISABLE, &wcd939x->status_mask)) { + dev_dbg(component->dev, + "%s: buck already in enabled state\n", + __func__); + clear_bit(ALLOW_BUCK_DISABLE, &wcd939x->status_mask); + return 0; + } + ret = msm_cdc_enable_ondemand_supply(wcd939x->dev, + wcd939x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck"); + if (ret == -EINVAL) { + dev_err_ratelimited(component->dev, "%s: vdd buck is not enabled\n", + __func__); + return ret; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd939x->status_mask); + /* + * 200us sleep is required after LDO is enabled as per + * HW requirement + */ + usleep_range(200, 250); + break; + case SND_SOC_DAPM_POST_PMD: + set_bit(ALLOW_BUCK_DISABLE, &wcd939x->status_mask); + break; + } + return 0; +} + + +static int wcd939x_ldoh_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd939x->ldoh; + + return 0; +} + +static int wcd939x_ldoh_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + wcd939x->ldoh = ucontrol->value.integer.value[0]; + + return 0; +} + +const char * const tx_master_ch_text[] = { + "ZERO", "SWRM_PCM_OUT", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", + "SWRM_TX1_CH4", "SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", + "SWRM_TX2_CH4", "SWRM_TX3_CH1", "SWRM_TX3_CH2", "SWRM_TX3_CH3", + "SWRM_TX3_CH4", "SWRM_PCM_IN", +}; + +const struct soc_enum tx_master_ch_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_master_ch_text), + tx_master_ch_text); + +static void wcd939x_tx_get_slave_ch_type_idx(const char *wname, int *ch_idx) +{ + u8 ch_type = 0; + + if (strnstr(wname, "ADC1", sizeof("ADC1"))) + ch_type = ADC1; + else if (strnstr(wname, "ADC2", sizeof("ADC2"))) + ch_type = ADC2; + else if (strnstr(wname, "ADC3", sizeof("ADC3"))) + ch_type = ADC3; + else if (strnstr(wname, "ADC4", sizeof("ADC4"))) + ch_type = ADC4; + else if (strnstr(wname, "DMIC0", sizeof("DMIC0"))) + ch_type = DMIC0; + else if (strnstr(wname, "DMIC1", sizeof("DMIC1"))) + ch_type = DMIC1; + else if (strnstr(wname, "MBHC", sizeof("MBHC"))) + ch_type = MBHC; + else if (strnstr(wname, "DMIC2", sizeof("DMIC2"))) + ch_type = DMIC2; + else if (strnstr(wname, "DMIC3", sizeof("DMIC3"))) + ch_type = DMIC3; + else if (strnstr(wname, "DMIC4", sizeof("DMIC4"))) + ch_type = DMIC4; + else if (strnstr(wname, "DMIC5", sizeof("DMIC5"))) + ch_type = DMIC5; + else if (strnstr(wname, "DMIC6", sizeof("DMIC6"))) + ch_type = DMIC6; + else if (strnstr(wname, "DMIC7", sizeof("DMIC7"))) + ch_type = DMIC7; + else + pr_err_ratelimited("%s: port name: %s is not listed\n", __func__, wname); + + if (ch_type) + *ch_idx = wcd939x_slave_get_slave_ch_val(ch_type); + else + *ch_idx = -EINVAL; +} + +static int wcd939x_tx_master_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = NULL; + int slave_ch_idx = -EINVAL; + + if (component == NULL) + return -EINVAL; + + wcd939x = snd_soc_component_get_drvdata(component); + if (wcd939x == NULL) + return -EINVAL; + + wcd939x_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + if (slave_ch_idx < 0 || slave_ch_idx >= WCD939X_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + ucontrol->value.integer.value[0] = wcd939x_slave_get_master_ch_val( + wcd939x->tx_master_ch_map[slave_ch_idx]); + + return 0; +} + +static int wcd939x_tx_master_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = NULL; + int slave_ch_idx = -EINVAL, idx = 0; + + if (component == NULL) + return -EINVAL; + + wcd939x = snd_soc_component_get_drvdata(component); + if (wcd939x == NULL) + return -EINVAL; + + wcd939x_tx_get_slave_ch_type_idx(kcontrol->id.name, &slave_ch_idx); + + if (slave_ch_idx < 0 || slave_ch_idx >= WCD939X_MAX_SLAVE_CH_TYPES) + return -EINVAL; + + dev_dbg(component->dev, "%s: slave_ch_idx: %d", __func__, slave_ch_idx); + dev_dbg(component->dev, "%s: ucontrol->value.enumerated.item[0] = %ld\n", + __func__, ucontrol->value.enumerated.item[0]); + + idx = ucontrol->value.enumerated.item[0]; + if (idx < 0 || idx >= ARRAY_SIZE(swr_master_ch_map)) + return -EINVAL; + + wcd939x->tx_master_ch_map[slave_ch_idx] = wcd939x_slave_get_master_ch(idx); + return 0; +} + +static int wcd939x_bcs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd939x->bcs_dis; + + return 0; +} + +static int wcd939x_bcs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + wcd939x->bcs_dis = ucontrol->value.integer.value[0]; + + return 0; +} + +static const char * const tx_mode_mux_text_wcd9390[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", +}; + +static const struct soc_enum tx_mode_mux_enum_wcd9390 = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_mux_text_wcd9390), + tx_mode_mux_text_wcd9390); + +static const char * const tx_mode_mux_text[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", + "ADC_ULP1", "ADC_ULP2", +}; + +static const struct soc_enum tx_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const char * const rx_hph_mode_mux_text_wcd9390[] = { + "CLS_H_INVALID", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB", + "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP", + "CLS_AB_LOHIFI", +}; + +static const char * const wcd939x_ear_pa_gain_text[] = { + "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", "G_0_DB", + "G_M1P5_DB", "G_M3_DB", "G_M4P5_DB", + "G_M6_DB", "G_7P5_DB", "G_M9_DB", + "G_M10P5_DB", "G_M12_DB", "G_M13P5_DB", + "G_M15_DB", "G_M16P5_DB", "G_M18_DB", +}; + +static const struct soc_enum rx_hph_mode_mux_enum_wcd9390 = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9390), + rx_hph_mode_mux_text_wcd9390); + +static SOC_ENUM_SINGLE_EXT_DECL(wcd939x_ear_pa_gain_enum, + wcd939x_ear_pa_gain_text); + +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", "CLS_AB_LP", "CLS_AB_LOHIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static const struct snd_kcontrol_new wcd9390_snd_controls[] = { + SOC_ENUM_EXT("EAR PA GAIN", wcd939x_ear_pa_gain_enum, + wcd939x_ear_pa_gain_get, wcd939x_ear_pa_gain_put), + + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9390, + wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), + + SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum_wcd9390, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), +}; + +static const struct snd_kcontrol_new wcd9395_snd_controls[] = { + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), + + SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum, + wcd939x_tx_mode_get, wcd939x_tx_mode_put), +}; + +static const struct snd_kcontrol_new wcd939x_snd_controls[] = { + SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0, + wcd939x_get_compander, wcd939x_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0, + wcd939x_get_compander, wcd939x_set_compander), + SOC_SINGLE_EXT("LDOH Enable", SND_SOC_NOPM, 0, 1, 0, + wcd939x_ldoh_get, wcd939x_ldoh_put), + + SOC_SINGLE_EXT("ADC2_BCS Disable", SND_SOC_NOPM, 0, 1, 0, + wcd939x_bcs_get, wcd939x_bcs_put), + + SOC_SINGLE_TLV("HPHL Volume", WCD939X_PA_GAIN_CTL_L, 0, 0x18, 0, hph_analog_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD939X_PA_GAIN_CTL_R, 0, 0x18, 0, hph_analog_gain), + SOC_SINGLE_TLV("ADC1 Volume", WCD939X_TX_CH1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD939X_TX_CH2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD939X_TX_CH3, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD939X_TX_CH4, 0, 20, 0, + analog_gain), + + SOC_SINGLE_EXT("HPHL Compander", SND_SOC_NOPM, WCD939X_HPHL, 1, 0, + wcd939x_hph_compander_get, wcd939x_hph_compander_put), + SOC_SINGLE_EXT("HPHR Compander", SND_SOC_NOPM, WCD939X_HPHR, 1, 0, + wcd939x_hph_compander_get, wcd939x_hph_compander_put), + + SOC_SINGLE_EXT("HPHL XTALK", SND_SOC_NOPM, WCD939X_HPHL, 1, 0, + wcd939x_hph_xtalk_get, wcd939x_hph_xtalk_put), + SOC_SINGLE_EXT("HPHR XTALK", SND_SOC_NOPM, WCD939X_HPHR, 1, 0, + wcd939x_hph_xtalk_get, wcd939x_hph_xtalk_put), + + SOC_SINGLE_EXT("HPH PCM Enable", SND_SOC_NOPM, 0, 1, 0, + wcd939x_hph_pcm_enable_get, wcd939x_hph_pcm_enable_put), + + SOC_ENUM_EXT("ADC1 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("ADC2 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("ADC3 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("ADC4 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC0 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC1 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("MBHC ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC2 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC3 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC4 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC5 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC6 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), + SOC_ENUM_EXT("DMIC7 ChMap", tx_master_ch_enum, + wcd939x_tx_master_ch_get, wcd939x_tx_master_ch_put), +}; + +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 amic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new amic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new va_amic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic0_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 ear_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 adc1_mux_text[] = { + "CH1_AMIC_DISABLE", "CH1_AMIC1", "CH1_AMIC2", "CH1_AMIC3", "CH1_AMIC4", "CH1_AMIC5" +}; + +static const struct soc_enum adc1_enum = + SOC_ENUM_SINGLE(WCD939X_TX_CH12_MUX, WCD939X_TX_CH12_MUX_CH1_SEL_SHIFT, + ARRAY_SIZE(adc1_mux_text), adc1_mux_text); + +static const struct snd_kcontrol_new tx_adc1_mux = + SOC_DAPM_ENUM("ADC1 MUX Mux", adc1_enum); + +static const char * const adc2_mux_text[] = { + "CH2_AMIC_DISABLE", "CH2_AMIC1", "CH2_AMIC2", "CH2_AMIC3", "CH2_AMIC4", "CH2_AMIC5" +}; + +static const struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD939X_TX_CH12_MUX, WCD939X_TX_CH12_MUX_CH2_SEL_SHIFT, + 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[] = { + "CH3_AMIC_DISABLE", "CH3_AMIC1", "CH3_AMIC3", "CH3_AMIC4", "CH3_AMIC5" +}; + +static const struct soc_enum adc3_enum = + SOC_ENUM_SINGLE(WCD939X_TX_CH34_MUX, WCD939X_TX_CH34_MUX_CH3_SEL_SHIFT, + 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[] = { + "CH4_AMIC_DISABLE", "CH4_AMIC1", "CH4_AMIC3", "CH4_AMIC4", "CH4_AMIC5" +}; + +static const struct soc_enum adc4_enum = + SOC_ENUM_SINGLE(WCD939X_TX_CH34_MUX, WCD939X_TX_CH34_MUX_CH4_SEL_SHIFT, + 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[] = { + "RX3", "RX1" +}; + + +static const struct soc_enum rdac3_enum = + SOC_ENUM_SINGLE(WCD939X_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 char * const rx1_mux_text[] = { + "ZERO", "RX1 MUX" +}; +static const struct soc_enum rx1_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 0, rx1_mux_text); +static const struct snd_kcontrol_new rx1_mux = + SOC_DAPM_ENUM("RX1 MUX Mux", rx1_enum); + + +static const char * const rx2_mux_text[] = { + "ZERO", "RX2 MUX" +}; +static const struct soc_enum rx2_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 0, rx2_mux_text); +static const struct snd_kcontrol_new rx2_mux = + SOC_DAPM_ENUM("RX2 MUX Mux", rx2_enum); + +static const char * const rx3_mux_text[] = { + "ZERO", "RX3 MUX" +}; +static const struct soc_enum rx3_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 0, rx3_mux_text); +static const struct snd_kcontrol_new rx3_mux = + SOC_DAPM_ENUM("RX3 MUX Mux", rx3_enum); + +static const struct snd_soc_dapm_widget wcd939x_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("VA AMIC1"), + SND_SOC_DAPM_INPUT("VA AMIC2"), + SND_SOC_DAPM_INPUT("VA AMIC3"), + SND_SOC_DAPM_INPUT("VA AMIC4"), + SND_SOC_DAPM_INPUT("VA AMIC5"), + + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_EAR"), + /* + * These dummy widgets are null connected to WCD939x dapm input and + * output widgets which are not actual path endpoints. This ensures + * dapm doesnt set these dapm input and output widgets as endpoints. + */ + SND_SOC_DAPM_INPUT("WCD_TX_DUMMY"), + SND_SOC_DAPM_OUTPUT("WCD_RX_DUMMY"), + + /*tx widgets*/ + SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0, + wcd939x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 1, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 2, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 3, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 4, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 5, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 6, 0, + wcd939x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 7, 0, + wcd939x_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, wcd939x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 1, 0, + NULL, 0, wcd939x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 2, 0, + NULL, 0, wcd939x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 3, 0, + NULL, 0, wcd939x_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC1_MIXER", SND_SOC_NOPM, 0, 0, + amic1_switch, ARRAY_SIZE(amic1_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC2_MIXER", SND_SOC_NOPM, 0, 0, + amic2_switch, ARRAY_SIZE(amic2_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC3_MIXER", SND_SOC_NOPM, 0, 0, + amic3_switch, ARRAY_SIZE(amic3_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC4_MIXER", SND_SOC_NOPM, 0, 0, + amic4_switch, ARRAY_SIZE(amic4_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("AMIC5_MIXER", SND_SOC_NOPM, 0, 0, + amic5_switch, ARRAY_SIZE(amic5_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC1_MIXER", SND_SOC_NOPM, 0, 0, + va_amic1_switch, ARRAY_SIZE(va_amic1_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC2_MIXER", SND_SOC_NOPM, 0, 0, + va_amic2_switch, ARRAY_SIZE(va_amic2_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC3_MIXER", SND_SOC_NOPM, 0, 0, + va_amic3_switch, ARRAY_SIZE(va_amic3_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC4_MIXER", SND_SOC_NOPM, 0, 0, + va_amic4_switch, ARRAY_SIZE(va_amic4_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("VA_AMIC5_MIXER", SND_SOC_NOPM, 0, 0, + va_amic5_switch, ARRAY_SIZE(va_amic5_switch), NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC1 MUX", SND_SOC_NOPM, 0, 0, + &tx_adc1_mux), + 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, ADC1, 0, + adc1_switch, ARRAY_SIZE(adc1_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, ADC2, 0, + adc2_switch, ARRAY_SIZE(adc2_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, ADC3, 0, adc3_switch, + ARRAY_SIZE(adc3_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, ADC4, 0, adc4_switch, + ARRAY_SIZE(adc4_switch), wcd939x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC0_MIXER", SND_SOC_NOPM, DMIC0, + 0, dmic0_switch, ARRAY_SIZE(dmic0_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, DMIC1, + 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, DMIC2, + 0, dmic2_switch, ARRAY_SIZE(dmic2_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, DMIC3, + 0, dmic3_switch, ARRAY_SIZE(dmic3_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, DMIC4, + 0, dmic4_switch, ARRAY_SIZE(dmic4_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, DMIC5, + 0, dmic5_switch, ARRAY_SIZE(dmic5_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, DMIC6, + 0, dmic6_switch, ARRAY_SIZE(dmic6_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, DMIC7, + 0, dmic7_switch, ARRAY_SIZE(dmic7_switch), + wcd939x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + /* micbias widgets*/ + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd939x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS2_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd939x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS3_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd939x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0, + wcd939x_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, + wcd939x_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, + wcd939x_enable_clsh, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("CLS_H_DUMMY", 1, SND_SOC_NOPM, 0, 0, + wcd939x_clsh_dummy, SND_SOC_DAPM_POST_PMD), + + /*rx widgets*/ + SND_SOC_DAPM_PGA_E("EAR PGA", WCD939X_EAR, 7, 0, NULL, 0, + wcd939x_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", WCD939X_HPH, 7, 0, NULL, 0, + wcd939x_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", WCD939X_HPH, 6, 0, NULL, 0, + wcd939x_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd939x_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, + wcd939x_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, + wcd939x_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_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), + + SND_SOC_DAPM_MUX_E("RX1 MUX", SND_SOC_NOPM, WCD_RX1, 0, &rx1_mux, + wcd939x_rx_mux, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU + | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX2 MUX", SND_SOC_NOPM, WCD_RX2, 0, &rx2_mux, + wcd939x_rx_mux, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU + | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX3 MUX", SND_SOC_NOPM, WCD_RX3, 0, &rx3_mux, + wcd939x_rx3_mux, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, + wcd939x_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, + wcd939x_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, + wcd939x_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("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("WCD_TX_OUTPUT"), + + /*output widgets rx*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + + /* micbias pull up widgets*/ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, 0, 0, + wcd939x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route wcd939x_audio_map[] = { + +/*ADC-1 (channel-1)*/ + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, + {"WCD_TX_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1 REQ"}, + {"ADC1 REQ", NULL, "ADC1"}, + {"ADC1", NULL, "ADC1 MUX"}, + {"ADC1 MUX", "CH1_AMIC1", "AMIC1_MIXER"}, + {"ADC1 MUX", "CH1_AMIC2", "AMIC2_MIXER"}, + {"ADC1 MUX", "CH1_AMIC3", "AMIC3_MIXER"}, + {"ADC1 MUX", "CH1_AMIC4", "AMIC4_MIXER"}, + {"ADC1 MUX", "CH1_AMIC5", "AMIC5_MIXER"}, + + {"AMIC1_MIXER", "Switch", "AMIC1"}, + {"AMIC1_MIXER", NULL, "VA_AMIC1_MIXER"}, + {"VA_AMIC1_MIXER", "Switch", "VA AMIC1"}, + + {"AMIC2_MIXER", "Switch", "AMIC2"}, + {"AMIC2_MIXER", NULL, "VA_AMIC2_MIXER"}, + {"VA_AMIC2_MIXER", "Switch", "VA AMIC2"}, + + {"AMIC3_MIXER", "Switch", "AMIC3"}, + {"AMIC3_MIXER", NULL, "VA_AMIC3_MIXER"}, + {"VA_AMIC3_MIXER", "Switch", "VA AMIC3"}, + + {"AMIC4_MIXER", "Switch", "AMIC4"}, + {"AMIC4_MIXER", NULL, "VA_AMIC4_MIXER"}, + {"VA_AMIC4_MIXER", "Switch", "VA AMIC4"}, + + {"AMIC5_MIXER", "Switch", "AMIC5"}, + {"AMIC5_MIXER", NULL, "VA_AMIC5_MIXER"}, + {"VA_AMIC5_MIXER", "Switch", "VA AMIC5"}, + +/*ADC-2 (channel-2)*/ + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, + {"WCD_TX_OUTPUT", NULL, "ADC2_MIXER"}, + {"ADC2_MIXER", "Switch", "ADC2 REQ"}, + {"ADC2 REQ", NULL, "ADC2"}, + {"ADC2", NULL, "ADC2 MUX"}, + {"ADC2 MUX", "CH2_AMIC1", "AMIC1_MIXER"}, + {"ADC2 MUX", "CH2_AMIC2", "AMIC2_MIXER"}, + {"ADC2 MUX", "CH2_AMIC3", "AMIC3_MIXER"}, + {"ADC2 MUX", "CH2_AMIC4", "AMIC4_MIXER"}, + {"ADC2 MUX", "CH2_AMIC5", "AMIC5_MIXER"}, + +/*ADC-3 (channel-3)*/ + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, + {"WCD_TX_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_MIXER", "Switch", "ADC3 REQ"}, + {"ADC3 REQ", NULL, "ADC3"}, + {"ADC3", NULL, "ADC3 MUX"}, + {"ADC3 MUX", "CH3_AMIC1", "AMIC1_MIXER"}, + {"ADC3 MUX", "CH3_AMIC3", "AMIC3_MIXER"}, + {"ADC3 MUX", "CH3_AMIC4", "AMIC4_MIXER"}, + {"ADC3 MUX", "CH3_AMIC5", "AMIC5_MIXER"}, + +/*ADC-4 (channel-4)*/ + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, + {"WCD_TX_OUTPUT", NULL, "ADC4_MIXER"}, + {"ADC4_MIXER", "Switch", "ADC4 REQ"}, + {"ADC4 REQ", NULL, "ADC4"}, + {"ADC4", NULL, "ADC4 MUX"}, + {"ADC4 MUX", "CH4_AMIC1", "AMIC1_MIXER"}, + {"ADC4 MUX", "CH4_AMIC3", "AMIC3_MIXER"}, + {"ADC4 MUX", "CH4_AMIC4", "AMIC4_MIXER"}, + {"ADC4 MUX", "CH4_AMIC5", "AMIC5_MIXER"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC0_MIXER"}, + {"DMIC0_MIXER", "Switch", "DMIC0"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_MIXER", "Switch", "DMIC3"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_MIXER", "Switch", "DMIC4"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_MIXER", "Switch", "DMIC5"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_MIXER", "Switch", "DMIC6"}, + + {"WCD_TX_OUTPUT", NULL, "DMIC7_MIXER"}, + {"DMIC7_MIXER", "Switch", "DMIC7"}, + + {"IN1_HPHL", NULL, "WCD_RX_DUMMY"}, + {"IN1_HPHL", NULL, "VDD_BUCK"}, + {"IN1_HPHL", NULL, "CLS_H_PORT"}, + {"RX1 MUX", NULL, "IN1_HPHL"}, + {"RX1", NULL, "RX1 MUX"}, + {"RDAC1", NULL, "RX1"}, + {"HPHL_RDAC", "Switch", "RDAC1"}, + {"HPHL PGA", NULL, "HPHL_RDAC"}, + {"HPHL", NULL, "HPHL PGA"}, + + {"IN2_HPHR", NULL, "WCD_RX_DUMMY"}, + {"IN2_HPHR", NULL, "VDD_BUCK"}, + {"IN2_HPHR", NULL, "CLS_H_PORT"}, + {"RX2 MUX", NULL, "IN2_HPHR"}, + {"RX2", NULL, "RX2 MUX"}, + {"RDAC2", NULL, "RX2"}, + {"HPHR_RDAC", "Switch", "RDAC2"}, + {"HPHR PGA", NULL, "HPHR_RDAC"}, + {"HPHR", NULL, "HPHR PGA"}, + + {"IN3_EAR", NULL, "WCD_RX_DUMMY"}, + {"IN3_EAR", NULL, "VDD_BUCK"}, + {"IN3_EAR", NULL, "CLS_H_DUMMY"}, + {"RX3 MUX", NULL, "IN3_EAR"}, + {"RX3", NULL, "RX3 MUX"}, + {"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 wcd939x_version_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct wcd939x_priv *priv; + char buffer[WCD939X_VERSION_ENTRY_SIZE]; + int len = 0; + + priv = (struct wcd939x_priv *) entry->private_data; + if (!priv) { + pr_err_ratelimited("%s: wcd939x priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->version) { + case WCD939X_VERSION_1_0: + case WCD939X_VERSION_1_1: + len = snprintf(buffer, sizeof(buffer), "WCD939X_1_0\n"); + break; + case WCD939X_VERSION_2_0: + len = snprintf(buffer, sizeof(buffer), "WCD939X_2_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 wcd939x_info_ops = { + .read = wcd939x_version_read, +}; + +static ssize_t wcd939x_variant_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, size_t count, + loff_t pos) +{ + struct wcd939x_priv *priv; + char buffer[WCD939X_VARIANT_ENTRY_SIZE]; + int len = 0; + + priv = (struct wcd939x_priv *) entry->private_data; + if (!priv) { + pr_err_ratelimited("%s: wcd939x priv is null\n", __func__); + return -EINVAL; + } + + switch (priv->variant) { + case WCD9390: + len = snprintf(buffer, sizeof(buffer), "WCD9390\n"); + break; + case WCD9395: + len = snprintf(buffer, sizeof(buffer), "WCD9395\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 wcd939x_variant_ops = { + .read = wcd939x_variant_read, +}; + +/* + * wcd939x_get_codec_variant + * @component: component instance + * + * Return: codec variant or -EINVAL in error. + */ +int wcd939x_get_codec_variant(struct snd_soc_component *component) +{ + struct wcd939x_priv *priv = NULL; + + if (!component) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) { + dev_err(component->dev, + "%s:wcd939x not probed\n", __func__); + return 0; + } + + return priv->variant; +} +EXPORT_SYMBOL(wcd939x_get_codec_variant); + +/* + * wcd939x_info_create_codec_entry - creates wcd939x module + * @codec_root: The parent directory + * @component: component instance + * + * Creates wcd939x module, variant and version entry under the given + * parent directory. + * + * Return: 0 on success or negative error code on failure. + */ +int wcd939x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + struct snd_info_entry *version_entry; + struct snd_info_entry *variant_entry; + struct wcd939x_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:wcd939x module already created\n", __func__); + return 0; + } + card = component->card; + + priv->entry = snd_info_create_module_entry(codec_root->module, + "wcd939x", codec_root); + if (!priv->entry) { + dev_dbg(component->dev, "%s: failed to create wcd939x entry\n", + __func__); + return -ENOMEM; + } + priv->entry->mode = S_IFDIR | 0555; + if (snd_info_register(priv->entry) < 0) { + snd_info_free_entry(priv->entry); + 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 wcd939x version entry\n", + __func__); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + version_entry->private_data = priv; + version_entry->size = WCD939X_VERSION_ENTRY_SIZE; + version_entry->content = SNDRV_INFO_CONTENT_DATA; + version_entry->c.ops = &wcd939x_info_ops; + + if (snd_info_register(version_entry) < 0) { + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->version_entry = version_entry; + + variant_entry = snd_info_create_card_entry(card->snd_card, + "variant", + priv->entry); + if (!variant_entry) { + dev_dbg(component->dev, "%s: failed to create wcd939x variant entry\n", + __func__); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + + variant_entry->private_data = priv; + variant_entry->size = WCD939X_VARIANT_ENTRY_SIZE; + variant_entry->content = SNDRV_INFO_CONTENT_DATA; + variant_entry->c.ops = &wcd939x_variant_ops; + + if (snd_info_register(variant_entry) < 0) { + snd_info_free_entry(variant_entry); + snd_info_free_entry(version_entry); + snd_info_free_entry(priv->entry); + return -ENOMEM; + } + priv->variant_entry = variant_entry; + + return 0; +} +EXPORT_SYMBOL(wcd939x_info_create_codec_entry); + +static int wcd939x_set_micbias_data(struct wcd939x_priv *wcd939x, + struct wcd939x_pdata *pdata) +{ + int vout_ctl_1 = 0, vout_ctl_2 = 0, vout_ctl_3 = 0, vout_ctl_4 = 0; + int rc = 0; + + if (!pdata) { + dev_err(wcd939x->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl_1 = wcd939x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + vout_ctl_2 = wcd939x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv); + vout_ctl_3 = wcd939x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv); + vout_ctl_4 = wcd939x_get_micb_vout_ctl_val(pdata->micbias.micb4_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || + vout_ctl_4 < 0) { + rc = -EINVAL; + goto done; + } + regmap_update_bits(wcd939x->regmap, WCD939X_MICB1, 0x3F, + vout_ctl_1); + regmap_update_bits(wcd939x->regmap, WCD939X_MICB2, 0x3F, + vout_ctl_2); + regmap_update_bits(wcd939x->regmap, WCD939X_MICB3, 0x3F, + vout_ctl_3); + regmap_update_bits(wcd939x->regmap, WCD939X_MICB4, 0x3F, + vout_ctl_4); + +done: + return rc; +} + +static int wcd939x_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret = -EINVAL; + + dev_info(component->dev, "%s()\n", __func__); + wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x) + return -EINVAL; + + wcd939x->component = component; + snd_soc_component_init_regmap(component, wcd939x->regmap); + + devm_regmap_qti_debugfs_register(&wcd939x->tx_swr_dev->dev, wcd939x->regmap); + + /*Harmonium contains only one variant i.e wcd9395*/ + wcd939x->variant = WCD9395; + + /* Check device tree to see if 2Vpk flag is enabled, this value should not be changed */ + wcd939x->in_2Vpk_mode = of_find_property(wcd939x->dev->of_node, + "qcom,hph-2p15v-mode", NULL) != NULL; + + wcd939x->fw_data = devm_kzalloc(component->dev, + sizeof(*(wcd939x->fw_data)), + GFP_KERNEL); + if (!wcd939x->fw_data) { + dev_err(component->dev, "Failed to allocate fw_data\n"); + ret = -ENOMEM; + goto err; + } + + set_bit(WCD9XXX_MBHC_CAL, wcd939x->fw_data->cal_bit); + ret = wcd_cal_create_hwdep(wcd939x->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 = wcd939x_mbhc_init(&wcd939x->mbhc, component, wcd939x->fw_data); + if (ret) { + pr_err("%s: mbhc initialization failed\n", __func__); + goto err_hwdep; + } + + snd_soc_dapm_ignore_suspend(dapm, "WCD939X_AIF Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WCD939X_AIF Capture"); + 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, "VA AMIC1"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC3"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC4"); + snd_soc_dapm_ignore_suspend(dapm, "VA AMIC5"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_OUTPUT"); + snd_soc_dapm_ignore_suspend(dapm, "IN1_HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "IN2_HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "IN3_EAR"); + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_DUMMY"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_RX_DUMMY"); + snd_soc_dapm_sync(dapm); + + wcd_cls_h_init(&wcd939x->clsh_info); + wcd939x_init_reg(component); + + if (wcd939x->variant == WCD9390) { + ret = snd_soc_add_component_controls(component, wcd9390_snd_controls, + ARRAY_SIZE(wcd9390_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd939x->variant); + goto err_hwdep; + } + } + if (wcd939x->variant == WCD9395) { + ret = snd_soc_add_component_controls(component, wcd9395_snd_controls, + ARRAY_SIZE(wcd9395_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd939x->variant); + goto err_hwdep; + } + } + /* Register event notifier */ + wcd939x->nblock.notifier_call = wcd939x_event_notify; + if (wcd939x->register_notifier) { + ret = wcd939x->register_notifier(wcd939x->handle, + &wcd939x->nblock, + true); + if (ret) { + dev_err(component->dev, + "%s: Failed to register notifier %d\n", + __func__, ret); + return ret; + } + } + return ret; + +err_hwdep: + wcd939x->fw_data = NULL; + +err: + return ret; +} + +static void wcd939x_soc_codec_remove(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x) { + dev_err(component->dev, "%s: wcd939x is already NULL\n", + __func__); + return; + } + if (wcd939x->register_notifier) + wcd939x->register_notifier(wcd939x->handle, + &wcd939x->nblock, + false); +} + +static int wcd939x_soc_codec_suspend(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x) + return 0; + wcd939x->dapm_bias_off = true; + return 0; +} + +static int wcd939x_soc_codec_resume(struct snd_soc_component *component) +{ + struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); + + if (!wcd939x) + return 0; + wcd939x->dapm_bias_off = false; + return 0; +} + +static struct snd_soc_component_driver soc_codec_dev_wcd939x = { + .name = WCD939X_DRV_NAME, + .probe = wcd939x_soc_codec_probe, + .remove = wcd939x_soc_codec_remove, + .controls = wcd939x_snd_controls, + .num_controls = ARRAY_SIZE(wcd939x_snd_controls), + .dapm_widgets = wcd939x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd939x_dapm_widgets), + .dapm_routes = wcd939x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd939x_audio_map), + .suspend = wcd939x_soc_codec_suspend, + .resume = wcd939x_soc_codec_resume, +}; + +static void wcd_usbss_set_ovp_threshold(u32 threshold) +{ + uint32_t ovp_regs[2][2] = {{WCD_USBSS_DP_EN, 0x00}, {WCD_USBSS_DN_EN, 0x00}}; + + /* Get current register values */ + wcd_usbss_register_update(ovp_regs, WCD_USBSS_READ, ARRAY_SIZE(ovp_regs)); + /* Overwrite OVP tresholds */ + ovp_regs[0][1] &= (~P_THRESH_SEL_MASK); + ovp_regs[0][1] |= (threshold << P_THRESH_SEL_SHIFT); + ovp_regs[1][1] &= (~P_THRESH_SEL_MASK); + ovp_regs[1][1] |= (threshold << P_THRESH_SEL_SHIFT); + /* Write updated register values */ + wcd_usbss_register_update(ovp_regs, WCD_USBSS_WRITE, ARRAY_SIZE(ovp_regs)); +} + +static int wcd939x_reset(struct device *dev) +{ + struct wcd939x_priv *wcd939x = NULL; + int rc = 0; + int value = 0; + + if (!dev) + return -ENODEV; + + wcd939x = dev_get_drvdata(dev); + if (!wcd939x) + return -EINVAL; + + if (!wcd939x->rst_np) { + dev_err_ratelimited(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + value = msm_cdc_pinctrl_get_state(wcd939x->rst_np); + if (value > 0) + return 0; + + /* Set OVP threshold to 4.0V before reset */ +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + wcd_usbss_set_ovp_threshold(VTH_4P0); +#endif + + rc = msm_cdc_pinctrl_select_sleep_state(wcd939x->rst_np); + if (rc) { + dev_err_ratelimited(dev, "%s: wcd sleep state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 20us sleep required after pulling the reset gpio to LOW */ + usleep_range(80, 85); + + rc = msm_cdc_pinctrl_select_active_state(wcd939x->rst_np); + if (rc) { + dev_err_ratelimited(dev, "%s: wcd active state request fail!\n", + __func__); + return -EPROBE_DEFER; + } + /* 20us sleep required after pulling the reset gpio to HIGH */ + usleep_range(80, 85); + + /* Set OVP threshold to 4.2V after reset */ +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + wcd_usbss_set_ovp_threshold(VTH_4P2); +#endif + + return rc; +} + +static int wcd939x_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 int wcd939x_read_of_property_s32(struct device *dev, const char *name, + s32 *val) +{ + int rc = 0; + + rc = of_property_read_s32(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 wcd939x_dt_parse_micbias_info(struct device *dev, + struct wcd939x_micbias_setting *mb) +{ + u32 prop_val = 0; + int rc = 0; + + /* MB1 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv", + NULL)) { + rc = wcd939x_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 = wcd939x_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 = wcd939x_read_of_property_u32(dev, + "qcom,cdc-micbias3-mv", + &prop_val); + if (!rc) + mb->micb3_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias3 DT property not found\n", + __func__); + } + + /* MB4 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias4-mv", + NULL)) { + rc = wcd939x_read_of_property_u32(dev, + "qcom,cdc-micbias4-mv", + &prop_val); + if (!rc) + mb->micb4_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias4 DT property not found\n", + __func__); + } +} + +static void fill_r_common_gnd_buffer(struct wcd939x_usbcss_hs_params *usbcss_hs, u32 val) +{ + size_t i; + + for (i = 0; i < R_COMMON_GND_BUFFER_SIZE; i++) + usbcss_hs->gnd.r_cm_gnd_buffer.data[i] = val; +} + +static void init_usbcss_hs_params(struct wcd939x_usbcss_hs_params *usbcss_hs) +{ + fill_r_common_gnd_buffer(usbcss_hs, 0); + usbcss_hs->gnd.sbu1.r_gnd_int_fet_mohms = 183; + usbcss_hs->gnd.sbu2.r_gnd_int_fet_mohms = 127; + usbcss_hs->gnd.r_cm_gnd_buffer.write_index = 0; + usbcss_hs->gnd.rdson_mohms = 500; + usbcss_hs->gnd.rdson_3p6v_mohms = 545; + usbcss_hs->gnd.r_gnd_ext_fet_mohms = 0; /* to be computed during MBHC zdet */ + usbcss_hs->gnd.r_common_gnd_mohms = 0; + usbcss_hs->gnd.r_common_gnd_offset = 0; + usbcss_hs->gnd.r_common_gnd_margin = 500; + usbcss_hs->gnd.gnd_ext_fet_delta_mohms = 45; + usbcss_hs->gnd.gnd_ext_fet_min_mohms = 0; + usbcss_hs->gnd.sbu1.r_gnd_par_route1_mohms = 5; + usbcss_hs->gnd.sbu2.r_gnd_par_route1_mohms = 5; + usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms = 330; + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms = 330; + usbcss_hs->gnd.sbu1.r_gnd_par_tot_mohms = 0; + usbcss_hs->gnd.sbu2.r_gnd_par_tot_mohms = 0; + usbcss_hs->gnd.sbu1.r_gnd_res_tot_mohms = 0; + usbcss_hs->gnd.sbu2.r_gnd_res_tot_mohms = 0; + usbcss_hs->aud.l.r_aud_int_fet_mohms = 290; + usbcss_hs->aud.r.r_aud_int_fet_mohms = 290; + usbcss_hs->aud.l.r_aud_ext_fet_mohms = 0; /* to be computed during MBHC zdet */ + usbcss_hs->aud.r.r_aud_ext_fet_mohms = 0; /* to be computed during MBHC zdet */ + usbcss_hs->aud.l.r_aud_res_tot_mohms = 0; + usbcss_hs->aud.r.r_aud_res_tot_mohms = 0; + usbcss_hs->aud.r_surge_mohms = 229; + usbcss_hs->aud.l.r_load_eff_mohms = 0; /* to be computed during MBHC zdet */ + usbcss_hs->aud.r.r_load_eff_mohms = 0; /* to be computed during MBHC zdet */ + usbcss_hs->aud.l.zval = 0; /* to be computed during MBHC zdet */ + usbcss_hs->aud.r.zval = 0; /* to be computed during MBHC zdet */ + usbcss_hs->zdiffval = 0; /* to be computed during MBHC zdet */ + usbcss_hs->diff_slope_factor_times_1000 = 9898; + usbcss_hs->se_slope_factor_times_1000 = 9906; + usbcss_hs->aud.l.r1 = 310; + usbcss_hs->aud.r.r1 = 310; + usbcss_hs->aud.l.r3 = 1; + usbcss_hs->aud.r.r3 = 1; + usbcss_hs->gnd.sbu1.r4 = 530; + usbcss_hs->gnd.sbu2.r4 = 530; + usbcss_hs->gnd.sbu1.r5 = 5; + usbcss_hs->gnd.sbu2.r5 = 5; + usbcss_hs->gnd.sbu1.r6 = 1; + usbcss_hs->gnd.sbu2.r6 = 1; + usbcss_hs->gnd.sbu1.r7 = 5; + usbcss_hs->gnd.sbu2.r7 = 5; + usbcss_hs->aud.k_aud_times_100 = 13; + usbcss_hs->aud.aud_tap_offset = 0; + usbcss_hs->xtalk.scale_l = MAX_XTALK_SCALE; + usbcss_hs->xtalk.alpha_l = MIN_XTALK_ALPHA; + usbcss_hs->xtalk.scale_r = MAX_XTALK_SCALE; + usbcss_hs->xtalk.alpha_r = MIN_XTALK_ALPHA; + usbcss_hs->xtalk.xtalk_config = XTALK_NONE; +} + +static void parse_xtalk_param(struct device *dev, u32 default_val, u32 *prop_val_p, + char *prop) +{ + int rc = 0; + + if (of_find_property(dev->of_node, prop, NULL)) { + rc = wcd939x_read_of_property_u32(dev, prop, prop_val_p); + if ((!rc) && (*prop_val_p <= MAX_USBCSS_HS_IMPEDANCE_MOHMS) && (*prop_val_p > 0)) + return; + *prop_val_p = default_val; + dev_dbg(dev, "%s: %s OOB. Default value of %d will be used.\n", __func__, prop, + default_val); + } else { + *prop_val_p = default_val; + dev_dbg(dev, "%s: %s property not found. Default value of %d will be used.\n", + __func__, prop, default_val); + } +} + +static void wcd939x_dt_parse_usbcss_hs_info(struct device *dev, + struct wcd939x_usbcss_hs_params *usbcss_hs) +{ + u32 prop_val = 0, r_common_gnd_mohms = 0; + s32 prop_val_signed = 0; + int rc = 0; + + /* Default values for parameters */ + init_usbcss_hs_params(usbcss_hs); + + /* xtalk_config: Determine type of crosstalk: none (0), digital (1), or analog (2) */ + if (of_find_property(dev->of_node, "qcom,usbcss-hs-xtalk-config", NULL)) { + rc = wcd939x_read_of_property_u32(dev, "qcom,usbcss-hs-xtalk-config", &prop_val); + if ((!rc) && (prop_val == XTALK_NONE || prop_val == XTALK_DIGITAL + || prop_val == XTALK_ANALOG)) { + usbcss_hs->xtalk.xtalk_config = (enum xtalk_mode) prop_val; + } else + dev_dbg(dev, "%s: %s OOB. Default value of %s used.\n", + __func__, "qcom,usbcss-hs-xtalk-config", "XTALK_NONE"); + } else + dev_dbg(dev, "%s: %s property not found. Default value of %s used.\n", + __func__, "qcom,usbcss-hs-xtalk-config", "XTALK_NONE"); + + /* k values for linearizer */ + if (of_find_property(dev->of_node, "qcom,usbcss-hs-lin-k-aud", NULL)) { + rc = wcd939x_read_of_property_s32(dev, "qcom,usbcss-hs-lin-k-aud", + &prop_val_signed); + if ((!rc) && (prop_val_signed <= MAX_K_TIMES_100) && + (prop_val_signed >= MIN_K_TIMES_100)) + usbcss_hs->aud.k_aud_times_100 = prop_val_signed; + else + dev_dbg(dev, "%s: %s OOB. Default value of %d will be used.\n", + __func__, "qcom,usbcss-hs-lin-k-aud", + usbcss_hs->aud.k_aud_times_100); + } else { + dev_dbg(dev, "%s: %s property not found. Default value of %d will be used.\n", + __func__, "qcom,usbcss-hs-lin-k-aud", + usbcss_hs->aud.k_aud_times_100); + } + + /* Differential slope factor */ + if (of_find_property(dev->of_node, "qcom,usbcss-hs-diff-slope", NULL)) { + rc = wcd939x_read_of_property_u32(dev, "qcom,usbcss-hs-diff-slope", &prop_val); + if ((!rc) && (prop_val <= MAX_DIFF_SLOPE_FACTOR) && + (prop_val >= MIN_DIFF_SLOPE_FACTOR)) + usbcss_hs->diff_slope_factor_times_1000 = prop_val; + else + dev_dbg(dev, "%s: %s OOB. Default value of %d will be used.\n", + __func__, "qcom,usbcss-hs-diff-slope", + usbcss_hs->diff_slope_factor_times_1000); + } else { + dev_dbg(dev, "%s: %s property not found. Default value of %d will be used.\n", + __func__, "qcom,usbcss-hs-diff-slope", + usbcss_hs->diff_slope_factor_times_1000); + } + + /* R_ds(on) */ + parse_xtalk_param(dev, usbcss_hs->gnd.rdson_mohms, &prop_val, "qcom,usbcss-hs-rdson-6v"); + usbcss_hs->gnd.rdson_mohms = prop_val; + /* R_ds(on) Vgs=3.6V */ + parse_xtalk_param(dev, usbcss_hs->gnd.rdson_3p6v_mohms, &prop_val, + "qcom,usbcss-hs-rdson-3p6v"); + usbcss_hs->gnd.rdson_3p6v_mohms = prop_val; + usbcss_hs->gnd.gnd_ext_fet_delta_mohms = (s32) (usbcss_hs->gnd.rdson_3p6v_mohms - + usbcss_hs->gnd.rdson_mohms); + /* r_common_gnd_margin */ + parse_xtalk_param(dev, usbcss_hs->gnd.r_common_gnd_margin, &prop_val, + "qcom,usbcss-hs-rcom-margin"); + usbcss_hs->gnd.r_common_gnd_margin = prop_val; + /* r1 */ + parse_xtalk_param(dev, usbcss_hs->aud.l.r1, &prop_val, + "qcom,usbcss-hs-r1-l"); + usbcss_hs->aud.l.r1 = prop_val; + parse_xtalk_param(dev, usbcss_hs->aud.r.r1, &prop_val, + "qcom,usbcss-hs-r1-r"); + usbcss_hs->aud.r.r1 = prop_val; + /* r3 */ + parse_xtalk_param(dev, usbcss_hs->aud.l.r3, &prop_val, + "qcom,usbcss-hs-r3-l"); + usbcss_hs->aud.l.r3 = prop_val; + parse_xtalk_param(dev, usbcss_hs->aud.r.r3, &prop_val, + "qcom,usbcss-hs-r3-r"); + usbcss_hs->aud.r.r3 = prop_val; + /* r4 */ + parse_xtalk_param(dev, usbcss_hs->gnd.sbu1.r4, &prop_val, + "qcom,usbcss-hs-r4-sbu1"); + usbcss_hs->gnd.sbu1.r4 = prop_val; + parse_xtalk_param(dev, usbcss_hs->gnd.sbu2.r4, &prop_val, + "qcom,usbcss-hs-r4-sbu2"); + usbcss_hs->gnd.sbu2.r4 = prop_val; + /* r_gnd_par_route1_mohms and r_gnd_par_route2_mohms */ + if (usbcss_hs->xtalk.xtalk_config == XTALK_ANALOG) { + parse_xtalk_param(dev, usbcss_hs->gnd.sbu1.r5, &prop_val, + "qcom,usbcss-hs-r5-sbu1"); + usbcss_hs->gnd.sbu1.r5 = prop_val; + parse_xtalk_param(dev, usbcss_hs->gnd.sbu2.r5, &prop_val, + "qcom,usbcss-hs-r5-sbu2"); + usbcss_hs->gnd.sbu2.r5 = prop_val; + usbcss_hs->gnd.sbu1.r_gnd_par_route1_mohms = usbcss_hs->gnd.sbu1.r5 + + usbcss_hs->gnd.sbu1.r4; + usbcss_hs->gnd.sbu2.r_gnd_par_route1_mohms = usbcss_hs->gnd.sbu2.r5 + + usbcss_hs->gnd.sbu2.r4; + usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms = 125; + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms = 125; + } else if (usbcss_hs->xtalk.xtalk_config == XTALK_DIGITAL) { + parse_xtalk_param(dev, usbcss_hs->gnd.sbu1.r6, &prop_val, + "qcom,usbcss-hs-r6-sbu1"); + usbcss_hs->gnd.sbu1.r6 = prop_val; + parse_xtalk_param(dev, usbcss_hs->gnd.sbu2.r6, &prop_val, + "qcom,usbcss-hs-r6-sbu2"); + usbcss_hs->gnd.sbu2.r6 = prop_val; + usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms = usbcss_hs->gnd.sbu1.r6 + + usbcss_hs->gnd.sbu1.r4; + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms = usbcss_hs->gnd.sbu2.r6 + + usbcss_hs->gnd.sbu2.r4; + parse_xtalk_param(dev, usbcss_hs->gnd.sbu1.r7, &prop_val, + "qcom,usbcss-hs-r7-sbu1"); + usbcss_hs->gnd.sbu1.r7 = prop_val; + usbcss_hs->gnd.sbu1.r_gnd_par_route1_mohms = prop_val; + parse_xtalk_param(dev, usbcss_hs->gnd.sbu2.r7, &prop_val, + "qcom,usbcss-hs-r7-sbu2"); + usbcss_hs->gnd.sbu2.r7 = prop_val; + usbcss_hs->gnd.sbu2.r_gnd_par_route1_mohms = prop_val; + } + + /* Compute total resistances */ + usbcss_hs->gnd.sbu1.r_gnd_par_tot_mohms = usbcss_hs->gnd.sbu1.r_gnd_par_route1_mohms + + usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms; + usbcss_hs->gnd.sbu2.r_gnd_par_tot_mohms = usbcss_hs->gnd.sbu2.r_gnd_par_route1_mohms + + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms; + usbcss_hs->gnd.sbu1.r_gnd_res_tot_mohms = get_r_gnd_res_tot_mohms( + usbcss_hs->gnd.sbu1.r_gnd_int_fet_mohms, + usbcss_hs->gnd.r_gnd_ext_fet_mohms, + usbcss_hs->gnd.sbu1.r_gnd_par_tot_mohms); + usbcss_hs->gnd.sbu2.r_gnd_res_tot_mohms = get_r_gnd_res_tot_mohms( + usbcss_hs->gnd.sbu2.r_gnd_int_fet_mohms, + usbcss_hs->gnd.r_gnd_ext_fet_mohms, + usbcss_hs->gnd.sbu2.r_gnd_par_tot_mohms); + usbcss_hs->aud.l.r_aud_res_tot_mohms = get_r_aud_res_tot_mohms( + usbcss_hs->aud.l.r_aud_int_fet_mohms, + usbcss_hs->aud.l.r_aud_ext_fet_mohms, + usbcss_hs->aud.l.r3); + usbcss_hs->aud.r.r_aud_res_tot_mohms = get_r_aud_res_tot_mohms( + usbcss_hs->aud.r.r_aud_int_fet_mohms, + usbcss_hs->aud.r.r_aud_ext_fet_mohms, + usbcss_hs->aud.r.r3); + + /* Fill r_common_gnd buffer */ + r_common_gnd_mohms = usbcss_hs->gnd.rdson_mohms + + (usbcss_hs->gnd.sbu1.r_gnd_par_route2_mohms + + usbcss_hs->gnd.sbu2.r_gnd_par_route2_mohms) / 2; + fill_r_common_gnd_buffer(usbcss_hs, r_common_gnd_mohms); + + /* Determine min val used for linearizer audio tap calculations */ + if (usbcss_hs->gnd.rdson_3p6v_mohms < GND_EXT_FET_MARGIN_MOHMS) + usbcss_hs->gnd.gnd_ext_fet_min_mohms = 0; + else if ((usbcss_hs->gnd.rdson_3p6v_mohms - GND_EXT_FET_MARGIN_MOHMS) + < GND_EXT_FET_MARGIN_MOHMS) + usbcss_hs->gnd.gnd_ext_fet_min_mohms = usbcss_hs->gnd.rdson_3p6v_mohms - + GND_EXT_FET_MARGIN_MOHMS; + else + usbcss_hs->gnd.gnd_ext_fet_min_mohms = GND_EXT_FET_MARGIN_MOHMS; + +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + /* Set linearizer calibration codes to be sourced from SW */ + wcd_usbss_linearizer_rdac_cal_code_select(LINEARIZER_SOURCE_SW); +#endif +} + +static int wcd939x_reset_low(struct device *dev) +{ + struct wcd939x_priv *wcd939x = NULL; + int rc = 0; + + if (!dev) + return -ENODEV; + + wcd939x = dev_get_drvdata(dev); + if (!wcd939x) + return -EINVAL; + + if (!wcd939x->rst_np) { + dev_err_ratelimited(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + /* Set OVP threshold to 4.0V before reset */ +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + wcd_usbss_set_ovp_threshold(VTH_4P0); +#endif + + rc = msm_cdc_pinctrl_select_sleep_state(wcd939x->rst_np); + if (rc) { + dev_err_ratelimited(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 wcd939x_pdata *wcd939x_populate_dt_data(struct device *dev) +{ + struct wcd939x_pdata *pdata = NULL; + + pdata = devm_kzalloc(dev, sizeof(struct wcd939x_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_ratelimited(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_ratelimited(dev, "%s: no power supplies defined for codec\n", + __func__); + return NULL; + } + + pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-slave", 0); + pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0); + + wcd939x_dt_parse_micbias_info(dev, &pdata->micbias); + wcd939x_dt_parse_usbcss_hs_info(dev, &pdata->usbcss_hs); + + return pdata; +} + +static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data) +{ + pr_err_ratelimited("%s: Watchdog interrupt for irq =%d triggered\n", + __func__, irq); + return IRQ_HANDLED; +} + +static struct snd_soc_dai_driver wcd939x_dai[] = { + { + .name = "wcd939x_cdc", + .playback = { + .stream_name = "WCD939X_AIF Playback", + .rates = WCD939X_RATES | WCD939X_FRAC_RATES, + .formats = WCD939X_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .capture = { + .stream_name = "WCD939X_AIF Capture", + .rates = WCD939X_RATES | WCD939X_FRAC_RATES, + .formats = WCD939X_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + }, +}; + + +static const struct reg_default reg_def_1_1[] = { + {WCD939X_VBG_FINE_ADJ, 0xA5}, + {WCD939X_FLYBACK_NEW_CTRL_2, 0x0}, + {WCD939X_FLYBACK_NEW_CTRL_3, 0x0}, + {WCD939X_FLYBACK_NEW_CTRL_4, 0x44}, + {WCD939X_PA_GAIN_CTL_R, 0x80}, +}; + +static const struct reg_default reg_def_2_0[] = { + {WCD939X_INTR_MASK_2, 0x3E}, +}; + +static const char *version_to_str(u32 version) +{ + switch (version) { + case WCD939X_VERSION_1_0: + return __stringify(WCD939X_1_0); + case WCD939X_VERSION_1_1: + return __stringify(WCD939X_1_1); + case WCD939X_VERSION_2_0: + return __stringify(WCD939X_2_0); + } + return NULL; +} + +static void wcd939x_update_regmap_cache(struct wcd939x_priv *wcd939x) +{ + if (wcd939x->version == WCD939X_VERSION_1_0) + return; + + if (wcd939x->version >= WCD939X_VERSION_1_1) { + for (int i = 0; i < ARRAY_SIZE(reg_def_1_1); ++i) + regmap_write(wcd939x->regmap, reg_def_1_1[i].reg, reg_def_1_1[i].def); + } + + if (wcd939x->version == WCD939X_VERSION_2_0) { + for (int i = 0; i < ARRAY_SIZE(reg_def_2_0); ++i) + regmap_write(wcd939x->regmap, reg_def_2_0[i].reg, reg_def_2_0[i].def); + } +} + +static int wcd939x_bind(struct device *dev) +{ + int ret = 0, i = 0; + struct wcd939x_pdata *pdata = dev_get_platdata(dev); + struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); + u8 id1 = 0, status1 = 0; +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + int val = 0; +#endif + /* + * 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, wcd939x); + if (ret) { + dev_err_ratelimited(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + return ret; + } + + wcd939x->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave); + if (!wcd939x->rx_swr_dev) { + dev_err_ratelimited(dev, "%s: Could not find RX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + + wcd939x->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave); + if (!wcd939x->tx_swr_dev) { + dev_err_ratelimited(dev, "%s: Could not find TX swr slave device\n", + __func__); + ret = -ENODEV; + goto err; + } + swr_init_port_params(wcd939x->tx_swr_dev, SWR_NUM_PORTS, + wcd939x->swr_tx_port_params); + + /* Check WCD9395 version */ + swr_read(wcd939x->tx_swr_dev, wcd939x->tx_swr_dev->dev_num, + WCD939X_CHIP_ID1, &id1, 1); + swr_read(wcd939x->tx_swr_dev, wcd939x->tx_swr_dev->dev_num, + WCD939X_STATUS_REG_1, &status1, 1); + if (id1 == 0) + wcd939x->version = ((status1 & 0x3) ? WCD939X_VERSION_1_1 : WCD939X_VERSION_1_0); + else if (id1 == 1) + wcd939x->version = WCD939X_VERSION_2_0; + wcd939x_version = wcd939x->version; + dev_info(dev, "%s: wcd9395 version: %s\n", __func__, + version_to_str(wcd939x->version)); + wcd939x_regmap_config.readable_reg = wcd939x_readable_register; + wcd939x->regmap = devm_regmap_init_swr(wcd939x->tx_swr_dev, + &wcd939x_regmap_config); + if (!wcd939x->regmap) { + dev_err_ratelimited(dev, "%s: Regmap init failed\n", + __func__); + goto err; + } +#if IS_ENABLED(CONFIG_QCOM_WCD_USBSS_I2C) + regmap_read(wcd939x->regmap, WCD939X_EFUSE_REG_17, &val); + if (wcd939x_version == WCD939X_VERSION_2_0 && val < 3) + wcd_usbss_update_default_trim(); +#endif + wcd939x_update_regmap_cache(wcd939x); + + /* Set all interupts as edge triggered */ + for (i = 0; i < wcd939x_regmap_irq_chip.num_regs; i++) + regmap_write(wcd939x->regmap, + (WCD939X_INTR_LEVEL_0 + i), 0); + + wcd939x_regmap_irq_chip.irq_drv_data = wcd939x; + wcd939x->irq_info.wcd_regmap_irq_chip = &wcd939x_regmap_irq_chip; + wcd939x->irq_info.codec_name = "WCD939X"; + wcd939x->irq_info.regmap = wcd939x->regmap; + wcd939x->irq_info.dev = dev; + ret = wcd_irq_init(&wcd939x->irq_info, &wcd939x->virq); + + if (ret) { + dev_err_ratelimited(wcd939x->dev, "%s: IRQ init failed: %d\n", + __func__, ret); + goto err; + } + wcd939x->tx_swr_dev->slave_irq = wcd939x->virq; + + ret = wcd939x_set_micbias_data(wcd939x, pdata); + if (ret < 0) { + dev_err_ratelimited(dev, "%s: bad micbias pdata\n", __func__); + goto err_irq; + } + + /* Request for watchdog interrupt */ + wcd_request_irq(&wcd939x->irq_info, WCD939X_IRQ_HPHR_PDM_WD_INT, + "HPHR PDM WD INT", wcd939x_wd_handle_irq, NULL); + wcd_request_irq(&wcd939x->irq_info, WCD939X_IRQ_HPHL_PDM_WD_INT, + "HPHL PDM WD INT", wcd939x_wd_handle_irq, NULL); + wcd_request_irq(&wcd939x->irq_info, WCD939X_IRQ_EAR_PDM_WD_INT, + "EAR PDM WD INT", wcd939x_wd_handle_irq, NULL); + /* Disable watchdog interrupt for HPH and EAR */ + wcd_disable_irq(&wcd939x->irq_info, WCD939X_IRQ_HPHR_PDM_WD_INT); + wcd_disable_irq(&wcd939x->irq_info, WCD939X_IRQ_HPHL_PDM_WD_INT); + wcd_disable_irq(&wcd939x->irq_info, WCD939X_IRQ_EAR_PDM_WD_INT); + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd939x, + wcd939x_dai, ARRAY_SIZE(wcd939x_dai)); + if (ret) { + dev_err_ratelimited(dev, "%s: Codec registration failed\n", + __func__); + goto err_irq; + } + wcd939x->dev_up = true; + + return ret; +err_irq: + wcd_irq_exit(&wcd939x->irq_info, wcd939x->virq); +err: + component_unbind_all(dev, wcd939x); + return ret; +} + +static void wcd939x_unbind(struct device *dev) +{ + struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); + + wcd_free_irq(&wcd939x->irq_info, WCD939X_IRQ_HPHR_PDM_WD_INT, NULL); + wcd_free_irq(&wcd939x->irq_info, WCD939X_IRQ_HPHL_PDM_WD_INT, NULL); + wcd_free_irq(&wcd939x->irq_info, WCD939X_IRQ_EAR_PDM_WD_INT, NULL); + wcd_irq_exit(&wcd939x->irq_info, wcd939x->virq); + snd_soc_unregister_component(dev); + component_unbind_all(dev, wcd939x); +} + +static const struct of_device_id wcd939x_dt_match[] = { + { .compatible = "qcom,wcd939x-codec", .data = "wcd939x"}, + {} +}; + +static const struct component_master_ops wcd939x_comp_ops = { + .bind = wcd939x_bind, + .unbind = wcd939x_unbind, +}; + +static int wcd939x_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void wcd939x_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int wcd939x_add_slave_components(struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np, *rx_node, *tx_node; + + np = dev->of_node; + + rx_node = of_parse_phandle(np, "qcom,rx-slave", 0); + if (!rx_node) { + dev_err_ratelimited(dev, "%s: Rx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(rx_node); + component_match_add_release(dev, matchptr, + wcd939x_release_of, + wcd939x_compare_of, + rx_node); + + tx_node = of_parse_phandle(np, "qcom,tx-slave", 0); + if (!tx_node) { + dev_err_ratelimited(dev, "%s: Tx-slave node not defined\n", __func__); + return -ENODEV; + } + of_node_get(tx_node); + component_match_add_release(dev, matchptr, + wcd939x_release_of, + wcd939x_compare_of, + tx_node); + return 0; +} + +static int wcd939x_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct wcd939x_priv *wcd939x = NULL; + struct wcd939x_pdata *pdata = NULL; + struct wcd_ctrl_platform_data *plat_data = NULL; + struct device *dev = &pdev->dev; + int ret; + + wcd939x = devm_kzalloc(dev, sizeof(struct wcd939x_priv), + GFP_KERNEL); + if (!wcd939x) + return -ENOMEM; + + dev_set_drvdata(dev, wcd939x); + wcd939x->dev = dev; + + pdata = wcd939x_populate_dt_data(dev); + if (!pdata) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); + return -EINVAL; + } + dev->platform_data = pdata; + + wcd939x->rst_np = pdata->rst_np; + ret = msm_cdc_init_supplies(dev, &wcd939x->supplies, + pdata->regulator, pdata->num_supplies); + if (!wcd939x->supplies) { + dev_err(dev, "%s: Cannot init wcd supplies\n", + __func__); + return ret; + } + + plat_data = dev_get_platdata(dev->parent); + if (!plat_data) { + dev_err(dev, "%s: platform data from parent is NULL\n", + __func__); + return -EINVAL; + } + wcd939x->handle = (void *)plat_data->handle; + if (!wcd939x->handle) { + dev_err(dev, "%s: handle is NULL\n", __func__); + return -EINVAL; + } + + wcd939x->update_wcd_event = plat_data->update_wcd_event; + if (!wcd939x->update_wcd_event) { + dev_err(dev, "%s: update_wcd_event api is null!\n", + __func__); + return -EINVAL; + } + wcd939x->register_notifier = plat_data->register_notifier; + if (!wcd939x->register_notifier) { + dev_err(dev, "%s: register_notifier api is null!\n", + __func__); + return -EINVAL; + } + + ret = msm_cdc_enable_static_supplies(&pdev->dev, wcd939x->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(dev, "%s: wcd static supply enable failed!\n", + __func__); + return ret; + } + + if (msm_cdc_is_ondemand_supply(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px")) { + ret = msm_cdc_enable_ondemand_supply(wcd939x->dev, + wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px"); + if (ret) { + dev_err(dev, "%s: vdd px supply enable failed!\n", + __func__); + return ret; + } + } + + ret = wcd939x_parse_port_mapping(dev, "qcom,rx_swr_ch_map", + CODEC_RX); + ret |= wcd939x_parse_port_mapping(dev, "qcom,tx_swr_ch_map", + CODEC_TX); + + if (ret) { + dev_err(dev, "Failed to read port mapping\n"); + goto err; + } + ret = wcd939x_parse_port_params(dev, "qcom,swr-tx-port-params", + CODEC_TX); + if (ret) { + dev_err(dev, "Failed to read port params\n"); + goto err; + } + + mutex_init(&wcd939x->wakeup_lock); + mutex_init(&wcd939x->micb_lock); + ret = wcd939x_add_slave_components(dev, &match); + if (ret) + goto err_lock_init; + + ret = wcd939x_reset(dev); + if (ret == -EPROBE_DEFER) { + dev_err(dev, "%s: wcd reset failed!\n", __func__); + goto err_lock_init; + } + + wcd939x->wakeup = wcd939x_wakeup; + + return component_master_add_with_match(dev, + &wcd939x_comp_ops, match); + +err_lock_init: + mutex_destroy(&wcd939x->micb_lock); + mutex_destroy(&wcd939x->wakeup_lock); +err: + return ret; +} + +static int wcd939x_remove(struct platform_device *pdev) +{ + struct wcd939x_priv *wcd939x = NULL; + + wcd939x = platform_get_drvdata(pdev); + component_master_del(&pdev->dev, &wcd939x_comp_ops); + mutex_destroy(&wcd939x->micb_lock); + mutex_destroy(&wcd939x->wakeup_lock); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int wcd939x_suspend(struct device *dev) +{ + struct wcd939x_priv *wcd939x = NULL; + int ret = 0; + struct wcd939x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd939x = dev_get_drvdata(dev); + if (!wcd939x) + return -EINVAL; + + pdata = dev_get_platdata(wcd939x->dev); + + if (!pdata) { + dev_err_ratelimited(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(ALLOW_BUCK_DISABLE, &wcd939x->status_mask)) { + ret = msm_cdc_disable_ondemand_supply(wcd939x->dev, + wcd939x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck"); + if (ret == -EINVAL) { + dev_err_ratelimited(dev, "%s: vdd buck is not disabled\n", + __func__); + return 0; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd939x->status_mask); + } + if (wcd939x->dapm_bias_off || + (wcd939x->component && + (snd_soc_component_get_bias_level(wcd939x->component) == + SND_SOC_BIAS_OFF))) { + msm_cdc_set_supplies_lpm_mode(wcd939x->dev, + wcd939x->supplies, + pdata->regulator, + pdata->num_supplies, + true); + set_bit(WCD_SUPPLIES_LPM_MODE, &wcd939x->status_mask); + if (msm_cdc_is_ondemand_supply(wcd939x->dev, wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px")) { + + if (msm_cdc_supply_supports_retention_mode(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px") && + msm_cdc_check_supply_vote(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px")) { + ret = msm_cdc_disable_ondemand_supply(wcd939x->dev, + wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px"); + if (ret) { + dev_dbg(dev, "%s: vdd px supply suspend failed!\n", + __func__); + } + } + } + } + + return 0; +} + +static int wcd939x_resume(struct device *dev) +{ + int ret = 0; + struct wcd939x_priv *wcd939x = NULL; + struct wcd939x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd939x = dev_get_drvdata(dev); + if (!wcd939x) + return -EINVAL; + + pdata = dev_get_platdata(wcd939x->dev); + + if (!pdata) { + dev_err_ratelimited(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (msm_cdc_is_ondemand_supply(wcd939x->dev, wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px")) { + if (msm_cdc_supply_supports_retention_mode(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px") && + !msm_cdc_check_supply_vote(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px")) { + ret = msm_cdc_enable_ondemand_supply(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px"); + if (ret) { + dev_dbg(dev, "%s: vdd px supply resume failed!\n", + __func__); + } + } + } + + if (test_bit(WCD_SUPPLIES_LPM_MODE, &wcd939x->status_mask)) { + msm_cdc_set_supplies_lpm_mode(wcd939x->dev, + wcd939x->supplies, + pdata->regulator, + pdata->num_supplies, + false); + clear_bit(WCD_SUPPLIES_LPM_MODE, &wcd939x->status_mask); + } + + return 0; +} + +static const struct dev_pm_ops wcd939x_dev_pm_ops = { + .suspend_late = wcd939x_suspend, + .resume_early = wcd939x_resume, +}; +#endif + +static struct platform_driver wcd939x_codec_driver = { + .probe = wcd939x_probe, + .remove = wcd939x_remove, + .driver = { + .name = "wcd939x_codec", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wcd939x_dt_match), +#ifdef CONFIG_PM_SLEEP + .pm = &wcd939x_dev_pm_ops, +#endif + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd939x_codec_driver); +MODULE_DESCRIPTION("WCD939X Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x.h new file mode 100644 index 0000000000..135234ccd9 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd939x/wcd939x.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _WCD939X_H +#define _WCD939X_H + +#include + +#define WCD939X_MAX_SLAVE_CH_TYPES 13 +#define ZERO 0 +#define WCD939X_DRV_NAME "wcd939x_codec" + +enum { + WCD9390 = 0, + WCD9395 = 5, +}; + +/* from WCD to SWR DMIC events */ +enum { + WCD939X_EVT_SSR_DOWN, + WCD939X_EVT_SSR_UP, +}; + +struct swr_slave_ch_map { + u8 ch_type; + u8 index; +}; + +static const struct swr_slave_ch_map swr_slv_tx_ch_idx[] = { + {ADC1, 0}, + {ADC2, 1}, + {ADC3, 2}, + {ADC4, 3}, + {DMIC0, 4}, + {DMIC1, 5}, + {MBHC, 6}, + {DMIC2, 6}, + {DMIC3, 7}, + {DMIC4, 8}, + {DMIC5, 9}, + {DMIC6, 10}, + {DMIC7, 11}, +}; + +static int swr_master_ch_map[] = { + ZERO, + SWRM_TX_PCM_OUT, + SWRM_TX1_CH1, + SWRM_TX1_CH2, + SWRM_TX1_CH3, + SWRM_TX1_CH4, + SWRM_TX2_CH1, + SWRM_TX2_CH2, + SWRM_TX2_CH3, + SWRM_TX2_CH4, + SWRM_TX3_CH1, + SWRM_TX3_CH2, + SWRM_TX3_CH3, + SWRM_TX3_CH4, + SWRM_TX_PCM_IN, +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD939X) +int wcd939x_info_create_codec_entry(struct snd_info_entry *codec_root, + struct snd_soc_component *component); + +int wcd939x_get_codec_variant(struct snd_soc_component *component); +int wcd939x_codec_force_enable_micbias_v2(struct snd_soc_component *wcd939x, + int event, int micb_num); +int wcd939x_swr_dmic_register_notifier(struct snd_soc_component *wcd939x, + struct notifier_block *nblock, + bool enable); +int wcd939x_codec_get_dev_num(struct snd_soc_component *component); + +static inline int wcd939x_slave_get_master_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD939X_MAX_SLAVE_CH_TYPES; i++) + if (ch == swr_master_ch_map[i]) + return i; + return 0; +} + +static inline int wcd939x_slave_get_master_ch(int idx) +{ + return swr_master_ch_map[idx]; +} + +static inline int wcd939x_slave_get_slave_ch_val(int ch) +{ + int i; + + for (i = 0; i < WCD939X_MAX_SLAVE_CH_TYPES; i++) + if (ch == swr_slv_tx_ch_idx[i].ch_type) + return swr_slv_tx_ch_idx[i].index; + + return -EINVAL; +} +#else +static inline int wcd939x_info_create_codec_entry( + struct snd_info_entry *codec_root, + struct snd_soc_component *component) +{ + return 0; +} +static inline int wcd939x_get_codec_variant(struct snd_soc_component *component) +{ + return 0; +} +static inline int wcd939x_codec_force_enable_micbias_v2( + struct snd_soc_component *wcd939x, + int event, int micb_num) +{ + return 0; +} + +static inline int wcd939x_slave_get_master_ch_val(int ch) +{ + return 0; +} +static inline int wcd939x_slave_get_master_ch(int idx) +{ + return 0; +} +static inline int wcd939x_slave_get_slave_ch_val(int ch) +{ + return 0; +} +static int wcd939x_codec_get_dev_num(struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD939X */ +#endif /* _WCD939X_H */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-common-v2.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-common-v2.c new file mode 100644 index 0000000000..9143269f2d --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-common-v2.c @@ -0,0 +1,1411 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define WCD_USLEEP_RANGE 50 +#define MAX_IMPED_PARAMS 6 + +enum { + DAC_GAIN_0DB = 0, + DAC_GAIN_0P2DB, + DAC_GAIN_0P4DB, + DAC_GAIN_0P6DB, + DAC_GAIN_0P8DB, + DAC_GAIN_M0P2DB, + DAC_GAIN_M0P4DB, + DAC_GAIN_M0P6DB, +}; + +enum { + VREF_FILT_R_0OHM = 0, + VREF_FILT_R_25KOHM, + VREF_FILT_R_50KOHM, + VREF_FILT_R_100KOHM, +}; + +enum { + DELTA_I_0MA, + DELTA_I_10MA, + DELTA_I_20MA, + DELTA_I_30MA, + DELTA_I_40MA, + DELTA_I_50MA, +}; + +struct wcd_imped_val { + u32 imped_val; + u8 index; +}; + +static const struct wcd_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = { + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x0}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x0}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, +}; + +static const struct wcd_reg_mask_val imped_table_tavil[][MAX_IMPED_PARAMS] = { + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, +}; + +static const struct wcd_imped_val imped_index[] = { + {4, 0}, + {5, 1}, + {6, 2}, + {7, 3}, + {8, 4}, + {9, 5}, + {10, 6}, + {11, 7}, + {12, 8}, + {13, 9}, +}; + +static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_component *, + struct wcd_clsh_cdc_data *, + u8 req_state, bool en, int mode); + +static int get_impedance_index(int imped) +{ + int i = 0; + + if (imped < imped_index[i].imped_val) { + pr_debug("%s, detected impedance is less than 4 Ohm\n", + __func__); + i = 0; + goto ret; + } + if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) { + pr_debug("%s, detected impedance is greater than 12 Ohm\n", + __func__); + i = ARRAY_SIZE(imped_index) - 1; + goto ret; + } + for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) { + if (imped >= imped_index[i].imped_val && + imped < imped_index[i + 1].imped_val) + break; + } +ret: + pr_debug("%s: selected impedance index = %d\n", + __func__, imped_index[i].index); + return imped_index[i].index; +} + +/* + * Function: wcd_clsh_imped_config + * Params: component, imped, reset + * Description: + * This function updates HPHL and HPHR gain settings + * according to the impedance value. + */ +void wcd_clsh_imped_config(struct snd_soc_component *component, int imped, + bool reset) +{ + int i; + int index = 0; + int table_size; + + static const struct wcd_reg_mask_val + (*imped_table_ptr)[MAX_IMPED_PARAMS]; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (IS_CODEC_TYPE(wcd9xxx, WCD934X)) { + table_size = ARRAY_SIZE(imped_table_tavil); + imped_table_ptr = imped_table_tavil; + } else { + table_size = ARRAY_SIZE(imped_table); + imped_table_ptr = imped_table; + } + + /* reset = 1, which means request is to reset the register values */ + if (reset) { + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, 0); + return; + } + index = get_impedance_index(imped); + if (index >= (ARRAY_SIZE(imped_index) - 1)) { + pr_debug("%s, impedance not in range = %d\n", __func__, imped); + return; + } + if (index >= table_size) { + pr_debug("%s, impedance index not in range = %d\n", __func__, + index); + return; + } + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_component_update_bits(component, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, + imped_table_ptr[index][i].val); +} +EXPORT_SYMBOL(wcd_clsh_imped_config); + +static bool is_native_44_1_active(struct snd_soc_component *component) +{ + bool native_active = false; + u8 native_clk, rx1_rate, rx2_rate; + + native_clk = snd_soc_component_read32(component, + WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL); + rx1_rate = snd_soc_component_read32(component, + WCD9XXX_CDC_RX1_RX_PATH_CTL); + rx2_rate = snd_soc_component_read32(component, + WCD9XXX_CDC_RX2_RX_PATH_CTL); + dev_dbg(component->dev, "%s: native_clk %x rx1_rate= %x rx2_rate= %x", + __func__, native_clk, rx1_rate, rx2_rate); + + if ((native_clk & 0x2) && + ((rx1_rate & 0x0F) == 0x9 || (rx2_rate & 0x0F) == 0x9)) + native_active = true; + + return native_active; +} + +static const char *mode_to_str(int mode) +{ + switch (mode) { + case CLS_H_NORMAL: + return "CLS_H_NORMAL"; + case CLS_H_HIFI: + return "CLS_H_HIFI"; + case CLS_H_LOHIFI: + return "CLS_H_LOHIFI"; + case CLS_H_LP: + return "CLS_H_LP"; + case CLS_H_ULP: + return "CLS_H_ULP"; + case CLS_AB: + return "CLS_AB"; + case CLS_AB_HIFI: + return "CLS_AB_HIFI"; + default: + return "CLS_H_INVALID"; + }; +} + +static const char *state_to_str(u8 state, char *buf, size_t buflen) +{ + int i; + int cnt = 0; + /* + * This array of strings should match with enum wcd_clsh_state_bit. + */ + static const char *const states[] = { + "STATE_EAR", + "STATE_HPH_L", + "STATE_HPH_R", + "STATE_LO", + }; + + if (state == WCD_CLSH_STATE_IDLE) { + snprintf(buf, buflen, "[STATE_IDLE]"); + goto done; + } + + buf[0] = '\0'; + for (i = 0; i < ARRAY_SIZE(states); i++) { + if (!(state & (1 << i))) + continue; + cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf, + buf[0] == '\0' ? "[" : "|", + states[i]); + } + if (cnt > 0) + strlcat(buf + cnt, "]", buflen); + +done: + if (buf[0] == '\0') + snprintf(buf, buflen, "[STATE_UNKNOWN]"); + return buf; +} + +static inline void +wcd_enable_clsh_block(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, bool enable) +{ + if ((enable && ++clsh_d->clsh_users == 1) || + (!enable && --clsh_d->clsh_users == 0)) + snd_soc_component_update_bits(component, WCD9XXX_A_CDC_CLSH_CRC, + 0x01, (u8) enable); + if (clsh_d->clsh_users < 0) + clsh_d->clsh_users = 0; + dev_dbg(component->dev, "%s: clsh_users %d, enable %d", __func__, + clsh_d->clsh_users, enable); +} + +static inline bool wcd_clsh_enable_status(struct snd_soc_component *component) +{ + return snd_soc_component_read32(component, WCD9XXX_A_CDC_CLSH_CRC) & + 0x01; +} + +static inline int wcd_clsh_get_int_mode(struct wcd_clsh_cdc_data *clsh_d, + int clsh_state) +{ + int mode; + + if ((clsh_state != WCD_CLSH_STATE_EAR) && + (clsh_state != WCD_CLSH_STATE_HPHL) && + (clsh_state != WCD_CLSH_STATE_HPHR) && + (clsh_state != WCD_CLSH_STATE_LO)) + mode = CLS_NONE; + else + mode = clsh_d->interpolator_modes[ffs(clsh_state)]; + + return mode; +} + +static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_data *clsh_d, + int clsh_state, int mode) +{ + if ((clsh_state != WCD_CLSH_STATE_EAR) && + (clsh_state != WCD_CLSH_STATE_HPHL) && + (clsh_state != WCD_CLSH_STATE_HPHR) && + (clsh_state != WCD_CLSH_STATE_LO)) + return; + + clsh_d->interpolator_modes[ffs(clsh_state)] = mode; +} + +static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, + 0x08, 0x08); /* set to HIFI */ + else + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, + 0x08, 0x00); /* set to default */ +} + +static inline void wcd_clsh_set_flyback_mode( + struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, + 0x04, 0x04); /* set to HIFI */ + else + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, + 0x04, 0x00); /* set to Default */ +} + +static inline void wcd_clsh_gm3_boost_disable( + struct snd_soc_component *component, + int mode) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (!IS_CODEC_TYPE(wcd9xxx, WCD934X)) + return; + + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) { + if (TAVIL_IS_1_0(wcd9xxx)) + snd_soc_component_update_bits(component, + WCD9XXX_HPH_CNP_WG_CTL, + 0x80, 0x0); /* disable GM3 Boost */ + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x80); + } else { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_CNP_WG_CTL, + 0x80, 0x80); /* set to Default */ + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x70); + } +} + + +static inline void wcd_clsh_force_iq_ctl(struct snd_soc_component *component, + int mode) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (!IS_CODEC_TYPE(wcd9xxx, WCD934X)) + return; + + if (mode == CLS_H_LOHIFI || mode == CLS_AB) { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0xC0); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x02); + } else { + + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x0); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0x80); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x06); + } +} + +static void wcd_clsh_buck_ctrl(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + int mode, + bool enable) +{ + /* enable/disable buck */ + if ((enable && (++clsh_d->buck_users == 1)) || + (!enable && (--clsh_d->buck_users == 0))) + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, + (1 << 7), (enable << 7)); + dev_dbg(component->dev, "%s: buck_users %d, enable %d, mode: %s", + __func__, clsh_d->buck_users, enable, mode_to_str(mode)); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_flyback_ctrl(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + int mode, + bool enable) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + struct wcd9xxx_reg_val bulk_reg[2]; + u8 vneg[] = {0x00, 0x40}; + + /* enable/disable flyback */ + if ((enable && (++clsh_d->flyback_users == 1)) || + (!enable && (--clsh_d->flyback_users == 0))) { + snd_soc_component_update_bits(component, + WCD9XXX_A_ANA_RX_SUPPLIES, + (1 << 6), (enable << 6)); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + if (enable && (TASHA_IS_1_1(wcd9xxx))) { + wcd_clsh_set_flyback_mode(component, CLS_H_HIFI); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_EN, + 0x60, 0x40); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_EN, + 0x10, 0x10); + vneg[0] = snd_soc_component_read32(component, + WCD9XXX_A_ANA_RX_SUPPLIES); + vneg[0] &= ~(0x40); + vneg[1] = vneg[0] | 0x40; + bulk_reg[0].reg = WCD9XXX_A_ANA_RX_SUPPLIES; + bulk_reg[0].buf = &vneg[0]; + bulk_reg[0].bytes = 1; + bulk_reg[1].reg = WCD9XXX_A_ANA_RX_SUPPLIES; + bulk_reg[1].buf = &vneg[1]; + bulk_reg[1].bytes = 1; + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 510); + wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2, + false); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_EN, + 0x10, 0x00); + wcd_clsh_set_flyback_mode(component, mode); + } + + } + dev_dbg(component->dev, "%s: flyback_users %d, enable %d, mode: %s", + __func__, clsh_d->flyback_users, enable, mode_to_str(mode)); + /* + * 500us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_set_gain_path(struct snd_soc_component *component, + int mode) +{ + u8 val = 0; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (!TASHA_IS_2_0(wcd9xxx)) + return; + + switch (mode) { + case CLS_H_NORMAL: + case CLS_AB: + val = 0x00; + break; + case CLS_H_HIFI: + val = 0x02; + break; + case CLS_H_LP: + val = 0x01; + break; + default: + return; + }; + snd_soc_component_update_bits(component, WCD9XXX_HPH_L_EN, + 0xC0, (val << 6)); + snd_soc_component_update_bits(component, WCD9XXX_HPH_R_EN, + 0xC0, (val << 6)); +} + +static void wcd_clsh_set_hph_mode(struct snd_soc_component *component, + int mode) +{ + u8 val = 0; + u8 gain = 0; + u8 res_val = VREF_FILT_R_0OHM; + u8 ipeak = DELTA_I_50MA; + + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + switch (mode) { + case CLS_H_NORMAL: + res_val = VREF_FILT_R_50KOHM; + val = 0x00; + gain = DAC_GAIN_0DB; + ipeak = DELTA_I_50MA; + break; + case CLS_AB: + val = 0x00; + gain = DAC_GAIN_0DB; + ipeak = DELTA_I_50MA; + break; + case CLS_AB_HIFI: + val = 0x08; + break; + case CLS_H_HIFI: + val = 0x08; + gain = DAC_GAIN_M0P2DB; + ipeak = DELTA_I_50MA; + break; + case CLS_H_LOHIFI: + val = 0x00; + if ((IS_CODEC_TYPE(wcd9xxx, WCD9335)) || + (IS_CODEC_TYPE(wcd9xxx, WCD9326))) { + val = 0x08; + gain = DAC_GAIN_M0P2DB; + ipeak = DELTA_I_50MA; + } + break; + case CLS_H_ULP: + val = 0x0C; + break; + case CLS_H_LP: + val = 0x04; + ipeak = DELTA_I_30MA; + break; + default: + return; + }; + + /* + * For tavil set mode to Lower_power for + * CLS_H_LOHIFI and CLS_AB + */ + if ((IS_CODEC_TYPE(wcd9xxx, WCD934X)) && + (mode == CLS_H_LOHIFI || mode == CLS_AB)) + val = 0x04; + + snd_soc_component_update_bits(component, WCD9XXX_A_ANA_HPH, 0x0C, val); + if (TASHA_IS_2_0(wcd9xxx)) { + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_CTRL_VCL_2, + 0x30, (res_val << 4)); + if (mode != CLS_H_LP) + snd_soc_component_update_bits(component, + WCD9XXX_HPH_REFBUFF_UHQA_CTL, + 0x07, gain); + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_CTRL_CCL_1, + 0xF0, (ipeak << 4)); + } +} + +static void wcd_clsh_set_flyback_vneg_ctl(struct snd_soc_component *component, + bool enable) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (!TASHA_IS_2_0(wcd9xxx)) + return; + + if (enable) { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, (0x07 << 5)); + } else { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_1, + 0xE0, (0x07 << 5)); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, (0x02 << 5)); + } +} + +static void wcd_clsh_set_flyback_current(struct snd_soc_component *component, + int mode) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent); + + if (!TASHA_IS_2_0(wcd9xxx)) + return; + + snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF, + 0x0F, 0x0A); + snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF, + 0xF0, 0xA0); + /* Sleep needed to avoid click and pop as per HW requirement */ + usleep_range(100, 110); +} + +static void wcd_clsh_set_buck_regulator_mode( + struct snd_soc_component *component, + int mode) +{ + snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES, + 0x02, 0x00); +} + +static void wcd_clsh_state_lo(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + dev_err_ratelimited(component->dev, "%s: LO cannot be in this mode: %d\n", + __func__, mode); + return; + } + + if (is_enable) { + wcd_clsh_set_buck_regulator_mode(component, mode); + wcd_clsh_set_flyback_vneg_ctl(component, true); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + } else { + wcd_clsh_buck_ctrl(component, clsh_d, mode, false); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, false); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + wcd_clsh_set_flyback_vneg_ctl(component, false); + wcd_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_ear(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + int hph_mode = 0; + + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (is_enable) { + if (req_state == WCD_CLSH_STATE_EAR) { + /* If HPH is running in CLS-AB when + * EAR comes, let it continue to run + * in Class-AB, no need to enable Class-H + * for EAR. + */ + if (clsh_d->state & WCD_CLSH_STATE_HPHL) + hph_mode = wcd_clsh_get_int_mode(clsh_d, + WCD_CLSH_STATE_HPHL); + else if (clsh_d->state & WCD_CLSH_STATE_HPHR) + hph_mode = wcd_clsh_get_int_mode(clsh_d, + WCD_CLSH_STATE_HPHR); + else + return; + if (hph_mode != CLS_AB && hph_mode != CLS_AB_HIFI + && !is_native_44_1_active(component)) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x40); + } + + if (is_native_44_1_active(component)) { + snd_soc_component_write(component, + WCD9XXX_CDC_CLSH_HPH_V_PA, 0x39); + snd_soc_component_update_bits(component, + WCD9XXX_CDC_RX0_RX_PATH_SEC0, + 0x03, 0x00); + if ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR)) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x00); + } + + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x40); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x40); + if ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR)) { + wcd_clsh_set_gain_path(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_set_buck_mode(component, mode); + } + } else { + if (req_state == WCD_CLSH_STATE_EAR) { + /* + * If EAR goes away, disable EAR Channel Enable + * if HPH running in Class-H otherwise + * and if HPH requested mode is CLS_AB then + * no need to disable EAR channel enable bit. + */ + if (wcd_clsh_enable_status(component)) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x00); + } + + if (is_native_44_1_active(component)) { + snd_soc_component_write(component, + WCD9XXX_CDC_CLSH_HPH_V_PA, 0x1C); + snd_soc_component_update_bits(component, + WCD9XXX_CDC_RX0_RX_PATH_SEC0, + 0x03, 0x01); + if (((clsh_d->state & WCD_CLSH_STATE_HPH_ST) + != WCD_CLSH_STATE_HPH_ST) && + ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR))) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x40); + } + + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x00); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x00); + if ((req_state & WCD_CLSH_STATE_HPH_ST) && + !wcd_clsh_enable_status(component)) { + /* If Class-H is not enabled when HPH is turned + * off, enable it as EAR is in progress + */ + wcd_enable_clsh_block(component, clsh_d, true); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x40); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + } + } +} + +static void wcd_clsh_state_ear_lo(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (is_enable) { + /* LO powerup is taken care in PA sequence. + * No need to change to class AB here. + */ + if (req_state == WCD_CLSH_STATE_EAR) { + /* EAR powerup.*/ + if (!wcd_clsh_enable_status(component)) { + wcd_enable_clsh_block(component, clsh_d, true); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + } + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x40); + } + } else { + if (req_state == WCD_CLSH_STATE_EAR) { + /* EAR powerdown.*/ + wcd_enable_clsh_block(component, clsh_d, false); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x00); + } + /* LO powerdown is taken care in PA sequence. + * No need to change to class H here. + */ + } +} + +static void wcd_clsh_state_hph_lo(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + int hph_mode = 0; + + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (is_enable) { + /* + * If requested state is LO, put regulator + * in class-AB or if requested state is HPH, + * which means LO is already enabled, keep + * the regulator config the same at class-AB + * and just set the power modes for flyback + * and buck. + */ + if (req_state == WCD_CLSH_STATE_LO) + wcd_clsh_set_buck_regulator_mode(component, CLS_AB); + else { + if (!wcd_clsh_enable_status(component)) { + wcd_enable_clsh_block(component, clsh_d, true); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_MSB, + 0x0F, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_LSB, + 0xFF, 0xC0); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_set_flyback_vneg_ctl(component, false); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_set_hph_mode(component, mode); + wcd_clsh_set_gain_path(component, mode); + } else { + dev_dbg(component->dev, "%s:clsh is already enabled\n", + __func__); + } + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x40); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x40); + } + } else { + if ((req_state == WCD_CLSH_STATE_HPHL) || + (req_state == WCD_CLSH_STATE_HPHR)) { + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x00); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x00); + /* + * If HPH is powering down first, then disable clsh, + * set the buck/flyback mode to default and keep the + * regulator at Class-AB + */ + if ((clsh_d->state & WCD_CLSH_STATE_HPH_ST) + != WCD_CLSH_STATE_HPH_ST) { + wcd_enable_clsh_block(component, clsh_d, false); + wcd_clsh_set_flyback_vneg_ctl(component, true); + wcd_clsh_set_flyback_mode( + component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + } + } else { + /* LO powerdown. + * If HPH mode also is CLS-AB, no need + * to turn-on class-H, otherwise enable + * Class-H configuration. + */ + if (clsh_d->state & WCD_CLSH_STATE_HPHL) + hph_mode = wcd_clsh_get_int_mode(clsh_d, + WCD_CLSH_STATE_HPHL); + else if (clsh_d->state & WCD_CLSH_STATE_HPHR) + hph_mode = wcd_clsh_get_int_mode(clsh_d, + WCD_CLSH_STATE_HPHR); + else + return; + dev_dbg(component->dev, "%s: hph_mode = %d\n", __func__, + hph_mode); + + if ((hph_mode == CLS_AB) || + (hph_mode == CLS_AB_HIFI) || + (hph_mode == CLS_NONE)) + goto end; + + /* + * If Class-H is already enabled (HPH ON and then + * LO ON), no need to turn on again, just set the + * regulator mode. + */ + if (wcd_clsh_enable_status(component)) { + wcd_clsh_set_buck_regulator_mode(component, + hph_mode); + goto end; + } else { + dev_dbg(component->dev, "%s: clsh is not enabled\n", + __func__); + } + + wcd_enable_clsh_block(component, clsh_d, true); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_MSB, + 0x0F, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_LSB, + 0xFF, 0xC0); + wcd_clsh_set_buck_regulator_mode(component, + hph_mode); + if (clsh_d->state & WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x40); + if (clsh_d->state & WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x40); + wcd_clsh_set_hph_mode(component, hph_mode); + } + } +end: + return; +} + +static void wcd_clsh_state_hph_st(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (mode == CLS_AB || mode == CLS_AB_HIFI) + return; + + if (is_enable) { + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x40); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x40); + } else { + if (req_state == WCD_CLSH_STATE_HPHL) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x00); + if (req_state == WCD_CLSH_STATE_HPHR) + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x00); + } +} + +static void wcd_clsh_state_hph_r(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (mode == CLS_H_NORMAL) { + dev_err_ratelimited(component->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + wcd_enable_clsh_block(component, clsh_d, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_MSB, + 0x0F, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_LSB, + 0xFF, 0xC0); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x40); + } + wcd_clsh_set_buck_regulator_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_gm3_boost_disable(component, mode); + wcd_clsh_force_iq_ctl(component, mode); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_hph_mode(component, mode); + wcd_clsh_set_gain_path(component, mode); + } else { + wcd_clsh_set_hph_mode(component, CLS_H_NORMAL); + + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + 0x40, 0x00); + wcd_enable_clsh_block(component, clsh_d, false); + } + /* buck and flyback set to default mode and disable */ + wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL); + wcd_clsh_gm3_boost_disable(component, CLS_H_NORMAL); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_l(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (mode == CLS_H_NORMAL) { + dev_err_ratelimited(component->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + wcd_enable_clsh_block(component, clsh_d, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_MSB, + 0x0F, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_CLSH_K1_LSB, + 0xFF, 0xC0); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x40); + } + wcd_clsh_set_buck_regulator_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_gm3_boost_disable(component, mode); + wcd_clsh_force_iq_ctl(component, mode); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_hph_mode(component, mode); + wcd_clsh_set_gain_path(component, mode); + } else { + wcd_clsh_set_hph_mode(component, CLS_H_NORMAL); + + if (mode != CLS_AB && mode != CLS_AB_HIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + 0x40, 0x00); + wcd_enable_clsh_block(component, clsh_d, false); + } + /* set buck and flyback to Default Mode */ + wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL); + wcd_clsh_gm3_boost_disable(component, CLS_H_NORMAL); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_ear(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__, + mode_to_str(mode), + is_enable ? "enable" : "disable"); + + if (mode != CLS_H_NORMAL) { + dev_err_ratelimited(component->dev, "%s: mode: %s cannot be used for EAR\n", + __func__, mode_to_str(mode)); + return; + } + + if (is_enable) { + wcd_enable_clsh_block(component, clsh_d, true); + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x40); + wcd_clsh_set_buck_mode(component, mode); + wcd_clsh_set_flyback_mode(component, mode); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, true); + wcd_clsh_set_flyback_current(component, mode); + wcd_clsh_buck_ctrl(component, clsh_d, mode, true); + } else { + snd_soc_component_update_bits(component, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x00); + wcd_enable_clsh_block(component, clsh_d, false); + wcd_clsh_buck_ctrl(component, clsh_d, mode, false); + wcd_clsh_flyback_ctrl(component, clsh_d, mode, false); + wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(component, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_err(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *clsh_d, + u8 req_state, bool is_enable, int mode) +{ + char msg[128]; + + dev_err_ratelimited(component->dev, + "%s Wrong request for class H state machine requested to %s %s", + __func__, is_enable ? "enable" : "disable", + state_to_str(req_state, msg, sizeof(msg))); + WARN_ON(1); +} + +/* + * Function: wcd_clsh_is_state_valid + * Params: state + * Description: + * Provides information on valid states of Class H configuration + */ +static bool wcd_clsh_is_state_valid(u8 state) +{ + switch (state) { + case WCD_CLSH_STATE_IDLE: + case WCD_CLSH_STATE_EAR: + case WCD_CLSH_STATE_HPHL: + case WCD_CLSH_STATE_HPHR: + case WCD_CLSH_STATE_HPH_ST: + case WCD_CLSH_STATE_LO: + case WCD_CLSH_STATE_HPHL_EAR: + case WCD_CLSH_STATE_HPHR_EAR: + case WCD_CLSH_STATE_HPH_ST_EAR: + case WCD_CLSH_STATE_HPHL_LO: + case WCD_CLSH_STATE_HPHR_LO: + case WCD_CLSH_STATE_HPH_ST_LO: + case WCD_CLSH_STATE_EAR_LO: + return true; + default: + return false; + }; +} + +/* + * Function: wcd_clsh_fsm + * Params: component, cdc_clsh_d, req_state, req_type, clsh_event + * Description: + * This function handles PRE DAC and POST DAC conditions of different devices + * and updates class H configuration of different combination of devices + * based on validity of their states. cdc_clsh_d will contain current + * class h state information + */ +void wcd_clsh_fsm(struct snd_soc_component *component, + struct wcd_clsh_cdc_data *cdc_clsh_d, + u8 clsh_event, u8 req_state, + int int_mode) +{ + u8 old_state, new_state; + char msg0[128], msg1[128]; + + switch (clsh_event) { + case WCD_CLSH_EVENT_PRE_DAC: + old_state = cdc_clsh_d->state; + new_state = old_state | req_state; + + if (!wcd_clsh_is_state_valid(new_state)) { + dev_err_ratelimited(component->dev, + "%s: Class-H not a valid new state: %s\n", + __func__, + state_to_str(new_state, msg0, sizeof(msg0))); + return; + } + if (new_state == old_state) { + dev_err_ratelimited(component->dev, + "%s: Class-H already in requested state: %s\n", + __func__, + state_to_str(new_state, msg0, sizeof(msg0))); + return; + } + cdc_clsh_d->state = new_state; + wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode); + (*clsh_state_fp[new_state]) (component, cdc_clsh_d, req_state, + CLSH_REQ_ENABLE, int_mode); + dev_dbg(component->dev, + "%s: ClassH state transition from %s to %s\n", + __func__, state_to_str(old_state, msg0, sizeof(msg0)), + state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1))); + break; + case WCD_CLSH_EVENT_POST_PA: + old_state = cdc_clsh_d->state; + new_state = old_state & (~req_state); + if (new_state < NUM_CLSH_STATES_V2) { + if (!wcd_clsh_is_state_valid(old_state)) { + dev_err_ratelimited(component->dev, + "%s:Invalid old state:%s\n", + __func__, + state_to_str(old_state, msg0, + sizeof(msg0))); + return; + } + if (new_state == old_state) { + dev_err_ratelimited(component->dev, + "%s: Class-H already in requested state: %s\n", + __func__, + state_to_str(new_state, msg0, + sizeof(msg0))); + return; + } + (*clsh_state_fp[old_state]) (component, cdc_clsh_d, + req_state, CLSH_REQ_DISABLE, + int_mode); + cdc_clsh_d->state = new_state; + wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE); + dev_dbg(component->dev, "%s: ClassH state transition from %s to %s\n", + __func__, state_to_str(old_state, msg0, + sizeof(msg0)), + state_to_str(cdc_clsh_d->state, msg1, + sizeof(msg1))); + } + break; + }; +} +EXPORT_SYMBOL(wcd_clsh_fsm); + +int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh) +{ + return clsh->state; +} +EXPORT_SYMBOL(wcd_clsh_get_clsh_state); + +void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh) +{ + int i; + + clsh->state = WCD_CLSH_STATE_IDLE; + + for (i = 0; i < NUM_CLSH_STATES_V2; i++) + clsh_state_fp[i] = wcd_clsh_state_err; + + clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear; + clsh_state_fp[WCD_CLSH_STATE_HPHL] = + wcd_clsh_state_hph_l; + clsh_state_fp[WCD_CLSH_STATE_HPHR] = + wcd_clsh_state_hph_r; + clsh_state_fp[WCD_CLSH_STATE_HPH_ST] = + wcd_clsh_state_hph_st; + clsh_state_fp[WCD_CLSH_STATE_LO] = wcd_clsh_state_lo; + clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] = + wcd_clsh_state_hph_ear; + clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] = + wcd_clsh_state_hph_ear; + clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] = + wcd_clsh_state_hph_ear; + clsh_state_fp[WCD_CLSH_STATE_HPHL_LO] = wcd_clsh_state_hph_lo; + clsh_state_fp[WCD_CLSH_STATE_HPHR_LO] = wcd_clsh_state_hph_lo; + clsh_state_fp[WCD_CLSH_STATE_HPH_ST_LO] = + wcd_clsh_state_hph_lo; + clsh_state_fp[WCD_CLSH_STATE_EAR_LO] = wcd_clsh_state_ear_lo; + /* Set interpolaotr modes to NONE */ + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE); + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE); + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE); + wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_LO, CLS_NONE); + clsh->flyback_users = 0; + clsh->buck_users = 0; + clsh->clsh_users = 0; +} +EXPORT_SYMBOL(wcd_clsh_init); + +MODULE_DESCRIPTION("WCD9XXX Common Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-core-init.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-core-init.c new file mode 100644 index 0000000000..cd35a9e24b --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-core-init.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#define NUM_DRIVERS_REG_RET 3 + +static int __init wcd9xxx_core_init(void) +{ + int ret[NUM_DRIVERS_REG_RET] = {0}; + int i = 0; + + ret[0] = msm_cdc_pinctrl_drv_init(); + if (ret[0]) + pr_err("%s: Failed init pinctrl drv: %d\n", __func__, ret[0]); + + ret[1] = wcd9xxx_irq_drv_init(); + if (ret[1]) + pr_err("%s: Failed init irq drv: %d\n", __func__, ret[1]); + + ret[2] = wcd9xxx_init(); + if (ret[2]) + pr_err("%s: Failed wcd core drv: %d\n", __func__, ret[2]); + + for (i = 0; i < NUM_DRIVERS_REG_RET; i++) { + if (ret[i]) + return ret[i]; + } + + return 0; +} +module_init(wcd9xxx_core_init); + +static void __exit wcd9xxx_core_exit(void) +{ + wcd9xxx_exit(); + wcd9xxx_irq_drv_exit(); + msm_cdc_pinctrl_drv_exit(); +} +module_exit(wcd9xxx_core_exit); + +MODULE_DESCRIPTION("WCD9XXX CODEC core init driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-core.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-core.c new file mode 100644 index 0000000000..36825d5ea0 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-core.c @@ -0,0 +1,1810 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd9xxx-utils.h" +#include +#include +#include + +#define WCD9XXX_REGISTER_START_OFFSET 0x800 +#define WCD9XXX_SLIM_RW_MAX_TRIES 3 +#define SLIMBUS_PRESENT_TIMEOUT 100 + +#define MAX_WCD9XXX_DEVICE 4 +#define WCD9XXX_I2C_GSBI_SLAVE_ID "3-000d" +#define WCD9XXX_I2C_TOP_SLAVE_ADDR 0x0d +#define WCD9XXX_ANALOG_I2C_SLAVE_ADDR 0x77 +#define WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR 0x66 +#define WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR 0x55 +#define WCD9XXX_I2C_TOP_LEVEL 0 +#define WCD9XXX_I2C_ANALOG 1 +#define WCD9XXX_I2C_DIGITAL_1 2 +#define WCD9XXX_I2C_DIGITAL_2 3 + +/* + * Number of return values needs to be checked for each + * registration of Slimbus of I2C bus for each codec + */ +#define NUM_WCD9XXX_REG_RET 5 + +#define SLIM_USR_MC_REPEAT_CHANGE_VALUE 0x0 +#define SLIM_REPEAT_WRITE_MAX_SLICE 16 +#define REG_BYTES 2 +#define VAL_BYTES 1 +#define WCD9XXX_PAGE_NUM(reg) (((reg) >> 8) & 0xff) +#define WCD9XXX_PAGE_SIZE 256 + +struct wcd9xxx_i2c { + struct i2c_client *client; + struct i2c_msg xfer_msg[2]; + struct mutex xfer_lock; + int mod_id; +}; + +static struct regmap_config wcd9xxx_base_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .can_multi_write = true, + .use_single_read = true, + .use_single_write = true, +}; + +static struct regmap_config wcd9xxx_i2c_base_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .can_multi_write = false, + .use_single_read = true, + .use_single_write = true, +}; + +static u8 wcd9xxx_pgd_la; +static u8 wcd9xxx_inf_la; + +static const int wcd9xxx_cdc_types[] = { + [WCD9XXX] = WCD9XXX, + [WCD9330] = WCD9330, + [WCD9335] = WCD9335, + [WCD934X] = WCD934X, +}; + +static const struct of_device_id wcd9xxx_of_match[] = { + { .compatible = "qcom,tavil-i2c", + .data = (void *)&wcd9xxx_cdc_types[WCD934X]}, + { .compatible = "qcom,tasha-i2c-pgd", + .data = (void *)&wcd9xxx_cdc_types[WCD9335]}, + { .compatible = "qcom,wcd9xxx-i2c", + .data = (void *)&wcd9xxx_cdc_types[WCD9330]}, + { } +}; +MODULE_DEVICE_TABLE(of, wcd9xxx_of_match); + +static int wcd9xxx_slim_device_up(struct slim_device *sldev); +static int wcd9xxx_slim_device_down(struct slim_device *sldev); + +struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE]; + +/* + * wcd9xxx_vote_ondemand_regulator: Initialize codec dynamic supplies + * + * @wcd9xxx: Pointer to wcd9xxx structure + * @wcd9xxx_pdata: Pointer to wcd9xxx_pdata structure + * @supply_name: supply parameter to initialize regulator + * @enable: flag to initialize/uninitialize supply + * + * Return error code if supply init is failed + */ +int wcd9xxx_vote_ondemand_regulator(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_pdata *pdata, + const char *supply_name, + bool enable) +{ + int i, rc, index = -EINVAL; + + pr_debug("%s: enable %d\n", __func__, enable); + + for (i = 0; i < wcd9xxx->num_of_supplies; ++i) { + if (pdata->regulator[i].ondemand && + wcd9xxx->supplies[i].supply && + !strcmp(wcd9xxx->supplies[i].supply, supply_name)) { + index = i; + break; + } + } + + if (index < 0) { + pr_err("%s: no matching regulator found\n", __func__); + return -EINVAL; + } + + if (enable) { + rc = regulator_set_voltage(wcd9xxx->supplies[index].consumer, + pdata->regulator[index].min_uV, + pdata->regulator[index].max_uV); + if (rc) { + pr_err("%s: set regulator voltage failed for %s, err:%d\n", + __func__, supply_name, rc); + return rc; + } + rc = regulator_set_load(wcd9xxx->supplies[index].consumer, + pdata->regulator[index].optimum_uA); + if (rc < 0) { + pr_err("%s: set regulator optimum mode failed for %s, err:%d\n", + __func__, supply_name, rc); + return rc; + } + } else { + regulator_set_voltage(wcd9xxx->supplies[index].consumer, 0, + pdata->regulator[index].max_uV); + regulator_set_load(wcd9xxx->supplies[index].consumer, 0); + } + + return 0; +} +EXPORT_SYMBOL(wcd9xxx_vote_ondemand_regulator); + +static int wcd9xxx_slim_multi_reg_write(struct wcd9xxx *wcd9xxx, + const void *data, size_t count) +{ + unsigned int reg; + struct device *dev; + u8 val[WCD9XXX_PAGE_SIZE]; + int ret = 0; + int i = 0; + int n = 0; + unsigned int page_num; + size_t num_regs = (count / (REG_BYTES + VAL_BYTES)); + struct wcd9xxx_reg_val *bulk_reg; + u8 *buf; + + dev = wcd9xxx->dev; + if (!data) { + dev_err(dev, "%s: data is NULL\n", __func__); + return -EINVAL; + } + if (num_regs == 0) + return -EINVAL; + + bulk_reg = kzalloc(num_regs * (sizeof(struct wcd9xxx_reg_val)), + GFP_KERNEL); + if (!bulk_reg) + return -ENOMEM; + + buf = (u8 *)data; + reg = *(u16 *)buf; + page_num = WCD9XXX_PAGE_NUM(reg); + for (i = 0, n = 0; n < num_regs; i++, n++) { + reg = *(u16 *)buf; + if (page_num != WCD9XXX_PAGE_NUM(reg)) { + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, + i, false); + page_num = WCD9XXX_PAGE_NUM(reg); + i = 0; + } + buf += REG_BYTES; + val[i] = *buf; + buf += VAL_BYTES; + bulk_reg[i].reg = reg; + bulk_reg[i].buf = &val[i]; + bulk_reg[i].bytes = 1; + } + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, + i, false); + if (ret) + dev_err(dev, "%s: error writing bulk regs\n", + __func__); + + kfree(bulk_reg); + return ret; +} + +/* + * wcd9xxx_interface_reg_read: Read slim interface registers + * + * @wcd9xxx: Pointer to wcd9xxx structure + * @reg: register adderss + * + * Returns register value in success and negative error code in case of failure + */ +int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg) +{ + u8 val; + int ret; + + mutex_lock(&wcd9xxx->io_lock); + ret = wcd9xxx->read_dev(wcd9xxx, reg, 1, (void *)&val, + true); + if (ret < 0) + dev_err(wcd9xxx->dev, "%s: Codec read 0x%x failed\n", + __func__, reg); + else + dev_dbg(wcd9xxx->dev, "%s: Read 0x%02x from 0x%x\n", + __func__, val, reg); + + mutex_unlock(&wcd9xxx->io_lock); + + if (ret < 0) + return ret; + else + return val; +} +EXPORT_SYMBOL(wcd9xxx_interface_reg_read); + +/* + * wcd9xxx_interface_reg_write: Write slim interface registers + * + * @wcd9xxx: Pointer to wcd9xxx structure + * @reg: register adderss + * @val: value of the register to be written + * + * Returns 0 for success and negative error code in case of failure + */ +int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg, + u8 val) +{ + int ret; + + mutex_lock(&wcd9xxx->io_lock); + ret = wcd9xxx->write_dev(wcd9xxx, reg, 1, (void *)&val, true); + dev_dbg(wcd9xxx->dev, "%s: Write %02x to 0x%x ret(%d)\n", + __func__, val, reg, ret); + mutex_unlock(&wcd9xxx->io_lock); + + return ret; +} +EXPORT_SYMBOL(wcd9xxx_interface_reg_write); + +static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg, + int bytes, void *dest, bool interface) +{ + int ret; + struct slim_ele_access msg; + int slim_read_tries = WCD9XXX_SLIM_RW_MAX_TRIES; + + msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg; + msg.num_bytes = bytes; + msg.comp = NULL; + + if (!wcd9xxx->dev_up) { + dev_dbg_ratelimited( + wcd9xxx->dev, "%s: No read allowed. dev_up = %d\n", + __func__, wcd9xxx->dev_up); + return 0; + } + + while (1) { + mutex_lock(&wcd9xxx->xfer_lock); + ret = slim_request_val_element(interface ? + wcd9xxx->slim_slave : wcd9xxx->slim, + &msg, dest, bytes); + mutex_unlock(&wcd9xxx->xfer_lock); + if (likely(ret == 0) || (--slim_read_tries == 0)) + break; + usleep_range(5000, 5100); + } + + if (ret) + dev_err(wcd9xxx->dev, "%s: Error, Codec read failed (%d)\n", + __func__, ret); + + return ret; +} + +/* + * Interface specifies whether the write is to the interface or general + * registers. + */ +static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx, + unsigned short reg, int bytes, void *src, bool interface) +{ + int ret; + struct slim_ele_access msg; + int slim_write_tries = WCD9XXX_SLIM_RW_MAX_TRIES; + + msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg; + msg.num_bytes = bytes; + msg.comp = NULL; + + if (!wcd9xxx->dev_up) { + dev_dbg_ratelimited( + wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n", + __func__, wcd9xxx->dev_up); + return 0; + } + + while (1) { + mutex_lock(&wcd9xxx->xfer_lock); + ret = slim_change_val_element(interface ? + wcd9xxx->slim_slave : wcd9xxx->slim, + &msg, src, bytes); + mutex_unlock(&wcd9xxx->xfer_lock); + if (likely(ret == 0) || (--slim_write_tries == 0)) + break; + usleep_range(5000, 5100); + } + + if (ret) + pr_err("%s: Error, Codec write failed (%d)\n", __func__, ret); + + return ret; +} + +static int wcd9xxx_slim_get_allowed_slice(struct wcd9xxx *wcd9xxx, + int bytes) +{ + int allowed_sz = bytes; + + if (likely(bytes == SLIM_REPEAT_WRITE_MAX_SLICE)) + allowed_sz = 16; + else if (bytes >= 12) + allowed_sz = 12; + else if (bytes >= 8) + allowed_sz = 8; + else if (bytes >= 6) + allowed_sz = 6; + else if (bytes >= 4) + allowed_sz = 4; + else + allowed_sz = bytes; + + return allowed_sz; +} + +/* + * wcd9xxx_slim_write_repeat: Write the same register with multiple values + * @wcd9xxx: handle to wcd core + * @reg: register to be written + * @bytes: number of bytes to be written to reg + * @src: buffer with data content to be written to reg + * This API will write reg with bytes from src in a single slimbus + * transaction. All values from 1 to 16 are supported by this API. + */ +int wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx, unsigned short reg, + int bytes, void *src) +{ + int ret = 0, bytes_to_write = bytes, bytes_allowed; + struct slim_ele_access slim_msg; + + mutex_lock(&wcd9xxx->io_lock); + if (wcd9xxx->type == WCD9335 || wcd9xxx->type == WCD934X) { + ret = wcd9xxx_page_write(wcd9xxx, ®); + if (ret) + goto done; + } + + slim_msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg; + slim_msg.comp = NULL; + + if (unlikely(bytes > SLIM_REPEAT_WRITE_MAX_SLICE)) { + dev_err(wcd9xxx->dev, "%s: size %d not supported\n", + __func__, bytes); + ret = -EINVAL; + goto done; + } + + if (!wcd9xxx->dev_up) { + dev_dbg_ratelimited( + wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n", + __func__, wcd9xxx->dev_up); + ret = 0; + goto done; + } + + while (bytes_to_write > 0) { + bytes_allowed = wcd9xxx_slim_get_allowed_slice(wcd9xxx, + bytes_to_write); + + slim_msg.num_bytes = bytes_allowed; + mutex_lock(&wcd9xxx->xfer_lock); + ret = slim_user_msg(wcd9xxx->slim, wcd9xxx->slim->laddr, + SLIM_MSG_MT_DEST_REFERRED_USER, + SLIM_USR_MC_REPEAT_CHANGE_VALUE, + &slim_msg, src, bytes_allowed); + mutex_unlock(&wcd9xxx->xfer_lock); + + if (ret) { + dev_err(wcd9xxx->dev, "%s: failed, ret = %d\n", + __func__, ret); + break; + } + + bytes_to_write = bytes_to_write - bytes_allowed; + src = ((u8 *)src) + bytes_allowed; + } + +done: + mutex_unlock(&wcd9xxx->io_lock); + + return ret; +} +EXPORT_SYMBOL(wcd9xxx_slim_write_repeat); + +/* + * wcd9xxx_slim_reserve_bw: API to reserve the slimbus bandwidth + * @wcd9xxx: Handle to the wcd9xxx core + * @bw_ops: value of the bandwidth that is requested + * @commit: Flag to indicate if bandwidth change is to be committed + * right away + */ +int wcd9xxx_slim_reserve_bw(struct wcd9xxx *wcd9xxx, + u32 bw_ops, bool commit) +{ + if (!wcd9xxx || !wcd9xxx->slim) { + pr_err("%s: Invalid handle to %s\n", + __func__, + (!wcd9xxx) ? "wcd9xxx" : "slim_device"); + return -EINVAL; + } + + return slim_reservemsg_bw(wcd9xxx->slim, bw_ops, commit); +} +EXPORT_SYMBOL(wcd9xxx_slim_reserve_bw); + +/* + * wcd9xxx_slim_bulk_write: API to write multiple registers with one descriptor + * @wcd9xxx: Handle to the wcd9xxx core + * @wcd9xxx_reg_val: structure holding register and values to be written + * @size: Indicates number of messages to be written with one descriptor + * @is_interface: Indicates whether the register is for slim interface or for + * general registers. + * @return: returns 0 if success or error information to the caller in case + * of failure. + */ +int wcd9xxx_slim_bulk_write(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_reg_val *bulk_reg, + unsigned int size, bool is_interface) +{ + int ret, i; + struct slim_val_inf *msgs; + unsigned short reg; + + if (!bulk_reg || !size || !wcd9xxx) { + pr_err("%s: Invalid parameters\n", __func__); + return -EINVAL; + } + + if (!wcd9xxx->dev_up) { + dev_dbg_ratelimited( + wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n", + __func__, wcd9xxx->dev_up); + return 0; + } + + msgs = kzalloc(size * (sizeof(struct slim_val_inf)), GFP_KERNEL); + if (!msgs) { + ret = -ENOMEM; + goto mem_fail; + } + + mutex_lock(&wcd9xxx->io_lock); + reg = bulk_reg->reg; + for (i = 0; i < size; i++) { + msgs[i].start_offset = WCD9XXX_REGISTER_START_OFFSET + + (bulk_reg->reg & 0xFF); + msgs[i].num_bytes = bulk_reg->bytes; + msgs[i].wbuf = bulk_reg->buf; + bulk_reg++; + } + ret = wcd9xxx_page_write(wcd9xxx, ®); + if (ret) { + pr_err("%s: Page write error for reg: 0x%x\n", + __func__, reg); + goto err; + } + + ret = slim_bulk_msg_write(is_interface ? + wcd9xxx->slim_slave : wcd9xxx->slim, + SLIM_MSG_MT_CORE, + SLIM_MSG_MC_CHANGE_VALUE, msgs, size, + NULL, NULL); + if (ret) + pr_err("%s: Error, Codec bulk write failed (%d)\n", + __func__, ret); + /* 100 usec sleep is needed as per HW requirement */ + usleep_range(100, 110); +err: + mutex_unlock(&wcd9xxx->io_lock); + kfree(msgs); +mem_fail: + return ret; +} +EXPORT_SYMBOL(wcd9xxx_slim_bulk_write); + +static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx) +{ + return (wcd9xxx->codec_type->num_irqs / 8) + + ((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0); +} + +static int wcd9xxx_regmap_init_cache(struct wcd9xxx *wcd9xxx) +{ + struct regmap_config *regmap_config; + int rc; + + regmap_config = wcd9xxx_get_regmap_config(wcd9xxx->type); + if (!regmap_config) { + dev_err(wcd9xxx->dev, "regmap config is not defined\n"); + return -EINVAL; + } + + rc = regmap_reinit_cache(wcd9xxx->regmap, regmap_config); + if (rc != 0) { + dev_err(wcd9xxx->dev, "%s:Failed to reinit register cache: %d\n", + __func__, rc); + } + + return rc; +} + +static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx) +{ + int ret = 0, i; + struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res; + regmap_patch_fptr regmap_apply_patch = NULL; + + mutex_init(&wcd9xxx->io_lock); + mutex_init(&wcd9xxx->xfer_lock); + mutex_init(&wcd9xxx->reset_lock); + + ret = wcd9xxx_bringup(wcd9xxx->dev); + if (ret) { + ret = -EPROBE_DEFER; + goto err_bring_up; + } + + wcd9xxx->codec_type = devm_kzalloc(wcd9xxx->dev, + sizeof(struct wcd9xxx_codec_type), GFP_KERNEL); + if (!wcd9xxx->codec_type) { + ret = -ENOMEM; + goto err_bring_up; + } + ret = wcd9xxx_get_codec_info(wcd9xxx->dev); + if (ret) { + ret = -EPROBE_DEFER; + goto fail_cdc_fill; + } + wcd9xxx->version = wcd9xxx->codec_type->version; + if (!wcd9xxx->codec_type->dev || !wcd9xxx->codec_type->size) + goto fail_cdc_fill; + + core_res->parent = wcd9xxx; + core_res->dev = wcd9xxx->dev; + core_res->intr_table = wcd9xxx->codec_type->intr_tbl; + core_res->intr_table_size = wcd9xxx->codec_type->intr_tbl_size; + + for (i = 0; i < WCD9XXX_INTR_REG_MAX; i++) + wcd9xxx->core_res.intr_reg[i] = + wcd9xxx->codec_type->intr_reg[i]; + + wcd9xxx_core_res_init(&wcd9xxx->core_res, + wcd9xxx->codec_type->num_irqs, + wcd9xxx_num_irq_regs(wcd9xxx), + wcd9xxx->regmap); + + if (wcd9xxx_core_irq_init(&wcd9xxx->core_res)) + goto err; + + ret = wcd9xxx_regmap_init_cache(wcd9xxx); + if (ret) + goto err_irq; + + regmap_apply_patch = wcd9xxx_get_regmap_reg_patch( + wcd9xxx->type); + if (regmap_apply_patch) { + ret = regmap_apply_patch(wcd9xxx->regmap, + wcd9xxx->version); + if (ret) + dev_err(wcd9xxx->dev, + "Failed to register patch: %d\n", ret); + } + + ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx->codec_type->dev, + wcd9xxx->codec_type->size, NULL, 0, NULL); + if (ret != 0) { + dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret); + goto err_irq; + } + + ret = device_init_wakeup(wcd9xxx->dev, true); + if (ret) { + dev_err(wcd9xxx->dev, "Device wakeup init failed: %d\n", ret); + goto err_irq; + } + + return ret; +err_irq: + wcd9xxx_irq_exit(&wcd9xxx->core_res); +err: + wcd9xxx_core_res_deinit(&wcd9xxx->core_res); +fail_cdc_fill: + devm_kfree(wcd9xxx->dev, wcd9xxx->codec_type); + wcd9xxx_bringdown(wcd9xxx->dev); + wcd9xxx->codec_type = NULL; +err_bring_up: + mutex_destroy(&wcd9xxx->io_lock); + mutex_destroy(&wcd9xxx->xfer_lock); + mutex_destroy(&wcd9xxx->reset_lock); + return ret; +} + +static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx) +{ + device_init_wakeup(wcd9xxx->dev, false); + wcd9xxx_irq_exit(&wcd9xxx->core_res); + mfd_remove_devices(wcd9xxx->dev); + wcd9xxx_bringdown(wcd9xxx->dev); + wcd9xxx_reset_low(wcd9xxx->dev); + wcd9xxx_core_res_deinit(&wcd9xxx->core_res); + mutex_destroy(&wcd9xxx->io_lock); + mutex_destroy(&wcd9xxx->xfer_lock); + mutex_destroy(&wcd9xxx->reset_lock); + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + slim_remove_device(wcd9xxx->slim_slave); +} + + +#ifdef CONFIG_DEBUG_FS +struct wcd9xxx *debugCodec; + +static struct dentry *debugfs_wcd9xxx_dent; +static struct dentry *debugfs_peek; +static struct dentry *debugfs_poke; +static struct dentry *debugfs_power_state; +static struct dentry *debugfs_reg_dump; + +static unsigned char read_data; + +static int codec_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int get_parameters(char *buf, long int *param1, int num_of_par) +{ + char *token; + int base, cnt; + + token = strsep(&buf, " "); + + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token != NULL) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtoul(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else + return -EINVAL; + } + return 0; +} + +static ssize_t wcd9xxx_slimslave_reg_show(char __user *ubuf, size_t count, + loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[25]; /* each line is 12 bytes but 25 for margin of error */ + + for (i = (int) *ppos / 12; i <= SLIM_MAX_REG_ADDR; i++) { + reg_val = wcd9xxx_interface_reg_read(debugCodec, i); + len = snprintf(tmp_buf, sizeof(tmp_buf), + "0x%.3x: 0x%.2x\n", i, reg_val); + if (len < 0) { + pr_err("%s: fail to fill the buffer\n", __func__); + total = -EFAULT; + goto copy_err; + } + + if ((total + len) >= count - 1) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + pr_err("%s: fail to copy reg dump\n", __func__); + total = -EFAULT; + goto copy_err; + } + *ppos += len; + total += len; + } + +copy_err: + return total; +} + +static ssize_t codec_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char lbuf[8]; + char *access_str = file->private_data; + ssize_t ret_cnt; + + if (*ppos < 0 || !count) + return -EINVAL; + + if (!strcmp(access_str, "slimslave_peek")) { + snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data); + ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); + } else if (!strcmp(access_str, "slimslave_reg_dump")) { + ret_cnt = wcd9xxx_slimslave_reg_show(ubuf, count, ppos); + } else { + pr_err("%s: %s not permitted to read\n", __func__, access_str); + ret_cnt = -EPERM; + } + + return ret_cnt; +} + +static void wcd9xxx_set_reset_pin_state(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_pdata *pdata, + bool active) +{ + if (wcd9xxx->wcd_rst_np) { + if (active) + msm_cdc_pinctrl_select_active_state( + wcd9xxx->wcd_rst_np); + else + msm_cdc_pinctrl_select_sleep_state( + wcd9xxx->wcd_rst_np); + + return; + } else if (gpio_is_valid(wcd9xxx->reset_gpio)) { + gpio_direction_output(wcd9xxx->reset_gpio, + (active == true ? 1 : 0)); + } +} + +static int codec_debug_process_cdc_power(char *lbuf) +{ + long int param; + int rc; + struct wcd9xxx_pdata *pdata; + + if (wcd9xxx_get_intf_type() != WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + pr_err("%s: CODEC is not in SLIMBUS mode\n", __func__); + rc = -EPERM; + goto error_intf; + } + + rc = get_parameters(lbuf, ¶m, 1); + + if (likely(!rc)) { + pdata = debugCodec->slim->dev.platform_data; + if (param == 0) { + wcd9xxx_slim_device_down(debugCodec->slim); + msm_cdc_disable_static_supplies(debugCodec->dev, + debugCodec->supplies, + pdata->regulator, + pdata->num_supplies); + wcd9xxx_set_reset_pin_state(debugCodec, pdata, false); + } else if (param == 1) { + msm_cdc_enable_static_supplies(debugCodec->dev, + debugCodec->supplies, + pdata->regulator, + pdata->num_supplies); + usleep_range(1000, 2000); + wcd9xxx_set_reset_pin_state(debugCodec, pdata, false); + usleep_range(1000, 2000); + wcd9xxx_set_reset_pin_state(debugCodec, pdata, true); + usleep_range(1000, 2000); + wcd9xxx_slim_device_up(debugCodec->slim); + } else { + pr_err("%s: invalid command %ld\n", __func__, param); + } + } + +error_intf: + return rc; +} + +static ssize_t codec_debug_write(struct file *filp, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char *access_str = filp->private_data; + char lbuf[32]; + int rc; + long int param[5]; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + + if (!strcmp(access_str, "slimslave_poke")) { + /* write */ + rc = get_parameters(lbuf, param, 2); + if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) && + (rc == 0)) + wcd9xxx_interface_reg_write(debugCodec, param[0], + param[1]); + else + rc = -EINVAL; + } else if (!strcmp(access_str, "slimslave_peek")) { + /* read */ + rc = get_parameters(lbuf, param, 1); + if ((param[0] <= 0x3FF) && (rc == 0)) + read_data = wcd9xxx_interface_reg_read(debugCodec, + param[0]); + else + rc = -EINVAL; + } else if (!strcmp(access_str, "power_state")) { + rc = codec_debug_process_cdc_power(lbuf); + } + + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static const struct file_operations codec_debug_ops = { + .open = codec_debug_open, + .write = codec_debug_write, + .read = codec_debug_read +}; +#endif + +static struct wcd9xxx_i2c *wcd9xxx_i2c_get_device_info(struct wcd9xxx *wcd9xxx, + u16 reg) +{ + u16 mask = 0x0f00; + int value = 0; + struct wcd9xxx_i2c *wcd9xxx_i2c = NULL; + + if (wcd9xxx->type == WCD9335) { + wcd9xxx_i2c = &wcd9xxx_modules[0]; + } else { + value = ((reg & mask) >> 8) & 0x000f; + switch (value) { + case 0: + wcd9xxx_i2c = &wcd9xxx_modules[0]; + break; + case 1: + wcd9xxx_i2c = &wcd9xxx_modules[1]; + break; + case 2: + wcd9xxx_i2c = &wcd9xxx_modules[2]; + break; + case 3: + wcd9xxx_i2c = &wcd9xxx_modules[3]; + break; + + default: + break; + } + } + return wcd9xxx_i2c; +} + +static int wcd9xxx_i2c_write_device(struct wcd9xxx *wcd9xxx, u16 reg, u8 *value, + u32 bytes) +{ + + struct i2c_msg *msg; + int ret = 0; + u8 reg_addr = 0; + u8 *data = NULL; + struct wcd9xxx_i2c *wcd9xxx_i2c; + + wcd9xxx_i2c = wcd9xxx_i2c_get_device_info(wcd9xxx, reg); + if (wcd9xxx_i2c == NULL || wcd9xxx_i2c->client == NULL) { + pr_err("failed to get device info\n"); + return -ENODEV; + } + + data = kzalloc(bytes + 1, GFP_KERNEL); + if (!data) + return -ENOMEM; + + reg_addr = (u8)reg; + msg = &wcd9xxx_i2c->xfer_msg[0]; + msg->addr = wcd9xxx_i2c->client->addr; + msg->len = bytes + 1; + msg->flags = 0; + data[0] = reg; + data[1] = *value; + msg->buf = data; + ret = i2c_transfer(wcd9xxx_i2c->client->adapter, + wcd9xxx_i2c->xfer_msg, 1); + /* Try again if the write fails */ + if (ret != 1) { + ret = i2c_transfer(wcd9xxx_i2c->client->adapter, + wcd9xxx_i2c->xfer_msg, 1); + if (ret != 1) { + pr_err("failed to write the device\n"); + goto fail; + } + } + pr_debug("write success register = %x val = %x\n", reg, data[1]); +fail: + kfree(data); + return ret; +} + + +static int wcd9xxx_i2c_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg, + int bytes, unsigned char *dest) +{ + struct i2c_msg *msg; + int ret = 0; + u8 reg_addr = 0; + struct wcd9xxx_i2c *wcd9xxx_i2c; + u8 i = 0; + + wcd9xxx_i2c = wcd9xxx_i2c_get_device_info(wcd9xxx, reg); + if (wcd9xxx_i2c == NULL || wcd9xxx_i2c->client == NULL) { + pr_err("failed to get device info\n"); + return -ENODEV; + } + for (i = 0; i < bytes; i++) { + reg_addr = (u8)reg++; + msg = &wcd9xxx_i2c->xfer_msg[0]; + msg->addr = wcd9xxx_i2c->client->addr; + msg->len = 1; + msg->flags = 0; + msg->buf = ®_addr; + + msg = &wcd9xxx_i2c->xfer_msg[1]; + msg->addr = wcd9xxx_i2c->client->addr; + msg->len = 1; + msg->flags = I2C_M_RD; + msg->buf = dest++; + ret = i2c_transfer(wcd9xxx_i2c->client->adapter, + wcd9xxx_i2c->xfer_msg, 2); + + /* Try again if read fails first time */ + if (ret != 2) { + ret = i2c_transfer(wcd9xxx_i2c->client->adapter, + wcd9xxx_i2c->xfer_msg, 2); + if (ret != 2) { + pr_err("failed to read wcd9xxx register\n"); + return ret; + } + } + } + return 0; +} + +int wcd9xxx_i2c_read(struct wcd9xxx *wcd9xxx, unsigned short reg, + int bytes, void *dest, bool interface_reg) +{ + return wcd9xxx_i2c_read_device(wcd9xxx, reg, bytes, dest); +} + +int wcd9xxx_i2c_write(struct wcd9xxx *wcd9xxx, unsigned short reg, + int bytes, void *src, bool interface_reg) +{ + return wcd9xxx_i2c_write_device(wcd9xxx, reg, src, bytes); +} + +static int wcd9xxx_i2c_get_client_index(struct i2c_client *client, + int *wcd9xx_index) +{ + int ret = 0; + + switch (client->addr) { + case WCD9XXX_I2C_TOP_SLAVE_ADDR: + *wcd9xx_index = WCD9XXX_I2C_TOP_LEVEL; + break; + case WCD9XXX_ANALOG_I2C_SLAVE_ADDR: + *wcd9xx_index = WCD9XXX_I2C_ANALOG; + break; + case WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR: + *wcd9xx_index = WCD9XXX_I2C_DIGITAL_1; + break; + case WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR: + *wcd9xx_index = WCD9XXX_I2C_DIGITAL_2; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int wcd9xxx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct wcd9xxx *wcd9xxx = NULL; + struct wcd9xxx_pdata *pdata = NULL; + int val = 0; + int ret = 0; + int wcd9xx_index = 0; + struct device *dev; + int intf_type; + const struct of_device_id *of_id; + + intf_type = wcd9xxx_get_intf_type(); + + pr_debug("%s: interface status %d\n", __func__, intf_type); + if (intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n", + __func__); + return -ENODEV; + } else if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index); + if (ret != 0) + dev_err(&client->dev, "%s: I2C set codec I2C\n" + "client failed\n", __func__); + else { + dev_err(&client->dev, "%s:probe for other slaves\n" + "devices of codec I2C slave Addr = %x\n", + __func__, client->addr); + wcd9xxx_modules[wcd9xx_index].client = client; + } + return ret; + } else if (intf_type == WCD9XXX_INTERFACE_TYPE_PROBING) { + dev = &client->dev; + if (client->dev.of_node) { + dev_dbg(&client->dev, "%s:Platform data\n" + "from device tree\n", __func__); + pdata = wcd9xxx_populate_dt_data(&client->dev); + if (!pdata) { + dev_err(&client->dev, + "%s: Fail to obtain pdata from device tree\n", + __func__); + ret = -EINVAL; + goto fail; + } + client->dev.platform_data = pdata; + } else { + dev_dbg(&client->dev, "%s:Platform data from\n" + "board file\n", __func__); + pdata = client->dev.platform_data; + } + wcd9xxx = devm_kzalloc(&client->dev, sizeof(struct wcd9xxx), + GFP_KERNEL); + if (!wcd9xxx) { + ret = -ENOMEM; + goto fail; + } + + if (!pdata) { + dev_dbg(&client->dev, "no platform data?\n"); + ret = -EINVAL; + goto fail; + } + wcd9xxx->type = WCD9XXX; + if (client->dev.of_node) { + of_id = of_match_device(wcd9xxx_of_match, &client->dev); + if (of_id) { + wcd9xxx->type = *((int *)of_id->data); + dev_info(&client->dev, "%s: codec type is %d\n", + __func__, wcd9xxx->type); + } + } else { + dev_info(&client->dev, "%s: dev.of_node is NULL, default to WCD9XXX\n", + __func__); + wcd9xxx->type = WCD9XXX; + } + wcd9xxx->regmap = wcd9xxx_regmap_init(&client->dev, + &wcd9xxx_i2c_base_regmap_config); + if (IS_ERR(wcd9xxx->regmap)) { + ret = PTR_ERR(wcd9xxx->regmap); + dev_err(&client->dev, "%s: Failed to allocate register map: %d\n", + __func__, ret); + goto err_codec; + } + wcd9xxx->reset_gpio = pdata->reset_gpio; + wcd9xxx->wcd_rst_np = pdata->wcd_rst_np; + + if (!wcd9xxx->wcd_rst_np) { + pdata->use_pinctrl = false; + dev_err(&client->dev, "%s: pinctrl not used for rst_n\n", + __func__); + goto err_codec; + } + + if (i2c_check_functionality(client->adapter, + I2C_FUNC_I2C) == 0) { + dev_dbg(&client->dev, "can't talk I2C?\n"); + ret = -EIO; + goto fail; + } + dev_set_drvdata(&client->dev, wcd9xxx); + wcd9xxx->dev = &client->dev; + wcd9xxx->dev_up = true; + if (client->dev.of_node) + wcd9xxx->mclk_rate = pdata->mclk_rate; + + wcd9xxx->num_of_supplies = pdata->num_supplies; + ret = msm_cdc_init_supplies_v2(wcd9xxx->dev, &wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies, + pdata->vote_regulator_on_demand); + if (!wcd9xxx->supplies) { + dev_err(wcd9xxx->dev, "%s: Cannot init wcd supplies\n", + __func__); + goto err_codec; + } + ret = msm_cdc_enable_static_supplies(wcd9xxx->dev, + wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(wcd9xxx->dev, "%s: wcd static supply enable failed!\n", + __func__); + goto err_codec; + } + /* For WCD9335, it takes about 600us for the Vout_A and + * Vout_D to be ready after BUCK_SIDO is powered up\ + * SYS_RST_N shouldn't be pulled high during this time + */ + if (wcd9xxx->type == WCD9335) + usleep_range(600, 650); + else + usleep_range(5, 10); + + ret = wcd9xxx_reset(wcd9xxx->dev); + if (ret) { + pr_err("%s: Resetting Codec failed\n", __func__); + goto err_supplies; + } + + ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index); + if (ret != 0) { + pr_err("%s:Set codec I2C client failed\n", __func__); + goto err_supplies; + } + + wcd9xxx_modules[wcd9xx_index].client = client; + wcd9xxx->read_dev = wcd9xxx_i2c_read; + wcd9xxx->write_dev = wcd9xxx_i2c_write; + if (!wcd9xxx->dev->of_node) + wcd9xxx_assign_irq(&wcd9xxx->core_res, + pdata->irq, pdata->irq_base); + + ret = wcd9xxx_device_init(wcd9xxx); + if (ret) { + pr_err("%s: error, initializing device failed (%d)\n", + __func__, ret); + goto err_device_init; + } + + ret = wcd9xxx_i2c_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, + &val, 0); + if (ret < 0) + pr_err("%s: failed to read the wcd9xxx status (%d)\n", + __func__, ret); + if (val != wcd9xxx->codec_type->i2c_chip_status) + pr_err("%s: unknown chip status 0x%x\n", __func__, val); + + wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C); + + return ret; + } + + pr_err("%s: I2C probe in wrong state\n", __func__); + + +err_device_init: + wcd9xxx_reset_low(wcd9xxx->dev); +err_supplies: + msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies); + pdata->regulator = NULL; + pdata->num_supplies = 0; +err_codec: + devm_kfree(&client->dev, wcd9xxx); + dev_set_drvdata(&client->dev, NULL); +fail: + return ret; +} + +static int wcd9xxx_i2c_remove(struct i2c_client *client) +{ + struct wcd9xxx *wcd9xxx; + struct wcd9xxx_pdata *pdata = client->dev.platform_data; + + wcd9xxx = dev_get_drvdata(&client->dev); + msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies); + wcd9xxx_device_exit(wcd9xxx); + dev_set_drvdata(&client->dev, NULL); + return 0; +} + +static int wcd9xxx_dt_parse_slim_interface_dev_info(struct device *dev, + struct slim_device *slim_ifd) +{ + int ret = 0; + struct property *prop; + + ret = of_property_read_string(dev->of_node, "qcom,cdc-slim-ifd", + &slim_ifd->name); + if (ret) { + dev_err(dev, "Looking up %s property in node %s failed", + "qcom,cdc-slim-ifd-dev", dev->of_node->full_name); + return -ENODEV; + } + prop = of_find_property(dev->of_node, + "qcom,cdc-slim-ifd-elemental-addr", NULL); + if (!prop) { + dev_err(dev, "Looking up %s property in node %s failed", + "qcom,cdc-slim-ifd-elemental-addr", + dev->of_node->full_name); + return -ENODEV; + } else if (prop->length != 6) { + dev_err(dev, "invalid codec slim ifd addr. addr length = %d\n", + prop->length); + return -ENODEV; + } + memcpy(slim_ifd->e_addr, prop->value, 6); + + return 0; +} + +static int wcd9xxx_slim_get_laddr(struct slim_device *sb, + const u8 *e_addr, u8 e_len, u8 *laddr) +{ + int ret; + const unsigned long timeout = jiffies + + msecs_to_jiffies(SLIMBUS_PRESENT_TIMEOUT); + + do { + ret = slim_get_logical_addr(sb, e_addr, e_len, laddr); + if (!ret) + break; + /* Give SLIMBUS time to report present and be ready. */ + usleep_range(1000, 1100); + pr_debug_ratelimited("%s: retyring get logical addr\n", + __func__); + } while time_before(jiffies, timeout); + + return ret; +} + +static int wcd9xxx_slim_probe(struct slim_device *slim) +{ + struct wcd9xxx *wcd9xxx; + struct wcd9xxx_pdata *pdata; + const struct slim_device_id *device_id; + int ret = 0; + int intf_type; + + if (!slim) + return -EINVAL; + + intf_type = wcd9xxx_get_intf_type(); + + wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx), + GFP_KERNEL); + if (!wcd9xxx) + return -ENOMEM; + + if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n", + __func__); + ret = -ENODEV; + goto err; + } + if (slim->dev.of_node) { + dev_dbg(&slim->dev, "Platform data from device tree\n"); + pdata = wcd9xxx_populate_dt_data(&slim->dev); + if (!pdata) { + dev_err(&slim->dev, + "%s: Fail to obtain pdata from device tree\n", + __func__); + ret = -EINVAL; + goto err; + } + + ret = wcd9xxx_dt_parse_slim_interface_dev_info(&slim->dev, + &pdata->slimbus_slave_device); + if (ret) { + dev_err(&slim->dev, "Error, parsing slim interface\n"); + devm_kfree(&slim->dev, pdata); + ret = -EINVAL; + goto err; + } + slim->dev.platform_data = pdata; + + } else { + dev_info(&slim->dev, "Platform data from board file\n"); + pdata = slim->dev.platform_data; + } + + if (!pdata) { + dev_err(&slim->dev, "Error, no platform data\n"); + ret = -EINVAL; + goto err; + } + + if (!slim->ctrl) { + dev_err(&slim->dev, "%s: Error, no SLIMBUS control data\n", + __func__); + ret = -EINVAL; + goto err_codec; + } + + if (pdata->has_buck_vsel_gpio) + msm_cdc_pinctrl_select_active_state(pdata->buck_vsel_ctl_np); + + if (pdata->has_micb_supply_en_gpio) + msm_cdc_pinctrl_select_active_state(pdata->micb_en_ctl); + + device_id = slim_get_device_id(slim); + if (!device_id) { + dev_err(&slim->dev, "%s: Error, no device id\n", __func__); + ret = -EINVAL; + goto err; + } + + wcd9xxx->type = device_id->driver_data; + dev_info(&slim->dev, "%s: probing for wcd type: %d, name: %s\n", + __func__, wcd9xxx->type, device_id->name); + + /* wcd9xxx members init */ + wcd9xxx->multi_reg_write = wcd9xxx_slim_multi_reg_write; + wcd9xxx->slim = slim; + slim_set_clientdata(slim, wcd9xxx); + wcd9xxx->reset_gpio = pdata->reset_gpio; + wcd9xxx->dev = &slim->dev; + wcd9xxx->mclk_rate = pdata->mclk_rate; + wcd9xxx->dev_up = true; + wcd9xxx->wcd_rst_np = pdata->wcd_rst_np; + + wcd9xxx->regmap = wcd9xxx_regmap_init(&slim->dev, + &wcd9xxx_base_regmap_config); + if (IS_ERR(wcd9xxx->regmap)) { + ret = PTR_ERR(wcd9xxx->regmap); + dev_err(&slim->dev, "%s: Failed to allocate register map: %d\n", + __func__, ret); + goto err_codec; + } + + if (!wcd9xxx->wcd_rst_np) { + pdata->use_pinctrl = false; + dev_err(&slim->dev, "%s: pinctrl not used for rst_n\n", + __func__); + goto err_codec; + } + + wcd9xxx->num_of_supplies = pdata->num_supplies; + ret = msm_cdc_init_supplies_v2(&slim->dev, &wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies, + pdata->vote_regulator_on_demand); + if (!wcd9xxx->supplies) { + dev_err(wcd9xxx->dev, "%s: Cannot init wcd supplies\n", + __func__); + goto err_codec; + } + ret = msm_cdc_enable_static_supplies(wcd9xxx->dev, + wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies); + if (ret) { + dev_err(wcd9xxx->dev, "%s: wcd static supply enable failed!\n", + __func__); + goto err_codec; + } + + /* + * For WCD9335, it takes about 600us for the Vout_A and + * Vout_D to be ready after BUCK_SIDO is powered up. + * SYS_RST_N shouldn't be pulled high during this time + */ + if (wcd9xxx->type == WCD9335 || wcd9xxx->type == WCD934X) + usleep_range(600, 650); + else + usleep_range(5, 10); + + ret = wcd9xxx_reset(&slim->dev); + if (ret) { + dev_err(&slim->dev, "%s: Resetting Codec failed\n", __func__); + goto err_supplies; + } + + ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim, wcd9xxx->slim->e_addr, + ARRAY_SIZE(wcd9xxx->slim->e_addr), + &wcd9xxx->slim->laddr); + if (ret) { + dev_err(&slim->dev, "%s: failed to get slimbus %s logical address: %d\n", + __func__, wcd9xxx->slim->name, ret); + goto err_reset; + } + wcd9xxx->read_dev = wcd9xxx_slim_read_device; + wcd9xxx->write_dev = wcd9xxx_slim_write_device; + wcd9xxx_pgd_la = wcd9xxx->slim->laddr; + wcd9xxx->slim_slave = &pdata->slimbus_slave_device; + if (!wcd9xxx->dev->of_node) + wcd9xxx_assign_irq(&wcd9xxx->core_res, + pdata->irq, pdata->irq_base); + + ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave); + if (ret) { + dev_err(&slim->dev, "%s: error, adding SLIMBUS device failed\n", + __func__); + goto err_reset; + } + + ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim_slave, + wcd9xxx->slim_slave->e_addr, + ARRAY_SIZE(wcd9xxx->slim_slave->e_addr), + &wcd9xxx->slim_slave->laddr); + if (ret) { + dev_err(&slim->dev, "%s: failed to get slimbus %s logical address: %d\n", + __func__, wcd9xxx->slim->name, ret); + goto err_slim_add; + } + wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr; + wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_SLIMBUS); + + ret = wcd9xxx_device_init(wcd9xxx); + if (ret) { + dev_err(&slim->dev, "%s: error, initializing device failed (%d)\n", + __func__, ret); + goto err_slim_add; + } +#ifdef CONFIG_DEBUG_FS + debugCodec = wcd9xxx; + + debugfs_wcd9xxx_dent = debugfs_create_dir + ("wcd9xxx_core", 0); + if (!IS_ERR(debugfs_wcd9xxx_dent)) { + debugfs_peek = debugfs_create_file("slimslave_peek", + S_IFREG | 0444, debugfs_wcd9xxx_dent, + (void *) "slimslave_peek", &codec_debug_ops); + + debugfs_poke = debugfs_create_file("slimslave_poke", + S_IFREG | 0444, debugfs_wcd9xxx_dent, + (void *) "slimslave_poke", &codec_debug_ops); + + debugfs_power_state = debugfs_create_file("power_state", + S_IFREG | 0444, debugfs_wcd9xxx_dent, + (void *) "power_state", &codec_debug_ops); + + debugfs_reg_dump = debugfs_create_file("slimslave_reg_dump", + S_IFREG | 0444, debugfs_wcd9xxx_dent, + (void *) "slimslave_reg_dump", &codec_debug_ops); + } +#endif + + return ret; + +err_slim_add: + slim_remove_device(wcd9xxx->slim_slave); +err_reset: + wcd9xxx_reset_low(wcd9xxx->dev); +err_supplies: + msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies); +err_codec: + slim_set_clientdata(slim, NULL); +err: + devm_kfree(&slim->dev, wcd9xxx); + return ret; +} +static int wcd9xxx_slim_remove(struct slim_device *pdev) +{ + struct wcd9xxx *wcd9xxx; + struct wcd9xxx_pdata *pdata = pdev->dev.platform_data; + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(debugfs_wcd9xxx_dent); +#endif + wcd9xxx = slim_get_devicedata(pdev); + wcd9xxx_deinit_slimslave(wcd9xxx); + slim_remove_device(wcd9xxx->slim_slave); + msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies, + pdata->regulator, + pdata->num_supplies); + wcd9xxx_device_exit(wcd9xxx); + slim_set_clientdata(pdev, NULL); + return 0; +} + +static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx) +{ + int ret = 0; + struct wcd9xxx_core_resource *wcd9xxx_res = &wcd9xxx->core_res; + + dev_info(wcd9xxx->dev, "%s: codec bring up\n", __func__); + wcd9xxx_bringup(wcd9xxx->dev); + ret = wcd9xxx_irq_init(wcd9xxx_res); + if (ret) { + pr_err("%s: wcd9xx_irq_init failed : %d\n", __func__, ret); + } else { + if (wcd9xxx->post_reset) + ret = wcd9xxx->post_reset(wcd9xxx); + } + return ret; +} + +static int wcd9xxx_slim_device_reset(struct slim_device *sldev) +{ + int ret; + struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev); + + if (!wcd9xxx) { + pr_err("%s: wcd9xxx is NULL\n", __func__); + return -EINVAL; + } + + dev_info(wcd9xxx->dev, "%s: device reset, dev_up = %d\n", + __func__, wcd9xxx->dev_up); + if (wcd9xxx->dev_up) + return 0; + + mutex_lock(&wcd9xxx->reset_lock); + ret = wcd9xxx_reset(wcd9xxx->dev); + if (ret) + dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__); + mutex_unlock(&wcd9xxx->reset_lock); + + return ret; +} + +static int wcd9xxx_slim_device_up(struct slim_device *sldev) +{ + struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev); + int ret = 0; + + if (!wcd9xxx) { + pr_err("%s: wcd9xxx is NULL\n", __func__); + return -EINVAL; + } + dev_info(wcd9xxx->dev, "%s: slim device up, dev_up = %d\n", + __func__, wcd9xxx->dev_up); + if (wcd9xxx->dev_up) + return 0; + + wcd9xxx->dev_up = true; + + mutex_lock(&wcd9xxx->reset_lock); + ret = wcd9xxx_device_up(wcd9xxx); + mutex_unlock(&wcd9xxx->reset_lock); + + return ret; +} + +static int wcd9xxx_slim_device_down(struct slim_device *sldev) +{ + struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev); + + if (!wcd9xxx) { + pr_err("%s: wcd9xxx is NULL\n", __func__); + return -EINVAL; + } + + dev_info(wcd9xxx->dev, "%s: device down, dev_up = %d\n", + __func__, wcd9xxx->dev_up); + if (!wcd9xxx->dev_up) + return 0; + + wcd9xxx->dev_up = false; + + mutex_lock(&wcd9xxx->reset_lock); + if (wcd9xxx->dev_down) + wcd9xxx->dev_down(wcd9xxx); + wcd9xxx_irq_exit(&wcd9xxx->core_res); + wcd9xxx_reset_low(wcd9xxx->dev); + mutex_unlock(&wcd9xxx->reset_lock); + + return 0; +} + +static int wcd9xxx_slim_resume(struct slim_device *sldev) +{ + struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev); + + return wcd9xxx_core_res_resume(&wcd9xxx->core_res); +} + +static int wcd9xxx_i2c_resume(struct device *dev) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev); + + if (wcd9xxx) + return wcd9xxx_core_res_resume(&wcd9xxx->core_res); + else + return 0; +} + +static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg) +{ + struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev); + + return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg); +} + +static int wcd9xxx_i2c_suspend(struct device *dev) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev); + pm_message_t pmesg = {0}; + + if (wcd9xxx) + return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg); + else + return 0; +} + +static const struct slim_device_id wcd_slim_device_id[] = { + {"sitar-slim", 0}, + {"sitar1p1-slim", 0}, + {"tabla-slim", 0}, + {"tabla2x-slim", 0}, + {"taiko-slim-pgd", 0}, + {"tapan-slim-pgd", 0}, + {"tomtom-slim-pgd", WCD9330}, + {"tasha-slim-pgd", WCD9335}, + {"tavil-slim-pgd", WCD934X}, + {} +}; + +static struct slim_driver wcd_slim_driver = { + .driver = { + .name = "wcd-slim", + .owner = THIS_MODULE, + }, + .probe = wcd9xxx_slim_probe, + .remove = wcd9xxx_slim_remove, + .id_table = wcd_slim_device_id, + .resume = wcd9xxx_slim_resume, + .suspend = wcd9xxx_slim_suspend, + .device_up = wcd9xxx_slim_device_up, + .reset_device = wcd9xxx_slim_device_reset, + .device_down = wcd9xxx_slim_device_down, +}; + +static struct i2c_device_id wcd9xxx_id_table[] = { + {"wcd9xxx-i2c", WCD9XXX_I2C_TOP_LEVEL}, + {"wcd9xxx-i2c", WCD9XXX_I2C_ANALOG}, + {"wcd9xxx-i2c", WCD9XXX_I2C_DIGITAL_1}, + {"wcd9xxx-i2c", WCD9XXX_I2C_DIGITAL_2}, + {} +}; + +static struct i2c_device_id tasha_id_table[] = { + {"tasha-i2c-pgd", WCD9XXX_I2C_TOP_LEVEL}, + {} +}; + +static struct i2c_device_id tavil_id_table[] = { + {"tavil-i2c", WCD9XXX_I2C_TOP_LEVEL}, + {} +}; + +static struct i2c_device_id tabla_id_table[] = { + {"tabla top level", WCD9XXX_I2C_TOP_LEVEL}, + {"tabla analog", WCD9XXX_I2C_ANALOG}, + {"tabla digital1", WCD9XXX_I2C_DIGITAL_1}, + {"tabla digital2", WCD9XXX_I2C_DIGITAL_2}, + {} +}; +MODULE_DEVICE_TABLE(i2c, tabla_id_table); + +static const struct dev_pm_ops wcd9xxx_i2c_pm_ops = { + .suspend = wcd9xxx_i2c_suspend, + .resume = wcd9xxx_i2c_resume, +}; + +static struct i2c_driver tabla_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tabla-i2c-core", + .pm = &wcd9xxx_i2c_pm_ops, + }, + .id_table = tabla_id_table, + .probe = wcd9xxx_i2c_probe, + .remove = wcd9xxx_i2c_remove, +}; + +static struct i2c_driver wcd9xxx_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "wcd9xxx-i2c-core", + .pm = &wcd9xxx_i2c_pm_ops, + }, + .id_table = wcd9xxx_id_table, + .probe = wcd9xxx_i2c_probe, + .remove = wcd9xxx_i2c_remove, +}; + +static struct i2c_driver wcd9335_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tasha-i2c-core", + .pm = &wcd9xxx_i2c_pm_ops, + }, + .id_table = tasha_id_table, + .probe = wcd9xxx_i2c_probe, + .remove = wcd9xxx_i2c_remove, +}; + +static struct i2c_driver wcd934x_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tavil-i2c-core", + .pm = &wcd9xxx_i2c_pm_ops, + }, + .id_table = tavil_id_table, + .probe = wcd9xxx_i2c_probe, + .remove = wcd9xxx_i2c_remove, +}; + +int wcd9xxx_init(void) +{ + int ret[NUM_WCD9XXX_REG_RET] = {0}; + int i = 0; + + wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING); + + ret[0] = i2c_add_driver(&tabla_i2c_driver); + if (ret[0]) + pr_err("%s: Failed to add the tabla2x I2C driver: %d\n", + __func__, ret[0]); + + ret[1] = i2c_add_driver(&wcd9xxx_i2c_driver); + if (ret[1]) + pr_err("%s: Failed to add the wcd9xxx I2C driver: %d\n", + __func__, ret[1]); + + ret[2] = i2c_add_driver(&wcd9335_i2c_driver); + if (ret[2]) + pr_err("%s: Failed to add the wcd9335 I2C driver: %d\n", + __func__, ret[2]); + + ret[3] = slim_driver_register(&wcd_slim_driver); + if (ret[3]) + pr_err("%s: Failed to register wcd SB driver: %d\n", + __func__, ret[3]); + + ret[4] = i2c_add_driver(&wcd934x_i2c_driver); + if (ret[4]) + pr_err("%s: Failed to add the wcd934x I2C driver: %d\n", + __func__, ret[4]); + + for (i = 0; i < NUM_WCD9XXX_REG_RET; i++) { + if (ret[i]) + return ret[i]; + } + + return 0; +} + +void wcd9xxx_exit(void) +{ + wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING); + + i2c_del_driver(&tabla_i2c_driver); + i2c_del_driver(&wcd9xxx_i2c_driver); + i2c_del_driver(&wcd9335_i2c_driver); + i2c_del_driver(&wcd934x_i2c_driver); + slim_driver_unregister(&wcd_slim_driver); +} + +MODULE_DESCRIPTION("Codec core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-irq.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-irq.c new file mode 100644 index 0000000000..50615fc272 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-irq.c @@ -0,0 +1,894 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE)) +#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE) + +#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 100 + +#ifndef NO_IRQ +#define NO_IRQ (-1) +#endif + +#ifdef CONFIG_OF +struct wcd9xxx_irq_drv_data { + struct irq_domain *domain; + int irq; +}; +#endif + +static int virq_to_phyirq( + struct wcd9xxx_core_resource *wcd9xxx_res, int virq); +static int phyirq_to_virq( + struct wcd9xxx_core_resource *wcd9xxx_res, int irq); +static unsigned int wcd9xxx_irq_get_upstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res); +static void wcd9xxx_irq_put_downstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res); +static void wcd9xxx_irq_put_upstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res); +static int wcd9xxx_map_irq( + struct wcd9xxx_core_resource *wcd9xxx_res, int irq); + +static void wcd9xxx_irq_lock(struct irq_data *data) +{ + struct wcd9xxx_core_resource *wcd9xxx_res = + irq_data_get_irq_chip_data(data); + mutex_lock(&wcd9xxx_res->irq_lock); +} + +static void wcd9xxx_irq_sync_unlock(struct irq_data *data) +{ + struct wcd9xxx_core_resource *wcd9xxx_res = + irq_data_get_irq_chip_data(data); + int i; + + if ((ARRAY_SIZE(wcd9xxx_res->irq_masks_cur) > + WCD9XXX_MAX_IRQ_REGS) || + (ARRAY_SIZE(wcd9xxx_res->irq_masks_cache) > + WCD9XXX_MAX_IRQ_REGS)) { + pr_err("%s: Array Size out of bound\n", __func__); + return; + } + if (!wcd9xxx_res->wcd_core_regmap) { + pr_err("%s: Codec core regmap not defined\n", + __func__); + return; + } + + for (i = 0; i < ARRAY_SIZE(wcd9xxx_res->irq_masks_cur); i++) { + /* If there's been a change in the mask write it back + * to the hardware. + */ + if (wcd9xxx_res->irq_masks_cur[i] != + wcd9xxx_res->irq_masks_cache[i]) { + + wcd9xxx_res->irq_masks_cache[i] = + wcd9xxx_res->irq_masks_cur[i]; + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i, + wcd9xxx_res->irq_masks_cur[i]); + } + } + + mutex_unlock(&wcd9xxx_res->irq_lock); +} + +static void wcd9xxx_irq_enable(struct irq_data *data) +{ + struct wcd9xxx_core_resource *wcd9xxx_res = + irq_data_get_irq_chip_data(data); + int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq); + int byte = BIT_BYTE(wcd9xxx_irq); + int size = ARRAY_SIZE(wcd9xxx_res->irq_masks_cur); + + if ((byte < size) && (byte >= 0)) { + wcd9xxx_res->irq_masks_cur[byte] &= + ~(BYTE_BIT_MASK(wcd9xxx_irq)); + } else { + pr_err("%s: Array size is %d but index is %d: Out of range\n", + __func__, size, byte); + } +} + +static void wcd9xxx_irq_disable(struct irq_data *data) +{ + struct wcd9xxx_core_resource *wcd9xxx_res = + irq_data_get_irq_chip_data(data); + int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq); + int byte = BIT_BYTE(wcd9xxx_irq); + int size = ARRAY_SIZE(wcd9xxx_res->irq_masks_cur); + + if ((byte < size) && (byte >= 0)) { + wcd9xxx_res->irq_masks_cur[byte] + |= BYTE_BIT_MASK(wcd9xxx_irq); + } else { + pr_err("%s: Array size is %d but index is %d: Out of range\n", + __func__, size, byte); + } +} + +static void wcd9xxx_irq_ack(struct irq_data *data) +{ + int wcd9xxx_irq = 0; + struct wcd9xxx_core_resource *wcd9xxx_res = + irq_data_get_irq_chip_data(data); + + if (wcd9xxx_res == NULL) { + pr_err("%s: wcd9xxx_res is NULL\n", __func__); + return; + } + wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq); + pr_debug("%s: IRQ_ACK called for WCD9XXX IRQ: %d\n", + __func__, wcd9xxx_irq); +} + +static void wcd9xxx_irq_mask(struct irq_data *d) +{ + /* do nothing but required as linux calls irq_mask without NULL check */ +} + +static struct irq_chip wcd9xxx_irq_chip = { + .name = "wcd9xxx", + .irq_bus_lock = wcd9xxx_irq_lock, + .irq_bus_sync_unlock = wcd9xxx_irq_sync_unlock, + .irq_disable = wcd9xxx_irq_disable, + .irq_enable = wcd9xxx_irq_enable, + .irq_mask = wcd9xxx_irq_mask, + .irq_ack = wcd9xxx_irq_ack, +}; + +bool wcd9xxx_lock_sleep( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + enum wcd9xxx_pm_state os; + + /* + * wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread + * and its subroutines only motly. + * but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and + * It can race with wcd9xxx_irq_thread. + * So need to embrace wlock_holders with mutex. + * + * If system didn't resume, we can simply return false so codec driver's + * IRQ handler can return without handling IRQ. + * As interrupt line is still active, codec will have another IRQ to + * retry shortly. + */ + mutex_lock(&wcd9xxx_res->pm_lock); + if (wcd9xxx_res->wlock_holders++ == 0) { + pr_debug("%s: holding wake lock\n", __func__); + pm_qos_update_request(&wcd9xxx_res->pm_qos_req, + msm_cpuidle_get_deep_idle_latency()); + pm_stay_awake(wcd9xxx_res->dev); + } + mutex_unlock(&wcd9xxx_res->pm_lock); + + if (!wait_event_timeout(wcd9xxx_res->pm_wq, + ((os = wcd9xxx_pm_cmpxchg(wcd9xxx_res, + WCD9XXX_PM_SLEEPABLE, + WCD9XXX_PM_AWAKE)) == + WCD9XXX_PM_SLEEPABLE || + (os == WCD9XXX_PM_AWAKE)), + msecs_to_jiffies( + WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) { + pr_warn("%s: system didn't resume within %dms, s %d, w %d\n", + __func__, + WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx_res->pm_state, + wcd9xxx_res->wlock_holders); + wcd9xxx_unlock_sleep(wcd9xxx_res); + return false; + } + wake_up_all(&wcd9xxx_res->pm_wq); + return true; +} +EXPORT_SYMBOL(wcd9xxx_lock_sleep); + +void wcd9xxx_unlock_sleep( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + mutex_lock(&wcd9xxx_res->pm_lock); + if (--wcd9xxx_res->wlock_holders == 0) { + pr_debug("%s: releasing wake lock pm_state %d -> %d\n", + __func__, wcd9xxx_res->pm_state, WCD9XXX_PM_SLEEPABLE); + /* + * if wcd9xxx_lock_sleep failed, pm_state would be still + * WCD9XXX_PM_ASLEEP, don't overwrite + */ + if (likely(wcd9xxx_res->pm_state == WCD9XXX_PM_AWAKE)) + wcd9xxx_res->pm_state = WCD9XXX_PM_SLEEPABLE; + pm_qos_update_request(&wcd9xxx_res->pm_qos_req, + PM_QOS_DEFAULT_VALUE); + pm_relax(wcd9xxx_res->dev); + } + mutex_unlock(&wcd9xxx_res->pm_lock); + wake_up_all(&wcd9xxx_res->pm_wq); +} +EXPORT_SYMBOL(wcd9xxx_unlock_sleep); + +void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *wcd9xxx_res) +{ + mutex_lock(&wcd9xxx_res->nested_irq_lock); +} + +void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *wcd9xxx_res) +{ + mutex_unlock(&wcd9xxx_res->nested_irq_lock); +} + + +static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res, + struct intr_data *irqdata) +{ + int irqbit = irqdata->intr_num; + + if (!wcd9xxx_res->wcd_core_regmap) { + pr_err("%s: codec core regmap not defined\n", + __func__); + return; + } + + if (irqdata->clear_first) { + wcd9xxx_nested_irq_lock(wcd9xxx_res); + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] + + BIT_BYTE(irqbit), + BYTE_BIT_MASK(irqbit)); + + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT], + 0x02); + handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit)); + wcd9xxx_nested_irq_unlock(wcd9xxx_res); + } else { + wcd9xxx_nested_irq_lock(wcd9xxx_res); + handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit)); + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] + + BIT_BYTE(irqbit), + BYTE_BIT_MASK(irqbit)); + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT], + 0x02); + + wcd9xxx_nested_irq_unlock(wcd9xxx_res); + } +} + +static irqreturn_t wcd9xxx_irq_thread(int irq, void *data) +{ + int ret; + int i; + struct intr_data irqdata; + char linebuf[128]; + static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1); + struct wcd9xxx_core_resource *wcd9xxx_res = data; + int num_irq_regs = wcd9xxx_res->num_irq_regs; + struct wcd9xxx *wcd9xxx; + u8 status[4], status1[4] = {0}, unmask_status[4] = {0}; + + if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) { + dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n"); + return IRQ_NONE; + } + + if (!wcd9xxx_res->wcd_core_regmap) { + dev_err(wcd9xxx_res->dev, + "%s: Codec core regmap not supplied\n", + __func__); + goto err_disable_irq; + } + + wcd9xxx = (struct wcd9xxx *)wcd9xxx_res->parent; + if (!wcd9xxx) { + dev_err(wcd9xxx_res->dev, + "%s: Codec core not supplied\n", __func__); + goto err_disable_irq; + } + + if (!wcd9xxx->dev_up) { + dev_info_ratelimited(wcd9xxx_res->dev, "wcd9xxx dev not up\n"); + /* + * sleep to not block the core when device is + * not up (slimbus will not be available) to + * process interrupts. + */ + msleep(10); + } + + memset(status, 0, sizeof(status)); + ret = regmap_bulk_read(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_STATUS_BASE], + status, num_irq_regs); + + if (ret < 0) { + dev_err(wcd9xxx_res->dev, + "Failed to read interrupt status: %d\n", ret); + goto err_disable_irq; + } + /* + * If status is 0 return without clearing. + * status contains: HW status - masked interrupts + * status1 contains: unhandled interrupts - masked interrupts + * unmasked_status contains: unhandled interrupts + */ + if (unlikely(!memcmp(status, status1, sizeof(status)))) { + pr_debug("%s: status is 0\n", __func__); + wcd9xxx_unlock_sleep(wcd9xxx_res); + return IRQ_HANDLED; + } + + /* + * Copy status to unmask_status before masking, otherwise SW may miss + * to clear masked interrupt in corner case. + */ + memcpy(unmask_status, status, sizeof(unmask_status)); + + /* Apply masking */ + for (i = 0; i < num_irq_regs; i++) + status[i] &= ~wcd9xxx_res->irq_masks_cur[i]; + + memcpy(status1, status, sizeof(status1)); + + /* Find out which interrupt was triggered and call that interrupt's + * handler function + * + * Since codec has only one hardware irq line which is shared by + * codec's different internal interrupts, so it's possible master irq + * handler dispatches multiple nested irq handlers after breaking + * order. Dispatch interrupts in the order that is maintained by + * the interrupt table. + */ + for (i = 0; i < wcd9xxx_res->intr_table_size; i++) { + irqdata = wcd9xxx_res->intr_table[i]; + if (status[BIT_BYTE(irqdata.intr_num)] & + BYTE_BIT_MASK(irqdata.intr_num)) { + wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata); + status1[BIT_BYTE(irqdata.intr_num)] &= + ~BYTE_BIT_MASK(irqdata.intr_num); + unmask_status[BIT_BYTE(irqdata.intr_num)] &= + ~BYTE_BIT_MASK(irqdata.intr_num); + } + } + + /* + * As a failsafe if unhandled irq is found, clear it to prevent + * interrupt storm. + * Note that we can say there was an unhandled irq only when no irq + * handled by nested irq handler since Taiko supports qdsp as irqs' + * destination for few irqs. Therefore driver shouldn't clear pending + * irqs when few handled while few others not. + */ + if (unlikely(!memcmp(status, status1, sizeof(status)))) { + if (__ratelimit(&ratelimit)) { + pr_warn("%s: Unhandled irq found\n", __func__); + hex_dump_to_buffer(status, sizeof(status), 16, 1, + linebuf, sizeof(linebuf), false); + pr_warn("%s: status0 : %s\n", __func__, linebuf); + hex_dump_to_buffer(status1, sizeof(status1), 16, 1, + linebuf, sizeof(linebuf), false); + pr_warn("%s: status1 : %s\n", __func__, linebuf); + } + /* + * unmask_status contains unhandled interrupts, hence clear all + * unhandled interrupts. + */ + ret = regmap_bulk_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE], + unmask_status, num_irq_regs); + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT], + 0x02); + } + wcd9xxx_unlock_sleep(wcd9xxx_res); + + return IRQ_HANDLED; + +err_disable_irq: + dev_err(wcd9xxx_res->dev, + "Disable irq %d\n", wcd9xxx_res->irq); + + disable_irq_wake(wcd9xxx_res->irq); + disable_irq_nosync(wcd9xxx_res->irq); + wcd9xxx_unlock_sleep(wcd9xxx_res); + return IRQ_NONE; +} + +/** + * wcd9xxx_free_irq + * + * @wcd9xxx_res: pointer to core resource + * irq: irq number + * @data: data pointer + * + */ +void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res, + int irq, void *data) +{ + free_irq(phyirq_to_virq(wcd9xxx_res, irq), data); +} +EXPORT_SYMBOL(wcd9xxx_free_irq); + +/** + * wcd9xxx_enable_irq + * + * @wcd9xxx_res: pointer to core resource + * irq: irq number + * + */ +void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq) +{ + if (wcd9xxx_res->irq) + enable_irq(phyirq_to_virq(wcd9xxx_res, irq)); +} +EXPORT_SYMBOL(wcd9xxx_enable_irq); + +/** + * wcd9xxx_disable_irq + * + * @wcd9xxx_res: pointer to core resource + * irq: irq number + * + */ +void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq) +{ + if (wcd9xxx_res->irq) + disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq)); +} +EXPORT_SYMBOL(wcd9xxx_disable_irq); + +/** + * wcd9xxx_disable_irq_sync + * + * @wcd9xxx_res: pointer to core resource + * irq: irq number + * + */ +void wcd9xxx_disable_irq_sync( + struct wcd9xxx_core_resource *wcd9xxx_res, int irq) +{ + if (wcd9xxx_res->irq) + disable_irq(phyirq_to_virq(wcd9xxx_res, irq)); +} +EXPORT_SYMBOL(wcd9xxx_disable_irq_sync); + +static int wcd9xxx_irq_setup_downstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + int irq, virq, ret; + + pr_debug("%s: enter\n", __func__); + + for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) { + /* Map OF irq */ + virq = wcd9xxx_map_irq(wcd9xxx_res, irq); + pr_debug("%s: irq %d -> %d\n", __func__, irq, virq); + if (virq == NO_IRQ) { + pr_err("%s, No interrupt specifier for irq %d\n", + __func__, irq); + return NO_IRQ; + } + + ret = irq_set_chip_data(virq, wcd9xxx_res); + if (ret) { + pr_err("%s: Failed to configure irq %d (%d)\n", + __func__, irq, ret); + return ret; + } + + if (wcd9xxx_res->irq_level_high[irq]) + irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip, + handle_level_irq); + else + irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip, + handle_edge_irq); + + irq_set_nested_thread(virq, 1); + } + + pr_debug("%s: leave\n", __func__); + + return 0; +} + +/** + * wcd9xxx_irq_init + * + * @wcd9xxx_res: pointer to core resource + * + * Returns 0 on success, appropriate error code otherwise + */ +int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res) +{ + int i, ret; + u8 *irq_level = NULL; + struct irq_domain *domain; + struct device_node *pnode; + + mutex_init(&wcd9xxx_res->irq_lock); + mutex_init(&wcd9xxx_res->nested_irq_lock); + + pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node); + if (unlikely(!pnode)) + return -EINVAL; + + domain = irq_find_host(pnode); + if (unlikely(!domain)) + return -EINVAL; + + wcd9xxx_res->domain = domain; + + wcd9xxx_res->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx_res); + if (!wcd9xxx_res->irq) { + pr_warn("%s: irq driver is not yet initialized\n", __func__); + mutex_destroy(&wcd9xxx_res->irq_lock); + mutex_destroy(&wcd9xxx_res->nested_irq_lock); + return -EPROBE_DEFER; + } + pr_debug("%s: probed irq %d\n", __func__, wcd9xxx_res->irq); + + /* Setup downstream IRQs */ + ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx_res); + if (ret) { + pr_err("%s: Failed to setup downstream IRQ\n", __func__); + goto fail_irq_level; + return ret; + } + + /* All other wcd9xxx interrupts are edge triggered */ + wcd9xxx_res->irq_level_high[0] = true; + + /* mask all the interrupts */ + irq_level = kzalloc(wcd9xxx_res->num_irq_regs, GFP_KERNEL); + if (!irq_level) { + ret = -ENOMEM; + goto fail_irq_level; + } + for (i = 0; i < wcd9xxx_res->num_irqs; i++) { + wcd9xxx_res->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i); + wcd9xxx_res->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i); + irq_level[BIT_BYTE(i)] |= + wcd9xxx_res->irq_level_high[i] << (i % BITS_PER_BYTE); + } + + if (!wcd9xxx_res->wcd_core_regmap) { + dev_err(wcd9xxx_res->dev, + "%s: Codec core regmap not defined\n", + __func__); + ret = -EINVAL; + goto fail_irq_init; + } + + for (i = 0; i < wcd9xxx_res->num_irq_regs; i++) { + /* Initialize interrupt mask and level registers */ + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] + i, + irq_level[i]); + regmap_write(wcd9xxx_res->wcd_core_regmap, + wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i, + wcd9xxx_res->irq_masks_cur[i]); + } + + ret = request_threaded_irq(wcd9xxx_res->irq, NULL, wcd9xxx_irq_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "wcd9xxx", wcd9xxx_res); + if (ret != 0) + dev_err(wcd9xxx_res->dev, "Failed to request IRQ %d: %d\n", + wcd9xxx_res->irq, ret); + else { + ret = enable_irq_wake(wcd9xxx_res->irq); + if (ret) + dev_err(wcd9xxx_res->dev, + "Failed to set wake interrupt on IRQ %d: %d\n", + wcd9xxx_res->irq, ret); + if (ret) + free_irq(wcd9xxx_res->irq, wcd9xxx_res); + } + + if (ret) + goto fail_irq_init; + + kfree(irq_level); + return ret; + +fail_irq_init: + dev_err(wcd9xxx_res->dev, + "%s: Failed to init wcd9xxx irq\n", __func__); + kfree(irq_level); +fail_irq_level: + wcd9xxx_irq_put_upstream_irq(wcd9xxx_res); + mutex_destroy(&wcd9xxx_res->irq_lock); + mutex_destroy(&wcd9xxx_res->nested_irq_lock); + return ret; +} +EXPORT_SYMBOL(wcd9xxx_irq_init); + +int wcd9xxx_request_irq(struct wcd9xxx_core_resource *wcd9xxx_res, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + int virq; + + virq = phyirq_to_virq(wcd9xxx_res, irq); + + return request_threaded_irq(virq, NULL, handler, IRQF_TRIGGER_RISING, + name, data); +} +EXPORT_SYMBOL(wcd9xxx_request_irq); + +void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res) +{ + dev_dbg(wcd9xxx_res->dev, "%s: Cleaning up irq %d\n", __func__, + wcd9xxx_res->irq); + + if (wcd9xxx_res->irq) { + disable_irq_wake(wcd9xxx_res->irq); + free_irq(wcd9xxx_res->irq, wcd9xxx_res); + wcd9xxx_res->irq = 0; + wcd9xxx_irq_put_downstream_irq(wcd9xxx_res); + wcd9xxx_irq_put_upstream_irq(wcd9xxx_res); + } + mutex_destroy(&wcd9xxx_res->irq_lock); + mutex_destroy(&wcd9xxx_res->nested_irq_lock); +} + +#ifndef CONFIG_OF +static int phyirq_to_virq( + struct wcd9xxx_core_resource *wcd9xxx_res, + int offset) +{ + return wcd9xxx_res->irq_base + offset; +} + +static int virq_to_phyirq( + struct wcd9xxx_core_resource *wcd9xxx_res, + int virq) +{ + return virq - wcd9xxx_res->irq_base; +} + +static unsigned int wcd9xxx_irq_get_upstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + return wcd9xxx_res->irq; +} + +static void wcd9xxx_irq_put_upstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + /* Do nothing */ +} + +static int wcd9xxx_map_irq( + struct wcd9xxx_core_resource *wcd9xxx_core_res, int irq) +{ + return phyirq_to_virq(wcd9xxx_core_res, irq); +} +#else +static struct wcd9xxx_irq_drv_data * +wcd9xxx_irq_add_domain(struct device_node *node, + struct device_node *parent) +{ + struct wcd9xxx_irq_drv_data *data = NULL; + + pr_debug("%s: node %s, node parent %s\n", __func__, + node->name, node->parent->name); + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return NULL; + + /* + * wcd9xxx_intc interrupt controller supports N to N irq mapping with + * single cell binding with irq numbers(offsets) only. + * Use irq_domain_simple_ops that has irq_domain_simple_map and + * irq_domain_xlate_onetwocell. + */ + data->domain = irq_domain_add_linear(node, WCD9XXX_MAX_NUM_IRQS, + &irq_domain_simple_ops, data); + if (!data->domain) { + kfree(data); + return NULL; + } + + return data; +} + +static struct wcd9xxx_irq_drv_data * +wcd9xxx_get_irq_drv_d(const struct wcd9xxx_core_resource *wcd9xxx_res) +{ + struct irq_domain *domain; + + domain = wcd9xxx_res->domain; + + if (domain) + return domain->host_data; + else + return NULL; +} + +static int phyirq_to_virq(struct wcd9xxx_core_resource *wcd9xxx_res, int offset) +{ + struct wcd9xxx_irq_drv_data *data; + + data = wcd9xxx_get_irq_drv_d(wcd9xxx_res); + if (!data) { + pr_warn("%s: not registered to interrupt controller\n", + __func__); + return -EINVAL; + } + return irq_linear_revmap(data->domain, offset); +} + +static int virq_to_phyirq(struct wcd9xxx_core_resource *wcd9xxx_res, int virq) +{ + struct irq_data *irq_data = irq_get_irq_data(virq); + + if (unlikely(!irq_data)) { + pr_err("%s: irq_data is NULL", __func__); + return -EINVAL; + } + return irq_data->hwirq; +} + +static unsigned int wcd9xxx_irq_get_upstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + struct wcd9xxx_irq_drv_data *data; + + data = wcd9xxx_get_irq_drv_d(wcd9xxx_res); + if (!data) { + pr_err("%s: interrupt controller is not registered\n", + __func__); + return 0; + } + + /* Make sure data is updated before return. */ + rmb(); + return data->irq; +} + +static void wcd9xxx_irq_put_downstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + int irq, virq, ret; + + /* + * IRQ migration hits error if the chip data and handles + * are not made NULL. make associated data and handles + * to NULL at irq_exit + */ + for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) { + virq = wcd9xxx_map_irq(wcd9xxx_res, irq); + pr_debug("%s: irq %d -> %d\n", __func__, irq, virq); + ret = irq_set_chip_data(virq, NULL); + if (ret) { + pr_err("%s: Failed to configure irq %d (%d)\n", + __func__, irq, ret); + return; + } + irq_set_chip_and_handler(virq, NULL, NULL); + } +} + +static void wcd9xxx_irq_put_upstream_irq( + struct wcd9xxx_core_resource *wcd9xxx_res) +{ + wcd9xxx_res->domain = NULL; +} + +static int wcd9xxx_map_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq) +{ + return of_irq_to_resource(wcd9xxx_res->dev->of_node, irq, NULL); +} + +static int wcd9xxx_irq_probe(struct platform_device *pdev) +{ + int irq, dir_apps_irq = -EINVAL; + struct wcd9xxx_irq_drv_data *data; + struct device_node *node = pdev->dev.of_node; + int ret = -EINVAL; + + irq = of_get_named_gpio(node, "qcom,gpio-connect", 0); + if (!gpio_is_valid(irq)) + dir_apps_irq = platform_get_irq_byname(pdev, "wcd_irq"); + + if (!gpio_is_valid(irq) && dir_apps_irq < 0) { + dev_err(&pdev->dev, "TLMM connect gpio not found\n"); + return -EPROBE_DEFER; + } + if (dir_apps_irq > 0) { + irq = dir_apps_irq; + } else { + irq = gpio_to_irq(irq); + if (irq < 0) { + dev_err(&pdev->dev, "Unable to configure irq\n"); + return irq; + } + } + dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq); + data = wcd9xxx_irq_add_domain(node, node->parent); + if (!data) { + pr_err("%s: irq_add_domain failed\n", __func__); + return -EINVAL; + } + data->irq = irq; + + /* Make sure irq is saved before return. */ + wmb(); + ret = 0; + + return ret; +} + +static int wcd9xxx_irq_remove(struct platform_device *pdev) +{ + struct irq_domain *domain; + struct wcd9xxx_irq_drv_data *data; + + domain = irq_find_host(pdev->dev.of_node); + if (unlikely(!domain)) { + pr_err("%s: domain is NULL", __func__); + return -EINVAL; + } + data = (struct wcd9xxx_irq_drv_data *)domain->host_data; + data->irq = 0; + + /* Make sure irq variable is updated in data, before irq removal. */ + wmb(); + irq_domain_remove(data->domain); + kfree(data); + + return 0; +} + +static const struct of_device_id of_match[] = { + { .compatible = "qcom,wcd9xxx-irq" }, + { } +}; + +static struct platform_driver wcd9xxx_irq_driver = { + .probe = wcd9xxx_irq_probe, + .remove = wcd9xxx_irq_remove, + .driver = { + .name = "wcd9xxx_intc", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_match), + .suppress_bind_attrs = true, + }, +}; + +int wcd9xxx_irq_drv_init(void) +{ + return platform_driver_register(&wcd9xxx_irq_driver); +} + +void wcd9xxx_irq_drv_exit(void) +{ + platform_driver_unregister(&wcd9xxx_irq_driver); +} +#endif /* CONFIG_OF */ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-resmgr-v2.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-resmgr-v2.c new file mode 100644 index 0000000000..fcb82f96e1 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-resmgr-v2.c @@ -0,0 +1,687 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include + +#define WCD9XXX_RCO_CALIBRATION_DELAY_INC_US 5000 +/* This register is valid only for WCD9335 */ +#define WCD93XX_ANA_CLK_TOP 0x0602 + +#define WCD93XX_ANA_BIAS 0x0601 +#define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41 +#define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42 +#define WCD93XX_CLK_SYS_MCLK_PRG 0x711 +#define WCD93XX_CODEC_RPM_CLK_GATE 0x002 +#define WCD93XX_ANA_RCO 0x603 +#define WCD93XX_ANA_BUCK_CTL 0x606 + +static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type) +{ + if (clk_type == WCD_CLK_OFF) + return "WCD_CLK_OFF"; + else if (clk_type == WCD_CLK_RCO) + return "WCD_CLK_RCO"; + else if (clk_type == WCD_CLK_MCLK) + return "WCD_CLK_MCLK"; + else + return "WCD_CLK_UNDEFINED"; +} + +static int wcd_resmgr_codec_reg_update_bits(struct wcd9xxx_resmgr_v2 *resmgr, + u16 reg, u8 mask, u8 val) +{ + bool change; + int ret; + + if (resmgr->codec_type != WCD9335) { + /* Tavil and Pahu does not support ANA_CLK_TOP register */ + if (reg == WCD93XX_ANA_CLK_TOP) + return 0; + } else { + /* Tasha does not support CLK_SYS_MCLK_PRG register */ + if (reg == WCD93XX_CLK_SYS_MCLK_PRG) + return 0; + } + if (resmgr->component) { + ret = snd_soc_component_update_bits(resmgr->component, reg, + mask, val); + } else if (resmgr->core_res->wcd_core_regmap) { + ret = regmap_update_bits_check( + resmgr->core_res->wcd_core_regmap, + reg, mask, val, &change); + if (!ret) + ret = change; + } else { + pr_err("%s: codec/regmap not defined\n", __func__); + ret = -EINVAL; + } + + return ret; +} + +static int wcd_resmgr_codec_reg_read(struct wcd9xxx_resmgr_v2 *resmgr, + unsigned int reg) +{ + int val, ret; + + if (resmgr->codec_type != WCD9335) { + if (reg == WCD93XX_ANA_CLK_TOP) + return 0; + } else { + if (reg == WCD93XX_CLK_SYS_MCLK_PRG) + return 0; + } + if (resmgr->component) { + val = snd_soc_component_read32(resmgr->component, reg); + } else if (resmgr->core_res->wcd_core_regmap) { + ret = regmap_read(resmgr->core_res->wcd_core_regmap, + reg, &val); + if (ret) + val = ret; + } else { + pr_err("%s: wcd regmap is null\n", __func__); + return -EINVAL; + } + + return val; +} + +/* + * wcd_resmgr_get_clk_type() + * Returns clk type that is currently enabled + */ +int wcd_resmgr_get_clk_type(struct wcd9xxx_resmgr_v2 *resmgr) +{ + if (!resmgr) { + pr_err("%s: resmgr not initialized\n", __func__); + return -EINVAL; + } + return resmgr->clk_type; +} +EXPORT_SYMBOL(wcd_resmgr_get_clk_type); + +static void wcd_resmgr_cdc_specific_get_clk(struct wcd9xxx_resmgr_v2 *resmgr, + int clk_users) +{ + /* Caller of this function should have acquired BG_CLK lock */ + if (clk_users) { + if (resmgr->resmgr_cb && + resmgr->resmgr_cb->cdc_rco_ctrl) { + while (clk_users--) + resmgr->resmgr_cb->cdc_rco_ctrl( + resmgr->component, true); + } + } +} + +/* + * wcd_resmgr_post_ssr_v2 + * @resmgr: handle to struct wcd9xxx_resmgr_v2 + */ +void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr) +{ + int old_bg_audio_users; + int old_clk_rco_users, old_clk_mclk_users; + + WCD9XXX_V2_BG_CLK_LOCK(resmgr); + + old_bg_audio_users = resmgr->master_bias_users; + old_clk_mclk_users = resmgr->clk_mclk_users; + old_clk_rco_users = resmgr->clk_rco_users; + resmgr->master_bias_users = 0; + resmgr->clk_mclk_users = 0; + resmgr->clk_rco_users = 0; + resmgr->clk_type = WCD_CLK_OFF; + + pr_debug("%s: old_bg_audio_users=%d old_clk_mclk_users=%d old_clk_rco_users=%d\n", + __func__, old_bg_audio_users, + old_clk_mclk_users, old_clk_rco_users); + + if (old_bg_audio_users) { + while (old_bg_audio_users--) + wcd_resmgr_enable_master_bias(resmgr); + } + + if (old_clk_mclk_users) { + while (old_clk_mclk_users--) + wcd_resmgr_enable_clk_block(resmgr, WCD_CLK_MCLK); + } + + if (old_clk_rco_users) + wcd_resmgr_cdc_specific_get_clk(resmgr, old_clk_rco_users); + + WCD9XXX_V2_BG_CLK_UNLOCK(resmgr); +} +EXPORT_SYMBOL(wcd_resmgr_post_ssr_v2); + +/* + * wcd_resmgr_enable_master_bias: enable codec master bias + * @resmgr: handle to struct wcd9xxx_resmgr_v2 + */ +int wcd_resmgr_enable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr) +{ + mutex_lock(&resmgr->master_bias_lock); + + resmgr->master_bias_users++; + if (resmgr->master_bias_users == 1) { + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, + 0x80, 0x80); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, + 0x40, 0x40); + /* + * 1ms delay is required after pre-charge is enabled + * as per HW requirement + */ + usleep_range(1000, 1100); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, + 0x40, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_BIAS, 0x20, 0x00); + } + + pr_debug("%s: current master bias users: %d\n", __func__, + resmgr->master_bias_users); + + mutex_unlock(&resmgr->master_bias_lock); + return 0; +} +EXPORT_SYMBOL(wcd_resmgr_enable_master_bias); + +/* + * wcd_resmgr_disable_master_bias: disable codec master bias + * @resmgr: handle to struct wcd9xxx_resmgr_v2 + */ +int wcd_resmgr_disable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr) +{ + mutex_lock(&resmgr->master_bias_lock); + if (resmgr->master_bias_users <= 0) { + mutex_unlock(&resmgr->master_bias_lock); + return -EINVAL; + } + + resmgr->master_bias_users--; + if (resmgr->master_bias_users == 0) { + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, + 0x80, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_BIAS, 0x20, 0x00); + } + mutex_unlock(&resmgr->master_bias_lock); + return 0; +} +EXPORT_SYMBOL(wcd_resmgr_disable_master_bias); + +static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr) +{ + /* Enable mclk requires master bias to be enabled first */ + if (resmgr->master_bias_users <= 0) { + pr_err("%s: Cannot turn on MCLK, BG is not enabled\n", + __func__); + return -EINVAL; + } + + if (((resmgr->clk_mclk_users == 0) && + (resmgr->clk_type == WCD_CLK_MCLK)) || + ((resmgr->clk_mclk_users > 0) && + (resmgr->clk_type != WCD_CLK_MCLK))) { + pr_err("%s: Error enabling MCLK, clk_type: %s\n", + __func__, + wcd_resmgr_clk_type_to_str(resmgr->clk_type)); + return -EINVAL; + } + + if (++resmgr->clk_mclk_users == 1) { + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_CLK_TOP, 0x80, 0x80); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_CLK_TOP, 0x08, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_CLK_TOP, 0x04, 0x04); + if (resmgr->codec_type != WCD9335) { + /* + * In tavil clock contrl register is changed + * to CLK_SYS_MCLK_PRG + */ + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x80, 0x80); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x30, 0x10); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x02, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x02, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CODEC_RPM_CLK_GATE, 0x03, 0x00); + } else { + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + } + /* + * 10us sleep is required after clock is enabled + * as per HW requirement + */ + usleep_range(10, 15); + } + + resmgr->clk_type = WCD_CLK_MCLK; + + pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__, + resmgr->clk_mclk_users, + wcd_resmgr_clk_type_to_str(resmgr->clk_type)); + + return 0; +} + +static int wcd_resmgr_disable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr) +{ + if (resmgr->clk_mclk_users <= 0) { + pr_err("%s: No mclk users, cannot disable mclk\n", __func__); + return -EINVAL; + } + + if (--resmgr->clk_mclk_users == 0) { + if (resmgr->clk_rco_users > 0) { + /* MCLK to RCO switch */ + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_CLK_TOP, + 0x08, 0x08); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x02, 0x02); + /* Disable clock buffer */ + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x80, 0x00); + resmgr->clk_type = WCD_CLK_RCO; + } else { + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_CLK_TOP, + 0x04, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, 0x81, 0x00); + resmgr->clk_type = WCD_CLK_OFF; + } + + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_CLK_TOP, + 0x80, 0x00); + } + + if ((resmgr->codec_type != WCD9335) && + (resmgr->clk_type == WCD_CLK_OFF)) + wcd_resmgr_set_sido_input_src(resmgr, SIDO_SOURCE_INTERNAL); + + pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__, + resmgr->clk_mclk_users, + wcd_resmgr_clk_type_to_str(resmgr->clk_type)); + + return 0; +} + +static void wcd_resmgr_set_buck_accuracy(struct wcd9xxx_resmgr_v2 *resmgr) +{ + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x02, 0x02); + /* 100us sleep needed after HIGH_ACCURACY_PRE_EN1 */ + usleep_range(100, 110); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x01, 0x01); + /* 100us sleep needed after HIGH_ACCURACY_PRE_EN2 */ + usleep_range(100, 110); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x04, 0x04); + /* 100us sleep needed after HIGH_ACCURACY_EN */ + usleep_range(100, 110); +} + +static int wcd_resmgr_enable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr) +{ + bool rco_cal_done = true; + + resmgr->clk_rco_users++; + if ((resmgr->clk_rco_users == 1) && + ((resmgr->clk_type == WCD_CLK_OFF) || + (resmgr->clk_mclk_users == 0))) { + pr_warn("%s: RCO enable requires MCLK to be ON first\n", + __func__); + resmgr->clk_rco_users--; + return -EINVAL; + } else if ((resmgr->clk_rco_users == 1) && + (resmgr->clk_mclk_users)) { + /* RCO Enable */ + if (resmgr->sido_input_src == SIDO_SOURCE_INTERNAL) { + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_RCO, + 0x80, 0x80); + if (resmgr->codec_type != WCD9335) + wcd_resmgr_set_buck_accuracy(resmgr); + } + + /* + * 20us required after RCO BG is enabled as per HW + * requirements + */ + usleep_range(20, 25); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_RCO, + 0x40, 0x40); + /* + * 20us required after RCO is enabled as per HW + * requirements + */ + usleep_range(20, 25); + /* RCO Calibration */ + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_RCO, + 0x04, 0x04); + if (resmgr->codec_type != WCD9335) + /* + * For wcd934x and wcd936x codecs, 20us sleep is needed + * after enabling RCO calibration + */ + usleep_range(20, 25); + + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_RCO, + 0x04, 0x00); + if (resmgr->codec_type != WCD9335) + /* + * For wcd934x and wcd936x codecs, 20us sleep is needed + * after disabling RCO calibration + */ + usleep_range(20, 25); + + /* RCO calibration takes app. 5ms to complete */ + usleep_range(WCD9XXX_RCO_CALIBRATION_DELAY_INC_US, + WCD9XXX_RCO_CALIBRATION_DELAY_INC_US + 100); + if (wcd_resmgr_codec_reg_read(resmgr, WCD93XX_ANA_RCO) & 0x02) + rco_cal_done = false; + + WARN((!rco_cal_done), "RCO Calibration failed\n"); + + /* Switch MUX to RCO */ + if (resmgr->clk_mclk_users == 1) { + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_CLK_TOP, + 0x08, 0x08); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, + 0x02, 0x02); + resmgr->clk_type = WCD_CLK_RCO; + } + } + pr_debug("%s: rco clk users: %d, clk_type: %s\n", __func__, + resmgr->clk_rco_users, + wcd_resmgr_clk_type_to_str(resmgr->clk_type)); + + return 0; +} + +static int wcd_resmgr_disable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr) +{ + if ((resmgr->clk_rco_users <= 0) || + (resmgr->clk_type == WCD_CLK_OFF)) { + pr_err("%s: rco_clk_users = %d, clk_type = %d, cannot disable\n", + __func__, resmgr->clk_rco_users, resmgr->clk_type); + return -EINVAL; + } + + resmgr->clk_rco_users--; + + if ((resmgr->clk_rco_users == 0) && + (resmgr->clk_type == WCD_CLK_RCO)) { + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_CLK_TOP, + 0x08, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, + 0x02, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_CLK_TOP, + 0x04, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_RCO, + 0x40, 0x00); + if (resmgr->sido_input_src == SIDO_SOURCE_INTERNAL) + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_RCO, + 0x80, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CLK_SYS_MCLK_PRG, + 0x01, 0x00); + resmgr->clk_type = WCD_CLK_OFF; + } else if ((resmgr->clk_rco_users == 0) && + (resmgr->clk_mclk_users)) { + /* Disable RCO while MCLK is ON */ + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_RCO, + 0x40, 0x00); + if (resmgr->sido_input_src == SIDO_SOURCE_INTERNAL) + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_RCO, + 0x80, 0x00); + } + + if ((resmgr->codec_type != WCD9335) && + (resmgr->clk_type == WCD_CLK_OFF)) + wcd_resmgr_set_sido_input_src(resmgr, SIDO_SOURCE_INTERNAL); + + pr_debug("%s: rco clk users: %d, clk_type: %s\n", __func__, + resmgr->clk_rco_users, + wcd_resmgr_clk_type_to_str(resmgr->clk_type)); + + return 0; +} + +/* + * wcd_resmgr_enable_clk_block: enable MCLK or RCO + * @resmgr: handle to struct wcd9xxx_resmgr_v2 + * @type: Clock type to enable + */ +int wcd_resmgr_enable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr, + enum wcd_clock_type type) +{ + int ret; + + switch (type) { + case WCD_CLK_MCLK: + ret = wcd_resmgr_enable_clk_mclk(resmgr); + break; + case WCD_CLK_RCO: + ret = wcd_resmgr_enable_clk_rco(resmgr); + break; + default: + pr_err("%s: Unknown Clock type: %s\n", __func__, + wcd_resmgr_clk_type_to_str(type)); + ret = -EINVAL; + break; + }; + + if (ret) + pr_err("%s: Enable clock %s failed\n", __func__, + wcd_resmgr_clk_type_to_str(type)); + + return ret; +} +EXPORT_SYMBOL(wcd_resmgr_enable_clk_block); + +void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr, + int sido_src) +{ + if (!resmgr) + return; + + if (sido_src == resmgr->sido_input_src) + return; + + if (sido_src == SIDO_SOURCE_INTERNAL) { + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x04, 0x00); + usleep_range(100, 110); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x03, 0x00); + usleep_range(100, 110); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_RCO, + 0x80, 0x00); + usleep_range(100, 110); + resmgr->sido_input_src = SIDO_SOURCE_INTERNAL; + pr_debug("%s: sido input src to internal\n", __func__); + } else if (sido_src == SIDO_SOURCE_RCO_BG) { + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_RCO, + 0x80, 0x80); + usleep_range(100, 110); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x02, 0x02); + usleep_range(100, 110); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x01, 0x01); + usleep_range(100, 110); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BUCK_CTL, + 0x04, 0x04); + usleep_range(100, 110); + resmgr->sido_input_src = SIDO_SOURCE_RCO_BG; + pr_debug("%s: sido input src to external\n", __func__); + } +} +EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src); + +/* + * wcd_resmgr_set_sido_input_src_locked: + * Set SIDO input in BG_CLK locked context + * + * @resmgr: handle to struct wcd9xxx_resmgr_v2 + * @sido_src: Select the SIDO input source + */ +void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr, + int sido_src) +{ + if (!resmgr) + return; + + WCD9XXX_V2_BG_CLK_LOCK(resmgr); + wcd_resmgr_set_sido_input_src(resmgr, sido_src); + WCD9XXX_V2_BG_CLK_UNLOCK(resmgr); +} +EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src_locked); + +/* + * wcd_resmgr_disable_clk_block: disable MCLK or RCO + * @resmgr: handle to struct wcd9xxx_resmgr_v2 + * @type: Clock type to disable + */ +int wcd_resmgr_disable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr, + enum wcd_clock_type type) +{ + int ret; + + switch (type) { + case WCD_CLK_MCLK: + ret = wcd_resmgr_disable_clk_mclk(resmgr); + break; + case WCD_CLK_RCO: + ret = wcd_resmgr_disable_clk_rco(resmgr); + break; + default: + pr_err("%s: Unknown Clock type: %s\n", __func__, + wcd_resmgr_clk_type_to_str(type)); + ret = -EINVAL; + break; + }; + + if (ret) + pr_err("%s: Disable clock %s failed\n", __func__, + wcd_resmgr_clk_type_to_str(type)); + + return ret; +} +EXPORT_SYMBOL(wcd_resmgr_disable_clk_block); + +/* + * wcd_resmgr_init: initialize wcd resource manager + * @core_res: handle to struct wcd9xxx_core_resource + * + * Early init call without a handle to snd_soc_component * + */ +struct wcd9xxx_resmgr_v2 *wcd_resmgr_init( + struct wcd9xxx_core_resource *core_res, + struct snd_soc_component *component) +{ + struct wcd9xxx_resmgr_v2 *resmgr; + struct wcd9xxx *wcd9xxx; + + resmgr = kzalloc(sizeof(struct wcd9xxx_resmgr_v2), GFP_KERNEL); + if (!resmgr) + return ERR_PTR(-ENOMEM); + + wcd9xxx = container_of(core_res, struct wcd9xxx, core_res); + if (!wcd9xxx) { + kfree(resmgr); + pr_err("%s: Cannot get wcd9xx pointer\n", __func__); + return ERR_PTR(-EINVAL); + } + + mutex_init(&resmgr->codec_bg_clk_lock); + mutex_init(&resmgr->master_bias_lock); + resmgr->master_bias_users = 0; + resmgr->clk_mclk_users = 0; + resmgr->clk_rco_users = 0; + resmgr->master_bias_users = 0; + resmgr->component = component; + resmgr->core_res = core_res; + resmgr->sido_input_src = SIDO_SOURCE_INTERNAL; + resmgr->codec_type = wcd9xxx->type; + + return resmgr; +} +EXPORT_SYMBOL(wcd_resmgr_init); + +/* + * wcd_resmgr_remove: Clean-up wcd resource manager + * @resmgr: handle to struct wcd9xxx_resmgr_v2 + */ +void wcd_resmgr_remove(struct wcd9xxx_resmgr_v2 *resmgr) +{ + mutex_destroy(&resmgr->master_bias_lock); + kfree(resmgr); +} +EXPORT_SYMBOL(wcd_resmgr_remove); + +/* + * wcd_resmgr_post_init: post init call to assign codec handle + * @resmgr: handle to struct wcd9xxx_resmgr_v2 created during early init + * @resmgr_cb: codec callback function for resmgr + * @component: handle to struct snd_soc_component + */ +int wcd_resmgr_post_init(struct wcd9xxx_resmgr_v2 *resmgr, + const struct wcd_resmgr_cb *resmgr_cb, + struct snd_soc_component *component) +{ + if (!resmgr) { + pr_err("%s: resmgr not allocated\n", __func__); + return -EINVAL; + } + + if (!component) { + pr_err("%s: Codec memory is NULL, nothing to post init\n", + __func__); + return -EINVAL; + } + + resmgr->component = component; + resmgr->resmgr_cb = resmgr_cb; + + return 0; +} +EXPORT_SYMBOL(wcd_resmgr_post_init); + +MODULE_DESCRIPTION("wcd9xxx resmgr v2 module"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-rst.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-rst.c new file mode 100644 index 0000000000..4171a713f6 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-rst.c @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include "wcd9xxx-utils.h" +#include "wcd9335_registers.h" +#include "wcd9335_irq.h" +#include +#include "wcd934x/wcd934x_irq.h" + +/* wcd9335 interrupt table */ +static const struct intr_data wcd9335_intr_table[] = { + {WCD9XXX_IRQ_SLIMBUS, false}, + {WCD9335_IRQ_MBHC_SW_DET, true}, + {WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true}, + {WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true}, + {WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true}, + {WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true}, + {WCD9335_IRQ_FLL_LOCK_LOSS, false}, + {WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false}, + {WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false}, + {WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false}, + {WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false}, + {WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false}, + {WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false}, + {WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false}, + {WCD9335_IRQ_HPH_PA_OCPL_FAULT, false}, + {WCD9335_IRQ_HPH_PA_OCPR_FAULT, false}, + {WCD9335_IRQ_EAR_PA_OCP_FAULT, false}, + {WCD9335_IRQ_SOUNDWIRE, false}, + {WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false}, + {WCD9335_IRQ_RCO_ERROR, false}, + {WCD9335_IRQ_SVA_ERROR, false}, + {WCD9335_IRQ_MAD_AUDIO, false}, + {WCD9335_IRQ_MAD_BEACON, false}, + {WCD9335_IRQ_SVA_OUTBOX1, true}, + {WCD9335_IRQ_SVA_OUTBOX2, true}, + {WCD9335_IRQ_MAD_ULTRASOUND, false}, + {WCD9335_IRQ_VBAT_ATTACK, false}, + {WCD9335_IRQ_VBAT_RESTORE, false}, +}; + +static const struct intr_data wcd934x_intr_table[] = { + {WCD9XXX_IRQ_SLIMBUS, false}, + {WCD934X_IRQ_MBHC_SW_DET, true}, + {WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, true}, + {WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, true}, + {WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, true}, + {WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true}, + {WCD934X_IRQ_MISC, false}, + {WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, false}, + {WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, false}, + {WCD934X_IRQ_EAR_PA_CNP_COMPLETE, false}, + {WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, false}, + {WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, false}, + {WCD934X_IRQ_SLNQ_ANALOG_ERROR, false}, + {WCD934X_IRQ_RESERVED_3, false}, + {WCD934X_IRQ_HPH_PA_OCPL_FAULT, false}, + {WCD934X_IRQ_HPH_PA_OCPR_FAULT, false}, + {WCD934X_IRQ_EAR_PA_OCP_FAULT, false}, + {WCD934X_IRQ_SOUNDWIRE, false}, + {WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, false}, + {WCD934X_IRQ_RCO_ERROR, false}, + {WCD934X_IRQ_CPE_ERROR, false}, + {WCD934X_IRQ_MAD_AUDIO, false}, + {WCD934X_IRQ_MAD_BEACON, false}, + {WCD934X_IRQ_CPE1_INTR, true}, + {WCD934X_IRQ_RESERVED_4, false}, + {WCD934X_IRQ_MAD_ULTRASOUND, false}, + {WCD934X_IRQ_VBAT_ATTACK, false}, + {WCD934X_IRQ_VBAT_RESTORE, false}, +}; + +/* + * wcd9335_bring_down: Bringdown WCD Codec + * + * @wcd9xxx: Pointer to wcd9xxx structure + * + * Returns 0 for success or negative error code for failure + */ +static int wcd9335_bring_down(struct wcd9xxx *wcd9xxx) +{ + if (!wcd9xxx || !wcd9xxx->regmap) + return -EINVAL; + + regmap_write(wcd9xxx->regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x04); + + return 0; +} + +/* + * wcd9335_bring_up: Bringup WCD Codec + * + * @wcd9xxx: Pointer to the wcd9xxx structure + * + * Returns 0 for success or negative error code for failure + */ +static int wcd9335_bring_up(struct wcd9xxx *wcd9xxx) +{ + int ret = 0; + int val, byte0; + struct regmap *wcd_regmap; + + if (!wcd9xxx) + return -EINVAL; + + if (!wcd9xxx->regmap) { + dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n", + __func__); + return -EINVAL; + } + wcd_regmap = wcd9xxx->regmap; + + regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val); + regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0); + + if ((val < 0) || (byte0 < 0)) { + dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n", + __func__); + return -EINVAL; + } + if ((val & 0x80) && (byte0 == 0x0)) { + dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n", + __func__); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01); + regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC); + regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x5); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x7); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x3); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3); + } else if (byte0 == 0x1) { + dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n", + __func__); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01); + regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00); + regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F); + regmap_write(wcd_regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x5); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x7); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x3); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3); + } else if ((byte0 == 0) && (!(val & 0x80))) { + dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n", + __func__); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01); + regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC); + regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x3); + regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3); + } else { + dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n", + __func__); + ret = -EINVAL; + } + + return ret; +} + +/* + * wcd9335_get_cdc_info: Get codec specific information + * + * @wcd9xxx: pointer to wcd9xxx structure + * @wcd_type: pointer to wcd9xxx_codec_type structure + * + * Returns 0 for success or negative error code for failure + */ +static int wcd9335_get_cdc_info(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_codec_type *wcd_type) +{ + u16 id_minor, id_major; + struct regmap *wcd_regmap; + int rc, val, version = 0; + + if (!wcd9xxx || !wcd_type) + return -EINVAL; + + if (!wcd9xxx->regmap) { + dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n", + __func__); + return -EINVAL; + } + wcd_regmap = wcd9xxx->regmap; + + rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, + (u8 *)&id_minor, sizeof(u16)); + if (rc) + return -EINVAL; + + rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2, + (u8 *)&id_major, sizeof(u16)); + if (rc) + return -EINVAL; + + dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n", + __func__, id_major, id_minor); + + /* Version detection */ + if (id_major == TASHA_MAJOR) { + regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, + &val); + version = ((u8)val & 0x80) >> 7; + } else if (id_major == TASHA2P0_MAJOR) + version = 2; + else + dev_err(wcd9xxx->dev, "%s: wcd9335 version unknown (major 0x%x, minor 0x%x)\n", + __func__, id_major, id_minor); + + /* Fill codec type info */ + wcd_type->id_major = id_major; + wcd_type->id_minor = id_minor; + wcd_type->num_irqs = WCD9335_NUM_IRQS; + wcd_type->version = version; + wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1; + wcd_type->i2c_chip_status = 0x01; + wcd_type->intr_tbl = wcd9335_intr_table; + wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9335_intr_table); + + wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] = + WCD9335_INTR_PIN1_STATUS0; + wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] = + WCD9335_INTR_PIN1_CLEAR0; + wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] = + WCD9335_INTR_PIN1_MASK0; + wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] = + WCD9335_INTR_LEVEL0; + wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] = + WCD9335_INTR_CLR_COMMIT; + + return rc; +} + +/* + * wcd934x_bring_down: Bringdown WCD Codec + * + * @wcd9xxx: Pointer to wcd9xxx structure + * + * Returns 0 for success or negative error code for failure + */ +static int wcd934x_bring_down(struct wcd9xxx *wcd9xxx) +{ + if (!wcd9xxx || !wcd9xxx->regmap) + return -EINVAL; + + regmap_write(wcd9xxx->regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x04); + + return 0; +} + +/* + * wcd934x_bring_up: Bringup WCD Codec + * + * @wcd9xxx: Pointer to the wcd9xxx structure + * + * Returns 0 for success or negative error code for failure + */ +static int wcd934x_bring_up(struct wcd9xxx *wcd9xxx) +{ + struct regmap *wcd_regmap; + + if (!wcd9xxx) + return -EINVAL; + + if (!wcd9xxx->regmap) { + dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n", + __func__); + return -EINVAL; + } + wcd_regmap = wcd9xxx->regmap; + + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01); + regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19); + regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15); + /* Add 1msec delay for VOUT to settle */ + usleep_range(1000, 1100); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); + + return 0; +} + +/* + * wcd934x_get_cdc_info: Get codec specific information + * + * @wcd9xxx: pointer to wcd9xxx structure + * @wcd_type: pointer to wcd9xxx_codec_type structure + * + * Returns 0 for success or negative error code for failure + */ +static int wcd934x_get_cdc_info(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_codec_type *wcd_type) +{ + u16 id_minor, id_major; + struct regmap *wcd_regmap; + int rc, version = -1; + + if (!wcd9xxx || !wcd_type) + return -EINVAL; + + if (!wcd9xxx->regmap) { + dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null\n", __func__); + return -EINVAL; + } + wcd_regmap = wcd9xxx->regmap; + + rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0, + (u8 *)&id_minor, sizeof(u16)); + if (rc) + return -EINVAL; + + rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2, + (u8 *)&id_major, sizeof(u16)); + if (rc) + return -EINVAL; + + dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n", + __func__, id_major, id_minor); + + if (id_major != TAVIL_MAJOR) + goto version_unknown; + + /* + * As fine version info cannot be retrieved before tavil probe. + * Assign coarse versions for possible future use before tavil probe. + */ + if (id_minor == cpu_to_le16(0)) + version = TAVIL_VERSION_1_0; + else if (id_minor == cpu_to_le16(0x01)) + version = TAVIL_VERSION_1_1; + +version_unknown: + if (version < 0) + dev_err(wcd9xxx->dev, "%s: wcd934x version unknown\n", + __func__); + + /* Fill codec type info */ + wcd_type->id_major = id_major; + wcd_type->id_minor = id_minor; + wcd_type->num_irqs = WCD934X_NUM_IRQS; + wcd_type->version = version; + wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1; + wcd_type->i2c_chip_status = 0x01; + wcd_type->intr_tbl = wcd934x_intr_table; + wcd_type->intr_tbl_size = ARRAY_SIZE(wcd934x_intr_table); + + wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] = + WCD934X_INTR_PIN1_STATUS0; + wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] = + WCD934X_INTR_PIN1_CLEAR0; + wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] = + WCD934X_INTR_PIN1_MASK0; + wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] = + WCD934X_INTR_LEVEL0; + wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] = + WCD934X_INTR_CLR_COMMIT; + + return rc; +} + +codec_bringdown_fn wcd9xxx_bringdown_fn(int type) +{ + codec_bringdown_fn cdc_bdown_fn; + + switch (type) { + case WCD934X: + cdc_bdown_fn = wcd934x_bring_down; + break; + case WCD9335: + cdc_bdown_fn = wcd9335_bring_down; + break; + default: + cdc_bdown_fn = NULL; + break; + } + + return cdc_bdown_fn; +} + +codec_bringup_fn wcd9xxx_bringup_fn(int type) +{ + codec_bringup_fn cdc_bup_fn; + + switch (type) { + case WCD934X: + cdc_bup_fn = wcd934x_bring_up; + break; + case WCD9335: + cdc_bup_fn = wcd9335_bring_up; + break; + default: + cdc_bup_fn = NULL; + break; + } + + return cdc_bup_fn; +} + +codec_type_fn wcd9xxx_get_codec_info_fn(int type) +{ + codec_type_fn cdc_type_fn; + + switch (type) { + case WCD934X: + cdc_type_fn = wcd934x_get_cdc_info; + break; + case WCD9335: + cdc_type_fn = wcd9335_get_cdc_info; + break; + default: + cdc_type_fn = NULL; + break; + } + + return cdc_type_fn; +} + diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-slimslave.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-slimslave.c new file mode 100644 index 0000000000..9d538afd10 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-slimslave.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2012-2018, 2020-2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include + +struct wcd9xxx_slim_sch { + u16 rx_port_ch_reg_base; + u16 port_tx_cfg_reg_base; + u16 port_rx_cfg_reg_base; +}; + +static struct wcd9xxx_slim_sch sh_ch; + +static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx, + u8 wcd9xxx_pgd_la, u32 cnt, + struct wcd9xxx_ch *channels, u32 path); + +static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim, + u32 cnt, struct wcd9xxx_ch *channels); + +static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx) +{ + if (wcd9xxx->codec_type->slim_slave_type == + WCD9XXX_SLIM_SLAVE_ADDR_TYPE_0) { + sh_ch.rx_port_ch_reg_base = 0x180; + sh_ch.port_rx_cfg_reg_base = 0x040; + sh_ch.port_tx_cfg_reg_base = 0x040; + } else { + sh_ch.rx_port_ch_reg_base = + 0x180 - (TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4); + sh_ch.port_rx_cfg_reg_base = + 0x040 - TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS; + sh_ch.port_tx_cfg_reg_base = 0x050; + } + + return 0; +} + +/** + * wcd9xxx_init_slimslave + * + * @wcd9xxx: pointer to wcd9xxx struct + * @wcd9xxx_pgd_la: pgd_la value + * @tx_num: tx number + * @rx_num: rx number + * @tx_slot: pointer to tx slot + * @rx_slot: pointer to rx slot + * + * Returns 0 on success, appropriate error code otherwise + */ +int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + int ret = 0; + int i; + + ret = wcd9xxx_configure_ports(wcd9xxx); + if (ret) { + pr_err("%s: Failed to configure register address offset\n", + __func__); + goto err; + } + + if (!rx_num || rx_num > wcd9xxx->num_rx_port) { + pr_err("%s: invalid rx num %d\n", __func__, rx_num); + return -EINVAL; + } + if (wcd9xxx->rx_chs) { + wcd9xxx->num_rx_port = rx_num; + for (i = 0; i < rx_num; i++) { + wcd9xxx->rx_chs[i].ch_num = rx_slot[i]; + INIT_LIST_HEAD(&wcd9xxx->rx_chs[i].list); + } + ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la, + wcd9xxx->num_rx_port, + wcd9xxx->rx_chs, + SLIM_SINK); + if (ret) { + pr_err("%s: Failed to alloc %d rx slimbus channels\n", + __func__, wcd9xxx->num_rx_port); + kfree(wcd9xxx->rx_chs); + wcd9xxx->rx_chs = NULL; + wcd9xxx->num_rx_port = 0; + } + } else { + pr_err("Not able to allocate memory for %d slimbus rx ports\n", + wcd9xxx->num_rx_port); + } + + if (!tx_num || tx_num > wcd9xxx->num_tx_port) { + pr_err("%s: invalid tx num %d\n", __func__, tx_num); + return -EINVAL; + } + if (wcd9xxx->tx_chs) { + wcd9xxx->num_tx_port = tx_num; + for (i = 0; i < tx_num; i++) { + wcd9xxx->tx_chs[i].ch_num = tx_slot[i]; + INIT_LIST_HEAD(&wcd9xxx->tx_chs[i].list); + } + ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la, + wcd9xxx->num_tx_port, + wcd9xxx->tx_chs, + SLIM_SRC); + if (ret) { + pr_err("%s: Failed to alloc %d tx slimbus channels\n", + __func__, wcd9xxx->num_tx_port); + kfree(wcd9xxx->tx_chs); + wcd9xxx->tx_chs = NULL; + wcd9xxx->num_tx_port = 0; + } + } else { + pr_err("Not able to allocate memory for %d slimbus tx ports\n", + wcd9xxx->num_tx_port); + } + return 0; +err: + return ret; +} +EXPORT_SYMBOL(wcd9xxx_init_slimslave); + +int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx) +{ + if (wcd9xxx->num_rx_port) { + wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim, + wcd9xxx->num_rx_port, + wcd9xxx->rx_chs); + wcd9xxx->num_rx_port = 0; + } + if (wcd9xxx->num_tx_port) { + wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim, + wcd9xxx->num_tx_port, + wcd9xxx->tx_chs); + wcd9xxx->num_tx_port = 0; + } + return 0; +} + + +static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx, + u8 wcd9xxx_pgd_la, u32 cnt, + struct wcd9xxx_ch *channels, u32 path) +{ + int ret = 0; + u32 ch_idx; + + /* The slimbus channel allocation seem take longer time + * so do the allocation up front to avoid delay in start of + * playback + */ + pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la); + for (ch_idx = 0; ch_idx < cnt; ch_idx++) { + ret = slim_get_slaveport(wcd9xxx_pgd_la, + channels[ch_idx].port, + &channels[ch_idx].sph, path); + pr_debug("%s: pgd_la[%d] channels[%d].port[%d]\n" + "channels[%d].sph[%d] path[%d]\n", + __func__, wcd9xxx_pgd_la, ch_idx, + channels[ch_idx].port, + ch_idx, channels[ch_idx].sph, path); + if (ret < 0) { + pr_err("%s: slave port failure id[%d] ret[%d]\n", + __func__, channels[ch_idx].ch_num, ret); + goto err; + } + + ret = slim_query_ch(wcd9xxx->slim, + channels[ch_idx].ch_num, + &channels[ch_idx].ch_h); + if (ret < 0) { + pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n", + __func__, channels[ch_idx].ch_num, ret); + goto err; + } + } +err: + return ret; +} + +static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim, + u32 cnt, struct wcd9xxx_ch *channels) +{ + int idx = 0; + int ret = 0; + /* slim_dealloc_ch */ + for (idx = 0; idx < cnt; idx++) { + ret = slim_dealloc_ch(slim, channels[idx].ch_h); + if (ret < 0) { + pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n", + __func__, ret, channels[idx].ch_h); + } + } + return ret; +} + +/* Enable slimbus slave device for RX path */ +int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, + struct list_head *wcd9xxx_ch_list, + unsigned int rate, unsigned int bit_width, + u16 *grph) +{ + u8 ch_cnt = 0; + u16 ch_h[SLIM_MAX_RX_PORTS] = {0}; + u8 payload = 0; + u16 codec_port = 0; + int ret; + struct slim_ch prop; + struct wcd9xxx_ch *rx; + int size = ARRAY_SIZE(ch_h); + + /* Configure slave interface device */ + + list_for_each_entry(rx, wcd9xxx_ch_list, list) { + payload |= 1 << rx->shift; + if (ch_cnt < size) { + ch_h[ch_cnt] = rx->ch_h; + ch_cnt++; + pr_debug("list ch->ch_h %d ch->sph %d\n", + rx->ch_h, rx->sph); + } else { + pr_err("%s: allocated channel number %u is out of max rangae %d\n", + __func__, ch_cnt, + size); + ret = EINVAL; + goto err; + } + } + pr_debug("%s: ch_cnt[%d] rate=%d WATER_MARK_VAL %d\n", + __func__, ch_cnt, rate, WATER_MARK_VAL); + /* slim_define_ch api */ + prop.prot = SLIM_AUTO_ISO; + if ((rate == 44100) || (rate == 88200) || (rate == 176400) || + (rate == 352800)) { + prop.baser = SLIM_RATE_11025HZ; + prop.ratem = (rate/11025); + } else { + prop.baser = SLIM_RATE_4000HZ; + prop.ratem = (rate/4000); + } + prop.dataf = SLIM_CH_DATAF_NOT_DEFINED; + prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE; + prop.sampleszbits = bit_width; + + pr_debug("Before slim_define_ch:\n" + "ch_cnt %d,ch_h[0] %d ch_h[1] %d, grph %d\n", + ch_cnt, ch_h[0], ch_h[1], *grph); + ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, + true, grph); + if (ret < 0) { + pr_err("%s: slim_define_ch failed ret[%d]\n", + __func__, ret); + goto err; + } + + list_for_each_entry(rx, wcd9xxx_ch_list, list) { + codec_port = rx->port; + pr_debug("%s: codec_port %d rx 0x%p, payload %d\n" + "sh_ch.rx_port_ch_reg_base0 0x%x\n" + "sh_ch.port_rx_cfg_reg_base 0x%x\n", + __func__, codec_port, rx, payload, + sh_ch.rx_port_ch_reg_base, + sh_ch.port_rx_cfg_reg_base); + + /* look for the valid port range and chose the + * payload accordingly + */ + /* write to interface device */ + ret = wcd9xxx_interface_reg_write(wcd9xxx, + SB_PGD_RX_PORT_MULTI_CHANNEL_0( + sh_ch.rx_port_ch_reg_base, codec_port), + payload); + + if (ret < 0) { + pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n", + __func__, + SB_PGD_RX_PORT_MULTI_CHANNEL_0( + sh_ch.rx_port_ch_reg_base, codec_port), + payload, ret); + goto err; + } + /* configure the slave port for water mark and enable*/ + ret = wcd9xxx_interface_reg_write(wcd9xxx, + SB_PGD_PORT_CFG_BYTE_ADDR( + sh_ch.port_rx_cfg_reg_base, codec_port), + WATER_MARK_VAL); + if (ret < 0) { + pr_err("%s:watermark set failure for port[%d] ret[%d]", + __func__, codec_port, ret); + } + + ret = slim_connect_sink(wcd9xxx->slim, &rx->sph, 1, rx->ch_h); + if (ret < 0) { + pr_err("%s: slim_connect_sink failed ret[%d]\n", + __func__, ret); + goto err_close_slim_sch; + } + } + /* slim_control_ch */ + ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE, + true); + if (ret < 0) { + pr_err("%s: slim_control_ch failed ret[%d]\n", + __func__, ret); + goto err_close_slim_sch; + } + return 0; + +err_close_slim_sch: + /* release all acquired handles */ + wcd9xxx_close_slim_sch_rx(wcd9xxx, wcd9xxx_ch_list, *grph); +err: + return ret; +} +EXPORT_SYMBOL(wcd9xxx_cfg_slim_sch_rx); + +/* Enable slimbus slave device for RX path */ +int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, + struct list_head *wcd9xxx_ch_list, + unsigned int rate, unsigned int bit_width, + u16 *grph) +{ + u16 ch_cnt = 0; + u16 payload = 0; + u16 ch_h[SLIM_MAX_TX_PORTS] = {0}; + u16 codec_port; + int ret = 0; + struct wcd9xxx_ch *tx; + int size = ARRAY_SIZE(ch_h); + + struct slim_ch prop; + + list_for_each_entry(tx, wcd9xxx_ch_list, list) { + payload |= 1 << tx->shift; + if (ch_cnt < size) { + ch_h[ch_cnt] = tx->ch_h; + ch_cnt++; + } else { + pr_err("%s: allocated channel number %u is out of max rangae %d\n", + __func__, ch_cnt, + size); + ret = EINVAL; + goto err; + } + } + + /* slim_define_ch api */ + prop.prot = SLIM_AUTO_ISO; + prop.baser = SLIM_RATE_4000HZ; + prop.dataf = SLIM_CH_DATAF_NOT_DEFINED; + prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE; + prop.ratem = (rate/4000); + prop.sampleszbits = bit_width; + ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, + true, grph); + if (ret < 0) { + pr_err("%s: slim_define_ch failed ret[%d]\n", + __func__, ret); + goto err; + } + + pr_debug("%s: ch_cnt[%d] rate[%d] bitwidth[%u]\n", __func__, ch_cnt, + rate, bit_width); + list_for_each_entry(tx, wcd9xxx_ch_list, list) { + codec_port = tx->port; + pr_debug("%s: codec_port %d tx 0x%p, payload 0x%x\n", + __func__, codec_port, tx, payload); + /* write to interface device */ + ret = wcd9xxx_interface_reg_write(wcd9xxx, + SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port), + payload & 0x00FF); + if (ret < 0) { + pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n", + __func__, + SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port), + payload, ret); + goto err; + } + /* ports 8,9 */ + ret = wcd9xxx_interface_reg_write(wcd9xxx, + SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port), + (payload & 0xFF00)>>8); + if (ret < 0) { + pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n", + __func__, + SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port), + payload, ret); + goto err; + } + /* configure the slave port for water mark and enable*/ + ret = wcd9xxx_interface_reg_write(wcd9xxx, + SB_PGD_PORT_CFG_BYTE_ADDR( + sh_ch.port_tx_cfg_reg_base, codec_port), + WATER_MARK_VAL); + if (ret < 0) { + pr_err("%s:watermark set failure for port[%d] ret[%d]", + __func__, codec_port, ret); + } + + ret = slim_connect_src(wcd9xxx->slim, tx->sph, tx->ch_h); + + if (ret < 0) { + pr_err("%s: slim_connect_src failed ret[%d]\n", + __func__, ret); + goto err; + } + } + /* slim_control_ch */ + ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE, + true); + if (ret < 0) { + pr_err("%s: slim_control_ch failed ret[%d]\n", + __func__, ret); + goto err; + } + return 0; +err: + /* release all acquired handles */ + wcd9xxx_close_slim_sch_tx(wcd9xxx, wcd9xxx_ch_list, *grph); + return ret; +} +EXPORT_SYMBOL(wcd9xxx_cfg_slim_sch_tx); + +int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, + struct list_head *wcd9xxx_ch_list, u16 grph) +{ + u32 sph[SLIM_MAX_RX_PORTS] = {0}; + int ch_cnt = 0; + int ret = 0; + struct wcd9xxx_ch *rx; + + list_for_each_entry(rx, wcd9xxx_ch_list, list) + sph[ch_cnt++] = rx->sph; + + pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n", __func__, ch_cnt, + sph[0], sph[1]); + + /* slim_control_ch (REMOVE) */ + pr_debug("%s before slim_control_ch grph %d\n", __func__, grph); + ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true); + if (ret < 0) { + pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret); + goto err; + } +err: + return ret; +} +EXPORT_SYMBOL(wcd9xxx_close_slim_sch_rx); + +int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, + struct list_head *wcd9xxx_ch_list, + u16 grph) +{ + u32 sph[SLIM_MAX_TX_PORTS] = {0}; + int ret = 0; + int ch_cnt = 0; + struct wcd9xxx_ch *tx; + + pr_debug("%s\n", __func__); + list_for_each_entry(tx, wcd9xxx_ch_list, list) + sph[ch_cnt++] = tx->sph; + + pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n", + __func__, ch_cnt, sph[0], sph[1]); + /* slim_control_ch (REMOVE) */ + ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true); + if (ret < 0) { + pr_err("%s: slim_control_ch failed ret[%d]\n", + __func__, ret); + goto err; + } +err: + return ret; +} +EXPORT_SYMBOL(wcd9xxx_close_slim_sch_tx); + +int wcd9xxx_get_slave_port(unsigned int ch_num) +{ + int ret = 0; + + ret = (ch_num - BASE_CH_NUM); + pr_debug("%s: ch_num[%d] slave port[%d]\n", __func__, ch_num, ret); + if (ret < 0) { + pr_err("%s: Error:- Invalid slave port found = %d\n", + __func__, ret); + return -EINVAL; + } + return ret; +} +EXPORT_SYMBOL(wcd9xxx_get_slave_port); + +int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx, + struct list_head *wcd9xxx_ch_list, u16 grph) +{ + u32 sph[SLIM_MAX_TX_PORTS + SLIM_MAX_RX_PORTS] = {0}; + int ch_cnt = 0; + int ret = 0; + struct wcd9xxx_ch *slim_ch; + + list_for_each_entry(slim_ch, wcd9xxx_ch_list, list) + sph[ch_cnt++] = slim_ch->sph; + + /* slim_disconnect_port */ + ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt); + if (ret < 0) { + pr_err("%s: slim_disconnect_ports failed ret[%d]\n", + __func__, ret); + } + return ret; +} +EXPORT_SYMBOL(wcd9xxx_disconnect_port); + +/* This function is called with mutex acquired */ +int wcd9xxx_rx_vport_validation(u32 port_id, + struct list_head *codec_dai_list) +{ + struct wcd9xxx_ch *ch; + int ret = 0; + + pr_debug("%s: port_id %u\n", __func__, port_id); + + list_for_each_entry(ch, + codec_dai_list, list) { + pr_debug("%s: ch->port %u\n", __func__, ch->port); + if (ch->port == port_id) { + ret = -EINVAL; + break; + } + } + return ret; +} +EXPORT_SYMBOL(wcd9xxx_rx_vport_validation); + + +/* This function is called with mutex acquired */ +int wcd9xxx_tx_vport_validation(u32 table, u32 port_id, + struct wcd9xxx_codec_dai_data *codec_dai, + u32 num_codec_dais) +{ + struct wcd9xxx_ch *ch; + int ret = 0; + u32 index; + unsigned long vtable = table; + u32 size = sizeof(table) * BITS_PER_BYTE; + + pr_debug("%s: vtable 0x%lx port_id %u size %d\n", __func__, + vtable, port_id, size); + for_each_set_bit(index, &vtable, size) { + if (index < num_codec_dais) { + list_for_each_entry(ch, + &codec_dai[index].wcd9xxx_ch_list, + list) { + pr_debug("%s: index %u ch->port %u vtable 0x%lx\n", + __func__, index, ch->port, + vtable); + if (ch->port == port_id) { + pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n", + __func__, port_id + 1, + (index + 1)/2); + ret = -EINVAL; + break; + } + } + } else { + pr_err("%s: Invalid index %d of codec dai", + __func__, index); + ret = -EINVAL; + } + if (ret) + break; + } + return ret; +} +EXPORT_SYMBOL(wcd9xxx_tx_vport_validation); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-soc-init.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-soc-init.c new file mode 100644 index 0000000000..b9c4486148 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-soc-init.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, 2021 The Linux Foundation. All rights reserved. + */ + +#include +#include "audio-ext-clk-up.h" + +static int __init wcd9xxx_soc_init(void) +{ + int ret = 0; + + ret = audio_ref_clk_platform_init(); + if (ret) + pr_err("%s: init extclk fail: %d\n", __func__, ret); + + return ret; +} +module_init(wcd9xxx_soc_init); + +static void __exit wcd9xxx_soc_exit(void) +{ + audio_ref_clk_platform_exit(); +} +module_exit(wcd9xxx_soc_exit); + +MODULE_DESCRIPTION("WCD9XXX CODEC soc init driver"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-utils.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-utils.c new file mode 100644 index 0000000000..face7118df --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-utils.c @@ -0,0 +1,1224 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd9xxx-utils.h" + +#define REG_BYTES 2 +#define VAL_BYTES 1 +/* + * Page Register Address that APP Proc uses to + * access WCD9335 Codec registers is identified + * as 0x00 + */ +#define PAGE_REG_ADDR 0x00 + +static enum wcd9xxx_intf_status wcd9xxx_intf = -1; + +static struct mfd_cell tavil_devs[] = { + { + .name = "qcom-wcd-pinctrl", + .of_compatible = "qcom,wcd-pinctrl", + }, + { + .name = "tavil_codec", + }, +}; + +static struct mfd_cell tasha_devs[] = { + { + .name = "tasha_codec", + }, +}; + +static struct mfd_cell tomtom_devs[] = { + { + .name = "tomtom_codec", + }, +}; + +static int wcd9xxx_read_of_property_u32(struct device *dev, const char *name, + u32 *val) +{ + int rc = 0; + + rc = of_property_read_u32(dev->of_node, name, val); + if (rc) + dev_err(dev, "%s: Looking up %s property in node %s failed", + __func__, name, dev->of_node->full_name); + + return rc; +} + +static void wcd9xxx_dt_parse_micbias_info(struct device *dev, + struct wcd9xxx_micbias_setting *mb) +{ + u32 prop_val; + int rc; + + if (of_find_property(dev->of_node, "qcom,cdc-micbias-ldoh-v", NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias-ldoh-v", + &prop_val); + if (!rc) + mb->ldoh_v = (u8)prop_val; + } + + /* MB1 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt1-mv", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias-cfilt1-mv", + &prop_val); + if (!rc) + mb->cfilt1_mv = prop_val; + + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias1-cfilt-sel", + &prop_val); + if (!rc) + mb->bias1_cfilt_sel = (u8)prop_val; + + } else if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias1-mv", + &prop_val); + if (!rc) + mb->micb1_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias1 DT property not found\n", + __func__); + } + + /* MB2 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt2-mv", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias-cfilt2-mv", + &prop_val); + if (!rc) + mb->cfilt2_mv = prop_val; + + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias2-cfilt-sel", + &prop_val); + if (!rc) + mb->bias2_cfilt_sel = (u8)prop_val; + + } else if (of_find_property(dev->of_node, "qcom,cdc-micbias2-mv", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias2-mv", + &prop_val); + if (!rc) + mb->micb2_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias2 DT property not found\n", + __func__); + } + + /* MB3 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt3-mv", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias-cfilt3-mv", + &prop_val); + if (!rc) + mb->cfilt3_mv = prop_val; + + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias3-cfilt-sel", + &prop_val); + if (!rc) + mb->bias3_cfilt_sel = (u8)prop_val; + + } else if (of_find_property(dev->of_node, "qcom,cdc-micbias3-mv", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias3-mv", + &prop_val); + if (!rc) + mb->micb3_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias3 DT property not found\n", + __func__); + } + + /* MB4 */ + if (of_find_property(dev->of_node, "qcom,cdc-micbias4-cfilt-sel", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias4-cfilt-sel", + &prop_val); + if (!rc) + mb->bias4_cfilt_sel = (u8)prop_val; + + } else if (of_find_property(dev->of_node, "qcom,cdc-micbias4-mv", + NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-micbias4-mv", + &prop_val); + if (!rc) + mb->micb4_mv = prop_val; + } else { + dev_info(dev, "%s: Micbias4 DT property not found\n", + __func__); + } + + mb->bias1_cap_mode = + (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ? + MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP); + mb->bias2_cap_mode = + (of_property_read_bool(dev->of_node, "qcom,cdc-micbias2-ext-cap") ? + MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP); + mb->bias3_cap_mode = + (of_property_read_bool(dev->of_node, "qcom,cdc-micbias3-ext-cap") ? + MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP); + mb->bias4_cap_mode = + (of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ? + MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP); + + mb->bias2_is_headset_only = + of_property_read_bool(dev->of_node, + "qcom,cdc-micbias2-headset-only"); + + /* Print micbias info */ + dev_dbg(dev, "%s: ldoh_v %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u", + __func__, (u32)mb->ldoh_v, (u32)mb->cfilt1_mv, + (u32)mb->cfilt2_mv, (u32)mb->cfilt3_mv); + + dev_dbg(dev, "%s: micb1_mv %u micb2_mv %u micb3_mv %u micb4_mv %u", + __func__, mb->micb1_mv, mb->micb2_mv, + mb->micb3_mv, mb->micb4_mv); + + dev_dbg(dev, "%s: bias1_cfilt_sel %u bias2_cfilt_sel %u\n", + __func__, (u32)mb->bias1_cfilt_sel, (u32)mb->bias2_cfilt_sel); + + dev_dbg(dev, "%s: bias3_cfilt_sel %u bias4_cfilt_sel %u\n", + __func__, (u32)mb->bias3_cfilt_sel, (u32)mb->bias4_cfilt_sel); + + dev_dbg(dev, "%s: bias1_ext_cap %d bias2_ext_cap %d\n", + __func__, mb->bias1_cap_mode, mb->bias2_cap_mode); + + dev_dbg(dev, "%s: bias3_ext_cap %d bias4_ext_cap %d\n", + __func__, mb->bias3_cap_mode, mb->bias4_cap_mode); + + dev_dbg(dev, "%s: bias2_is_headset_only %d\n", + __func__, mb->bias2_is_headset_only); +} + +/* + * wcd9xxx_validate_dmic_sample_rate: + * Given the dmic_sample_rate and mclk rate, validate the + * dmic_sample_rate. If dmic rate is found to be invalid, + * assign the dmic rate as undefined, so individual codec + * drivers can use their own defaults + * @dev: the device for which the dmic is to be configured + * @dmic_sample_rate: The input dmic_sample_rate + * @mclk_rate: The input codec mclk rate + * @dmic_rate_type: String to indicate the type of dmic sample + * rate, used for debug/error logging. + */ +static u32 wcd9xxx_validate_dmic_sample_rate(struct device *dev, + u32 dmic_sample_rate, u32 mclk_rate, + const char *dmic_rate_type) +{ + u32 div_factor; + + if (dmic_sample_rate == WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED || + mclk_rate % dmic_sample_rate != 0) + goto undefined_rate; + + div_factor = mclk_rate / dmic_sample_rate; + + switch (div_factor) { + case 2: + case 3: + case 4: + case 8: + case 16: + /* Valid dmic DIV factors */ + dev_dbg(dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n", + __func__, div_factor, mclk_rate); + break; + case 6: + /* + * DIV 6 is valid for both 9.6MHz and 12.288MHz + * MCLK on Tavil. Older codecs support DIV6 only + * for 12.288MHz MCLK. + */ + if ((mclk_rate == WCD9XXX_MCLK_CLK_9P6HZ) && + (of_device_is_compatible(dev->of_node, + "qcom,tavil-slim-pgd"))) + dev_dbg(dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n", + __func__, div_factor, mclk_rate); + else if (mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) + goto undefined_rate; + break; + default: + /* Any other DIV factor is invalid */ + goto undefined_rate; + } + + return dmic_sample_rate; + +undefined_rate: + dev_dbg(dev, "%s: Invalid %s = %d, for mclk %d\n", + __func__, dmic_rate_type, dmic_sample_rate, mclk_rate); + dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED; + + return dmic_sample_rate; +} + +/* + * wcd9xxx_populate_dt_data: + * Parse device tree properties for the given codec device + * + * @dev: pointer to codec device + * + * Returns pointer to the platform data resulting from parsing + * device tree. + */ +struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev) +{ + struct wcd9xxx_pdata *pdata; + u32 dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED; + u32 mad_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED; + u32 ecpp_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED; + u32 dmic_clk_drive = WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED; + u32 prop_val; + int rc = 0; + + if (!dev || !dev->of_node) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(struct wcd9xxx_pdata), + GFP_KERNEL); + if (!pdata) + return NULL; + + /* Parse power supplies */ + msm_cdc_get_power_supplies(dev, &pdata->regulator, + &pdata->num_supplies); + if (!pdata->regulator || (pdata->num_supplies <= 0)) { + dev_err(dev, "%s: no power supplies defined for codec\n", + __func__); + goto err_power_sup; + } + + /* Parse micbias info */ + wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias); + + pdata->wcd_rst_np = of_parse_phandle(dev->of_node, + "qcom,wcd-rst-gpio-node", 0); + if (!pdata->wcd_rst_np) { + dev_err(dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,wcd-rst-gpio-node", + dev->of_node->full_name); + goto err_parse_dt_prop; + } + + pdata->has_buck_vsel_gpio = of_property_read_bool(dev->of_node, + "qcom,has-buck-vsel-gpio"); + if (pdata->has_buck_vsel_gpio) { + pdata->buck_vsel_ctl_np = of_parse_phandle(dev->of_node, + "qcom,buck-vsel-gpio-node", 0); + if (!pdata->buck_vsel_ctl_np) { + dev_err(dev, "%s No entry for %s property in node %s\n", + __func__, "qcom,buck-vsel-gpio-node", + dev->of_node->full_name); + goto err_parse_dt_prop; + } + } + + pdata->has_micb_supply_en_gpio = of_property_read_bool(dev->of_node, + "qcom,has-micbias-supply-en-gpio"); + if (pdata->has_micb_supply_en_gpio) { + pdata->micb_en_ctl = of_parse_phandle(dev->of_node, + "qcom,micbias-supply-en-gpio-node", 0); + if (!pdata->micb_en_ctl) { + dev_err(dev, "%s No entry for %s property in node %s\n", + __func__, "qcom,micbias-supply-en-gpio-node", + dev->of_node->full_name); + goto err_parse_dt_prop; + } + } + + if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-mclk-clk-rate", + &prop_val))) + pdata->mclk_rate = prop_val; + + if (pdata->mclk_rate != WCD9XXX_MCLK_CLK_9P6HZ && + pdata->mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) { + dev_err(dev, "%s: Invalid mclk_rate = %u\n", __func__, + pdata->mclk_rate); + goto err_parse_dt_prop; + } + + if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-dmic-sample-rate", + &prop_val))) + dmic_sample_rate = prop_val; + + pdata->dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev, + dmic_sample_rate, + pdata->mclk_rate, + "audio_dmic_rate"); + if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-mad-dmic-rate", + &prop_val))) + mad_dmic_sample_rate = prop_val; + + pdata->mad_dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev, + mad_dmic_sample_rate, + pdata->mclk_rate, + "mad_dmic_rate"); + + if (of_find_property(dev->of_node, "qcom,cdc-ecpp-dmic-rate", NULL)) { + rc = wcd9xxx_read_of_property_u32(dev, + "qcom,cdc-ecpp-dmic-rate", + &prop_val); + if (!rc) + ecpp_dmic_sample_rate = prop_val; + } + + pdata->ecpp_dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev, + ecpp_dmic_sample_rate, + pdata->mclk_rate, + "ecpp_dmic_rate"); + + if (!(of_property_read_u32(dev->of_node, + "qcom,cdc-dmic-clk-drv-strength", + &prop_val))) { + dmic_clk_drive = prop_val; + + if (dmic_clk_drive != 2 && dmic_clk_drive != 4 && + dmic_clk_drive != 8 && dmic_clk_drive != 16) + dev_err(dev, "Invalid cdc-dmic-clk-drv-strength %d\n", + dmic_clk_drive); + } + + pdata->dmic_clk_drv = dmic_clk_drive; + + rc = of_property_read_u32(dev->of_node, + "qcom,vote-dynamic-supply-on-demand", + &pdata->vote_regulator_on_demand); + if (rc) + dev_dbg(dev, "%s No entry for %s property in node %s\n", + __func__, "qcom,vote-dynamic-supply-on-demand", + dev->of_node->full_name); + + return pdata; + +err_parse_dt_prop: + devm_kfree(dev, pdata->regulator); + pdata->regulator = NULL; + pdata->num_supplies = 0; +err_power_sup: + devm_kfree(dev, pdata); + return NULL; +} +EXPORT_SYMBOL(wcd9xxx_populate_dt_data); + +static bool is_wcd9xxx_reg_power_down(struct wcd9xxx *wcd9xxx, u16 rreg) +{ + bool ret = false; + int i; + struct wcd9xxx_power_region *wcd9xxx_pwr; + + if (!wcd9xxx) + return ret; + + for (i = 0; i < WCD9XXX_MAX_PWR_REGIONS; i++) { + wcd9xxx_pwr = wcd9xxx->wcd9xxx_pwr[i]; + if (!wcd9xxx_pwr) + continue; + if (((wcd9xxx_pwr->pwr_collapse_reg_min == 0) && + (wcd9xxx_pwr->pwr_collapse_reg_max == 0)) || + (wcd9xxx_pwr->power_state == + WCD_REGION_POWER_COLLAPSE_REMOVE)) + ret = false; + else if (((wcd9xxx_pwr->power_state == + WCD_REGION_POWER_DOWN) || + (wcd9xxx_pwr->power_state == + WCD_REGION_POWER_COLLAPSE_BEGIN)) && + (rreg >= wcd9xxx_pwr->pwr_collapse_reg_min) && + (rreg <= wcd9xxx_pwr->pwr_collapse_reg_max)) + ret = true; + } + return ret; +} + +/* + * wcd9xxx_page_write: + * Retrieve page number from register and + * write that page number to the page address. + * Called under io_lock acquisition. + * + * @wcd9xxx: pointer to wcd9xxx + * @reg: Register address from which page number is retrieved + * + * Returns 0 for success and negative error code for failure. + */ +int wcd9xxx_page_write(struct wcd9xxx *wcd9xxx, unsigned short *reg) +{ + int ret = 0; + unsigned short c_reg, reg_addr; + u8 pg_num, prev_pg_num; + + if (wcd9xxx->type != WCD9335 && wcd9xxx->type != WCD934X) + return ret; + + c_reg = *reg; + pg_num = c_reg >> 8; + reg_addr = c_reg & 0xff; + if (wcd9xxx->prev_pg_valid) { + prev_pg_num = wcd9xxx->prev_pg; + if (prev_pg_num != pg_num) { + ret = wcd9xxx->write_dev( + wcd9xxx, PAGE_REG_ADDR, 1, + (void *) &pg_num, false); + if (ret < 0) + pr_err("page write error, pg_num: 0x%x\n", + pg_num); + else { + wcd9xxx->prev_pg = pg_num; + dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n", + __func__, pg_num); + } + } + } else { + ret = wcd9xxx->write_dev( + wcd9xxx, PAGE_REG_ADDR, 1, (void *) &pg_num, + false); + if (ret < 0) + pr_err("page write error, pg_num: 0x%x\n", pg_num); + else { + wcd9xxx->prev_pg = pg_num; + wcd9xxx->prev_pg_valid = true; + dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n", + __func__, pg_num); + } + } + *reg = reg_addr; + return ret; +} +EXPORT_SYMBOL(wcd9xxx_page_write); + +static int regmap_bus_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev); + unsigned short c_reg, rreg; + int ret, i; + + if (!wcd9xxx) { + dev_err(dev, "%s: wcd9xxx is NULL\n", __func__); + return -EINVAL; + } + if (!reg || !val) { + dev_err(dev, "%s: reg or val is NULL\n", __func__); + return -EINVAL; + } + + if (reg_size != REG_BYTES) { + dev_err(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return -EINVAL; + } + + mutex_lock(&wcd9xxx->io_lock); + c_reg = *(u16 *)reg; + rreg = c_reg; + + if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) { + ret = 0; + for (i = 0; i < val_size; i++) + ((u8 *)val)[i] = 0; + goto err; + } + ret = wcd9xxx_page_write(wcd9xxx, &c_reg); + if (ret) + goto err; + ret = wcd9xxx->read_dev(wcd9xxx, c_reg, val_size, val, false); + if (ret < 0) + dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n", + __func__, ret, rreg, val_size); + else { + for (i = 0; i < val_size; i++) + dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n", + __func__, ((u8 *)val)[i], rreg + i); + } +err: + mutex_unlock(&wcd9xxx->io_lock); + + return ret; +} + +static int regmap_bus_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) +{ + struct device *dev = context; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev); + unsigned short c_reg, rreg; + int ret, i; + + if (!wcd9xxx) { + dev_err(dev, "%s: wcd9xxx is NULL\n", __func__); + return -EINVAL; + } + if (!reg || !val) { + dev_err(dev, "%s: reg or val is NULL\n", __func__); + return -EINVAL; + } + if (reg_size != REG_BYTES) { + dev_err(dev, "%s: register size %zd bytes, not supported\n", + __func__, reg_size); + return -EINVAL; + } + mutex_lock(&wcd9xxx->io_lock); + c_reg = *(u16 *)reg; + rreg = c_reg; + + if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) { + ret = 0; + goto err; + } + ret = wcd9xxx_page_write(wcd9xxx, &c_reg); + if (ret) + goto err; + + for (i = 0; i < val_size; i++) + dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i], + rreg + i); + + ret = wcd9xxx->write_dev(wcd9xxx, c_reg, val_size, (void *) val, + false); + if (ret < 0) + dev_err(dev, "%s: Codec write failed (%d), reg:0x%x, size:%zd\n", + __func__, ret, rreg, val_size); + +err: + mutex_unlock(&wcd9xxx->io_lock); + return ret; +} + +static int regmap_bus_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev); + + if (!wcd9xxx) + return -EINVAL; + + WARN_ON(count < REG_BYTES); + + if (count > (REG_BYTES + VAL_BYTES)) { + if (wcd9xxx->multi_reg_write) + return wcd9xxx->multi_reg_write(wcd9xxx, + data, count); + } else + return regmap_bus_gather_write(context, data, REG_BYTES, + data + REG_BYTES, + count - REG_BYTES); + + dev_err(dev, "%s: bus multi reg write failure\n", __func__); + + return -EINVAL; +} + +static struct regmap_bus regmap_bus_config = { + .write = regmap_bus_write, + .gather_write = regmap_bus_gather_write, + .read = regmap_bus_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +/* + * wcd9xxx_regmap_init: + * Initialize wcd9xxx register map + * + * @dev: pointer to wcd device + * @config: pointer to register map config + * + * Returns pointer to regmap structure for success + * or NULL in case of failure. + */ +struct regmap *wcd9xxx_regmap_init(struct device *dev, + const struct regmap_config *config) +{ + return devm_regmap_init(dev, ®map_bus_config, dev, config); +} +EXPORT_SYMBOL(wcd9xxx_regmap_init); + +/* + * wcd9xxx_reset: + * Reset wcd9xxx codec + * + * @dev: pointer to wcd device + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_reset(struct device *dev) +{ + struct wcd9xxx *wcd9xxx; + int rc; + int value; + + if (!dev) + return -ENODEV; + + wcd9xxx = dev_get_drvdata(dev); + if (!wcd9xxx) + return -EINVAL; + + if (!wcd9xxx->wcd_rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + value = msm_cdc_pinctrl_get_state(wcd9xxx->wcd_rst_np); + if (value > 0) { + wcd9xxx->avoid_cdc_rstlow = 1; + return 0; + } + + rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np); + if (rc) { + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + return rc; + } + + /* 20ms sleep required after pulling the reset gpio to LOW */ + msleep(20); + + rc = msm_cdc_pinctrl_select_active_state(wcd9xxx->wcd_rst_np); + if (rc) { + dev_err(dev, "%s: wcd active state request fail!\n", + __func__); + return rc; + } + msleep(20); + + return rc; +} +EXPORT_SYMBOL(wcd9xxx_reset); + +/* + * wcd9xxx_reset_low: + * Pull the wcd9xxx codec reset_n to low + * + * @dev: pointer to wcd device + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_reset_low(struct device *dev) +{ + struct wcd9xxx *wcd9xxx; + int rc; + + if (!dev) + return -ENODEV; + + wcd9xxx = dev_get_drvdata(dev); + if (!wcd9xxx) + return -EINVAL; + + if (!wcd9xxx->wcd_rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + if (wcd9xxx->avoid_cdc_rstlow) { + wcd9xxx->avoid_cdc_rstlow = 0; + dev_dbg(dev, "%s: avoid pull down of reset GPIO\n", __func__); + return 0; + } + + rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np); + if (rc) + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + + return rc; +} +EXPORT_SYMBOL(wcd9xxx_reset_low); + +/* + * wcd9xxx_bringup: + * Toggle reset analog and digital cores of wcd9xxx codec + * + * @dev: pointer to wcd device + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_bringup(struct device *dev) +{ + struct wcd9xxx *wcd9xxx; + int rc; + codec_bringup_fn cdc_bup_fn; + + if (!dev) + return -ENODEV; + + wcd9xxx = dev_get_drvdata(dev); + if (!wcd9xxx) + return -EINVAL; + + cdc_bup_fn = wcd9xxx_bringup_fn(wcd9xxx->type); + if (!cdc_bup_fn) { + dev_err(dev, "%s: Codec bringup fn NULL!\n", + __func__); + return -EINVAL; + } + rc = cdc_bup_fn(wcd9xxx); + if (rc) + dev_err(dev, "%s: Codec bringup error, rc: %d\n", + __func__, rc); + + return rc; +} +EXPORT_SYMBOL(wcd9xxx_bringup); + +/* + * wcd9xxx_bringup: + * Set analog and digital cores of wcd9xxx codec in reset state + * + * @dev: pointer to wcd device + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_bringdown(struct device *dev) +{ + struct wcd9xxx *wcd9xxx; + int rc; + codec_bringdown_fn cdc_bdown_fn; + + if (!dev) + return -ENODEV; + + wcd9xxx = dev_get_drvdata(dev); + if (!wcd9xxx) + return -EINVAL; + + cdc_bdown_fn = wcd9xxx_bringdown_fn(wcd9xxx->type); + if (!cdc_bdown_fn) { + dev_err(dev, "%s: Codec bring down fn NULL!\n", + __func__); + return -EINVAL; + } + rc = cdc_bdown_fn(wcd9xxx); + if (rc) + dev_err(dev, "%s: Codec bring down error, rc: %d\n", + __func__, rc); + + return rc; +} +EXPORT_SYMBOL(wcd9xxx_bringdown); + +/* + * wcd9xxx_get_codec_info: + * Fill codec specific information like interrupts, version + * + * @dev: pointer to wcd device + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_get_codec_info(struct device *dev) +{ + struct wcd9xxx *wcd9xxx; + int rc; + codec_type_fn cdc_type_fn; + struct wcd9xxx_codec_type *cinfo; + + if (!dev) + return -ENODEV; + + wcd9xxx = dev_get_drvdata(dev); + if (!wcd9xxx) + return -EINVAL; + + cdc_type_fn = wcd9xxx_get_codec_info_fn(wcd9xxx->type); + if (!cdc_type_fn) { + dev_err(dev, "%s: Codec fill type fn NULL!\n", + __func__); + return -EINVAL; + } + + cinfo = wcd9xxx->codec_type; + if (!cinfo) + return -EINVAL; + + rc = cdc_type_fn(wcd9xxx, cinfo); + if (rc) { + dev_err(dev, "%s: Codec type fill failed, rc:%d\n", + __func__, rc); + return rc; + + } + + switch (wcd9xxx->type) { + case WCD934X: + cinfo->dev = tavil_devs; + cinfo->size = ARRAY_SIZE(tavil_devs); + break; + case WCD9335: + cinfo->dev = tasha_devs; + cinfo->size = ARRAY_SIZE(tasha_devs); + break; + case WCD9330: + cinfo->dev = tomtom_devs; + cinfo->size = ARRAY_SIZE(tomtom_devs); + break; + default: + cinfo->dev = NULL; + cinfo->size = 0; + break; + } + + return rc; +} +EXPORT_SYMBOL(wcd9xxx_get_codec_info); + +/* + * wcd9xxx_core_irq_init: + * Initialize wcd9xxx codec irq instance + * + * @wcd9xxx_core_res: pointer to wcd core resource + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_core_irq_init( + struct wcd9xxx_core_resource *wcd9xxx_core_res) +{ + int ret = 0; + + if (!wcd9xxx_core_res) + return -EINVAL; + + if (wcd9xxx_core_res->irq != 1) { + ret = wcd9xxx_irq_init(wcd9xxx_core_res); + if (ret) + pr_err("IRQ initialization failed\n"); + } + + return ret; +} +EXPORT_SYMBOL(wcd9xxx_core_irq_init); + +/* + * wcd9xxx_assign_irq: + * Assign irq and irq_base to wcd9xxx core resource + * + * @wcd9xxx_core_res: pointer to wcd core resource + * @irq: irq number + * @irq_base: base irq number + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_assign_irq( + struct wcd9xxx_core_resource *wcd9xxx_core_res, + unsigned int irq, + unsigned int irq_base) +{ + if (!wcd9xxx_core_res) + return -EINVAL; + + wcd9xxx_core_res->irq = irq; + wcd9xxx_core_res->irq_base = irq_base; + + return 0; +} +EXPORT_SYMBOL(wcd9xxx_assign_irq); + +/* + * wcd9xxx_core_res_init: + * Initialize wcd core resource instance + * + * @wcd9xxx_core_res: pointer to wcd core resource + * @num_irqs: number of irqs for wcd9xxx core + * @num_irq_regs: number of irq registers + * @wcd_regmap: pointer to the wcd register map + * + * Returns 0 for success or negative error code in case of failure + */ +int wcd9xxx_core_res_init( + struct wcd9xxx_core_resource *wcd9xxx_core_res, + int num_irqs, int num_irq_regs, struct regmap *wcd_regmap) +{ + if (!wcd9xxx_core_res || !wcd_regmap) + return -EINVAL; + + mutex_init(&wcd9xxx_core_res->pm_lock); + wcd9xxx_core_res->wlock_holders = 0; + wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE; + init_waitqueue_head(&wcd9xxx_core_res->pm_wq); + pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + + wcd9xxx_core_res->num_irqs = num_irqs; + wcd9xxx_core_res->num_irq_regs = num_irq_regs; + wcd9xxx_core_res->wcd_core_regmap = wcd_regmap; + + pr_debug("%s: num_irqs = %d, num_irq_regs = %d\n", + __func__, wcd9xxx_core_res->num_irqs, + wcd9xxx_core_res->num_irq_regs); + + return 0; +} +EXPORT_SYMBOL(wcd9xxx_core_res_init); + +/* + * wcd9xxx_core_res_deinit: + * Deinit wcd core resource instance + * + * @wcd9xxx_core_res: pointer to wcd core resource + */ +void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res) +{ + if (!wcd9xxx_core_res) + return; + + pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req); + mutex_destroy(&wcd9xxx_core_res->pm_lock); +} +EXPORT_SYMBOL(wcd9xxx_core_res_deinit); + +/* + * wcd9xxx_pm_cmpxchg: + * Check old state and exchange with pm new state + * if old state matches with current state + * + * @wcd9xxx_core_res: pointer to wcd core resource + * @o: pm old state + * @n: pm new state + * + * Returns old state + */ +enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg( + struct wcd9xxx_core_resource *wcd9xxx_core_res, + enum wcd9xxx_pm_state o, + enum wcd9xxx_pm_state n) +{ + enum wcd9xxx_pm_state old; + + if (!wcd9xxx_core_res) + return o; + + mutex_lock(&wcd9xxx_core_res->pm_lock); + old = wcd9xxx_core_res->pm_state; + if (old == o) + wcd9xxx_core_res->pm_state = n; + mutex_unlock(&wcd9xxx_core_res->pm_lock); + + return old; +} +EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg); + +/* + * wcd9xxx_core_res_suspend: + * Suspend callback function for wcd9xxx core + * + * @wcd9xxx_core_res: pointer to wcd core resource + * @pm_message_t: pm message + * + * Returns 0 for success or negative error code for failure/busy + */ +int wcd9xxx_core_res_suspend( + struct wcd9xxx_core_resource *wcd9xxx_core_res, + pm_message_t pmesg) +{ + int ret = 0; + + pr_debug("%s: enter\n", __func__); + /* + * pm_qos_update_request() can be called after this suspend chain call + * started. thus suspend can be called while lock is being held + */ + mutex_lock(&wcd9xxx_core_res->pm_lock); + if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) { + pr_debug("%s: suspending system, state %d, wlock %d\n", + __func__, wcd9xxx_core_res->pm_state, + wcd9xxx_core_res->wlock_holders); + wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP; + } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) { + /* + * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE + * then set to WCD9XXX_PM_ASLEEP + */ + pr_debug("%s: waiting to suspend system, state %d, wlock %d\n", + __func__, wcd9xxx_core_res->pm_state, + wcd9xxx_core_res->wlock_holders); + mutex_unlock(&wcd9xxx_core_res->pm_lock); + if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq, + wcd9xxx_pm_cmpxchg(wcd9xxx_core_res, + WCD9XXX_PM_SLEEPABLE, + WCD9XXX_PM_ASLEEP) == + WCD9XXX_PM_SLEEPABLE, + HZ))) { + pr_debug("%s: suspend failed state %d, wlock %d\n", + __func__, wcd9xxx_core_res->pm_state, + wcd9xxx_core_res->wlock_holders); + ret = -EBUSY; + } else { + pr_debug("%s: done, state %d, wlock %d\n", __func__, + wcd9xxx_core_res->pm_state, + wcd9xxx_core_res->wlock_holders); + } + mutex_lock(&wcd9xxx_core_res->pm_lock); + } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) { + pr_warn("%s: system is already suspended, state %d, wlock %dn", + __func__, wcd9xxx_core_res->pm_state, + wcd9xxx_core_res->wlock_holders); + } + mutex_unlock(&wcd9xxx_core_res->pm_lock); + + return ret; +} +EXPORT_SYMBOL(wcd9xxx_core_res_suspend); + +/* + * wcd9xxx_core_res_resume: + * Resume callback function for wcd9xxx core + * + * @wcd9xxx_core_res: pointer to wcd core resource + * + * Returns 0 for success or negative error code for failure/busy + */ +int wcd9xxx_core_res_resume( + struct wcd9xxx_core_resource *wcd9xxx_core_res) +{ + int ret = 0; + + pr_debug("%s: enter\n", __func__); + mutex_lock(&wcd9xxx_core_res->pm_lock); + if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) { + pr_debug("%s: resuming system, state %d, wlock %d\n", __func__, + wcd9xxx_core_res->pm_state, + wcd9xxx_core_res->wlock_holders); + wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE; + } else { + pr_warn("%s: system is already awake, state %d wlock %d\n", + __func__, wcd9xxx_core_res->pm_state, + wcd9xxx_core_res->wlock_holders); + } + mutex_unlock(&wcd9xxx_core_res->pm_lock); + wake_up_all(&wcd9xxx_core_res->pm_wq); + + return ret; +} +EXPORT_SYMBOL(wcd9xxx_core_res_resume); + +/* + * wcd9xxx_get_intf_type: + * Get interface type of wcd9xxx core + * + * Returns interface type + */ +enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void) +{ + return wcd9xxx_intf; +} +EXPORT_SYMBOL(wcd9xxx_get_intf_type); + +/* + * wcd9xxx_set_intf_type: + * Set interface type of wcd9xxx core + * + */ +void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status) +{ + wcd9xxx_intf = intf_status; +} +EXPORT_SYMBOL(wcd9xxx_set_intf_type); + +/* + * wcd9xxx_set_power_state: set power state for the region + * @wcd9xxx: handle to wcd core + * @state: power state to be set + * @region: region index + * + * Returns error code in case of failure or 0 for success + */ +int wcd9xxx_set_power_state(struct wcd9xxx *wcd9xxx, + enum codec_power_states state, + enum wcd_power_regions region) +{ + if (!wcd9xxx) { + pr_err("%s: wcd9xxx is NULL\n", __func__); + return -EINVAL; + } + + if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) { + dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n", + __func__, region); + return -EINVAL; + } + if (!wcd9xxx->wcd9xxx_pwr[region]) { + dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n", + __func__, region); + return -EINVAL; + } + mutex_lock(&wcd9xxx->io_lock); + wcd9xxx->wcd9xxx_pwr[region]->power_state = state; + mutex_unlock(&wcd9xxx->io_lock); + + return 0; +} +EXPORT_SYMBOL(wcd9xxx_set_power_state); + +/* + * wcd9xxx_get_current_power_state: Get power state of the region + * @wcd9xxx: handle to wcd core + * @region: region index + * + * Returns current power state of the region or error code for failure + */ +int wcd9xxx_get_current_power_state(struct wcd9xxx *wcd9xxx, + enum wcd_power_regions region) +{ + int state; + + if (!wcd9xxx) { + pr_err("%s: wcd9xxx is NULL\n", __func__); + return -EINVAL; + } + + if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) { + dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n", + __func__, region); + return -EINVAL; + } + if (!wcd9xxx->wcd9xxx_pwr[region]) { + dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n", + __func__, region); + return -EINVAL; + } + + mutex_lock(&wcd9xxx->io_lock); + state = wcd9xxx->wcd9xxx_pwr[region]->power_state; + mutex_unlock(&wcd9xxx->io_lock); + + return state; +} +EXPORT_SYMBOL(wcd9xxx_get_current_power_state); diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-utils.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-utils.h new file mode 100644 index 0000000000..1e063abfb5 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd9xxx-utils.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __WCD9XXX_UTILS_H__ +#define __WCD9XXX_UTILS_H__ + +#include +#include +#include +#include "pdata.h" +#include "core.h" + +struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev); +int wcd9xxx_bringup(struct device *dev); +int wcd9xxx_bringdown(struct device *dev); +struct regmap *wcd9xxx_regmap_init(struct device *dev, + const struct regmap_config *config); +int wcd9xxx_reset(struct device *dev); +int wcd9xxx_reset_low(struct device *dev); +int wcd9xxx_get_codec_info(struct device *dev); + +typedef int (*codec_bringup_fn)(struct wcd9xxx *dev); +typedef int (*codec_bringdown_fn)(struct wcd9xxx *dev); +typedef int (*codec_type_fn)(struct wcd9xxx *dev, + struct wcd9xxx_codec_type *wcd_type); + +codec_bringdown_fn wcd9xxx_bringdown_fn(int type); +codec_bringup_fn wcd9xxx_bringup_fn(int type); +codec_type_fn wcd9xxx_get_codec_info_fn(int type); + +#endif diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd_cmi_api.h b/qcom/opensource/audio-kernel/asoc/codecs/wcd_cmi_api.h new file mode 100644 index 0000000000..b02c665836 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd_cmi_api.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. + */ + +#ifndef __CMI_API__ +#define __CMI_API__ + +enum cmi_api_result { + CMI_API_FAILED = 1, + CMI_API_BUSY, + CMI_API_NO_MEMORY, + CMI_API_NOT_READY, +}; + +enum cmi_api_event { + CMI_API_MSG = 1, + CMI_API_OFFLINE, + CMI_API_ONLINE, + CMI_API_DEINITIALIZED, +}; + +struct cmi_api_notification { + enum cmi_api_event event; + enum cmi_api_result result; + void *message; +}; + +void *cmi_register( + void notification_callback + (const struct cmi_api_notification *parameter), + u32 service); +enum cmi_api_result cmi_deregister(void *reg_handle); +enum cmi_api_result cmi_send_msg(void *message); + +#endif /*__CMI_API__*/ diff --git a/qcom/opensource/audio-kernel/asoc/codecs/wcd_cpe_core.c b/qcom/opensource/audio-kernel/asoc/codecs/wcd_cpe_core.c new file mode 100644 index 0000000000..fa6d0f0e39 --- /dev/null +++ b/qcom/opensource/audio-kernel/asoc/codecs/wcd_cpe_core.c @@ -0,0 +1,4592 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include